├── lib └── README.md ├── LedBlinker ├── LedBlinkerDeployment │ ├── fprime-gds.yml │ ├── CMakeLists.txt │ ├── Top │ │ ├── CMakeLists.txt │ │ ├── instances.fpp │ │ ├── LedBlinkerDeploymentTopologyDefs.hpp │ │ ├── LedBlinkerDeploymentTopology.hpp │ │ ├── LedBlinkerDeploymentTopology.cpp │ │ ├── LedBlinkerDeploymentPackets.fppi │ │ └── topology.fpp │ ├── README.md │ └── Main.cpp ├── Components │ ├── CMakeLists.txt │ └── Led │ │ ├── docs │ │ ├── blink-cmd.png │ │ └── blink-cmd.uml │ │ ├── test │ │ ├── ut │ │ │ ├── LedTestMain.cpp │ │ │ ├── LedTester.hpp │ │ │ └── LedTester.cpp │ │ └── int │ │ │ └── led_integration_tests.py │ │ ├── coverage │ │ ├── summary.txt │ │ ├── coverage.html │ │ ├── coverage.functions.html │ │ ├── coverage.css │ │ └── coverage.Led.cpp.5ec3b97ffe17af934b96682795bb24f6.html │ │ ├── CMakeLists.txt │ │ ├── Led.fpp │ │ ├── Led.hpp │ │ └── Led.cpp └── CMakeLists.txt ├── .clang-format ├── .gitmodules ├── docs ├── img │ ├── component-design.png │ ├── rancher-config.png │ └── rancher-running.png ├── _config.yml ├── _includes │ └── toc.md ├── appendix-1.md └── led-blinker.md ├── settings.ini ├── .gitignore ├── bin └── macos-docker ├── CMakeLists.txt ├── README.md ├── CMakePresets.json └── LICENSE /lib/README.md: -------------------------------------------------------------------------------- 1 | # Libraries 2 | 3 | Libraries used by F Prime should live here. 4 | -------------------------------------------------------------------------------- /LedBlinker/LedBlinkerDeployment/fprime-gds.yml: -------------------------------------------------------------------------------- 1 | command-line-options: 2 | ip-client: 3 | -------------------------------------------------------------------------------- /LedBlinker/Components/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Led/") 3 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: Chromium 3 | IndentWidth: 4 4 | ColumnLimit: 120 5 | AccessModifierOffset: -2 -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/fprime"] 2 | path = lib/fprime 3 | url = https://github.com/nasa/fprime.git 4 | -------------------------------------------------------------------------------- /docs/img/component-design.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fprime-community/fprime-workshop-led-blinker/HEAD/docs/img/component-design.png -------------------------------------------------------------------------------- /docs/img/rancher-config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fprime-community/fprime-workshop-led-blinker/HEAD/docs/img/rancher-config.png -------------------------------------------------------------------------------- /docs/img/rancher-running.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fprime-community/fprime-workshop-led-blinker/HEAD/docs/img/rancher-running.png -------------------------------------------------------------------------------- /LedBlinker/Components/Led/docs/blink-cmd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fprime-community/fprime-workshop-led-blinker/HEAD/LedBlinker/Components/Led/docs/blink-cmd.png -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | title: "F´" 2 | description: "Flight Software & Embedded Systems Framework" 3 | remote_theme: "fprime-community/fprime-theme@main" 4 | includes_dir: _includes 5 | -------------------------------------------------------------------------------- /settings.ini: -------------------------------------------------------------------------------- 1 | [fprime] 2 | project_root: . 3 | framework_path: ./lib/fprime 4 | 5 | default_cmake_options: FPRIME_ENABLE_FRAMEWORK_UTS=OFF 6 | FPRIME_ENABLE_AUTOCODER_UTS=OFF 7 | -------------------------------------------------------------------------------- /LedBlinker/Components/Led/docs/blink-cmd.uml: -------------------------------------------------------------------------------- 1 | ```plantuml 2 | @startuml 3 | ground -> cmdDispatcher: Turn On/Off blink 4 | cmdDispatcher -> led: Turn On/Off blink 5 | led -> led: Sets its blinking state to commanded state 6 | @enduml 7 | ``` 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # fprime items 2 | logs/ 3 | cmake-build-* 4 | build-artifacts/ 5 | build-fprime-* 6 | *-template 7 | *.template.cpp 8 | *.template.hpp 9 | 10 | # Misc 11 | /venv/ 12 | /fprime-venv/ 13 | /.idea/ 14 | /.vscode/ 15 | .DS_Store 16 | *.gcov 17 | -------------------------------------------------------------------------------- /LedBlinker/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # This CMake file is intended to register project-wide objects. 2 | # This allows for reuse between deployments, or other projects. 3 | 4 | add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Components") 5 | add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/LedBlinkerDeployment/") 6 | -------------------------------------------------------------------------------- /bin/macos-docker: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Detect the project root directory 4 | export SOURCE_DIR=`dirname $0` 5 | export PROJECT_ROOT=`cd "${SOURCE_DIR}/.."; pwd` 6 | 7 | USER_ID=`id -u` 8 | GROUP_ID=`id -g` 9 | 10 | docker run --platform=linux/amd64 --net host -e USER=$USER -u "${USER_ID}:${GROUP_ID}" -v "${PROJECT_ROOT}:/project" -it \ 11 | nasafprime/fprime-arm:latest 12 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #### 2 | # This sets up the build system for the 'led-blinker' project, including 3 | # components and deployments from project.cmake. In addition, it imports the core F Prime components. 4 | #### 5 | 6 | cmake_minimum_required(VERSION 3.13) 7 | project(led-blinker C CXX) 8 | 9 | ### 10 | # F' Core Setup 11 | # This includes all of the F prime core components, and imports the make-system. 12 | ### 13 | include("${CMAKE_CURRENT_LIST_DIR}/lib/fprime/cmake/FPrime.cmake") 14 | # NOTE: register custom targets between these two lines 15 | fprime_setup_included_code() 16 | 17 | 18 | # This includes project-wide objects 19 | add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/LedBlinker") 20 | -------------------------------------------------------------------------------- /LedBlinker/LedBlinkerDeployment/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ##### 2 | # 'LedBlinker' Deployment: 3 | # 4 | # This registers the 'LedBlinker' deployment to the build system. 5 | # Custom components that have not been added at the project-level should be added to 6 | # the list below. 7 | # 8 | ##### 9 | 10 | ### 11 | # Topology and Components 12 | ### 13 | 14 | add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Top/") 15 | 16 | # Add custom components to this specific deployment here 17 | # add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/MyComponent/") 18 | 19 | register_fprime_deployment( 20 | SOURCES 21 | "${CMAKE_CURRENT_LIST_DIR}/Main.cpp" 22 | DEPENDS 23 | ${FPRIME_CURRENT_MODULE}_Top 24 | ) 25 | -------------------------------------------------------------------------------- /LedBlinker/Components/Led/test/ut/LedTestMain.cpp: -------------------------------------------------------------------------------- 1 | // ====================================================================== 2 | // \title LedTestMain.cpp 3 | // \author ortega 4 | // \brief cpp file for Led component test main function 5 | // ====================================================================== 6 | 7 | #include "LedTester.hpp" 8 | 9 | TEST(Nominal, TestBlinking) { 10 | LedBlinker::LedTester tester; 11 | tester.testBlinking(); 12 | } 13 | 14 | TEST(Nominal, TestBlinkInterval) { 15 | LedBlinker::LedTester tester; 16 | tester.testBlinkInterval(); 17 | } 18 | 19 | int main(int argc, char** argv) { 20 | ::testing::InitGoogleTest(&argc, argv); 21 | return RUN_ALL_TESTS(); 22 | } 23 | -------------------------------------------------------------------------------- /LedBlinker/LedBlinkerDeployment/Top/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #### 2 | # F Prime CMakeLists.txt: 3 | # 4 | # SOURCES: list of source files (to be compiled) 5 | # AUTOCODER_INPUTS: list of files to be passed to the autocoders 6 | # DEPENDS: list of libraries that this module depends on 7 | # 8 | # More information in the F´ CMake API documentation: 9 | # https://fprime.jpl.nasa.gov/latest/docs/reference/api/cmake/API/ 10 | # 11 | #### 12 | 13 | register_fprime_module( 14 | AUTOCODER_INPUTS 15 | "${CMAKE_CURRENT_LIST_DIR}/instances.fpp" 16 | "${CMAKE_CURRENT_LIST_DIR}/topology.fpp" 17 | SOURCES 18 | "${CMAKE_CURRENT_LIST_DIR}/LedBlinkerDeploymentTopology.cpp" 19 | DEPENDS 20 | Fw_Logger 21 | ) 22 | -------------------------------------------------------------------------------- /LedBlinker/Components/Led/coverage/summary.txt: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------ 2 | GCC Code Coverage Report 3 | Directory: ../.. 4 | ------------------------------------------------------------------------------ 5 | File Lines Exec Cover Missing 6 | ------------------------------------------------------------------------------ 7 | Components/Led/Led.cpp 44 44 100% 8 | ------------------------------------------------------------------------------ 9 | TOTAL 44 44 100% 10 | ------------------------------------------------------------------------------ 11 | -------------------------------------------------------------------------------- /LedBlinker/Components/Led/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #### 2 | # F Prime CMakeLists.txt: 3 | # 4 | # SOURCES: list of source files (to be compiled) 5 | # AUTOCODER_INPUTS: list of files to be passed to the autocoders 6 | # DEPENDS: list of libraries that this module depends on 7 | # 8 | # More information in the F´ CMake API documentation: 9 | # https://fprime.jpl.nasa.gov/latest/docs/reference/api/cmake/API/ 10 | # 11 | #### 12 | 13 | # Module names are derived from the path from the nearest project/library/framework 14 | # root when not specifically overridden by the developer. i.e. The module defined by 15 | # `Ref/SignalGen/CMakeLists.txt` will be named `Ref_SignalGen`. 16 | 17 | register_fprime_library( 18 | AUTOCODER_INPUTS 19 | "${CMAKE_CURRENT_LIST_DIR}/Led.fpp" 20 | SOURCES 21 | "${CMAKE_CURRENT_LIST_DIR}/Led.cpp" 22 | # DEPENDS 23 | # MyPackage_MyOtherModule 24 | ) 25 | 26 | # ### Unit Tests ### 27 | register_fprime_ut( 28 | AUTOCODER_INPUTS 29 | "${CMAKE_CURRENT_LIST_DIR}/Led.fpp" 30 | SOURCES 31 | "${CMAKE_CURRENT_LIST_DIR}/test/ut/LedTestMain.cpp" 32 | "${CMAKE_CURRENT_LIST_DIR}/test/ut/LedTester.cpp" 33 | DEPENDS 34 | STest # For rules-based testing 35 | UT_AUTO_HELPERS 36 | ) 37 | 38 | -------------------------------------------------------------------------------- /docs/_includes/toc.md: -------------------------------------------------------------------------------- 1 | 2 |

F´ Documentation

3 | 6 |

LedBlinker Tutorial

7 |
    8 |
  1. Project Setup
  2. 9 |
  3. Requirements Specification
  4. 10 |
  5. Component Design and Initial Implementation
  6. 11 |
  7. Initial Component Integration
  8. 12 |
  9. Continuing Component Implementation
  10. 13 |
  11. Unit-Testing
  12. 14 |
  13. Full System Integration
  14. 15 |
  15. Running on Hardware
  16. 16 |
  17. System Testing
  18. 17 |
18 | -------------------------------------------------------------------------------- /LedBlinker/LedBlinkerDeployment/README.md: -------------------------------------------------------------------------------- 1 | # LedBlinker Application 2 | 3 | This deployment was auto-generated by the F' utility tool. 4 | 5 | ## Building and Running the LedBlinker Application 6 | 7 | In order to build the LedBlinker application, or any other F´ application, we first need to generate a build directory. This can be done with the following commands: 8 | 9 | ``` 10 | cd LedBlinker 11 | fprime-util generate 12 | ``` 13 | 14 | The next step is to build the LedBlinker application's code. 15 | ``` 16 | fprime-util build 17 | ``` 18 | 19 | ## Running the application and F' GDS 20 | 21 | The following command will spin up the F' GDS as well as run the application binary and the components necessary for the GDS and application to communicate. 22 | 23 | ``` 24 | cd LedBlinker 25 | fprime-gds 26 | ``` 27 | 28 | 29 | To run the ground system without starting the LedBlinker app: 30 | ``` 31 | 32 | cd LedBlinker 33 | fprime-gds --no-app 34 | ``` 35 | 36 | The application binary may then be run independently from the created 'bin' directory. 37 | 38 | ``` 39 | cd LedBlinker/build-artifacts//bin/ 40 | ./LedBlinker -a 127.0.0.1 -p 50000 41 | ``` 42 | 43 | 44 | ## This deployment uses F' **core subtopologies** for a modular, reusable architecture: 45 | 46 | - **CdhCore**: Command & Data Handling 47 | - Command dispatching and event management 48 | - Event logging and telemetry collection 49 | - Health monitoring system 50 | - Fatal error handling 51 | 52 | - **ComCcsds**: CCSDS Communication Subsystem 53 | - CCSDS protocol implementation 54 | - Uplink/downlink data handling 55 | - Frame processing and routing 56 | 57 | - **FileHandling**: File Transfer & Command Sequencing 58 | - File upload and download services 59 | - Parameter database management 60 | - File system operations 61 | 62 | - **DataProducts**: Data Product Management 63 | - Data product cataloging 64 | - Storage and retrieval capabilities 65 | - Product metadata management -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LED Blinker: An F´ Tutorial on Physical Hardware 2 | 3 | This repository contains the source code and documentation for the F Prime MathComponent tutorial. 4 | 5 | To run through the tutorial, please visit the F´ website and look for the tutorial section: https://fprime.jpl.nasa.gov 6 | 7 | This is designed to be an extended introductory F´ tutorial taking the user through the basics of creating components, 8 | using events, telemetry, commands, and parameters, and integrating topologies with the goal of running F´ on embedded 9 | hardware. Users will be guided through the process of software development and testing on embedded Linux running on an 10 | ARM processor (e.g. RaspberryPI, Odroid, etc). 11 | 12 | ## Prerequisites 13 | 14 | In order to run through this tutorial, you must first do the following: 15 | 16 | 1. Meet the [F´ System Requirements](https://github.com/nasa/fprime#system-requirements) 17 | 2. Install an IDE or text editor supporting copy-paste. [VSCode](https://code.visualstudio.com/) has [plugins](https://marketplace.visualstudio.com/items?itemName=unlv-team5.fpptools) to work with FPP. 18 | 3. Attempt the [Hello World Tutorial](https://fprime.jpl.nasa.gov/latest/docs/tutorials/) 19 | 20 | To run on hardware with cross-compiling, you must also: 21 | 1. Acquire and set up the appropriate [hardware](docs/led-blinker.md#appendix-optional-hardware-requirements) for this tutorial 22 | 2. Set up a [cross-compiling environment](https://github.com/nasa/fprime/blob/devel/docs/tutorials/cross-compilation.md) for their ARM processor 23 | 24 | > [!NOTE] 25 | > Attendees to an in-person F´ workshop will have access to 64-bit ARM hardware and should set up the 64-bit cross compiling environment. 26 | 27 | ## Contributing 28 | If you would like to contribute to this tutorial, please open a pull request. 29 | 30 | ## Resources 31 | - [Discussions](https://github.com/nasa/fprime/discussions) 32 | - [Submit an Issue](https://github.com/nasa/fprime/issues) 33 | - [F´ Community](https://github.com/fprime-community) 34 | -------------------------------------------------------------------------------- /CMakePresets.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 4, 3 | "configurePresets": [ 4 | { 5 | "name": "fprime", 6 | "displayName": "F´ Release Preset", 7 | "description": "F´ release build using local fprime-venv", 8 | "binaryDir": "${sourceDir}/build-fprime-automatic-native", 9 | "environment": { 10 | "VIRTUAL_ENV": "${fileDir}/fprime-venv", 11 | "PATH": "$env{VIRTUAL_ENV}/bin:$penv{PATH}" 12 | }, 13 | "cacheVariables": { 14 | "CMAKE_EXPORT_COMPILE_COMMANDS": "ON", 15 | "CMAKE_BUILD_TYPE": "Release" 16 | } 17 | }, 18 | { 19 | "name": "fprime-debug", 20 | "inherits": "fprime", 21 | "displayName": "F´ Debug Preset", 22 | "description": "F´ debug build using local fprime-venv", 23 | "cacheVariables": { 24 | "CMAKE_BUILD_TYPE": "Debug" 25 | } 26 | }, 27 | { 28 | "name": "fprime-ut", 29 | "inherits": "fprime-debug", 30 | "displayName": "F´ Unit Test Preset", 31 | "description": "F´ debug build including unit tests using local fprime-venv", 32 | "binaryDir": "${sourceDir}/build-fprime-automatic-native-ut", 33 | "cacheVariables": { 34 | "BUILD_TESTING": "ON" 35 | } 36 | }, 37 | { 38 | "name": "fprime-ninja", 39 | "inherits": "fprime", 40 | "displayName": "F´ Release (Ninja) Preset", 41 | "description": "F´ release build using ninja and local fprime-venv", 42 | "generator": "Ninja" 43 | }, 44 | { 45 | "name": "fprime-debug-ninja", 46 | "inherits": "fprime-debug", 47 | "displayName": "F´ Debug (Ninja) Preset", 48 | "description": "F´ debug build using ninja and local fprime-venv", 49 | "generator": "Ninja" 50 | }, 51 | { 52 | "name": "fprime-ut-ninja", 53 | "inherits": "fprime-ut", 54 | "displayName": "F´ Unit Test (Ninja) Preset", 55 | "description": "F´ debug build including unit tests using ninja and local fprime-venv", 56 | "binaryDir": "${sourceDir}/build-fprime-automatic-native-ut", 57 | "generator": "Ninja" 58 | } 59 | ] 60 | } 61 | -------------------------------------------------------------------------------- /docs/appendix-1.md: -------------------------------------------------------------------------------- 1 | # Appendix I: Installing Rancher Desktop and the F´ ARM Container 2 | 3 | Some users may with to run cross-compilers within docker to minimize the impact of those tools on their systems. Macintosh users will be required to use docker as the ARM/Linux cross-compilers are not available natively for macOS and simple virtualization of a Linux box is no longer practical since the introduction of M1 and M2 hardware. 4 | 5 | ## Rancher Desktop Setup 6 | 7 | Rancher Desktop is an alternative to Docker Desktop that allows users to run docker containers directly on their desktop computer. It does not require a license for use like Docker Desktop does and also supports both intel and ARM based Macintosh computers. 8 | 9 | > Non-Macintosh users are advised to run without the below Docker container 10 | 11 | To install [Rancher Desktop](https://rancherdesktop.io/), follow the instructions for your operating system. When presented with a "Welcome to Rancher Desktop" dialog, choose the following settings: 12 | 1. Disable Kubernetes 13 | 2. Select `dockerd` 14 | 3. Configure PATH Automatic 15 | 16 | ![Rancher Config](./img/rancher-config.png) 17 | 18 | Ensure that Rancher Desktop is running and that the VM it uses has been started. You can confirm this by ensuring no pop-ups nor progress bars are visible in Rancher Desktop's main window as shown below. 19 | 20 | ![Rancher Main Window](./img/rancher-running.png) 21 | 22 | Once this is done, users can install the container by running the following command in their host terminal. It should complete without errors. 23 | 24 | ```bash 25 | docker pull nasafprime/fprime-arm:latest 26 | ``` 27 | 28 | ## Running The Container 29 | 30 | In order to run the commands provided by the docker container (i.e. the cross-compilers), users must start the container and attach to a terminal inside. This should be done **after** the user has created a project to work within. 31 | 32 | To run this container, users may wish to download [this script](https://github.com/fprime-community/fprime-workshop-led-blinker/blob/main/bin/macos-docker) to a `bin` directory in the root of their project. This will start the docker container with appropriate settings. 33 | 34 | Alternatively, the user may run the following command to start the terminal 35 | ```bash 36 | docker run --platform=linux/amd64 --net host -e USER=$USER -u "`id -u`:`id -g`" -v "/path/to/project:/project" -it \ 37 | docker pull nasafprime/fprime-arm:latest 38 | ``` 39 | 40 | > Anytime Macintosh users run cross-compilation commands, they **must** do so in a terminal inside the docker container. 41 | -------------------------------------------------------------------------------- /LedBlinker/Components/Led/Led.fpp: -------------------------------------------------------------------------------- 1 | module LedBlinker { 2 | @ Component to blink an LED driven by a rate group 3 | active component Led { 4 | 5 | @ Command to turn on or off the blinking LED 6 | async command BLINKING_ON_OFF( 7 | onOff: Fw.On @< Indicates whether the blinking should be on or off 8 | ) 9 | 10 | @ Telemetry channel to report blinking state. 11 | telemetry BlinkingState: Fw.On 12 | 13 | @ Telemetry channel counting LED transitions 14 | telemetry LedTransitions: U64 15 | 16 | @ Reports the state we set to blinking. 17 | event SetBlinkingState($state: Fw.On) \ 18 | severity activity high \ 19 | format "Set blinking state to {}." 20 | 21 | @ Event logged when the LED turns on or off 22 | event LedState(onOff: Fw.On) \ 23 | severity activity low \ 24 | format "LED is {}" 25 | 26 | @ Event logged when the LED blink interval is updated 27 | event BlinkIntervalSet(interval: U32) \ 28 | severity activity high \ 29 | format "LED blink interval set to {}" 30 | 31 | @ Blinking interval in rate group ticks 32 | param BLINK_INTERVAL: U32 default 1 33 | 34 | @ Port receiving calls from the rate group 35 | async input port run: Svc.Sched 36 | 37 | @ Port sending calls to the GPIO driver 38 | output port gpioSet: Drv.GpioWrite 39 | 40 | ############################################################################### 41 | # Standard AC Ports: Required for Channels, Events, Commands, and Parameters # 42 | ############################################################################### 43 | @ Port for requesting the current time 44 | time get port timeCaller 45 | 46 | @ Port for sending command registrations 47 | command reg port cmdRegOut 48 | 49 | @ Port for receiving commands 50 | command recv port cmdIn 51 | 52 | @ Port for sending command responses 53 | command resp port cmdResponseOut 54 | 55 | @ Port for sending textual representation of events 56 | text event port logTextOut 57 | 58 | @ Port for sending events to downlink 59 | event port logOut 60 | 61 | @ Port for sending telemetry channels to downlink 62 | telemetry port tlmOut 63 | 64 | @ Port to return the value of a parameter 65 | param get port prmGetOut 66 | 67 | @Port to set the value of a parameter 68 | param set port prmSetOut 69 | 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /LedBlinker/LedBlinkerDeployment/Top/instances.fpp: -------------------------------------------------------------------------------- 1 | module LedBlinker { 2 | 3 | # ---------------------------------------------------------------------- 4 | # Base ID Convention 5 | # ---------------------------------------------------------------------- 6 | # 7 | # All Base IDs follow the 8-digit hex format: 0xDSSCCxxx 8 | # 9 | # Where: 10 | # D = Deployment digit (1 for this deployment) 11 | # SS = Subtopology digits (00 for main topology, 01-05 for subtopologies) 12 | # CC = Component digits (00, 01, 02, etc.) 13 | # xxx = Reserved for internal component items (events, commands, telemetry) 14 | # 15 | 16 | # ---------------------------------------------------------------------- 17 | # Defaults 18 | # ---------------------------------------------------------------------- 19 | 20 | module Default { 21 | constant QUEUE_SIZE = 10 22 | constant STACK_SIZE = 64 * 1024 23 | } 24 | 25 | # ---------------------------------------------------------------------- 26 | # Active component instances 27 | # ---------------------------------------------------------------------- 28 | 29 | instance rateGroup1: Svc.ActiveRateGroup base id 0x10001000 \ 30 | queue size Default.QUEUE_SIZE \ 31 | stack size Default.STACK_SIZE \ 32 | priority 120 33 | 34 | instance rateGroup2: Svc.ActiveRateGroup base id 0x10002000 \ 35 | queue size Default.QUEUE_SIZE \ 36 | stack size Default.STACK_SIZE \ 37 | priority 119 38 | 39 | instance rateGroup3: Svc.ActiveRateGroup base id 0x10003000 \ 40 | queue size Default.QUEUE_SIZE \ 41 | stack size Default.STACK_SIZE \ 42 | priority 118 43 | 44 | instance cmdSeq: Svc.CmdSequencer base id 0x10004000 \ 45 | queue size Default.QUEUE_SIZE \ 46 | stack size Default.STACK_SIZE \ 47 | priority 117 48 | 49 | instance led: LedBlinker.Led base id 0x10005000 \ 50 | queue size Default.QUEUE_SIZE \ 51 | stack size Default.STACK_SIZE \ 52 | priority 95 53 | 54 | # ---------------------------------------------------------------------- 55 | # Queued component instances 56 | # ---------------------------------------------------------------------- 57 | 58 | 59 | # ---------------------------------------------------------------------- 60 | # Passive component instances 61 | # ---------------------------------------------------------------------- 62 | 63 | instance chronoTime: Svc.ChronoTime base id 0x10010000 64 | 65 | instance rateGroupDriver: Svc.RateGroupDriver base id 0x10011000 66 | 67 | instance systemResources: Svc.SystemResources base id 0x10012000 68 | 69 | instance linuxTimer: Svc.LinuxTimer base id 0x10013000 70 | 71 | instance comDriver: Drv.TcpServer base id 0x10014000 72 | 73 | instance gpioDriver: Drv.LinuxGpioDriver base id 0x10015000 74 | 75 | } 76 | -------------------------------------------------------------------------------- /LedBlinker/Components/Led/test/ut/LedTester.hpp: -------------------------------------------------------------------------------- 1 | // ====================================================================== 2 | // \title LedTester.hpp 3 | // \author ortega 4 | // \brief hpp file for Led component test harness implementation class 5 | // ====================================================================== 6 | 7 | #ifndef Components_LedTester_HPP 8 | #define Components_LedTester_HPP 9 | 10 | #include "LedBlinker/Components/Led/Led.hpp" 11 | #include "LedBlinker/Components/Led/LedGTestBase.hpp" 12 | 13 | namespace LedBlinker { 14 | 15 | class LedTester : public LedGTestBase { 16 | public: 17 | // ---------------------------------------------------------------------- 18 | // Constants 19 | // ---------------------------------------------------------------------- 20 | 21 | // Maximum size of histories storing events, telemetry, and port outputs 22 | static const U32 MAX_HISTORY_SIZE = 10; 23 | 24 | // Instance ID supplied to the component instance under test 25 | static const FwEnumStoreType TEST_INSTANCE_ID = 0; 26 | 27 | // Queue depth supplied to the component instance under test 28 | static const FwSizeType TEST_INSTANCE_QUEUE_DEPTH = 10; 29 | 30 | public: 31 | // ---------------------------------------------------------------------- 32 | // Construction and destruction 33 | // ---------------------------------------------------------------------- 34 | 35 | //! Construct object LedTester 36 | LedTester(); 37 | 38 | //! Destroy object LedTester 39 | ~LedTester(); 40 | 41 | public: 42 | // ---------------------------------------------------------------------- 43 | // Tests 44 | // ---------------------------------------------------------------------- 45 | 46 | void testBlinking(); 47 | void testBlinkInterval(); 48 | 49 | private: 50 | // ---------------------------------------------------------------------- 51 | // Handlers for typed from ports 52 | // ---------------------------------------------------------------------- 53 | 54 | //! Handler for from_gpioSet 55 | //! 56 | Drv::GpioStatus from_gpioSet_handler(const FwIndexType portNum, /*!< The port number*/ 57 | const Fw::Logic& state); 58 | 59 | private: 60 | // ---------------------------------------------------------------------- 61 | // Helper functions 62 | // ---------------------------------------------------------------------- 63 | 64 | //! Connect ports 65 | void connectPorts(); 66 | 67 | //! Initialize components 68 | void initComponents(); 69 | 70 | private: 71 | // ---------------------------------------------------------------------- 72 | // Member variables 73 | // ---------------------------------------------------------------------- 74 | 75 | //! The component under test 76 | Led component; 77 | }; 78 | 79 | } // namespace LedBlinker 80 | 81 | #endif 82 | -------------------------------------------------------------------------------- /LedBlinker/Components/Led/Led.hpp: -------------------------------------------------------------------------------- 1 | // ====================================================================== 2 | // \title Led.hpp 3 | // \author ortega 4 | // \brief hpp file for Led component implementation class 5 | // ====================================================================== 6 | 7 | #ifndef Components_Led_HPP 8 | #define Components_Led_HPP 9 | 10 | #include "LedBlinker/Components/Led/LedComponentAc.hpp" 11 | 12 | namespace LedBlinker { 13 | 14 | class Led : public LedComponentBase { 15 | public: 16 | // ---------------------------------------------------------------------- 17 | // Component construction and destruction 18 | // ---------------------------------------------------------------------- 19 | 20 | //! Construct Led object 21 | Led(const char* const compName //!< The component name 22 | ); 23 | 24 | //! Destroy Led object 25 | ~Led(); 26 | 27 | private : 28 | //! Emit parameter updated EVR 29 | //! 30 | void 31 | parameterUpdated(FwPrmIdType id //!< The parameter ID 32 | ) override; 33 | 34 | private : 35 | 36 | // ---------------------------------------------------------------------- 37 | // Handler implementations for user-defined typed input ports 38 | // ---------------------------------------------------------------------- 39 | 40 | //! Handler implementation for run 41 | //! 42 | //! Port receiving calls from the rate group 43 | void 44 | run_handler(FwIndexType portNum, //!< The port number 45 | U32 context //!< The call order 46 | ) override; 47 | 48 | private : 49 | // ---------------------------------------------------------------------- 50 | // Handler implementations for commands 51 | // ---------------------------------------------------------------------- 52 | 53 | //! Handler implementation for command BLINKING_ON_OFF 54 | //! 55 | //! Command to turn on or off the blinking LED 56 | void 57 | BLINKING_ON_OFF_cmdHandler(FwOpcodeType opCode, //!< The opcode 58 | U32 cmdSeq, //!< The command sequence number 59 | Fw::On onOff //!< Indicates whether the blinking should be on or off 60 | ) override; 61 | 62 | Fw::On m_state = Fw::On::OFF; //! Keeps track if LED is on or off 63 | U64 m_transitions = 0; //! The number of on/off transitions that have occurred 64 | //! from FSW boot up 65 | U32 m_toggleCounter = 0; //! Keeps track of how many ticks the LED has been on for 66 | bool m_blinking = false; //! Flag: if true then LED blinking will occur else 67 | //! no blinking will happen 68 | }; 69 | 70 | } // namespace Components 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /LedBlinker/Components/Led/test/int/led_integration_tests.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | from fprime_gds.common.testing_fw import predicates 4 | 5 | 6 | def test_blinking(fprime_test_api): 7 | """Test that LED component can respond to ground commands""" 8 | 9 | # Send command to enable blinking, then assert expected events are emitted 10 | blink_start_evr = fprime_test_api.get_event_pred( 11 | "LedBlinker.led.SetBlinkingState", ["ON"] 12 | ) 13 | led_on_evr = fprime_test_api.get_event_pred("LedBlinker.led.LedState", ["ON"]) 14 | led_off_evr = fprime_test_api.get_event_pred("LedBlinker.led.LedState", ["OFF"]) 15 | 16 | fprime_test_api.send_and_assert_event( 17 | "LedBlinker.led.BLINKING_ON_OFF", 18 | args=["ON"], 19 | events=[blink_start_evr, led_on_evr, led_off_evr, led_on_evr], 20 | timeout=5, 21 | ) 22 | 23 | # Assert that blink command sets blinking state on 24 | blink_state_on_tlm = fprime_test_api.get_telemetry_pred( 25 | "LedBlinker.led.BlinkingState", "ON" 26 | ) 27 | fprime_test_api.assert_telemetry(blink_state_on_tlm) 28 | 29 | # Assert that the LedTransitions channel increments 30 | results = fprime_test_api.assert_telemetry_count( 31 | predicates.greater_than(2), "LedBlinker.led.LedTransitions", timeout=4 32 | ) 33 | ascending = True 34 | prev = None 35 | for res in results: 36 | if prev is not None: 37 | if not res.get_val() > prev.get_val(): 38 | ascending = False 39 | fprime_test_api.log( 40 | f"LedBlinker.led.LedTransitions not in ascending order: First ({prev.get_val()}) Second ({res.get_val()})" 41 | ) 42 | prev = res 43 | assert fprime_test_api.test_assert( 44 | ascending, "Expected all LedBlinker.led.LedTransitions updates to ascend.", True 45 | ) 46 | 47 | # Send command to stop blinking, then assert blinking stops 48 | blink_stop_evr = fprime_test_api.get_event_pred( 49 | "LedBlinker.led.SetBlinkingState", ["OFF"] 50 | ) 51 | fprime_test_api.send_and_assert_event( 52 | "LedBlinker.led.BLINKING_ON_OFF", args=["OFF"], events=[blink_stop_evr] 53 | ) 54 | time.sleep(1) # Wait one second to let any in-progress telemetry be sent 55 | # Save reference to current telemetry history so we can search against future telemetry 56 | telem_after_blink_off = fprime_test_api.telemetry_history.size() 57 | time.sleep(2) # Wait to receive telemetry after stopping blinking 58 | # Assert that blinking has stopped and that LedTransitions is no longer updating 59 | fprime_test_api.assert_telemetry_count( 60 | 0, "LedBlinker.led.LedTransitions", start=telem_after_blink_off 61 | ) 62 | 63 | # Assert that blink command sets blinking state off 64 | blink_state_off_tlm = fprime_test_api.get_telemetry_pred( 65 | "LedBlinker.led.BlinkingState", "OFF" 66 | ) 67 | fprime_test_api.assert_telemetry(blink_state_off_tlm, timeout=2) 68 | -------------------------------------------------------------------------------- /LedBlinker/Components/Led/coverage/coverage.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | GCC Code Coverage Report 7 | 8 | 9 | 10 | 11 | 12 |
13 |

GCC Code Coverage Report

14 | 15 |
16 | 17 |
18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 35 | 36 |
Directory:Components/Led/
Date:2023-04-17 15:08:37
Coverage: 31 | low: ≥ 0% 32 | medium: ≥ 75.0% 33 | high: ≥ 90.0% 34 |
37 |
38 | 39 |
40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 |
ExecTotalCoverage
Lines:4444100.0%
Functions:7887.5%
Branches:457857.7%
66 |
67 |
68 | 69 |
70 |
71 | 72 | 75 | 76 |
77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 95 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 |
FileLinesFunctionsBranches
93 | Led.cpp 94 | 96 | 100.0 97 | 100.0%44 / 4487.5%7 / 857.7%45 / 78
107 |
108 |
109 | 110 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /LedBlinker/LedBlinkerDeployment/Main.cpp: -------------------------------------------------------------------------------- 1 | // ====================================================================== 2 | // \title Main.cpp 3 | // \brief main program for the F' application. Intended for CLI-based systems (Linux, macOS) 4 | // 5 | // ====================================================================== 6 | // Used to access topology functions 7 | #include 8 | // OSAL initialization 9 | #include 10 | // Used for signal handling shutdown 11 | #include 12 | // Used for command line argument processing 13 | #include 14 | // Used for printf functions 15 | #include 16 | 17 | /** 18 | * \brief print command line help message 19 | * 20 | * This will print a command line help message including the available command line arguments. 21 | * 22 | * @param app: name of application 23 | */ 24 | void print_usage(const char* app) { 25 | (void)printf("Usage: ./%s [options]\n-a\thostname/IP address\n-p\tport_number\n", app); 26 | } 27 | 28 | /** 29 | * \brief shutdown topology cycling on signal 30 | * 31 | * The reference topology allows for a simulated cycling of the rate groups. This simulated cycling needs to be stopped 32 | * in order for the program to shutdown. This is done via handling signals such that it is performed via Ctrl-C 33 | * 34 | * @param signum 35 | */ 36 | static void signalHandler(int signum) { 37 | LedBlinker::stopRateGroups(); 38 | } 39 | 40 | /** 41 | * \brief execute the program 42 | * 43 | * This F´ program is designed to run in standard environments (e.g. Linux/macOs running on a laptop). Thus it uses 44 | * command line inputs to specify how to connect. 45 | * 46 | * @param argc: argument count supplied to program 47 | * @param argv: argument values supplied to program 48 | * @return: 0 on success, something else on failure 49 | */ 50 | int main(int argc, char* argv[]) { 51 | I32 option = 0; 52 | CHAR* hostname = nullptr; 53 | U16 port_number = 0; 54 | 55 | Os::init(); 56 | 57 | // Loop while reading the getopt supplied options 58 | while ((option = getopt(argc, argv, "hp:a:")) != -1) { 59 | switch (option) { 60 | // Handle the -a argument for address/hostname 61 | case 'a': 62 | hostname = optarg; 63 | break; 64 | // Handle the -p port number argument 65 | case 'p': 66 | port_number = static_cast(atoi(optarg)); 67 | break; 68 | // Cascade intended: help output 69 | case 'h': 70 | // Cascade intended: help output 71 | case '?': 72 | // Default case: output help and exit 73 | default: 74 | print_usage(argv[0]); 75 | return (option == 'h') ? 0 : 1; 76 | } 77 | } 78 | // Object for communicating state to the topology 79 | LedBlinker::TopologyState inputs; 80 | inputs.hostname = hostname; 81 | inputs.port = port_number; 82 | 83 | // Setup program shutdown via Ctrl-C 84 | signal(SIGINT, signalHandler); 85 | signal(SIGTERM, signalHandler); 86 | (void)printf("Hit Ctrl-C to quit\n"); 87 | 88 | // Setup, cycle, and teardown topology 89 | LedBlinker::setupTopology(inputs); 90 | LedBlinker::startRateGroups(Fw::TimeInterval(1,0)); // Program loop cycling rate groups at 1Hz 91 | LedBlinker::teardownTopology(inputs); 92 | (void)printf("Exiting...\n"); 93 | return 0; 94 | } 95 | -------------------------------------------------------------------------------- /LedBlinker/LedBlinkerDeployment/Top/LedBlinkerDeploymentTopologyDefs.hpp: -------------------------------------------------------------------------------- 1 | // ====================================================================== 2 | // \title LedBlinkerTopologyDefs.hpp 3 | // \brief required header file containing the required definitions for the topology autocoder 4 | // 5 | // ====================================================================== 6 | #ifndef LEDBLINKER_LEDBLINKERTOPOLOGYDEFS_HPP 7 | #define LEDBLINKER_LEDBLINKERTOPOLOGYDEFS_HPP 8 | 9 | // Subtopology PingEntries includes 10 | #include "Svc/Subtopologies/CdhCore/PingEntries.hpp" 11 | #include "Svc/Subtopologies/ComCcsds/PingEntries.hpp" 12 | #include "Svc/Subtopologies/DataProducts/PingEntries.hpp" 13 | #include "Svc/Subtopologies/FileHandling/PingEntries.hpp" 14 | 15 | // SubtopologyTopologyDefs includes 16 | #include "Svc/Subtopologies/CdhCore/SubtopologyTopologyDefs.hpp" 17 | #include "Svc/Subtopologies/ComCcsds/SubtopologyTopologyDefs.hpp" 18 | #include "Svc/Subtopologies/DataProducts/SubtopologyTopologyDefs.hpp" 19 | #include "Svc/Subtopologies/FileHandling/SubtopologyTopologyDefs.hpp" 20 | 21 | //ComCcsds Enum Includes 22 | #include "Svc/Subtopologies/ComCcsds/Ports_ComPacketQueueEnumAc.hpp" 23 | #include "Svc/Subtopologies/ComCcsds/Ports_ComBufferQueueEnumAc.hpp" 24 | 25 | // Include autocoded FPP constants 26 | #include "LedBlinker/LedBlinkerDeployment/Top/FppConstantsAc.hpp" 27 | 28 | /** 29 | * \brief required ping constants 30 | * 31 | * The topology autocoder requires a WARN and FATAL constant definition for each component that supports the health-ping 32 | * interface. These are expressed as enum constants placed in a namespace named for the component instance. These 33 | * are all placed in the PingEntries namespace. 34 | * 35 | * Each constant specifies how many missed pings are allowed before a WARNING_HI/FATAL event is triggered. In the 36 | * following example, the health component will emit a WARNING_HI event if the component instance cmdDisp does not 37 | * respond for 3 pings and will FATAL if responses are not received after a total of 5 pings. 38 | * 39 | * ```c++ 40 | * namespace PingEntries { 41 | * namespace cmdDisp { 42 | * enum { WARN = 3, FATAL = 5 }; 43 | * } 44 | * } 45 | * ``` 46 | */ 47 | namespace PingEntries { 48 | namespace LedBlinker_rateGroup1 {enum { WARN = 3, FATAL = 5 };} 49 | namespace LedBlinker_rateGroup2 {enum { WARN = 3, FATAL = 5 };} 50 | namespace LedBlinker_rateGroup3 {enum { WARN = 3, FATAL = 5 };} 51 | namespace LedBlinker_cmdSeq {enum { WARN = 3, FATAL = 5 };} 52 | } // namespace PingEntries 53 | 54 | // Definitions are placed within the same namespace (FPP module name) 55 | namespace LedBlinker { 56 | 57 | /** 58 | * \brief required type definition to carry state 59 | * 60 | * The topology autocoder requires an object that carries state with the name `LedBlinker::TopologyState`. Only the type 61 | * definition is required by the autocoder and the contents of this object are otherwise opaque to the autocoder. The 62 | * contents are entirely up to the definition of the project. This deployment uses subtopologies. 63 | */ 64 | struct TopologyState { 65 | const char* hostname; //!< Hostname for TCP communication 66 | U16 port; //!< Port for TCP communication 67 | CdhCore::SubtopologyState cdhCore; //!< Subtopology state for CdhCore 68 | ComCcsds::SubtopologyState comCcsds; //!< Subtopology state for ComCcsds 69 | DataProducts::SubtopologyState dataProducts; //!< Subtopology state for DataProducts 70 | FileHandling::SubtopologyState fileHandling; //!< Subtopology state for FileHandling 71 | }; 72 | 73 | namespace PingEntries = ::PingEntries; 74 | } // namespace LedBlinker 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /LedBlinker/Components/Led/Led.cpp: -------------------------------------------------------------------------------- 1 | // ====================================================================== 2 | // \title Led.cpp 3 | // \author ortega 4 | // \brief cpp file for Led component implementation class 5 | // ====================================================================== 6 | 7 | #include "LedBlinker/Components/Led/Led.hpp" 8 | #include "config/FpConfig.hpp" 9 | 10 | namespace LedBlinker { 11 | 12 | // ---------------------------------------------------------------------- 13 | // Component construction and destruction 14 | // ---------------------------------------------------------------------- 15 | 16 | Led ::Led(const char* const compName) : LedComponentBase(compName) {} 17 | 18 | Led ::~Led() {} 19 | 20 | void Led ::parameterUpdated(FwPrmIdType id) { 21 | Fw::ParamValid isValid = Fw::ParamValid::INVALID; 22 | switch (id) { 23 | case PARAMID_BLINK_INTERVAL: { 24 | // Read back the parameter value 25 | const U32 interval = this->paramGet_BLINK_INTERVAL(isValid); 26 | // NOTE: isValid is always VALID in parameterUpdated as it was just properly set 27 | FW_ASSERT(isValid == Fw::ParamValid::VALID, static_cast(isValid)); 28 | 29 | // Emit the blink interval set event 30 | this->log_ACTIVITY_HI_BlinkIntervalSet(interval); 31 | break; 32 | } 33 | default: 34 | FW_ASSERT(0, static_cast(id)); 35 | break; 36 | } 37 | } 38 | 39 | // ---------------------------------------------------------------------- 40 | // Handler implementations for user-defined typed input ports 41 | // ---------------------------------------------------------------------- 42 | 43 | void Led ::run_handler(FwIndexType portNum, U32 context) { 44 | // Read back the parameter value 45 | Fw::ParamValid isValid = Fw::ParamValid::INVALID; 46 | U32 interval = this->paramGet_BLINK_INTERVAL(isValid); 47 | FW_ASSERT((isValid != Fw::ParamValid::INVALID) && (isValid != Fw::ParamValid::UNINIT), 48 | static_cast(isValid)); 49 | 50 | // Only perform actions when set to blinking 51 | if (this->m_blinking && (interval != 0)) { 52 | // If toggling state 53 | if (this->m_toggleCounter == 0) { 54 | // Toggle state 55 | this->m_state = (this->m_state == Fw::On::ON) ? Fw::On::OFF : Fw::On::ON; 56 | this->m_transitions++; 57 | this->tlmWrite_LedTransitions(this->m_transitions); 58 | 59 | // Port may not be connected, so check before sending output 60 | if (this->isConnected_gpioSet_OutputPort(0)) { 61 | this->gpioSet_out(0, (Fw::On::ON == this->m_state) ? Fw::Logic::HIGH : Fw::Logic::LOW); 62 | } 63 | 64 | this->log_ACTIVITY_LO_LedState(this->m_state); 65 | } 66 | 67 | this->m_toggleCounter = (this->m_toggleCounter + 1) % interval; 68 | } 69 | // We are not blinking 70 | else { 71 | if (this->m_state == Fw::On::ON) { 72 | // Port may not be connected, so check before sending output 73 | if (this->isConnected_gpioSet_OutputPort(0)) { 74 | this->gpioSet_out(0, Fw::Logic::LOW); 75 | } 76 | 77 | this->m_state = Fw::On::OFF; 78 | this->log_ACTIVITY_LO_LedState(this->m_state); 79 | } 80 | } 81 | } 82 | 83 | // ---------------------------------------------------------------------- 84 | // Handler implementations for commands 85 | // ---------------------------------------------------------------------- 86 | 87 | void Led ::BLINKING_ON_OFF_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, Fw::On onOff) { 88 | this->m_toggleCounter = 0; // Reset count on any successful command 89 | this->m_blinking = Fw::On::ON == onOff; // Update blinking state 90 | 91 | this->log_ACTIVITY_HI_SetBlinkingState(onOff); 92 | 93 | this->tlmWrite_BlinkingState(onOff); 94 | 95 | // Provide command response 96 | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); 97 | } 98 | 99 | } // namespace LedBlinker 100 | -------------------------------------------------------------------------------- /LedBlinker/LedBlinkerDeployment/Top/LedBlinkerDeploymentTopology.hpp: -------------------------------------------------------------------------------- 1 | // ====================================================================== 2 | // \title LedBlinkerTopology.hpp 3 | // \brief header file containing the topology instantiation definitions 4 | // 5 | // ====================================================================== 6 | #ifndef LEDBLINKER_LEDBLINKERTOPOLOGY_HPP 7 | #define LEDBLINKER_LEDBLINKERTOPOLOGY_HPP 8 | // Included for access to LedBlinker::TopologyState and LedBlinker::ConfigObjects::pingEntries. These definitions are 9 | // required by the autocoder, but are also used in this hand-coded topology. 10 | #include 11 | 12 | 13 | namespace LedBlinker { 14 | /** 15 | * \brief initialize and run the F´ topology 16 | * 17 | * Initializes, configures, and runs the F´ topology. This is performed through a series of steps, some provided via 18 | * autocoded functions, and others provided via the functions implementation. These steps are: 19 | * 20 | * 1. Call the autocoded `initComponents()` function initializing each component via the `component.init` method 21 | * 2. Call the autocoded `setBaseIds()` function to set the base IDs (offset) for each component instance 22 | * 3. Call the autocoded `connectComponents()` function to wire-together the topology of components 23 | * 4. Configure components requiring custom configuration 24 | * 5. Call the autocoded `loadParameters()` function to cause each component to load initial parameter values 25 | * 6. Call the autocoded `startTasks()` function to start the active component tasks 26 | * 7. Start tasks not owned by active components 27 | * 28 | * Step 4 and step 7 are custom and supplied by the project. The ordering of steps 1, 2, 3, 5, and 6 are critical for 29 | * F´ topologies to function. Configuration (step 4) typically assumes a connect but not started topology and is thus 30 | * inserted between step 3 and 5. Step 7 may come before or after the active component initializations. Since these 31 | * custom tasks often start radio communication it is convenient to start them last. 32 | * 33 | * The state argument carries command line inputs used to setup the topology. For an explanation of the required type 34 | * LedBlinker::TopologyState see: LedBlinkerTopologyDefs.hpp. 35 | * 36 | * \param state: object shuttling CLI arguments (e.g. hostname/port, or UART baudrate) needed to construct the topology 37 | */ 38 | void setupTopology(const TopologyState& state); 39 | 40 | /** 41 | * \brief teardown the F´ topology 42 | * 43 | * Tears down the F´ topology in preparation for shutdown. This is done via a series of steps, some provided by 44 | * autocoded functions, and others provided via the function implementation. These steps are: 45 | * 46 | * 1. Call the autocoded `stopTasks()` function to stop the tasks started by `startTasks()` (active components) 47 | * 2. Call the autocoded `freeThreads()` function to join to the tasks started by `startTasks()` 48 | * 3. Stop the tasks not owned by active components 49 | * 4. Join to the tasks not owned by active components 50 | * 5. Deallocate other resources 51 | * 52 | * Step 1, 2, 3, and 4 must occur in-order as the tasks must be stopped before being joined. These tasks must be stopped 53 | * and joined before any active resources may be deallocated. 54 | * 55 | * For an explanation of the required type LedBlinker::TopologyState see: LedBlinkerTopologyDefs.hpp. 56 | * 57 | * \param state: state object provided to setupTopology 58 | */ 59 | void teardownTopology(const TopologyState& state); 60 | 61 | /** 62 | * \brief cycle the rate group driver at a crude rate 63 | * 64 | * The reference topology does not have a true 1Hz input clock for the rate group driver because it is designed to 65 | * operate across various computing endpoints (e.g. laptops) where a clear 1Hz source may not be easily and generically 66 | * achieved. This function mimics the cycling via a Task::delay(milliseconds) loop that manually invokes the ISR call 67 | * to the example block driver. 68 | * 69 | * 70 | * This loop is stopped via a stopRateGroups call. 71 | * 72 | */ 73 | void startRateGroups(const Fw::TimeInterval& interval = Fw::TimeInterval(1, 0)); 74 | 75 | /** 76 | * \brief stop the rate groups 77 | * 78 | * This stops the cycle started by startRateGroups. 79 | */ 80 | void stopRateGroups(); 81 | 82 | } // namespace LedBlinker 83 | #endif 84 | -------------------------------------------------------------------------------- /LedBlinker/Components/Led/test/ut/LedTester.cpp: -------------------------------------------------------------------------------- 1 | // ====================================================================== 2 | // \title LedTester.cpp 3 | // \author ortega 4 | // \brief cpp file for Led component test harness implementation class 5 | // ====================================================================== 6 | 7 | #include "LedTester.hpp" 8 | 9 | namespace LedBlinker { 10 | 11 | // ---------------------------------------------------------------------- 12 | // Construction and destruction 13 | // ---------------------------------------------------------------------- 14 | 15 | LedTester ::LedTester() : LedGTestBase("LedTester", LedTester::MAX_HISTORY_SIZE), component("Led") { 16 | this->initComponents(); 17 | this->connectPorts(); 18 | } 19 | 20 | LedTester ::~LedTester() { 21 | this->component.deinit(); 22 | } 23 | 24 | // ---------------------------------------------------------------------- 25 | // Tests 26 | // ---------------------------------------------------------------------- 27 | 28 | void LedTester ::testBlinking() { 29 | // This test will make use of parameters. So need to load them. 30 | this->component.loadParameters(); 31 | 32 | // Ensure LED stays off when blinking is disabled 33 | // The Led component defaults to blinking off 34 | this->invoke_to_run(0, 0); // invoke the 'run' port to simulate running one cycle 35 | this->component.doDispatch(); // Trigger execution of async port 36 | 37 | ASSERT_EVENTS_LedState_SIZE(0); // ensure no LedState change events we emitted 38 | 39 | ASSERT_from_gpioSet_SIZE(0); // ensure gpio LED wasn't set 40 | 41 | ASSERT_TLM_LedTransitions_SIZE(0); // ensure no LedTransitions were recorded 42 | 43 | // Send command to enable blinking 44 | this->sendCmd_BLINKING_ON_OFF(0, 0, Fw::On::ON); 45 | this->component.doDispatch(); // Trigger execution of async command 46 | ASSERT_CMD_RESPONSE_SIZE(1); // ensure a command response was emitted 47 | ASSERT_CMD_RESPONSE(0, Led::OPCODE_BLINKING_ON_OFF, 0, 48 | Fw::CmdResponse::OK); // ensure the expected command response was emitted 49 | 50 | // Step through 3 run cycles to observe LED turning on and off 3 times 51 | // Cycle 1: LED initalization->On 52 | this->invoke_to_run(0, 0); 53 | this->component.doDispatch(); // Trigger execution of async port 54 | ASSERT_EVENTS_LedState_SIZE(1); 55 | ASSERT_EVENTS_LedState(0, Fw::On::ON); 56 | ASSERT_from_gpioSet_SIZE(1); 57 | ASSERT_from_gpioSet(0, Fw::Logic::HIGH); 58 | ASSERT_TLM_LedTransitions_SIZE(1); 59 | ASSERT_TLM_LedTransitions(0, 1); 60 | 61 | // Cycle 2: LED On->Off 62 | this->invoke_to_run(0, 0); 63 | this->component.doDispatch(); // Trigger execution of async port 64 | ASSERT_EVENTS_LedState_SIZE(2); 65 | ASSERT_EVENTS_LedState(1, Fw::On::OFF); 66 | ASSERT_from_gpioSet_SIZE(2); 67 | ASSERT_from_gpioSet(1, Fw::Logic::LOW); 68 | ASSERT_TLM_LedTransitions_SIZE(2); 69 | ASSERT_TLM_LedTransitions(1, 2); 70 | 71 | // Cycle 3: LED Off->On 72 | this->invoke_to_run(0, 0); 73 | this->component.doDispatch(); // Trigger execution of async port 74 | ASSERT_EVENTS_LedState_SIZE(3); 75 | ASSERT_EVENTS_LedState(2, Fw::On::ON); 76 | ASSERT_from_gpioSet_SIZE(3); 77 | ASSERT_from_gpioSet(2, Fw::Logic::HIGH); 78 | ASSERT_TLM_LedTransitions_SIZE(3); 79 | ASSERT_TLM_LedTransitions(2, 3); 80 | } 81 | 82 | void LedTester ::testBlinkInterval() { 83 | // Enable LED Blinking 84 | this->sendCmd_BLINKING_ON_OFF(0, 0, Fw::On::ON); 85 | this->component.doDispatch(); // Trigger execution of async command 86 | 87 | // Adjust blink interval to 4 cycles 88 | U32 blinkInterval = 4; 89 | this->paramSet_BLINK_INTERVAL(blinkInterval, Fw::ParamValid::VALID); 90 | this->paramSend_BLINK_INTERVAL(0, 0); 91 | ASSERT_EVENTS_BlinkIntervalSet_SIZE(1); 92 | 93 | // Step through blinkInterval**2 cycles and verify blinkInterval transitions are observed 94 | for (U32 i = 0; i < blinkInterval * blinkInterval; i++) { 95 | this->invoke_to_run(0, 0); 96 | this->component.doDispatch(); // Trigger execution of async input port invocation 97 | } 98 | // Verify the LED has toggled on and off 4 times in 8 cycles 99 | ASSERT_EVENTS_LedState_SIZE(blinkInterval); 100 | ASSERT_from_gpioSet_SIZE(blinkInterval); 101 | ASSERT_TLM_LedTransitions(this->tlmHistory_LedTransitions->size() - 1, blinkInterval); 102 | } 103 | 104 | // ---------------------------------------------------------------------- 105 | // Handlers for typed from ports 106 | // ---------------------------------------------------------------------- 107 | 108 | Drv::GpioStatus LedTester ::from_gpioSet_handler(const FwIndexType portNum, const Fw::Logic& state) { 109 | this->pushFromPortEntry_gpioSet(state); 110 | return Drv::GpioStatus::OP_OK; 111 | } 112 | 113 | } // namespace LedBlinker 114 | -------------------------------------------------------------------------------- /LedBlinker/LedBlinkerDeployment/Top/LedBlinkerDeploymentTopology.cpp: -------------------------------------------------------------------------------- 1 | // ====================================================================== 2 | // \title LedBlinkerTopology.cpp 3 | // \brief cpp file containing the topology instantiation code 4 | // 5 | // ====================================================================== 6 | // Provides access to autocoded functions 7 | #include 8 | // Note: Uncomment when using Svc:TlmPacketizer 9 | //#include 10 | 11 | // Necessary project-specified types 12 | #include 13 | 14 | #include 15 | 16 | // Allows easy reference to objects in FPP/autocoder required namespaces 17 | using namespace LedBlinker; 18 | 19 | // Instantiate a malloc allocator for cmdSeq buffer allocation 20 | Fw::MallocAllocator mallocator; 21 | 22 | // The reference topology divides the incoming clock signal (1Hz) into sub-signals: 1Hz, 1/2Hz, and 1/4Hz with 0 offset 23 | Svc::RateGroupDriver::DividerSet rateGroupDivisorsSet{{{1, 0}, {2, 0}, {4, 0}}}; 24 | 25 | // Rate groups may supply a context token to each of the attached children whose purpose is set by the project. The 26 | // reference topology sets each token to zero as these contexts are unused in this project. 27 | U32 rateGroup1Context[Svc::ActiveRateGroup::CONNECTION_COUNT_MAX] = {}; 28 | U32 rateGroup2Context[Svc::ActiveRateGroup::CONNECTION_COUNT_MAX] = {}; 29 | U32 rateGroup3Context[Svc::ActiveRateGroup::CONNECTION_COUNT_MAX] = {}; 30 | 31 | enum TopologyConstants { 32 | COMM_PRIORITY = 100, 33 | }; 34 | 35 | // Public functions for use in main program are namespaced with deployment module name 36 | namespace LedBlinker { 37 | 38 | /** 39 | * \brief configure/setup components in project-specific way 40 | * 41 | * This is a *helper* function which configures/sets up each component requiring project specific input. This includes 42 | * allocating resources, passing-in arguments, etc. This function may be inlined into the topology setup function if 43 | * desired, but is extracted here for clarity. 44 | */ 45 | void configureTopology() { 46 | // Rate group driver needs a divisor list 47 | rateGroupDriver.configure(rateGroupDivisorsSet); 48 | 49 | // Rate groups require context arrays. 50 | rateGroup1.configure(rateGroup1Context, FW_NUM_ARRAY_ELEMENTS(rateGroup1Context)); 51 | rateGroup2.configure(rateGroup2Context, FW_NUM_ARRAY_ELEMENTS(rateGroup2Context)); 52 | rateGroup3.configure(rateGroup3Context, FW_NUM_ARRAY_ELEMENTS(rateGroup3Context)); 53 | 54 | // Command sequencer needs to allocate memory to hold contents of command sequences 55 | cmdSeq.allocateBuffer(0, mallocator, 5 * 1024); 56 | 57 | Os::File::Status status = gpioDriver.open("/dev/gpiochip4", 13, Drv::LinuxGpioDriver::GpioConfiguration::GPIO_OUTPUT); 58 | if (status != Os::File::Status::OP_OK) { 59 | Fw::Logger::log("[ERROR] Failed to open GPIO pin\n"); 60 | } 61 | } 62 | 63 | 64 | void setupTopology(const TopologyState& state) { 65 | // Autocoded initialization. Function provided by autocoder. 66 | initComponents(state); 67 | // Autocoded id setup. Function provided by autocoder. 68 | setBaseIds(); 69 | // Autocoded connection wiring. Function provided by autocoder. 70 | connectComponents(); 71 | // Autocoded command registration. Function provided by autocoder. 72 | regCommands(); 73 | // Autocoded configuration. Function provided by autocoder. 74 | configComponents(state); 75 | if (state.hostname != nullptr && state.port != 0) { 76 | comDriver.configure(state.hostname, state.port); 77 | } 78 | // Project-specific component configuration. Function provided above. May be inlined, if desired. 79 | configureTopology(); 80 | // Autocoded parameter loading. Function provided by autocoder. 81 | loadParameters(); 82 | // Autocoded task kick-off (active components). Function provided by autocoder. 83 | startTasks(state); 84 | // Initialize socket communication if and only if there is a valid specification 85 | if (state.hostname != nullptr && state.port != 0) { 86 | Os::TaskString name("ReceiveTask"); 87 | // Uplink is configured for receive so a socket task is started 88 | comDriver.start(name, COMM_PRIORITY, Default::STACK_SIZE); 89 | } 90 | } 91 | 92 | void startRateGroups(const Fw::TimeInterval& interval) { 93 | // This timer drives the fundamental tick rate of the system. 94 | // Svc::RateGroupDriver will divide this down to the slower rate groups. 95 | // This call will block until the stopRateGroups() call is made. 96 | // For this Linux demo, that call is made from a signal handler. 97 | linuxTimer.startTimer(interval); 98 | } 99 | 100 | void stopRateGroups() { 101 | linuxTimer.quit(); 102 | } 103 | 104 | void teardownTopology(const TopologyState& state) { 105 | // Autocoded (active component) task clean-up. Functions provided by topology autocoder. 106 | stopTasks(state); 107 | freeThreads(state); 108 | 109 | // Other task clean-up. 110 | comDriver.stop(); 111 | (void)comDriver.join(); 112 | 113 | // Resource deallocation 114 | cmdSeq.deallocateBuffer(mallocator); 115 | 116 | tearDownComponents(state); 117 | } 118 | }; // namespace LedBlinker 119 | -------------------------------------------------------------------------------- /LedBlinker/LedBlinkerDeployment/Top/LedBlinkerDeploymentPackets.fppi: -------------------------------------------------------------------------------- 1 | telemetry packets LedBlinkerDeploymentPackets { 2 | 3 | packet CDH id 1 group 1 { 4 | CdhCore.cmdDisp.CommandsDispatched 5 | 6 | FileHandling.fileUplink.FilesReceived 7 | FileHandling.fileUplink.PacketsReceived 8 | FileHandling.fileDownlink.FilesSent 9 | FileHandling.fileDownlink.PacketsSent 10 | FileHandling.fileManager.CommandsExecuted 11 | 12 | LedBlinker.cmdSeq.CS_LoadCommands 13 | LedBlinker.cmdSeq.CS_CancelCommands 14 | LedBlinker.cmdSeq.CS_CommandsExecuted 15 | LedBlinker.cmdSeq.CS_SequencesCompleted 16 | ComCcsds.comQueue.comQueueDepth 17 | ComCcsds.comQueue.buffQueueDepth 18 | ComCcsds.commsBufferManager.TotalBuffs 19 | ComCcsds.commsBufferManager.CurrBuffs 20 | ComCcsds.commsBufferManager.HiBuffs 21 | #ComCcsds.tlmSend.SendLevel 22 | 23 | # LED Blinker telemetry channels 24 | LedBlinker.led.BlinkingState 25 | LedBlinker.led.LedTransitions 26 | 27 | LedBlinker.rateGroup1.RgMaxTime 28 | LedBlinker.rateGroup2.RgMaxTime 29 | LedBlinker.rateGroup3.RgMaxTime 30 | } 31 | 32 | packet CDHErrors id 2 group 1 { 33 | CdhCore.$health.PingLateWarnings 34 | 35 | FileHandling.fileUplink.Warnings 36 | FileHandling.fileDownlink.Warnings 37 | FileHandling.fileManager.Errors 38 | 39 | LedBlinker.cmdSeq.CS_Errors 40 | ComCcsds.commsBufferManager.NoBuffs 41 | ComCcsds.commsBufferManager.EmptyBuffs 42 | 43 | LedBlinker.rateGroup1.RgCycleSlips 44 | LedBlinker.rateGroup2.RgCycleSlips 45 | LedBlinker.rateGroup3.RgCycleSlips 46 | } 47 | 48 | packet SystemRes1 id 5 group 2 { 49 | LedBlinker.systemResources.MEMORY_TOTAL 50 | LedBlinker.systemResources.MEMORY_USED 51 | LedBlinker.systemResources.NON_VOLATILE_TOTAL 52 | LedBlinker.systemResources.NON_VOLATILE_FREE 53 | } 54 | 55 | packet SystemRes3 id 6 group 2 { 56 | LedBlinker.systemResources.CPU 57 | LedBlinker.systemResources.CPU_00 58 | LedBlinker.systemResources.CPU_01 59 | LedBlinker.systemResources.CPU_02 60 | LedBlinker.systemResources.CPU_03 61 | LedBlinker.systemResources.CPU_04 62 | LedBlinker.systemResources.CPU_05 63 | LedBlinker.systemResources.CPU_06 64 | LedBlinker.systemResources.CPU_07 65 | LedBlinker.systemResources.CPU_08 66 | LedBlinker.systemResources.CPU_09 67 | LedBlinker.systemResources.CPU_10 68 | LedBlinker.systemResources.CPU_11 69 | LedBlinker.systemResources.CPU_12 70 | LedBlinker.systemResources.CPU_13 71 | LedBlinker.systemResources.CPU_14 72 | LedBlinker.systemResources.CPU_15 73 | } 74 | 75 | packet DataProducts id 21 group 3 { 76 | DataProducts.dpCat.CatalogDps 77 | DataProducts.dpCat.DpsSent 78 | 79 | DataProducts.dpMgr.NumSuccessfulAllocations 80 | DataProducts.dpMgr.NumFailedAllocations 81 | DataProducts.dpMgr.NumDataProducts 82 | DataProducts.dpMgr.NumBytes 83 | 84 | DataProducts.dpWriter.NumBuffersReceived 85 | DataProducts.dpWriter.NumBytesWritten 86 | DataProducts.dpWriter.NumSuccessfulWrites 87 | DataProducts.dpWriter.NumFailedWrites 88 | DataProducts.dpWriter.NumErrors 89 | 90 | DataProducts.dpBufferManager.TotalBuffs 91 | DataProducts.dpBufferManager.CurrBuffs 92 | DataProducts.dpBufferManager.HiBuffs 93 | DataProducts.dpBufferManager.NoBuffs 94 | DataProducts.dpBufferManager.EmptyBuffs 95 | } 96 | 97 | packet Version1 id 22 group 2 { 98 | CdhCore.version.FrameworkVersion 99 | CdhCore.version.ProjectVersion 100 | } 101 | 102 | packet Version_Library1 id 23 group 2 { 103 | CdhCore.version.LibraryVersion01 104 | CdhCore.version.LibraryVersion02 105 | } 106 | 107 | packet Version_Library2 id 24 group 2 { 108 | CdhCore.version.LibraryVersion03 109 | CdhCore.version.LibraryVersion04 110 | } 111 | 112 | packet Version_Library3 id 25 group 2 { 113 | CdhCore.version.LibraryVersion05 114 | CdhCore.version.LibraryVersion06 115 | } 116 | 117 | packet Version_Library4 id 26 group 2 { 118 | CdhCore.version.LibraryVersion07 119 | CdhCore.version.LibraryVersion08 120 | } 121 | 122 | packet Version_Library5 id 27 group 2 { 123 | CdhCore.version.LibraryVersion09 124 | CdhCore.version.LibraryVersion10 125 | } 126 | 127 | packet Version_Custom1 id 28 group 2 { 128 | CdhCore.version.CustomVersion01 129 | } 130 | 131 | packet Version_Custom2 id 29 group 2 { 132 | CdhCore.version.CustomVersion02 133 | } 134 | 135 | packet Version_Custom3 id 30 group 2 { 136 | CdhCore.version.CustomVersion03 137 | } 138 | 139 | packet Version_Custom4 id 31 group 2 { 140 | CdhCore.version.CustomVersion04 141 | } 142 | 143 | packet Version_Custom5 id 32 group 2 { 144 | CdhCore.version.CustomVersion05 145 | } 146 | 147 | packet Version_Custom6 id 33 group 2 { 148 | CdhCore.version.CustomVersion06 149 | } 150 | 151 | packet Version_Custom7 id 34 group 2 { 152 | CdhCore.version.CustomVersion07 153 | } 154 | 155 | packet Version_Custom8 id 35 group 2 { 156 | CdhCore.version.CustomVersion08 157 | } 158 | 159 | packet Version_Custom9 id 36 group 2 { 160 | CdhCore.version.CustomVersion09 161 | } 162 | 163 | packet Version_Custom10 id 37 group 2 { 164 | CdhCore.version.CustomVersion10 165 | } 166 | 167 | } omit { 168 | CdhCore.cmdDisp.CommandErrors 169 | } 170 | -------------------------------------------------------------------------------- /LedBlinker/LedBlinkerDeployment/Top/topology.fpp: -------------------------------------------------------------------------------- 1 | module LedBlinker { 2 | 3 | # ---------------------------------------------------------------------- 4 | # Symbolic constants for port numbers 5 | # ---------------------------------------------------------------------- 6 | 7 | enum Ports_RateGroups { 8 | rateGroup1 9 | rateGroup2 10 | rateGroup3 11 | } 12 | 13 | topology LedBlinkerDeployment { 14 | 15 | # ---------------------------------------------------------------------- 16 | # Subtopology imports 17 | # ---------------------------------------------------------------------- 18 | import CdhCore.Subtopology 19 | import ComCcsds.Subtopology 20 | import DataProducts.Subtopology 21 | import FileHandling.Subtopology 22 | 23 | # ---------------------------------------------------------------------- 24 | # Instances used in the topology 25 | # ---------------------------------------------------------------------- 26 | instance chronoTime 27 | instance rateGroup1 28 | instance rateGroup2 29 | instance rateGroup3 30 | instance rateGroupDriver 31 | instance systemResources 32 | instance linuxTimer 33 | instance comDriver 34 | instance cmdSeq 35 | instance led 36 | instance gpioDriver 37 | 38 | # ---------------------------------------------------------------------- 39 | # Pattern graph specifiers 40 | # ---------------------------------------------------------------------- 41 | 42 | command connections instance CdhCore.cmdDisp 43 | event connections instance CdhCore.events 44 | telemetry connections instance CdhCore.tlmSend 45 | text event connections instance CdhCore.textLogger 46 | health connections instance CdhCore.$health 47 | param connections instance FileHandling.prmDb 48 | time connections instance chronoTime 49 | 50 | # ---------------------------------------------------------------------- 51 | # Telemetry packets (only used when TlmPacketizer is used) 52 | # ---------------------------------------------------------------------- 53 | 54 | # include "LedBlinkerPackets.fppi" 55 | 56 | # ---------------------------------------------------------------------- 57 | # Direct graph specifiers 58 | # ---------------------------------------------------------------------- 59 | 60 | connections ComCcsds_CdhCore { 61 | # Core events and telemetry to communication queue 62 | CdhCore.events.PktSend -> ComCcsds.comQueue.comPacketQueueIn[ComCcsds.Ports_ComPacketQueue.EVENTS] 63 | CdhCore.tlmSend.PktSend -> ComCcsds.comQueue.comPacketQueueIn[ComCcsds.Ports_ComPacketQueue.TELEMETRY] 64 | 65 | # Router to Command Dispatcher 66 | ComCcsds.fprimeRouter.commandOut -> CdhCore.cmdDisp.seqCmdBuff 67 | CdhCore.cmdDisp.seqCmdStatus -> ComCcsds.fprimeRouter.cmdResponseIn 68 | 69 | } 70 | 71 | connections ComCcsds_FileHandling { 72 | # File Downlink to Communication Queue 73 | FileHandling.fileDownlink.bufferSendOut -> ComCcsds.comQueue.bufferQueueIn[ComCcsds.Ports_ComBufferQueue.FILE] 74 | ComCcsds.comQueue.bufferReturnOut[ComCcsds.Ports_ComBufferQueue.FILE] -> FileHandling.fileDownlink.bufferReturn 75 | 76 | # Router to File Uplink 77 | ComCcsds.fprimeRouter.fileOut -> FileHandling.fileUplink.bufferSendIn 78 | FileHandling.fileUplink.bufferSendOut -> ComCcsds.fprimeRouter.fileBufferReturnIn 79 | } 80 | 81 | connections Communications { 82 | # ComDriver buffer allocations 83 | comDriver.allocate -> ComCcsds.commsBufferManager.bufferGetCallee 84 | comDriver.deallocate -> ComCcsds.commsBufferManager.bufferSendIn 85 | 86 | # ComDriver <-> ComStub (Uplink) 87 | comDriver.$recv -> ComCcsds.comStub.drvReceiveIn 88 | ComCcsds.comStub.drvReceiveReturnOut -> comDriver.recvReturnIn 89 | 90 | # ComStub <-> ComDriver (Downlink) 91 | ComCcsds.comStub.drvSendOut -> comDriver.$send 92 | comDriver.ready -> ComCcsds.comStub.drvConnected 93 | } 94 | 95 | connections FileHandling_DataProducts { 96 | # Data Products to File Downlink 97 | DataProducts.dpCat.fileOut -> FileHandling.fileDownlink.SendFile 98 | FileHandling.fileDownlink.FileComplete -> DataProducts.dpCat.fileDone 99 | } 100 | 101 | connections RateGroups { 102 | # LinuxTimer to drive rate group 103 | linuxTimer.CycleOut -> rateGroupDriver.CycleIn 104 | 105 | # Rate group 1 106 | rateGroupDriver.CycleOut[Ports_RateGroups.rateGroup1] -> rateGroup1.CycleIn 107 | rateGroup1.RateGroupMemberOut[0] -> CdhCore.tlmSend.Run 108 | rateGroup1.RateGroupMemberOut[1] -> FileHandling.fileDownlink.Run 109 | rateGroup1.RateGroupMemberOut[2] -> systemResources.run 110 | rateGroup1.RateGroupMemberOut[3] -> ComCcsds.comQueue.run 111 | rateGroup1.RateGroupMemberOut[4] -> ComCcsds.aggregator.timeout 112 | 113 | # Rate group 2 114 | rateGroupDriver.CycleOut[Ports_RateGroups.rateGroup2] -> rateGroup2.CycleIn 115 | rateGroup2.RateGroupMemberOut[0] -> cmdSeq.schedIn 116 | 117 | # Rate group 3 118 | rateGroupDriver.CycleOut[Ports_RateGroups.rateGroup3] -> rateGroup3.CycleIn 119 | rateGroup3.RateGroupMemberOut[0] -> CdhCore.$health.Run 120 | rateGroup3.RateGroupMemberOut[1] -> ComCcsds.commsBufferManager.schedIn 121 | rateGroup3.RateGroupMemberOut[2] -> DataProducts.dpBufferManager.schedIn 122 | rateGroup3.RateGroupMemberOut[3] -> DataProducts.dpWriter.schedIn 123 | rateGroup3.RateGroupMemberOut[4] -> DataProducts.dpMgr.schedIn 124 | } 125 | 126 | connections CdhCore_cmdSeq { 127 | # Command Sequencer 128 | cmdSeq.comCmdOut -> CdhCore.cmdDisp.seqCmdBuff 129 | CdhCore.cmdDisp.seqCmdStatus -> cmdSeq.cmdResponseIn 130 | } 131 | 132 | # Named connection group 133 | connections LedBlinker { 134 | # Rate Group 1 (1Hz cycle) ouput is connected to led's run input 135 | rateGroup1.RateGroupMemberOut[5] -> led.run 136 | # led's gpioSet output is connected to gpioDriver's gpioWrite input 137 | led.gpioSet -> gpioDriver.gpioWrite 138 | 139 | } 140 | 141 | 142 | } 143 | 144 | } 145 | -------------------------------------------------------------------------------- /LedBlinker/Components/Led/coverage/coverage.functions.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | GCC Code Coverage Report 7 | 8 | 9 | 10 | 11 | 12 |
13 |

GCC Code Coverage Report

14 | 15 |
16 | 17 |
18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 |
Directory:Components/Led/
Date:2023-04-17 15:08:37
29 |
30 | 31 |
32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 |
ExecTotalCoverage
Lines:4444100.0%
Functions:7887.5%
Branches:457857.7%
58 |
59 |
60 | 61 |
62 |
63 | 64 | 66 | 67 |
68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 79 | 82 | 85 | 88 | 89 | 90 | 93 | 96 | 99 | 102 | 103 | 104 | 107 | 110 | 113 | 116 | 117 | 118 | 121 | 124 | 127 | 130 | 131 | 132 | 135 | 138 | 141 | 144 | 145 | 146 | 149 | 152 | 155 | 158 | 159 | 160 | 163 | 166 | 169 | 172 | 173 | 174 | 177 | 180 | 183 | 186 | 187 |
FunctionFileLineCall count
77 | _ZN10Components3Led11run_handlerEij 78 | 80 | Components/Led/Led.cpp 81 | 83 | 42 84 | 86 | called 12 times 87 |
91 | _ZN10Components3Led16parameterUpdatedEj 92 | 94 | Components/Led/Led.cpp 95 | 97 | 25 98 | 100 | called 1 time 101 |
105 | _ZN10Components3Led26BLINKING_ON_OFF_cmdHandlerEjjN2Fw2OnE 106 | 108 | Components/Led/Led.cpp 109 | 111 | 83 112 | 114 | called 2 times 115 |
119 | _ZN10Components3LedC1EPKc 120 | 122 | Components/Led/Led.cpp 123 | 125 | 16 126 | 128 | called 2 times 129 |
133 | _ZN10Components3LedC2EPKc 134 | 136 | Components/Led/Led.cpp 137 | 139 | 16 140 | 142 | called 2 times 143 |
147 | _ZN10Components3LedD0Ev 148 | 150 | Components/Led/Led.cpp 151 | 153 | 23 154 | 156 | not called 157 |
161 | _ZN10Components3LedD1Ev 162 | 164 | Components/Led/Led.cpp 165 | 167 | 23 168 | 170 | called 2 times 171 |
175 | _ZN10Components3LedD2Ev 176 | 178 | Components/Led/Led.cpp 179 | 181 | 23 182 | 184 | called 2 times 185 |
188 |
189 |
190 | 191 | 194 | 195 | 196 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LedBlinker/Components/Led/coverage/coverage.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: sans-serif; 3 | --tab_size: 4; 4 | } 5 | 6 | .theme-green, .theme-blue { 7 | --unknown_color: lightgray; 8 | --low_color: #FF6666; 9 | --medium_color: #F9FD63; 10 | --high_color: #85E485; 11 | --covered_color: #85E485; 12 | --uncovered_color: #FF8C8C; 13 | --excluded_color: #53BFFD; 14 | --warning_color: orangered; 15 | --takenBranch_color: green; 16 | --notTakenBranch_color: red; 17 | --takenDecision_color: green; 18 | --uncheckedDecision_color: darkorange; 19 | --notTakenDecision_color: red; 20 | --invokedCall_color: green; 21 | --notInvokedCall_color: red; 22 | } 23 | 24 | .theme-blue { 25 | --high_color: #66B4FF; 26 | --covered_color: #66B4Ff; 27 | --takenBranch_color: blue; 28 | } 29 | 30 | body 31 | { 32 | color: #000000; 33 | background-color: #FFFFFF; 34 | } 35 | 36 | h1 37 | { 38 | text-align: center; 39 | margin: 0; 40 | padding-bottom: 10px; 41 | font-size: 20pt; 42 | font-weight: bold; 43 | } 44 | 45 | hr 46 | { 47 | background-color: navy; 48 | height: 2px; 49 | border: 0; 50 | } 51 | 52 | /* Link formats: use maroon w/underlines */ 53 | a:link 54 | { 55 | color: navy; 56 | text-decoration: underline; 57 | } 58 | a:visited 59 | { 60 | color: maroon; 61 | text-decoration: underline; 62 | } 63 | 64 | /*** Summary formats ***/ 65 | 66 | .summary 67 | { 68 | display: flex; 69 | flex-flow: row wrap; 70 | max-width: 100%; 71 | justify-content: flex-start; 72 | } 73 | 74 | .summary > table 75 | { 76 | flex: 1 0 7em; 77 | border: 0; 78 | } 79 | 80 | .summary > :last-child { 81 | margin-left: auto; 82 | } 83 | 84 | table.legend 85 | { 86 | color: black; 87 | display: flex; 88 | flex-flow: row wrap; 89 | justify-content: flex-start; 90 | } 91 | 92 | table.legend th[scope=row] 93 | { 94 | font-weight: normal; 95 | text-align: right; 96 | white-space: nowrap; 97 | } 98 | 99 | table.legend td 100 | { 101 | color: blue; 102 | text-align: left; 103 | white-space: nowrap; 104 | padding-left: 5px; 105 | } 106 | 107 | table.legend td.legend 108 | { 109 | color: black; 110 | font-size: 80%; 111 | } 112 | 113 | table.legend td.warning_text 114 | { 115 | color: var(--warning_color); 116 | } 117 | 118 | table.coverage td, 119 | table.coverage th 120 | { 121 | text-align: right; 122 | color: black; 123 | font-weight: normal; 124 | white-space: nowrap; 125 | padding-left: 5px; 126 | padding-right: 4px; 127 | } 128 | 129 | table.coverage td 130 | { 131 | background-color: LightSteelBlue; 132 | } 133 | 134 | table.coverage th[scope=row] 135 | { 136 | color: black; 137 | font-weight: normal; 138 | white-space: nowrap; 139 | } 140 | 141 | table.coverage th[scope=col] 142 | { 143 | color: blue; 144 | font-weight: normal; 145 | white-space: nowrap; 146 | } 147 | 148 | table.legend span 149 | { 150 | margin-right: 4px; 151 | padding: 2px; 152 | } 153 | 154 | table.legend span.coverage-unknown, 155 | table.legend span.coverage-none, 156 | table.legend span.coverage-low, 157 | table.legend span.coverage-medium, 158 | table.legend span.coverage-high 159 | { 160 | padding-left: 3px; 161 | padding-right: 3px; 162 | } 163 | 164 | table.legend span.coverage-unknown, 165 | table.coverage td.coverage-unknown, 166 | table.file-list td.coverage-unknow 167 | { 168 | background-color: var(--unknown_color) !important; 169 | } 170 | 171 | table.legend span.coverage-none, 172 | table.legend span.coverage-low, 173 | table.coverage td.coverage-none, 174 | table.coverage td.coverage-low, 175 | table.file-list td.coverage-none, 176 | table.file-list td.coverage-low 177 | { 178 | background-color: var(--low_color) !important; 179 | } 180 | 181 | table.legend span.coverage-medium, 182 | table.coverage td.coverage-medium, 183 | table.file-list td.coverage-medium 184 | { 185 | background-color: var(--medium_color) !important; 186 | } 187 | 188 | table.legend span.coverage-high, 189 | table.coverage td.coverage-high, 190 | table.file-list td.coverage-high 191 | { 192 | background-color: var(--high_color) !important; 193 | } 194 | /*** End of Summary formats ***/ 195 | /*** Meter formats ***/ 196 | 197 | /* Common */ 198 | meter { 199 | -moz-appearance: none; 200 | 201 | width: 30vw; 202 | min-width: 4em; 203 | max-width: 15em; 204 | height: 0.75em; 205 | padding: 0; 206 | vertical-align: baseline; 207 | margin-top: 3px; 208 | /* Outer background for Mozilla */ 209 | background: none; 210 | background-color: whitesmoke; 211 | } 212 | 213 | /* Webkit */ 214 | 215 | meter::-webkit-meter-bar { 216 | /* Outer background for Webkit */ 217 | background: none; 218 | background-color: whitesmoke; 219 | height: 0.75em; 220 | border-radius: 0px; 221 | } 222 | 223 | meter::-webkit-meter-optimum-value, 224 | meter::-webkit-meter-suboptimum-value, 225 | meter::-webkit-meter-even-less-good-value 226 | { 227 | /* Inner shadow for Webkit */ 228 | border: solid 1px black; 229 | } 230 | 231 | meter.coverage-none::-webkit-meter-optimum-value, 232 | meter.coverage-low::-webkit-meter-optimum-value 233 | { 234 | background: var(--low_color); 235 | } 236 | 237 | meter.coverage-medium::-webkit-meter-optimum-value 238 | { 239 | background: var(--medium_color); 240 | } 241 | 242 | meter.coverage-high::-webkit-meter-optimum-value 243 | { 244 | background: var(--high_color); 245 | } 246 | 247 | /* Mozilla */ 248 | 249 | meter::-moz-meter-bar 250 | { 251 | box-sizing: border-box; 252 | } 253 | 254 | meter:-moz-meter-optimum::-moz-meter-bar, 255 | meter:-moz-meter-sub-optimum::-moz-meter-bar, 256 | meter:-moz-meter-sub-sub-optimum::-moz-meter-bar 257 | { 258 | /* Inner shadow for Mozilla */ 259 | border: solid 1px black; 260 | } 261 | 262 | meter.coverage-none:-moz-meter-optimum::-moz-meter-bar, 263 | meter.coverage-low:-moz-meter-optimum::-moz-meter-bar 264 | { 265 | background: var(--low_color); 266 | } 267 | 268 | meter.coverage-medium:-moz-meter-optimum::-moz-meter-bar 269 | { 270 | background: var(--medium_color); 271 | } 272 | 273 | meter.coverage-high:-moz-meter-optimum::-moz-meter-bar 274 | { 275 | background: var(--high_color); 276 | } 277 | 278 | /*** End of Meter formats ***/ 279 | .file-list td, .file-list th { 280 | padding: 0 10px; 281 | font-weight: bold; 282 | } 283 | 284 | .file-list th[scope^=col] 285 | { 286 | text-align: center; 287 | color: white; 288 | background-color: SteelBlue; 289 | font-size: 120%; 290 | } 291 | 292 | .file-list th[scope=row] 293 | { 294 | text-align: left; 295 | color: black; 296 | font-family: monospace; 297 | font-weight: bold; 298 | font-size: 110%; 299 | } 300 | 301 | .file-list tr > td, 302 | .file-list tr > th { 303 | background: aliceblue; 304 | } 305 | 306 | .file-list tr:nth-child(even) > td, 307 | .file-list tr:nth-child(even) > th { 308 | background: LightSteelBlue 309 | } 310 | 311 | .file-list tr:hover > td, 312 | .file-list tr:hover > th[scope=row] 313 | { 314 | background-color: #ddd; 315 | } 316 | td.CoverValue 317 | { 318 | text-align: right; 319 | white-space: nowrap; 320 | } 321 | 322 | td.coveredLine, 323 | span.coveredLine 324 | { 325 | background-color: var(--covered_color) !important; 326 | } 327 | 328 | td.uncoveredLine, 329 | span.uncoveredLine 330 | { 331 | background-color: var(--uncovered_color) !important; 332 | } 333 | 334 | td.excludedLine, 335 | span.excludedLine 336 | { 337 | background-color: var(--excluded_color) !important; 338 | } 339 | 340 | .linebranch, .linedecision, .linecall, .linecount 341 | { 342 | font-family: monospace; 343 | border-right: 1px gray solid; 344 | background-color: lightgray; 345 | text-align: right; 346 | } 347 | 348 | 349 | .linebranchDetails, .linedecisionDetails, .linecallDetails 350 | { 351 | position: relative; 352 | } 353 | .linebranchSummary, .linedecisionSummary, .linecallSummary 354 | { 355 | cursor: help; 356 | } 357 | .linebranchContents, .linedecisionContents, .linecallContents 358 | { 359 | font-family: sans-serif; 360 | font-size: small; 361 | text-align: left; 362 | position: absolute; 363 | width: 15em; 364 | padding: 1em; 365 | background: white; 366 | border: solid gray 1px; 367 | box-shadow: 5px 5px 10px gray; 368 | z-index: 1; /* show in front of the table entries */ 369 | } 370 | 371 | .takenBranch 372 | { 373 | color: var(--takenBranch_color) !important; 374 | } 375 | 376 | .notTakenBranch 377 | { 378 | color: var(--notTakenBranch_color) !important; 379 | } 380 | 381 | .takenDecision 382 | { 383 | color: var(--takenDecision_color) !important; 384 | } 385 | 386 | .notTakenDecision 387 | { 388 | color: var(--notTakenDecision_color) !important; 389 | } 390 | 391 | .uncheckedDecision 392 | { 393 | color: var(--uncheckedDecision_color) !important; 394 | } 395 | 396 | .invokedCall 397 | { 398 | color: var(--invokedCall_color) !important; 399 | } 400 | 401 | .notInvokedCall 402 | { 403 | color: var(--notInvokedCall_color) !important; 404 | } 405 | 406 | .src 407 | { 408 | padding-left: 12px; 409 | text-align: left; 410 | 411 | font-family: monospace; 412 | white-space: pre; 413 | 414 | tab-size: var(--tab_size); 415 | -moz-tab-size: var(--tab_size); 416 | } 417 | 418 | span.takenBranch, 419 | span.notTakenBranch, 420 | span.takenDecision, 421 | span.notTakenDecision, 422 | span.uncheckedDecision 423 | { 424 | font-family: monospace; 425 | font-weight: bold; 426 | } 427 | 428 | pre 429 | { 430 | height : 15px; 431 | margin-top: 0; 432 | margin-bottom: 0; 433 | } 434 | 435 | .listOfFunctions td, .listOfFunctions th { 436 | padding: 0 10px; 437 | } 438 | .listOfFunctions th 439 | { 440 | text-align: center; 441 | color: white; 442 | background-color: SteelBlue; 443 | } 444 | .listOfFunctions tr > td { 445 | background: aliceblue; 446 | } 447 | .listOfFunctions tr:nth-child(even) > td { 448 | background: LightSteelBlue 449 | } 450 | .listOfFunctions tr:hover > td 451 | { 452 | background-color: #ddd; 453 | } 454 | .listOfFunctions tr > td > a 455 | { 456 | text-decoration: none; 457 | color: inherit; 458 | } 459 | 460 | .source-line 461 | { 462 | height : 15px; 463 | margin-top: 0; 464 | margin-bottom: 0; 465 | } 466 | 467 | .lineno 468 | { 469 | background-color: #EFE383; 470 | border-right: 1px solid #BBB15F; 471 | text-align: right; 472 | unicode-bidi: embed; 473 | font-family: monospace; 474 | white-space: pre; 475 | } 476 | 477 | .lineno > a 478 | { 479 | text-decoration: none; 480 | color: inherit; 481 | } 482 | 483 | .file-list 484 | { 485 | margin: 1em auto; 486 | border: 0; 487 | border-spacing: 1px; 488 | } 489 | 490 | .file-source table 491 | { 492 | border-spacing: 0; 493 | } 494 | 495 | .file-source table td, 496 | .file-source table th 497 | { 498 | padding: 1px 10px; 499 | } 500 | 501 | .file-source table th 502 | { 503 | font-family: monospace; 504 | font-weight: bold; 505 | } 506 | 507 | .file-source table td:last-child 508 | { 509 | width: 100%; 510 | } 511 | footer 512 | { 513 | text-align: center; 514 | padding-top: 3px; 515 | } 516 | 517 | /* pygments syntax highlighting */ 518 | pre { line-height: 125%; } 519 | td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } 520 | span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } 521 | td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } 522 | span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } 523 | .hll { background-color: #ffffcc } 524 | .c { color: #3D7B7B; font-style: italic } /* Comment */ 525 | .err { border: 1px solid #FF0000 } /* Error */ 526 | .k { color: #008000; font-weight: bold } /* Keyword */ 527 | .o { color: #666666 } /* Operator */ 528 | .ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */ 529 | .cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */ 530 | .cp { color: #9C6500 } /* Comment.Preproc */ 531 | .cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */ 532 | .c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */ 533 | .cs { color: #3D7B7B; font-style: italic } /* Comment.Special */ 534 | .gd { color: #A00000 } /* Generic.Deleted */ 535 | .ge { font-style: italic } /* Generic.Emph */ 536 | .gr { color: #E40000 } /* Generic.Error */ 537 | .gh { color: #000080; font-weight: bold } /* Generic.Heading */ 538 | .gi { color: #008400 } /* Generic.Inserted */ 539 | .go { color: #717171 } /* Generic.Output */ 540 | .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ 541 | .gs { font-weight: bold } /* Generic.Strong */ 542 | .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 543 | .gt { color: #0044DD } /* Generic.Traceback */ 544 | .kc { color: #008000; font-weight: bold } /* Keyword.Constant */ 545 | .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ 546 | .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ 547 | .kp { color: #008000 } /* Keyword.Pseudo */ 548 | .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ 549 | .kt { color: #B00040 } /* Keyword.Type */ 550 | .m { color: #666666 } /* Literal.Number */ 551 | .s { color: #BA2121 } /* Literal.String */ 552 | .na { color: #687822 } /* Name.Attribute */ 553 | .nb { color: #008000 } /* Name.Builtin */ 554 | .nc { color: #0000FF; font-weight: bold } /* Name.Class */ 555 | .no { color: #880000 } /* Name.Constant */ 556 | .nd { color: #AA22FF } /* Name.Decorator */ 557 | .ni { color: #717171; font-weight: bold } /* Name.Entity */ 558 | .ne { color: #CB3F38; font-weight: bold } /* Name.Exception */ 559 | .nf { color: #0000FF } /* Name.Function */ 560 | .nl { color: #767600 } /* Name.Label */ 561 | .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ 562 | .nt { color: #008000; font-weight: bold } /* Name.Tag */ 563 | .nv { color: #19177C } /* Name.Variable */ 564 | .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ 565 | .w { color: #bbbbbb } /* Text.Whitespace */ 566 | .mb { color: #666666 } /* Literal.Number.Bin */ 567 | .mf { color: #666666 } /* Literal.Number.Float */ 568 | .mh { color: #666666 } /* Literal.Number.Hex */ 569 | .mi { color: #666666 } /* Literal.Number.Integer */ 570 | .mo { color: #666666 } /* Literal.Number.Oct */ 571 | .sa { color: #BA2121 } /* Literal.String.Affix */ 572 | .sb { color: #BA2121 } /* Literal.String.Backtick */ 573 | .sc { color: #BA2121 } /* Literal.String.Char */ 574 | .dl { color: #BA2121 } /* Literal.String.Delimiter */ 575 | .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ 576 | .s2 { color: #BA2121 } /* Literal.String.Double */ 577 | .se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */ 578 | .sh { color: #BA2121 } /* Literal.String.Heredoc */ 579 | .si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */ 580 | .sx { color: #008000 } /* Literal.String.Other */ 581 | .sr { color: #A45A77 } /* Literal.String.Regex */ 582 | .s1 { color: #BA2121 } /* Literal.String.Single */ 583 | .ss { color: #19177C } /* Literal.String.Symbol */ 584 | .bp { color: #008000 } /* Name.Builtin.Pseudo */ 585 | .fm { color: #0000FF } /* Name.Function.Magic */ 586 | .vc { color: #19177C } /* Name.Variable.Class */ 587 | .vg { color: #19177C } /* Name.Variable.Global */ 588 | .vi { color: #19177C } /* Name.Variable.Instance */ 589 | .vm { color: #19177C } /* Name.Variable.Magic */ 590 | .il { color: #666666 } /* Literal.Number.Integer.Long */ -------------------------------------------------------------------------------- /LedBlinker/Components/Led/coverage/coverage.Led.cpp.5ec3b97ffe17af934b96682795bb24f6.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | GCC Code Coverage Report 7 | 8 | 9 | 10 | 11 | 12 |
13 |

GCC Code Coverage Report

14 | 15 |
16 | 17 |
18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 |
Directory:Components/Led/
File:Components/Led/Led.cpp
Date:2023-04-17 15:08:37
33 |
34 |
35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 |
ExecTotalCoverage
Lines:4444100.0%
Functions:7887.5%
Branches:457857.7%
61 |
62 |
63 | 64 |
65 |
66 | 67 | 168 | 169 |
170 |
171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 182 | 183 | 184 | 185 | 186 | 187 | 189 | 190 | 191 | 192 | 193 | 194 | 196 | 197 | 198 | 199 | 200 | 201 | 203 | 204 | 205 | 206 | 207 | 208 | 210 | 211 | 212 | 213 | 214 | 215 | 217 | 218 | 219 | 220 | 221 | 222 | 224 | 225 | 226 | 227 | 228 | 229 | 231 | 232 | 233 | 234 | 235 | 236 | 238 | 239 | 240 | 241 | 242 | 243 | 245 | 246 | 247 | 248 | 249 | 250 | 252 | 253 | 254 | 255 | 256 | 257 | 259 | 260 | 261 | 262 | 263 | 264 | 266 | 267 | 268 | 269 | 270 | 271 | 273 | 274 | 275 | 276 | 277 | 278 | 280 | 281 | 282 | 283 | 284 | 285 | 287 | 288 | 289 | 290 | 291 | 292 | 301 | 302 | 303 | 304 | 305 | 306 | 308 | 309 | 310 | 311 | 312 | 313 | 315 | 316 | 317 | 318 | 319 | 320 | 322 | 323 | 324 | 325 | 326 | 327 | 329 | 330 | 331 | 332 | 333 | 334 | 336 | 337 | 338 | 339 | 340 | 341 | 343 | 344 | 345 | 346 | 347 | 348 | 350 | 351 | 352 | 353 | 354 | 355 | 357 | 358 | 359 | 360 | 361 | 362 | 364 | 365 | 366 | 367 | 368 | 369 | 371 | 372 | 373 | 374 | 375 | 376 | 385 | 386 | 387 | 388 | 389 | 390 | 392 | 393 | 394 | 395 | 396 | 397 | 399 | 400 | 401 | 402 | 403 | 404 | 413 | 414 | 415 | 416 | 417 | 418 | 431 | 432 | 433 | 434 | 435 | 436 | 438 | 439 | 440 | 441 | 442 | 443 | 452 | 453 | 454 | 455 | 456 | 457 | 459 | 460 | 461 | 462 | 463 | 464 | 466 | 467 | 468 | 469 | 470 | 471 | 473 | 474 | 475 | 476 | 477 | 478 | 480 | 481 | 482 | 483 | 484 | 485 | 487 | 488 | 489 | 490 | 491 | 492 | 494 | 495 | 496 | 497 | 498 | 499 | 501 | 502 | 503 | 504 | 505 | 506 | 508 | 509 | 510 | 511 | 512 | 513 | 515 | 516 | 517 | 518 | 519 | 520 | 522 | 523 | 524 | 525 | 526 | 527 | 536 | 537 | 538 | 539 | 540 | 541 | 543 | 544 | 545 | 546 | 547 | 548 | 550 | 551 | 552 | 553 | 554 | 555 | 570 | 571 | 572 | 573 | 574 | 575 | 577 | 578 | 579 | 580 | 581 | 582 | 584 | 585 | 586 | 587 | 588 | 589 | 598 | 599 | 600 | 601 | 602 | 603 | 612 | 613 | 614 | 615 | 616 | 617 | 619 | 620 | 621 | 622 | 623 | 624 | 637 | 638 | 639 | 640 | 641 | 642 | 651 | 652 | 653 | 654 | 655 | 656 | 669 | 670 | 671 | 672 | 673 | 674 | 683 | 684 | 685 | 686 | 687 | 688 | 690 | 691 | 692 | 693 | 694 | 695 | 697 | 698 | 699 | 700 | 701 | 702 | 704 | 705 | 706 | 707 | 708 | 709 | 722 | 723 | 724 | 725 | 726 | 727 | 729 | 730 | 731 | 732 | 733 | 734 | 745 | 746 | 747 | 748 | 749 | 750 | 752 | 753 | 754 | 755 | 756 | 757 | 759 | 760 | 761 | 762 | 763 | 764 | 775 | 776 | 777 | 778 | 779 | 780 | 793 | 794 | 795 | 796 | 797 | 798 | 800 | 801 | 802 | 803 | 804 | 805 | 816 | 817 | 818 | 819 | 820 | 821 | 830 | 831 | 832 | 833 | 834 | 835 | 837 | 838 | 839 | 840 | 841 | 842 | 844 | 845 | 846 | 847 | 848 | 849 | 851 | 852 | 853 | 854 | 855 | 856 | 858 | 859 | 860 | 861 | 862 | 863 | 872 | 873 | 874 | 875 | 876 | 877 | 879 | 880 | 881 | 882 | 883 | 884 | 886 | 887 | 888 | 889 | 890 | 891 | 893 | 894 | 895 | 896 | 897 | 898 | 900 | 901 | 902 | 903 | 904 | 905 | 907 | 908 | 909 | 910 | 911 | 912 | 914 | 915 | 916 | 917 | 918 | 919 | 921 | 922 | 923 | 924 | 925 | 926 | 928 | 929 | 930 | 931 | 932 | 933 | 935 | 936 | 937 | 938 | 939 | 940 | 951 | 952 | 953 | 954 | 955 | 956 | 958 | 959 | 960 | 961 | 962 | 963 | 965 | 966 | 967 | 968 | 969 | 970 | 979 | 980 | 981 | 982 | 983 | 984 | 986 | 987 | 988 | 989 | 990 | 991 | 993 | 994 | 995 | 996 | 997 | 998 | 1000 | 1001 | 1002 | 1003 | 1004 | 1005 | 1007 | 1008 | 1009 | 1010 |
LineBranchExecSource
1 181 | // ======================================================================
2 188 | // \title Led.cpp
3 195 | // \author mstarch
4 202 | // \brief cpp file for Led component implementation class
5 209 | // ======================================================================
6 216 |
7 223 | #include <config/FpConfig.hpp>
8 230 | #include <Components/Led/Led.hpp>
9 237 |
10 244 | namespace Components {
11 251 |
12 258 | // ----------------------------------------------------------------------
13 265 | // Construction, initialization, and destruction
14 272 | // ----------------------------------------------------------------------
15 279 |
16 286 | 4Led ::Led(const char* const compName) : LedComponentBase(compName),
17 293 |
294 | 1/2 295 |
296 |
✓ Branch 0 taken 2 times.
297 |
✗ Branch 1 not taken.
298 |
299 |
300 |
2 state(Fw::On::OFF),
18 307 | 2 transitions(0),
19 314 | 2 count(0),
20 321 | 2 blinking(false)
21 328 | 6{}
22 335 |
23 342 | 4Led ::~Led() {}
24 349 |
25 356 | 1void Led ::parameterUpdated(FwPrmIdType id) {
26 363 | // Read back the parameter value
27 370 | 1 Fw::ParamValid isValid;
28 377 |
378 | 1/2 379 |
380 |
✓ Branch 0 taken 1 times.
381 |
✗ Branch 1 not taken.
382 |
383 |
384 |
1 U32 interval = this->paramGet_BLINK_INTERVAL(isValid);
29 391 |
30 398 | // Check the parameter ID is expected and the read was valid before sending the event
31 405 |
406 | 1/2 407 |
408 |
✓ Branch 0 taken 1 times.
409 |
✗ Branch 1 not taken.
410 |
411 |
412 |
1 U32 local_parameter_id = (id - this->getIdBase());
32 419 |
420 | 3/6 421 |
422 |
✓ Branch 0 taken 1 times.
423 |
✗ Branch 1 not taken.
424 |
✓ Branch 2 taken 1 times.
425 |
✗ Branch 3 not taken.
426 |
✓ Branch 4 taken 1 times.
427 |
✗ Branch 5 not taken.
428 |
429 |
430 |
1 if ((PARAMID_BLINK_INTERVAL == local_parameter_id ) && (Fw::ParamValid::VALID == isValid)) {
33 437 | // Emit the blink set event
34 444 |
445 | 1/2 446 |
447 |
✓ Branch 0 taken 1 times.
448 |
✗ Branch 1 not taken.
449 |
450 |
451 |
1 this->log_ACTIVITY_HI_BlinkIntervalSet(interval);
35 458 | 1 }
36 465 | 1}
37 472 |
38 479 | // ----------------------------------------------------------------------
39 486 | // Handler implementations for user-defined typed input ports
40 493 | // ----------------------------------------------------------------------
41 500 |
42 507 | 12void Led ::run_handler(const FwIndexType portNum, U32 context) {
43 514 | // Read back the parameter value
44 521 | 12 Fw::ParamValid isValid;
45 528 |
529 | 1/2 530 |
531 |
✓ Branch 0 taken 12 times.
532 |
✗ Branch 1 not taken.
533 |
534 |
535 |
12 U32 interval = this->paramGet_BLINK_INTERVAL(isValid);
46 542 |
47 549 | // Force interval to be 0 when invalid or not set
48 556 |
557 | 5/8 558 |
559 |
✓ Branch 0 taken 12 times.
560 |
✗ Branch 1 not taken.
561 |
✓ Branch 2 taken 12 times.
562 |
✗ Branch 3 not taken.
563 |
✓ Branch 4 taken 12 times.
564 |
✗ Branch 5 not taken.
565 |
✓ Branch 6 taken 4 times.
566 |
✓ Branch 7 taken 8 times.
567 |
568 |
569 |
12 interval = ((Fw::ParamValid::INVALID == isValid) || (Fw::ParamValid::UNINIT == isValid)) ? 0 : interval;
49 576 |
50 583 | // Only perform actions when counting
51 590 |
591 | 2/2 592 |
593 |
✓ Branch 0 taken 11 times.
594 |
✓ Branch 1 taken 1 times.
595 |
596 |
597 |
12 if (this->blinking) {
52 604 |
605 | 1/2 606 |
607 |
✓ Branch 0 taken 11 times.
608 |
✗ Branch 1 not taken.
609 |
610 |
611 |
11 Fw::On new_state = this->state;
53 618 | // Check for transitions
54 625 |
626 | 5/6 627 |
628 |
✓ Branch 0 taken 5 times.
629 |
✓ Branch 1 taken 6 times.
630 |
✓ Branch 2 taken 5 times.
631 |
✗ Branch 3 not taken.
632 |
✓ Branch 4 taken 4 times.
633 |
✓ Branch 5 taken 1 times.
634 |
635 |
636 |
11 if ((0 == this->count) && (this->state == Fw::On::OFF)) {
55 643 |
644 | 1/2 645 |
646 |
✓ Branch 0 taken 4 times.
647 |
✗ Branch 1 not taken.
648 |
649 |
650 |
4 new_state = Fw::On::ON;
56 657 |
658 | 4/6 659 |
660 |
✓ Branch 0 taken 3 times.
661 |
✓ Branch 1 taken 4 times.
662 |
✗ Branch 2 not taken.
663 |
✓ Branch 3 taken 3 times.
664 |
✓ Branch 4 taken 3 times.
665 |
✗ Branch 5 not taken.
666 |
667 |
668 |
11 } else if (((interval/2) == this->count) && (this->state == Fw::On::ON)) {
57 675 |
676 | 1/2 677 |
678 |
✗ Branch 0 not taken.
679 |
✓ Branch 1 taken 3 times.
680 |
681 |
682 |
3 new_state = Fw::On::OFF;
58 689 | 3 }
59 696 |
60 703 | // A transition has occurred
61 710 |
711 | 4/6 712 |
713 |
✗ Branch 0 not taken.
714 |
✓ Branch 1 taken 11 times.
715 |
✗ Branch 2 not taken.
716 |
✓ Branch 3 taken 11 times.
717 |
✓ Branch 4 taken 7 times.
718 |
✓ Branch 5 taken 4 times.
719 |
720 |
721 |
11 if (this->state != new_state) {
62 728 | 7 this->transitions = this->transitions + 1;
63 735 |
736 | 2/4 737 |
738 |
✗ Branch 0 not taken.
739 |
✓ Branch 1 taken 7 times.
740 |
✓ Branch 2 taken 7 times.
741 |
✗ Branch 3 not taken.
742 |
743 |
744 |
7 this->tlmWrite_LedTransitions(this->transitions);
64 751 |
65 758 | // Port may not be connected, so check before sending output
66 765 |
766 | 2/4 767 |
768 |
✗ Branch 0 not taken.
769 |
✓ Branch 1 taken 7 times.
770 |
✓ Branch 2 taken 7 times.
771 |
✗ Branch 3 not taken.
772 |
773 |
774 |
7 if (this->isConnected_gpioSet_OutputPort(0)) {
67 781 |
782 | 3/6 783 |
784 |
✗ Branch 0 not taken.
785 |
✓ Branch 1 taken 7 times.
786 |
✗ Branch 2 not taken.
787 |
✓ Branch 3 taken 7 times.
788 |
✓ Branch 4 taken 7 times.
789 |
✗ Branch 5 not taken.
790 |
791 |
792 |
7 this->gpioSet_out(0, (Fw::On::ON == new_state) ? Fw::Logic::HIGH : Fw::Logic::LOW);
68 799 | 7 }
69 806 |
807 | 2/4 808 |
809 |
✗ Branch 0 not taken.
810 |
✓ Branch 1 taken 7 times.
811 |
✓ Branch 2 taken 7 times.
812 |
✗ Branch 3 not taken.
813 |
814 |
815 |
7 this->log_ACTIVITY_LO_LedState(new_state);
70 822 |
823 | 1/2 824 |
825 |
✗ Branch 0 not taken.
826 |
✓ Branch 1 taken 7 times.
827 |
828 |
829 |
7 this->state = new_state;
71 836 | 7 }
72 843 |
73 850 |
74 857 |
75 864 |
865 | 2/2 866 |
867 |
✓ Branch 0 taken 5 times.
868 |
✓ Branch 1 taken 6 times.
869 |
870 |
871 |
11 this->count = ((this->count + 1) >= interval) ? 0 : (this->count + 1);
76 878 | 11 }
77 885 | 12}
78 892 |
79 899 | // ----------------------------------------------------------------------
80 906 | // Command handler implementations
81 913 | // ----------------------------------------------------------------------
82 920 |
83 927 | 2void Led ::BLINKING_ON_OFF_cmdHandler(const FwOpcodeType opCode, const U32 cmdSeq, Fw::On on_off) {
84 934 | // Check the command input before processing
85 941 |
942 | 1/4 943 |
944 |
✗ Branch 0 not taken.
945 |
✓ Branch 1 taken 2 times.
946 |
✗ Branch 2 not taken.
947 |
✗ Branch 3 not taken.
948 |
949 |
950 |
2 FW_ASSERT(on_off == Fw::On::ON or on_off == Fw::On::OFF, on_off.e);
86 957 | 2 this->count = 0; // Reset count on any command
87 964 | 2 this->blinking = Fw::On::ON == on_off; // Update blinking state
88 971 |
972 | 1/2 973 |
974 |
✓ Branch 0 taken 2 times.
975 |
✗ Branch 1 not taken.
976 |
977 |
978 |
2 this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
89 985 | 2}
90 992 |
91 999 | } // end namespace LedBlinker
92 1006 |
1011 |
1012 |
1013 |
1014 | 1015 | 1018 | 1019 | 1020 | -------------------------------------------------------------------------------- /docs/led-blinker.md: -------------------------------------------------------------------------------- 1 | --- 2 | permalink: / 3 | --- 4 | 5 | # LED Blinker Tutorial 6 | 7 | This is designed to be an extended introductory F´ tutorial taking the user through the basics of creating components, using events, telemetry, commands, and parameters, and integrating topologies with the goal of running F´ on embedded hardware. Users will be guided through the process of software development and testing on embedded Linux running on an ARM processor (e.g. RaspberryPI, Odroid, etc). 8 | 9 | The goal of this tutorial is to build a spacecraft whose mission is to blink an LED. 10 | 11 | > [!TIP] 12 | > The source for this tutorial is located here: [https://github.com/fprime-community/fprime-workshop-led-blinker](https://github.com/fprime-community/fprime-workshop-led-blinker). If you are stuck at some point during the tutorial, you may refer to that reference as the "solution". 13 | 14 | ## Prerequisites 15 | 16 | In order to run through this tutorial, you must first do the following: 17 | 18 | 1. Meet the [F´ System Requirements](https://github.com/nasa/fprime?tab=readme-ov-file#system-requirements) 19 | 2. Install an IDE or text editor supporting copy-paste. [VSCode](https://code.visualstudio.com/) has [plugins](https://marketplace.visualstudio.com/items?itemName=jet-propulsion-laboratory.fpp) to work with FPP. 20 | 3. Attempt the [Hello World Tutorial](https://fprime.jpl.nasa.gov/latest/docs/tutorials/) 21 | 22 | > [!IMPORTANT] 23 | > If you do not have the hardware, you can still follow the LED Blinker tutorial! You should just skip the Hardware sections. 24 | 25 | To run on hardware with cross-compiling, you must also: 26 | 27 | 1. Acquire and set up the appropriate hardware as described in the [Appendix: Optional Hardware Requirement](#appendix-optional-hardware-requirements) section 28 | 2. Set up a [cross-compiling environment](https://fprime.jpl.nasa.gov/latest/docs/tutorials/cross-compilation/) for their ARM processor 29 | 30 | > [!NOTE] 31 | > Attendees to an in-person F´ workshop will have access to 64-bit ARM hardware and should set up the 64-bit cross compiling environment. 32 | 33 | ## Troubleshooting 34 | 35 | If at any point during this tutorial you encounter issues: 36 | 1. **Check your current directory**: Ensure you are in the correct directory as specified in each step of the tutorial 37 | 2. **Activate your virtual environment**: Always make sure your F´ project's virtual environment is activated with `. fprime-venv/bin/activate` 38 | 3. **Refer to the F´ troubleshooting guide**: Visit [F´ Installation and Troubleshooting](https://fprime.jpl.nasa.gov/latest/docs/getting-started/installing-fprime/#troubleshooting) for common installation and setup issues 39 | 4. **Verify your F´ installation**: Run `fprime-util --help` to ensure F´ tools are properly installed 40 | 5. **Check build errors**: If you encounter build errors, ensure all previous steps were completed successfully 41 | 42 | ## Tutorial Steps 43 | 44 | This tutorial is composed of the following steps: 45 | 46 | 1. [Project Setup](#1-led-blinker-project-setup) 47 | 2. [Requirements Specification](#2-specifying-requirements) 48 | 3. [Component Design and Initial Implementation](#3-led-blinker-component-design-and-initial-implementation) 49 | 4. [Initial Component Integration](#4-led-blinker-initial-component-integration) 50 | 5. [Continuing Component Implementation](#5-led-blinker-component-design-and-implementation-continued) 51 | 6. [Unit-Testing](#6-led-blinker-unit-testing) 52 | 7. [Full System Integration](#7-led-blinker-full-system-integration) 53 | 8. [Running on Hardware](#8-led-blinker-running-on-hardware) 54 | 9. [System Testing](#9-system-testing) 55 | 10. [Conclusion](#10-led-blinker-conclusion) 56 | 57 | --- 58 | 59 | ## 1. LED Blinker: Project Setup 60 | 61 | > [!NOTE] 62 | > If you have followed the [HelloWorld tutorial](https://fprime.jpl.nasa.gov/latest/docs/tutorials/) previously, this should feel very familiar... 63 | 64 | An F´ Project ties to a specific version of tools to work with F´. In order to create 65 | this project and install the correct version of tools, you should perform a bootstrap of F´: 66 | 67 | 1. Ensure you meet the [F´ System Requirements](https://github.com/nasa/fprime?tab=readme-ov-file#system-requirements) 68 | 2. [Bootstrap your F´ project](https://fprime.jpl.nasa.gov/latest/docs/getting-started/installing-fprime/#creating-a-new-f-project) with the name `led-blinker` and namespace `LedBlinker` 69 | 70 | Bootstrapping your F´ project created a folder called `led-blinker` (or any name you chose) containing the standard F´ project structure as well as the virtual environment up containing the tools to work with F´. 71 | 72 | Next, generate a build cache using the following commands: 73 | 74 | ``` 75 | cd led-blinker 76 | . fprime-venv/bin/activate 77 | fprime-util generate 78 | ``` 79 | > [!NOTE] 80 | > Always remember to activate your project's virtual environment whenever you work with it. 81 | 82 | --- 83 | 84 | ## 2. Specifying Requirements 85 | 86 | In this section to the tutorial, you will learn a bit about specifying requirements. Software requirements are derived from higher-level system requirements and represent the detail needed to implement the software. 87 | > [!NOTE] Typically these would be done in the Component's Software Specifications Document, or `sdd.md` 88 | 89 | ### System Requirements 90 | 91 | For this tutorial we have several higher-level system requirements. These requirements would be defined by requirements specified by the electronics subsystem which are themselves derived by requirements defined at the full system level. 92 | 93 | | Requirement | Description | 94 | |-----------------|----------------------------------------------------------| 95 | | ELECTRONICS-001 | The system shall blink an LED in response to a command. | 96 | | ELECTRONICS-002 | The blink rate of the LED shall be changeable in-flight. | 97 | 98 | ### Software Requirements 99 | 100 | These are the requirements that the software team cares about. These dictate how the software should operate and trace to the higher-level system requirements. These also come with a verification method to ensure the software meets these requirements. 101 | 102 | Ideally, the software engineer would be handed these requirements, however; in-practice this is often a discussion between the software engineer and their system engineers. A sample requirement is provided below. 103 | 104 | | Requirement | Description | Derives From | Verification | 105 | |-----------------|-----------------------------------------------------------------|-----------------|--------------| 106 | | LED-BLINKER-001 | The software shall start LED blinking in response to a command. | ELECTRONICS-001 | Unit Test | 107 | 108 | > [!WARNING] 109 | > Take a moment to identify some other requirements you might derive from the above electronics requirements. Do this before moving on to the next section. 110 | 111 | ### LED Blinker 112 | 113 | Here we list a number of requirements for our LED software to implement. 114 | 115 | | Requirement | Description | Derived From | Verification | 116 | |-----------------|-----------------------------------------------------------------|-----------------|--------------| 117 | | LED-BLINKER-001 | The software shall start LED blinking in response to a command. | ELECTRONICS-001 | Unit Test | 118 | | LED-BLINKER-002 | The software shall stop LED blinking in response to a command. | ELECTRONICS-001 | Unit Test | 119 | | LED-BLINKER-003 | The software shall telemeter the current LED blinking state. | ELECTRONICS-001 | Unit Test | 120 | | LED-BLINKER-004 | The software shall emit events when the blinking state changes. | ELECTRONICS-001 | Unit Test | 121 | | LED-BLINKER-005 | The software shall store the blink interval as a parameter. | ELECTRONICS-002 | Unit Test | 122 | | LED-BLINKER-006 | The software shall blink the LED using GPIO pin 13 | Electrical ICD | Unit Test | 123 | 124 | > [!NOTE] 125 | > Notice how the software also includes a requirement that derived from the Electrical Interface Control Document. This captures the details of the software/hardware interface and is captured here as a requirement. 126 | 127 | --- 128 | 129 | 130 | ## 3. LED Blinker: Component Design and Initial Implementation 131 | 132 | The purpose of this exercise is to walk you through the creation and initial design and implementation of an F´ component to control the blinking of an LED. This section will discuss the design of the component, the implementation of a command to start/stop the LED blinking, and the sending of events. Users will then proceed to the initial ground testing before finishing the implementation in a later section. 133 | 134 | ### Component Design 135 | 136 | In order for our component to blink an LED, it needs to accept a command to turn on the LED and drive a GPIO pin via a port call to the GPIO driver. It will also need a [rate group](https://fprime.jpl.nasa.gov/latest/docs/user-manual/design-patterns/rate-group/) input port to control the timing of the blink. Additionally, we will define events and telemetry channels to report component state, and a parameter to control the period of the blink. 137 | 138 | This component design is captured in the block diagram below with input ports on the left and output ports on the right. Ports for standard F´ functions (e.g. commands, events, telemetry, and parameters) are circled in green. 139 | 140 | ![Led Component Block Diagram](img/component-design.png) 141 | > [!NOTE] This component diagram was created using the built-in [fprime-visual](https://github.com/fprime-community/fprime-visual) tool 142 | 143 | In this exercise, the `BLINKING_ON_OFF` command shall toggle the blinking state of the LED. The period of the blinking is controlled by the `BLINK_INTERVAL` parameter. Blinking is implemented on the `run` rate group input port. The component also defines several telemetry channels and events describing the various actions taken by the component. 144 | 145 | #### Design Summary 146 | 147 | **Component Ports:** 148 | 1. `run`: invoked at a set rate from the rate group, used to control the LED blinking 149 | 2. `gpioSet`: invoked by the `Led` component to control the GPIO driver 150 | 151 | > [!NOTE] 152 | > Standard component ports (circled in green) are not listed here. 153 | 154 | **Commands:** 155 | 1. `BLINKING_ON_OFF`: turn the LED blinking on/off 156 | 157 | **Events:** 158 | 1. `SetBlinkingState`: emitted when the component sets the blink state 159 | 2. `BlinkIntervalSet`: emitted when the component blink interval parameter is set 160 | 3. `LedState`: emitted when the LED is driven to a new state 161 | 162 | **Telemetry Channels:** 163 | 1. `BlinkingState`: state of the LED blinking 164 | 2. `LedTransitions`: count of the LED transitions 165 | 166 | **Parameters:** 167 | 1. `BLINK_INTERVAL`: LED blink period in number of rate group calls 168 | 169 | #### Create the component 170 | 171 | It is time to create the basic component. In a terminal, navigate to the project's root directory and run the following: 172 | 173 | ```bash 174 | # In led-blinker 175 | cd LedBlinker/Components 176 | 177 | fprime-util new --component 178 | ``` 179 | You will be prompted for information regarding your component. Fill out the prompts as shown below: 180 | 181 | ```bash 182 | [INFO] Cookiecutter source: using builtin 183 | [1/8] Component name (MyComponent): Led 184 | [2/8] Component short description (Component for F Prime FSW framework.): Component to blink an LED driven by a rate group 185 | [3/8] Component namespace (LedBlinker): LedBlinker 186 | [4/8] Select component kind 187 | 1 - active 188 | 2 - passive 189 | 3 - queued 190 | Choose from [1/2/3] (1): 1 191 | [5/8] Enable Commands? 192 | 1 - yes 193 | 2 - no 194 | Choose from [1/2] (1): 1 195 | [6/8] Enable Telemetry? 196 | 1 - yes 197 | 2 - no 198 | Choose from [1/2] (1): 1 199 | [7/8] Enable Events? 200 | 1 - yes 201 | 2 - no 202 | Choose from [1/2] (1): 1 203 | [8/8] Enable Parameters? 204 | 1 - yes 205 | 2 - no 206 | Choose from [1/2] (1): 1 207 | [INFO] Found CMake file at 'LedBlinker/Components/CMakeLists.txt' 208 | Add Led to LedBlinker/Components/CMakeLists.txt at end of file? (yes/no) [yes]: yes 209 | Generate implementation files? (yes/no) [yes]: yes 210 | Refreshing cache and generating implementation files... 211 | [INFO] Created new component and generated initial implementations. 212 | ``` 213 | Your new component is located in the directory `LedBlinker/Components/Led`. 214 | 215 | #### Commands 216 | 217 | Commands are used to command the component from the ground system or a command sequencer. We will add a command named `BLINKING_ON_OFF` to turn on or off the blinking LED. This command will take in an argument named `onOff` of type `Fw.On`. 218 | 219 | 220 | Inside your `LedBlinker/Components/Led` directory, open the file `Led.fpp` and search for the following: 221 | 222 | ``` 223 | # One async command/port is required for active components 224 | # This should be overridden by the developers with a useful command/port 225 | @ TODO 226 | async command TODO opcode 0 227 | ``` 228 | 229 | Replace that block with the following: 230 | 231 | ``` 232 | @ Command to turn on or off the blinking LED 233 | async command BLINKING_ON_OFF( 234 | onOff: Fw.On @< Indicates whether the blinking should be on or off 235 | ) 236 | ``` 237 | > [!NOTE] 238 | > The text following a symbol @ or @< is called an annotation. These annotations are carried through the parsing and become comments in the generated code. For more information, see [The FPP User's Guide](https://nasa.github.io/fpp/fpp-users-guide.html#Writing-Comments-and-Annotations_Annotations) 239 | 240 | #### Events 241 | 242 | Events represent a log of system activities. Events are typically emitted any time the system takes an action. Events are also emitted to report off-nominal conditions. 243 | 244 | Inside your `LedBlinker/Components/Led` directory, open the `Led.fpp` file. After the command you added in the previous section, add this event: 245 | 246 | ``` 247 | @ Reports the state we set to blinking. 248 | event SetBlinkingState($state: Fw.On) \ 249 | severity activity high \ 250 | format "Set blinking state to {}." 251 | ``` 252 | 253 | > [!NOTE] 254 | > `state` is a keyword in FPP. In order to use it as a variable name, you need to escape it by prepending `$`. 255 | 256 | #### Do it yourself 257 | 258 | Below is a table with tasks you must complete before moving on to the next section. These tasks require you to update the component's fpp file. 259 | 260 | | Task | Solution | 261 | |-------|-------------| 262 | | 1. Add an activity high event named `BlinkIntervalSet` to the fpp. The event takes an argument of `U32` type to indicate the set interval. |
Answer`event BlinkIntervalSet(interval: U32) severity activity high format "LED blink interval set to {}"`
| 263 | | 2. Add an activity low event named `LedState` to the fpp. The event takes an argument of `Fw.On` type to indicate the LED has been driven to a different state. |
Answer`event LedState(onOff: Fw.On) severity activity low format "LED is {}"`
| 264 | 265 | 266 | You have completed the Command and Event design phase. We'll move on to the Command and Event implementation phase. 267 | 268 | ### Component Implementation 269 | 270 | In the `LedBlinker/Components/Led` directory, run the following: 271 | 272 | ```bash 273 | # In LedBlinker/Components/Led 274 | fprime-util impl 275 | ``` 276 | 277 | This command will auto generate two files: `Led.template.hpp` and `Led.template.cpp`. These files contain the stub implementation for the component's newly added command. 278 | 279 | Since this is the start of the component's implementation, we can use the generated template files for our initial component implementation. Inside your `LedBlinker/Components/Led` directory, rename `Led.template.hpp` to `Led.hpp` and rename `Led.template.cpp` to `Led.cpp`. You can rename the files through the terminal using the two commands below: 280 | 281 | ```bash 282 | # In LedBlinker/Components/Led 283 | mv Led.template.hpp Led.hpp 284 | mv Led.template.cpp Led.cpp 285 | ``` 286 | 287 | Verify your component is building correctly by running the following command in the `LedBlinker/Components/Led` directory. 288 | 289 | ```bash 290 | # In LedBlinker/Components/Led 291 | fprime-util build 292 | ``` 293 | 294 | > [!NOTE] 295 | > Fix any errors that occur before proceeding with the rest of the tutorial. 296 | 297 | #### Component State 298 | 299 | Many of the behaviors of the component discussed in the [Component Design](#component-design) section require the tracking of some state. Let us set up and initialize that state. 300 | 301 | Open `Led.hpp` in `LedBlinker/Components/Led`. Add the following private member variables to the end of the file just before the two closing `}` of the class definition and namespace. 302 | 303 | ```cpp 304 | Fw::On m_state = Fw::On::OFF; //! Keeps track if LED is on or off 305 | U64 m_transitions = 0; //! The number of on/off transitions that have occurred from FSW boot up 306 | U32 m_toggleCounter = 0; //! Keeps track of how many ticks the LED has been on for 307 | bool m_blinking = false; //! Flag: if true then LED blinking will occur else no blinking will happen 308 | ``` 309 | 310 | Run the following in the `LedBlinker/Components/Led` directory to verify your component is building correctly. 311 | 312 | ```bash 313 | # In LedBlinker/Components/Led 314 | fprime-util build 315 | ``` 316 | 317 | Now that the member variables are set up, we can continue into the component implementation. 318 | 319 | #### Command 320 | 321 | Now we will implement the behavior of the `BLINKING_ON_OFF` command. An initial implementation is shown below and may be copied into `Led.cpp` in-place of the BLINKING_ON_OFF command stub. 322 | 323 | ```cpp 324 | void Led ::BLINKING_ON_OFF_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, Fw::On onOff) { 325 | this->m_toggleCounter = 0; // Reset count on any successful command 326 | this->m_blinking = Fw::On::ON == onOff; // Update blinking state 327 | 328 | // TODO: Emit an event SetBlinkingState to report the blinking state (onOff). 329 | // NOTE: This event will be added during the "Events" exercise. 330 | 331 | // TODO: Report the blinking state (onOff) on channel BlinkingState. 332 | // NOTE: This telemetry channel will be added during the "Telemetry" exercise. 333 | 334 | // Provide command response 335 | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); 336 | } 337 | ``` 338 | Run the following command in the terminal to verify your component is building correctly. 339 | 340 | ```bash 341 | # In LedBlinker/Components/Led 342 | fprime-util build 343 | ``` 344 | 345 | > [!NOTE] 346 | > Fix any errors that occur before proceeding with the rest of the tutorial. 347 | 348 | #### Events 349 | 350 | Open `Led.cpp` in your `LedBlinker/Components/Led` directory and navigate to the `BLINKING_ON_OFF` command. Report, via an event, the blinking state has been set. 351 | 352 | To do so, replace: 353 | ```cpp 354 | // TODO: Emit an event SetBlinkingState to report the blinking state (onOff). 355 | // NOTE: This event will be added during the "Events" exercise. 356 | ``` 357 | 358 | with: 359 | ```cpp 360 | this->log_ACTIVITY_HI_SetBlinkingState(onOff); 361 | ``` 362 | 363 | Run the following to verify your component is building correctly. 364 | 365 | ```bash 366 | fprime-util build 367 | ``` 368 | 369 | > [!NOTE] 370 | > Resolve any `fprime-util build` errors before continuing 371 | 372 | ### LED Blinker Step 3 Conclusion 373 | 374 | Congratulations! You have now implemented some basic functionality in a new F´ component. Your command should look like this 375 | ```cpp 376 | void Led ::BLINKING_ON_OFF_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, Fw::On onOff) { 377 | this->m_toggleCounter = 0; // Reset count on any successful command 378 | this->m_blinking = Fw::On::ON == onOff; // Update blinking state 379 | 380 | this->log_ACTIVITY_HI_SetBlinkingState(onOff); 381 | 382 | // TODO: Report the blinking state (onOff) on channel BlinkingState. 383 | // NOTE: This telemetry channel will be added during the "Telemetry" exercise. 384 | 385 | // Provide command response 386 | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); 387 | } 388 | ``` 389 | 390 | Before finishing the implementation, let's take a break and try running the above command through the ground system. This will require integrating the component into the system topology, which we will get into in the next section. 391 | 392 | > [!NOTE] 393 | > The last TODO in the `BLINKING_ON_OFF` command handler will be addressed in a future section. 394 | 395 | --- 396 | 397 | 398 | ## 4. LED Blinker: Initial Component Integration 399 | 400 | In this section, users will create a deployment and perform the initial integration of the LED component into that deployment. This deployment will automatically include the basic command and data handling setup needed to interact with the component. Wiring the `Led` component to the GPIO driver component will be covered in a later section after the component implementation has finished. 401 | 402 | > [!NOTE] 403 | > Users must have created the [initial Led component implementation](#4-led-blinker-initial-component-integration) in order to run through this section. Users may continue to define commands, events, telemetry, and ports after this initial integration. 404 | 405 | ### Creating the `LedBlinkerDeployment` Deployment 406 | 407 | In order to produce an executable to run the software, users need to create a deployment. A deployment is one software executable that contains the main entry point, and an F´ system topology. 408 | 409 | Create a new deployment with the following: 410 | 411 | ```shell 412 | #In led-blinker 413 | cd LedBlinker 414 | fprime-util new --deployment 415 | ``` 416 | 417 | This will ask for some input, respond with the answers `LedBlinkerDeployment` for the deployment name and `2` for the communication driver type, shown below: 418 | 419 | ```shell 420 | [1/2] Deployment name (MyDeployment): LedBlinkerDeployment 421 | [2/2] Select communication driver type 422 | 1 - TcpClient 423 | 2 - TcpServer 424 | 3 - UART 425 | Choose from [1/2/3] (1): 2 426 | [INFO] Found CMake file at 'LedBlinker/LedBlinkerDeployment/CMakeLists.txt' 427 | Add LedBlinkerDeployment to LedBlinker/LedBlinkerDeployment/CMakeLists.txt at end of file? (yes/no) [yes]: yes 428 | [INFO] New deployment successfully created: /Users/chammard/Work/fp/tmp/LedBlinker/LedBlinkerDeployment/LedBlinkerDeployment 429 | ``` 430 | > [!NOTE] 431 | > Use the default response for any other questions asked. Usually, you may want to choose a shorter name for a deployment, as this will impact namespaces and file paths. We are using a verbose name here for the learning experience. 432 | 433 | In order to check that the deployment was created successfully, the user can build the deployment. This will build the code for the current host system, not the remote embedded hardware allowing local testing during development. 434 | 435 | ```shell 436 | # In LedBlinker 437 | cd LedBlinkerDeployment 438 | fprime-util build 439 | ``` 440 | 441 | > [!NOTE] 442 | > This will reuse the build cache created during the project creation. CMake warnings may appear to indicate that the build cache is refreshing. The build should start shortly thereafter. 443 | 444 | ### Adding `Led` Component To The Deployment 445 | 446 | The component can now be added to the deployment's topology effectively adding this component to the running system. This is done by modifying `instances.fpp` and `topology.fpp` in the `Top` directory. 447 | 448 | Add the following to `LedBlinker/LedBlinkerDeployment/Top/instances.fpp`. Typically, this is added to the "Active component instances" section of that document. 449 | 450 | ``` 451 | instance led: LedBlinker.Led base id 0x10005000 \ 452 | queue size Default.QUEUE_SIZE \ 453 | stack size Default.STACK_SIZE \ 454 | priority 95 455 | ``` 456 | 457 | This defines an instance of the `Led` component called `led`. Since the component is active it needs a queue size, stack size, and priority for the thread of the component and the queue that thread serves. We have chosen the topology specified defaults and a priority of 95. 458 | 459 | Next, the topology needs to use the above definition. This is done by adding the `led` instance to the list of instances defined in `LedBlinker/LedBlinkerDeployment/Top/topology.fpp`: 460 | 461 | ``` 462 | # ---------------------------------------------------------------------- 463 | # Instances used in the topology 464 | # ---------------------------------------------------------------------- 465 | 466 | instance led 467 | ``` 468 | 469 | > [!NOTE] 470 | > No port connections need to be added because thus far the component only defines standard ports and those are connected automatically. 471 | 472 | Build your deployment 473 | 474 | ```shell 475 | cd LedBlinkerDeployment 476 | fprime-util build 477 | ``` 478 | 479 | ### Testing the Topology 480 | 481 | The topology may now be run. This can be done with the `fprime-gds` command. Since we are currently building for the host platform, that command will run the ground data system (GDS) and the deployment executable automatically in-tandem. 482 | 483 | > [!NOTE] 484 | > Make sure to build the deployment first with `fprime-util build` 485 | 486 | ```shell 487 | fprime-gds --ip-client 488 | ``` 489 | This will likely open up your browser and show the running flight software. If it does not open a browser, navigate to `http://localhost:5000`. 490 | 491 | Test the component integration with the following steps: 492 | 1. **Verify connection**: confirm that there is a green circle and not a red X in the upper right corner. 493 | 2. **Send a Command**: select the 'Commanding' tab, search for `led.BLINKING_ON_OFF` and send it with the argument set to `ON`. 494 | 3. **Verify Event**: select the 'Events' tab and verify that the `SetBlinkingState` event reports the blinking state was set to `ON`. 495 | 496 | `CTRL-C` to stop the F´ GDS program. 497 | 498 | ### LED Blinker Step 4 Conclusion 499 | 500 | Congratulations! You have now integrated your component and tested that integration. 501 | 502 | Return to the `LedBlinker/LedBlinkerDeployment` and run the following commands to test whenever you desire. 503 | 504 | ``` 505 | #In LedBlinker/LedBlinkerDeployment 506 | fprime-util build 507 | fprime-gds --ip-client 508 | 509 | # CTRL-C to exit 510 | ``` 511 | 512 | This tutorial will return to the component implementation before finishing the integration of the component and testing on hardware. 513 | 514 | --- 515 | 516 | ## 5. LED Blinker: Component Design and Implementation, Continued 517 | 518 | In this section, we will complete the component design and implementation by adding telemetry, parameters, and ports; and implementing the behavior of the `run` port, which is called by the rate-group. 519 | 520 | > [!NOTE] 521 | > Refer back to the [component design](#component-design) for explanations of what each of these items is intended to do. 522 | 523 | ### Continued Component Design 524 | 525 | #### Telemetry 526 | 527 | Telemetry channels represent the state of the system. Typically, telemetry channels are defined for any states that give crucial insight into the component's behavior. 528 | 529 | Inside your `LedBlinker/Components/Led` directory, open the `Led.fpp` file. After the events you added in the previous section, add a telemetry channel of type `Fw.On` to report the blinking state. 530 | 531 | ``` 532 | @ Telemetry channel to report blinking state. 533 | telemetry BlinkingState: Fw.On 534 | ``` 535 | 536 | #### Do it yourself 537 | 538 | Below is a table with a task you must complete before moving on to the next section. This task require you to update the component's fpp file. 539 | 540 | | Task | Solution | 541 | |-------|-------------| 542 | | 1. Add a telemetry channel `LedTransitions` of type `U64` to count LED Transitions to `Led.fpp`. |
Answer`telemetry LedTransitions: U64`
| 543 | 544 | #### Parameters 545 | 546 | Parameters are ground-controllable settings for the system. Parameters are used to set settings of the system that the ground may need to change at some point during the lifetime of the system. This tutorial sets one parameter, the blink interval. 547 | 548 | For each parameter you define in your fpp, the F´ autocoder will autogenerate a SET and SAVE command. The SET command allows ground to update the parameter. The SAVE command tells your parameter database to stage this new parameter value for saving. To save the parameter for use on a FSW reboot, ground will need to send the `PRM_SAVE_FILE` command. 549 | 550 | In your `LedBlinker/Components/Led` directory, open the `Led.fpp` file. After the telemetry channels you added previously, add a parameter for the blinking interval. Give the parameter the name `BLINK_INTERVAL`, type `U32`, and a default value. It is good practice to assign parameters a valid default value. 551 | 552 | ``` 553 | @ Blinking interval in rate group ticks 554 | param BLINK_INTERVAL: U32 default 1 555 | ``` 556 | 557 | #### Additional Ports 558 | 559 | Any communication between components should be accomplished through F´ ports. Thus far we have been using a set of standard ports for handling Commands, Telemetry, Events, and Parameters. This section will add two specific ports to our component: input `run` to be called from the rate group, and output `gpioSet` to drive the GPIO driver. 560 | 561 | In your `LedBlinker/Components/Led` directory, open the `Led.fpp` file. After the parameters you added previously, add the following two ports: 562 | 563 | ``` 564 | @ Port receiving calls from the rate group 565 | async input port run: Svc.Sched 566 | 567 | @ Port sending calls to the GPIO driver 568 | output port gpioSet: Drv.GpioWrite 569 | ``` 570 | 571 | > [!NOTE] 572 | > Input and output ports can be given any name that you choose. In this example, we choose `run` and `gpioSet` since these names capture the behavioral intent. The types of `Svc.Sched` and `Drv.GpioWrite` are significant as these types must match the remote component. 573 | 574 | ### Continued Component Implementation 575 | 576 | #### Input Port Implementation 577 | 578 | In your `LedBlinker/Components/Led` directory, run the following to autogenerate stub functions for the `run` input port we just added. 579 | 580 | ```bash 581 | # In LedBlinker/Components/Led 582 | fprime-util impl 583 | ``` 584 | 585 | In your `LedBlinker/Components/Led` directory, open `Led.template.hpp` file and copy this block over to `Led.hpp`. 586 | 587 | ```cpp 588 | private: 589 | // ---------------------------------------------------------------------- 590 | // Handler implementations for user-defined typed input ports 591 | // ---------------------------------------------------------------------- 592 | 593 | //! Handler implementation for run 594 | //! 595 | //! Port receiving calls from the rate group 596 | void run_handler(FwIndexType portNum, //!< The port number 597 | U32 context //!< The call order 598 | ) override; 599 | ``` 600 | 601 | In your `LedBlinker/Components/Led` directory, open `Led.template.cpp` file and copy this block over to `Led.cpp`. 602 | ```cpp 603 | // ---------------------------------------------------------------------- 604 | // Handler implementations for user-defined typed input ports 605 | // ---------------------------------------------------------------------- 606 | 607 | void Led ::run_handler(FwIndexType portNum, U32 context) { 608 | // TODO 609 | } 610 | ``` 611 | 612 | > [!NOTE] 613 | > Copying from the template file and pasting into your implementation file is a pattern in F Prime that is often used when adding new input ports or commands. 614 | 615 | The `run` port will be invoked repeatedly on each cycle of the rate group. Each invocation will call into the `run_handler` function such that the component may perform behavior on each cycle. 616 | 617 | Here we want to turn the LED on or OFF based on a cycle count to implement the "blinking" behavior we desire. 618 | 619 | Copy the run_handler implementation below into your run_handler. Try filling in the TODOs based on what you learned and defined in previous sections. 620 | 621 | > [!NOTE] 622 | > Don't forget to read the code and comments to understand more about how to use F´. 623 | 624 | ```cpp 625 | void Led ::run_handler(FwIndexType portNum, U32 context) { 626 | // Read back the parameter value 627 | Fw::ParamValid isValid = Fw::ParamValid::INVALID; 628 | U32 interval = this->paramGet_BLINK_INTERVAL(isValid); 629 | FW_ASSERT((isValid != Fw::ParamValid::INVALID) && (isValid != Fw::ParamValid::UNINIT), 630 | static_cast(isValid)); 631 | 632 | // Only perform actions when set to blinking 633 | if (this->m_blinking && (interval != 0)) { 634 | // If toggling state 635 | if (this->m_toggleCounter == 0) { 636 | // Toggle state 637 | this->m_state = (this->m_state == Fw::On::ON) ? Fw::On::OFF : Fw::On::ON; 638 | this->m_transitions++; 639 | // TODO: Report the number of LED transitions (this->m_transitions) on channel LedTransitions 640 | 641 | // Port may not be connected, so check before sending output 642 | if (this->isConnected_gpioSet_OutputPort(0)) { 643 | this->gpioSet_out(0, (Fw::On::ON == this->m_state) ? Fw::Logic::HIGH : Fw::Logic::LOW); 644 | } 645 | 646 | // TODO: Emit an event LedState to report the LED state (this->m_state). 647 | } 648 | 649 | this->m_toggleCounter = (this->m_toggleCounter + 1) % interval; 650 | } 651 | // We are not blinking 652 | else { 653 | if (this->m_state == Fw::On::ON) { 654 | // Port may not be connected, so check before sending output 655 | if (this->isConnected_gpioSet_OutputPort(0)) { 656 | this->gpioSet_out(0, Fw::Logic::LOW); 657 | } 658 | 659 | this->m_state = Fw::On::OFF; 660 | // TODO: Emit an event LedState to report the LED state (this->m_state). 661 | } 662 | } 663 | } 664 | ``` 665 | In the terminal, run the following to verify your component is building correctly. 666 | 667 | ```bash 668 | # In LedBlinker/Components/Led 669 | fprime-util build 670 | ``` 671 | 672 | > [!NOTE] 673 | > Fix any errors that occur before proceeding with the rest of the tutorial. 674 | 675 | #### Command Implementation Continued 676 | 677 | Inside your `LedBlinker/Components/Led` directory, open `Led.cpp`, and navigate to the `BLINKING_ON_OFF` command. Report the blinking state via the telemetry channel we just added. To do so, replace the following: 678 | 679 | ```cpp 680 | // TODO: Report the blinking state (onOff) on channel BlinkingState. 681 | // NOTE: This telemetry channel will be added during the "Telemetry" exercise. 682 | ``` 683 | 684 | with the function to send the telemetry channel: 685 | 686 | ```cpp 687 | this->tlmWrite_BlinkingState(onOff); 688 | ``` 689 | 690 | In the terminal, run the following to verify your component is building correctly. 691 | 692 | ```bash 693 | # In LedBlinker/Components/Led 694 | fprime-util build 695 | ``` 696 | 697 | > [!NOTE] 698 | > Fix any errors that occur before proceeding with the rest of the tutorial. 699 | 700 | #### Parameter Implementation 701 | 702 | When ground updates a component's parameter, the user may want the component to react to the parameter update. F Prime provides a function called `parameterUpdated` where your component can react to each parameter update. Implementing `parameterUpdated` for a component is optional but we'll implement it for this tutorial. 703 | 704 | In your `LedBlinker/Components/Led` directory, open the file `Led.hpp` and add the following function signature in the `private:` scope: 705 | 706 | ```cpp 707 | //! Emit parameter updated EVR 708 | //! 709 | void parameterUpdated(FwPrmIdType id //!< The parameter ID 710 | ) override; 711 | ``` 712 | 713 | > This function is called when a parameter is updated via the auto generated SET command. Although the value is updated automatically, this function gives developers a chance to respond to changing parameters. This tutorial uses it to emit an event. 714 | 715 | Save file and in your `LedBlinker/Components/Led` directory, open `Led.cpp` and add the implementation for `parameterUpdated`: 716 | 717 | ```cpp 718 | void Led ::parameterUpdated(FwPrmIdType id) { 719 | Fw::ParamValid isValid = Fw::ParamValid::INVALID; 720 | switch (id) { 721 | case PARAMID_BLINK_INTERVAL: { 722 | // Read back the parameter value 723 | const U32 interval = this->paramGet_BLINK_INTERVAL(isValid); 724 | // NOTE: isValid is always VALID in parameterUpdated as it was just properly set 725 | FW_ASSERT(isValid == Fw::ParamValid::VALID, static_cast(isValid)); 726 | 727 | // Emit the blink interval set event 728 | // TODO: Emit an event with, severity activity high, named BlinkIntervalSet that takes in an argument of 729 | // type U32 to report the blink interval. 730 | break; 731 | } 732 | default: 733 | FW_ASSERT(0, static_cast(id)); 734 | break; 735 | } 736 | } 737 | ``` 738 | 739 | In the terminal, run the following to verify your component is building correctly. 740 | 741 | ```bash 742 | # In LedBlinker/Components/Led 743 | fprime-util build 744 | ``` 745 | > [!NOTE] 746 | > Resolve any errors before continuing 747 | 748 | ### Do it Yourself 749 | 750 | Below is a table with tasks you must complete. These tasks require you to go back into the component's code and add the missing function calls. 751 | 752 | | Task | Solution | 753 | |------|----------| 754 | | Inside the `parameterUpdated` function, emit an activity high event named `BlinkIntervalSet` that takes in an argument of type `U32` to report the blink interval. |
Answer`this->log_ACTIVITY_HI_BlinkIntervalSet(interval);`
| 755 | | Inside the `run_handler` port handler, report the number of LED transitions (this->m_transitions) on channel LedTransitions. |
Answer`this->tlmWrite_LedTransitions(this->m_transitions);`
| 756 | | Inside the `run_handler` port handler, emit an event LedState to report the LED state (this->m_state). There are two places to add this event. |
Answer`this->log_ACTIVITY_LO_LedState(this->m_state);`
| 757 | 758 | > [!TIP] 759 | > Emitting an event follows this pattern: `this->log__();` 760 | > [!TIP] 761 | > Emitting a telemetry channel follows this pattern: `this->tlmWrite_();` 762 | > [!TIP] 763 | > After running `fprime-util build`, your IDE should be able to autocomplete these functions. 764 | 765 | 766 | ### LED Blinker Step 5 Conclusion 767 | 768 | Congratulations! You just completed the implementation of your component. It is time to unit test! 769 | 770 | --- 771 | 772 | ## 6. LED Blinker: Unit Testing 773 | 774 | This exercise will walk through development of basic unit tests for the `Led` component created in the component implementation section. 775 | 776 | ### Unit Test Generation 777 | 778 | To start off, use `fprime-util` to generate a unit test outline for the `Led` component. 779 | 780 | First, generate a unit test build cache by running the following terminal commands: 781 | 782 | ```shell 783 | #In LedBlinker/Components/Led 784 | fprime-util generate --ut 785 | ``` 786 | > [!NOTE] 787 | > Unit tests run with special build settings and as such need their own build cache generated. 788 | 789 | Next we will generate unit test template files. This is similar to the component implementations we have run, but will set up the complete unit test harness. 790 | 791 | To do so, run the implementation command in the terminal within your `LedBlinker/Components/Led` directory: 792 | ```shell 793 | #In LedBlinker/Components/Led 794 | fprime-util impl --ut 795 | ``` 796 | 797 | This step should create the files `LedTester.template.cpp`, `LedTester.template.hpp`, and `LedTestMain.template.cpp` in `LedBlinker/Components/Led/test/ut`. 798 | 799 | Since this is the start of the test's implementation, we use the generated template files for our initial test implementation. Inside your `LedBlinker/Components/Led/test/ut` directory, rename the files removing the `.template` suffix: 800 | 801 | ```bash 802 | # In LedBlinker/Components/Led/test/ut 803 | mv LedTester.template.hpp LedTester.hpp 804 | mv LedTester.template.cpp LedTester.cpp 805 | mv LedTestMain.template.cpp LedTestMain.cpp 806 | ``` 807 | 808 | Then, register the unit test files with the build system by uncommenting these lines at the very end of the component `CMakeLists.txt` file in your `LedBlinker/Components/Led` directory: 809 | 810 | ```cmake 811 | register_fprime_ut( 812 | AUTOCODER_INPUTS 813 | "${CMAKE_CURRENT_LIST_DIR}/Led.fpp" 814 | SOURCES 815 | "${CMAKE_CURRENT_LIST_DIR}/test/ut/LedTestMain.cpp" 816 | "${CMAKE_CURRENT_LIST_DIR}/test/ut/LedTester.cpp" 817 | DEPENDS 818 | STest # For rules-based testing 819 | UT_AUTO_HELPERS 820 | ) 821 | ``` 822 | 823 | Finally, test the skeleton unit tests with the following command: 824 | 825 | ```shell 826 | #In LedBlinker/Components/Led 827 | fprime-util check 828 | ``` 829 | > [!NOTE] 830 | > `check` will build and run unit tests. It may report an error as no tests are defined yet. To simply build them, run `fprime-util build --ut`. 831 | 832 | ### Add a New Test Case 833 | 834 | Now that unit tests have been written, we can add our first unit test case. First, remove the default `toDo` test and add a new test case called `testBlinking`. In `LedBlinker/Components/Led/test/ut/LedTester.hpp` rename the declaration for `toDo` to be `testBlinking` instead: 835 | 836 | ```c++ 837 | void testBlinking(); 838 | ``` 839 | 840 | In `LedBlinker/Components/Led/test/ut/LedTester.cpp` rename the definition for `toDo` to be `testBlinking`: 841 | 842 | ```c++ 843 | void LedTester ::testBlinking() { 844 | 845 | } 846 | ``` 847 | 848 | In `LedBlinker/Components/Led/test/ut/LedTestMain.cpp`: 849 | 850 | ```c++ 851 | TEST(Nominal, TestBlinking) { 852 | LedBlinker::LedTester tester; 853 | tester.testBlinking(); 854 | } 855 | ``` 856 | 857 | Use `fprime-util check` to make sure the new check builds and passes. 858 | 859 | > [!NOTE] 860 | > Ensure all errors are resolved before continuing. 861 | 862 | 863 | ### Write a Test Case 864 | 865 | The first test we will write is to test that the LED doesn't blink when blinking is disabled. 866 | 867 | Add the following code to the `testBlinking` method in `LedBlinker/Components/Led/test/ut/LedTester.cpp`: 868 | 869 | ```c++ 870 | // This test will make use of parameters. So need to load them. 871 | this->component.loadParameters(); 872 | 873 | // Ensure LED stays off when blinking is disabled 874 | // The Led component defaults to blinking off 875 | this->invoke_to_run(0, 0); // invoke the 'run' port to simulate running one cycle 876 | this->component.doDispatch(); // Trigger execution of async port 877 | 878 | ASSERT_EVENTS_LedState_SIZE(0); // ensure no LedState change events we emitted 879 | 880 | ASSERT_from_gpioSet_SIZE(0); // ensure gpio LED wasn't set 881 | 882 | ASSERT_TLM_LedTransitions_SIZE(0); // ensure no LedTransitions were recorded 883 | ``` 884 | 885 | The `this->invoke_to_()` methods are used to call input ports on the component under test acting like a port invocation in the system topology but driven by our test harness. `run` is an `async` input port, it's not dispatched immediately, but instead added to an execution queue that would normally be driven off the component's thread. 886 | 887 | To dispatch a queued port message, unit tests must explicitly call the `doDispatch()` function to dispatch the first message on the queue. 888 | 889 | The F´ unit testing framework generates a series of history buffers to store a fixed amount of events, telemetry, command responses, and output ports emitted from the component. 890 | 891 | The `ASSERT_<>_SIZE(size)` (e.g. `ASSERT_EVENTS_LedState_SIZE(0)`) macros are used to assert the size of the history buffer matches your expectations. The `ASSERT_<>(index, , , )` macros are used to check that items in the history buffer match expectations. 892 | 893 | Use `fprime-util check` to make sure the test case builds and passes. 894 | 895 | Next, enable blinking, then step through 3 cycles to verify the LED component blinks the LED on, off, and the on again. 896 | 897 | ```c++ 898 | // Send command to enable blinking 899 | this->sendCmd_BLINKING_ON_OFF(0, 0, Fw::On::ON); 900 | this->component.doDispatch(); // Trigger execution of async command 901 | ASSERT_CMD_RESPONSE_SIZE(1); // ensure a command response was emitted 902 | ASSERT_CMD_RESPONSE(0, Led::OPCODE_BLINKING_ON_OFF, 0, 903 | Fw::CmdResponse::OK); // ensure the expected command response was emitted 904 | ``` 905 | 906 | The F´ unit test framework provides `this->sendCmd_COMMAND_NAME(args)` function that allows calling a command on the component under test. `BLINKING_ON_OFF` is an `async` command, it's not dispatched immediately, but instead added to an execution queue that would normally be driven off the component's thread. 907 | 908 | To dispatch a queued command, unit tests must explicitly call the `doDispatch()` function to dispatch the first message on the queue. 909 | 910 | Once dispatched, the command is ran. In your unit tests, it's good practice to check the command responded and it responded with the expected results. In this case, we expect our command to succeed with an `Fw::CmdResponse::OK` response. 911 | 912 | Now, check that the state of the component matches expectations after each of three cycles. Write assertions to fill in the todo comments. 913 | 914 | ```c++ 915 | // Step through 3 run cycles to observe LED turning on and off 3 times 916 | // Cycle 1: LED initalization->On 917 | this->invoke_to_run(0, 0); 918 | this->component.doDispatch(); // Trigger execution of async port 919 | ASSERT_EVENTS_LedState_SIZE(1); 920 | ASSERT_EVENTS_LedState(0, Fw::On::ON); 921 | ASSERT_from_gpioSet_SIZE(1); 922 | ASSERT_from_gpioSet(0, Fw::Logic::HIGH); 923 | ASSERT_TLM_LedTransitions_SIZE(1); 924 | ASSERT_TLM_LedTransitions(0, 1); 925 | 926 | // Cycle 2: LED On->Off 927 | this->invoke_to_run(0, 0); 928 | this->component.doDispatch(); // Trigger execution of async port 929 | ASSERT_EVENTS_LedState_SIZE(2); 930 | ASSERT_EVENTS_LedState(1, Fw::On::OFF); 931 | ASSERT_from_gpioSet_SIZE(2); 932 | ASSERT_from_gpioSet(1, Fw::Logic::LOW); 933 | // TODO: Add assertions for LedTransitions telemetry 934 | 935 | // Cycle 3: LED Off->On 936 | this->invoke_to_run(0, 0); 937 | this->component.doDispatch(); // Trigger execution of async port 938 | //TODO: Write assertions for third cycle 939 | ``` 940 | 941 | Run `fprime-util check` and make sure the new assertions pass. 942 | 943 | ### Adding a Parameter Test Case 944 | 945 | This second test will test that adjusting `BLINK_INTERVAL` will impact the blink interval. 946 | 947 | Add a new test case called `testBlinkInterval` and use the following code as a starting point: 948 | 949 | ```c++ 950 | void LedTester ::testBlinkInterval() { 951 | // Enable LED Blinking 952 | this->sendCmd_BLINKING_ON_OFF(0, 0, Fw::On::ON); 953 | this->component.doDispatch(); // Trigger execution of async command 954 | 955 | // Adjust blink interval to 4 cycles 956 | U32 blinkInterval = 4; 957 | this->paramSet_BLINK_INTERVAL(blinkInterval, Fw::ParamValid::VALID); 958 | this->paramSend_BLINK_INTERVAL(0, 0); 959 | ASSERT_EVENTS_BlinkIntervalSet_SIZE(1); 960 | 961 | // TODO: Add logic to test adjusted blink interval 962 | } 963 | ``` 964 | > [!NOTE] 965 | > Don't forget to add `testBlinkInterval()` to `LedTester.hpp` and `LedTestMain.cpp` as well. Run `fprime-util check` and resolve any issues before continuing. 966 | 967 | ### Checking Coverage 968 | 969 | Coverage of the code can be easily checked by adding the `--coverage` flag and opening the report with your web browser. 970 | 971 | ```shell 972 | # In LedBlinker/Components/Led 973 | fprime-util check --coverage 974 | ``` 975 | 976 | Now open the file `LedBlinker/Components/Led/coverage/coverage.html` with your web browser and explore the coverage report. 977 | ```shell 978 | # In LedBlinker/Components/Led/coverage 979 | open coverage.html 980 | ``` 981 | 982 | ### LED Blinker Step 6 Conclusion 983 | 984 | Congratulations! You've tested the `Led` component with some unit-tests. It is time to finish implementation and run on hardware! 985 | 986 | --- 987 | 988 | ## 7. LED Blinker: Full System Integration 989 | 990 | Now it is time to add a GPIO driver to our system and attach it to the `led` component instance. We'll also connect the `led` component instance to a 1 Hz rate group. Finally, we'll configure the driver to manage the GPIO 13 pin on our hardware. Once this section is finished, the system is ready for running on hardware. 991 | 992 | ### Adding the GPIO Driver to the Topology 993 | 994 | F´ provides a GPIO driver for Linux systems called `Drv.LinuxGpioDriver`. This should be added to both the instance definition list and the topology instance list just like we did for the `led` component. Since the GPIO driver is a passive component, its definition is a bit more simple. 995 | 996 | Add to "Passive Component" section of `LedBlinker/LedBlinkerDeployment/Top/instance.fpp`: 997 | ``` 998 | instance gpioDriver: Drv.LinuxGpioDriver base id 0x10015000 999 | ``` 1000 | 1001 | Add to the instance list of `LedBlinker/LedBlinkerDeployment/Top/topology.fpp`: 1002 | ``` 1003 | instance gpioDriver 1004 | ``` 1005 | 1006 | > [!NOTE] 1007 | > In `LedBlinker/LedBlinkerDeployment` build the deployment and resolve any errors before continuing. 1008 | 1009 | ### Wiring The `led` Component Instance to the `gpioComponent` Component Instance and Rate Group 1010 | 1011 | The `Led` component defines the `gpioSet` output port and the `LinuxGpioDriver` defines the `gpioWrite` input port. These two ports need to be connected from output to input. The `ActiveRateGroup` component defines an array of ports called `RateGroupMemberOut` and one of these needs to be connected to `run` port defined on the `Led` component. 1012 | 1013 | We can create a named connections block in the topology and connect the two port pairs. Remember to use the component instances and not the component definitions for each connection. 1014 | 1015 | To do this, add the following lines to `LedBlinker/LedBlinkerDeployment/Top/topology.fpp`: 1016 | ``` 1017 | # Named connection group 1018 | connections LedBlinker { 1019 | # Rate Group 1 (1Hz cycle) ouput is connected to led's run input 1020 | rateGroup1.RateGroupMemberOut[4] -> led.run 1021 | # led's gpioSet output is connected to gpioDriver's gpioWrite input 1022 | led.gpioSet -> gpioDriver.gpioWrite 1023 | } 1024 | ``` 1025 | 1026 | > [!NOTE] 1027 | > `rateGroup1` is preconfigured to call all `RateGroupMemberOut` at a rate of 1 Hz. We use index `RateGroupMemberOut[4]` because `RateGroupMemberOut[0]` through `RateGroupMemberOut[3]` were used previously in the `RateGroups` connection block. 1028 | 1029 | ### Configuring The GPIO Driver 1030 | 1031 | So far the GPIO driver has been instantiated and wired, but has not been told what GPIO pin to control. For this tutorial, GPIO pin 13 will be used. To configure this, the `open` function needs to be called in the topology's C++ implementation and passed the pin's number and direction. 1032 | 1033 | This is done by adding the following at the end of the `configureTopology` function defined in `LedBlinker/LedBlinkerDeployment/Top/LedBlinkerTopology.cpp`: 1034 | 1035 | ```c++ 1036 | Os::File::Status status = 1037 | gpioDriver.open("/dev/gpiochip4", 13, Drv::LinuxGpioDriver::GpioConfiguration::GPIO_OUTPUT); 1038 | if (status != Os::File::Status::OP_OK) { 1039 | Fw::Logger::log("[ERROR] Failed to open GPIO pin\n"); 1040 | } 1041 | ``` 1042 | 1043 | And since this code uses `Fw::Logger`, you will need to add the following line near the top of the `LedBlinker/LedBlinkerDeployment/Top/LedBlinkerTopology.cpp` file. 1044 | 1045 | ```c++ 1046 | #include 1047 | ``` 1048 | 1049 | This code tells the GPIO driver to open pin 13 as an output pin. If this fails, an error is printed to the console, but the system continues to start. 1050 | 1051 | > [!WARNING] 1052 | > In `LedBlinker/LedBlinkerDeployment` build the deployment and resolve any errors before continuing. 1053 | 1054 | ### LED Blinker Step 7 Conclusion 1055 | 1056 | Congratulations! You've wired your component to the rate group driver and GPIO driver components. It is time to try it on hardware. 1057 | 1058 | --- 1059 | 1060 | ## 8. LED Blinker: Running on Hardware 1061 | 1062 | In order to run on hardware, the deployment needs to be built for the given hardware target (a process called cross-compiling). Then the executable needs to be uploaded to the hardware, and the executable needs to be run connecting back to the host running the F´ GDS. This section will walk the user through cross-compiling, uploading, and running on hardware. 1063 | 1064 | ### Cross-Compiling for Embedded Arm Linux 1065 | 1066 | In the prerequisites for this tutorial, the ARM Linux cross-compilers were installed. In this section, we will use these compilers to cross-compile for ARM Linux by utilizing integration files called "CMake Toolchain". Follow the steps in the [ARM cross compilation tutorial](https://fprime.jpl.nasa.gov/latest/docs/tutorials/cross-compilation#cross-compilation-tutorial-compiling-for-arm) on how to compile for ARM. 1067 | 1068 | > [!NOTE] 1069 | > During the step for running the `fprime-util generate` and `fprime-util build` commands, macOS users must run from within the Docker container in the directory `/project/LedBlinker` 1070 | 1071 | ### Running on Hardware 1072 | 1073 | Now it is time to run on hardware. For this tutorial, the assumption is that the Arm Linux machine is available on the network, is running SSH, and the username, password, device address, and host address are known to the student. Without this configuration, users should skip to the next section of the tutorial. 1074 | 1075 | Follow the [F´ Running on ARM Linux Tutorial](https://fprime.jpl.nasa.gov/latest/docs/tutorials/cross-compilation#f-running-on-arm-linux-tutorial) for step-by-step instructions on how to upload the software to the hardware platform, launching F´ GDS, and for running the uploaded software. 1076 | 1077 | ### LED Blinker Step 8 Conclusion 1078 | 1079 | Congratulations you've now run on hardware. The final section of this tutorial is to test the component via some system tests! 1080 | 1081 | 1082 | --- 1083 | 1084 | ## 9. System Testing 1085 | 1086 | In this section, we will walk through the creation of system tests, also known as integration tests, for the LED component created in prior steps. 1087 | 1088 | F Prime system tests use a Python API to dispatch commands to a deployment using the F´ GDS, verifying components behave as expected as part of deployment running on actual hardware. 1089 | 1090 | Before starting this guide, users should have the LedBlinking deployment running on their hardware and connected to the F´ GDS running on a development machine. If hardware is not available, this guide can be followed by running the LedBlinking deployment locally on a development machine instead. 1091 | 1092 | > [!NOTE] 1093 | > If running the LedBlinker deployment locally instead of on the intended hardware, make sure to rebuild F´ with stubbed GPIO drivers so the LedBlinker deployment doesn't attempt to write to physical GPIO ports. Regenerate the native deployment with `fprime-util generate -DFPRIME_USE_STUBBED_DRIVERS=ON`. MacOS defaults to stubbed drivers and does not require explicitly setting this option. 1094 | 1095 | ### Intro to F Prime System Testing 1096 | 1097 | Installing the fprime-gds also installs a pytest fixture called `fprime_test_api`. When used, this allows the pytest testing library to automatically connect to the currently running fprime-gds. 1098 | 1099 | > [!NOTE] 1100 | > If running the GDS on non-default ports, you can use the same command line arguments used with `fprime-cli` with `pytest` to point the system testing library to the correct GDS instance 1101 | 1102 | 1103 | First, we'll create a basic test case to verify the system testing library is correctly setup. 1104 | 1105 | Make a directory `int`, which is a convention in flight software development for integration. Then, create the file `led_integration_tests.py` 1106 | ```shell 1107 | # In Components/Led/test 1108 | mkdir int 1109 | touch int/led_integration_tests.py 1110 | ``` 1111 | 1112 | 1113 | Open the file `Components/Led/test/int/led_integration_tests.py` and add the following contents: 1114 | 1115 | ```python 1116 | def test_cmd_no_op(fprime_test_api): 1117 | """Test command CMD_NO_OP 1118 | 1119 | Test that CMD_NO_OP can be sent and return without and errors 1120 | """ 1121 | fprime_test_api.send_and_assert_command("LedBlinker.cmdDisp.CMD_NO_OP") 1122 | ``` 1123 | 1124 | This test will send a `CMD_NO_OP` command and verify if successfully returns. 1125 | 1126 | Next, after verifying the F´ GDS is connected to your deployment, run the new system test and confirm it executes successfully. 1127 | 1128 | ```shell 1129 | # In LedBlinker/LedBlinkerDeployment 1130 | # Requires fprime-gds to be running and connected to LedBlinker deployment 1131 | $ pytest ../Components/Led/test/int/led_integration_tests.py 1132 | ``` 1133 | 1134 | ### F Prime System Testing Assertions 1135 | 1136 | The typical pattern for F´ system tests is to send a command, then wait until some condition is met, such as receiving an event. If the system test don't receive the expected results, they will time out and fail. 1137 | 1138 | `fprime_test_api.send_and_assert_command` will send a command and wait for its completion, but there are several other variants we will use in this guide. 1139 | 1140 | For example, `fprime_test_api.send_and_assert_event` will send a command, then wait for specific events to be emitted. 1141 | 1142 | Independently from sending commands, you can also search the history of received of events and telemetry to make sure deployments are sending the expected data. 1143 | 1144 | There are several variants of these assertions, but this guide will use `fprime_test_api.assert_telemetry` is used to check the expected telemetry values arrive and `fprime_test_api.assert_telemetry_count` to assert that the expected amount of telemetry arrives. 1145 | 1146 | ### Testing SetBlinking On/Off 1147 | 1148 | Next, we will develop a test for the `SetBlinkingState` command. 1149 | 1150 | 1151 | Add the following to your previously created system test `Components/Led/test/int/led_integration_tests.py`: 1152 | 1153 | 1154 | ```python 1155 | import time 1156 | 1157 | from fprime_gds.common.testing_fw import predicates 1158 | 1159 | def test_blinking(fprime_test_api): 1160 | """Test that LED component can respond to ground commands""" 1161 | ``` 1162 | 1163 | First, we will turn blinking on, verify that we receive a `SetBlinkingState` event, then check that `LedState` on and off events start arriving. After, we will turn blinking off, and make sure that a `SetBlinkingState` off event arrives. 1164 | 1165 | Add the following to the `test_blinking()` method: 1166 | 1167 | ```python 1168 | # Send command to enable blinking, then assert expected events are emitted 1169 | blink_start_evr = fprime_test_api.get_event_pred("LedBlinker.led.SetBlinkingState", ["ON"]) 1170 | led_on_evr = fprime_test_api.get_event_pred("LedBlinker.led.LedState", ["ON"]) 1171 | led_off_evr = fprime_test_api.get_event_pred("LedBlinker.led.LedState", ["OFF"]) 1172 | 1173 | fprime_test_api.send_and_assert_event( 1174 | "LedBlinker.led.BLINKING_ON_OFF", 1175 | args=["ON"], 1176 | events=[blink_start_evr, led_on_evr, led_off_evr, led_on_evr], 1177 | ) 1178 | 1179 | # Send command to stop blinking, then assert blinking stops 1180 | #TODO: Define blink_stop_evr 1181 | fprime_test_api.send_and_assert_event( 1182 | "LedBlinker.led.BLINKING_ON_OFF", args=["OFF"], events=[blink_stop_evr] 1183 | ) 1184 | ``` 1185 | 1186 | Now, run `pytest` and verify the new test passes. Open the fprime GDS webpage and see if the expected events from the test appear in the event viewer. 1187 | 1188 | ### Test BlinkingState Telemetry 1189 | 1190 | Next, we will check that the BlinkingState telemetry channel is set ON and OFF when setting blinking on and off. 1191 | 1192 | `fprime_test_api.assert_telemetry` can be used to check that telemetry matches expectations. 1193 | 1194 | In `test_blinking()`, after turning blinking on, add the following the check that BlinkingState is set ON. 1195 | 1196 | ```python 1197 | # Assert that blink command sets blinking state on 1198 | blink_state_on_tlm = fprime_test_api.get_telemetry_pred("LedBlinker.led.BlinkingState", "ON") 1199 | fprime_test_api.assert_telemetry(blink_state_on_tlm) 1200 | ``` 1201 | 1202 | Run `pytest` and make sure the new assertion passes. 1203 | 1204 | Now, add the similar assertion to verify the BlinkingState is set OFF after stopping blinking 1205 | Run `pytest` again. **Notice that this new telemetry check should fail.** 1206 | 1207 | ```python 1208 | # Assert that blink command sets blinking state off 1209 | #TODO: use fprime_test_api.assert_telemetry to check that "LedBlinker.led.BlinkingState" is off 1210 | ``` 1211 | 1212 | Events in F´ are emitted immediately, but telemetry is only emitted periodically. In the LedBlinker deployment, telemetry channels are sent once per second. 1213 | 1214 | The `fprime_test_api.assert_telemetry` check will immediately search for a matching `LedBlinker.led.BlinkingState` telemetry value. 1215 | However, because one second hasn't passed between setting blinking off and checking for telemetry, there hasn't been sufficient time for the updated telemetry value to be sent. 1216 | 1217 | To correct this, add `timeout=2` to `fprime_test_api.assert_telemetry`. This will allow this check to wait for up to 2 seconds to receive the expected telemetry before failing. 1218 | 1219 | Run `pytest` and the tests should now pass. 1220 | 1221 | ### Advanced: Test LedTransitions Telemetry 1222 | 1223 | To check that blinking stops after turning blinking off, we can check that the `LedTransitions` channel is no longer being emitted. 1224 | 1225 | Add the following assertion after disabling blinking: 1226 | 1227 | ```python 1228 | time.sleep(1) # Wait one second to let any in-progress telemetry be sent 1229 | # Save reference to current telemetry history so we can search against future telemetry 1230 | telem_after_blink_off = fprime_test_api.telemetry_history.size() 1231 | time.sleep(2) # Wait to receive telemetry after stopping blinking 1232 | # Assert that blinking has stopped and that LedTransitions is no longer updating 1233 | fprime_test_api.assert_telemetry_count( 1234 | 0, "LedBlinker.led.LedTransitions", start=telem_after_blink_off 1235 | ) 1236 | ``` 1237 | 1238 | Because telemetry is sent once per second, some outdated telemetry may be sent after disabling blinking. 1239 | After waiting 1 second for old telemetry to be sent, we can save a reference to telemetry history size, allowing us to search any telemetry received after this point. We then search telemetry using that start reference to assert that 0 new values of the LedTransitions channel are received after this start time. This allows us to confirm that blinking is no longer occurring. 1240 | 1241 | 1242 | Finally, while blinking is enabled, verify that LedTransitions increments over time. 1243 | To verify this, `fprime_test_api.assert_telemetry_count` can be used to wait for and collect a number of LedTransitions values. 1244 | 1245 | ```python 1246 | # Assert that the LedTransitions channel increments 1247 | results = fprime_test_api.assert_telemetry_count( 1248 | predicates.greater_than(2), "LedBlinker.led.LedTransitions", timeout=4 1249 | ) 1250 | ascending = True 1251 | prev = None 1252 | for res in results: 1253 | if prev is not None: 1254 | if not res.get_val() > prev.get_val(): 1255 | ascending = False 1256 | fprime_test_api.log( 1257 | f"LedBlinker.led.LedTransitions not in ascending order: First ({prev.get_val()}) Second ({res.get_val()})" 1258 | ) 1259 | prev = res 1260 | assert fprime_test_api.test_assert( 1261 | ascending, "Expected all LedBlinker.led.LedTransitions updates to ascend.", True 1262 | ) 1263 | ``` 1264 | 1265 | ## 10. LED Blinker: Conclusion 1266 | 1267 | Congratulations! You have now completed the F´ on-hardware tutorial. You should now have a solid understanding of building an F´ project that runs on hardware! 1268 | 1269 | 1270 | --- 1271 | 1272 | 1273 | ## Appendix: Optional Hardware Requirements 1274 | 1275 | You will need two hardware elements in order to run on hardware during the LedBlinker tutorial: 1276 | 1. an embedded ARM Linux computer (e.g. RaspberryPi or similar), 1277 | 2. an LED capable of withstanding the operating voltage of the computer. 1278 | 1279 | > [!IMPORTANT] 1280 | > If you do not have the hardware, you can still follow the LED Blinker tutorial! You should just skip the Hardware sections. You may also skip the rest of this page. 1281 | 1282 | ### Embedded Computer Requirements 1283 | 1284 | The embedded computer must be an ARM Linux machine with little-endian architecture and available GPIO pins. Some platforms that should work include: the RaspberryPI, Odroids, the BeagleBone, and similar platforms. The user is expected to set up Linux running Kernel 4.8+ or newer and enable the GPIO pins in the platform configuration. 1285 | 1286 | > [!NOTE] 1287 | > Write down the ARM architecture bus-width: 32-bit, or 64-bit. We will need it later. 1288 | 1289 | ### LED Requirements 1290 | 1291 | The user may use any LED that can withstand the GPIO voltage of the chosen platform (typically 3.3 or 5 volts). This usually means choosing an LED with sufficient diode drop or inlining a resistor. 1292 | 1293 | ### Wiring Diagram 1294 | 1295 | For this tutorial, GPIO pin 13 will be used. For platforms that do not have GPIO pin 13 readily available another pin should be chosen, noted, and used in-place of GPIO 13. 1296 | 1297 | ``` 1298 | GPIO 13 ----> LED + (cathode) 1299 | GND <---- LED - (anode) 1300 | ``` 1301 | 1302 | --------------------------------------------------------------------------------