diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..a78293d --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +/alire/ +.git +.unison* +**/build +**/.tar diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..4496330 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,52 @@ +# Make sure detected text files are stored with LF, since all these +# files need to work in a Linux VM. Windows users should install a +# text editor that can work with Unix line endings. +# Make everything auto that doesn't have a file extension. This ignores +# LF in binary files and the like that don't have extensions. +* text=auto +# Any text file with an extension we want to force UNIX LF. +*.* text eol=lf + +# Make sure that git recognizes the following as +# text files that should have LFs. +*.txt text eol=lf +*.sh text eol=lf +*.do text eol=lf +*.txt text eol=lf +*.c text eol=lf +*.h text eol=lf +*.cpp text eol=lf +*.hpp text eol=lf +*.adb text eol=lf +*.ads text eol=lf +*.md text eol=lf +*.py text eol=lf +*.html text eol=lf +*.htm text eol=lf +*.tex text eol=lf +*.yaml text eol=lf +*.dot text eol=lf +*.xml text eol=lf +*.csv text eol=lf +*.json text eol=lf +.gitignore text eol=lf +.gitattributes text eol=lf +Vagrantfile text eol=lf + +# These files are binary and should be left untouched +# (binary is a macro for -text -diff) +*.pptx binary +*.ppt binary +*.doc binary +*.docx binary +*.xls binary +*.xlsx binary +*.png binary +*.jpg binary +*.jpeg binary +*.gif binary +*.ico binary +*.gz binary +*.zip binary +*.pyc binary +*.pdf binary diff --git a/.github/workflows/build_linux.yml b/.github/workflows/build_linux.yml new file mode 100644 index 0000000..01682e4 --- /dev/null +++ b/.github/workflows/build_linux.yml @@ -0,0 +1,47 @@ +name: Build the Linux Assembly +on: + push: + branches: + - master + workflow_dispatch: +jobs: + compile_job: + name: build_linux_assembly + runs-on: ubuntu-latest + container: + image: dinkelk/adamant:example-latest + credentials: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + env: + INSTALL_DIR: /home/user/env + EXAMPLE_DIR: ${{ github.workspace }}/example + ADAMANT_DIR: ${{ github.workspace }}/adamant + steps: + - run: echo "Starting job triggered by a ${{ github.event_name }} event on a ${{ runner.os }} server hosted by GitHub." + - run: echo "Checking out ${{ github.repository }} on branch ${{ github.ref }}." + - name: Check out repository code + uses: actions/checkout@v3 + with: + set-safe-directory: true + path: example + - name: Clone adamant repository + uses: actions/checkout@v3 + with: + set-safe-directory: true + repository: lasp/adamant + token: ${{ secrets.GH_PAT }} # `GH_PAT` is a secret that contains your PAT + path: adamant + ref: ${{ github.ref }} + - name: Get Adamant alire dependencies + run: alr -n build --release && alr -n toolchain --select gnat_native && alr -n toolchain --select gprbuild + working-directory: ${{ env.ADAMANT_DIR }} + - name: Build the Linux binary + run: bash example/docker/env/github_run.sh "redo example/src/assembly/linux/main/build/bin/Linux/main.elf" + - name: Archive Linux binary + uses: actions/upload-artifact@v3 + with: + name: linux_elf + path: example/src/assembly/linux/main/build/bin/Linux/main.elf + if-no-files-found: error + - run: echo "Finished with status - ${{ job.status }}." diff --git a/.github/workflows/build_pico.yml b/.github/workflows/build_pico.yml new file mode 100644 index 0000000..80a9139 --- /dev/null +++ b/.github/workflows/build_pico.yml @@ -0,0 +1,52 @@ +name: Build the Pico Assembly +on: + push: + branches: + - master + workflow_dispatch: +jobs: + compile_job: + name: build_pico_assembly + runs-on: ubuntu-latest + container: + image: dinkelk/adamant:example-latest + credentials: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + env: + INSTALL_DIR: /home/user/env + EXAMPLE_DIR: ${{ github.workspace }}/example + ADAMANT_DIR: ${{ github.workspace }}/adamant + steps: + - run: echo "Starting job triggered by a ${{ github.event_name }} event on a ${{ runner.os }} server hosted by GitHub." + - run: echo "Checking out ${{ github.repository }} on branch ${{ github.ref }}." + - name: Check out repository code + uses: actions/checkout@v3 + with: + set-safe-directory: true + path: example + - name: Clone adamant repository + uses: actions/checkout@v3 + with: + set-safe-directory: true + repository: lasp/adamant + token: ${{ secrets.GH_PAT }} # `GH_PAT` is a secret that contains your PAT + path: adamant + ref: ${{ github.ref }} + - name: Get Adamant alire dependencies + run: alr -n build --release && alr -n toolchain --select gnat_native && alr -n toolchain --select gprbuild + working-directory: ${{ env.ADAMANT_DIR }} + - name: Get example alire dependencies + run: alr -n build --release + working-directory: ${{ env.EXAMPLE_DIR }} + - name: Build the Pico binary + run: bash example/docker/env/github_run.sh "redo example/src/assembly/pico/main/build/bin/Pico/main.uf2" + - name: Archive Pico binary + uses: actions/upload-artifact@v3 + with: + name: pico_elf + path: | + example/src/assembly/pico/main/build/bin/Pico/main.elf + example/src/assembly/pico/main/build/bin/Pico/main.uf2 + if-no-files-found: error + - run: echo "Finished with status - ${{ job.status }}." diff --git a/.github/workflows/publish_all.yml b/.github/workflows/publish_all.yml new file mode 100644 index 0000000..eecade7 --- /dev/null +++ b/.github/workflows/publish_all.yml @@ -0,0 +1,45 @@ +name: Build All Documentation +on: + push: + branches: + - master + workflow_dispatch: +jobs: + compile_job: + name: test_all + runs-on: ubuntu-latest + container: + image: dinkelk/adamant:example-latest + credentials: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + env: + INSTALL_DIR: /home/user/env + EXAMPLE_DIR: ${{ github.workspace }}/example + ADAMANT_DIR: ${{ github.workspace }}/adamant + steps: + - run: echo "Starting job triggered by a ${{ github.event_name }} event on a ${{ runner.os }} server hosted by GitHub." + - run: echo "Checking out ${{ github.repository }} on branch ${{ github.ref }}." + - name: Check out repository code + uses: actions/checkout@v3 + with: + set-safe-directory: true + path: example + - name: Clone adamant repository + uses: actions/checkout@v3 + with: + set-safe-directory: true + repository: lasp/adamant + token: ${{ secrets.GH_PAT }} # `GH_PAT` is a secret that contains your PAT + path: adamant + ref: ${{ github.ref }} + - name: Get Adamant alire dependencies + run: alr -n build --release && alr -n toolchain --select gnat_native && alr -n toolchain --select gprbuild + working-directory: ${{ env.ADAMANT_DIR }} + - name: Get example alire dependencies + run: alr -n build --release + working-directory: ${{ env.EXAMPLE_DIR }} + - name: Build all documentation + run: bash example/docker/env/github_run.sh "redo example/publish" + - run: echo "Finished with status - ${{ job.status }}." + if: always() diff --git a/.github/workflows/style_all.yml b/.github/workflows/style_all.yml new file mode 100644 index 0000000..6e40ae1 --- /dev/null +++ b/.github/workflows/style_all.yml @@ -0,0 +1,51 @@ +name: Check Style +on: + push: + branches: + - master + workflow_dispatch: +jobs: + compile_job: + name: style_all + runs-on: ubuntu-latest + container: + image: dinkelk/adamant:example-latest + credentials: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + env: + INSTALL_DIR: /home/user/env + EXAMPLE_DIR: ${{ github.workspace }}/example + ADAMANT_DIR: ${{ github.workspace }}/adamant + steps: + - run: echo "Starting job triggered by a ${{ github.event_name }} event on a ${{ runner.os }} server hosted by GitHub." + - run: echo "Checking out ${{ github.repository }} on branch ${{ github.ref }}." + - name: Check out repository code + uses: actions/checkout@v3 + with: + set-safe-directory: true + path: example + - name: Clone adamant repository + uses: actions/checkout@v3 + with: + set-safe-directory: true + repository: lasp/adamant + token: ${{ secrets.GH_PAT }} # `GH_PAT` is a secret that contains your PAT + path: adamant + ref: ${{ github.ref }} + - name: Get Adamant alire dependencies + run: alr -n build --release && alr -n toolchain --select gnat_native && alr -n toolchain --select gprbuild + working-directory: ${{ env.ADAMANT_DIR }} + - name: Get example alire dependencies + run: alr -n build --release + working-directory: ${{ env.EXAMPLE_DIR }} + - name: Check all style + run: bash example/docker/env/github_run.sh "redo example/style_all" + continue-on-error: true + - name: Archive logs for failed style checks + uses: actions/upload-artifact@v3 + with: + name: failed_style_logs + path: example/build/failed_style_logs + if-no-files-found: ignore + - run: echo "Finished with status - ${{ job.status }}." diff --git a/.github/workflows/test_all.yml b/.github/workflows/test_all.yml new file mode 100644 index 0000000..2c05e5c --- /dev/null +++ b/.github/workflows/test_all.yml @@ -0,0 +1,51 @@ +name: Run All Unit Tests +on: + push: + branches: + - master + workflow_dispatch: +jobs: + compile_job: + name: test_all + runs-on: ubuntu-latest + container: + image: dinkelk/adamant:example-latest + credentials: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + env: + INSTALL_DIR: /home/user/env + EXAMPLE_DIR: ${{ github.workspace }}/example + ADAMANT_DIR: ${{ github.workspace }}/adamant + steps: + - run: echo "Starting job triggered by a ${{ github.event_name }} event on a ${{ runner.os }} server hosted by GitHub." + - run: echo "Checking out ${{ github.repository }} on branch ${{ github.ref }}." + - name: Check out repository code + uses: actions/checkout@v3 + with: + set-safe-directory: true + path: example + - name: Clone adamant repository + uses: actions/checkout@v3 + with: + set-safe-directory: true + repository: lasp/adamant + token: ${{ secrets.GH_PAT }} # `GH_PAT` is a secret that contains your PAT + path: adamant + ref: ${{ github.ref }} + - name: Get Adamant alire dependencies + run: alr -n build --release && alr -n toolchain --select gnat_native && alr -n toolchain --select gprbuild + working-directory: ${{ env.ADAMANT_DIR }} + - name: Get example alire dependencies + run: alr -n build --release + working-directory: ${{ env.EXAMPLE_DIR }} + - name: Run all unit tests + run: bash example/docker/env/github_run.sh "redo example/test_all" + continue-on-error: true + - name: Archive logs for failed unit tests + uses: actions/upload-artifact@v3 + with: + name: failed_test_logs + path: example/build/failed_test_logs + if-no-files-found: ignore + - run: echo "Finished with status - ${{ job.status }}." diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ecfa4c0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,19 @@ +build/ +.vagrant +.Trash* +.pyenv/ +*.pyc +__pycache__/ +.tmp +.DS_Store +*.swp +GNAT-* +*.tmp +~$* +.unison* + +# Standard alire ignores: +/alire/ +/config/ +!/config/README.md +!/config/example.configuration.yaml diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..64f8612 --- /dev/null +++ b/NOTICE @@ -0,0 +1,2 @@ +Adamant +Copyright (c) 2023 The Regents of the University of Colorado diff --git a/README.md b/README.md new file mode 100644 index 0000000..02371db --- /dev/null +++ b/README.md @@ -0,0 +1,49 @@ +# Adamant Example Project + +[![Build the Linux Assembly](https://github.com/lasp/example/actions/workflows/build_linux.yml/badge.svg)](https://github.com/lasp/example/actions/workflows/build_linux.yml) +[![Build the Pico Assembly](https://github.com/lasp/example/actions/workflows/build_pico.yml/badge.svg)](https://github.com/lasp/example/actions/workflows/build_pico.yml) +[![Run All Unit Tests](https://github.com/lasp/example/actions/workflows/test_all.yml/badge.svg)](https://github.com/lasp/example/actions/workflows/test_all.yml) +[![Check Style](https://github.com/lasp/example/actions/workflows/style_all.yml/badge.svg)](https://github.com/lasp/example/actions/workflows/styl_all.yml) +[![Build All Documentation](https://github.com/lasp/example/actions/workflows/publish_all.yml/badge.svg)](https://github.com/lasp/example/actions/workflows/publish_all.yml) + +This repository contains an example project which utilizes the [Adamant](https://github.com/lasp/adamant) software framework. Its purpose is to demonstrate how the framework can be used to create components, unit test components, and connect those components together into an executable assembly. + +The project can be compiled for two different targets, a Linux desktop environment and the [Raspberry Pi Pico](https://www.raspberrypi.com/products/raspberry-pi-pico/). + +![`Adamant on the Raspberry Pi Pico`](src/assembly/pico/main/img/pico.jpg "Adamant on the Raspberry Pi Pico") + +## Getting Started + + 1. First, we need to set up the development environment for the project by following [this guide](docker/README.md). + 2. Build, run, and explore the [Linux assembly](src/assembly/linux/main/README.md). + 3. Build, run, and explore the [Raspberry Pi Pico assembly](src/assembly/pico/main/README.md). + 4. Copy, modify, and adapt the example project for your own project. + +## Need Help? + + * Have a question or suggestion? Please use the project's [discussions](https://github.com/lasp/example/discussions). + * Find a bug? Please [submit an issue](https://github.com/lasp/example/issues). + +## Contributing + +Contributions are welcome! This repository follows the guidelines from the main Adamant repository. For details see [CONTRIBUTING.md](https://github.com/lasp/adamant/blob/main/CONTRIBUTING.md). + +## Resources + +Below are some helpful resources for learning up on [Adamant](https://github.com/lasp/adamant) and the various tools used in this framework. + + * The design documents for the example assemblies can be found here: [Linux](src/assembly/linux/doc/linux_example.pdf), [Raspberry Pi Pico](src/assembly/pico/doc/pico_example.pdf). + * The [Architecture Description Document](https://github.com/lasp/adamant/blob/main/doc/architecture_description_document/architecture_description_document.pdf) provides an overview of Adamant's architecture and main concepts. + * The [User Guide](https://github.com/lasp/adamant/blob/main/doc/user_guide/user_guide.pdf) is a comprehensive resource for developers looking to start using the Adamant framework. + * New to Ada or SPARK? Learn more [here](https://learn.adacore.com/). But familiar with C++ or Java? Take a look at [this guide](https://learn.adacore.com/courses/Ada_For_The_CPP_Java_Developer/index.html). + * Learn more about Adamant's [redo](https://github.com/dinkelk/redo)-based build system. + +## Directory Structure + +The following is a description of what you can expect to find in the subdirectories of this directory. + + * `config/` - Adamant configuration file for the project + * `env/` - files used for configuring the development environment used by the project + * `redo/` - [redo](https://github.com/dinkelk/redo) build files for the project + * `src/` - the source code which makes up the project + * `docker/` - files for configuring the development environment used for this project diff --git a/alire.toml b/alire.toml new file mode 100644 index 0000000..9c9065a --- /dev/null +++ b/alire.toml @@ -0,0 +1,31 @@ +# +# This alire.toml is used to download the Raspberry Pi Pico cross compile +# dependencies for the Adamant example repository. The Adamant build system +# then uses these dependencies via the `alr printenv` GPR_BUILD_PATH to +# compile targets within this repository. This alire.toml itself only points +# to a simple hello world program that demonstrates tasking, LED blinking, +# and UART transmition on the Raspberry Pi Pico. +# + +name = "adamant_example" +description = "Example project for the Adamant software framework." +version = "1.0.0" +licenses = "Apache-2.0" +# Project file lives with the hello pico program: +project-files = ["src/pico_util/hello_pico/hello_pico.gpr"] + +tags = ["embedded", "framework", "demo", "rp2040", "raspberrypi"] +website = "https://github.com/lasp/example" + +[[depends-on]] +ravenscar_full_rp2040 = "~0.2.0" +[[pins]] +ravenscar_full_rp2040 = { url='https://github.com/dinkelk/ravenscar_full_rp2040.git', branch="pico-bsp" } + +[configuration.values] +rp2040_hal.Use_Startup = false + +[[depends-on]] +pico_bsp = "^2.0.0" +[[pins]] +pico_bsp = { url='https://github.com/dinkelk/pico_bsp.git', branch="ravenscar" } diff --git a/clean.do b/clean.do new file mode 100644 index 0000000..724a3b6 --- /dev/null +++ b/clean.do @@ -0,0 +1,23 @@ +#!/usr/bin/env python + +# Optimize python path: +from util import performance +performance.optimize_path() + +# Imports +import sys +import os +import glob + +# Special clean that removes b~main files before +# doing the normal clean. +if __name__ == "__main__": + assert len(sys.argv) == 4 + for hgx in glob.glob("b~*"): + os.remove(hgx) + from rules.build_clean import build_clean + rule = build_clean() + rule.build(*sys.argv[1:]) + +# Exit fast: +performance.exit() diff --git a/config/README.md b/config/README.md new file mode 100644 index 0000000..74aa417 --- /dev/null +++ b/config/README.md @@ -0,0 +1,13 @@ +# Config + +## Description + +This directory contains configuration files used to tune specific parameters within Adamant to tailor it +for a specific project. + +## Contents + +The Adamant framework will not function without a configuration file used to defined certain core values. +The configuration file for the example repository was copied from the Adamant repository +[adamant.configuration.yaml.original](https://github.com/dinkelk/adamant/blob/open_source/config/adamant.configuration.yaml.original) +and modified as necessary. diff --git a/config/example.configuration.yaml b/config/example.configuration.yaml new file mode 100644 index 0000000..cf6260f --- /dev/null +++ b/config/example.configuration.yaml @@ -0,0 +1,120 @@ +# example.configuration.yaml +# +# This file provides global definitions for Adamant. These variables are +# used to configure Adamant for a specific project. Changeable entities +# include the sizing of different core data types, etc. +# +# Note: This file is not meant to be checked into a version control system +# in this location, as it will be different for every usage of Adamant. +# +# Instead consider version controlling it inside of your project repository +# and copying it into this location on startup. Alternatively, the Adamant +# build system looks for the location of this file using the environment +# variable ADAMANT_CONFIGURATION_YAML. If you set that variable to a configuration +# file stored in your project repository, then Adamant will load your desired +# variables. +# +# Variables defined below should be simple YAML maps, mapping a string key to a +# numeral value. +# +# To reference these variables within an Adamant YAML file you need to use Jinja +# format for variable reference: https://jinja.palletsprojects.com/en/2.11.x/ +# For example to use value of the data_product_buffer_size variable within your YAML +# you would write {{ data_product_buffer_size }} in the location you wish the +# substitution to occur. +# +# To reference these variables within an Ada file you need to "with" the package +# Configuration +--- +# Description of this configuration file. +description: This is the configuration for the Example repository. +################################################################################# +# REQUIRED - Adamant Configuration Values +################################################################################# +# +# Type Sizing Variables - The following are used to size core types within Adamant +# for your project. +# +# The size of the buffer within the data product type (in bytes). This buffer is +# used to serialize the data product type. Choose a size that fits the largest +# data product type in your system: +data_product_buffer_size: 32 + +# The size of the buffer within the command type (in bytes). This buffer is +# used to serialize the command arguments. Choose a size that fits the largest +# command argument in your system: +command_buffer_size: 255 + +# The size of the buffer within the event type (in bytes). This buffer is +# used to serialize the event parameters. Choose a size that fits the largest +# event parameters in your system: +event_buffer_size: 32 + +# The size of the buffer within the parameter type (in bytes). This buffer is +# used to serialize the parameter type. Choose a size that fits the largest +# parameter type in your system: +parameter_buffer_size: 32 + +# The size of the buffer within the fault type (in bytes). This buffer is +# used to serialize the fault parameters. Choose a size that fits the largest +# fault parameters in your system: +fault_buffer_size: 8 + +# The size of the buffer within the CCSDS space packet type. If you are not +# using CCSDS then you can leave this value as the default. +# This is sized for largest possible packet in system based on the maximum ISS 1553 CCSDS packet size. +ccsds_packet_buffer_size: 1274 + +# The size of the buffer within the packet type (in bytes). +# The current size of a CCSDS data packet is 1274, which is the maximum for a ISS LRT. We need to subtract the +# following: +# +# 10 byte lrt secondary header +# 2 byte lrt checksum +# 6 bytes ccsds primary header +# 8 bytes ccsds secondary header +# 2 byte ccsds checksum +# +# For telemetry, this includes 2 bytes for a checksum, and +# 16 bytes for a secondary header. This is very fragile, but for now, the size of an Adamant packet needs to depend +# on the size of a CCSDS packet. +packet_buffer_size: 1246 + +# +# Other Variables - Various configurations that do not have to do with core types +# + +# The stack margin in bytes. This value is used in src/core/task/task_util.adb to +# define the amount of "usable" stack used by the Stack Monitor component. You should +# size this value as small as possible, but the value MUST be larger than the amount +# of stack that a task uses prior to calling the Cycle procedure the first time, and MUST +# be smaller than that smallest task stack efined in the system. When in doubt, leave +# this value at the default. +# +# Note, this value only affects bareboard runtimes. Linux uses a predefined stack margin +# of 12KB defined in src/core/task/linux/stack_margin.ads. +stack_margin: 1000 + +# The command registration delay in microseconds. This value is used by each commandable component +# when registering commands. After sending out the command registration, the component will sleep +# for this many microseconds before registering its next command. The purpose of this delay is to +# reduce the stress on the queue of the component who is receiving the command registrations, +# usually the Command Router. By sleeping, it allows time for the command router to process the +# registration before a new item is put on its queue. If registration items are falling off the +# Command Router's queue at initialization you can increase this sleep time, or increase the +# queue size of the Command Router depending on which is more suitable for your mission. +command_registration_delay: 250 # microseconds + +################################################################################# +# OPTIONAL - Custom Project Specific Configuration Values +################################################################################# +# Define your own key value pairs below. You will be able to use these +# within your own YAML or Ada files using the methods described at the +# top of this file. +# +# Examples of a project specific variables: +# project_specific_variable: 17 +# project_specific_string: "This project rocks!" + +# Add URL to CodePeer IDE server: +# codepeer_ide_server: http://path:8081 diff --git a/default.do b/default.do new file mode 100644 index 0000000..32dc773 --- /dev/null +++ b/default.do @@ -0,0 +1,90 @@ +#!/usr/bin/env python + +# Optimize python path: +from util import performance +performance.optimize_path() + +# Imports +import sys +from util import redo_arg + +# This is the catch all .do file. If none of the other +# do files in this directory match a redo target, then +# this .do file is executed. It handles special redo +# commands like "redo all" or "redo what" as well as +# building files that could have any extension, such +# as those built by a generator. + +if __name__ == "__main__": + assert len(sys.argv) == 4 + directory, base = redo_arg.split_redo_arg(sys.argv[2]) + rule_cls = None + # Is the file a product of the metric generator: + if redo_arg.in_build_metric_dir(sys.argv[2]): + from rules.build_metric import build_metric as rule_cls + # Is the file a type range yaml file? + elif base.endswith(".type_ranges.yaml"): + from rules.build_type_ranges_yaml import build_type_ranges_yaml as rule_cls + elif base.endswith("_h.ads") or base.endswith("_hpp.ads"): + from rules.build_bindings import build_bindings as rule_cls + # Is the file a product of a generator? + elif redo_arg.in_build_dir(sys.argv[2]): + from rules.build_via_generator import build_via_generator as rule_cls + # Special redo directives: + elif base == "clean": + from rules.build_clean import build_clean as rule_cls + elif base == "clean_all": + from rules.build_clean_all import build_clean_all as rule_cls + elif base == "what": + from rules.build_what import build_what as rule_cls + elif base == "prove": + from rules.build_prove import build_prove as rule_cls + elif base == "analyze": + from rules.build_analyze import build_analyze as rule_cls + elif base == "style": + from rules.build_style import build_style as rule_cls + elif base == "style_all": + from rules.build_style_all import build_style_all as rule_cls + elif base == "pretty": + from rules.build_pretty import build_pretty as rule_cls + elif base == "targets": + from rules.build_targets import build_targets as rule_cls + elif base == "templates": + from rules.build_templates import build_templates as rule_cls + elif base == "all": + from rules.build_all import build_all as rule_cls + elif base == "recursive": + from rules.build_recursive import build_recursive as rule_cls + elif base == "path": + from rules.build_path import build_path as rule_cls + elif base == "print_path": + from rules.build_print_path import build_print_path as rule_cls + elif base == "test": + from rules.build_test import build_test as rule_cls + elif base == "coverage": + from rules.build_coverage import build_coverage as rule_cls + from util import target as tgt + tgt.set_default_coverage_target() + elif base == "run": + from rules.build_run import build_run as rule_cls + elif base == "test_all": + from rules.build_test_all import build_test_all as rule_cls + elif base == "coverage_all": + from rules.build_coverage_all import build_coverage_all as rule_cls + elif base == "publish": + from rules.build_publish import build_publish as rule_cls + elif base == "codepeer_server": + from rules.build_codepeer_server import build_codepeer_server as rule_cls + elif base == "yaml_sloc": + from rules.build_yaml_sloc import build_yaml_sloc as rule_cls + + # Run the rule + if rule_cls: + rule = rule_cls() + rule.build(*sys.argv[1:]) + else: + from util import error + error.error_abort("default.do: No rule to build '" + sys.argv[1] + "'.") + +# Exit fast: +performance.exit() diff --git a/default.elf.do b/default.elf.do new file mode 100644 index 0000000..ac2cf59 --- /dev/null +++ b/default.elf.do @@ -0,0 +1,19 @@ +#!/usr/bin/env python + +# Optimize python path: +from util import performance +performance.optimize_path() + +# Imports +import sys +from rules.build_executable import build_executable + +# This .do file builds .elf (executable binary) files. + +if __name__ == "__main__": + assert len(sys.argv) == 4 + rule = build_executable() + rule.build(*sys.argv[1:]) + +# Exit fast: +performance.exit() diff --git a/default.eps.do b/default.eps.do new file mode 100644 index 0000000..70296e4 --- /dev/null +++ b/default.eps.do @@ -0,0 +1,19 @@ +#!/usr/bin/env python + +# Optimize python path: +from util import performance +performance.optimize_path() + +# Imports +import sys +from rules.build_eps import build_eps + +# This .do file builds .eps (PostScript) files. + +if __name__ == "__main__": + assert len(sys.argv) == 4 + rule = build_eps() + rule.build(*sys.argv[1:]) + +# Exit fast: +performance.exit() diff --git a/default.gpr.do b/default.gpr.do new file mode 100644 index 0000000..6fe0422 --- /dev/null +++ b/default.gpr.do @@ -0,0 +1,19 @@ +#!/usr/bin/env python + +# Optimize python path: +from util import performance +performance.optimize_path() + +# Imports +import sys +from rules.build_gpr import build_gpr + +# This .do file builds .gpr files. + +if __name__ == "__main__": + assert len(sys.argv) == 4 + rule = build_gpr() + rule.build(*sys.argv[1:]) + +# Exit fast: +performance.exit() diff --git a/default.o.do b/default.o.do new file mode 100644 index 0000000..53cec04 --- /dev/null +++ b/default.o.do @@ -0,0 +1,19 @@ +#!/usr/bin/env python + +# Optimize python path: +from util import performance +performance.optimize_path() + +# Imports +import sys +from rules.build_object import build_object + +# This .do file builds .o (object) files. + +if __name__ == "__main__": + assert len(sys.argv) == 4 + rule = build_object() + rule.build(*sys.argv[1:]) + +# Exit fast: +performance.exit() diff --git a/default.pdf.do b/default.pdf.do new file mode 100644 index 0000000..22ebae7 --- /dev/null +++ b/default.pdf.do @@ -0,0 +1,19 @@ +#!/usr/bin/env python + +# Optimize python path: +from util import performance +performance.optimize_path() + +# Imports +import sys +from rules.build_pdf import build_pdf + +# This .do file builds .pdf files. + +if __name__ == "__main__": + assert len(sys.argv) == 4 + rule = build_pdf() + rule.build(*sys.argv[1:]) + +# Exit fast: +performance.exit() diff --git a/default.png.do b/default.png.do new file mode 100644 index 0000000..7881d69 --- /dev/null +++ b/default.png.do @@ -0,0 +1,19 @@ +#!/usr/bin/env python + +# Optimize python path: +from util import performance +performance.optimize_path() + +# Imports +import sys +from rules.build_png import build_png + +# This .do file builds .png files. + +if __name__ == "__main__": + assert len(sys.argv) == 4 + rule = build_png() + rule.build(*sys.argv[1:]) + +# Exit fast: +performance.exit() diff --git a/default.svg.do b/default.svg.do new file mode 100644 index 0000000..45782fb --- /dev/null +++ b/default.svg.do @@ -0,0 +1,19 @@ +#!/usr/bin/env python + +# Optimize python path: +from util import performance +performance.optimize_path() + +# Imports +import sys +from rules.build_svg import build_svg + +# This .do file builds .svg (vector graphics) files. + +if __name__ == "__main__": + assert len(sys.argv) == 4 + rule = build_svg() + rule.build(*sys.argv[1:]) + +# Exit fast: +performance.exit() diff --git a/default.uf2.do b/default.uf2.do new file mode 100644 index 0000000..771be31 --- /dev/null +++ b/default.uf2.do @@ -0,0 +1,5 @@ +#!/bin/sh + +elf=$2.elf +redo-ifchange $elf +elf2uf2 $elf $3 diff --git a/docker/.gitignore b/docker/.gitignore new file mode 100644 index 0000000..6df453c --- /dev/null +++ b/docker/.gitignore @@ -0,0 +1,4 @@ +*.tar +docker_container_name.sh +.Trash +*.log diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..d91c20f --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,213 @@ +# +# This Dockerfile needs to be run from within the project/ directory (AKA ../../ from here) +# so that docker has access to all the files it needs. ie. +# +# $ docker build -t $DOCKER_IMAGE_NAME -f example/docker/Dockerfile . +# +# For best results use the ./build_image.sh and ./create_container.sh scripts +# provided in this directory. +# +FROM ubuntu:22.04 AS base + +ENV DEBIAN_FRONTEND=noninteractive +ARG DOCKER_USER=user + +# install common dependencies +RUN DEBIAN_FRONTEND=noninteractive apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -yq install \ + software-properties-common \ + apt-utils \ + locales \ + curl \ + lsb-release \ + # openssh-server \ + sudo \ + python3 \ + git \ + build-essential \ + && DEBIAN_FRONTEND=noninteractive apt-get -yq clean + +# ensure we have the en_US.UTF-8 locale available +RUN locale-gen en_US.UTF-8 + +# setup the user +RUN if ! getent passwd $DOCKER_USER; then useradd -d /home/$DOCKER_USER -m -s /bin/bash $DOCKER_USER; fi \ + && echo $DOCKER_USER:$DOCKER_USER | chpasswd \ + && echo "$DOCKER_USER ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers \ + && mkdir -p /etc/sudoers.d \ + && echo "$DOCKER_USER ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/$DOCKER_USER \ + && chmod 0440 /etc/sudoers.d/$DOCKER_USER + +RUN rm /etc/apt/apt.conf.d/docker-clean + +# Add environment variables: +ENV HOME=/home/$DOCKER_USER +ENV ENV_DIR=$HOME/env +ENV PROVISION_DIR=$ENV_DIR/provision +ENV BIN_DIR=/usr/local/bin +RUN mkdir -p $PROVISION_DIR + +# +# Adamant add-on portion: +# +FROM base as adamant_base + +# Copy files: +USER $DOCKER_USER +COPY example/docker/env/provision/bashrc.sh $HOME/.bashrc +COPY example/docker/env/provision/example.prf $HOME/.unison/example.prf +COPY adamant/env/provision/adamant.prf $HOME/.unison/adamant.prf + +# Set up symlink to shared folder: +USER root +RUN if ! test -d /share; then mkdir /share; fi +RUN if ! test -d $HOME/share; then ln -sf /share $HOME/share; fi + +# Install some base Adamant dependencies: +# +# Note: Due to this issue: +# +# https://bugs.python.org/issue40350 +# https://github.com/python/cpython/issues/84530 +# +# We need to use python 3.7 until it is resolved. +# By default this version of Ubuntu uses 3.8 which +# exhibits the bug. +RUN cat /dev/zero | ssh-keygen -q -N "" \ + && echo "vm.swappiness = 0" > /etc/sysctl.conf \ + && sudo ln -sf /usr/lib/x86_64-linux-gnu/libreadline.so.8 /usr/lib/x86_64-linux-gnu/libreadline.so.7 \ + && DEBIAN_FRONTEND=noninteractive add-apt-repository -y ppa:linuxuprising/libpng12 \ + && DEBIAN_FRONTEND=noninteractive add-apt-repository -y ppa:deadsnakes/ppa \ + && apt install --reinstall -y software-properties-common \ + && add-apt-repository ppa:linuxuprising/libpng12 \ + && add-apt-repository ppa:deadsnakes/ppa \ + && DEBIAN_FRONTEND=noninteractive apt-get update \ + && DEBIAN_FRONTEND=noninteractive apt-get install -yq socat graphviz libpng12-0 gawk xxd time psmisc python3.7 python3.7-venv python3.7-dev \ + && DEBIAN_FRONTEND=noninteractive apt install -yq `DEBIAN_FRONTEND=noninteractive apt --assume-no install texlive-full | \ + awk '/The following additional packages will be installed/{f=1;next} /Suggested packages/{f=0} f' | \ + tr ' ' '\n' | \ + grep -vP 'doc$' | \ + grep -vP 'texlive-lang' | \ + grep -vP 'texlive-fonts' | \ + grep -vP 'latex-cjk' | \ + tr '\n' ' '` \ + && DEBIAN_FRONTEND=noninteractive apt install -yq texlive-lang-english texlive-lang-european texlive-fonts-recommended \ + && DEBIAN_FRONTEND=noninteractive apt-get -yq clean + +# Install python: +# Do to this issue: https://bugs.python.org/issue40350 +# We need to use python 3.7 until it is resolved. +# By default this version of Ubuntu uses 3.8 which +# exhibits the bug. +ENV PYTHON_ENV_DIR=$ENV_DIR/python +COPY adamant/env/provision $ENV_DIR/requirements +RUN DEBIAN_FRONTEND=noninteractive sudo apt-get -yq install python3.7 \ + && python3.7 -m venv $PYTHON_ENV_DIR \ + && . $PYTHON_ENV_DIR/bin/activate \ + && pip3.7 install --upgrade pip \ + && pip3.7 install wheel \ + && pip3.7 install -r $ENV_DIR/requirements/requirements1.txt \ + && pip3.7 install -r $ENV_DIR/requirements/requirements2.txt + +# Install unison: +FROM base AS install_unison +RUN DEBIAN_FRONTEND=noninteractive sudo apt-get install -yq wget ocaml make \ + && cd $PROVISION_DIR \ + && git clone https://github.com/bcpierce00/unison \ + && cd $PROVISION_DIR/unison \ + && git fetch --tags \ + && git checkout v2.53.3 \ + && make + +# Install redo: +FROM base AS install_redo +ENV STACK_ROOT=/root/.stack +RUN DEBIAN_FRONTEND=noninteractive sudo apt-get install -yq wget \ + && wget -qO- https://get.haskellstack.org/ | sh \ + && git config --global core.autocrlf false \ + && git clone https://github.com/dinkelk/redo.git $PROVISION_DIR/redo \ + && $PROVISION_DIR/redo/do $PROVISION_DIR/redo/all + +# Install elf2uf2 +# +# source: https://circuitdigest.com/microcontroller-projects/how-to-program-raspberry-pi-pico-using-c +# +# # Install prerequisites: +# sudo apt install git cmake gcc-arm-none-eabi gcc g++ libstdc++-arm-none-eabi-newlib +# sudo apt-get install cmake make +# sudo apt install automake autoconf build-essential texinfo libtool libftdi-dev libusb-1.0-0-dev +# ^ The prepreqs for compiling elf2uf2 are already installed at this point, +# but leaving this comment here for reference +# +FROM base AS install_elf2uf2 +RUN DEBIAN_FRONTEND=noninteractive sudo apt-get install -yq make cmake \ + && mkdir -p $PROVISION_DIR/pico \ + && cd $PROVISION_DIR/pico \ + && git clone -b master https://github.com/raspberrypi/pico-sdk.git \ + && cd $PROVISION_DIR/pico/pico-sdk/tools/elf2uf2 \ + && mkdir build \ + && cd build \ + && cmake .. \ + && make + +# Install Alire: +FROM base AS install_alire +ENV ALIRE_VERSION="1.2.2" +ENV ALIRE_FILE=alr-$ALIRE_VERSION-bin-x86_64-linux.zip +ENV ALIRE_URL=https://github.com/alire-project/alire/releases/download/v$ALIRE_VERSION/$ALIRE_FILE +RUN DEBIAN_FRONTEND=noninteractive sudo apt-get install -yq wget unzip \ + && mkdir -p $PROVISION_DIR/alire \ + && cd $PROVISION_DIR/alire \ + && wget $ALIRE_URL \ + && rm -rf bin \ + && unzip $ALIRE_FILE \ + && cp -r $PROVISION_DIR/alire/bin/alr $BIN_DIR + +# Install GNAT tools like gnatpp and gnatmetric: +FROM install_alire AS install_libadalang +RUN mkdir -p $PROVISION_DIR/libadalang \ + && cd $PROVISION_DIR/libadalang \ + && git clone https://github.com/dinkelk/libadalang_tool_builder.git \ + && cd libadalang_tool_builder \ + && alr -n build --release \ + && mkdir tools \ + && sh install.sh tools + +# +# This build stage increases the docker image size by several GB. Delaying the +# configuration of the Ada dependencies to the first time the container is +# created only adds about 1 minute to the configuration time. So instead of +# adding the "install_ada_deps" to the base image, we delay this part of the +# configuration until the container is created by the user. +# +# FROM install_alire AS install_ada_deps +# USER root +# COPY adamant $HOME/adamant +# COPY example $HOME/example +# RUN chown -R $DOCKER_USER:$DOCKER_USER $HOME +# +# # Install Adamant Ada dependencies: +# USER $DOCKER_USER +# RUN cd $HOME/adamant \ +# && alr -n build --release \ +# && alr -n toolchain --select gnat_native \ +# && alr -n toolchain --select gprbuild +# +# # Install Example Ada dependencies: +# RUN cd $HOME/example \ +# && alr -n build --release +# + +# Construct the final image from the multi-step build images above: +FROM adamant_base AS final +USER root +COPY --from=install_unison $PROVISION_DIR/unison/src/unison $BIN_DIR +COPY --from=install_unison $PROVISION_DIR/unison/src/unison-fsmonitor $BIN_DIR +COPY --from=install_redo $PROVISION_DIR/redo/bin/* $BIN_DIR +COPY --from=install_alire $PROVISION_DIR/alire/bin/alr $BIN_DIR +COPY --from=install_elf2uf2 $PROVISION_DIR/pico/pico-sdk/tools/elf2uf2/build/elf2uf2 $BIN_DIR +COPY --from=install_libadalang $PROVISION_DIR/libadalang/libadalang_tool_builder/tools/* $BIN_DIR +# COPY --from=install_ada_deps $HOME/.config $HOME/.config +RUN chown -R $DOCKER_USER:$DOCKER_USER $HOME + +# Make sure user is root at end. +USER root diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 0000000..04c0419 --- /dev/null +++ b/docker/README.md @@ -0,0 +1,90 @@ +# Adamant Environment Setup + +Below is the procedure for creating the Adamant build environment for the Example Project. Adamant requires quite a few dependencies. To make this easy to manage, a [pre-built Docker image](https://hub.docker.com/r/dinkelk/adamant/tags) is provided to get you started with minimal fuss. + +Note, the following has been tested successfully on MacOS, Ubuntu Linux, and Windows with [Git for Windows](https://git-scm.com/download/win) and [WSL](https://learn.microsoft.com/en-us/windows/wsl/install). If you cannot get things working on your machine, please submit an issue or a fix via pull request. + +## Creating the Environment + +This procedure is used to create a new Docker container that hosts the Adamant build environment. This is only meant to be run once. If you have already created the container, proceed to the next section to start the container. + + 1. Start by downloading [Docker Desktop](https://www.docker.com/products/docker-desktop/). + 2. Next, create a new project directory and clone both the [Adamant](https://github.com/lasp/adamant) and [Example](https://github.com/lasp/adamant) repositories. + + ``` + $ mkdir project + $ cd project + $ git clone https://github.com/lasp/example.git + $ git clone https://github.com/lasp/adamant.git + ``` + + 3. Next, tell Docker to create a new container from the [pre-built image](https://hub.docker.com/r/dinkelk/adamant/tags). This make take a few minutes and ~6 GB of disk space. By default the container created is named `adamant_example_container`. To change this, or the image that the container uses, modify `docker_config.sh` before running the commands below. + + ``` + $ cd example/docker + $ ./create_container.sh + ``` + + 4. Finally, you can log into the container by running. + + ``` + $ ./login_container.sh + ``` + +The `example/` and `adamant/` directories in `project/` will be shared with the new Docker container at `~/example/` and `~/adamant/`. + +**Note**: The entire `project/` directory on the host is shared with the Docker container via a bind mount at `/share/`. Compiling +is slow when done on files in a mounted folder, so internal to the Docker container, [unison](https://github.com/bcpierce00/unison) is +used to bi-directional sync `/share/adamant/` and `/share/example/` to `~/adamant/` and `~/example/` respectively. This significantly increases the performance +of the build system. Be aware that there can be some latency or other issues with the internal sync when changing git branches, cleaning, or making +other changes that modify many files quickly. If you get stuck, try restarting the container via `./stop_container.sh` and `./start_container.sh`. + +## Starting and Stopping the Container + +Once you have created a container using the section above you can stop it by running. + + ``` + $ ./stop_container.sh + ``` + +To start the container up again, run: + + ``` + $ ./start_container.sh + ``` + +## Running the Example Project + +To build and run the example project (for Linux) we need to first log in to the container. + + ``` + $ ./login_container.sh + ``` + +From within the container run: + + ``` + user@1234$ cd ~/example/src/assembly/linux/main + user@1234$ redo run + ``` + +## Building the Docker Image from Scratch + +The procedures above use the [pre-built Docker](https://hub.docker.com/r/dinkelk/adamant/tags) image. You can recreate this image locally using the provided `Dockerfile`. If you have +not already, clone both the [Adamant](https://github.com/lasp/adamant) and [Example](https://github.com/lasp/adamant) repositories into a project directory. + + ``` + $ mkdir project + $ cd project + $ git clone https://github.com/lasp/example.git + $ git clone https://github.com/lasp/adamant.git + ``` + +Next, you can create the Docker image by running: + + ``` + $ cd example/docker + $ ./build_image.sh + ``` + +This may take 30 minutes to 1 hour to complete. By default, the image created is named `dinkelk/adamant:example-latest`. To change this, modify `docker_config.sh` before running `./build_image.sh`. diff --git a/docker/build_image.sh b/docker/build_image.sh new file mode 100755 index 0000000..c857fdc --- /dev/null +++ b/docker/build_image.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +. ./docker_config.sh +# Execute the docker machine from the project/ directory so that we have access +# to files in both adamant/ and example/. +cd ../.. +execute "docker build --progress=plain -t $DOCKER_IMAGE_NAME -f example/docker/Dockerfile ." +cd - >/dev/null diff --git a/docker/create_container.sh b/docker/create_container.sh new file mode 100755 index 0000000..3445efb --- /dev/null +++ b/docker/create_container.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +# Create the docker container with a bind mount: +echo "Creating container..." +. ./docker_config.sh +execute "docker run -d \ + --name $DOCKER_CONTAINER_NAME \ + --mount type=bind,source=\"$(pwd)\"/../..,target=/share \ + $DOCKER_IMAGE_NAME \ + sleep infinity" + +# Run docker provision script inside of container to get things set up: +echo "Provisioning container..." +if [ -n "$ON_WINDOWS" ]; then + execute "winpty docker exec -u user $DOCKER_CONTAINER_NAME //share//example//docker//env//provision//provision_container.sh" +else + execute "docker exec -u user $DOCKER_CONTAINER_NAME /share/example/docker/env/provision/provision_container.sh" +fi + +echo "Finished creating container \"$DOCKER_CONTAINER_NAME\"." +execute "docker ps -a" + +echo "" +echo "Run ./login_container.sh to log in." diff --git a/docker/docker_config.sh b/docker/docker_config.sh new file mode 100755 index 0000000..f37f1e7 --- /dev/null +++ b/docker/docker_config.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +DOCKER_CONTAINER_NAME="adamant_example_container" +DOCKER_IMAGE_NAME="dinkelk/adamant:example-latest" +export DOCKER_CONTAINER_NAME +export DOCKER_IMAGE_NAME + +case "$OSTYPE" in + cygwin|msys|win32) + ON_WINDOWS="yes" + export ON_WINDOWS + ;; +esac + +# Helper function to print out command as executed: +execute () { + echo "$ $@" + eval "$@" +} diff --git a/docker/env/_setenv.sh b/docker/env/_setenv.sh new file mode 100644 index 0000000..80cc894 --- /dev/null +++ b/docker/env/_setenv.sh @@ -0,0 +1,39 @@ +#!/bin/sh + +# This script sets up the environment for the example project. + +# Only set the environment once: +if test -n "$EXAMPLE_ENVIRONMENT_SET" +then + return +fi + +if test -z "$EXAMPLE_DIR" # ie. /home/user/example +then + echo "EXAMPLE_DIR not set in environment." >&2 + exit 1 +fi + +# Source the setenv script from the adamant repository: +. $ADAMANT_DIR/env/setenv.sh + +# Add local python packages to the python path: +. $ADAMANT_DIR/env/set_python_path.sh $EXAMPLE_DIR + +# Set the path to our Adamant configuration file for example: +export ADAMANT_CONFIGURATION_YAML=$EXAMPLE_DIR/config/example.configuration.yaml + +# This runs "export GPR_PROJECT_PATH=etc" which sets the GPR_PROJECT_PATH +# to whatever alr thinks it should be for the Adamant example project crate. +# This allows the Adamant build system to then use gprbuild in the same way +# that alr would. +# +# Also update PATH. Alire will include the current PATH set by the Adamant +# environment plus some alire specific paths. +# +cd $EXAMPLE_DIR +eval `alr printenv | grep PATH` +cd - &> /dev/null + +# Signify the environment it set up: +export EXAMPLE_ENVIRONMENT_SET="yes" diff --git a/docker/env/github_run.sh b/docker/env/github_run.sh new file mode 100755 index 0000000..fdb65c5 --- /dev/null +++ b/docker/env/github_run.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +# Set the environment for the github command: +this_dir=`dirname "$0"` +. $this_dir/_setenv.sh + +# Run the command passed to the script: +echo "$ $@" +eval "$@" diff --git a/docker/env/provision/bashrc.sh b/docker/env/provision/bashrc.sh new file mode 100644 index 0000000..c737318 --- /dev/null +++ b/docker/env/provision/bashrc.sh @@ -0,0 +1,119 @@ +# ~/.bashrc: executed by bash(1) for non-login shells. +# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc) +# for examples + +# If not running interactively, don't do anything +case $- in + *i*) ;; + *) return;; +esac + +# don't put duplicate lines or lines starting with space in the history. +# See bash(1) for more options +HISTCONTROL=ignoreboth + +# append to the history file, don't overwrite it +shopt -s histappend + +# for setting history length see HISTSIZE and HISTFILESIZE in bash(1) +HISTSIZE=1000 +HISTFILESIZE=2000 + +# check the window size after each command and, if necessary, +# update the values of LINES and COLUMNS. +shopt -s checkwinsize + +# If set, the pattern "**" used in a pathname expansion context will +# match all files and zero or more directories and subdirectories. +#shopt -s globstar + +# make less more friendly for non-text input files, see lesspipe(1) +[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)" + +# set variable identifying the chroot you work in (used in the prompt below) +if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then + debian_chroot=$(cat /etc/debian_chroot) +fi + +# set a fancy prompt (non-color, unless we know we "want" color) +case "$TERM" in + xterm-color|*-256color) color_prompt=yes;; +esac + +# uncomment for a colored prompt, if the terminal has the capability; turned +# off by default to not distract the user: the focus in a terminal window +# should be on the output of commands, not on the prompt +#force_color_prompt=yes + +if [ -n "$force_color_prompt" ]; then + if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then + # We have color support; assume it's compliant with Ecma-48 + # (ISO/IEC-6429). (Lack of such support is extremely rare, and such + # a case would tend to support setf rather than setaf.) + color_prompt=yes + else + color_prompt= + fi +fi + +if [ "$color_prompt" = yes ]; then + PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ ' +else + PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ ' +fi +unset color_prompt force_color_prompt + +# If this is an xterm set the title to user@host:dir +case "$TERM" in +xterm*|rxvt*) + PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \w\a\]$PS1" + ;; +*) + ;; +esac + +# enable color support of ls and also add handy aliases +if [ -x /usr/bin/dircolors ]; then + test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)" + alias ls='ls --color=auto' + #alias dir='dir --color=auto' + #alias vdir='vdir --color=auto' + + alias grep='grep --color=auto' + alias fgrep='fgrep --color=auto' + alias egrep='egrep --color=auto' +fi + +# colored GCC warnings and errors +#export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01' + +# some more ls aliases +alias ll='ls -alF' +alias la='ls -A' +alias l='ls -CF' + +# Add an "alert" alias for long running commands. Use like so: +# sleep 10; alert +alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"' + +# Alias definitions. +# You may want to put all your additions into a separate file like +# ~/.bash_aliases, instead of adding them here directly. +# See /usr/share/doc/bash-doc/examples in the bash-doc package. + +if [ -f ~/.bash_aliases ]; then + . ~/.bash_aliases +fi + +# enable programmable completion features (you don't need to enable +# this, if it's already enabled in /etc/bash.bashrc and /etc/profile +# sources /etc/bash.bashrc). +if ! shopt -oq posix; then + if [ -f /usr/share/bash-completion/bash_completion ]; then + . /usr/share/bash-completion/bash_completion + elif [ -f /etc/bash_completion ]; then + . /etc/bash_completion + fi +fi + +cd ~/example/docker/env && . ./setenv.sh && cd ../../.. && pwd && ls diff --git a/docker/env/provision/example.prf b/docker/env/provision/example.prf new file mode 100644 index 0000000..878e1ec --- /dev/null +++ b/docker/env/provision/example.prf @@ -0,0 +1,21 @@ +# Unison profile for syncing the "example" directory +# between two locations + +# Set the root directories for the sync +root = /home/user/example +root = /share/example + +# Set the options for the sync +silent = true +batch = true +fastcheck = true +logfile = /home/user/.unison/example.log +times = true +prefer = /home/user/example +repeat = watch+20 +maxsizethreshold = 20000 +sortbysize = true + +# Ignore the specified directories +ignore = Name src/assembly/pico/main/hydra/Rundirs/* +ignore = Name src/assembly/linux/main/hydra/Rundirs/* diff --git a/docker/env/provision/provision_container.sh b/docker/env/provision/provision_container.sh new file mode 100755 index 0000000..00deb19 --- /dev/null +++ b/docker/env/provision/provision_container.sh @@ -0,0 +1,34 @@ +#!/bin/sh + +home="/home/user" +# First do a copy from /share to /home/user: +safe_copy() { + src=$1 + dest=$2 + if [ ! -d "dest" ]; then + echo "Copying $src to $dest..." + cp -rf $src $dest + echo "Done." + else + echo "Already copied $src to $dest." + fi +} + +echo "Copying shared repositories to /home/user to optimize build speed." +safe_copy /share/adamant $home/adamant +safe_copy /share/example $home/example + +# Start unison: +echo "Starting Unison." +/share/example/docker/env/start_unison.sh & + +# Set up alire: +echo "Setting up Alire build dependencies." +export PATH=$PATH:/home/user/env/bin +cd /home/user/adamant +alr -n build --release +alr -n toolchain --select gnat_native +alr -n toolchain --select gprbuild +cd /home/user/example +alr -n build --release +echo "Done." diff --git a/docker/env/setenv.sh b/docker/env/setenv.sh new file mode 100644 index 0000000..feb54c4 --- /dev/null +++ b/docker/env/setenv.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +# This script sets up the environment for the example project. +echo "Setting up environment..." + +# Source the setenv script from the adamant repository: +INSTALL_DIR=$HOME/env +ADAMANT_DIR=$HOME/adamant +EXAMPLE_DIR=$HOME/example +export EXAMPLE_DIR +export INSTALL_DIR +export ADAMANT_DIR + +# Set the environment for docker: +. $EXAMPLE_DIR/docker/env/_setenv.sh + +# Make sure unison is started: +sh $EXAMPLE_DIR/docker/env/start_unison.sh +echo "Done." diff --git a/docker/env/start_unison.sh b/docker/env/start_unison.sh new file mode 100755 index 0000000..c74399a --- /dev/null +++ b/docker/env/start_unison.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +ADAMANT_DIR=/share/adamant +sh $ADAMANT_DIR/env/start_unison.sh adamant +sh $ADAMANT_DIR/env/start_unison.sh example diff --git a/docker/login_container.sh b/docker/login_container.sh new file mode 100755 index 0000000..aec531b --- /dev/null +++ b/docker/login_container.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +. ./docker_config.sh + +if [ -n "$ON_WINDOWS" ]; then + execute "winpty docker exec -it -u user $DOCKER_CONTAINER_NAME //bin//bash" +else + execute "docker exec -it -u user $DOCKER_CONTAINER_NAME /bin/bash" +fi diff --git a/docker/remove_container.sh b/docker/remove_container.sh new file mode 100755 index 0000000..1fef816 --- /dev/null +++ b/docker/remove_container.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +. ./docker_config.sh +execute "docker rm $DOCKER_CONTAINER_NAME" +execute "docker ps -a" diff --git a/docker/start_container.sh b/docker/start_container.sh new file mode 100755 index 0000000..131303b --- /dev/null +++ b/docker/start_container.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +. ./docker_config.sh +execute "docker start $DOCKER_CONTAINER_NAME" +if [ -n "$ON_WINDOWS" ]; then + execute "winpty docker exec -u user $DOCKER_CONTAINER_NAME //share//example//docker//env//start_unison.sh &" +else + execute "docker exec -u user $DOCKER_CONTAINER_NAME /share/example/docker/env/start_unison.sh &" +fi +execute "docker ps -a" diff --git a/docker/stop_container.sh b/docker/stop_container.sh new file mode 100755 index 0000000..c72a575 --- /dev/null +++ b/docker/stop_container.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +. ./docker_config.sh +execute "docker stop $DOCKER_CONTAINER_NAME" +execute "docker ps -a" diff --git a/gnd/README.md b/gnd/README.md new file mode 100644 index 0000000..d1f8b1d --- /dev/null +++ b/gnd/README.md @@ -0,0 +1,5 @@ +# Gnd + +## Description + +This directory contains "ground" related tools and source code for the Example Project. diff --git a/gnd/hydra/Config/Scripts/setup.prc b/gnd/hydra/Config/Scripts/setup.prc new file mode 100644 index 0000000..1a89fd4 --- /dev/null +++ b/gnd/hydra/Config/Scripts/setup.prc @@ -0,0 +1,13 @@ +; This script handles setting some default values during startup + +echo "Setting up Hydra for Example Assembly interaction." + +; Set the CCSDS Header info: +set Ccsds_Ground_Command_Header-Ccsds_Primary_Header-Apid = 0 +set Ccsds_Ground_Command_Header-Ccsds_Primary_Header-Packet_Type = 1 +set Ccsds_Ground_Command_Header-Ccsds_Primary_Header-Secondary_Header = 1 + +; Send the NOOP command to the assembly to make sure things are working +command_Router_Instance-Noop + +echo "Setup complete." diff --git a/gnd/hydra/Config/downlink_decoders.xml b/gnd/hydra/Config/downlink_decoders.xml new file mode 100644 index 0000000..abce485 --- /dev/null +++ b/gnd/hydra/Config/downlink_decoders.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gnd/hydra/README.md b/gnd/hydra/README.md new file mode 100644 index 0000000..a1fca6e --- /dev/null +++ b/gnd/hydra/README.md @@ -0,0 +1,3 @@ +# Hydra + +This includes common configuration files for the Example Project use with [Hydra](TODO). Note that Hydra is not yet publically available, but will be made so in the future. diff --git a/gnd/hydra/build_hydra_config.sh b/gnd/hydra/build_hydra_config.sh new file mode 100755 index 0000000..6bacab7 --- /dev/null +++ b/gnd/hydra/build_hydra_config.sh @@ -0,0 +1,44 @@ +#!/bin/sh + +# +# Configure hydra for a particular assembly and then +# start hydra in the background. +# + +assembly_file=$1 +config_file=$2 +background=$3 + +# Check commandline arguments: +if test -z "$assembly_file" || test -z "$config_file" +then + echo "Usage: build_hydra_config.sh /path/to/assembly_file.assembly.yaml /path/to/hydra/hydra_config.xml" >&2 + exit 1 +fi + +# Set some other vars: +assembly_name=`basename $assembly_file .assembly.yaml` +config_dir=`dirname $config_file` +assembly_dir=`dirname $assembly_file` + +# Build all hydra scripts and pages: +cd $assembly_dir +scripts=`redo what 2>&1 | grep "hydra/Scripts" | awk '{ print $2 }'` +pages=`redo what 2>&1 | grep "hydra/Pages" | awk '{ print $2 }'` +{ + echo $scripts + echo $pages +} | xargs redo-ifchange +cd - >/dev/null + +# Dirty work around to get autocoded pages into hydra. Eventually hydra will be +# updated and we won't have to do this copy. +pages_dir=$config_dir/Pages/$assembly_name +mkdir -p $pages_dir +for page in $pages +do + cp $assembly_dir/$page $pages_dir +done + +# Depend on all hydra dependencies specified in the config file: +$ADAMANT_DIR/redo/bin/redo_hydra_deps.py $config_file diff --git a/redo/README.md b/redo/README.md new file mode 100644 index 0000000..ffa4b25 --- /dev/null +++ b/redo/README.md @@ -0,0 +1,5 @@ +# Redo + +## Description + +This directory contains a variety of python libraries which customize the Adamant [`redo`](https://github.com/dinkelk/redo)-based build system for the example repository. In particular, build targets for the [Raspberry Pi Pico](https://www.raspberrypi.com/products/raspberry-pi-pico/) are included. diff --git a/redo/__init__.py b/redo/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/redo/environments/pico.py b/redo/environments/pico.py new file mode 100644 index 0000000..257a01e --- /dev/null +++ b/redo/environments/pico.py @@ -0,0 +1,10 @@ +# Import this file to change the default target for a directory to Pico instead of Linux. +from util import target +from os import environ, path + +target.set_target("Pico") +try: + adamant_dir = environ['ADAMANT_DIR'] +except KeyError: + adamant_dir = '/home/user/adamant' +environ["REMOVE_BUILD_PATH"] = path.join(adamant_dir, "src/components/ccsds_serial_interface/uart") diff --git a/redo/targets/gpr/pico_debug.gpr b/redo/targets/gpr/pico_debug.gpr new file mode 100644 index 0000000..3f7ce29 --- /dev/null +++ b/redo/targets/gpr/pico_debug.gpr @@ -0,0 +1,32 @@ +with "pico_bsp.gpr"; +with "ravenscar_build.gpr"; + +project pico_debug extends all "a_bareboard_debug.gpr" is + + ----------------------------------------------- + -- These lines of code must be included at the + -- top of every Adamant based .gpr file. They + -- are used to connect the Adamant build system + -- to GPRBuild. + ----------------------------------------------- + for Source_Dirs use a_adamant.SOURCE_DIRS; + for Object_Dir use a_adamant.OBJECT_DIR; + for Exec_Dir use a_adamant.EXEC_DIR; + + -- Specify cross compiler ARM target and Ravenscar runtime: + for Target use "arm-eabi"; + for Runtime ("Ada") use Ravenscar_Build'Runtime ("Ada"); + + -- Common binder switches: + package Binder is + for Switches ("Ada") use a_bareboard_base.Binder'Switches ("Ada") & + -- Store tracebacks in exception occurrences + -- https://gcc.gnu.org/onlinedocs/gcc-4.8.5/gnat_ugn_unw/Switches-for-gnatbind.html + ("-E"); + end Binder; + + package Linker is + for Switches ("Ada") use a_bareboard_base.Linker'Switches ("Ada"); + end Linker; + +end pico_debug; diff --git a/redo/targets/gpr/pico_development.gpr b/redo/targets/gpr/pico_development.gpr new file mode 100644 index 0000000..76cf0c7 --- /dev/null +++ b/redo/targets/gpr/pico_development.gpr @@ -0,0 +1,32 @@ +with "pico_bsp.gpr"; +with "ravenscar_build.gpr"; + +project pico_development extends all "a_bareboard_development.gpr" is + + ----------------------------------------------- + -- These lines of code must be included at the + -- top of every Adamant based .gpr file. They + -- are used to connect the Adamant build system + -- to GPRBuild. + ----------------------------------------------- + for Source_Dirs use a_adamant.SOURCE_DIRS; + for Object_Dir use a_adamant.OBJECT_DIR; + for Exec_Dir use a_adamant.EXEC_DIR; + + -- Specify cross compiler ARM target and Ravenscar runtime: + for Target use "arm-eabi"; + for Runtime ("Ada") use Ravenscar_Build'Runtime ("Ada"); + + -- Common binder switches: + package Binder is + for Switches ("Ada") use a_bareboard_base.Binder'Switches ("Ada") & + -- Store tracebacks in exception occurrences + -- https://gcc.gnu.org/onlinedocs/gcc-4.8.5/gnat_ugn_unw/Switches-for-gnatbind.html + ("-E"); + end Binder; + + package Linker is + for Switches ("Ada") use a_bareboard_base.Linker'Switches ("Ada"); + end Linker; + +end pico_development; diff --git a/redo/targets/gpr/pico_production.gpr b/redo/targets/gpr/pico_production.gpr new file mode 100644 index 0000000..3f63e3b --- /dev/null +++ b/redo/targets/gpr/pico_production.gpr @@ -0,0 +1,32 @@ +with "pico_bsp.gpr"; +with "ravenscar_build.gpr"; + +project pico_production extends all "a_bareboard_production.gpr" is + + ----------------------------------------------- + -- These lines of code must be included at the + -- top of every Adamant based .gpr file. They + -- are used to connect the Adamant build system + -- to GPRBuild. + ----------------------------------------------- + for Source_Dirs use a_adamant.SOURCE_DIRS; + for Object_Dir use a_adamant.OBJECT_DIR; + for Exec_Dir use a_adamant.EXEC_DIR; + + -- Specify cross compiler ARM target and Ravenscar runtime: + for Target use "arm-eabi"; + for Runtime ("Ada") use Ravenscar_Build'Runtime ("Ada"); + + -- Common binder switches: + package Binder is + for Switches ("Ada") use a_bareboard_base.Binder'Switches ("Ada") & + -- Store tracebacks in exception occurrences + -- https://gcc.gnu.org/onlinedocs/gcc-4.8.5/gnat_ugn_unw/Switches-for-gnatbind.html + ("-E"); + end Binder; + + package Linker is + for Switches ("Ada") use a_bareboard_base.Linker'Switches ("Ada"); + end Linker; + +end pico_production; diff --git a/redo/targets/pico.py b/redo/targets/pico.py new file mode 100644 index 0000000..bbc596f --- /dev/null +++ b/redo/targets/pico.py @@ -0,0 +1,68 @@ +from targets.arm_bare_board import arm_bare_board +import os.path + +# +# This file contains the cross compile build targets for the +# Raspberry Pi Pico microprocessor. It utilizes the embedded-rpi-pico-smp +# runtime provided in the gnat_arm_elf Alire crate. +# + + +class Pico_Base(arm_bare_board): + def path_files(self): + return list(set(super(Pico_Base, self).path_files() + ["Pico"])) + + +class Pico_Production(Pico_Base): + def description(self): + return ("This target compiles for the Raspberry Pi Pico microprocessor. It has optimization enabled and " + "only enforces the Ada Reference Manual validation checks.") + + def gpr_project_file(self): + return os.path.join( + os.environ["EXAMPLE_DIR"], + "redo" + + os.sep + + "targets" + + os.sep + + "gpr" + + os.sep + + "pico_production.gpr", + ) + + +class Pico_Development(Pico_Base): + def description(self): + return ("This target compiles for the Raspberry Pi Pico microprocessor. It has optimization enabled and " + "enforces all possible validation checks with pragma Initialize_Scalars enabled.") + + def gpr_project_file(self): + return os.path.join( + os.environ["EXAMPLE_DIR"], + "redo" + + os.sep + + "targets" + + os.sep + + "gpr" + + os.sep + + "pico_development.gpr", + ) + + +class Pico(Pico_Development): + def description(self): + return ("This is the default Raspberry Pi Pico microprocessor cross compile target. This is simply a " + "rename of Pico_Development.") + + +class Pico_Debug(Pico_Base): + def description(self): + return ("This target compiles for the Raspberry Pi Pico microprocessor. It has optimization disabled in " + "both the Adamant code and the runtime code. It enforces all possible validation checks with " + "pragma Initialize_Scalars enabled.") + + def gpr_project_file(self): + return os.path.join( + os.environ["EXAMPLE_DIR"], + "redo" + os.sep + "targets" + os.sep + "gpr" + os.sep + "pico_debug.gpr", + ) diff --git a/src/README.md b/src/README.md new file mode 100644 index 0000000..6f69724 --- /dev/null +++ b/src/README.md @@ -0,0 +1,14 @@ +# Src + +## Description + +This directory contains the source files which make up the example project. + +## Contents + +The following is a description of what you can expect to find in the subdirectories of this directory. + + * `assembly/` - the assembly models for the example project, which integrates the example components together into an executable network of components + * `components/` - the set of mission-specific components that make up the example assembly + * `last_chance_handler/` - code for implementing the Ada Last_Chance_Handler subprogram + * `pico_util/` - code for accessing various devices on the Raspberry Pi Pico diff --git a/src/assembly/README.md b/src/assembly/README.md new file mode 100644 index 0000000..c587de0 --- /dev/null +++ b/src/assembly/README.md @@ -0,0 +1,7 @@ +# Example Assemblies + +This directory contains the Adamant Example assemblies. Each assembly demonstrates how to connect Adamant components together, compile them into a runnable binary, and deploy that binary onto +the target hardware. Currently there are two assemblies available: + + - **linux** - This assembly compiles and runs natively in the Adamant [build environment](../../docker/README.md). To get started look [here](linux/main/README.md). + - **pico** - This assembly cross compiles for the [Raspberry Pi Pico](https://www.raspberrypi.com/products/raspberry-pi-pico/). To get started look [here](pico/main/README.md). diff --git a/src/assembly/linux/.Linux_path b/src/assembly/linux/.Linux_path new file mode 100644 index 0000000..e69de29 diff --git a/src/assembly/linux/README.md b/src/assembly/linux/README.md new file mode 100644 index 0000000..6a10308 --- /dev/null +++ b/src/assembly/linux/README.md @@ -0,0 +1,7 @@ +# Linux Demo + +This directory contains models for the Linux demo. To try out this demo look in [main](main/README.md). Contents of the subdirectories are listed below: + + * `doc/` - Contains the generated design documentation for the assembly. + * `main/` - Contains the main entry-point for the assembly executable and instructions on how to build and run it. + * `views/` - Contains graphical views of the assembly. diff --git a/src/assembly/linux/doc/README.md b/src/assembly/linux/doc/README.md new file mode 100644 index 0000000..8b4828f --- /dev/null +++ b/src/assembly/linux/doc/README.md @@ -0,0 +1,3 @@ +# Linux Demo Documentation + +This directory contains the assembly [design documentation](linux_example.pdf). diff --git a/src/assembly/linux/doc/linux_example.pdf b/src/assembly/linux/doc/linux_example.pdf new file mode 100644 index 0000000..7dc944c Binary files /dev/null and b/src/assembly/linux/doc/linux_example.pdf differ diff --git a/src/assembly/linux/doc/linux_example.tex b/src/assembly/linux/doc/linux_example.tex new file mode 100644 index 0000000..cf998b8 --- /dev/null +++ b/src/assembly/linux/doc/linux_example.tex @@ -0,0 +1,80 @@ +\input{common_packages.tex} + +\begin{document} + +\title{\textbf{Linux Example} \\ +\large\textit{Assembly Design Document}} +\date{} +\maketitle + +\section{Description} +\input{build/tex/linux_example_description.tex} + +\section{Design} + +\subsection{At a Glance} +\input{build/tex/linux_example_stats.tex} + +\subsection{Components} +All of the components in the Linux Example assembly are reusable components that can be found within the Adamant repository (in \textit{src/components/}) with a few exceptions: + +\vspace{5mm} %5mm vertical space +\begin{spaceditemize} + \item \textbf{\texttt{\url{Counter}}} - This is an extremely simple component that produces an incrementing counter as telemetry. + \item \textbf{\texttt{\url{Fault_Producer}}} - This is an component that can be used to inject a fault into the system via command. + \item \textbf{\texttt{\url{Oscillator}}} - This is a simple component that produces two sinusoidal outputs into telemetry. + \item \textbf{\texttt{\url{Parameter_Manager}}} - This component demonstrates how parameter tables can be copied between a non-volatile store and an active (in-use) parameter store. + \item \textbf{\texttt{\url{Interrupt_Responder}}} - This is a simple component that receives a tick when an interrupt is received. It processes this interrupt by printing the interrupt's time stamp to the terminal. +\end{spaceditemize} +\vspace{5mm} %5mm vertical space + +These specific component are located in the Example repository in \textit{src/components/}. A full list of the components included in the assembly can be seen below. Note that components marked as active execute on their own task within the Ada runtime. + +\input{build/tex/linux_example_components.tex} + +\subsection{Views} + +This section shows the example assembly visually as a set of \textit{views}. Each shows a specific set of components and connections (while not showing other components and connections) in order to highlight a particular function of the assembly. Components that are bold are \textit{active}, meaning they have an Ada task assigned to them. Connections are labeled with the type that is passed along them. A dotted line indicates that the connection is asynchronous, meaning the data is put onto a queue for later processing. A solid line indicates that the connection is synchronous, meaning processing of that data occurs right when the data is passed along the connector. + +\input{build/tex/linux_example_views.tex} + +\subsection{Task Priorities} +\input{build/tex/linux_example_priorities.tex} + +\subsection{Commands} + +\input{build/tex/linux_example_commands.tex} + +\subsection{Parameters} + +\input{build/tex/linux_example_parameters.tex} + +\subsection{Events} + +\input{build/tex/linux_example_events.tex} + +\subsection{Data Products} + +\input{build/tex/linux_example_data_products.tex} + +\subsection{Packets} + +\input{build/tex/linux_example_packets.tex} + +\subsection{Faults} + +\input{build/tex/linux_example_faults.tex} + +\section{Appendix} +\subsection{Connections} +\input{build/tex/linux_example_connections.tex} + +\subsection{Packed Types} + +\input{build/tex/linux_example_types.tex} + +\subsection{Enumerations} + +\input{build/tex/linux_example_enums.tex} + +\end{document} diff --git a/src/assembly/linux/linux_example.assembly.yaml b/src/assembly/linux/linux_example.assembly.yaml new file mode 100644 index 0000000..51f8880 --- /dev/null +++ b/src/assembly/linux/linux_example.assembly.yaml @@ -0,0 +1,1083 @@ +--- +description: This example assembly is designed to run inside the Adamant Linux build environment. It includes a small collection of components that demonstrate how Adamant can be compiled into a single binary and run on native Linux. In particular, the assembly demonstrates a simple rate group system, commanding, telemetry reporting using events, parameters, data products and packets, and a simple fault detection and correction scheme. Explore the tables and diagrams below to learn more about the design of the example assembly. +with: + - Start_Up + - System + - Ada.Interrupts.Names + - Linux_Example_Event_To_Text + - Linux_Example_Product_Packets + - Linux_Example_Commands + - Linux_Example_Events + - Linux_Example_Data_Products + - Logger_Enums + - Tick_Interrupt_Handler + - Logger_Enums + - Linux_Example_Task_Watchdog_List + - Linux_Example_Fault_Responses + - Linux_Example_Parameter_Table + - Memory_Map +prepreamble: | + -- Make sure Start_Up is elaborated before the tasks in this package are started. + pragma Unreferenced (Start_Up); + pragma Elaborate_All (Start_Up); +preamble: | + Dividers : aliased Component.Tick_Divider.Divider_Array_Type := (1 => 5, 2 => 10, 3 => 1); +######################################## +components: +######################################## +######################################## +# System time: +######################################## + - type: Gps_Time + name: System_Time_Instance + description: This component provides the system time for the assembly. +######################################## +# Rate group system: +######################################## + - type: Ticker + description: This component uses a periodic signal to drive the assembly rate groups. + priority: 10 + stack_size: 50000 + secondary_stack_size: 10000 + discriminant: + - "Period_Us => 200000" # 1/5 second period + - type: Tick_Divider + description: This component divides a periodic signal into intervals suitable for the assembly rate groups. + init_base: + - "Tick_T_Send_Count => 3" + init: + - "Dividers => Dividers'Access" + - type: Rate_Group + name: Slow_Rate_Group + description: This component provides a 0.5 Hz task for other components to execute on periodically. + priority: 9 + stack_size: 50000 + secondary_stack_size: 10000 + init_base: + - "Queue_Size => 3 * Slow_Rate_Group.Get_Max_Queue_Element_Size" + - "Tick_T_Send_Count => 8" + init: + - "Ticks_Per_Timing_Report => 10" + - type: Rate_Group + name: Fast_Rate_Group + description: This component provides a 5 Hz task for other components to execute on periodically. + priority: 9 + stack_size: 50000 + secondary_stack_size: 10000 + init_base: + - "Queue_Size => 3 * Fast_Rate_Group.Get_Max_Queue_Element_Size" + - "Tick_T_Send_Count => 3" + init: + - "Ticks_Per_Timing_Report => 400" + - type: Rate_Group + name: Watchdog_Rate_Group + description: This component provides a 1 Hz task for the watchdog components to execute on periodically. + priority: 10 + stack_size: 50000 + secondary_stack_size: 10000 + init_base: + - "Queue_Size => 3 * Watchdog_Rate_Group.Get_Max_Queue_Element_Size" + - "Tick_T_Send_Count => 1" + init: + - "Ticks_Per_Timing_Report => 400" +######################################## +# Command system: +######################################## + - type: Ccsds_Command_Depacketizer + description: This component converts CCSDS packets containing commands to valid Adamant formatted command types. + - type: Command_Router + description: This component provides command and command response routing throughout the assembly. + priority: 8 + stack_size: 50000 + secondary_stack_size: 10000 + init_base: + - "Queue_Size => 10 * Command_Router_Instance.Get_Max_Queue_Element_Size" + - "Command_T_Send_Count => 22" + - "Command_Response_T_To_Forward_Send_Count => 1" + init: + - "Max_Number_Of_Commands => Linux_Example_Commands.Number_Of_Commands" +######################################## +# Event system: +######################################## + - type: Event_Text_Logger + description: This component prints events in human readable format to the terminal. + priority: 1 + stack_size: 50000 + secondary_stack_size: 10000 + discriminant: + - "Event_To_Text => Linux_Example_Event_To_Text.Event_To_Text'Access" + init_base: + - "Queue_Size => 1024" + - type: Event_Filter + description: This component filters events by ID. + init: + - "Event_Id_Start_Range => Linux_Example_Events.Minimum_Event_Id" + - "Event_Id_End_Range => Linux_Example_Events.Maximum_Event_Id" + - type: Event_Limiter + description: This component filters out events that spam the system too frequently. + init: + - "Event_Id_Start => Linux_Example_Events.Minimum_Event_Id" + - "Event_Id_Stop => Linux_Example_Events.Maximum_Event_Id" + - "Event_Limit_Persistence => 5" + - type: Splitter + description: This component splits the event stream into a filtered and limited stream and an unfiltered and unlimited stream for the post mortem log. + name: Event_Splitter_Instance + generic_types: + - "T => Event.T" + init_base: + - "T_Send_Count => 2" + - type: Splitter + description: This component splits the event stream between events to printed to the terminal and those fowarded out of the socket interface. + name: Event_Splitter_2_Instance + generic_types: + - "T => Event.T" + init_base: + - "T_Send_Count => 2" + - type: Logger + name: Event_Post_Mortem_Logger + description: This component stores events in a circular buffer on the heap. In an embedded system this log will usually be instantiated in non-volatile memory, so that events can be dumped after a power cycle. + generic_types: + - "T => Event.T" + - "Serialized_Length => Event.Serialized_Length" + init: + - "Size => 1024 * 100" + - "Initial_Mode => Logger_Enums.Logger_Mode.Enabled" + - type: Event_Packetizer + description: This component gathers events and packetizes them for downlink. + init: + - "Num_Internal_Packets => 5" + - "Partial_Packet_Timeout => 1" + set_id_bases: + - "Packet_Id_Base => 98" +######################################## +# Parameter system: +######################################## + - type: Parameters + description: This component manages the active parameter table and provides parameter updates to any component in the assembly that uses parameters. + priority: 3 + stack_size: 40000 + secondary_stack_size: 5000 + init_base: + - "Queue_Size => 3 * Parameters_Instance.Get_Max_Queue_Element_Size" + - "Parameter_Update_T_Provide_Count => 2" + init: + - "Parameter_Table_Entries => Linux_Example_Parameter_Table.Parameter_Table_Entries'Access" + - "Dump_Parameters_On_Change => True" + - type: Parameter_Store + description: This component manages the default parameter table, storing it on the heap. In an embedded system the default parameter table will usually be instantiated in non-volatile memory, so that it can be restored after reset. + priority: 3 + stack_size: 40000 + secondary_stack_size: 5000 + init_base: + - "Queue_Size => 3 * Parameter_Store_Instance.Get_Max_Queue_Element_Size" + init: + - "Bytes => Memory_Map.Parameter_Store_Bytes_Access" + - "Dump_Parameters_On_Change => True" + - type: Parameter_Manager + description: This component responds to commands to copy parameter tables from the active parameter table to the default parameter table or vice versa. + priority: 3 + stack_size: 30000 + secondary_stack_size: 5000 + init_base: + - "Queue_Size => 3 * Parameter_Manager_Instance.Get_Max_Queue_Element_Size" + set_id_bases: + - "Command_Id_Base => 5200" + init: + - "Parameter_Table_Length => Linux_Example_Parameter_Table.Parameter_Table_Size_In_Bytes" + - "Ticks_Until_Timeout => 3" +######################################## +# Telemetry system: +######################################## + - type: Product_Database + description: This component serves as the database for data products throughout the system. + init: + - "Minimum_Data_Product_Id => Linux_Example_Data_Products.Minimum_Data_Product_Id" + - "Maximum_Data_Product_Id => Linux_Example_Data_Products.Maximum_Data_Product_Id" + - "Send_Event_On_Missing => False" + - type: Product_Packetizer + description: This component periodically fetches values from the Product Database and packetizes them for downlink. + init_base: + - "Queue_Size => 3 * Product_Packetizer_Instance.Get_Max_Queue_Element_Size" + discriminant: + - "packet_List => Linux_Example_Product_Packets.Packet_List'Access" + init: + - type: Ccsds_Packetizer + description: This component converts Adamant formatted packets to CCSDS for downlink. + - type: Ccsds_Socket_Interface + description: This component receives commands from and sends events and telemetry packets through a TCP/IP Socket. + priority: 6 + stack_size: 50000 + secondary_stack_size: 10000 + init_base: + - "Queue_Size => 8192" + init: + - "Addr => \"host.docker.internal\"" + - "Port => 2003" + subtasks: + - name: Listener + priority: 0 + stack_size: 20000 + secondary_stack_size: 5000 + disabled: False + - type: Memory_Packetizer + description: This component packetizes the event post mortem log when a dump is requested. + priority: 1 + stack_size: 50000 + secondary_stack_size: 10000 + init_base: + - "Queue_Size => 1024" + init: + - "Max_Packets_Per_Time_Period => 10" + - "Time_Period_In_Seconds => 1" + - "Max_Packet_Ids => 10" +######################################## +# Interrupt system: +######################################## + - type: Interrupt_Servicer + description: This component waits for interrupt and, when received, passes it along to the assembly for processing. + priority: 1 + stack_size: 20000 + secondary_stack_size: 10000 + generic_types: + - "Interrupt_Data_Type => Tick.T" + - "Set_Interrupt_Data_Time => Tick_Interrupt_Handler.Set_Tick_Time" + discriminant: + - "Interrupt_Priority => System.Interrupt_Priority'Last" + - "Interrupt_Id => Ada.Interrupts.Names.SIGUSR1" + - "Custom_Interrupt_Procedure => Tick_Interrupt_Handler.Handler'Access" + - type: Interrupt_Responder + description: This component responds to an interrupt. +######################################## +# Example assembly "mission" components: +######################################## + - type: Counter + description: This component periodically produces a count data product. + set_id_bases: + - "Command_Id_Base => 99" + init_base: + - "Queue_Size => 3 * Counter_Instance.Get_Max_Queue_Element_Size" + - type: Oscillator + name: Oscillator_A + description: This component periodically produces an oscillating data product. + init_base: + - "Queue_Size => 3 * Oscillator_A.Get_Max_Queue_Element_Size" + - type: Oscillator + name: Oscillator_B + description: This component periodically produces an oscillating data product. + init_base: + - "Queue_Size => 3 * Oscillator_B.Get_Max_Queue_Element_Size" +######################################## +# Fault protection system: +######################################## + - type: Zero_Divider + description: This component responds to a command that divides by zero if received. This can be used to trigger a fault condition within the processor. + init: + - "Magic_Number => 16#DEADBEEF#" + - type: Task_Watchdog + description: This component monitors other critical active components (tasks) within the assembly to make sure they continue to run. + init_base: + - "Pet_T_Recv_Sync_Count => 2" + init: + - "Task_Watchdog_Entry_Init_List => Linux_Example_Task_Watchdog_List.Task_Watchdog_Entry_Init_List" + - type: Fault_Producer + description: This component can be used to induce a fault into the system by command. + stack_size: 40000 + - type: Fault_Correction + description: This component produces a corrective action (a command) for any fault that is thrown in the system. + priority: 11 + stack_size: 40000 + secondary_stack_size: 5000 + init_base: + - "Queue_Size => 5 * Fault_Correction_Instance.Get_Max_Queue_Element_Size" + init: + - "Fault_Response_Configurations => Linux_Example_Fault_Responses.Fault_Response_List" +######################################## +# FSW monitoring system: +######################################## + - type: Cpu_Monitor + description: This component produces a packet that includes the CPU usage percentage for each task and interrupt in the system. + init: + - "Task_List => Task_List'Access" + - "Interrupt_List => Interrupt_List'Access" + - type: Queue_Monitor + description: This component produces a packet that includes the current and maximum queue usage for each component in the system. + init: + - "Queued_Component_List => Queued_Component_List'Access" + - type: Stack_Monitor + description: This component produces a packet that includes the maximum stack and secondary stack usage for each component in the system. + init: + - "Task_List => Task_List'Access" + - "Packet_Period => 1" +######################################## +connections: +######################################## + # Time Connections: + - from_component: Ticker_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Tick_Divider_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Slow_Rate_Group + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Fast_Rate_Group + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Watchdog_Rate_Group + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Command_Router_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Counter_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Oscillator_A + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Oscillator_B + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Ccsds_Socket_Interface_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Interrupt_Servicer_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Interrupt_Responder_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Event_Packetizer_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Product_Database_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Product_Packetizer_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Ccsds_Command_Depacketizer_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Event_Post_Mortem_Logger + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Memory_Packetizer_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Cpu_Monitor_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Stack_Monitor_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Queue_Monitor_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Event_Filter_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Event_Limiter_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Parameters_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Parameter_Store_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Zero_Divider_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Task_Watchdog_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Fault_Correction_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Parameter_Manager_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Fault_Producer_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + # Rate Group Connections: + - from_component: Ticker_Instance + from_connector: Tick_T_Send + to_component: Tick_Divider_Instance + to_connector: Tick_T_Recv_Sync + - from_component: Tick_Divider_Instance + from_connector: Tick_T_Send + from_index: 1 + to_component: Watchdog_Rate_Group + to_connector: Tick_T_Recv_Async + - from_component: Tick_Divider_Instance + from_connector: Tick_T_Send + from_index: 2 + to_component: Slow_Rate_Group + to_connector: Tick_T_Recv_Async + - from_component: Tick_Divider_Instance + from_connector: Tick_T_Send + from_index: 3 + to_component: Fast_Rate_Group + to_connector: Tick_T_Recv_Async + - description: Schedule connection from the rate group to the counter + from_component: Slow_Rate_Group + from_connector: Tick_T_Send + from_index: 1 + to_component: Counter_Instance + to_connector: Tick_T_Recv_Sync + - description: Schedule connection from the rate group to the packetizer + from_component: Slow_Rate_Group + from_connector: Tick_T_Send + from_index: 2 + to_component: Event_Packetizer_Instance + to_connector: Tick_T_Recv_Sync + - from_component: Slow_Rate_Group + from_connector: Tick_T_Send + from_index: 3 + to_component: Cpu_Monitor_Instance + to_connector: Tick_T_Recv_Sync + - from_component: Slow_Rate_Group + from_connector: Tick_T_Send + from_index: 4 + to_component: Queue_Monitor_Instance + to_connector: Tick_T_Recv_Sync + - from_component: Slow_Rate_Group + from_connector: Tick_T_Send + from_index: 5 + to_component: Stack_Monitor_Instance + to_connector: Tick_T_Recv_Sync + - from_component: Slow_Rate_Group + from_connector: Tick_T_Send + from_index: 6 + to_component: Event_Filter_Instance + to_connector: Tick_T_Recv_Sync + - from_component: Slow_Rate_Group + from_connector: Tick_T_Send + from_index: 7 + to_component: Event_Limiter_Instance + to_connector: Tick_T_Recv_Sync + - from_component: Slow_Rate_Group + from_connector: Tick_T_Send + from_index: 8 + to_component: Parameter_Manager_Instance + to_connector: Timeout_Tick_Recv_Sync + - description: Schedule connection from the rate group to the oscillator + from_component: Fast_Rate_Group + from_connector: Tick_T_Send + from_index: 1 + to_component: Oscillator_A + to_connector: Tick_T_Recv_Sync + - description: Schedule connection from the rate group to the oscillator + from_component: Fast_Rate_Group + from_connector: Tick_T_Send + from_index: 2 + to_component: Oscillator_B + to_connector: Tick_T_Recv_Sync + - description: Schedule connection from the rate group to the packetizer + from_component: Fast_Rate_Group + from_connector: Tick_T_Send + from_index: 3 + to_component: Product_Packetizer_Instance + to_connector: Tick_T_Recv_Sync + - from_component: Watchdog_Rate_Group + from_connector: Tick_T_Send + from_index: 1 + to_component: Task_Watchdog_Instance + to_connector: Tick_T_Recv_Sync + # Event Connections: + - from_component: Tick_Divider_Instance + from_connector: Event_T_Send + to_component: Event_Splitter_Instance + to_connector: T_Recv_Sync + - from_component: Slow_Rate_Group + from_connector: Event_T_Send + to_component: Event_Splitter_Instance + to_connector: T_Recv_Sync + - from_component: Fast_Rate_Group + from_connector: Event_T_Send + to_component: Event_Splitter_Instance + to_connector: T_Recv_Sync + - from_component: Watchdog_Rate_Group + from_connector: Event_T_Send + to_component: Event_Splitter_Instance + to_connector: T_Recv_Sync + - from_component: Command_Router_Instance + from_connector: Event_T_Send + to_component: Event_Splitter_Instance + to_connector: T_Recv_Sync + - from_component: Counter_Instance + from_connector: Event_T_Send + to_component: Event_Splitter_Instance + to_connector: T_Recv_Sync + - from_component: Oscillator_A + from_connector: Event_T_Send + to_component: Event_Splitter_Instance + to_connector: T_Recv_Sync + - from_component: Oscillator_B + from_connector: Event_T_Send + to_component: Event_Splitter_Instance + to_connector: T_Recv_Sync + - from_component: Ccsds_Socket_Interface_Instance + from_connector: Event_T_Send + to_component: Event_Splitter_Instance + to_connector: T_Recv_Sync + - from_component: Product_Packetizer_Instance + from_connector: Event_T_Send + to_component: Event_Splitter_Instance + to_connector: T_Recv_Sync + - from_component: Stack_Monitor_Instance + from_connector: Event_T_Send + to_component: Event_Splitter_Instance + to_connector: T_Recv_Sync + - from_component: Queue_Monitor_Instance + from_connector: Event_T_Send + to_component: Event_Splitter_Instance + to_connector: T_Recv_Sync + - from_component: Cpu_Monitor_Instance + from_connector: Event_T_Send + to_component: Event_Splitter_Instance + to_connector: T_Recv_Sync + - from_component: Event_Filter_Instance + from_connector: Event_T_Send + to_component: Event_Splitter_Instance + to_connector: T_Recv_Sync + - from_component: Event_Limiter_Instance + from_connector: Event_T_Send + to_component: Event_Splitter_Instance + to_connector: T_Recv_Sync + - from_component: Parameters_Instance + from_connector: Event_T_Send + to_component: Event_Splitter_Instance + to_connector: T_Recv_Sync + - from_component: Parameter_Store_Instance + from_connector: Event_T_Send + to_component: Event_Splitter_Instance + to_connector: T_Recv_Sync + - from_component: Zero_Divider_Instance + from_connector: Event_T_Send + to_component: Event_Splitter_Instance + to_connector: T_Recv_Sync + - from_component: Task_Watchdog_Instance + from_connector: Event_T_Send + to_component: Event_Splitter_Instance + to_connector: T_Recv_Sync + - from_component: Fault_Correction_Instance + from_connector: Event_T_Send + to_component: Event_Splitter_Instance + to_connector: T_Recv_Sync + - description: Split the event stream to create a filtered and limited stream for downlink and printing. + from_component: Event_Splitter_Instance + from_connector: T_Send + from_index: 1 + to_component: Event_Filter_Instance + to_connector: Event_T_Recv_Sync + - from_component: Event_Filter_Instance + from_connector: Event_Forward_T_Send + to_component: Event_Limiter_Instance + to_connector: Event_T_Recv_Sync + - from_component: Event_Limiter_Instance + from_connector: Event_Forward_T_Send + to_component: Event_Splitter_2_Instance + to_connector: T_Recv_Sync + - from_component: Event_Splitter_2_Instance + from_connector: T_Send + from_index: 1 + to_component: Event_Packetizer_Instance + to_connector: Event_T_Recv_Sync + - from_component: Event_Splitter_2_Instance + from_connector: T_Send + from_index: 2 + to_component: Event_Text_Logger_Instance + to_connector: Event_T_Recv_Async + - description: Unfiltered and unlimited event stream is passed to the post mortem event logger. + from_component: Event_Splitter_Instance + from_connector: T_Send + from_index: 2 + to_component: Event_Post_Mortem_Logger + to_connector: T_Recv_Sync + - from_component: Interrupt_Responder_Instance + from_connector: Event_T_Send + to_component: Event_Splitter_Instance + to_connector: T_Recv_Sync + - from_component: Product_Database_Instance + from_connector: Event_T_Send + to_component: Event_Splitter_Instance + to_connector: T_Recv_Sync + - from_component: Ccsds_Command_Depacketizer_Instance + from_connector: Event_T_Send + to_component: Event_Splitter_Instance + to_connector: T_Recv_Sync + - from_component: Event_Post_Mortem_Logger + from_connector: Event_T_Send + to_component: Event_Splitter_Instance + to_connector: T_Recv_Sync + - from_component: Memory_Packetizer_Instance + from_connector: Event_T_Send + to_component: Event_Splitter_Instance + to_connector: T_Recv_Sync + - from_component: Parameter_Manager_Instance + from_connector: Event_T_Send + to_component: Event_Splitter_Instance + to_connector: T_Recv_Sync + - from_component: Fault_Producer_Instance + from_connector: Event_T_Send + to_component: Event_Splitter_Instance + to_connector: T_Recv_Sync + # Command Response: + - from_component: Command_Router_Instance + from_connector: Command_Response_T_Send + to_component: Command_Router_Instance + to_connector: Command_Response_T_Recv_Async + - from_component: Counter_Instance + from_connector: Command_Response_T_Send + to_component: Command_Router_Instance + to_connector: Command_Response_T_Recv_Async + - from_component: Oscillator_A + from_connector: Command_Response_T_Send + to_component: Command_Router_Instance + to_connector: Command_Response_T_Recv_Async + - from_component: Oscillator_B + from_connector: Command_Response_T_Send + to_component: Command_Router_Instance + to_connector: Command_Response_T_Recv_Async + - from_component: Product_Packetizer_Instance + from_connector: Command_Response_T_Send + to_component: Command_Router_Instance + to_connector: Command_Response_T_Recv_Async + - from_component: Event_Packetizer_Instance + from_connector: Command_Response_T_Send + to_component: Command_Router_Instance + to_connector: Command_Response_T_Recv_Async + - from_component: Event_Post_Mortem_Logger + from_connector: Command_Response_T_Send + to_component: Command_Router_Instance + to_connector: Command_Response_T_Recv_Async + - from_component: Memory_Packetizer_Instance + from_connector: Command_Response_T_Send + to_component: Command_Router_Instance + to_connector: Command_Response_T_Recv_Async + - from_component: Ccsds_Command_Depacketizer_Instance + from_connector: Command_Response_T_Send + to_component: Command_Router_Instance + to_connector: Command_Response_T_Recv_Async + - from_component: Product_Database_Instance + from_connector: Command_Response_T_Send + to_component: Command_Router_Instance + to_connector: Command_Response_T_Recv_Async + - from_component: Stack_Monitor_Instance + from_connector: Command_Response_T_Send + to_component: Command_Router_Instance + to_connector: Command_Response_T_Recv_Async + - from_component: Queue_Monitor_Instance + from_connector: Command_Response_T_Send + to_component: Command_Router_Instance + to_connector: Command_Response_T_Recv_Async + - from_component: Cpu_Monitor_Instance + from_connector: Command_Response_T_Send + to_component: Command_Router_Instance + to_connector: Command_Response_T_Recv_Async + - from_component: Event_Filter_Instance + from_connector: Command_Response_T_Send + to_component: Command_Router_Instance + to_connector: Command_Response_T_Recv_Async + - from_component: Event_Limiter_Instance + from_connector: Command_Response_T_Send + to_component: Command_Router_Instance + to_connector: Command_Response_T_Recv_Async + - from_component: Parameters_Instance + from_connector: Command_Response_T_Send + to_component: Command_Router_Instance + to_connector: Command_Response_T_Recv_Async + - from_component: Parameter_Store_Instance + from_connector: Command_Response_T_Send + to_component: Command_Router_Instance + to_connector: Command_Response_T_Recv_Async + - from_component: Task_Watchdog_Instance + from_connector: Command_Response_T_Send + to_component: Command_Router_Instance + to_connector: Command_Response_T_Recv_Async + - from_component: Fault_Correction_Instance + from_connector: Command_Response_T_Send + to_component: Command_Router_Instance + to_connector: Command_Response_T_Recv_Async + - from_component: Zero_Divider_Instance + from_connector: Command_Response_T_Send + to_component: Command_Router_Instance + to_connector: Command_Response_T_Recv_Async + - from_component: Parameter_Manager_Instance + from_connector: Command_Response_T_Send + to_component: Command_Router_Instance + to_connector: Command_Response_T_Recv_Async + - from_component: Fault_Producer_Instance + from_connector: Command_Response_T_Send + to_component: Command_Router_Instance + to_connector: Command_Response_T_Recv_Async + # Command Routing: + - from_component: Command_Router_Instance + from_connector: Command_T_Send + from_index: 1 + to_component: Command_Router_Instance + to_connector: Command_T_Recv_Async + - from_component: Command_Router_Instance + from_connector: Command_T_Send + from_index: 2 + to_component: Counter_Instance + to_connector: Command_T_Recv_Async + - from_component: Command_Router_Instance + from_connector: Command_T_Send + from_index: 3 + to_component: Oscillator_A + to_connector: Command_T_Recv_Async + - from_component: Command_Router_Instance + from_connector: Command_T_Send + from_index: 4 + to_component: Oscillator_B + to_connector: Command_T_Recv_Async + - from_component: Command_Router_Instance + from_connector: Command_T_Send + from_index: 5 + to_component: Product_Packetizer_Instance + to_connector: Command_T_Recv_Async + - from_component: Command_Router_Instance + from_connector: Command_T_Send + from_index: 6 + to_component: Event_Packetizer_Instance + to_connector: Command_T_Recv_Sync + - from_component: Command_Router_Instance + from_connector: Command_T_Send + from_index: 7 + to_component: Event_Post_Mortem_Logger + to_connector: Command_T_Recv_Sync + - from_component: Command_Router_Instance + from_connector: Command_T_Send + from_index: 8 + to_component: Memory_Packetizer_Instance + to_connector: Command_T_Recv_Async + - from_component: Command_Router_Instance + from_connector: Command_T_Send + from_index: 9 + to_component: Product_Database_Instance + to_connector: Command_T_Recv_Sync + - from_component: Command_Router_Instance + from_connector: Command_T_Send + from_index: 10 + to_component: Ccsds_Command_Depacketizer_Instance + to_connector: Command_T_Recv_Sync + - from_component: Ccsds_Command_Depacketizer_Instance + from_connector: Command_T_Send + to_component: Command_Router_Instance + to_connector: Command_T_To_Route_Recv_Async + - from_component: Command_Router_Instance + from_connector: Command_T_Send + from_index: 11 + to_component: Stack_Monitor_Instance + to_connector: Command_T_Recv_Sync + - from_component: Command_Router_Instance + from_connector: Command_T_Send + from_index: 12 + to_component: Queue_Monitor_Instance + to_connector: Command_T_Recv_Sync + - from_component: Command_Router_Instance + from_connector: Command_T_Send + from_index: 13 + to_component: Cpu_Monitor_Instance + to_connector: Command_T_Recv_Sync + - from_component: Command_Router_Instance + from_connector: Command_T_Send + from_index: 14 + to_component: Event_Filter_Instance + to_connector: Command_T_Recv_Sync + - from_component: Command_Router_Instance + from_connector: Command_T_Send + from_index: 15 + to_component: Event_Limiter_Instance + to_connector: Command_T_Recv_Sync + - from_component: Command_Router_Instance + from_connector: Command_T_Send + from_index: 16 + to_component: Parameters_Instance + to_connector: Command_T_Recv_Async + - from_component: Command_Router_Instance + from_connector: Command_T_Send + from_index: 17 + to_component: Parameter_Store_Instance + to_connector: Command_T_Recv_Async + - from_component: Command_Router_Instance + from_connector: Command_T_Send + from_index: 18 + to_component: Zero_Divider_Instance + to_connector: Command_T_Recv_Sync + - from_component: Command_Router_Instance + from_connector: Command_T_Send + from_index: 19 + to_component: Fault_Correction_Instance + to_connector: Command_T_Recv_Async + - from_component: Command_Router_Instance + from_connector: Command_T_Send + from_index: 20 + to_component: Task_Watchdog_Instance + to_connector: Command_T_Recv_Sync + - from_component: Command_Router_Instance + from_connector: Command_T_Send + from_index: 21 + to_component: Parameter_Manager_Instance + to_connector: Command_T_Recv_Async + - from_component: Command_Router_Instance + from_connector: Command_T_Send + from_index: 22 + to_component: Fault_Producer_Instance + to_connector: Command_T_Recv_Sync + # Command Response Forwarding: + - from_component: Command_Router_Instance + from_connector: Command_Response_T_To_Forward_Send + from_index: 1 + to_component: Command_Router_Instance + to_connector: Command_Response_T_Recv_Async # Forward the first command response back to the router for noop test + # Data Product Connections: + - description: Data product connection between the oscillator and packetizer + from_component: Oscillator_A + from_connector: Data_Product_T_Send + to_component: Product_Database_Instance + to_connector: Data_Product_T_Recv_Sync + - description: Data product connection between the oscillator and packetizer + from_component: Oscillator_B + from_connector: Data_Product_T_Send + to_component: Product_Database_Instance + to_connector: Data_Product_T_Recv_Sync + - from_component: Event_Packetizer_Instance + from_connector: Data_Product_T_Send + to_component: Product_Database_Instance + to_connector: Data_Product_T_Recv_Sync + - from_component: Ccsds_Command_Depacketizer_Instance + from_connector: Data_Product_T_Send + to_component: Product_Database_Instance + to_connector: Data_Product_T_Recv_Sync + - from_component: Slow_Rate_Group + from_connector: Data_Product_T_Send + to_component: Product_Database_Instance + to_connector: Data_Product_T_Recv_Sync + - from_component: Fast_Rate_Group + from_connector: Data_Product_T_Send + to_component: Product_Database_Instance + to_connector: Data_Product_T_Recv_Sync + - from_component: Watchdog_Rate_Group + from_connector: Data_Product_T_Send + to_component: Product_Database_Instance + to_connector: Data_Product_T_Recv_Sync + - from_component: Command_Router_Instance + from_connector: Data_Product_T_Send + to_component: Product_Database_Instance + to_connector: Data_Product_T_Recv_Sync + - from_component: Event_Post_Mortem_Logger + from_connector: Data_Product_T_Send + to_component: Product_Database_Instance + to_connector: Data_Product_T_Recv_Sync + - from_component: Memory_Packetizer_Instance + from_connector: Data_Product_T_Send + to_component: Product_Database_Instance + to_connector: Data_Product_T_Recv_Sync + - from_component: Product_Database_Instance + from_connector: Data_Product_T_Send + to_component: Product_Database_Instance + to_connector: Data_Product_T_Recv_Sync + - from_component: Stack_Monitor_Instance + from_connector: Data_Product_T_Send + to_component: Product_Database_Instance + to_connector: Data_Product_T_Recv_Sync + - from_component: Queue_Monitor_Instance + from_connector: Data_Product_T_Send + to_component: Product_Database_Instance + to_connector: Data_Product_T_Recv_Sync + - from_component: Cpu_Monitor_Instance + from_connector: Data_Product_T_Send + to_component: Product_Database_Instance + to_connector: Data_Product_T_Recv_Sync + - from_component: Event_Filter_Instance + from_connector: Data_Product_T_Send + to_component: Product_Database_Instance + to_connector: Data_Product_T_Recv_Sync + - from_component: Event_Limiter_Instance + from_connector: Data_Product_T_Send + to_component: Product_Database_Instance + to_connector: Data_Product_T_Recv_Sync + - from_component: Task_Watchdog_Instance + from_connector: Data_Product_T_Send + to_component: Product_Database_Instance + to_connector: Data_Product_T_Recv_Sync + - from_component: Fault_Correction_Instance + from_connector: Data_Product_T_Send + to_component: Product_Database_Instance + to_connector: Data_Product_T_Recv_Sync + # Packetizer Connections: + - from_component: Product_Packetizer_Instance + from_connector: Data_Product_Fetch_T_Request + to_component: Product_Database_Instance + to_connector: Data_Product_Fetch_T_Service + # Interrupt Connections: + - from_component: Interrupt_Servicer_Instance + from_connector: Interrupt_Data_Type_Send + to_component: Interrupt_Responder_Instance + to_connector: Tick_T_Recv_Sync + # Uplink connections: + - from_component: Ccsds_Socket_Interface_Instance + from_connector: Ccsds_Space_Packet_T_Send + to_component: Ccsds_Command_Depacketizer_Instance + to_connector: Ccsds_Space_Packet_T_Recv_Sync + # Memory dump connections: + - from_component: Event_Post_Mortem_Logger + from_connector: Memory_Dump_Send + to_component: Memory_Packetizer_Instance + to_connector: Memory_Dump_Recv_Async + # Downlink connections: + - from_component: Event_Packetizer_Instance + from_connector: Packet_T_Send + to_component: Ccsds_Packetizer_Instance + to_connector: Packet_T_Recv_Sync + - from_component: Product_Packetizer_Instance + from_connector: Packet_T_Send + to_component: Ccsds_Packetizer_Instance + to_connector: Packet_T_Recv_Sync + - from_component: Counter_Instance + from_connector: Packet_T_Send + to_component: Ccsds_Packetizer_Instance + to_connector: Packet_T_Recv_Sync + - from_component: Memory_Packetizer_Instance + from_connector: Packet_T_Send + to_component: Ccsds_Packetizer_Instance + to_connector: Packet_T_Recv_Sync + - from_component: Ccsds_Command_Depacketizer_Instance + from_connector: Packet_T_Send + to_component: Ccsds_Packetizer_Instance + to_connector: Packet_T_Recv_Sync + - from_component: Product_Database_Instance + from_connector: Packet_T_Send + to_component: Ccsds_Packetizer_Instance + to_connector: Packet_T_Recv_Sync + - from_component: Ccsds_Packetizer_Instance + from_connector: Ccsds_Space_Packet_T_Send + to_component: Ccsds_Socket_Interface_Instance + to_connector: Ccsds_Space_Packet_T_Recv_Async + - from_component: Cpu_Monitor_Instance + from_connector: Packet_T_Send + to_component: Ccsds_Packetizer_Instance + to_connector: Packet_T_Recv_Sync + - from_component: Queue_Monitor_Instance + from_connector: Packet_T_Send + to_component: Ccsds_Packetizer_Instance + to_connector: Packet_T_Recv_Sync + - from_component: Stack_Monitor_Instance + from_connector: Packet_T_Send + to_component: Ccsds_Packetizer_Instance + to_connector: Packet_T_Recv_Sync + - from_component: Parameters_Instance + from_connector: Packet_T_Send + to_component: Ccsds_Packetizer_Instance + to_connector: Packet_T_Recv_Sync + - from_component: Parameter_Store_Instance + from_connector: Packet_T_Send + to_component: Ccsds_Packetizer_Instance + to_connector: Packet_T_Recv_Sync + - from_component: Event_Filter_Instance + from_connector: Packet_T_Send + to_component: Ccsds_Packetizer_Instance + to_connector: Packet_T_Recv_Sync + - from_component: Event_Limiter_Instance + from_connector: Packet_T_Send + to_component: Ccsds_Packetizer_Instance + to_connector: Packet_T_Recv_Sync + # Parameter connections: + - from_component: Parameters_Instance + from_connector: Parameter_Update_T_Provide + from_index: 1 + to_component: Oscillator_A + to_connector: Parameter_Update_T_Modify + - from_component: Parameters_Instance + from_connector: Parameter_Update_T_Provide + from_index: 2 + to_component: Oscillator_B + to_connector: Parameter_Update_T_Modify + # Task watchdog pet connections: + - from_component: Slow_Rate_Group + from_connector: Pet_T_Send + to_component: Task_Watchdog_Instance + to_connector: Pet_T_Recv_Sync + to_index: 1 + - from_component: Fast_Rate_Group + from_connector: Pet_T_Send + to_component: Task_Watchdog_Instance + to_connector: Pet_T_Recv_Sync + to_index: 2 + - description: The watchdog rate group is checked implicitly since it runs the task watchdog itself. + from_component: Watchdog_Rate_Group + from_connector: Pet_T_Send + to_component: ignore + to_connector: ignore + - description: This should be attached to a hardware watchdog on an embedded system. + from_component: Task_Watchdog_Instance + from_connector: Pet_T_Send + to_component: ignore + to_connector: ignore + # Fault connections: + - from_component: Task_Watchdog_Instance + from_connector: Fault_T_Send + to_component: Fault_Correction_Instance + to_connector: Fault_T_Recv_Async + - from_component: Fault_Producer_Instance + from_connector: Fault_T_Send + to_component: Fault_Correction_Instance + to_connector: Fault_T_Recv_Async + - description: We connect the fault correction command response to the command router synchronous connector for the fastest, most reliable execution. This bypasses the command router's queue. + from_component: Fault_Correction_Instance + from_connector: Command_T_Send + to_component: Command_Router_Instance + to_connector: Command_T_To_Route_Recv_Sync + # Parameter table connections: + - from_component: Parameter_Manager_Instance + from_connector: Working_Parameters_Memory_Region_Send + to_component: Parameters_Instance + to_connector: Parameters_Memory_Region_T_Recv_Async + - from_component: Parameter_Manager_Instance + from_connector: Default_Parameters_Memory_Region_Send + to_component: Parameter_Store_Instance + to_connector: Parameters_Memory_Region_T_Recv_Async + - from_component: Parameter_Store_Instance + from_connector: Parameters_Memory_Region_Release_T_Send + to_component: Parameter_Manager_Instance + to_connector: Parameters_Memory_Region_Release_T_Recv_Sync + - from_component: Parameters_Instance + from_connector: Parameters_Memory_Region_Release_T_Send + to_component: Parameter_Manager_Instance + to_connector: Parameters_Memory_Region_Release_T_Recv_Sync diff --git a/src/assembly/linux/linux_example.fault_responses.yaml b/src/assembly/linux/linux_example.fault_responses.yaml new file mode 100644 index 0000000..81664df --- /dev/null +++ b/src/assembly/linux/linux_example.fault_responses.yaml @@ -0,0 +1,27 @@ +--- +description: This is the fault response table for the example assembly. +fault_responses: + - fault: Task_Watchdog_Instance.Slow_Rate_Group_Fault + latching: True + startup_state: enabled + command_response: Command_Router_Instance.Noop_Arg + command_arg: (Value => 1) + description: Throw noop with value 1 if this fault occurs. + - fault: Task_Watchdog_Instance.Fast_Rate_Group_Fault + latching: True + startup_state: enabled + command_response: Command_Router_Instance.Noop_Arg + command_arg: (Value => 2) + description: Throw noop with value 2 if this fault occurs. + - fault: Fault_Producer_Instance.Fault_1 + latching: False + startup_state: enabled + command_response: Command_Router_Instance.Noop_Arg + command_arg: (Value => 3) + description: Throw noop with value 3 if this fault occurs. + - fault: Fault_Producer_Instance.Fault_2 + latching: False + startup_state: enabled + command_response: Command_Router_Instance.Noop_Arg + command_arg: (Value => 4) + description: Throw noop with value 4 if this fault occurs. diff --git a/src/assembly/linux/linux_example.parameter_table.yaml b/src/assembly/linux/linux_example.parameter_table.yaml new file mode 100644 index 0000000..ce1e66e --- /dev/null +++ b/src/assembly/linux/linux_example.parameter_table.yaml @@ -0,0 +1,10 @@ +--- +description: This is an parameter table layout for the Parameters component in the example assembly. +parameters_instance_name: Parameters_Instance +parameters: + - Oscillator_A.Frequency + - Oscillator_A.Amplitude + - Oscillator_A.Offset + - Oscillator_B.Frequency + - Oscillator_B.Amplitude + - Oscillator_B.Offset diff --git a/src/assembly/linux/linux_example.product_packets.yaml b/src/assembly/linux/linux_example.product_packets.yaml new file mode 100644 index 0000000..245a726 --- /dev/null +++ b/src/assembly/linux/linux_example.product_packets.yaml @@ -0,0 +1,11 @@ +--- +description: This is the set of packets for the data product packetizer in the Linux example assembly. +packets: + - name: Housekeeping_Packet + description: This packet contains housekeeping data. + id: 1 + data_products: + - name: Oscillator_A.Oscillator_Value + use_timestamp: True + - name: Oscillator_B.Oscillator_Value + period: "1" # create every 3 ticks diff --git a/src/assembly/linux/linux_example.task_watchdog_list.yaml b/src/assembly/linux/linux_example.task_watchdog_list.yaml new file mode 100644 index 0000000..c129267 --- /dev/null +++ b/src/assembly/linux/linux_example.task_watchdog_list.yaml @@ -0,0 +1,20 @@ +--- +description: Configure the task watchdog for the example assembly. +petters: + - name: Slow_Rate_Group + connector_name: Slow_Rate_Group.Pet_T_Send + description: Slow rate group monitoring. + limit: 3 + action: error_fault + critical: False # Make True to stop servicing downstream HW watchdog + fault_id: 1 + - name: Fast_Rate_Group + connector_name: Fast_Rate_Group.Pet_T_Send + description: Fast rate group monitoring. + limit: 3 + action: error_fault + critical: False # Make True to stop servicing downstream HW watchdog + fault_id: 2 + # We don't need to monitor the Watchdog_Rate_Group since the + # task watchdog is on that rate group. That makes it a defacto critical + # task, which will stop petting the watchdog if it freezes up. diff --git a/src/assembly/linux/main/README.md b/src/assembly/linux/main/README.md new file mode 100644 index 0000000..f5744d2 --- /dev/null +++ b/src/assembly/linux/main/README.md @@ -0,0 +1,78 @@ +# Linux Demo + + ![`Adamant running on Linux`](img/linux_cmd_line.png "Adamant running on Linux") + +This demo will walk you through how to build and run an [Adamant](https://github.com/lasp/adamant) assembly inside the +Linux development environment. Running Adamant on Linux can aid in designing and troubleshooting many problems before deploying +on more demanding hardware, like the [Raspberry Pi Pico](../../pico/main/README.md). + +## First Things First + + 1. Make sure you have your Adamant Linux build [environment](../../../../docker/README.md) set up. + 2. Explore the [design](../doc/linux_example.pdf) of the Linux assembly. + 3. Make sure you are familiar with the Adamant [architecture design](https://github.com/lasp/adamant/blob/main/doc/architecture_description_document/architecture_description_document.pdf) and know where to find the [user guide](https://github.com/lasp/adamant/blob/main/doc/user_guide/user_guide.pdf). + +## Building and running the Binary + +From this directory in your Adamant Linux environment run: + +``` +$ redo run +``` + +This will compile the assembly and create the Linux binary at `build/bin/Linux/main.elf`. After compilation is complete +the binary will automatically be started in the terminal. You should begin to see the software output events periodically +as it runs, like: + +``` +Starting Linux demo... Use Ctrl+C to exit. +0000168822.872929071 - Ccsds_Socket_Interface_Instance.Socket_Connected (0x00000085) : (Ip_Address = [C0 A8 41 02], Port = 2003) +0000168823.861770448 - Counter_Instance.Sending_Value (0x00000091) : (Value = 1) +0000168825.862075414 - Counter_Instance.Sending_Value (0x00000091) : (Value = 2) +0000168827.862054941 - Counter_Instance.Sending_Value (0x00000091) : (Value = 3) +... +``` + +## Commanding and Telemetry with Hydra + + ![`Commanding and Telemetry with Hydra`](../../pico/main/img/hydra.jpg "Commanding and Telemetry with Hydra") + +*Note that Hydra is not yet publicly available, but will be made so in the future. The instructions below serve as an example of how you could interact with this assembly with any ground system.* + +To best interact with the Linux assembly, we need to use a ground system interface, such as Hydra. Before running +Hydra we need to build the Hydra configuration files. This will allow Hydra to decode telemetry from the Linux assembly and properly format +outgoing commands. + +From this directory in your Adamant environment run: + +``` +$ redo hydra_config +``` + +You can also translate the produced Hydra configuration files to work with another ground system. + +Hydra will listen on a network socket for connections on port 2003 of your host machine. The Linux assembly will periodically try to +connect to Hydra on this port. + +With the Linux assembly running, see the previous section, open Hydra on your host machine and select your project directory as +`src/assembly/linux/main/hydra`. + +Hydra will start up and you should see events being received every two seconds from the Linux assembly over the socket in the main panel. + +With Hydra running, here are some interesting things you can try: + + 1. View events generated from the Linux assembly in the main panel. + 2. View telemetry from the Counter and Oscillator components by opening the `Display Page -> custom -> plots` panel. + 3. Send any command by double clicking a line in the `View -> All Commands` panel. Try sending a NOOP or changing the Oscillator frequencies. + 4. View the queue usage for each component by opening the `Display Page -> linux_example -> linux_example_queue_monitor` panel. + 5. Send an interrupt to the running assembly by running `sh send_interrupt.sh` from a new SSH session within within the Linux environment. You should see the software respond by printing out `Interrupt received` with a time stamp in the terminal where `redo run` was started. + +## What's Next + +Now that you have Adamant running on Linux, it is time to make it your own. Try modifying or adding a component. Follow the tutorials +in the [user guide](https://github.com/lasp/adamant/blob/main/doc/user_guide/user_guide.pdf) to get going. + +Other things to look at: + + * Check out the example running on the [Raspberry Pi Pico](../../pico/main/README.md) + * [Learn more about Ada](https://learn.adacore.com/) diff --git a/src/assembly/linux/main/hydra/.gitignore b/src/assembly/linux/main/hydra/.gitignore new file mode 100644 index 0000000..7ab074f --- /dev/null +++ b/src/assembly/linux/main/hydra/.gitignore @@ -0,0 +1,2 @@ +Rundirs +Pages diff --git a/src/assembly/linux/main/hydra/Config/.gitkeep b/src/assembly/linux/main/hydra/Config/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/assembly/linux/main/hydra/Config/hardware.xml b/src/assembly/linux/main/hydra/Config/hardware.xml new file mode 100644 index 0000000..0452e92 --- /dev/null +++ b/src/assembly/linux/main/hydra/Config/hardware.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/assembly/linux/main/hydra/Config/readers.xml b/src/assembly/linux/main/hydra/Config/readers.xml new file mode 100644 index 0000000..a8b2564 --- /dev/null +++ b/src/assembly/linux/main/hydra/Config/readers.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assembly/linux/main/hydra/Config/uplink_decoders.xml b/src/assembly/linux/main/hydra/Config/uplink_decoders.xml new file mode 100644 index 0000000..48127d5 --- /dev/null +++ b/src/assembly/linux/main/hydra/Config/uplink_decoders.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/assembly/linux/main/hydra/Files/.gitkeep b/src/assembly/linux/main/hydra/Files/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/assembly/linux/main/hydra/Menus/.gitkeep b/src/assembly/linux/main/hydra/Menus/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/assembly/linux/main/hydra/Scripts/.gitkeep b/src/assembly/linux/main/hydra/Scripts/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/assembly/linux/main/hydra/Scripts/setup.prc b/src/assembly/linux/main/hydra/Scripts/setup.prc new file mode 100644 index 0000000..73f4609 --- /dev/null +++ b/src/assembly/linux/main/hydra/Scripts/setup.prc @@ -0,0 +1,14 @@ +; This script handles setting some default values during startup +; that are specific to the Example mission: + +echo "Setting up Hydra for the Example Assembly." + +; Set the CCSDS Header: +set Ccsds_Ground_Command_Header-Ccsds_Primary_Header-Apid = 7 +set Ccsds_Ground_Command_Header-Ccsds_Primary_Header-Packet_Type = 1 +set Ccsds_Ground_Command_Header-Ccsds_Primary_Header-Secondary_Header = 1 + +; Send the NOOP command to the assembly to make sure things are working +command_Router_Instance-Noop + +echo "Setup complete." diff --git a/src/assembly/linux/main/hydra/hydra_config.xml b/src/assembly/linux/main/hydra/hydra_config.xml new file mode 100644 index 0000000..b38eb4a --- /dev/null +++ b/src/assembly/linux/main/hydra/hydra_config.xml @@ -0,0 +1,21 @@ + + +./Config/hardware.xml + +../../../../../../adamant/gnd/hydra/Config/adamant_types.xml + +../../build/hydra/Config/linux_example.xml +../../build/hydra/Config/linux_example_ccsds_commands.xml +../../build/hydra/Config/linux_example_ccsds_packets.xml + +./Config/uplink_decoders.xml + +../../../../../gnd/hydra/Config/downlink_decoders.xml +./Config/readers.xml + + + + + + + diff --git a/src/assembly/linux/main/hydra/init.prc b/src/assembly/linux/main/hydra/init.prc new file mode 100644 index 0000000..38d786d --- /dev/null +++ b/src/assembly/linux/main/hydra/init.prc @@ -0,0 +1,7 @@ +; This script runs at startup automatically + +; Run the autocoded generate packet pages script to set up all the pages for packets in the assembly +start linux_example_packet_pages + +; Run the setup script +start setup diff --git a/src/assembly/linux/main/hydra_config.do b/src/assembly/linux/main/hydra_config.do new file mode 100644 index 0000000..7cedda7 --- /dev/null +++ b/src/assembly/linux/main/hydra_config.do @@ -0,0 +1,8 @@ +# Start Hydra: +export TARGET= +this_dir=`dirname "$0"` +hydra_dir=`realpath $this_dir/../../../../gnd/hydra` +config_file=$this_dir/hydra/hydra_config.xml +assembly_dir=`realpath $this_dir/..` +assembly_file=`ls $assembly_dir'/'*'.assembly.yaml' | head -1` +$hydra_dir/build_hydra_config.sh $assembly_file $config_file >/dev/null diff --git a/src/assembly/linux/main/img/linux_cmd_line.png b/src/assembly/linux/main/img/linux_cmd_line.png new file mode 100644 index 0000000..6c09115 Binary files /dev/null and b/src/assembly/linux/main/img/linux_cmd_line.png differ diff --git a/src/assembly/linux/main/main.adb b/src/assembly/linux/main/main.adb new file mode 100644 index 0000000..21324ea --- /dev/null +++ b/src/assembly/linux/main/main.adb @@ -0,0 +1,33 @@ +with Ada.Text_IO; use Ada.Text_IO; +with Ada.Real_Time; use Ada.Real_Time; +with Ada.Exceptions; use Ada.Exceptions; +with Linux_Example; +with Last_Chance_Handler; +pragma Unreferenced (Last_Chance_Handler); + +procedure Main is + Wait_Time : constant Ada.Real_Time.Time_Span := Ada.Real_Time.Microseconds (1000000); + Start_Time : constant Ada.Real_Time.Time := Ada.Real_Time.Clock + Wait_Time; +begin + ---- Set up the assembly: + Linux_Example.Init_Base; + Linux_Example.Set_Id_Bases; + Linux_Example.Connect_Components; + Linux_Example.Init_Components; + + -- Start the assembly: + Put_Line ("Starting Linux demo... Use Ctrl+C to exit."); + delay until Start_Time; + Linux_Example.Start_Components; + Linux_Example.Set_Up_Components; + + -- Loop forever: + loop + delay until Clock + Milliseconds (500); + end loop; + +exception + when Error : others => + Put ("Unhandled exception occurred in main: "); + Put_Line (Exception_Information (Error)); +end Main; diff --git a/src/assembly/linux/main/send_interrupt.sh b/src/assembly/linux/main/send_interrupt.sh new file mode 100755 index 0000000..ecd72ea --- /dev/null +++ b/src/assembly/linux/main/send_interrupt.sh @@ -0,0 +1,2 @@ +#!/bin/sh +kill -s USR1 `pgrep "main.elf"` diff --git a/src/assembly/linux/memory_map.ads b/src/assembly/linux/memory_map.ads new file mode 100644 index 0000000..7fc7122 --- /dev/null +++ b/src/assembly/linux/memory_map.ads @@ -0,0 +1,11 @@ +with Basic_Types; +with Linux_Example_Parameter_Table; + +package Memory_Map is + + -- Define parameter store. This is declared as static memory address for linux assembly, but for + -- an embedded assembly might reference a static address in a non-volatile memory region like MRAM. + Parameter_Store_Bytes : aliased Basic_Types.Byte_Array := (0 .. Linux_Example_Parameter_Table.Parameter_Table_Size_In_Bytes - 1 => <>); + Parameter_Store_Bytes_Access : constant Basic_Types.Byte_Array_Access := Parameter_Store_Bytes'Access; + +end Memory_Map; diff --git a/src/assembly/linux/start_up.adb b/src/assembly/linux/start_up.adb new file mode 100644 index 0000000..8c5a54c --- /dev/null +++ b/src/assembly/linux/start_up.adb @@ -0,0 +1,31 @@ +with Ada.Task_Termination; use Ada.Task_Termination; +with Ada.Text_IO; use Ada.Text_IO; + +package body Start_Up is + + -- Print out task termination information to the user: + protected body Task_Termination is + procedure Handler (Cause : Ada.Task_Termination.Cause_Of_Termination; T : Ada.Task_Identification.Task_Id; X : Ada.Exceptions.Exception_Occurrence) is + use Ada.Task_Identification; + use Ada.Exceptions; + begin + Put ("Task: "); + Put (Image (T)); + case Cause is + when Normal => + null; + Put_Line (" exited."); + when Abnormal => + Put_Line (" exited abnormally."); + when Unhandled_Exception => + Put_Line (" exited due to an unhandled exception:"); + Put_Line (Exception_Information (X)); + end case; + end Handler; + end Task_Termination; + +begin + -- Set up the fallback handler during elaboration to make sure that + -- it gets set up before any tasks get started. + Set_Dependents_Fallback_Handler (Task_Termination.Handler'Access); +end Start_Up; diff --git a/src/assembly/linux/start_up.ads b/src/assembly/linux/start_up.ads new file mode 100644 index 0000000..f489542 --- /dev/null +++ b/src/assembly/linux/start_up.ads @@ -0,0 +1,18 @@ +with Ada.Task_Termination; +with Ada.Task_Identification; +with Ada.Exceptions; + +package Start_Up is + -- Elaborate the body which will set up the task termination handlers + -- for all library level tasks. This is done to ensure that the termination + -- handler is set up before the tasks are started, thus eliminating a race + -- condition; + pragma Elaborate_Body; + + -- Note: This task termination prototype will only work on a native + -- platform. Ada.Task_Termination has a different package spec for + -- embedded plaforms that use Ravenscar. + protected Task_Termination is + procedure Handler (Cause : Ada.Task_Termination.Cause_Of_Termination; T : Ada.Task_Identification.Task_Id; X : Ada.Exceptions.Exception_Occurrence); + end Task_Termination; +end Start_Up; diff --git a/src/assembly/linux/views/.Linux_path b/src/assembly/linux/views/.Linux_path new file mode 100644 index 0000000..e69de29 diff --git a/src/assembly/linux/views/README.md b/src/assembly/linux/views/README.md new file mode 100644 index 0000000..92b2aad --- /dev/null +++ b/src/assembly/linux/views/README.md @@ -0,0 +1,9 @@ +# Linux Example Views + +This directory contains views for the Linux assembly. To build them run: + +``` +$ redo +``` + +Assembly views will appear in `build/svg/`. Open any of the SVG files in a web browser to inspect them. diff --git a/src/assembly/linux/views/command.linux_example.view.yaml b/src/assembly/linux/views/command.linux_example.view.yaml new file mode 100644 index 0000000..97792d2 --- /dev/null +++ b/src/assembly/linux/views/command.linux_example.view.yaml @@ -0,0 +1,9 @@ +--- +description: This view shows how commands are routed throughout the assembly. Commands are contained in the Command.T data type. Commands coming from the ground system originate from the Ccsds_Command_Depacketizer_Instance and then get passed the Command_Router_Instance. The router looks at the command's ID, determines the destination component for which the command is intended, and then forwards the command to that appropriate destination component. When a destination component receives a command, it will execute it and pass a Command_Response.T data type back to the command router (shown in the Command Response View). Note that the Fault_Correction_Instance can also produce commands in order to correct a system fault. Commands from the Fault_Correction_Instance are passed to the router synchronously, bypassing the standard command queue that the Ccsds_Command_Depacketizer_Instance uses. +layout: left-to-right +filters: + - name: cmd_connections + type: connector_type + include: + - Command.T +postamble: "{ rank=source; Fault_Correction_Instance, Ccsds_Command_Depacketizer_Instance }" diff --git a/src/assembly/linux/views/command_response.linux_example.view.yaml b/src/assembly/linux/views/command_response.linux_example.view.yaml new file mode 100644 index 0000000..162a053 --- /dev/null +++ b/src/assembly/linux/views/command_response.linux_example.view.yaml @@ -0,0 +1,7 @@ +--- +description: After a component executes a command received from the Command_Router_Instance, it passes back a Command_Response.T type to the router letting it know if the command succeeded or failed. This connection is also used to register all the commands with the router an initialization. This allows the Command_Router_Instance to create the internal routing table that it uses to route incoming commands. +filters: + - name: reg_connections + type: connector_type + include: + - Command_Response.T diff --git a/src/assembly/linux/views/data_products.linux_example.view.yaml b/src/assembly/linux/views/data_products.linux_example.view.yaml new file mode 100644 index 0000000..936b63c --- /dev/null +++ b/src/assembly/linux/views/data_products.linux_example.view.yaml @@ -0,0 +1,7 @@ +--- +description: Any data product produced by a component during execution is sent synchronously to on onboard storage database, the Product_Database_Instance. This component stores the latest value and timestamp of each data product in the system. Other components, such as the Product_Packetizer_Instance can then fetch these data products at a later time for limit checking, packetization, etc. +filters: + - name: dp_connections + type: connector_type + include: + - Data_Product.T diff --git a/src/assembly/linux/views/downlink.linux_example.view.yaml b/src/assembly/linux/views/downlink.linux_example.view.yaml new file mode 100644 index 0000000..5ea03e5 --- /dev/null +++ b/src/assembly/linux/views/downlink.linux_example.view.yaml @@ -0,0 +1,14 @@ +--- +description: Any packet produced by the assembly is sent to the Ccsds_Packetizer_Instance. This component takes the Adamant formatted packets, converts them to CCSDS, and sends them asynchronously to the Ccsds_Socket_Interface_Instance. The socket interface component will take packets stored on its queue and transmit them over a network TCP socket. The Product_Packetizer_Instance periodically requests data products from the Product_Database_Instance to create packets containing data from multiple components. These packets are also forwarded to the Ccsds_Packetizer_Instance for downlink. +layout: left-to-right +filters: + - name: downlink_connections + type: connector_type + include: + - Packet.T + - Data_Product_Fetch.T + - Ccsds_Space_Packet.T + - name: rm_component + type: component_type + exclude: + - Ccsds_Command_Depacketizer diff --git a/src/assembly/linux/views/events.linux_example.view.yaml b/src/assembly/linux/views/events.linux_example.view.yaml new file mode 100644 index 0000000..0820508 --- /dev/null +++ b/src/assembly/linux/views/events.linux_example.view.yaml @@ -0,0 +1,13 @@ +--- +description: Events are produced by components when something interesting happens. All components send their events to the Event_Splitter_Instance. This components duplicates the event and passes it to two destination components. The first path goes to the Event_Post_Mortem_Logger, which stores the event into a memory store. On an embedded assembly, this would typically be in non-volatile memory. The event is also passed down a different path to the Event_Filter_Instance. This component can enabled/disable individual events by ID. Next, events are forwarded to the Event_Limiter_Instance. This component will start limiting problematic spam events that might flood the system. Any event that passes both of these filtering components is split by the Event_Splitter_2_Instance to two final destinations. The first is the Event_Text_Logger_Instance which prints out human readable events to the Linux terminal. The second is the Event_Packetizer_Instance which collects incoming events into packets for later downlink. This design allows for all events to be stored (unfiltered and unlimited) in the post mortem logger. A filtered and limited event stream is presented to both the Linux terminal and socket. +filters: + - name: evt_connections + type: connector_type + include: + - Event.T + - name: rm_connections + type: connector_name + exclude: + - Event_Limiter_Instance.Event_T_Send + - Event_Filter_Instance.Event_T_Send + - Event_Post_Mortem_Logger.Event_T_Send diff --git a/src/assembly/linux/views/faults.linux_example.view.yaml b/src/assembly/linux/views/faults.linux_example.view.yaml new file mode 100644 index 0000000..762cfb8 --- /dev/null +++ b/src/assembly/linux/views/faults.linux_example.view.yaml @@ -0,0 +1,20 @@ +--- +description: Any component that produces faults will send them to the Fault_Correction_Instance. This component maps the fault to a response action. This action is in the form of a correction command which is sent to the Command_Router_Instance synchronously for execution. In the Linux assembly, two components can throw faults. The first is the Task_Watchdog_Instance. This component monitors some critical tasks to ensure that they are always running in a timely fashion. If one stops executing, a fault is thrown. The Fault_Producer_Instance is a simple component that throws a fault when commanded to. This can be used to inject a fault into the system for testing purposes. +rule: flt_connections | (flt_response & rm_connectors) +filters: + - name: flt_connections + type: connector_type + include: + - Fault.T + - name: flt_response + type: component_type + include: + - Fault_Correction + - Command_Router + - name: rm_connectors + type: connector_name + exclude: + - Command_Router_Instance.Command_T_Send + - Command_Router_Instance.Command_Response_T_To_Forward_Send + - Command_Router_Instance.Command_Response_T_Send + - Command_Router_Instance.Command_Response_T_Recv_Async diff --git a/src/assembly/linux/views/parameters.linux_example.view.yaml b/src/assembly/linux/views/parameters.linux_example.view.yaml new file mode 100644 index 0000000..192cacd --- /dev/null +++ b/src/assembly/linux/views/parameters.linux_example.view.yaml @@ -0,0 +1,9 @@ +--- +description: This view demonstrates an example usage of the Adamant parameter system. Any component that requires parameters (Oscillator_A and Oscillator_B) receives them from the Parameters_Instance. This component manages the updating and fetching of parameters from any parameter-using components in the system. The Parameter_Store_Instance maintains a memory copy of the parameter table for the entire assembly. This table includes values for each individual parameter used by all the components in the system. In an embedded assembly, this parameter store would usually store the parameter table in a non-volatile memory region. The Parameter_Manager_Instance is responsible for managing commands to copy parameter tables between the Parameter_Store_Instance (usually manages what is called the default parameter table) and the Parameter_Instance (usually manages what is called the active parameter table). Any updates to the active parameter table will cause the Parameters_Instance to push individual parameter updates to the downstream components that need the updated parameters. Note - The current Linux assembly does not include code within the Parameter_Manager_Instance for uploading new parameter tables from a ground system yet. +filters: + - name: param_connections + type: connector_type + include: + - Parameter_Update.T + - Parameters_Memory_Region.T + - Parameters_Memory_Region_Release.T diff --git a/src/assembly/linux/views/tick.linux_example.view.yaml b/src/assembly/linux/views/tick.linux_example.view.yaml new file mode 100644 index 0000000..4abd995 --- /dev/null +++ b/src/assembly/linux/views/tick.linux_example.view.yaml @@ -0,0 +1,7 @@ +--- +description: In this assembly, Tick.T types are used to indicate when periodic or interrupt driven tasks should be run. This view shows the rate groups and interrupts that exist in the assembly. The Interrupt_Servicer_Instance is an active component that sits and waits, ready to execute when a specific interrupt is received. When this interrupt is received, it passes a tick to the Interrupt_Responder_Instance, which performs a task in response to the received interrupt. The Interrupt_Servicer_Instance will then immediately wait again for a subsequent interrupt. The Ticker_Instance runs in a high priority task and produces a Tick.T at 5 Hz. This tick is forwarded to the Tick_Divider_Instance which takes the 5 Hz signal and divides it up among 3 different rate groups. The Slow_Rate_Group runs at 0.5 Hz. The Fast_Rate_Group runs a 5 Hz. The Watchdog_Rate_Group runs as 1 Hz. Each of these rate group components will call the components connected to them every time they receive a tick from upstream. This architecture allows for periodic execution of certain functions, such as collecting telemetry or creating packets. Note that the actual execution of each rate group is also interleaved by the Ada scheduler. Each rate group is an active component, which executes on a task with a priority shown in the top right hand corner of the component. Rate groups produce telemetry relating how long it takes them to execute, both in CPU time and in wall clock time. +filters: + - name: tick_connections + type: connector_type + include: + - Tick.T diff --git a/src/assembly/linux/views/time.linux_example.view.yaml b/src/assembly/linux/views/time.linux_example.view.yaml new file mode 100644 index 0000000..6e801e5 --- /dev/null +++ b/src/assembly/linux/views/time.linux_example.view.yaml @@ -0,0 +1,7 @@ +--- +description: All components in the system fetch time by requesting it from the System_Time_Instance. By implementing the time system at the Adamant architectural level, different time sources and time synchronization schemes can be easily swapped into the system by replacing System_Time_Instance with a more tailored version. Note that synchronous connectors exhibit extremely low overhead, so exposing anything at the architectural level should not be prohibitive in terms of performance. +filters: + - name: time + type: connector_type + include: + - Sys_Time.T diff --git a/src/assembly/linux/views/uplink.linux_example.view.yaml b/src/assembly/linux/views/uplink.linux_example.view.yaml new file mode 100644 index 0000000..65a876d --- /dev/null +++ b/src/assembly/linux/views/uplink.linux_example.view.yaml @@ -0,0 +1,18 @@ +--- +description: The Ccsds_Socket_Interface_Instance receives data from a ground system on a TCP socket. If the component receives a valid CCSDS packet it forwards it along to the Ccsds_Commmand_Depacketizer_Instance. This component looks for commands in the CCSDS packet, extracts them, and then forwards them along the Command_Router_Instance for routing and later execution. +layout: left-to-right +filters: + - name: downlink_types + type: connector_type + include: + - Ccsds_Space_Packet.T + - Command.T + - name: rm_connector + type: connector_name + exclude: + - Command_Router_Instance.Command_T_Send + - name: rm_component + type: component_type + exclude: + - Ccsds_Packetizer + - Fault_Correction diff --git a/src/assembly/pico/.Pico_path b/src/assembly/pico/.Pico_path new file mode 100644 index 0000000..e69de29 diff --git a/src/assembly/pico/README.md b/src/assembly/pico/README.md new file mode 100644 index 0000000..4422d7a --- /dev/null +++ b/src/assembly/pico/README.md @@ -0,0 +1,7 @@ +# Raspberry Pi Pico Demo + +This directory contains models for the Raspberry Pi Pico demo. To try out this demo look in [main](main/README.md). Contents of the subdirectories are listed below: + + * `doc/` - Contains the generated design documentation for the assembly. + * `main/` - Contains the main entry-point for the assembly executable and instructions on how to build and run it. + * `views/` - Contains graphical views of the assembly. diff --git a/src/assembly/pico/doc/README.md b/src/assembly/pico/doc/README.md new file mode 100644 index 0000000..2736a06 --- /dev/null +++ b/src/assembly/pico/doc/README.md @@ -0,0 +1,3 @@ +# Raspberry Pi Pico Demo Documentation + +This directory contains the assembly [design documentation](pico_example.pdf). diff --git a/src/assembly/pico/doc/env.py b/src/assembly/pico/doc/env.py new file mode 100644 index 0000000..d9cba61 --- /dev/null +++ b/src/assembly/pico/doc/env.py @@ -0,0 +1 @@ +from environments import pico # noqa: F401 diff --git a/src/assembly/pico/doc/pico_example.pdf b/src/assembly/pico/doc/pico_example.pdf new file mode 100644 index 0000000..16664ae Binary files /dev/null and b/src/assembly/pico/doc/pico_example.pdf differ diff --git a/src/assembly/pico/doc/pico_example.tex b/src/assembly/pico/doc/pico_example.tex new file mode 100644 index 0000000..2ac5f64 --- /dev/null +++ b/src/assembly/pico/doc/pico_example.tex @@ -0,0 +1,79 @@ +\input{common_packages.tex} + +\begin{document} + +\title{\textbf{Pico Example} \\ +\large\textit{Assembly Design Document}} +\date{} +\maketitle + +\section{Description} +\input{build/tex/pico_example_description.tex} + +\section{Design} + +\subsection{At a Glance} +\input{build/tex/pico_example_stats.tex} + +\subsection{Components} +All of the components in the Pico Example assembly are reusable components that can be found within the Adamant repository (in \textit{src/components/}) with a few exceptions: + +\vspace{5mm} %5mm vertical space +\begin{spaceditemize} + \item \textbf{\texttt{\url{Adc_Data_Collector}}} - This component collects internal telemetry from the Raspberry Pi Pico including system voltage and temperature. + \item \textbf{\texttt{\url{Counter}}} - This is an extremely simple component that produces an incrementing counter as telemetry. + \item \textbf{\texttt{\url{Fault_Producer}}} - This is an component that can be used to inject a fault into the system via command. + \item \textbf{\texttt{\url{Oscillator}}} - This is a simple component that produces two sinusoidal outputs into telemetry. +\end{spaceditemize} +\vspace{5mm} %5mm vertical space + +These specific component are located in the Example repository in \textit{src/components/}. A full list of the components included in the assembly can be seen below. Note that components marked as active execute on their own task within the Ada runtime. + +\input{build/tex/pico_example_components.tex} + +\subsection{Views} + +This section shows the example assembly visually as a set of \textit{views}. Each shows a specific set of components and connections (while not showing other components and connections) in order to highlight a particular function of the assembly. Components that are bold are \textit{active}, meaning they have an Ada task assigned to them. Connections are labeled with the type that is passed along them. A dotted line indicates that the connection is asynchronous, meaning the data is put onto a queue for later processing. A solid line indicates that the connection is synchronous, meaning processing of that data occurs right when the data is passed along the connector. + +\input{build/tex/pico_example_views.tex} + +\subsection{Task Priorities} +\input{build/tex/pico_example_priorities.tex} + +\subsection{Commands} + +\input{build/tex/pico_example_commands.tex} + +\subsection{Parameters} + +\input{build/tex/pico_example_parameters.tex} + +\subsection{Events} + +\input{build/tex/pico_example_events.tex} + +\subsection{Data Products} + +\input{build/tex/pico_example_data_products.tex} + +\subsection{Packets} + +\input{build/tex/pico_example_packets.tex} + +\subsection{Faults} + +\input{build/tex/pico_example_faults.tex} + +\section{Appendix} +\subsection{Connections} +\input{build/tex/pico_example_connections.tex} + +\subsection{Packed Types} + +\input{build/tex/pico_example_types.tex} + +\subsection{Enumerations} + +\input{build/tex/pico_example_enums.tex} + +\end{document} diff --git a/src/assembly/pico/env.py b/src/assembly/pico/env.py new file mode 100644 index 0000000..d9cba61 --- /dev/null +++ b/src/assembly/pico/env.py @@ -0,0 +1 @@ +from environments import pico # noqa: F401 diff --git a/src/assembly/pico/main/README.md b/src/assembly/pico/main/README.md new file mode 100644 index 0000000..d2c4117 --- /dev/null +++ b/src/assembly/pico/main/README.md @@ -0,0 +1,167 @@ +# Raspberry Pi Pico Demo + + ![`Adamant on the Raspberry Pi Pico`](img/pico.jpg "Adamant on the Raspberry Pi Pico") + +This demo will walk you through how to build and deploy an [Adamant](https://github.com/lasp/adamant) assembly onto the +[Raspberry Pi Pico](https://www.raspberrypi.com/products/raspberry-pi-pico/). The +Raspberry Pi Pico is a tiny development board that utilizes the RP2040 microcontroller +with 264kB of SRAM. It is a great platform to demonstrate how Adamant +can be used effectively, even on deeply embedded systems. + +## First Things First + + 1. Make sure you have your Adamant build [environment](../../../../docker/README.md) set up. + 2. Explore the [design](../doc/pico_example.pdf) of the Pico assembly. + 3. Make sure you are familiar with the Adamant [architecture design](https://github.com/lasp/adamant/blob/main/doc/architecture_description_document/architecture_description_document.pdf) and know where to find the [user guide](https://github.com/lasp/adamant/blob/main/doc/user_guide/user_guide.pdf). + +## Board Setup + +This demo was prepared using the [Raspberry Pi Pico H](https://www.raspberrypi.com/documentation/microcontrollers/raspberry-pi-pico.html), +although any board in the Pico family should work, a breadboard, micro-USB cable, and the +[Raspberry Pi Debug Probe](https://www.raspberrypi.com/documentation/microcontrollers/debug-probe.html) or a USB to TTL serial cable. +Two setups are possible: 1) with the Raspberry Pi Debug Probe, which allows for debugging via OpenOCD and GDB or 2) with a USB to TTL serial cable, +which does not allow for debugging. + +### With the Debug Probe (Recommended) + + ![`Pico with Debug Probe`](img/pico_probe.jpg "Pico with Debug Probe") + +Setup the Pico as shown above with the following connections ([detailed pinout](https://datasheets.raspberrypi.com/pico/Pico-R3-A4-Pinout.pdf)): + + 1. USB from PC to Pico Micro-USB connector + 2. USB from PC to Debug Probe Micro-USB connector + 3. Debug Probe "D" connector to Pico SWD JST (DEBUG) connector + 4. Debug Probe "U" connector breaks out to three pins (male) + * Probe RX (yellow) connected to Pico UART0 TX pin 21 + * Probe TX (orange) connected to Pico UART0 RX pin 22 + * Probe GND (black) connected to Pico GND pin 23 + +### Without the Debug Probe + + ![`Pico with USB to Serial`](img/pico_usb.jpg "Pico with USB to Serial") + +Setup the Pico as shown above with the following connections ([detailed pinout](https://datasheets.raspberrypi.com/pico/Pico-R3-A4-Pinout.pdf)): + + 1. USB from PC to Pico Micro-USB connector + 2. USB to TTL serial cable from PC breaks out to three pins (male) + * USB RX (white) connected to Pico UART0 TX pin 21 + * USB TX (green) connected to Pico UART0 RX pin 22 + * USB GND (black) connected to Pico GND pin 23 + +## Building the Binary + +From this directory in your Adamant environment run: + +``` +$ redo +``` + +This will compile the Pico assembly and create `build/bin/Pico/main.elf` and `build/bin/Pico/main.uf2` which will be used in the next section. + +## Uploading to the Pico + +Now we can upload our freshly compiled binary to the Pico. There are two methods for doing this. The first, using the Raspberry Pi Debug Probe, +will allow for traditional debugging of the running code using GDB. If you do not have a Debug Probe, you can still upload and run the binary +using the second method. + +### With the Debug Probe (Recommended) + +With the Raspberry Pi Debug Probe we can upload new programs to the Pico, send and receive data on the UART, and perform debugging with GDB. +Before starting, install OpenOCD and GDB on your host machine using [these instructions](https://www.raspberrypi.com/documentation/microcontrollers/debug-probe.html#installing-tools). + +To program the Pico without debugging you can run `./program.sh` from your host machine, or manually run: + +``` +$ openocd -f interface/cmsis-dap.cfg -f target/rp2040.cfg -c "adapter speed 5000" -c "program build/bin/Pico/main.elf verify reset exit" +``` + +You may need `sudo`. + +To perform debugging with GDB we will need two terminals open on the host machine. In the first, run `./start_openocd.sh` or manually run: + +``` +$ openocd -f interface/cmsis-dap.cfg -f target/rp2040.cfg -c "adapter speed 5000" +``` + +Next, start GDB in the second terminal by running `./debug.sh` or manually run: + +``` +$ gdb build/bin/Pico/main.elf +> target remote localhost:3333 +> monitor reset init +> load +> continue +``` + +From here you can use GDB as you normally would to set break points, pause the program, etc. + +You can verify that telemetry is being produced by the Pico by opening the USB serial device on your PC with a program like minicom or screen with a baud rate of 115200, ie. + +``` +$ screen /dev/tty.usbmodem22402 115200 +``` + +### Without the Debug Probe + +The Pico can act like a USB storage device, allowing you to program it by simply drag-and-dropping the `.uf2` file onto the device. + + 1. With the Pico Micro-USB connector disconnected, push and hold the BOOTSEL button on the Pico. + 2. Connect the Micro-USB connector to your PC. + 3. Once the USB storage device RPI-RP2 automatically mounts on your computer, you can release the BOOTSEL button. + 4. Finally, copy or drag-and-drop `build/bin/Pico/main.uf2` onto the RPI-RP2 device. The program should begin running automatically. + + ![`Copy main.uf2 to RPI-RP2 device`](img/copy_uf2.png "Copy main.uf2 to RPI-RP2 device") + +You can verify that telemetry is being produced by the Pico by opening the USB serial device on your PC with a program like minicom or screen with a baud rate of 115200, ie. + +``` +$ screen /dev/tty.usbserial-230 115200 +``` + +## Commanding and Telemetry with Hydra + + ![`Commanding and Telemetry with Hydra`](img/hydra.jpg "Commanding and Telemetry with Hydra") + +*Note that Hydra is not yet publicly available, but will be made so in the future. The instructions below serve as an example of how you could interact with this assembly with any ground system.* + +To best interact with the Pico, we need to use a ground system interface, such as Hydra. Before running +Hydra we need to build the Hydra configuration files. This will allow Hydra to decode telemetry from the Pico and properly format +outgoing commands. + +From this directory in your Adamant environment run: + +``` +$ redo hydra_config +``` + +You can also translate the produced Hydra configuration files to work with another ground system. + +Hydra will connect to the serial port on your host machine. You can tell Hydra to connect to the appropriate device by modifying the +[hardware configuration file](hydra/Config/hardware.xml). Change the `port` field in the following line: + +``` + +``` + +to the USB serial port from the Pico on your PC. + +Next, open Hydra on your host machine and select your project directory as `src/assembly/pico/main/hydra`. +Hydra will start up and you should see events being received every two seconds from the Pico over the UART in the main panel. + +With Hydra running, here are some interesting things you can try: + + 1. View events generated from the Pico in the main panel. + 2. View telemetry from the Counter and Oscillator components by opening the `Display Page -> custom -> plots` panel. + 3. Send any command by double clicking a line in the `View -> All Commands` panel. Try sending a NOOP or changing the Oscillator frequencies. + 4. View the Pico temperature and system voltage by opening the `Display Page -> Ccsds-Product_Packetizer_Instance-Housekeeping_Packet` panel. + 5. View the CPU usage for each active component by opening the `Display Page -> pico_example -> pico_example_cpu_monitor` panel. + +## What's Next + +Now that you have a Raspberry Pi Pico running Adamant, it is time to make it your own. Try modifying or adding a component. Follow the tutorials +in the [user guide](https://github.com/lasp/adamant/blob/main/doc/user_guide/user_guide.pdf) to get going. + +Other things to look at: + + * Check out the example [Linux assembly](../../linux/main/README.md) + * [Learn more about Ada](https://learn.adacore.com/) diff --git a/src/assembly/pico/main/all.do b/src/assembly/pico/main/all.do new file mode 100644 index 0000000..203faa4 --- /dev/null +++ b/src/assembly/pico/main/all.do @@ -0,0 +1 @@ +redo-ifchange build/bin/Pico/main.uf2 diff --git a/src/assembly/pico/main/config.gdb b/src/assembly/pico/main/config.gdb new file mode 100644 index 0000000..6bc827b --- /dev/null +++ b/src/assembly/pico/main/config.gdb @@ -0,0 +1,4 @@ +target remote localhost:3333 +monitor reset init +load +continue diff --git a/src/assembly/pico/main/debug.sh b/src/assembly/pico/main/debug.sh new file mode 100755 index 0000000..cc0e7b7 --- /dev/null +++ b/src/assembly/pico/main/debug.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +gdb build/bin/Pico/main.elf -x config.gdb diff --git a/src/assembly/pico/main/env.py b/src/assembly/pico/main/env.py new file mode 100644 index 0000000..d9cba61 --- /dev/null +++ b/src/assembly/pico/main/env.py @@ -0,0 +1 @@ +from environments import pico # noqa: F401 diff --git a/src/assembly/pico/main/hydra/.gitignore b/src/assembly/pico/main/hydra/.gitignore new file mode 100644 index 0000000..7ab074f --- /dev/null +++ b/src/assembly/pico/main/hydra/.gitignore @@ -0,0 +1,2 @@ +Rundirs +Pages diff --git a/src/assembly/pico/main/hydra/Config/.gitkeep b/src/assembly/pico/main/hydra/Config/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/assembly/pico/main/hydra/Config/hardware.xml b/src/assembly/pico/main/hydra/Config/hardware.xml new file mode 100644 index 0000000..8caf5ec --- /dev/null +++ b/src/assembly/pico/main/hydra/Config/hardware.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/src/assembly/pico/main/hydra/Config/readers.xml b/src/assembly/pico/main/hydra/Config/readers.xml new file mode 100644 index 0000000..5cf2bbe --- /dev/null +++ b/src/assembly/pico/main/hydra/Config/readers.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assembly/pico/main/hydra/Config/serial_types.xml b/src/assembly/pico/main/hydra/Config/serial_types.xml new file mode 100644 index 0000000..4da4e50 --- /dev/null +++ b/src/assembly/pico/main/hydra/Config/serial_types.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assembly/pico/main/hydra/Config/uplink_decoders.xml b/src/assembly/pico/main/hydra/Config/uplink_decoders.xml new file mode 100644 index 0000000..5600ee7 --- /dev/null +++ b/src/assembly/pico/main/hydra/Config/uplink_decoders.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/assembly/pico/main/hydra/Files/.gitkeep b/src/assembly/pico/main/hydra/Files/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/assembly/pico/main/hydra/Menus/.gitkeep b/src/assembly/pico/main/hydra/Menus/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/assembly/pico/main/hydra/Scripts/.gitkeep b/src/assembly/pico/main/hydra/Scripts/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/assembly/pico/main/hydra/Scripts/setup.prc b/src/assembly/pico/main/hydra/Scripts/setup.prc new file mode 100644 index 0000000..73f4609 --- /dev/null +++ b/src/assembly/pico/main/hydra/Scripts/setup.prc @@ -0,0 +1,14 @@ +; This script handles setting some default values during startup +; that are specific to the Example mission: + +echo "Setting up Hydra for the Example Assembly." + +; Set the CCSDS Header: +set Ccsds_Ground_Command_Header-Ccsds_Primary_Header-Apid = 7 +set Ccsds_Ground_Command_Header-Ccsds_Primary_Header-Packet_Type = 1 +set Ccsds_Ground_Command_Header-Ccsds_Primary_Header-Secondary_Header = 1 + +; Send the NOOP command to the assembly to make sure things are working +command_Router_Instance-Noop + +echo "Setup complete." diff --git a/src/assembly/pico/main/hydra/hydra_config.xml b/src/assembly/pico/main/hydra/hydra_config.xml new file mode 100644 index 0000000..a20cea3 --- /dev/null +++ b/src/assembly/pico/main/hydra/hydra_config.xml @@ -0,0 +1,22 @@ + + +./Config/hardware.xml + +../../../../../../adamant/gnd/hydra/Config/adamant_types.xml + +../../build/hydra/Config/pico_example.xml +../../build/hydra/Config/pico_example_ccsds_commands.xml +../../build/hydra/Config/pico_example_ccsds_packets.xml + +./Config/uplink_decoders.xml + +../../../../../gnd/hydra/Config/downlink_decoders.xml +./Config/serial_types.xml +./Config/readers.xml + + + + + + + diff --git a/src/assembly/pico/main/hydra/init.prc b/src/assembly/pico/main/hydra/init.prc new file mode 100644 index 0000000..d2bda14 --- /dev/null +++ b/src/assembly/pico/main/hydra/init.prc @@ -0,0 +1,7 @@ +; This script runs at startup automatically + +; Run the autocoded generate packet pages script to set up all the pages for packets in the assembly +start pico_example_packet_pages + +; Run the setup script +start setup diff --git a/src/assembly/pico/main/hydra_config.do b/src/assembly/pico/main/hydra_config.do new file mode 100644 index 0000000..c77d49e --- /dev/null +++ b/src/assembly/pico/main/hydra_config.do @@ -0,0 +1,8 @@ +# Start Hydra: +export TARGET=Pico +this_dir=`dirname "$0"` +hydra_dir=`realpath $this_dir/../../../../gnd/hydra` +config_file=$this_dir/hydra/hydra_config.xml +assembly_dir=`realpath $this_dir/..` +assembly_file=`ls $assembly_dir'/'*'.assembly.yaml' | head -1` +$hydra_dir/build_hydra_config.sh $assembly_file $config_file >/dev/null diff --git a/src/assembly/pico/main/img/copy_uf2.png b/src/assembly/pico/main/img/copy_uf2.png new file mode 100644 index 0000000..dfe087f Binary files /dev/null and b/src/assembly/pico/main/img/copy_uf2.png differ diff --git a/src/assembly/pico/main/img/hydra.jpg b/src/assembly/pico/main/img/hydra.jpg new file mode 100644 index 0000000..fe998a2 Binary files /dev/null and b/src/assembly/pico/main/img/hydra.jpg differ diff --git a/src/assembly/pico/main/img/hydra.png b/src/assembly/pico/main/img/hydra.png new file mode 100644 index 0000000..3950be8 Binary files /dev/null and b/src/assembly/pico/main/img/hydra.png differ diff --git a/src/assembly/pico/main/img/pico.jpg b/src/assembly/pico/main/img/pico.jpg new file mode 100644 index 0000000..a5562d7 Binary files /dev/null and b/src/assembly/pico/main/img/pico.jpg differ diff --git a/src/assembly/pico/main/img/pico_probe.jpg b/src/assembly/pico/main/img/pico_probe.jpg new file mode 100644 index 0000000..34a848f Binary files /dev/null and b/src/assembly/pico/main/img/pico_probe.jpg differ diff --git a/src/assembly/pico/main/img/pico_usb.jpg b/src/assembly/pico/main/img/pico_usb.jpg new file mode 100644 index 0000000..3e35205 Binary files /dev/null and b/src/assembly/pico/main/img/pico_usb.jpg differ diff --git a/src/assembly/pico/main/main.adb b/src/assembly/pico/main/main.adb new file mode 100644 index 0000000..eff9953 --- /dev/null +++ b/src/assembly/pico/main/main.adb @@ -0,0 +1,55 @@ +with Ada.Real_Time; use Ada.Real_Time; +with Pico_Example; +with Pico; +-- with RP.GPIO; use RP.GPIO; +with RP.Clock; +with Pico_Uart; +with Last_Chance_Handler; +pragma Unreferenced (Last_Chance_Handler); + +procedure Main is + Wait_Time : constant Ada.Real_Time.Time_Span := Ada.Real_Time.Microseconds (1000000); + Start_Time : constant Ada.Real_Time.Time := Ada.Real_Time.Clock + Wait_Time; +begin + -- Initialize the Pico internal clock: + RP.Clock.Initialize (Pico.XOSC_Frequency); + RP.Clock.Enable (RP.Clock.PERI); + + -- Initialize the UART. This needs to be done + -- after clock initialization, so cannot be done + -- at elaboration time: + Pico_Uart.Initialize; + + -- Initialize the LED: + -- RP.GPIO.Enable; + -- Pico.LED.Configure (RP.GPIO.Output); + -- Pico.LED.Set; + + -- Initialize the UART: + -- Pico_Uart.Put_Line ("Starting..."); + + -- Set up the assembly: + -- Pico_Uart.Put_Line ("Init_Base"); + Pico_Example.Init_Base; + -- Pico_Uart.Put_Line ("Set_Id_Bases"); + Pico_Example.Set_Id_Bases; + -- Pico_Uart.Put_Line ("Connect_Components"); + Pico_Example.Connect_Components; + -- Pico_Uart.Put_Line ("Init_Components"); + Pico_Example.Init_Components; + + -- Start the assembly: + -- Pico_Uart.Put_Line ("delaying..."); + delay until Start_Time; + -- Pico_Uart.Put_Line ("Start_Components"); + Pico_Example.Start_Components; + -- Pico_Uart.Put_Line ("Set_Up_Components"); + Pico_Example.Set_Up_Components; + + -- Loop forever: + loop + delay until Clock + Milliseconds (500); + -- Pico.LED.Toggle; + -- Pico_Uart.Put_Line ("looping..."); + end loop; +end Main; diff --git a/src/assembly/pico/main/program.sh b/src/assembly/pico/main/program.sh new file mode 100755 index 0000000..fde0ef8 --- /dev/null +++ b/src/assembly/pico/main/program.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +openocd -f interface/cmsis-dap.cfg -f target/rp2040.cfg -c "adapter speed 5000" -c "program build/bin/Pico/main.elf verify reset exit" diff --git a/src/assembly/pico/main/start_openocd.sh b/src/assembly/pico/main/start_openocd.sh new file mode 100755 index 0000000..5290847 --- /dev/null +++ b/src/assembly/pico/main/start_openocd.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +openocd -f interface/cmsis-dap.cfg -f target/rp2040.cfg -c "adapter speed 5000" diff --git a/src/assembly/pico/pico_example.assembly.yaml b/src/assembly/pico/pico_example.assembly.yaml new file mode 100644 index 0000000..832b8ab --- /dev/null +++ b/src/assembly/pico/pico_example.assembly.yaml @@ -0,0 +1,856 @@ +--- +description: This example assembly is designed to run on the Raspberry Pi Pico. It includes a small collection of components that demonstrate how Adamant can be deployed onto a bare metal embedded system. In particular, the assembly demonstrates a simple rate group system, commanding, telemetry reporting using events, data products, and packets, and a simple fault detection and correction scheme. Explore the tables and diagrams below to learn more about the design of the example assembly. +with: + - System + # - Ada.Interrupts.Names + - Pico_Example_Product_Packets + - Pico_Example_Commands + - Pico_Example_Events + - Pico_Example_Data_Products + # - Tick_Interrupt_Handler + - Pico_Example_Task_Watchdog_List + - Pico_Example_Fault_Responses + - Ccsds_Space_Packet +preamble: | + Dividers : aliased Component.Tick_Divider.Divider_Array_Type := (1 => 5, 2 => 10, 3 => 1); +######################################## +components: +######################################## +######################################## +# System time: +######################################## + - type: Gps_Time + name: System_Time_Instance + description: This component provides the system time for the assembly. +######################################## +# Rate group system: +######################################## + - type: Ticker + description: This component uses a periodic signal to drive the assembly rate groups. + priority: 10 + stack_size: 2000 + secondary_stack_size: 100 + discriminant: + - "Period_Us => 200000" # 1/5 second period + - type: Tick_Divider + description: This component divides a periodic signal into intervals suitable for the assembly rate groups. + init_base: + - "Tick_T_Send_Count => 3" + init: + - "Dividers => Dividers'Access" + - type: Rate_Group + name: Slow_Rate_Group + description: This component provides a 0.5 Hz task for other components to execute on periodically. + priority: 9 + stack_size: 15000 + secondary_stack_size: 100 + init_base: + - "Queue_Size => 3 * Slow_Rate_Group.Get_Max_Queue_Element_Size" + - "Tick_T_Send_Count => 8" + init: + - "Ticks_Per_Timing_Report => 10" + - type: Rate_Group + name: Fast_Rate_Group + description: This component provides a 5 Hz task for other components to execute on periodically. + priority: 9 + stack_size: 10000 + secondary_stack_size: 100 + init_base: + - "Queue_Size => 3 * Fast_Rate_Group.Get_Max_Queue_Element_Size" + - "Tick_T_Send_Count => 3" + init: + - "Ticks_Per_Timing_Report => 400" + - type: Rate_Group + name: Watchdog_Rate_Group + description: This component provides a 1 Hz task for the watchdog components to execute on periodically. + priority: 10 + stack_size: 3000 + secondary_stack_size: 100 + init_base: + - "Queue_Size => 3 * Watchdog_Rate_Group.Get_Max_Queue_Element_Size" + - "Tick_T_Send_Count => 1" + init: + - "Ticks_Per_Timing_Report => 400" +######################################## +# Command system: +######################################## + - type: Ccsds_Command_Depacketizer + description: This component converts CCSDS packets containing commands to valid Adamant formatted command types. + - type: Command_Router + description: This component provides command and command response routing throughout the assembly. + priority: 8 + stack_size: 5000 + secondary_stack_size: 100 + init_base: + - "Queue_Size => 5 * Command_Router_Instance.Get_Max_Queue_Element_Size" + - "Command_T_Send_Count => 17" + - "Command_Response_T_To_Forward_Send_Count => 1" + init: + - "Max_Number_Of_Commands => Pico_Example_Commands.Number_Of_Commands" +######################################## +# Event system: +######################################## + - type: Event_Filter + description: This component filters events by ID. + init: + - "Event_Id_Start_Range => Pico_Example_Events.Minimum_Event_Id" + - "Event_Id_End_Range => Pico_Example_Events.Maximum_Event_Id" + - type: Event_Limiter + description: This component filters out events that spam the system too frequently. + init: + - "Event_Id_Start => Pico_Example_Events.Minimum_Event_Id" + - "Event_Id_Stop => Pico_Example_Events.Maximum_Event_Id" + - "Event_Limit_Persistence => 5" + - "Event_Disable_List => (0 => Pico_Example_Events.Ccsds_Serial_Interface_Instance_Have_Not_Seen_Sync_Pattern)" + - type: Event_Packetizer + description: This component gathers events and packetizes them for downlink. + init: + - "Num_Internal_Packets => 5" + - "Partial_Packet_Timeout => 1" + set_id_bases: + - "Packet_Id_Base => 98" +######################################## +# Telemetry system: +######################################## + - type: Product_Database + description: This component serves as the database for data products throughout the system. + init: + - "Minimum_Data_Product_Id => Pico_Example_Data_Products.Minimum_Data_Product_Id" + - "Maximum_Data_Product_Id => Pico_Example_Data_Products.Maximum_Data_Product_Id" + - "Send_Event_On_Missing => False" + - type: Product_Packetizer + description: This component periodically fetches values from the Product Database and packetizes them for downlink. + init_base: + - "Queue_Size => 3 * Product_Packetizer_Instance.Get_Max_Queue_Element_Size" + discriminant: + - "packet_List => Pico_Example_Product_Packets.Packet_List'Access" + init: + - type: Ccsds_Packetizer + description: This component converts Adamant formatted packets to CCSDS for downlink. + - type: Ccsds_Serial_Interface + description: This component manages the Raspberry Pi Pico UART interface for command uplink and telemetry downlink. + priority: 1 + stack_size: 2000 + secondary_stack_size: 100 + init_base: + - "Queue_Size => 4 * Ccsds_Space_Packet.Size_In_Bytes" + subtasks: + - name: Listener + # This MUST be the lowest priority task as it spins on the + # UART without sleeping. + priority: 0 + stack_size: 2000 + secondary_stack_size: 100 + disabled: False +######################################## +# Interrupt system: +######################################## +# - type: Interrupt_Servicer +# description: This component handles and interrupt and passes it along to the assembly. +# priority: 1 +# stack_size: 4000 +# secondary_stack_size: 100 +# generic_types: +# - "Interrupt_Data_Type => Tick.T" +# - "Set_Interrupt_Data_Time => Tick_Interrupt_Handler.Set_Tick_Time" +# discriminant: +# - "Interrupt_Priority => System.Interrupt_Priority'Last" +# - "Interrupt_Id => Ada.Interrupts.Names.IO_IRQ_BANK0_Interrupt_CPU_1" +# - "Custom_Interrupt_Procedure => Tick_Interrupt_Handler.Handler'Access" +# - type: Interrupt_Responder +# description: This component responds to an interrupt. +######################################## +# Example assembly "mission" components: +######################################## + - type: Counter + description: This component periodically produces a count data product. + set_id_bases: + - "Command_Id_Base => 99" + init_base: + - "Queue_Size => 3 * Counter_Instance.Get_Max_Queue_Element_Size" + - type: Oscillator + name: Oscillator_A + description: This component periodically produces an oscillating data product. + init_base: + - "Queue_Size => 3 * Oscillator_A.Get_Max_Queue_Element_Size" + - type: Oscillator + name: Oscillator_B + description: This component periodically produces an oscillating data product. + init_base: + - "Queue_Size => 3 * Oscillator_B.Get_Max_Queue_Element_Size" + - type: Adc_Data_Collector + description: This component collects data from the internal Raspberry Pi Pico analog to digital converted (ADC) and reports it as telemetry. +######################################## +# Fault protection system: +######################################## + - type: Zero_Divider + description: This component responds to a command that divides by zero if received. This can be used to trigger a fault condition within the processor. + init: + - "Magic_Number => 16#DEADBEEF#" + - "Sleep_Before_Divide_Ms => 2200" # Give time for event to come out on 2s rate group + set_id_bases: + - "Packet_Id_Base => 97" + - type: Task_Watchdog + description: This component monitors other critical active components (tasks) within the assembly to make sure they continue to run. + init_base: + - "Pet_T_Recv_Sync_Count => 2" + init: + - "Task_Watchdog_Entry_Init_List => Pico_Example_Task_Watchdog_List.Task_Watchdog_Entry_Init_List" + - type: Fault_Producer + description: This component can be used to induce a fault into the system by command. + - type: Fault_Correction + description: This component produces a corrective action (a command) for any fault that is thrown in the system. + priority: 11 + stack_size: 4000 + secondary_stack_size: 100 + init_base: + - "Queue_Size => 3 * Fault_Correction_Instance.Get_Max_Queue_Element_Size" + init: + - "Fault_Response_Configurations => Pico_Example_Fault_Responses.Fault_Response_List" +######################################## +# FSW monitoring system: +######################################## + - type: Cpu_Monitor + description: This component produces a packet that includes the CPU usage percentage for each task and interrupt in the system. + init: + - "Task_List => Task_List'Access" + - "Interrupt_List => Interrupt_List'Access" + - type: Queue_Monitor + description: This component produces a packet that includes the current and maximum queue usage for each component in the system. + init: + - "Queued_Component_List => Queued_Component_List'Access" + - type: Stack_Monitor + description: This component produces a packet that includes the maximum stack and secondary stack usage for each component in the system. + init: + - "Task_List => Task_List'Access" + - "Packet_Period => 1" +######################################## +connections: +######################################## + # Time Connections: + - from_component: Ticker_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Tick_Divider_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Slow_Rate_Group + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Fast_Rate_Group + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Watchdog_Rate_Group + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Command_Router_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Counter_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Oscillator_A + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Oscillator_B + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + # - from_component: Interrupt_Servicer_Instance + # from_connector: Sys_Time_T_Get + # to_component: System_Time_Instance + # to_connector: Sys_Time_T_Return + # - from_component: Interrupt_Responder_Instance + # from_connector: Sys_Time_T_Get + # to_component: System_Time_Instance + # to_connector: Sys_Time_T_Return + - from_component: Event_Packetizer_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Product_Database_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Product_Packetizer_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Ccsds_Command_Depacketizer_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Cpu_Monitor_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Stack_Monitor_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Queue_Monitor_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Event_Filter_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Event_Limiter_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Zero_Divider_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Task_Watchdog_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Fault_Correction_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Fault_Producer_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Ccsds_Serial_Interface_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + - from_component: Adc_Data_Collector_Instance + from_connector: Sys_Time_T_Get + to_component: System_Time_Instance + to_connector: Sys_Time_T_Return + # Rate Group Connections: + - from_component: Ticker_Instance + from_connector: Tick_T_Send + to_component: Tick_Divider_Instance + to_connector: Tick_T_Recv_Sync + - from_component: Tick_Divider_Instance + from_connector: Tick_T_Send + from_index: 1 + to_component: Watchdog_Rate_Group + to_connector: Tick_T_Recv_Async + - from_component: Tick_Divider_Instance + from_connector: Tick_T_Send + from_index: 2 + to_component: Slow_Rate_Group + to_connector: Tick_T_Recv_Async + - from_component: Tick_Divider_Instance + from_connector: Tick_T_Send + from_index: 3 + to_component: Fast_Rate_Group + to_connector: Tick_T_Recv_Async + - description: Schedule connection from the rate group to the counter + from_component: Slow_Rate_Group + from_connector: Tick_T_Send + from_index: 1 + to_component: Counter_Instance + to_connector: Tick_T_Recv_Sync + - description: Schedule connection from the rate group to the packetizer + from_component: Slow_Rate_Group + from_connector: Tick_T_Send + from_index: 2 + to_component: Event_Packetizer_Instance + to_connector: Tick_T_Recv_Sync + - from_component: Slow_Rate_Group + from_connector: Tick_T_Send + from_index: 3 + to_component: Cpu_Monitor_Instance + to_connector: Tick_T_Recv_Sync + - from_component: Slow_Rate_Group + from_connector: Tick_T_Send + from_index: 4 + to_component: Queue_Monitor_Instance + to_connector: Tick_T_Recv_Sync + - from_component: Slow_Rate_Group + from_connector: Tick_T_Send + from_index: 5 + to_component: Stack_Monitor_Instance + to_connector: Tick_T_Recv_Sync + - from_component: Slow_Rate_Group + from_connector: Tick_T_Send + from_index: 6 + to_component: Event_Filter_Instance + to_connector: Tick_T_Recv_Sync + - from_component: Slow_Rate_Group + from_connector: Tick_T_Send + from_index: 7 + to_component: Event_Limiter_Instance + to_connector: Tick_T_Recv_Sync + - from_component: Slow_Rate_Group + from_connector: Tick_T_Send + from_index: 8 + to_component: Adc_Data_Collector_Instance + to_connector: Tick_T_Recv_Sync + - description: Schedule connection from the rate group to the oscillator + from_component: Fast_Rate_Group + from_connector: Tick_T_Send + from_index: 1 + to_component: Oscillator_A + to_connector: Tick_T_Recv_Sync + - description: Schedule connection from the rate group to the oscillator + from_component: Fast_Rate_Group + from_connector: Tick_T_Send + from_index: 2 + to_component: Oscillator_B + to_connector: Tick_T_Recv_Sync + - description: Schedule connection from the rate group to the packetizer + from_component: Fast_Rate_Group + from_connector: Tick_T_Send + from_index: 3 + to_component: Product_Packetizer_Instance + to_connector: Tick_T_Recv_Sync + - from_component: Watchdog_Rate_Group + from_connector: Tick_T_Send + from_index: 1 + to_component: Task_Watchdog_Instance + to_connector: Tick_T_Recv_Sync + # Event Connections: + - from_component: Tick_Divider_Instance + from_connector: Event_T_Send + to_component: Event_Filter_Instance + to_connector: Event_T_Recv_Sync + - from_component: Slow_Rate_Group + from_connector: Event_T_Send + to_component: Event_Filter_Instance + to_connector: Event_T_Recv_Sync + - from_component: Fast_Rate_Group + from_connector: Event_T_Send + to_component: Event_Filter_Instance + to_connector: Event_T_Recv_Sync + - from_component: Watchdog_Rate_Group + from_connector: Event_T_Send + to_component: Event_Filter_Instance + to_connector: Event_T_Recv_Sync + - from_component: Command_Router_Instance + from_connector: Event_T_Send + to_component: Event_Filter_Instance + to_connector: Event_T_Recv_Sync + - from_component: Counter_Instance + from_connector: Event_T_Send + to_component: Event_Filter_Instance + to_connector: Event_T_Recv_Sync + - from_component: Oscillator_A + from_connector: Event_T_Send + to_component: Event_Filter_Instance + to_connector: Event_T_Recv_Sync + - from_component: Oscillator_B + from_connector: Event_T_Send + to_component: Event_Filter_Instance + to_connector: Event_T_Recv_Sync + - from_component: Product_Packetizer_Instance + from_connector: Event_T_Send + to_component: Event_Filter_Instance + to_connector: Event_T_Recv_Sync + - from_component: Stack_Monitor_Instance + from_connector: Event_T_Send + to_component: Event_Filter_Instance + to_connector: Event_T_Recv_Sync + - from_component: Queue_Monitor_Instance + from_connector: Event_T_Send + to_component: Event_Filter_Instance + to_connector: Event_T_Recv_Sync + - from_component: Cpu_Monitor_Instance + from_connector: Event_T_Send + to_component: Event_Filter_Instance + to_connector: Event_T_Recv_Sync + - from_component: Event_Filter_Instance + from_connector: Event_T_Send + to_component: Event_Filter_Instance + to_connector: Event_T_Recv_Sync + - from_component: Event_Limiter_Instance + from_connector: Event_T_Send + to_component: Event_Filter_Instance + to_connector: Event_T_Recv_Sync + - from_component: Zero_Divider_Instance + from_connector: Event_T_Send + to_component: Event_Filter_Instance + to_connector: Event_T_Recv_Sync + - from_component: Task_Watchdog_Instance + from_connector: Event_T_Send + to_component: Event_Filter_Instance + to_connector: Event_T_Recv_Sync + - from_component: Fault_Correction_Instance + from_connector: Event_T_Send + to_component: Event_Filter_Instance + to_connector: Event_T_Recv_Sync + - from_component: Ccsds_Serial_Interface_Instance + from_connector: Event_T_Send + to_component: Event_Filter_Instance + to_connector: Event_T_Recv_Sync + - from_component: Event_Filter_Instance + from_connector: Event_Forward_T_Send + to_component: Event_Limiter_Instance + to_connector: Event_T_Recv_Sync + - from_component: Event_Limiter_Instance + from_connector: Event_Forward_T_Send + to_component: Event_Packetizer_Instance + to_connector: Event_T_Recv_Sync + # - from_component: Interrupt_Responder_Instance + # from_connector: Event_T_Send + # to_component: Event_Filter_Instance + # to_connector: Event_T_Recv_Sync + - from_component: Product_Database_Instance + from_connector: Event_T_Send + to_component: Event_Filter_Instance + to_connector: Event_T_Recv_Sync + - from_component: Ccsds_Command_Depacketizer_Instance + from_connector: Event_T_Send + to_component: Event_Filter_Instance + to_connector: Event_T_Recv_Sync + - from_component: Fault_Producer_Instance + from_connector: Event_T_Send + to_component: Event_Filter_Instance + to_connector: Event_T_Recv_Sync + # Command Response: + - from_component: Command_Router_Instance + from_connector: Command_Response_T_Send + to_component: Command_Router_Instance + to_connector: Command_Response_T_Recv_Async + - from_component: Counter_Instance + from_connector: Command_Response_T_Send + to_component: Command_Router_Instance + to_connector: Command_Response_T_Recv_Async + - from_component: Oscillator_A + from_connector: Command_Response_T_Send + to_component: Command_Router_Instance + to_connector: Command_Response_T_Recv_Async + - from_component: Oscillator_B + from_connector: Command_Response_T_Send + to_component: Command_Router_Instance + to_connector: Command_Response_T_Recv_Async + - from_component: Product_Packetizer_Instance + from_connector: Command_Response_T_Send + to_component: Command_Router_Instance + to_connector: Command_Response_T_Recv_Async + - from_component: Event_Packetizer_Instance + from_connector: Command_Response_T_Send + to_component: Command_Router_Instance + to_connector: Command_Response_T_Recv_Async + - from_component: Ccsds_Command_Depacketizer_Instance + from_connector: Command_Response_T_Send + to_component: Command_Router_Instance + to_connector: Command_Response_T_Recv_Async + - from_component: Product_Database_Instance + from_connector: Command_Response_T_Send + to_component: Command_Router_Instance + to_connector: Command_Response_T_Recv_Async + - from_component: Stack_Monitor_Instance + from_connector: Command_Response_T_Send + to_component: Command_Router_Instance + to_connector: Command_Response_T_Recv_Async + - from_component: Queue_Monitor_Instance + from_connector: Command_Response_T_Send + to_component: Command_Router_Instance + to_connector: Command_Response_T_Recv_Async + - from_component: Cpu_Monitor_Instance + from_connector: Command_Response_T_Send + to_component: Command_Router_Instance + to_connector: Command_Response_T_Recv_Async + - from_component: Event_Filter_Instance + from_connector: Command_Response_T_Send + to_component: Command_Router_Instance + to_connector: Command_Response_T_Recv_Async + - from_component: Event_Limiter_Instance + from_connector: Command_Response_T_Send + to_component: Command_Router_Instance + to_connector: Command_Response_T_Recv_Async + - from_component: Task_Watchdog_Instance + from_connector: Command_Response_T_Send + to_component: Command_Router_Instance + to_connector: Command_Response_T_Recv_Async + - from_component: Fault_Correction_Instance + from_connector: Command_Response_T_Send + to_component: Command_Router_Instance + to_connector: Command_Response_T_Recv_Async + - from_component: Zero_Divider_Instance + from_connector: Command_Response_T_Send + to_component: Command_Router_Instance + to_connector: Command_Response_T_Recv_Async + - from_component: Fault_Producer_Instance + from_connector: Command_Response_T_Send + to_component: Command_Router_Instance + to_connector: Command_Response_T_Recv_Async + # Command Routing: + - from_component: Ccsds_Command_Depacketizer_Instance + from_connector: Command_T_Send + to_component: Command_Router_Instance + to_connector: Command_T_To_Route_Recv_Async + - from_component: Command_Router_Instance + from_connector: Command_T_Send + from_index: 1 + to_component: Command_Router_Instance + to_connector: Command_T_Recv_Async + - from_component: Command_Router_Instance + from_connector: Command_T_Send + from_index: 2 + to_component: Counter_Instance + to_connector: Command_T_Recv_Async + - from_component: Command_Router_Instance + from_connector: Command_T_Send + from_index: 3 + to_component: Oscillator_A + to_connector: Command_T_Recv_Async + - from_component: Command_Router_Instance + from_connector: Command_T_Send + from_index: 4 + to_component: Oscillator_B + to_connector: Command_T_Recv_Async + - from_component: Command_Router_Instance + from_connector: Command_T_Send + from_index: 5 + to_component: Product_Packetizer_Instance + to_connector: Command_T_Recv_Async + - from_component: Command_Router_Instance + from_connector: Command_T_Send + from_index: 6 + to_component: Event_Packetizer_Instance + to_connector: Command_T_Recv_Sync + - from_component: Command_Router_Instance + from_connector: Command_T_Send + from_index: 7 + to_component: Product_Database_Instance + to_connector: Command_T_Recv_Sync + - from_component: Command_Router_Instance + from_connector: Command_T_Send + from_index: 8 + to_component: Ccsds_Command_Depacketizer_Instance + to_connector: Command_T_Recv_Sync + - from_component: Command_Router_Instance + from_connector: Command_T_Send + from_index: 9 + to_component: Stack_Monitor_Instance + to_connector: Command_T_Recv_Sync + - from_component: Command_Router_Instance + from_connector: Command_T_Send + from_index: 10 + to_component: Queue_Monitor_Instance + to_connector: Command_T_Recv_Sync + - from_component: Command_Router_Instance + from_connector: Command_T_Send + from_index: 11 + to_component: Cpu_Monitor_Instance + to_connector: Command_T_Recv_Sync + - from_component: Command_Router_Instance + from_connector: Command_T_Send + from_index: 12 + to_component: Event_Filter_Instance + to_connector: Command_T_Recv_Sync + - from_component: Command_Router_Instance + from_connector: Command_T_Send + from_index: 13 + to_component: Event_Limiter_Instance + to_connector: Command_T_Recv_Sync + - from_component: Command_Router_Instance + from_connector: Command_T_Send + from_index: 14 + to_component: Zero_Divider_Instance + to_connector: Command_T_Recv_Sync + - from_component: Command_Router_Instance + from_connector: Command_T_Send + from_index: 15 + to_component: Fault_Correction_Instance + to_connector: Command_T_Recv_Async + - from_component: Command_Router_Instance + from_connector: Command_T_Send + from_index: 16 + to_component: Task_Watchdog_Instance + to_connector: Command_T_Recv_Sync + - from_component: Command_Router_Instance + from_connector: Command_T_Send + from_index: 17 + to_component: Fault_Producer_Instance + to_connector: Command_T_Recv_Sync + # Command Response Forwarding: + - from_component: Command_Router_Instance + from_connector: Command_Response_T_To_Forward_Send + from_index: 1 + to_component: Command_Router_Instance + to_connector: Command_Response_T_Recv_Async # Forward the first command response back to the router for noop test + # Data Product Connections: + - description: Data product connection between the oscillator and packetizer + from_component: Oscillator_A + from_connector: Data_Product_T_Send + to_component: Product_Database_Instance + to_connector: Data_Product_T_Recv_Sync + - description: Data product connection between the oscillator and packetizer + from_component: Oscillator_B + from_connector: Data_Product_T_Send + to_component: Product_Database_Instance + to_connector: Data_Product_T_Recv_Sync + - from_component: Event_Packetizer_Instance + from_connector: Data_Product_T_Send + to_component: Product_Database_Instance + to_connector: Data_Product_T_Recv_Sync + - from_component: Ccsds_Command_Depacketizer_Instance + from_connector: Data_Product_T_Send + to_component: Product_Database_Instance + to_connector: Data_Product_T_Recv_Sync + - from_component: Slow_Rate_Group + from_connector: Data_Product_T_Send + to_component: Product_Database_Instance + to_connector: Data_Product_T_Recv_Sync + - from_component: Fast_Rate_Group + from_connector: Data_Product_T_Send + to_component: Product_Database_Instance + to_connector: Data_Product_T_Recv_Sync + - from_component: Watchdog_Rate_Group + from_connector: Data_Product_T_Send + to_component: Product_Database_Instance + to_connector: Data_Product_T_Recv_Sync + - from_component: Command_Router_Instance + from_connector: Data_Product_T_Send + to_component: Product_Database_Instance + to_connector: Data_Product_T_Recv_Sync + - from_component: Product_Database_Instance + from_connector: Data_Product_T_Send + to_component: Product_Database_Instance + to_connector: Data_Product_T_Recv_Sync + - from_component: Stack_Monitor_Instance + from_connector: Data_Product_T_Send + to_component: Product_Database_Instance + to_connector: Data_Product_T_Recv_Sync + - from_component: Queue_Monitor_Instance + from_connector: Data_Product_T_Send + to_component: Product_Database_Instance + to_connector: Data_Product_T_Recv_Sync + - from_component: Cpu_Monitor_Instance + from_connector: Data_Product_T_Send + to_component: Product_Database_Instance + to_connector: Data_Product_T_Recv_Sync + - from_component: Event_Filter_Instance + from_connector: Data_Product_T_Send + to_component: Product_Database_Instance + to_connector: Data_Product_T_Recv_Sync + - from_component: Event_Limiter_Instance + from_connector: Data_Product_T_Send + to_component: Product_Database_Instance + to_connector: Data_Product_T_Recv_Sync + - from_component: Task_Watchdog_Instance + from_connector: Data_Product_T_Send + to_component: Product_Database_Instance + to_connector: Data_Product_T_Recv_Sync + - from_component: Fault_Correction_Instance + from_connector: Data_Product_T_Send + to_component: Product_Database_Instance + to_connector: Data_Product_T_Recv_Sync + - from_component: Adc_Data_Collector_Instance + from_connector: Data_Product_T_Send + to_component: Product_Database_Instance + to_connector: Data_Product_T_Recv_Sync + # Packetizer Connections: + - from_component: Product_Packetizer_Instance + from_connector: Data_Product_Fetch_T_Request + to_component: Product_Database_Instance + to_connector: Data_Product_Fetch_T_Service + # Interrupt Connections: + # - from_component: Interrupt_Servicer_Instance + # from_connector: Interrupt_Data_Type_Send + # to_component: Interrupt_Responder_Instance + # to_connector: Tick_T_Recv_Sync + # Downlink connections: + - from_component: Event_Packetizer_Instance + from_connector: Packet_T_Send + to_component: Ccsds_Packetizer_Instance + to_connector: Packet_T_Recv_Sync + - from_component: Product_Packetizer_Instance + from_connector: Packet_T_Send + to_component: Ccsds_Packetizer_Instance + to_connector: Packet_T_Recv_Sync + - from_component: Counter_Instance + from_connector: Packet_T_Send + to_component: Ccsds_Packetizer_Instance + to_connector: Packet_T_Recv_Sync + - from_component: Ccsds_Command_Depacketizer_Instance + from_connector: Packet_T_Send + to_component: Ccsds_Packetizer_Instance + to_connector: Packet_T_Recv_Sync + - from_component: Product_Database_Instance + from_connector: Packet_T_Send + to_component: Ccsds_Packetizer_Instance + to_connector: Packet_T_Recv_Sync + - from_component: Cpu_Monitor_Instance + from_connector: Packet_T_Send + to_component: Ccsds_Packetizer_Instance + to_connector: Packet_T_Recv_Sync + - from_component: Queue_Monitor_Instance + from_connector: Packet_T_Send + to_component: Ccsds_Packetizer_Instance + to_connector: Packet_T_Recv_Sync + - from_component: Stack_Monitor_Instance + from_connector: Packet_T_Send + to_component: Ccsds_Packetizer_Instance + to_connector: Packet_T_Recv_Sync + - from_component: Event_Filter_Instance + from_connector: Packet_T_Send + to_component: Ccsds_Packetizer_Instance + to_connector: Packet_T_Recv_Sync + - from_component: Event_Limiter_Instance + from_connector: Packet_T_Send + to_component: Ccsds_Packetizer_Instance + to_connector: Packet_T_Recv_Sync + # Task watchdog pet connections: + - from_component: Slow_Rate_Group + from_connector: Pet_T_Send + to_component: Task_Watchdog_Instance + to_connector: Pet_T_Recv_Sync + to_index: 1 + - from_component: Fast_Rate_Group + from_connector: Pet_T_Send + to_component: Task_Watchdog_Instance + to_connector: Pet_T_Recv_Sync + to_index: 2 + - description: The watchdog rate group is checked implicitly since it runs the task watchdog itself. + from_component: Watchdog_Rate_Group + from_connector: Pet_T_Send + to_component: ignore + to_connector: ignore + - description: This should be attached to a hardware watchdog on an embedded system. + from_component: Task_Watchdog_Instance + from_connector: Pet_T_Send + to_component: ignore + to_connector: ignore + # Fault connections: + - from_component: Task_Watchdog_Instance + from_connector: Fault_T_Send + to_component: Fault_Correction_Instance + to_connector: Fault_T_Recv_Async + - from_component: Fault_Producer_Instance + from_connector: Fault_T_Send + to_component: Fault_Correction_Instance + to_connector: Fault_T_Recv_Async + - description: We connect the fault correction command response to the command router synchronous connector for the fastest, most reliable execution. This bypasses the command router's queue. + from_component: Fault_Correction_Instance + from_connector: Command_T_Send + to_component: Command_Router_Instance + to_connector: Command_T_To_Route_Recv_Sync + # Serial connections: + - from_component: Ccsds_Packetizer_Instance + from_connector: Ccsds_Space_Packet_T_Send + to_component: Ccsds_Serial_Interface_Instance + to_connector: Ccsds_Space_Packet_T_Recv_Async + - from_component: Ccsds_Serial_Interface_Instance + from_connector: Ccsds_Space_Packet_T_Send + to_component: Ccsds_Command_Depacketizer_Instance + to_connector: Ccsds_Space_Packet_T_Recv_Sync + # Parameter connections not used in this assembly: + - from_component: ignore + from_connector: ignore + to_component: Oscillator_A + to_connector: Parameter_Update_T_Modify + - from_component: ignore + from_connector: ignore + to_component: Oscillator_B + to_connector: Parameter_Update_T_Modify diff --git a/src/assembly/pico/pico_example.fault_responses.yaml b/src/assembly/pico/pico_example.fault_responses.yaml new file mode 100644 index 0000000..026f061 --- /dev/null +++ b/src/assembly/pico/pico_example.fault_responses.yaml @@ -0,0 +1,27 @@ +--- +description: This is the fault response table for the Pico Example assembly. +fault_responses: + - fault: Task_Watchdog_Instance.Slow_Rate_Group_Fault + latching: True + startup_state: enabled + command_response: Command_Router_Instance.Noop_Arg + command_arg: (Value => 1) + description: Throw noop with value 1 if this fault occurs. + - fault: Task_Watchdog_Instance.Fast_Rate_Group_Fault + latching: True + startup_state: enabled + command_response: Command_Router_Instance.Noop_Arg + command_arg: (Value => 2) + description: Throw noop with value 2 if this fault occurs. + - fault: Fault_Producer_Instance.Fault_1 + latching: False + startup_state: enabled + command_response: Command_Router_Instance.Noop_Arg + command_arg: (Value => 3) + description: Throw noop with value 3 if this fault occurs. + - fault: Fault_Producer_Instance.Fault_2 + latching: False + startup_state: enabled + command_response: Command_Router_Instance.Noop_Arg + command_arg: (Value => 4) + description: Throw noop with value 4 if this fault occurs. diff --git a/src/assembly/pico/pico_example.product_packets.yaml b/src/assembly/pico/pico_example.product_packets.yaml new file mode 100644 index 0000000..04e8896 --- /dev/null +++ b/src/assembly/pico/pico_example.product_packets.yaml @@ -0,0 +1,15 @@ +--- +description: This is the set of packets for the data product packetizer in the Pico Example assembly. +packets: + - name: Housekeeping_Packet + description: This packet contains houskeeping data. + id: 1 + data_products: + - name: Oscillator_A.Oscillator_Value + use_timestamp: True + - name: Oscillator_B.Oscillator_Value + # Include all data products from ADC data collector in order. + - name: Adc_Data_Collector_Instance.Channel_0 + - name: Adc_Data_Collector_Instance.Vsys + - name: Adc_Data_Collector_Instance.Temperature + period: "1" # create every tick diff --git a/src/assembly/pico/pico_example.task_watchdog_list.yaml b/src/assembly/pico/pico_example.task_watchdog_list.yaml new file mode 100644 index 0000000..52b9d69 --- /dev/null +++ b/src/assembly/pico/pico_example.task_watchdog_list.yaml @@ -0,0 +1,20 @@ +--- +description: Configure the task watchdog for the Pico Example assembly. +petters: + - name: Slow_Rate_Group + connector_name: Slow_Rate_Group.Pet_T_Send + description: Slow rate group monitoring. + limit: 3 + action: error_fault + critical: False # Make True to stop servicing downstream HW watchdog + fault_id: 1 + - name: Fast_Rate_Group + connector_name: Fast_Rate_Group.Pet_T_Send + description: Fast rate group monitoring. + limit: 3 + action: error_fault + critical: False # Make True to stop servicing downstream HW watchdog + fault_id: 2 + # We don't need to monitor the Watchdog_Rate_Group since the + # task watchdog is on that rate group. That makes it a defacto critical + # task, which will stop petting the watchdog if it freezes up. diff --git a/src/assembly/pico/views/.Pico_path b/src/assembly/pico/views/.Pico_path new file mode 100644 index 0000000..e69de29 diff --git a/src/assembly/pico/views/README.md b/src/assembly/pico/views/README.md new file mode 100644 index 0000000..45587a7 --- /dev/null +++ b/src/assembly/pico/views/README.md @@ -0,0 +1,9 @@ +# Raspberry Pi Pico Example Views + +This directory contains views for the Raspberry Pi Pico assembly. To build them run: + +``` +$ redo +``` + +Assembly views will appear in `build/svg/`. Open any of the SVG files in a web browser to inspect them. diff --git a/src/assembly/pico/views/command.pico_example.view.yaml b/src/assembly/pico/views/command.pico_example.view.yaml new file mode 100644 index 0000000..97792d2 --- /dev/null +++ b/src/assembly/pico/views/command.pico_example.view.yaml @@ -0,0 +1,9 @@ +--- +description: This view shows how commands are routed throughout the assembly. Commands are contained in the Command.T data type. Commands coming from the ground system originate from the Ccsds_Command_Depacketizer_Instance and then get passed the Command_Router_Instance. The router looks at the command's ID, determines the destination component for which the command is intended, and then forwards the command to that appropriate destination component. When a destination component receives a command, it will execute it and pass a Command_Response.T data type back to the command router (shown in the Command Response View). Note that the Fault_Correction_Instance can also produce commands in order to correct a system fault. Commands from the Fault_Correction_Instance are passed to the router synchronously, bypassing the standard command queue that the Ccsds_Command_Depacketizer_Instance uses. +layout: left-to-right +filters: + - name: cmd_connections + type: connector_type + include: + - Command.T +postamble: "{ rank=source; Fault_Correction_Instance, Ccsds_Command_Depacketizer_Instance }" diff --git a/src/assembly/pico/views/command_response.pico_example.view.yaml b/src/assembly/pico/views/command_response.pico_example.view.yaml new file mode 100644 index 0000000..162a053 --- /dev/null +++ b/src/assembly/pico/views/command_response.pico_example.view.yaml @@ -0,0 +1,7 @@ +--- +description: After a component executes a command received from the Command_Router_Instance, it passes back a Command_Response.T type to the router letting it know if the command succeeded or failed. This connection is also used to register all the commands with the router an initialization. This allows the Command_Router_Instance to create the internal routing table that it uses to route incoming commands. +filters: + - name: reg_connections + type: connector_type + include: + - Command_Response.T diff --git a/src/assembly/pico/views/data_products.pico_example.view.yaml b/src/assembly/pico/views/data_products.pico_example.view.yaml new file mode 100644 index 0000000..936b63c --- /dev/null +++ b/src/assembly/pico/views/data_products.pico_example.view.yaml @@ -0,0 +1,7 @@ +--- +description: Any data product produced by a component during execution is sent synchronously to on onboard storage database, the Product_Database_Instance. This component stores the latest value and timestamp of each data product in the system. Other components, such as the Product_Packetizer_Instance can then fetch these data products at a later time for limit checking, packetization, etc. +filters: + - name: dp_connections + type: connector_type + include: + - Data_Product.T diff --git a/src/assembly/pico/views/downlink.pico_example.view.yaml b/src/assembly/pico/views/downlink.pico_example.view.yaml new file mode 100644 index 0000000..598adfc --- /dev/null +++ b/src/assembly/pico/views/downlink.pico_example.view.yaml @@ -0,0 +1,14 @@ +--- +description: Any packet produced by the assembly is sent to the Ccsds_Packetizer_Instance. This component takes the Adamant formatted packets, converts them to CCSDS, and sends them asynchronously to the Ccsds_Serial_Interface_Instance. The serial interface component will take packets stored on its queue and transmit them over the Raspberry Pi Pico UART. The Product_Packetizer_Instance periodically requests data products from the Product_Database_Instance to create packets containing data from multiple components. These packets are also forwarded to the Ccsds_Packetizer_Instance for downlink. +layout: left-to-right +filters: + - name: downlink_connections + type: connector_type + include: + - Packet.T + - Data_Product_Fetch.T + - Ccsds_Space_Packet.T + - name: rm_component + type: component_type + exclude: + - Ccsds_Command_Depacketizer diff --git a/src/assembly/pico/views/env.py b/src/assembly/pico/views/env.py new file mode 100644 index 0000000..d9cba61 --- /dev/null +++ b/src/assembly/pico/views/env.py @@ -0,0 +1 @@ +from environments import pico # noqa: F401 diff --git a/src/assembly/pico/views/events.pico_example.view.yaml b/src/assembly/pico/views/events.pico_example.view.yaml new file mode 100644 index 0000000..49c0095 --- /dev/null +++ b/src/assembly/pico/views/events.pico_example.view.yaml @@ -0,0 +1,12 @@ +--- +description: Events are produced by components when something interesting happens. All components send their events first to the Event_Filter_Instance. This component can enabled/disable individual events by ID. Next, events are forwarded to the Event_Limiter_Instance. This component will start limiting problematic spam events that might flood the system. Any event that passes both of these filtering components is passed to the Event_Packetizer_Instance for collection in a packet for later downlink. +filters: + - name: evt_connections + type: connector_type + include: + - Event.T + - name: rm_connector + type: connector_name + exclude: + - Event_Limiter_Instance.Event_T_Send + - Event_Filter_Instance.Event_T_Send diff --git a/src/assembly/pico/views/faults.pico_example.view.yaml b/src/assembly/pico/views/faults.pico_example.view.yaml new file mode 100644 index 0000000..29cd0ff --- /dev/null +++ b/src/assembly/pico/views/faults.pico_example.view.yaml @@ -0,0 +1,20 @@ +--- +description: Any component that produces faults will send them to the Fault_Correction_Instance. This component maps the fault to a response action. This action is in the form of a correction command which is sent to the Command_Router_Instance synchronously for execution. In the Raspberry Pi Pico assembly, two components can throw faults. The first is the Task_Watchdog_Instance. This component monitors some critical tasks to ensure that they are always running in a timely fashion. If one stops executing, a fault is thrown. The Fault_Producer_Instance is a simple component that throws a fault when commanded to. This can be used to inject a fault into the system for testing purposes. +rule: flt_connections | (flt_response & rm_connectors) +filters: + - name: flt_connections + type: connector_type + include: + - Fault.T + - name: flt_response + type: component_type + include: + - Fault_Correction + - Command_Router + - name: rm_connectors + type: connector_name + exclude: + - Command_Router_Instance.Command_T_Send + - Command_Router_Instance.Command_Response_T_To_Forward_Send + - Command_Router_Instance.Command_Response_T_Send + - Command_Router_Instance.Command_Response_T_Recv_Async diff --git a/src/assembly/pico/views/tick.pico_example.view.yaml b/src/assembly/pico/views/tick.pico_example.view.yaml new file mode 100644 index 0000000..f18e953 --- /dev/null +++ b/src/assembly/pico/views/tick.pico_example.view.yaml @@ -0,0 +1,7 @@ +--- +description: In this assembly, Tick.T types are used to indicate when periodic tasks should be run. This view shows the rate groups that exist in the assembly. The Ticker_Instance runs in a high priority task and produces a Tick.T at 5 Hz. This tick is forwarded to the Tick_Divider_Instance which takes the 5 Hz signal and divides it up among 3 different rate groups. The Slow_Rate_Group runs at 0.5 Hz. The Fast_Rate_Group runs a 5 Hz. The Watchdog_Rate_Group runs as 1 Hz. Each of these rate group components will call the components connected to them every time they receive a tick from upstream. This architecture allows for periodic execution of certain functions, such as collecting telemetry or creating packets. Note that the actual execution of each rate group is also interleaved by the Ada scheduler. Each rate group is an active component, which executes on a task with a priority shown in the top right hand corner of the component. Rate groups produce telemetry relating how long it takes them to execute, both in CPU time and in wall clock time. +filters: + - name: tick_connections + type: connector_type + include: + - Tick.T diff --git a/src/assembly/pico/views/time.pico_example.view.yaml b/src/assembly/pico/views/time.pico_example.view.yaml new file mode 100644 index 0000000..6e801e5 --- /dev/null +++ b/src/assembly/pico/views/time.pico_example.view.yaml @@ -0,0 +1,7 @@ +--- +description: All components in the system fetch time by requesting it from the System_Time_Instance. By implementing the time system at the Adamant architectural level, different time sources and time synchronization schemes can be easily swapped into the system by replacing System_Time_Instance with a more tailored version. Note that synchronous connectors exhibit extremely low overhead, so exposing anything at the architectural level should not be prohibitive in terms of performance. +filters: + - name: time + type: connector_type + include: + - Sys_Time.T diff --git a/src/assembly/pico/views/uplink.pico_example.view.yaml b/src/assembly/pico/views/uplink.pico_example.view.yaml new file mode 100644 index 0000000..9e4ca63 --- /dev/null +++ b/src/assembly/pico/views/uplink.pico_example.view.yaml @@ -0,0 +1,18 @@ +--- +description: The Ccsds_Serial_Interface_Instance receives data on the Raspberry Pi Pico UART. It is actively looking for a sync pattern followed by a CCSDS packet header. If it receives a valid CCSDS packet it forwards it along to the Ccsds_Commmand_Depacketizer_Instance. This component looks for commands in the CCSDS packet, extracts them, and then forwards them along the Command_Router_Instance for routing and later execution. +layout: left-to-right +filters: + - name: downlink_types + type: connector_type + include: + - Ccsds_Space_Packet.T + - Command.T + - name: rm_connector + type: connector_name + exclude: + - Command_Router_Instance.Command_T_Send + - name: rm_component + type: component_type + exclude: + - Ccsds_Packetizer + - Fault_Correction diff --git a/src/components/README.md b/src/components/README.md new file mode 100644 index 0000000..dfe23e9 --- /dev/null +++ b/src/components/README.md @@ -0,0 +1,13 @@ +# Example Component Library + +This directory contains Adamant Example project components. Below is an index of what is included. Please update this +README.md when adding a new component to this directory. + + - [**adc_data_collector**](adc_data_collector/doc/adc_data_collector.pdf) - This component reads the Raspberry Pi Pico internal ADC and produces data products. + - [**c_demo**](c_demo/doc/c_demo.pdf) - A simple component that calls a C library. + - [**counter**](counter/doc/counter.pdf) - This simple component periodically produces a data product including a counter. + - [**cpp_demo**](cpp_demo/doc/cpp_demo.pdf) - A simple component that calls a C++ library. + - [**fault_producer**](fault_producer/doc/fault_producer.pdf) - This component produces a fault when a specific command is received. + - [**interrupt_responder**](interrupt_responder/doc/interrupt_responder.pdf) - This component provides a response when an interrupt is received. + - [**oscillator**](oscillator/doc/oscillator.pdf) - This component produces a data product that is a sinusoid. The amplitude, frequency, and offset of the sinusoid can be modified by command. + - [**parameter_manager**](parameter_manager/doc/parameter_manager.pdf) - This component demonstrates how to implement the Adamant parameter system. diff --git a/src/components/adc_data_collector/.Pico_path b/src/components/adc_data_collector/.Pico_path new file mode 100644 index 0000000..e69de29 diff --git a/src/components/adc_data_collector/adc_data_collector.component.yaml b/src/components/adc_data_collector/adc_data_collector.component.yaml new file mode 100644 index 0000000..15c3f0f --- /dev/null +++ b/src/components/adc_data_collector/adc_data_collector.component.yaml @@ -0,0 +1,13 @@ +--- +description: This is the ADC data collector component. It periodically collects data values from the Raspberry Pi Pico's ADC and reports them as data products. +execution: passive +connectors: + - description: The schedule invokee connector + type: Tick.T + kind: recv_sync + - description: The data product invoker connector + type: Data_Product.T + kind: send + - description: The system time is retrieved via this connector. + return_type: Sys_Time.T + kind: get diff --git a/src/components/adc_data_collector/adc_data_collector.data_products.yaml b/src/components/adc_data_collector/adc_data_collector.data_products.yaml new file mode 100644 index 0000000..5e90bcd --- /dev/null +++ b/src/components/adc_data_collector/adc_data_collector.data_products.yaml @@ -0,0 +1,12 @@ +--- +description: Data products for the ADC data collector component. +data_products: + - name: Channel_0 + description: The ADC reading at Channel 0 in microvolts. + type: Packed_Integer.T + - name: Vsys + description: The ADC reading of the system voltage in microvolts. + type: Packed_Integer.T + - name: Temperature + description: The ADC temperature reading in Celsius. + type: Packed_Integer.T diff --git a/src/components/adc_data_collector/all.do b/src/components/adc_data_collector/all.do new file mode 100644 index 0000000..cd1e658 --- /dev/null +++ b/src/components/adc_data_collector/all.do @@ -0,0 +1 @@ +redo-ifchange build/obj/Pico/adc_data_collector_data_products.o build/obj/Pico/adc_data_collector_data_products.o build/obj/Pico/component-adc_data_collector-implementation.o build/obj/Pico/component-adc_data_collector.o diff --git a/src/components/adc_data_collector/component-adc_data_collector-implementation.adb b/src/components/adc_data_collector/component-adc_data_collector-implementation.adb new file mode 100644 index 0000000..9f7c8d3 --- /dev/null +++ b/src/components/adc_data_collector/component-adc_data_collector-implementation.adb @@ -0,0 +1,44 @@ +-------------------------------------------------------------------------------- +-- Adc_Data_Collector Component Implementation Body +-------------------------------------------------------------------------------- + +with RP.Device; use RP.Device; +with RP.GPIO; use RP.GPIO; +with RP.ADC; use RP.ADC; +with Pico; + +package body Component.Adc_Data_Collector.Implementation is + + --------------------------------------- + -- Invokee connector primitives: + --------------------------------------- + -- The schedule invokee connector + overriding procedure Tick_T_Recv_Sync (Self : in out Instance; Arg : in Tick.T) is + Ignore : Tick.T renames Arg; + The_Time : constant Sys_Time.T := Self.Sys_Time_T_Get; + begin + Pico.SMPS_PS.Set; + + -- Read ADC and produce data products: + Self.Data_Product_T_Send (Self.Data_Products.Channel_0 (The_Time, (Value => Integer (RP.ADC.Read_Microvolts (0))))); + Self.Data_Product_T_Send (Self.Data_Products.Vsys (The_Time, (Value => Integer (RP.ADC.Read_Microvolts (Pico.VSYS_DIV_3) * 3)))); + Self.Data_Product_T_Send (Self.Data_Products.Temperature (The_Time, (Value => Integer (RP.ADC.Temperature)))); + + Pico.SMPS_PS.Clear; + end Tick_T_Recv_Sync; + +begin + -- Setup the pico ADC at elaboration time. + -- + -- The Pico's power regulator dynamically adjusts it's switching frequency + -- based on load. This introduces noise that can affect ADC readings. The + -- Pico datasheet recommends setting Power Save pin high while performing + -- ADC measurements to minimize this noise, at tne expense of higher power + -- consumption. + Pico.SMPS_PS.Configure (Output, Pull_Up); + Pico.SMPS_PS.Clear; + + RP.ADC.Enable; + RP.ADC.Configure (0); + RP.ADC.Configure (Pico.VSYS_DIV_3); +end Component.Adc_Data_Collector.Implementation; diff --git a/src/components/adc_data_collector/component-adc_data_collector-implementation.ads b/src/components/adc_data_collector/component-adc_data_collector-implementation.ads new file mode 100644 index 0000000..8ed081c --- /dev/null +++ b/src/components/adc_data_collector/component-adc_data_collector-implementation.ads @@ -0,0 +1,45 @@ +-------------------------------------------------------------------------------- +-- Adc_Data_Collector Component Implementation Spec +-------------------------------------------------------------------------------- + +-- Includes: +with Tick; + +-- This is the ADC data collector component. It periodically collects data values from the Raspberry Pi Pico's ADC and reports them as data products. +package Component.Adc_Data_Collector.Implementation is + + -- The component class instance record: + type Instance is new Adc_Data_Collector.Base_Instance with private; + +private + + -- The component class instance record: + type Instance is new Adc_Data_Collector.Base_Instance with record + null; + end record; + + --------------------------------------- + -- Set Up Procedure + --------------------------------------- + -- Null method which can be implemented to provide some component + -- set up code. This method is generally called by the assembly + -- main.adb after all component initialization and tasks have been started. + -- Some activities need to only be run once at startup, but cannot be run + -- safely until everything is up and running, ie. command registration, initial + -- data product updates. This procedure should be implemented to do these things + -- if necessary. + overriding procedure Set_Up (Self : in out Instance) is null; + + --------------------------------------- + -- Invokee connector primitives: + --------------------------------------- + -- The schedule invokee connector + overriding procedure Tick_T_Recv_Sync (Self : in out Instance; Arg : in Tick.T); + + --------------------------------------- + -- Invoker connector primitives: + --------------------------------------- + -- This procedure is called when a Data_Product_T_Send message is dropped due to a full queue. + overriding procedure Data_Product_T_Send_Dropped (Self : in out Instance; Arg : in Data_Product.T) is null; + +end Component.Adc_Data_Collector.Implementation; diff --git a/src/components/adc_data_collector/doc/adc_data_collector.pdf b/src/components/adc_data_collector/doc/adc_data_collector.pdf new file mode 100644 index 0000000..dc19622 Binary files /dev/null and b/src/components/adc_data_collector/doc/adc_data_collector.pdf differ diff --git a/src/components/adc_data_collector/doc/adc_data_collector.tex b/src/components/adc_data_collector/doc/adc_data_collector.tex new file mode 100644 index 0000000..e485caf --- /dev/null +++ b/src/components/adc_data_collector/doc/adc_data_collector.tex @@ -0,0 +1,83 @@ +\input{common_packages.tex} + +\begin{document} + +\title{\textbf{Adc Data Collector} \\ +\large\textit{Component Design Document}} +\date{} +\maketitle + +\section{Description} +\input{build/tex/adc_data_collector_description.tex} + +\section{Requirements} +\input{build/tex/adc_data_collector_requirements.tex} + +\section{Design} + +\subsection{At a Glance} +\input{build/tex/adc_data_collector_stats.tex} + +\subsection{Diagram} +\begin{figure}[H] + \includegraphics[width=1.0\textwidth,center]{../build/eps/adc_data_collector.eps} + \caption{Adc Data Collector component diagram.} +\end{figure} + +\subsection{Connectors} +\input{build/tex/adc_data_collector_connectors.tex} + +\subsection{Interrupts} + +\input{build/tex/adc_data_collector_interrupts.tex} + +\subsection{Initialization} +\input{build/tex/adc_data_collector_init.tex} + +\subsection{Commands} + +\input{build/tex/adc_data_collector_commands.tex} + +\subsection{Parameters} + +\input{build/tex/adc_data_collector_parameters.tex} + +\subsection{Events} + +\input{build/tex/adc_data_collector_events.tex} + +\subsection{Data Products} + +\input{build/tex/adc_data_collector_data_products.tex} + +\subsection{Data Dependencies} + +\input{build/tex/adc_data_collector_data_dependencies.tex} + +\subsection{Packets} + +\input{build/tex/adc_data_collector_packets.tex} + +\subsection{Faults} + +\input{build/tex/adc_data_collector_faults.tex} + +\section{Unit Tests} + +\input{build/tex/adc_data_collector_unit_test.tex} + +\section{Appendix} + +\subsection{Preamble} + +\input{build/tex/adc_data_collector_preamble.tex} + +\subsection{Packed Types} + +\input{build/tex/adc_data_collector_types.tex} + +\subsection{Enumerations} + +\input{build/tex/adc_data_collector_enums.tex} + +\end{document} diff --git a/src/components/adc_data_collector/doc/env.py b/src/components/adc_data_collector/doc/env.py new file mode 100644 index 0000000..d9cba61 --- /dev/null +++ b/src/components/adc_data_collector/doc/env.py @@ -0,0 +1 @@ +from environments import pico # noqa: F401 diff --git a/src/components/adc_data_collector/env.py b/src/components/adc_data_collector/env.py new file mode 100644 index 0000000..d9cba61 --- /dev/null +++ b/src/components/adc_data_collector/env.py @@ -0,0 +1 @@ +from environments import pico # noqa: F401 diff --git a/src/components/c_demo/.all_path b/src/components/c_demo/.all_path new file mode 100644 index 0000000..e69de29 diff --git a/src/components/c_demo/c_demo.component.yaml b/src/components/c_demo/c_demo.component.yaml new file mode 100644 index 0000000..fda4833 --- /dev/null +++ b/src/components/c_demo/c_demo.component.yaml @@ -0,0 +1,13 @@ +--- +description: This component demonstrates how to include and use a C library within an Adamant component. +execution: passive +connectors: + - description: The schedule invokee connector + type: Tick.T + kind: recv_sync + - description: The event send connector + type: Event.T + kind: send + - description: The system time is retrieved via this connector. + return_type: Sys_Time.T + kind: get diff --git a/src/components/c_demo/c_demo.events.yaml b/src/components/c_demo/c_demo.events.yaml new file mode 100644 index 0000000..4e0a574 --- /dev/null +++ b/src/components/c_demo/c_demo.events.yaml @@ -0,0 +1,6 @@ +--- +description: Events for the c_demo component +events: + - name: Current_Count + description: Sending the current value out as data product. + param_type: Packed_U32.T diff --git a/src/components/c_demo/c_lib/.all_path b/src/components/c_demo/c_lib/.all_path new file mode 100644 index 0000000..e69de29 diff --git a/src/components/c_demo/c_lib/c_dep/.all_path b/src/components/c_demo/c_lib/c_dep/.all_path new file mode 100644 index 0000000..e69de29 diff --git a/src/components/c_demo/c_lib/c_dep/c_dep.c b/src/components/c_demo/c_lib/c_dep/c_dep.c new file mode 100644 index 0000000..6aa68a5 --- /dev/null +++ b/src/components/c_demo/c_lib/c_dep/c_dep.c @@ -0,0 +1,5 @@ +#include "c_dep.h" + +unsigned int add_1(unsigned int value) { + return value + 1; +} diff --git a/src/components/c_demo/c_lib/c_dep/c_dep.h b/src/components/c_demo/c_lib/c_dep/c_dep.h new file mode 100644 index 0000000..de3186e --- /dev/null +++ b/src/components/c_demo/c_lib/c_dep/c_dep.h @@ -0,0 +1,2 @@ +// C-dep function +unsigned int add_1(unsigned int value); diff --git a/src/components/c_demo/c_lib/c_lib.c b/src/components/c_demo/c_lib/c_lib.c new file mode 100644 index 0000000..4f6e070 --- /dev/null +++ b/src/components/c_demo/c_lib/c_lib.c @@ -0,0 +1,16 @@ +#include "c_lib.h" +#include "c_dep.h" + +unsigned int increment(c_data* data) { + // Increment count if it is less than limit, + // otherwise set equal to zero. + if (data->count < data->limit) { + data->count = add_1(data->count); + } else { + data->count = 0; + } + + // Return the current count. + return data->count; +} + diff --git a/src/components/c_demo/c_lib/c_lib.h b/src/components/c_demo/c_lib/c_lib.h new file mode 100644 index 0000000..ac7bd30 --- /dev/null +++ b/src/components/c_demo/c_lib/c_lib.h @@ -0,0 +1,8 @@ +// C-lib data type +typedef struct { + unsigned int count; + unsigned int limit; +} c_data; + +// C-lib function +unsigned int increment(c_data* data); diff --git a/src/components/c_demo/c_lib/c_lib_h.ads b/src/components/c_demo/c_lib/c_lib_h.ads new file mode 100644 index 0000000..ea7330c --- /dev/null +++ b/src/components/c_demo/c_lib/c_lib_h.ads @@ -0,0 +1,26 @@ +pragma Ada_2012; + +pragma Style_Checks (Off); +pragma Warnings (Off, "-gnatwu"); + +with Interfaces.C; use Interfaces.C; + +package c_lib_h is + + -- C-lib data type + type c_data is record + count : aliased unsigned; -- c_lib.h:3 + limit : aliased unsigned; -- c_lib.h:4 + end record + with Convention => C_Pass_By_Copy; -- c_lib.h:5 + + -- C-lib function + function increment (data : access c_data) return unsigned -- c_lib.h:8 + with Import => True, + Convention => C, + External_Name => "increment"; + +end c_lib_h; + +pragma Style_Checks (On); +pragma Warnings (On, "-gnatwu"); diff --git a/src/components/c_demo/component-c_demo-implementation.adb b/src/components/c_demo/component-c_demo-implementation.adb new file mode 100644 index 0000000..113811a --- /dev/null +++ b/src/components/c_demo/component-c_demo-implementation.adb @@ -0,0 +1,20 @@ +-------------------------------------------------------------------------------- +-- C_Demo Component Implementation Body +-------------------------------------------------------------------------------- +with Interfaces.C; use Interfaces.C; use Interfaces; + +package body Component.C_Demo.Implementation is + + --------------------------------------- + -- Invokee connector primitives: + --------------------------------------- + -- The schedule invokee connector + overriding procedure Tick_T_Recv_Sync (Self : in out Instance; Arg : in Tick.T) is + New_Count : constant unsigned := c_lib_h.increment (data => Self.My_C_Data'Access); + begin + Self.Event_T_Send_If_Connected ( + Self.Events.Current_Count (Self.Sys_Time_T_Get, (Value => Unsigned_32 (New_Count))) + ); + end Tick_T_Recv_Sync; + +end Component.C_Demo.Implementation; diff --git a/src/components/c_demo/component-c_demo-implementation.ads b/src/components/c_demo/component-c_demo-implementation.ads new file mode 100644 index 0000000..d7509b3 --- /dev/null +++ b/src/components/c_demo/component-c_demo-implementation.ads @@ -0,0 +1,47 @@ +-------------------------------------------------------------------------------- +-- C_Demo Component Implementation Spec +-------------------------------------------------------------------------------- + +-- Includes: +with Tick; +with c_lib_h; + +-- This component demonstrates how to include and use a C library within an +-- Adamant component. +package Component.C_Demo.Implementation is + + -- The component class instance record: + type Instance is new C_Demo.Base_Instance with private; + +private + + -- The component class instance record: + type Instance is new C_Demo.Base_Instance with record + My_C_Data : aliased c_lib_h.c_data := (count => 0, limit => 3); + end record; + + --------------------------------------- + -- Set Up Procedure + --------------------------------------- + -- Null method which can be implemented to provide some component + -- set up code. This method is generally called by the assembly + -- main.adb after all component initialization and tasks have been started. + -- Some activities need to only be run once at startup, but cannot be run + -- safely until everything is up and running, ie. command registration, initial + -- data product updates. This procedure should be implemented to do these things + -- if necessary. + overriding procedure Set_Up (Self : in out Instance) is null; + + --------------------------------------- + -- Invokee connector primitives: + --------------------------------------- + -- The schedule invokee connector + overriding procedure Tick_T_Recv_Sync (Self : in out Instance; Arg : in Tick.T); + + --------------------------------------- + -- Invoker connector primitives: + --------------------------------------- + -- This procedure is called when a Event_T_Send message is dropped due to a full queue. + overriding procedure Event_T_Send_Dropped (Self : in out Instance; Arg : in Event.T) is null; + +end Component.C_Demo.Implementation; diff --git a/src/components/c_demo/test/component-c_demo-implementation-tester.adb b/src/components/c_demo/test/component-c_demo-implementation-tester.adb new file mode 100644 index 0000000..075cfcc --- /dev/null +++ b/src/components/c_demo/test/component-c_demo-implementation-tester.adb @@ -0,0 +1,74 @@ +-------------------------------------------------------------------------------- +-- C_Demo Component Tester Body +-------------------------------------------------------------------------------- + +package body Component.C_Demo.Implementation.Tester is + + --------------------------------------- + -- Initialize heap variables: + --------------------------------------- + procedure Init_Base (Self : in out Instance) is + begin + -- Initialize tester heap: + -- Connector histories: + Self.Event_T_Recv_Sync_History.Init (Depth => 100); + Self.Sys_Time_T_Return_History.Init (Depth => 100); + -- Event histories: + Self.Current_Count_History.Init (Depth => 100); + end Init_Base; + + procedure Final_Base (Self : in out Instance) is + begin + -- Destroy tester heap: + -- Connector histories: + Self.Event_T_Recv_Sync_History.Destroy; + Self.Sys_Time_T_Return_History.Destroy; + -- Event histories: + Self.Current_Count_History.Destroy; + end Final_Base; + + --------------------------------------- + -- Test initialization functions: + --------------------------------------- + procedure Connect (Self : in out Instance) is + begin + Self.Component_Instance.Attach_Event_T_Send (To_Component => Self'Unchecked_Access, Hook => Self.Event_T_Recv_Sync_Access); + Self.Component_Instance.Attach_Sys_Time_T_Get (To_Component => Self'Unchecked_Access, Hook => Self.Sys_Time_T_Return_Access); + Self.Attach_Tick_T_Send (To_Component => Self.Component_Instance'Unchecked_Access, Hook => Self.Component_Instance.Tick_T_Recv_Sync_Access); + end Connect; + + --------------------------------------- + -- Invokee connector primitives: + --------------------------------------- + -- The event send connector + overriding procedure Event_T_Recv_Sync (Self : in out Instance; Arg : in Event.T) is + begin + -- Push the argument onto the test history for looking at later: + Self.Event_T_Recv_Sync_History.Push (Arg); + -- Dispatch the event to the correct handler: + Self.Dispatch_Event (Arg); + end Event_T_Recv_Sync; + + -- The system time is retrieved via this connector. + overriding function Sys_Time_T_Return (Self : in out Instance) return Sys_Time.T is + -- Return the system time: + To_Return : constant Sys_Time.T := Self.System_Time; + begin + -- Push the argument onto the test history for looking at later: + Self.Sys_Time_T_Return_History.Push (To_Return); + return To_Return; + end Sys_Time_T_Return; + + ----------------------------------------------- + -- Event handler primitive: + ----------------------------------------------- + -- Description: + -- Events for the c_demo component + -- Sending the current value out as data product. + overriding procedure Current_Count (Self : in out Instance; Arg : in Packed_U32.T) is + begin + -- Push the argument onto the test history for looking at later: + Self.Current_Count_History.Push (Arg); + end Current_Count; + +end Component.C_Demo.Implementation.Tester; diff --git a/src/components/c_demo/test/component-c_demo-implementation-tester.ads b/src/components/c_demo/test/component-c_demo-implementation-tester.ads new file mode 100644 index 0000000..94aad15 --- /dev/null +++ b/src/components/c_demo/test/component-c_demo-implementation-tester.ads @@ -0,0 +1,64 @@ +-------------------------------------------------------------------------------- +-- C_Demo Component Tester Spec +-------------------------------------------------------------------------------- + +-- Includes: +with Component.C_Demo_Reciprocal; +with Printable_History; +with Event.Representation; +with Sys_Time.Representation; +with Event; +with Packed_U32.Representation; + +-- This component demonstrates how to include and use a C library within an +-- Adamant component. +package Component.C_Demo.Implementation.Tester is + + use Component.C_Demo_Reciprocal; + -- Invoker connector history packages: + package Event_T_Recv_Sync_History_Package is new Printable_History (Event.T, Event.Representation.Image); + package Sys_Time_T_Return_History_Package is new Printable_History (Sys_Time.T, Sys_Time.Representation.Image); + + -- Event history packages: + package Current_Count_History_Package is new Printable_History (Packed_U32.T, Packed_U32.Representation.Image); + + -- Component class instance: + type Instance is new Component.C_Demo_Reciprocal.Base_Instance with record + -- The component instance under test: + Component_Instance : aliased Component.C_Demo.Implementation.Instance; + -- Connector histories: + Event_T_Recv_Sync_History : Event_T_Recv_Sync_History_Package.Instance; + Sys_Time_T_Return_History : Sys_Time_T_Return_History_Package.Instance; + -- Event histories: + Current_Count_History : Current_Count_History_Package.Instance; + end record; + type Instance_Access is access all Instance; + + --------------------------------------- + -- Initialize component heap variables: + --------------------------------------- + procedure Init_Base (Self : in out Instance); + procedure Final_Base (Self : in out Instance); + + --------------------------------------- + -- Test initialization functions: + --------------------------------------- + procedure Connect (Self : in out Instance); + + --------------------------------------- + -- Invokee connector primitives: + --------------------------------------- + -- The event send connector + overriding procedure Event_T_Recv_Sync (Self : in out Instance; Arg : in Event.T); + -- The system time is retrieved via this connector. + overriding function Sys_Time_T_Return (Self : in out Instance) return Sys_Time.T; + + ----------------------------------------------- + -- Event handler primitive: + ----------------------------------------------- + -- Description: + -- Events for the c_demo component + -- Sending the current value out as data product. + overriding procedure Current_Count (Self : in out Instance; Arg : in Packed_U32.T); + +end Component.C_Demo.Implementation.Tester; diff --git a/src/components/c_demo/test/env.py b/src/components/c_demo/test/env.py new file mode 100644 index 0000000..8d5248e --- /dev/null +++ b/src/components/c_demo/test/env.py @@ -0,0 +1 @@ +from environments import test # noqa: F401 diff --git a/src/components/c_demo/test/test.adb b/src/components/c_demo/test/test.adb new file mode 100644 index 0000000..2c39ee8 --- /dev/null +++ b/src/components/c_demo/test/test.adb @@ -0,0 +1,23 @@ +-------------------------------------------------------------------------------- +-- C_Demo Tests +-------------------------------------------------------------------------------- + +with AUnit.Reporter.Text; +with AUnit.Run; +with Tests.Implementation.Suite; +-- Make sure any terminating tasks are handled and an appropriate +-- error message is printed. +with Unit_Test_Termination_Handler; +pragma Unreferenced (Unit_Test_Termination_Handler); + +procedure Test is + -- Create runner for test suite: + procedure Runner is new AUnit.Run.Test_Runner (Tests.Implementation.Suite.Get); + -- Use the text reporter: + Reporter : AUnit.Reporter.Text.Text_Reporter; +begin + -- Add color output to test run: + AUnit.Reporter.Text.Set_Use_ANSI_Colors (Reporter, True); + -- Run tests: + Runner (Reporter); +end Test; diff --git a/src/components/c_demo/test/tests-implementation.adb b/src/components/c_demo/test/tests-implementation.adb new file mode 100644 index 0000000..e506552 --- /dev/null +++ b/src/components/c_demo/test/tests-implementation.adb @@ -0,0 +1,66 @@ +-------------------------------------------------------------------------------- +-- C_Demo Tests Body +-------------------------------------------------------------------------------- + +with Packed_U32.Assertion; use Packed_U32.Assertion; +with Basic_Assertions; use Basic_Assertions; + +package body Tests.Implementation is + + ------------------------------------------------------------------------- + -- Fixtures: + ------------------------------------------------------------------------- + + overriding procedure Set_Up_Test (Self : in out Instance) is + begin + -- Allocate heap memory to component: + Self.Tester.Init_Base; + + -- Make necessary connections between tester and component: + Self.Tester.Connect; + + -- Call the component set up method that the assembly would normally call. + Self.Tester.Component_Instance.Set_Up; + end Set_Up_Test; + + overriding procedure Tear_Down_Test (Self : in out Instance) is + begin + -- Free component heap: + Self.Tester.Final_Base; + end Tear_Down_Test; + + ------------------------------------------------------------------------- + -- Tests: + ------------------------------------------------------------------------- + + -- This unit test excersizes the c_demo component and makes sure it works + -- correctly. + overriding procedure Test_C (Self : in out Instance) is + T : Component.C_Demo.Implementation.Tester.Instance_Access renames Self.Tester; + begin + -- Send tick and verify increment + T.Tick_T_Send ((Time => (1, 1), Count => 1)); + Natural_Assert.Eq (T.Event_T_Recv_Sync_History.Get_Count, 1); + Natural_Assert.Eq (T.Current_Count_History.Get_Count, 1); + Packed_U32_Assert.Eq (T.Current_Count_History.Get (1), (Value => 1)); + + -- Send tick and verify increment + T.Tick_T_Send ((Time => (1, 1), Count => 2)); + Natural_Assert.Eq (T.Event_T_Recv_Sync_History.Get_Count, 2); + Natural_Assert.Eq (T.Current_Count_History.Get_Count, 2); + Packed_U32_Assert.Eq (T.Current_Count_History.Get (2), (Value => 2)); + + -- Send tick and verify increment + T.Tick_T_Send ((Time => (1, 1), Count => 2)); + Natural_Assert.Eq (T.Event_T_Recv_Sync_History.Get_Count, 3); + Natural_Assert.Eq (T.Current_Count_History.Get_Count, 3); + Packed_U32_Assert.Eq (T.Current_Count_History.Get (3), (Value => 3)); + + -- Send tick and verify increment + T.Tick_T_Send ((Time => (1, 1), Count => 2)); + Natural_Assert.Eq (T.Event_T_Recv_Sync_History.Get_Count, 4); + Natural_Assert.Eq (T.Current_Count_History.Get_Count, 4); + Packed_U32_Assert.Eq (T.Current_Count_History.Get (4), (Value => 0)); + end Test_C; + +end Tests.Implementation; diff --git a/src/components/c_demo/test/tests-implementation.ads b/src/components/c_demo/test/tests-implementation.ads new file mode 100644 index 0000000..574f7f3 --- /dev/null +++ b/src/components/c_demo/test/tests-implementation.ads @@ -0,0 +1,25 @@ +-------------------------------------------------------------------------------- +-- C_Demo Tests Spec +-------------------------------------------------------------------------------- + +-- This is a unit test suite for the c_demo component. +package Tests.Implementation is + + -- Test data and state: + type Instance is new Tests.Base_Instance with private; + type Class_Access is access all Instance'Class; + +private + -- Fixture procedures: + overriding procedure Set_Up_Test (Self : in out Instance); + overriding procedure Tear_Down_Test (Self : in out Instance); + + -- This unit test excersizes the c_demo component and makes sure it works + -- correctly. + overriding procedure Test_C (Self : in out Instance); + + -- Test data and state: + type Instance is new Tests.Base_Instance with record + null; + end record; +end Tests.Implementation; diff --git a/src/components/c_demo/test/tests.c_demo.tests.yaml b/src/components/c_demo/test/tests.c_demo.tests.yaml new file mode 100644 index 0000000..ad5c74b --- /dev/null +++ b/src/components/c_demo/test/tests.c_demo.tests.yaml @@ -0,0 +1,5 @@ +--- +description: This is a unit test suite for the c_demo component. +tests: + - name: Test_C + description: This unit test excersizes the c_demo component and makes sure it works correctly. diff --git a/src/components/counter/.all_path b/src/components/counter/.all_path new file mode 100644 index 0000000..e69de29 diff --git a/src/components/counter/command_args/.all_path b/src/components/counter/command_args/.all_path new file mode 100644 index 0000000..e69de29 diff --git a/src/components/counter/command_args/operands.record.yaml b/src/components/counter/command_args/operands.record.yaml new file mode 100644 index 0000000..4880810 --- /dev/null +++ b/src/components/counter/command_args/operands.record.yaml @@ -0,0 +1,11 @@ +--- +description: This is a type that contains a left and right side +fields: + - name: Left + type: Interfaces.Unsigned_16 + format: U16 + description: "The left side" + - name: Right + type: Interfaces.Unsigned_16 + format: U16 + description: "The right side" diff --git a/src/components/counter/component-counter-implementation.adb b/src/components/counter/component-counter-implementation.adb new file mode 100644 index 0000000..5c0df0d --- /dev/null +++ b/src/components/counter/component-counter-implementation.adb @@ -0,0 +1,89 @@ +-------------------------------------------------------------------------------- +-- Counter Component Implementation Body +-------------------------------------------------------------------------------- + +with Counter_Action; + +package body Component.Counter.Implementation is + + --------------------------------------- + -- Invokee connector primitives: + --------------------------------------- + -- The schedule invokee connector + overriding procedure Tick_T_Recv_Sync (Self : in out Instance; Arg : in Tick.T) is + Ignore : Tick.T renames Arg; + Ignore_2 : Natural; + Timestamp : constant Sys_Time.T := Self.Sys_Time_T_Get; + begin + -- Service the queue for commands: + Ignore_2 := Self.Dispatch_All; + + -- Increment the count and perform the counter action: + Self.The_Count := Self.The_Count + 1; + Counter_Action.Do_Action (Self.The_Count); + + -- Send the count value out: + Self.Event_T_Send_If_Connected (Self.Events.Sending_Value (Timestamp, (Value => Self.The_Count))); + Self.Packet_T_Send_If_Connected (Self.Packets.Counter_Value (Timestamp, (Value => Self.The_Count))); + end Tick_T_Recv_Sync; + + -- The command receive connector + overriding procedure Command_T_Recv_Async (Self : in out Instance; Arg : in Command.T) is + -- Execute the command: + Stat : constant Command_Response_Status.E := Self.Execute_Command (Arg); + begin + -- Send the return status: + Self.Command_Response_T_Send_If_Connected ((Source_Id => Arg.Header.Source_Id, Registration_Id => Self.Command_Reg_Id, Command_Id => Arg.Header.Id, Status => Stat)); + end Command_T_Recv_Async; + + -- This procedure is called when a Command_T_Recv_Async message is dropped due to a full queue. + overriding procedure Command_T_Recv_Async_Dropped (Self : in out Instance; Arg : in Command.T) is + begin + -- Throw event: + Self.Event_T_Send_If_Connected (Self.Events.Dropped_Command ( + Self.Sys_Time_T_Get, Arg.Header + )); + end Command_T_Recv_Async_Dropped; + + ----------------------------------------------- + -- Command handler primitives: + ----------------------------------------------- + -- Description: + -- Commands for the counter component + -- Change the current counter value in the counter component + overriding function Set_Count (Self : in out Instance; Arg : in Packed_U32.T) return Command_Execution_Status.E is + use Command_Execution_Status; + begin + Self.The_Count := Arg.Value; + Self.Event_T_Send_If_Connected (Self.Events.Set_Count_Command_Received (Self.Sys_Time_T_Get, (Value => Self.The_Count))); + return Success; + end Set_Count; + + -- Reset the current counter value in the counter component to zero + overriding function Reset_Count (Self : in out Instance) return Command_Execution_Status.E is + use Command_Execution_Status; + begin + Self.The_Count := 0; + Self.Event_T_Send_If_Connected (Self.Events.Reset_Count_Command_Received (Self.Sys_Time_T_Get)); + return Success; + end Reset_Count; + + -- Change the current counter value in the counter component to the sum of the arguments + overriding function Set_Count_Add (Self : in out Instance; Arg : in Operands.T) return Command_Execution_Status.E is + use Command_Execution_Status; + begin + Self.The_Count := Unsigned_32 (Arg.Left) + Unsigned_32 (Arg.Right); + Self.Event_T_Send_If_Connected (Self.Events.Set_Count_Add_Command_Received (Self.Sys_Time_T_Get, Arg)); + return Success; + end Set_Count_Add; + + -- Invalid command handler. This procedure is called when a command's arguments are found to be invalid: + overriding procedure Invalid_Command (Self : in out Instance; Cmd : in Command.T; Errant_Field_Number : in Unsigned_32; Errant_Field : in Basic_Types.Poly_Type) is + begin + Self.Event_T_Send_If_Connected (Self.Events.Invalid_Command_Received ( + Self.Sys_Time_T_Get, + (Id => Cmd.Header.Id, Errant_Field_Number => Errant_Field_Number, Errant_Field => Errant_Field) + )); + end Invalid_Command; + +end Component.Counter.Implementation; diff --git a/src/components/counter/component-counter-implementation.ads b/src/components/counter/component-counter-implementation.ads new file mode 100644 index 0000000..8822386 --- /dev/null +++ b/src/components/counter/component-counter-implementation.ads @@ -0,0 +1,69 @@ +-------------------------------------------------------------------------------- +-- Counter Component Implementation Spec +-------------------------------------------------------------------------------- + +-- Includes: +with Tick; +with Command; + +-- This is the counter component. +package Component.Counter.Implementation is + + -- The component class instance record: + type Instance is new Counter.Base_Instance with private; + +private + + -- The component class instance record: + type Instance is new Counter.Base_Instance with record + The_Count : Unsigned_32 := 0; + end record; + + --------------------------------------- + -- Set Up Procedure + --------------------------------------- + -- Null method which can be implemented to provide some component + -- set up code. This method is generally called by the assembly + -- main.adb after all component initialization and tasks have been started. + -- Some activities need to only be run once at startup, but cannot be run + -- safely until everything is up and running, ie. command registration, initial + -- data product updates. This procedure should be implemented to do these things + -- if necessary. + overriding procedure Set_Up (Self : in out Instance) is null; + + --------------------------------------- + -- Invokee connector primitives: + --------------------------------------- + -- The schedule invokee connector + overriding procedure Tick_T_Recv_Sync (Self : in out Instance; Arg : in Tick.T); + -- The command receive connector + overriding procedure Command_T_Recv_Async (Self : in out Instance; Arg : in Command.T); + -- This procedure is called when a Command_T_Recv_Async message is dropped due to a full queue. + overriding procedure Command_T_Recv_Async_Dropped (Self : in out Instance; Arg : in Command.T); + + --------------------------------------- + -- Invoker connector primitives: + --------------------------------------- + -- This procedure is called when a Command_Response_T_Send message is dropped due to a full queue. + overriding procedure Command_Response_T_Send_Dropped (Self : in out Instance; Arg : in Command_Response.T) is null; + -- This procedure is called when a Packet_T_Send message is dropped due to a full queue. + overriding procedure Packet_T_Send_Dropped (Self : in out Instance; Arg : in Packet.T) is null; + -- This procedure is called when a Event_T_Send message is dropped due to a full queue. + overriding procedure Event_T_Send_Dropped (Self : in out Instance; Arg : in Event.T) is null; + + ----------------------------------------------- + -- Command handler primitives: + ----------------------------------------------- + -- Description: + -- Commands for the counter component + -- Change the current counter value in the counter component + overriding function Set_Count (Self : in out Instance; Arg : in Packed_U32.T) return Command_Execution_Status.E; + -- Reset the current counter value in the counter component to zero + overriding function Reset_Count (Self : in out Instance) return Command_Execution_Status.E; + -- Change the current counter value in the counter component to the sum of the arguments + overriding function Set_Count_Add (Self : in out Instance; Arg : in Operands.T) return Command_Execution_Status.E; + + -- Invalid command handler. This procedure is called when a command's arguments are found to be invalid: + overriding procedure Invalid_Command (Self : in out Instance; Cmd : in Command.T; Errant_Field_Number : in Unsigned_32; Errant_Field : in Basic_Types.Poly_Type); + +end Component.Counter.Implementation; diff --git a/src/components/counter/counter.commands.yaml b/src/components/counter/counter.commands.yaml new file mode 100644 index 0000000..3102797 --- /dev/null +++ b/src/components/counter/counter.commands.yaml @@ -0,0 +1,11 @@ +--- +description: Commands for the counter component +commands: + - name: Set_Count + description: Change the current counter value in the counter component + arg_type: Packed_U32.T + - name: Reset_Count + description: Reset the current counter value in the counter component to zero + - name: Set_Count_Add + description: Change the current counter value in the counter component to the sum of the arguments + arg_type: Operands.T diff --git a/src/components/counter/counter.component.yaml b/src/components/counter/counter.component.yaml new file mode 100644 index 0000000..ad7e5b4 --- /dev/null +++ b/src/components/counter/counter.component.yaml @@ -0,0 +1,22 @@ +--- +description: This is the counter component. +execution: passive +connectors: + - description: The schedule invokee connector + type: Tick.T + kind: recv_sync + - description: The command receive connector + type: Command.T + kind: recv_async + - description: This connector is used to register the components commands with the command router component. + type: Command_Response.T + kind: send + - description: The packet invoker connector + type: Packet.T + kind: send + - description: The event send connector + type: Event.T + kind: send + - description: The system time is retrieved via this connector. + return_type: Sys_Time.T + kind: get diff --git a/src/components/counter/counter.events.yaml b/src/components/counter/counter.events.yaml new file mode 100644 index 0000000..e4faeb2 --- /dev/null +++ b/src/components/counter/counter.events.yaml @@ -0,0 +1,20 @@ +--- +description: Events for the counter component +events: + - name: Set_Count_Command_Received + description: Received a Set_Count command. + param_type: Packed_U32.T + - name: Reset_Count_Command_Received + description: Received a Reset_Count command. + - name: Set_Count_Add_Command_Received + description: Received a Set_Count_Add command. + param_type: Operands.T + - name: Sending_Value + description: Sending the current value out as data product. + param_type: Packed_U32.T + - name: Dropped_Command + description: The component's queue overflowed and the command was dropped. + param_type: Command_Header.T + - name: Invalid_Command_Received + description: A command was received with invalid parameters. + param_type: Invalid_Command_Info.T diff --git a/src/components/counter/counter.packets.yaml b/src/components/counter/counter.packets.yaml new file mode 100644 index 0000000..0005a8f --- /dev/null +++ b/src/components/counter/counter.packets.yaml @@ -0,0 +1,7 @@ +--- +description: Packets for the counter component +packets: + - name: Counter_Value + id: 7 + description: The counter value 1. + type: Packed_U32.T diff --git a/src/components/counter/counter_action/.all_path b/src/components/counter/counter_action/.all_path new file mode 100644 index 0000000..e69de29 diff --git a/src/components/counter/counter_action/counter_action.ads b/src/components/counter/counter_action/counter_action.ads new file mode 100644 index 0000000..39dc7b1 --- /dev/null +++ b/src/components/counter/counter_action/counter_action.ads @@ -0,0 +1,6 @@ +-- An action to perfrom when the count is +-- updated. +with Interfaces; use Interfaces; +package Counter_Action is + procedure Do_Action (Count : in Unsigned_32); +end Counter_Action; diff --git a/src/components/counter/counter_action/linux/.Linux_path b/src/components/counter/counter_action/linux/.Linux_path new file mode 100644 index 0000000..e69de29 diff --git a/src/components/counter/counter_action/linux/counter_action.adb b/src/components/counter/counter_action/linux/counter_action.adb new file mode 100644 index 0000000..ea8429a --- /dev/null +++ b/src/components/counter/counter_action/linux/counter_action.adb @@ -0,0 +1,6 @@ +package body Counter_Action is + procedure Do_Action (Count : in Unsigned_32) is + begin + null; -- Nothing for Linux + end Do_Action; +end Counter_Action; diff --git a/src/components/counter/counter_action/pico/.Pico_path b/src/components/counter/counter_action/pico/.Pico_path new file mode 100644 index 0000000..e69de29 diff --git a/src/components/counter/counter_action/pico/counter_action.adb b/src/components/counter/counter_action/pico/counter_action.adb new file mode 100644 index 0000000..6dc4efc --- /dev/null +++ b/src/components/counter/counter_action/pico/counter_action.adb @@ -0,0 +1,19 @@ +with RP.GPIO; use RP.GPIO; +with Pico; + +package body Counter_Action is + + procedure Do_Action (Count : in Unsigned_32) is + Ignore : Unsigned_32 renames Count; + begin + -- Toggle the LED on the Raspberry Pi Pico. + Pico.LED.Toggle; + end Do_Action; + +begin + -- Make sure LED is enabled on the the Raspberry Pi Pico + -- during elaboration. + RP.GPIO.Enable; + Pico.LED.Configure (RP.GPIO.Output); + Pico.LED.Set; +end Counter_Action; diff --git a/src/components/counter/counter_action/pico/env.py b/src/components/counter/counter_action/pico/env.py new file mode 100644 index 0000000..d9cba61 --- /dev/null +++ b/src/components/counter/counter_action/pico/env.py @@ -0,0 +1 @@ +from environments import pico # noqa: F401 diff --git a/src/components/counter/doc/counter.pdf b/src/components/counter/doc/counter.pdf new file mode 100644 index 0000000..f45d512 Binary files /dev/null and b/src/components/counter/doc/counter.pdf differ diff --git a/src/components/counter/doc/counter.tex b/src/components/counter/doc/counter.tex new file mode 100644 index 0000000..85fb31e --- /dev/null +++ b/src/components/counter/doc/counter.tex @@ -0,0 +1,83 @@ +\input{common_packages.tex} + +\begin{document} + +\title{\textbf{Counter} \\ +\large\textit{Component Design Document}} +\date{} +\maketitle + +\section{Description} +\input{build/tex/counter_description.tex} + +\section{Requirements} +\input{build/tex/counter_requirements.tex} + +\section{Design} + +\subsection{At a Glance} +\input{build/tex/counter_stats.tex} + +\subsection{Diagram} +\begin{figure}[H] + \includegraphics[width=1.0\textwidth,center]{../build/eps/counter.eps} + \caption{Counter component diagram.} +\end{figure} + +\subsection{Connectors} +\input{build/tex/counter_connectors.tex} + +\subsection{Interrupts} + +\input{build/tex/counter_interrupts.tex} + +\subsection{Initialization} +\input{build/tex/counter_init.tex} + +\subsection{Commands} + +\input{build/tex/counter_commands.tex} + +\subsection{Parameters} + +\input{build/tex/counter_parameters.tex} + +\subsection{Events} + +\input{build/tex/counter_events.tex} + +\subsection{Data Products} + +\input{build/tex/counter_data_products.tex} + +\subsection{Data Dependencies} + +\input{build/tex/counter_data_dependencies.tex} + +\subsection{Packets} + +\input{build/tex/counter_packets.tex} + +\subsection{Faults} + +\input{build/tex/counter_faults.tex} + +\section{Unit Tests} + +\input{build/tex/counter_unit_test.tex} + +\section{Appendix} + +\subsection{Preamble} + +\input{build/tex/counter_preamble.tex} + +\subsection{Packed Types} + +\input{build/tex/counter_types.tex} + +\subsection{Enumerations} + +\input{build/tex/counter_enums.tex} + +\end{document} diff --git a/src/components/counter/test/component-counter-implementation-tester.adb b/src/components/counter/test/component-counter-implementation-tester.adb new file mode 100644 index 0000000..fb9c58c --- /dev/null +++ b/src/components/counter/test/component-counter-implementation-tester.adb @@ -0,0 +1,203 @@ +-------------------------------------------------------------------------------- +-- Counter Component Tester Body +-------------------------------------------------------------------------------- + +package body Component.Counter.Implementation.Tester is + + --------------------------------------- + -- Initialize heap variables: + --------------------------------------- + procedure Init_Base (Self : in out Instance; Queue_Size : in Natural) is + begin + -- Initialize component heap: + Self.Component_Instance.Init_Base (Queue_Size => Queue_Size); + + -- Initialize tester heap: + -- Connector histories: + Self.Command_Response_T_Recv_Sync_History.Init (Depth => 100); + Self.Packet_T_Recv_Sync_History.Init (Depth => 100); + Self.Event_T_Recv_Sync_History.Init (Depth => 100); + Self.Sys_Time_T_Return_History.Init (Depth => 100); + -- Event histories: + Self.Set_Count_Command_Received_History.Init (Depth => 100); + Self.Reset_Count_Command_Received_History.Init (Depth => 100); + Self.Set_Count_Add_Command_Received_History.Init (Depth => 100); + Self.Sending_Value_History.Init (Depth => 100); + Self.Dropped_Command_History.Init (Depth => 100); + Self.Invalid_Command_Received_History.Init (Depth => 100); + -- Packet histories: + Self.Counter_Value_History.Init (Depth => 100); + end Init_Base; + + procedure Final_Base (Self : in out Instance) is + begin + -- Destroy tester heap: + -- Connector histories: + Self.Command_Response_T_Recv_Sync_History.Destroy; + Self.Packet_T_Recv_Sync_History.Destroy; + Self.Event_T_Recv_Sync_History.Destroy; + Self.Sys_Time_T_Return_History.Destroy; + -- Event histories: + Self.Set_Count_Command_Received_History.Destroy; + Self.Reset_Count_Command_Received_History.Destroy; + Self.Set_Count_Add_Command_Received_History.Destroy; + Self.Sending_Value_History.Destroy; + Self.Dropped_Command_History.Destroy; + Self.Invalid_Command_Received_History.Destroy; + -- Packet histories: + Self.Counter_Value_History.Destroy; + + -- Destroy component heap: + Self.Component_Instance.Final_Base; + end Final_Base; + + --------------------------------------- + -- Test initialization functions: + --------------------------------------- + procedure Connect (Self : in out Instance) is + begin + Self.Component_Instance.Attach_Command_Response_T_Send (To_Component => Self'Unchecked_Access, Hook => Self.Command_Response_T_Recv_Sync_Access); + Self.Component_Instance.Attach_Packet_T_Send (To_Component => Self'Unchecked_Access, Hook => Self.Packet_T_Recv_Sync_Access); + Self.Component_Instance.Attach_Event_T_Send (To_Component => Self'Unchecked_Access, Hook => Self.Event_T_Recv_Sync_Access); + Self.Component_Instance.Attach_Sys_Time_T_Get (To_Component => Self'Unchecked_Access, Hook => Self.Sys_Time_T_Return_Access); + Self.Attach_Tick_T_Send (To_Component => Self.Component_Instance'Unchecked_Access, Hook => Self.Component_Instance.Tick_T_Recv_Sync_Access); + Self.Attach_Command_T_Send (To_Component => Self.Component_Instance'Unchecked_Access, Hook => Self.Component_Instance.Command_T_Recv_Async_Access); + end Connect; + + --------------------------------------- + -- Invokee connector primitives: + --------------------------------------- + -- This connector is used to register the components commands with the command router component. + overriding procedure Command_Response_T_Recv_Sync (Self : in out Instance; Arg : in Command_Response.T) is + begin + -- Push the argument onto the test history for looking at later: + Self.Command_Response_T_Recv_Sync_History.Push (Arg); + end Command_Response_T_Recv_Sync; + + -- The packet invoker connector + overriding procedure Packet_T_Recv_Sync (Self : in out Instance; Arg : in Packet.T) is + begin + -- Push the argument onto the test history for looking at later: + Self.Packet_T_Recv_Sync_History.Push (Arg); + -- Dispatch the packet to the correct handler: + Self.Dispatch_Packet (Arg); + end Packet_T_Recv_Sync; + + -- The event send connector + overriding procedure Event_T_Recv_Sync (Self : in out Instance; Arg : in Event.T) is + begin + -- Push the argument onto the test history for looking at later: + Self.Event_T_Recv_Sync_History.Push (Arg); + -- Dispatch the event to the correct handler: + Self.Dispatch_Event (Arg); + end Event_T_Recv_Sync; + + -- The system time is retrieved via this connector. + overriding function Sys_Time_T_Return (Self : in out Instance) return Sys_Time.T is + -- Return the system time: + To_Return : constant Sys_Time.T := Self.System_Time; + begin + -- Push the argument onto the test history for looking at later: + Self.Sys_Time_T_Return_History.Push (To_Return); + return To_Return; + end Sys_Time_T_Return; + + --------------------------------------- + -- Invoker connector primitives: + --------------------------------------- + -- This procedure is called when a Command_T_Send message is dropped due to a full queue. + overriding procedure Command_T_Send_Dropped (Self : in out Instance; Arg : in Command.T) is + Ignore : Command.T renames Arg; + begin + if not Self.Expect_Command_T_Send_Dropped then + pragma Assert (False, "The component's queue filled up when Command_T_Send was called!"); + else + Self.Command_T_Send_Dropped_Count := Self.Command_T_Send_Dropped_Count + 1; + Self.Expect_Command_T_Send_Dropped := False; + end if; + end Command_T_Send_Dropped; + + ----------------------------------------------- + -- Event handler primitive: + ----------------------------------------------- + -- Description: + -- Events for the counter component + -- Received a Set_Count command. + overriding procedure Set_Count_Command_Received (Self : in out Instance; Arg : in Packed_U32.T) is + begin + -- Push the argument onto the test history for looking at later: + Self.Set_Count_Command_Received_History.Push (Arg); + end Set_Count_Command_Received; + + -- Received a Reset_Count command. + overriding procedure Reset_Count_Command_Received (Self : in out Instance) is + Arg : constant Natural := 0; + begin + -- Push the argument onto the test history for looking at later: + Self.Reset_Count_Command_Received_History.Push (Arg); + end Reset_Count_Command_Received; + + -- Received a Set_Count_Add command. + overriding procedure Set_Count_Add_Command_Received (Self : in out Instance; Arg : in Operands.T) is + begin + -- Push the argument onto the test history for looking at later: + Self.Set_Count_Add_Command_Received_History.Push (Arg); + end Set_Count_Add_Command_Received; + + -- Sending the current value out as data product. + overriding procedure Sending_Value (Self : in out Instance; Arg : in Packed_U32.T) is + begin + -- Push the argument onto the test history for looking at later: + Self.Sending_Value_History.Push (Arg); + end Sending_Value; + + -- The component's queue overflowed and the command was dropped. + overriding procedure Dropped_Command (Self : in out Instance; Arg : in Command_Header.T) is + begin + -- Push the argument onto the test history for looking at later: + Self.Dropped_Command_History.Push (Arg); + end Dropped_Command; + + -- A command was received with invalid parameters. + overriding procedure Invalid_Command_Received (Self : in out Instance; Arg : in Invalid_Command_Info.T) is + begin + -- Push the argument onto the test history for looking at later: + Self.Invalid_Command_Received_History.Push (Arg); + end Invalid_Command_Received; + + ----------------------------------------------- + -- Packet handler primitive: + ----------------------------------------------- + -- Description: + -- Packets for the counter component + -- The counter value 1. + overriding procedure Counter_Value (Self : in out Instance; Arg : in Packed_U32.T) is + begin + -- Push the argument onto the test history for looking at later: + Self.Counter_Value_History.Push (Arg); + end Counter_Value; + + ----------------------------------------------- + -- Special primitives for activating component + -- queues: + ----------------------------------------------- + -- Force the component to drain the entire queue + not overriding function Dispatch_All (Self : in out Instance) return Natural is + begin + return Self.Component_Instance.Dispatch_All; + end Dispatch_All; + + not overriding function Dispatch_N (Self : in out Instance; N : in Positive := 1) return Natural is + begin + return Self.Component_Instance.Dispatch_N (N); + end Dispatch_N; + + ----------------------------------------------- + -- Custom stuff: + ----------------------------------------------- + function Check_Count (Self : in Instance; Value : in Unsigned_32) return Boolean is + begin + return (Self.Component_Instance.The_Count = Value); + end Check_Count; + +end Component.Counter.Implementation.Tester; diff --git a/src/components/counter/test/component-counter-implementation-tester.ads b/src/components/counter/test/component-counter-implementation-tester.ads new file mode 100644 index 0000000..06c603f --- /dev/null +++ b/src/components/counter/test/component-counter-implementation-tester.ads @@ -0,0 +1,133 @@ +-------------------------------------------------------------------------------- +-- Counter Component Tester Spec +-------------------------------------------------------------------------------- + +-- Includes: +with Component.Counter_Reciprocal; +with Sys_Time; +with Printable_History; +with Command_Response.Representation; +with Packet.Representation; +with Event.Representation; +with Sys_Time.Representation; +with Packed_U32.Representation; +with Event; +with Operands.Representation; +with Command_Header.Representation; +with Invalid_Command_Info.Representation; + +-- This is the counter component. +package Component.Counter.Implementation.Tester is + + use Component.Counter_Reciprocal; + -- Invoker connector history packages: + package Command_Response_T_Recv_Sync_History_Package is new Printable_History (Command_Response.T, Command_Response.Representation.Image); + package Packet_T_Recv_Sync_History_Package is new Printable_History (Packet.T, Packet.Representation.Image); + package Event_T_Recv_Sync_History_Package is new Printable_History (Event.T, Event.Representation.Image); + package Sys_Time_T_Return_History_Package is new Printable_History (Sys_Time.T, Sys_Time.Representation.Image); + + -- Event history packages: + package Set_Count_Command_Received_History_Package is new Printable_History (Packed_U32.T, Packed_U32.Representation.Image); + package Reset_Count_Command_Received_History_Package is new Printable_History (Natural, Natural'Image); + package Set_Count_Add_Command_Received_History_Package is new Printable_History (Operands.T, Operands.Representation.Image); + package Sending_Value_History_Package is new Printable_History (Packed_U32.T, Packed_U32.Representation.Image); + package Dropped_Command_History_Package is new Printable_History (Command_Header.T, Command_Header.Representation.Image); + package Invalid_Command_Received_History_Package is new Printable_History (Invalid_Command_Info.T, Invalid_Command_Info.Representation.Image); + + -- Packet history packages: + package Counter_Value_History_Package is new Printable_History (Packed_U32.T, Packed_U32.Representation.Image); + + -- Component class instance: + type Instance is new Component.Counter_Reciprocal.Base_Instance with record + -- The component instance under test: + Component_Instance : aliased Component.Counter.Implementation.Instance; + -- Connector histories: + Command_Response_T_Recv_Sync_History : Command_Response_T_Recv_Sync_History_Package.Instance; + Packet_T_Recv_Sync_History : Packet_T_Recv_Sync_History_Package.Instance; + Event_T_Recv_Sync_History : Event_T_Recv_Sync_History_Package.Instance; + Sys_Time_T_Return_History : Sys_Time_T_Return_History_Package.Instance; + -- Event histories: + Set_Count_Command_Received_History : Set_Count_Command_Received_History_Package.Instance; + Reset_Count_Command_Received_History : Reset_Count_Command_Received_History_Package.Instance; + Set_Count_Add_Command_Received_History : Set_Count_Add_Command_Received_History_Package.Instance; + Sending_Value_History : Sending_Value_History_Package.Instance; + Dropped_Command_History : Dropped_Command_History_Package.Instance; + Invalid_Command_Received_History : Invalid_Command_Received_History_Package.Instance; + -- Packet histories: + Counter_Value_History : Counter_Value_History_Package.Instance; + -- Booleans to control assertion if message is dropped on async queue: + Expect_Command_T_Send_Dropped : Boolean := False; + Command_T_Send_Dropped_Count : Natural := 0; + end record; + type Instance_Access is access all Instance; + + --------------------------------------- + -- Initialize component heap variables: + --------------------------------------- + procedure Init_Base (Self : in out Instance; Queue_Size : in Natural); + procedure Final_Base (Self : in out Instance); + + --------------------------------------- + -- Test initialization functions: + --------------------------------------- + procedure Connect (Self : in out Instance); + + --------------------------------------- + -- Invokee connector primitives: + --------------------------------------- + -- This connector is used to register the components commands with the command router component. + overriding procedure Command_Response_T_Recv_Sync (Self : in out Instance; Arg : in Command_Response.T); + -- The packet invoker connector + overriding procedure Packet_T_Recv_Sync (Self : in out Instance; Arg : in Packet.T); + -- The event send connector + overriding procedure Event_T_Recv_Sync (Self : in out Instance; Arg : in Event.T); + -- The system time is retrieved via this connector. + overriding function Sys_Time_T_Return (Self : in out Instance) return Sys_Time.T; + + --------------------------------------- + -- Invoker connector primitives: + --------------------------------------- + -- This procedure is called when a Command_T_Send message is dropped due to a full queue. + overriding procedure Command_T_Send_Dropped (Self : in out Instance; Arg : in Command.T); + + ----------------------------------------------- + -- Event handler primitive: + ----------------------------------------------- + -- Description: + -- Events for the counter component + -- Received a Set_Count command. + overriding procedure Set_Count_Command_Received (Self : in out Instance; Arg : in Packed_U32.T); + -- Received a Reset_Count command. + overriding procedure Reset_Count_Command_Received (Self : in out Instance); + -- Received a Set_Count_Add command. + overriding procedure Set_Count_Add_Command_Received (Self : in out Instance; Arg : in Operands.T); + -- Sending the current value out as data product. + overriding procedure Sending_Value (Self : in out Instance; Arg : in Packed_U32.T); + -- The component's queue overflowed and the command was dropped. + overriding procedure Dropped_Command (Self : in out Instance; Arg : in Command_Header.T); + -- A command was received with invalid parameters. + overriding procedure Invalid_Command_Received (Self : in out Instance; Arg : in Invalid_Command_Info.T); + + ----------------------------------------------- + -- Packet handler primitives: + ----------------------------------------------- + -- Description: + -- Packets for the counter component + -- The counter value 1. + overriding procedure Counter_Value (Self : in out Instance; Arg : in Packed_U32.T); + + ----------------------------------------------- + -- Special primitives for activating component + -- queue: + ----------------------------------------------- + -- Tell the component to dispatch all items off of its queue: + not overriding function Dispatch_All (Self : in out Instance) return Natural; + -- Tell the component to dispatch n items off of its queue: + not overriding function Dispatch_N (Self : in out Instance; N : in Positive := 1) return Natural; + + --------------------------------------- + -- Auxillery test functions: + --------------------------------------- + function Check_Count (Self : in Instance; Value : in Unsigned_32) return Boolean; + +end Component.Counter.Implementation.Tester; diff --git a/src/components/counter/test/env.py b/src/components/counter/test/env.py new file mode 100644 index 0000000..8d5248e --- /dev/null +++ b/src/components/counter/test/env.py @@ -0,0 +1 @@ +from environments import test # noqa: F401 diff --git a/src/components/counter/test/test.adb b/src/components/counter/test/test.adb new file mode 100644 index 0000000..8432625 --- /dev/null +++ b/src/components/counter/test/test.adb @@ -0,0 +1,23 @@ +-------------------------------------------------------------------------------- +-- Counter Tests +-------------------------------------------------------------------------------- + +with AUnit.Reporter.Text; +with AUnit.Run; +with Tests.Implementation.Suite; +-- Make sure any terminating tasks are handled and an appropriate +-- error message is printed. +with Unit_Test_Termination_Handler; +pragma Unreferenced (Unit_Test_Termination_Handler); + +procedure Test is + -- Create runner for test suite: + procedure Runner is new AUnit.Run.Test_Runner (Tests.Implementation.Suite.Get); + -- Use the text reporter: + Reporter : AUnit.Reporter.Text.Text_Reporter; +begin + -- Add color output to test run: + AUnit.Reporter.Text.Set_Use_ANSI_Colors (Reporter, True); + -- Run tests: + Runner (Reporter); +end Test; diff --git a/src/components/counter/test/tests-implementation.adb b/src/components/counter/test/tests-implementation.adb new file mode 100644 index 0000000..a4fdc04 --- /dev/null +++ b/src/components/counter/test/tests-implementation.adb @@ -0,0 +1,117 @@ +-------------------------------------------------------------------------------- +-- Counter Tests Body +-------------------------------------------------------------------------------- + +-- Custom Includes: +with Component.Counter.Implementation.Tester; +with Counter_Commands; +with Interfaces; use Interfaces; +with Basic_Assertions; use Basic_Assertions; +with Operands.Assertion; use Operands.Assertion; +with Packed_U32.Assertion; use Packed_U32.Assertion; +with AUnit.Assertions; use AUnit.Assertions; + +package body Tests.Implementation is + + ------------------------------------------------------------------------- + -- Fixtures: + ------------------------------------------------------------------------- + + overriding procedure Set_Up_Test (Self : in out Instance) is + begin + -- Allocate heap memory to component: + Self.Tester.Init_Base (Queue_Size => Self.Tester.Component_Instance.Get_Max_Queue_Element_Size * 10); + + -- Make necessary connections between tester and component: + Self.Tester.Connect; + + -- Call the component set up method that the assembly would normally call. + Self.Tester.Component_Instance.Set_Up; + end Set_Up_Test; + + overriding procedure Tear_Down_Test (Self : in out Instance) is + begin + -- Free component heap: + Self.Tester.Final_Base; + end Tear_Down_Test; + + ------------------------------------------------------------------------- + -- Tests: + ------------------------------------------------------------------------- + + -- This unit test excersizes the counter component and makes sure it, well, counts! + overriding procedure Test_1 (Self : in out Instance) is + Value : Packed_U32.T; + begin + -- Invoke the schedule port on the counter and make sure it sends out data products: + Self.Tester.Tick_T_Send ((Time => (1, 1), Count => 1)); + Assert (Self.Tester.Check_Count (1), "Count = 1 failed."); + Self.Tester.Tick_T_Send ((Time => (1, 1), Count => 2)); + Assert (Self.Tester.Check_Count (2), "Count = 2 failed."); + Self.Tester.Tick_T_Send ((Time => (1, 1), Count => 3)); + Assert (Self.Tester.Check_Count (3), "Count = 3 failed."); + + -- Check history and make sure expected data product was sent out by component: + Natural_Assert.Eq (Self.Tester.Packet_T_Recv_Sync_History.Get_Count, 3); + Natural_Assert.Eq (Self.Tester.Counter_Value_History.Get_Count, 3); + Value := Self.Tester.Counter_Value_History.Get (1); + Packed_U32_Assert.Eq (Value, (Value => 1)); + Value := Self.Tester.Counter_Value_History.Get (2); + Packed_U32_Assert.Eq (Value, (Value => 2)); + Value := Self.Tester.Counter_Value_History.Get (3); + Packed_U32_Assert.Eq (Value, (Value => 3)); + end Test_1; + + -- This unit test tests all the commands for the counter component + overriding procedure Test_Commands (Self : in out Instance) is + -- Helper function which sends arbitraty numbers times. + procedure Go is + begin + Self.Tester.Tick_T_Send ((Time => (1, 1), Count => 1)); + end Go; + + -- Helper function which checks 3 values in the history + procedure Check_Val (Val : in Unsigned_32) is + Value : Packed_U32.T; + begin + Assert (Self.Tester.Check_Count (Val), "Count = " & Unsigned_32'Image (Val) & " failed."); + Value := Self.Tester.Counter_Value_History.Get (1); + Packed_U32_Assert.Eq (Value, (Value => Val)); + end Check_Val; + + Commands : Counter_Commands.Instance renames Self.Tester.Commands; + begin + -- Set Count: + Self.Tester.Packet_T_Recv_Sync_History.Clear; + Self.Tester.Counter_Value_History.Clear; + Natural_Assert.Eq (Self.Tester.Set_Count_Command_Received_History.Get_Count, 0); + Self.Tester.Command_T_Send (Commands.Set_Count ((Value => 10))); + Assert (Self.Tester.Check_Count (0), "Count = 1 failed."); + Go; + Check_Val (11); + Natural_Assert.Eq (Self.Tester.Set_Count_Command_Received_History.Get_Count, 1); + Packed_U32_Assert.Eq (Self.Tester.Set_Count_Command_Received_History.Get (1), (Value => 10)); + + -- Set Count Add: + Self.Tester.Packet_T_Recv_Sync_History.Clear; + Self.Tester.Counter_Value_History.Clear; + Natural_Assert.Eq (Self.Tester.Set_Count_Add_Command_Received_History.Get_Count, 0); + Self.Tester.Command_T_Send (Commands.Set_Count_Add (Arg => (10, 11))); + Assert (Self.Tester.Check_Count (11), "Count = 11 failed."); + Go; + Check_Val (22); + Natural_Assert.Eq (Self.Tester.Set_Count_Add_Command_Received_History.Get_Count, 1); + Operands_Assert.Eq (Self.Tester.Set_Count_Add_Command_Received_History.Get (1), (10, 11)); + + -- Reset: + Self.Tester.Packet_T_Recv_Sync_History.Clear; + Self.Tester.Counter_Value_History.Clear; + Natural_Assert.Eq (Self.Tester.Reset_Count_Command_Received_History.Get_Count, 0); + Self.Tester.Command_T_Send (Commands.Reset_Count); + Assert (Self.Tester.Check_Count (22), "Count = 0 failed."); + Go; + Check_Val (1); + Natural_Assert.Eq (Self.Tester.Reset_Count_Command_Received_History.Get_Count, 1); + end Test_Commands; + +end Tests.Implementation; diff --git a/src/components/counter/test/tests-implementation.ads b/src/components/counter/test/tests-implementation.ads new file mode 100644 index 0000000..5274d44 --- /dev/null +++ b/src/components/counter/test/tests-implementation.ads @@ -0,0 +1,26 @@ +-------------------------------------------------------------------------------- +-- Counter Tests Spec +-------------------------------------------------------------------------------- + +-- This is a unit test suite for the counter component +package Tests.Implementation is + + -- Test data and state: + type Instance is new Tests.Base_Instance with private; + type Class_Access is access all Instance'Class; + +private + -- Fixture procedures: + overriding procedure Set_Up_Test (Self : in out Instance); + overriding procedure Tear_Down_Test (Self : in out Instance); + + -- This unit test excersizes the counter component and makes sure it, well, counts! + overriding procedure Test_1 (Self : in out Instance); + -- This unit test tests all the commands for the counter component + overriding procedure Test_Commands (Self : in out Instance); + + -- Test data and state: + type Instance is new Tests.Base_Instance with record + null; + end record; +end Tests.Implementation; diff --git a/src/components/counter/test/tests.counter.tests.yaml b/src/components/counter/test/tests.counter.tests.yaml new file mode 100644 index 0000000..bef9ac7 --- /dev/null +++ b/src/components/counter/test/tests.counter.tests.yaml @@ -0,0 +1,7 @@ +--- +description: This is a unit test suite for the counter component +tests: + - name: Test_1 + description: This unit test excersizes the counter component and makes sure it, well, counts! + - name: Test_Commands + description: This unit test tests all the commands for the counter component diff --git a/src/components/cpp_demo/.all_path b/src/components/cpp_demo/.all_path new file mode 100644 index 0000000..e69de29 diff --git a/src/components/cpp_demo/component-cpp_demo-implementation.adb b/src/components/cpp_demo/component-cpp_demo-implementation.adb new file mode 100644 index 0000000..a9f3eac --- /dev/null +++ b/src/components/cpp_demo/component-cpp_demo-implementation.adb @@ -0,0 +1,40 @@ +-------------------------------------------------------------------------------- +-- Cpp_Demo Component Implementation Body +-------------------------------------------------------------------------------- +with Interfaces.C; use Interfaces.C; use Interfaces; + +package body Component.Cpp_Demo.Implementation is + + -------------------------------------------------- + -- Subprogram for implementation init method: + -------------------------------------------------- + -- The init subprogram used to set the rollover limit for the C++ counter class. + -- + -- Init Parameters: + -- Limit : Interfaces.Unsigned_32 - The limit at which to roll the counter back to + -- zero. + -- + overriding procedure Init (Self : in out Instance; Limit : in Interfaces.Unsigned_32) is + begin + cpp_lib_hpp.Class_Counter.initialize ( + this => Self.Counter'Access, + initialCount => 0, + maxLimit => unsigned (Limit) + ); + end Init; + + --------------------------------------- + -- Invokee connector primitives: + --------------------------------------- + -- The schedule invokee connector + overriding procedure Tick_T_Recv_Sync (Self : in out Instance; Arg : in Tick.T) is + New_Count : constant unsigned := cpp_lib_hpp.Class_Counter.increment ( + this => Self.Counter'Access + ); + begin + Self.Event_T_Send_If_Connected ( + Self.Events.Current_Count (Self.Sys_Time_T_Get, (Value => Unsigned_32 (New_Count))) + ); + end Tick_T_Recv_Sync; + +end Component.Cpp_Demo.Implementation; diff --git a/src/components/cpp_demo/component-cpp_demo-implementation.ads b/src/components/cpp_demo/component-cpp_demo-implementation.ads new file mode 100644 index 0000000..68ec8a8 --- /dev/null +++ b/src/components/cpp_demo/component-cpp_demo-implementation.ads @@ -0,0 +1,58 @@ +-------------------------------------------------------------------------------- +-- Cpp_Demo Component Implementation Spec +-------------------------------------------------------------------------------- + +-- Includes: +with Tick; +with cpp_lib_hpp; + +-- This component demonstrates how to include and use a C++ library within an +-- Adamant component. +package Component.Cpp_Demo.Implementation is + + -- The component class instance record: + type Instance is new Cpp_Demo.Base_Instance with private; + + -------------------------------------------------- + -- Subprogram for implementation init method: + -------------------------------------------------- + -- The init subprogram used to set the rollover limit for the C++ counter class. + -- + -- Init Parameters: + -- Limit : Interfaces.Unsigned_32 - The limit at which to roll the counter back to + -- zero. + -- + overriding procedure Init (Self : in out Instance; Limit : in Interfaces.Unsigned_32); + +private + + -- The component class instance record: + type Instance is new Cpp_Demo.Base_Instance with record + Counter : aliased cpp_lib_hpp.Class_Counter.Counter := cpp_lib_hpp.Class_Counter.New_Counter; + end record; + + --------------------------------------- + -- Set Up Procedure + --------------------------------------- + -- Null method which can be implemented to provide some component + -- set up code. This method is generally called by the assembly + -- main.adb after all component initialization and tasks have been started. + -- Some activities need to only be run once at startup, but cannot be run + -- safely until everything is up and running, ie. command registration, initial + -- data product updates. This procedure should be implemented to do these things + -- if necessary. + overriding procedure Set_Up (Self : in out Instance) is null; + + --------------------------------------- + -- Invokee connector primitives: + --------------------------------------- + -- The schedule invokee connector + overriding procedure Tick_T_Recv_Sync (Self : in out Instance; Arg : in Tick.T); + + --------------------------------------- + -- Invoker connector primitives: + --------------------------------------- + -- This procedure is called when a Event_T_Send message is dropped due to a full queue. + overriding procedure Event_T_Send_Dropped (Self : in out Instance; Arg : in Event.T) is null; + +end Component.Cpp_Demo.Implementation; diff --git a/src/components/cpp_demo/cpp_demo.component.yaml b/src/components/cpp_demo/cpp_demo.component.yaml new file mode 100644 index 0000000..e91e987 --- /dev/null +++ b/src/components/cpp_demo/cpp_demo.component.yaml @@ -0,0 +1,19 @@ +--- +description: This component demonstrates how to include and use a C++ library within an Adamant component. +execution: passive +init: + description: "The init subprogram used to set the rollover limit for the C++ counter class." + parameters: + - name: Limit + type: Interfaces.Unsigned_32 + description: "The limit at which to roll the counter back to zero." +connectors: + - description: The schedule invokee connector + type: Tick.T + kind: recv_sync + - description: The event send connector + type: Event.T + kind: send + - description: The system time is retrieved via this connector. + return_type: Sys_Time.T + kind: get diff --git a/src/components/cpp_demo/cpp_demo.events.yaml b/src/components/cpp_demo/cpp_demo.events.yaml new file mode 100644 index 0000000..4e0a574 --- /dev/null +++ b/src/components/cpp_demo/cpp_demo.events.yaml @@ -0,0 +1,6 @@ +--- +description: Events for the c_demo component +events: + - name: Current_Count + description: Sending the current value out as data product. + param_type: Packed_U32.T diff --git a/src/components/cpp_demo/cpp_lib/.all_path b/src/components/cpp_demo/cpp_lib/.all_path new file mode 100644 index 0000000..e69de29 diff --git a/src/components/cpp_demo/cpp_lib/cpp_dep/.all_path b/src/components/cpp_demo/cpp_lib/cpp_dep/.all_path new file mode 100644 index 0000000..e69de29 diff --git a/src/components/cpp_demo/cpp_lib/cpp_dep/cpp_dep.cpp b/src/components/cpp_demo/cpp_lib/cpp_dep/cpp_dep.cpp new file mode 100644 index 0000000..16aa2ad --- /dev/null +++ b/src/components/cpp_demo/cpp_lib/cpp_dep/cpp_dep.cpp @@ -0,0 +1,11 @@ +#include "cpp_dep.hpp" + +Container::Container() {} + +unsigned int Container::get() { + return value; +} + +void Container::set(unsigned int newValue) { + value = newValue; +} diff --git a/src/components/cpp_demo/cpp_lib/cpp_dep/cpp_dep.hpp b/src/components/cpp_demo/cpp_lib/cpp_dep/cpp_dep.hpp new file mode 100644 index 0000000..2364bb3 --- /dev/null +++ b/src/components/cpp_demo/cpp_lib/cpp_dep/cpp_dep.hpp @@ -0,0 +1,10 @@ + +class Container { +private: + unsigned int value; + +public: + Container(); + unsigned int get(); + void set(unsigned int newValue); +}; diff --git a/src/components/cpp_demo/cpp_lib/cpp_dep/cpp_dep_hpp.ads b/src/components/cpp_demo/cpp_lib/cpp_dep/cpp_dep_hpp.ads new file mode 100644 index 0000000..05576f6 --- /dev/null +++ b/src/components/cpp_demo/cpp_lib/cpp_dep/cpp_dep_hpp.ads @@ -0,0 +1,34 @@ +pragma Ada_2012; + +pragma Style_Checks (Off); +pragma Warnings (Off, "-gnatwu"); + +with Interfaces.C; use Interfaces.C; + +package cpp_dep_hpp is + + package Class_Container is + type Container is limited record + value : aliased unsigned; -- /home/user/example/src/components/cpp_demo/cpp_lib/cpp_dep/cpp_dep.hpp:4 + end record + with Import => True, + Convention => CPP; + + function New_Container return Container; -- /home/user/example/src/components/cpp_demo/cpp_lib/cpp_dep/cpp_dep.hpp:7 + pragma CPP_Constructor (New_Container, "_ZN9ContainerC1Ev"); + + function get (this : access Container) return unsigned -- /home/user/example/src/components/cpp_demo/cpp_lib/cpp_dep/cpp_dep.hpp:8 + with Import => True, + Convention => CPP, + External_Name => "_ZN9Container3getEv"; + + procedure set (this : access Container; newValue : unsigned) -- /home/user/example/src/components/cpp_demo/cpp_lib/cpp_dep/cpp_dep.hpp:9 + with Import => True, + Convention => CPP, + External_Name => "_ZN9Container3setEj"; + end; + use Class_Container; +end cpp_dep_hpp; + +pragma Style_Checks (On); +pragma Warnings (On, "-gnatwu"); diff --git a/src/components/cpp_demo/cpp_lib/cpp_lib.cpp b/src/components/cpp_demo/cpp_lib/cpp_lib.cpp new file mode 100644 index 0000000..869f68e --- /dev/null +++ b/src/components/cpp_demo/cpp_lib/cpp_lib.cpp @@ -0,0 +1,17 @@ +#include "cpp_lib.hpp" + +Counter::Counter () {} + +void Counter::initialize(unsigned int initialCount, unsigned int maxLimit) { + count = initialCount; + limit.set(maxLimit); +} + +unsigned int Counter::increment() { + if (count < limit.get()) { + count++; + } else { + count = 0; + } + return count; +} diff --git a/src/components/cpp_demo/cpp_lib/cpp_lib.hpp b/src/components/cpp_demo/cpp_lib/cpp_lib.hpp new file mode 100644 index 0000000..a404fe9 --- /dev/null +++ b/src/components/cpp_demo/cpp_lib/cpp_lib.hpp @@ -0,0 +1,12 @@ +#include "cpp_dep.hpp" + +class Counter { +private: + unsigned int count; + Container limit; + +public: + Counter(); + void initialize(unsigned int initialCount, unsigned int maxLimit); + unsigned int increment(); +}; diff --git a/src/components/cpp_demo/cpp_lib/cpp_lib_hpp.ads b/src/components/cpp_demo/cpp_lib/cpp_lib_hpp.ads new file mode 100644 index 0000000..4fcef63 --- /dev/null +++ b/src/components/cpp_demo/cpp_lib/cpp_lib_hpp.ads @@ -0,0 +1,39 @@ +pragma Ada_2012; + +pragma Style_Checks (Off); +pragma Warnings (Off, "-gnatwu"); + +with Interfaces.C; use Interfaces.C; +with cpp_dep_hpp; + +package cpp_lib_hpp is + + package Class_Counter is + type Counter is limited record + count : aliased unsigned; -- /home/user/example/src/components/cpp_demo/cpp_lib/cpp_lib.hpp:5 + limit : aliased cpp_dep_hpp.Class_Container.Container; -- /home/user/example/src/components/cpp_demo/cpp_lib/cpp_lib.hpp:6 + end record + with Import => True, + Convention => CPP; + + function New_Counter return Counter; -- /home/user/example/src/components/cpp_demo/cpp_lib/cpp_lib.hpp:9 + pragma CPP_Constructor (New_Counter, "_ZN7CounterC1Ev"); + + procedure initialize + (this : access Counter; + initialCount : unsigned; + maxLimit : unsigned) -- /home/user/example/src/components/cpp_demo/cpp_lib/cpp_lib.hpp:10 + with Import => True, + Convention => CPP, + External_Name => "_ZN7Counter10initializeEjj"; + + function increment (this : access Counter) return unsigned -- /home/user/example/src/components/cpp_demo/cpp_lib/cpp_lib.hpp:11 + with Import => True, + Convention => CPP, + External_Name => "_ZN7Counter9incrementEv"; + end; + use Class_Counter; +end cpp_lib_hpp; + +pragma Style_Checks (On); +pragma Warnings (On, "-gnatwu"); diff --git a/src/components/cpp_demo/test/component-cpp_demo-implementation-tester.adb b/src/components/cpp_demo/test/component-cpp_demo-implementation-tester.adb new file mode 100644 index 0000000..ec5fd6f --- /dev/null +++ b/src/components/cpp_demo/test/component-cpp_demo-implementation-tester.adb @@ -0,0 +1,74 @@ +-------------------------------------------------------------------------------- +-- Cpp_Demo Component Tester Body +-------------------------------------------------------------------------------- + +package body Component.Cpp_Demo.Implementation.Tester is + + --------------------------------------- + -- Initialize heap variables: + --------------------------------------- + procedure Init_Base (Self : in out Instance) is + begin + -- Initialize tester heap: + -- Connector histories: + Self.Event_T_Recv_Sync_History.Init (Depth => 100); + Self.Sys_Time_T_Return_History.Init (Depth => 100); + -- Event histories: + Self.Current_Count_History.Init (Depth => 100); + end Init_Base; + + procedure Final_Base (Self : in out Instance) is + begin + -- Destroy tester heap: + -- Connector histories: + Self.Event_T_Recv_Sync_History.Destroy; + Self.Sys_Time_T_Return_History.Destroy; + -- Event histories: + Self.Current_Count_History.Destroy; + end Final_Base; + + --------------------------------------- + -- Test initialization functions: + --------------------------------------- + procedure Connect (Self : in out Instance) is + begin + Self.Component_Instance.Attach_Event_T_Send (To_Component => Self'Unchecked_Access, Hook => Self.Event_T_Recv_Sync_Access); + Self.Component_Instance.Attach_Sys_Time_T_Get (To_Component => Self'Unchecked_Access, Hook => Self.Sys_Time_T_Return_Access); + Self.Attach_Tick_T_Send (To_Component => Self.Component_Instance'Unchecked_Access, Hook => Self.Component_Instance.Tick_T_Recv_Sync_Access); + end Connect; + + --------------------------------------- + -- Invokee connector primitives: + --------------------------------------- + -- The event send connector + overriding procedure Event_T_Recv_Sync (Self : in out Instance; Arg : in Event.T) is + begin + -- Push the argument onto the test history for looking at later: + Self.Event_T_Recv_Sync_History.Push (Arg); + -- Dispatch the event to the correct handler: + Self.Dispatch_Event (Arg); + end Event_T_Recv_Sync; + + -- The system time is retrieved via this connector. + overriding function Sys_Time_T_Return (Self : in out Instance) return Sys_Time.T is + -- Return the system time: + To_Return : constant Sys_Time.T := Self.System_Time; + begin + -- Push the argument onto the test history for looking at later: + Self.Sys_Time_T_Return_History.Push (To_Return); + return To_Return; + end Sys_Time_T_Return; + + ----------------------------------------------- + -- Event handler primitive: + ----------------------------------------------- + -- Description: + -- Events for the c_demo component + -- Sending the current value out as data product. + overriding procedure Current_Count (Self : in out Instance; Arg : in Packed_U32.T) is + begin + -- Push the argument onto the test history for looking at later: + Self.Current_Count_History.Push (Arg); + end Current_Count; + +end Component.Cpp_Demo.Implementation.Tester; diff --git a/src/components/cpp_demo/test/component-cpp_demo-implementation-tester.ads b/src/components/cpp_demo/test/component-cpp_demo-implementation-tester.ads new file mode 100644 index 0000000..17c4c52 --- /dev/null +++ b/src/components/cpp_demo/test/component-cpp_demo-implementation-tester.ads @@ -0,0 +1,64 @@ +-------------------------------------------------------------------------------- +-- Cpp_Demo Component Tester Spec +-------------------------------------------------------------------------------- + +-- Includes: +with Component.Cpp_Demo_Reciprocal; +with Printable_History; +with Event.Representation; +with Sys_Time.Representation; +with Event; +with Packed_U32.Representation; + +-- This component demonstrates how to include and use a C++ library within an +-- Adamant component. +package Component.Cpp_Demo.Implementation.Tester is + + use Component.Cpp_Demo_Reciprocal; + -- Invoker connector history packages: + package Event_T_Recv_Sync_History_Package is new Printable_History (Event.T, Event.Representation.Image); + package Sys_Time_T_Return_History_Package is new Printable_History (Sys_Time.T, Sys_Time.Representation.Image); + + -- Event history packages: + package Current_Count_History_Package is new Printable_History (Packed_U32.T, Packed_U32.Representation.Image); + + -- Component class instance: + type Instance is new Component.Cpp_Demo_Reciprocal.Base_Instance with record + -- The component instance under test: + Component_Instance : aliased Component.Cpp_Demo.Implementation.Instance; + -- Connector histories: + Event_T_Recv_Sync_History : Event_T_Recv_Sync_History_Package.Instance; + Sys_Time_T_Return_History : Sys_Time_T_Return_History_Package.Instance; + -- Event histories: + Current_Count_History : Current_Count_History_Package.Instance; + end record; + type Instance_Access is access all Instance; + + --------------------------------------- + -- Initialize component heap variables: + --------------------------------------- + procedure Init_Base (Self : in out Instance); + procedure Final_Base (Self : in out Instance); + + --------------------------------------- + -- Test initialization functions: + --------------------------------------- + procedure Connect (Self : in out Instance); + + --------------------------------------- + -- Invokee connector primitives: + --------------------------------------- + -- The event send connector + overriding procedure Event_T_Recv_Sync (Self : in out Instance; Arg : in Event.T); + -- The system time is retrieved via this connector. + overriding function Sys_Time_T_Return (Self : in out Instance) return Sys_Time.T; + + ----------------------------------------------- + -- Event handler primitive: + ----------------------------------------------- + -- Description: + -- Events for the c_demo component + -- Sending the current value out as data product. + overriding procedure Current_Count (Self : in out Instance; Arg : in Packed_U32.T); + +end Component.Cpp_Demo.Implementation.Tester; diff --git a/src/components/cpp_demo/test/env.py b/src/components/cpp_demo/test/env.py new file mode 100644 index 0000000..8d5248e --- /dev/null +++ b/src/components/cpp_demo/test/env.py @@ -0,0 +1 @@ +from environments import test # noqa: F401 diff --git a/src/components/cpp_demo/test/test.adb b/src/components/cpp_demo/test/test.adb new file mode 100644 index 0000000..d28ecde --- /dev/null +++ b/src/components/cpp_demo/test/test.adb @@ -0,0 +1,23 @@ +-------------------------------------------------------------------------------- +-- Cpp_Demo Tests +-------------------------------------------------------------------------------- + +with AUnit.Reporter.Text; +with AUnit.Run; +with Tests.Implementation.Suite; +-- Make sure any terminating tasks are handled and an appropriate +-- error message is printed. +with Unit_Test_Termination_Handler; +pragma Unreferenced (Unit_Test_Termination_Handler); + +procedure Test is + -- Create runner for test suite: + procedure Runner is new AUnit.Run.Test_Runner (Tests.Implementation.Suite.Get); + -- Use the text reporter: + Reporter : AUnit.Reporter.Text.Text_Reporter; +begin + -- Add color output to test run: + AUnit.Reporter.Text.Set_Use_ANSI_Colors (Reporter, True); + -- Run tests: + Runner (Reporter); +end Test; diff --git a/src/components/cpp_demo/test/tests-implementation.adb b/src/components/cpp_demo/test/tests-implementation.adb new file mode 100644 index 0000000..04d3eb4 --- /dev/null +++ b/src/components/cpp_demo/test/tests-implementation.adb @@ -0,0 +1,69 @@ +-------------------------------------------------------------------------------- +-- Cpp_Demo Tests Body +-------------------------------------------------------------------------------- + +with Packed_U32.Assertion; use Packed_U32.Assertion; +with Basic_Assertions; use Basic_Assertions; + +package body Tests.Implementation is + + ------------------------------------------------------------------------- + -- Fixtures: + ------------------------------------------------------------------------- + + overriding procedure Set_Up_Test (Self : in out Instance) is + begin + -- Allocate heap memory to component: + Self.Tester.Init_Base; + + -- Make necessary connections between tester and component: + Self.Tester.Connect; + + -- Call component init here. + Self.Tester.Component_Instance.Init (Limit => 3); + + -- Call the component set up method that the assembly would normally call. + Self.Tester.Component_Instance.Set_Up; + end Set_Up_Test; + + overriding procedure Tear_Down_Test (Self : in out Instance) is + begin + -- Free component heap: + Self.Tester.Final_Base; + end Tear_Down_Test; + + ------------------------------------------------------------------------- + -- Tests: + ------------------------------------------------------------------------- + + -- This unit test excersizes the c_demo component and makes sure it works + -- correctly. + overriding procedure Test_Cpp (Self : in out Instance) is + T : Component.Cpp_Demo.Implementation.Tester.Instance_Access renames Self.Tester; + begin + -- Send tick and verify increment + T.Tick_T_Send ((Time => (1, 1), Count => 1)); + Natural_Assert.Eq (T.Event_T_Recv_Sync_History.Get_Count, 1); + Natural_Assert.Eq (T.Current_Count_History.Get_Count, 1); + Packed_U32_Assert.Eq (T.Current_Count_History.Get (1), (Value => 1)); + + -- Send tick and verify increment + T.Tick_T_Send ((Time => (1, 1), Count => 2)); + Natural_Assert.Eq (T.Event_T_Recv_Sync_History.Get_Count, 2); + Natural_Assert.Eq (T.Current_Count_History.Get_Count, 2); + Packed_U32_Assert.Eq (T.Current_Count_History.Get (2), (Value => 2)); + + -- Send tick and verify increment + T.Tick_T_Send ((Time => (1, 1), Count => 2)); + Natural_Assert.Eq (T.Event_T_Recv_Sync_History.Get_Count, 3); + Natural_Assert.Eq (T.Current_Count_History.Get_Count, 3); + Packed_U32_Assert.Eq (T.Current_Count_History.Get (3), (Value => 3)); + + -- Send tick and verify increment + T.Tick_T_Send ((Time => (1, 1), Count => 2)); + Natural_Assert.Eq (T.Event_T_Recv_Sync_History.Get_Count, 4); + Natural_Assert.Eq (T.Current_Count_History.Get_Count, 4); + Packed_U32_Assert.Eq (T.Current_Count_History.Get (4), (Value => 0)); + end Test_Cpp; + +end Tests.Implementation; diff --git a/src/components/cpp_demo/test/tests-implementation.ads b/src/components/cpp_demo/test/tests-implementation.ads new file mode 100644 index 0000000..e47a4cf --- /dev/null +++ b/src/components/cpp_demo/test/tests-implementation.ads @@ -0,0 +1,25 @@ +-------------------------------------------------------------------------------- +-- Cpp_Demo Tests Spec +-------------------------------------------------------------------------------- + +-- This is a unit test suite for the c_demo component. +package Tests.Implementation is + + -- Test data and state: + type Instance is new Tests.Base_Instance with private; + type Class_Access is access all Instance'Class; + +private + -- Fixture procedures: + overriding procedure Set_Up_Test (Self : in out Instance); + overriding procedure Tear_Down_Test (Self : in out Instance); + + -- This unit test excersizes the c_demo component and makes sure it works + -- correctly. + overriding procedure Test_Cpp (Self : in out Instance); + + -- Test data and state: + type Instance is new Tests.Base_Instance with record + null; + end record; +end Tests.Implementation; diff --git a/src/components/cpp_demo/test/tests.cpp_demo.tests.yaml b/src/components/cpp_demo/test/tests.cpp_demo.tests.yaml new file mode 100644 index 0000000..c783931 --- /dev/null +++ b/src/components/cpp_demo/test/tests.cpp_demo.tests.yaml @@ -0,0 +1,5 @@ +--- +description: This is a unit test suite for the cpp_demo component. +tests: + - name: Test_Cpp + description: This unit test excersizes the cpp_demo component and makes sure it works correctly. diff --git a/src/components/fault_producer/.all_path b/src/components/fault_producer/.all_path new file mode 100644 index 0000000..e69de29 diff --git a/src/components/fault_producer/component-fault_producer-implementation.adb b/src/components/fault_producer/component-fault_producer-implementation.adb new file mode 100644 index 0000000..d13f3e1 --- /dev/null +++ b/src/components/fault_producer/component-fault_producer-implementation.adb @@ -0,0 +1,54 @@ +-------------------------------------------------------------------------------- +-- Fault_Producer Component Implementation Body +-------------------------------------------------------------------------------- + +package body Component.Fault_Producer.Implementation is + + --------------------------------------- + -- Invokee connector primitives: + --------------------------------------- + -- The command receive connector. + overriding procedure Command_T_Recv_Sync (Self : in out Instance; Arg : in Command.T) is + -- Execute the command: + Stat : constant Command_Response_Status.E := Self.Execute_Command (Arg); + begin + -- Send the return status: + Self.Command_Response_T_Send_If_Connected ((Source_Id => Arg.Header.Source_Id, Registration_Id => Self.Command_Reg_Id, Command_Id => Arg.Header.Id, Status => Stat)); + end Command_T_Recv_Sync; + + ----------------------------------------------- + -- Command handler primitives: + ----------------------------------------------- + -- Description: + -- Commands for the fault producer component + -- Throw the first fault. + overriding function Throw_Fault_1 (Self : in out Instance) return Command_Execution_Status.E is + use Command_Execution_Status; + begin + -- Send event and fault: + Self.Event_T_Send_If_Connected (Self.Events.Sending_Fault_1 (Self.Sys_Time_T_Get)); + Self.Fault_T_Send_If_Connected (Self.Faults.Fault_1 (Self.Sys_Time_T_Get)); + return Success; + end Throw_Fault_1; + + -- Throw the second fault. + overriding function Throw_Fault_2 (Self : in out Instance) return Command_Execution_Status.E is + use Command_Execution_Status; + begin + -- Send event and fault: + Self.Event_T_Send_If_Connected (Self.Events.Sending_Fault_2 (Self.Sys_Time_T_Get)); + Self.Fault_T_Send_If_Connected (Self.Faults.Fault_2 (Self.Sys_Time_T_Get, (Value => 99))); + return Success; + end Throw_Fault_2; + + -- Invalid command handler. This procedure is called when a command's arguments are found to be invalid: + overriding procedure Invalid_Command (Self : in out Instance; Cmd : in Command.T; Errant_Field_Number : in Unsigned_32; Errant_Field : in Basic_Types.Poly_Type) is + begin + -- Throw event: + Self.Event_T_Send_If_Connected (Self.Events.Invalid_Command_Received ( + Self.Sys_Time_T_Get, + (Id => Cmd.Header.Id, Errant_Field_Number => Errant_Field_Number, Errant_Field => Errant_Field) + )); + end Invalid_Command; + +end Component.Fault_Producer.Implementation; diff --git a/src/components/fault_producer/component-fault_producer-implementation.ads b/src/components/fault_producer/component-fault_producer-implementation.ads new file mode 100644 index 0000000..9c566d5 --- /dev/null +++ b/src/components/fault_producer/component-fault_producer-implementation.ads @@ -0,0 +1,62 @@ +-------------------------------------------------------------------------------- +-- Fault_Producer Component Implementation Spec +-------------------------------------------------------------------------------- + +-- Includes: +with Command; + +-- This is the fault producer component. It allows you to simulate a fault being triggered in the system by throwing a fault upon command. +package Component.Fault_Producer.Implementation is + + -- The component class instance record: + type Instance is new Fault_Producer.Base_Instance with private; + +private + + -- The component class instance record: + type Instance is new Fault_Producer.Base_Instance with record + null; + end record; + + --------------------------------------- + -- Set Up Procedure + --------------------------------------- + -- Null method which can be implemented to provide some component + -- set up code. This method is generally called by the assembly + -- main.adb after all component initialization and tasks have been started. + -- Some activities need to only be run once at startup, but cannot be run + -- safely until everything is up and running, ie. command registration, initial + -- data product updates. This procedure should be implemented to do these things + -- if necessary. + overriding procedure Set_Up (Self : in out Instance) is null; + + --------------------------------------- + -- Invokee connector primitives: + --------------------------------------- + -- The command receive connector. + overriding procedure Command_T_Recv_Sync (Self : in out Instance; Arg : in Command.T); + + --------------------------------------- + -- Invoker connector primitives: + --------------------------------------- + -- This procedure is called when a Command_Response_T_Send message is dropped due to a full queue. + overriding procedure Command_Response_T_Send_Dropped (Self : in out Instance; Arg : in Command_Response.T) is null; + -- This procedure is called when a Event_T_Send message is dropped due to a full queue. + overriding procedure Event_T_Send_Dropped (Self : in out Instance; Arg : in Event.T) is null; + -- This procedure is called when a Fault_T_Send message is dropped due to a full queue. + overriding procedure Fault_T_Send_Dropped (Self : in out Instance; Arg : in Fault.T) is null; + + ----------------------------------------------- + -- Command handler primitives: + ----------------------------------------------- + -- Description: + -- Commands for the fault producer component + -- Throw the first fault. + overriding function Throw_Fault_1 (Self : in out Instance) return Command_Execution_Status.E; + -- Throw the second fault. + overriding function Throw_Fault_2 (Self : in out Instance) return Command_Execution_Status.E; + + -- Invalid command handler. This procedure is called when a command's arguments are found to be invalid: + overriding procedure Invalid_Command (Self : in out Instance; Cmd : in Command.T; Errant_Field_Number : in Unsigned_32; Errant_Field : in Basic_Types.Poly_Type); + +end Component.Fault_Producer.Implementation; diff --git a/src/components/fault_producer/doc/fault_producer.pdf b/src/components/fault_producer/doc/fault_producer.pdf new file mode 100644 index 0000000..87cf18d Binary files /dev/null and b/src/components/fault_producer/doc/fault_producer.pdf differ diff --git a/src/components/fault_producer/doc/fault_producer.tex b/src/components/fault_producer/doc/fault_producer.tex new file mode 100644 index 0000000..d3a4698 --- /dev/null +++ b/src/components/fault_producer/doc/fault_producer.tex @@ -0,0 +1,83 @@ +\input{common_packages.tex} + +\begin{document} + +\title{\textbf{Fault Producer} \\ +\large\textit{Component Design Document}} +\date{} +\maketitle + +\section{Description} +\input{build/tex/fault_producer_description.tex} + +\section{Requirements} +\input{build/tex/fault_producer_requirements.tex} + +\section{Design} + +\subsection{At a Glance} +\input{build/tex/fault_producer_stats.tex} + +\subsection{Diagram} +\begin{figure}[H] + \includegraphics[width=1.0\textwidth,center]{../build/eps/fault_producer.eps} + \caption{Fault Producer component diagram.} +\end{figure} + +\subsection{Connectors} +\input{build/tex/fault_producer_connectors.tex} + +\subsection{Interrupts} + +\input{build/tex/fault_producer_interrupts.tex} + +\subsection{Initialization} +\input{build/tex/fault_producer_init.tex} + +\subsection{Commands} + +\input{build/tex/fault_producer_commands.tex} + +\subsection{Parameters} + +\input{build/tex/fault_producer_parameters.tex} + +\subsection{Events} + +\input{build/tex/fault_producer_events.tex} + +\subsection{Data Products} + +\input{build/tex/fault_producer_data_products.tex} + +\subsection{Data Dependencies} + +\input{build/tex/fault_producer_data_dependencies.tex} + +\subsection{Packets} + +\input{build/tex/fault_producer_packets.tex} + +\subsection{Faults} + +\input{build/tex/fault_producer_faults.tex} + +\section{Unit Tests} + +\input{build/tex/fault_producer_unit_test.tex} + +\section{Appendix} + +\subsection{Preamble} + +\input{build/tex/fault_producer_preamble.tex} + +\subsection{Packed Types} + +\input{build/tex/fault_producer_types.tex} + +\subsection{Enumerations} + +\input{build/tex/fault_producer_enums.tex} + +\end{document} diff --git a/src/components/fault_producer/fault_producer.commands.yaml b/src/components/fault_producer/fault_producer.commands.yaml new file mode 100644 index 0000000..2602818 --- /dev/null +++ b/src/components/fault_producer/fault_producer.commands.yaml @@ -0,0 +1,7 @@ +--- +description: Commands for the fault producer component +commands: + - name: Throw_Fault_1 + description: Throw the first fault. + - name: Throw_Fault_2 + description: Throw the second fault. diff --git a/src/components/fault_producer/fault_producer.component.yaml b/src/components/fault_producer/fault_producer.component.yaml new file mode 100644 index 0000000..def8a22 --- /dev/null +++ b/src/components/fault_producer/fault_producer.component.yaml @@ -0,0 +1,19 @@ +--- +description: This is the fault producer component. It allows you to simulate a fault being triggered in the system by throwing a fault upon command. +execution: passive +connectors: + - description: The command receive connector. + type: Command.T + kind: recv_sync + - description: This connector is used to register the components commands with the command router component. + type: Command_Response.T + kind: send + - description: The event send connector + type: Event.T + kind: send + - description: The fault send connector + type: Fault.T + kind: send + - description: The system time is retrieved via this connector. + return_type: Sys_Time.T + kind: get diff --git a/src/components/fault_producer/fault_producer.events.yaml b/src/components/fault_producer/fault_producer.events.yaml new file mode 100644 index 0000000..947928c --- /dev/null +++ b/src/components/fault_producer/fault_producer.events.yaml @@ -0,0 +1,10 @@ +--- +description: Events for the fault producer component +events: + - name: Sending_Fault_1 + description: The component received a command to send out fault 1. + - name: Sending_Fault_2 + description: The component received a command to send out fault 2. + - name: Invalid_Command_Received + description: A command was received with invalid parameters. + param_type: Invalid_Command_Info.T diff --git a/src/components/fault_producer/fault_producer.faults.yaml b/src/components/fault_producer/fault_producer.faults.yaml new file mode 100644 index 0000000..4bd8478 --- /dev/null +++ b/src/components/fault_producer/fault_producer.faults.yaml @@ -0,0 +1,8 @@ +--- +description: Faults for the fault producer component +faults: + - name: Fault_1 + description: First fault that the component can send. + - name: Fault_2 + description: Second fault that the component can send. + param_type: Packed_Natural.T diff --git a/src/components/interrupt_responder/.all_path b/src/components/interrupt_responder/.all_path new file mode 100644 index 0000000..e69de29 diff --git a/src/components/interrupt_responder/component-interrupt_responder-implementation.adb b/src/components/interrupt_responder/component-interrupt_responder-implementation.adb new file mode 100644 index 0000000..5b0ef07 --- /dev/null +++ b/src/components/interrupt_responder/component-interrupt_responder-implementation.adb @@ -0,0 +1,20 @@ +-------------------------------------------------------------------------------- +-- Interrupt_Responder Component Implementation Body +-------------------------------------------------------------------------------- + +with Interrupt_Action; + +package body Component.Interrupt_Responder.Implementation is + + --------------------------------------- + -- Invokee connector primitives: + --------------------------------------- + -- The schedule invokee connector + overriding procedure Tick_T_Recv_Sync (Self : in out Instance; Arg : in Tick.T) is + Ignore : Instance renames Self; + begin + -- Call the interrupt action: + Interrupt_Action.Do_Action (Arg); + end Tick_T_Recv_Sync; + +end Component.Interrupt_Responder.Implementation; diff --git a/src/components/interrupt_responder/component-interrupt_responder-implementation.ads b/src/components/interrupt_responder/component-interrupt_responder-implementation.ads new file mode 100644 index 0000000..ba4b405 --- /dev/null +++ b/src/components/interrupt_responder/component-interrupt_responder-implementation.ads @@ -0,0 +1,45 @@ +-------------------------------------------------------------------------------- +-- Interrupt_Responder Component Implementation Spec +-------------------------------------------------------------------------------- + +-- Includes: +with Tick; + +-- This is the Interrupt Responder component. +package Component.Interrupt_Responder.Implementation is + + -- The component class instance record: + type Instance is new Interrupt_Responder.Base_Instance with private; + +private + + -- The component class instance record: + type Instance is new Interrupt_Responder.Base_Instance with record + null; + end record; + + --------------------------------------- + -- Set Up Procedure + --------------------------------------- + -- Null method which can be implemented to provide some component + -- set up code. This method is generally called by the assembly + -- main.adb after all component initialization and tasks have been started. + -- Some activities need to only be run once at startup, but cannot be run + -- safely until everything is up and running, ie. command registration, initial + -- data product updates. This procedure should be implemented to do these things + -- if necessary. + overriding procedure Set_Up (Self : in out Instance) is null; + + --------------------------------------- + -- Invokee connector primitives: + --------------------------------------- + -- The schedule invokee connector + overriding procedure Tick_T_Recv_Sync (Self : in out Instance; Arg : in Tick.T); + + --------------------------------------- + -- Invoker connector primitives: + --------------------------------------- + -- This procedure is called when a Event_T_Send message is dropped due to a full queue. + overriding procedure Event_T_Send_Dropped (Self : in out Instance; Arg : in Event.T) is null; + +end Component.Interrupt_Responder.Implementation; diff --git a/src/components/interrupt_responder/doc/interrupt_responder.pdf b/src/components/interrupt_responder/doc/interrupt_responder.pdf new file mode 100644 index 0000000..529ebb5 Binary files /dev/null and b/src/components/interrupt_responder/doc/interrupt_responder.pdf differ diff --git a/src/components/interrupt_responder/doc/interrupt_responder.tex b/src/components/interrupt_responder/doc/interrupt_responder.tex new file mode 100644 index 0000000..4b5c02f --- /dev/null +++ b/src/components/interrupt_responder/doc/interrupt_responder.tex @@ -0,0 +1,83 @@ +\input{common_packages.tex} + +\begin{document} + +\title{\textbf{Interrupt Responder} \\ +\large\textit{Component Design Document}} +\date{} +\maketitle + +\section{Description} +\input{build/tex/interrupt_responder_description.tex} + +\section{Requirements} +\input{build/tex/interrupt_responder_requirements.tex} + +\section{Design} + +\subsection{At a Glance} +\input{build/tex/interrupt_responder_stats.tex} + +\subsection{Diagram} +\begin{figure}[H] + \includegraphics[width=1.0\textwidth,center]{../build/eps/interrupt_responder.eps} + \caption{Interrupt Responder component diagram.} +\end{figure} + +\subsection{Connectors} +\input{build/tex/interrupt_responder_connectors.tex} + +\subsection{Interrupts} + +\input{build/tex/interrupt_responder_interrupts.tex} + +\subsection{Initialization} +\input{build/tex/interrupt_responder_init.tex} + +\subsection{Commands} + +\input{build/tex/interrupt_responder_commands.tex} + +\subsection{Parameters} + +\input{build/tex/interrupt_responder_parameters.tex} + +\subsection{Events} + +\input{build/tex/interrupt_responder_events.tex} + +\subsection{Data Products} + +\input{build/tex/interrupt_responder_data_products.tex} + +\subsection{Data Dependencies} + +\input{build/tex/interrupt_responder_data_dependencies.tex} + +\subsection{Packets} + +\input{build/tex/interrupt_responder_packets.tex} + +\subsection{Faults} + +\input{build/tex/interrupt_responder_faults.tex} + +\section{Unit Tests} + +\input{build/tex/interrupt_responder_unit_test.tex} + +\section{Appendix} + +\subsection{Preamble} + +\input{build/tex/interrupt_responder_preamble.tex} + +\subsection{Packed Types} + +\input{build/tex/interrupt_responder_types.tex} + +\subsection{Enumerations} + +\input{build/tex/interrupt_responder_enums.tex} + +\end{document} diff --git a/src/components/interrupt_responder/interrupt_action/.all_path b/src/components/interrupt_responder/interrupt_action/.all_path new file mode 100644 index 0000000..e69de29 diff --git a/src/components/interrupt_responder/interrupt_action/interrupt_action.ads b/src/components/interrupt_responder/interrupt_action/interrupt_action.ads new file mode 100644 index 0000000..876efec --- /dev/null +++ b/src/components/interrupt_responder/interrupt_action/interrupt_action.ads @@ -0,0 +1,5 @@ +with Tick; +package Interrupt_Action is + pragma Elaborate_Body; + procedure Do_Action (The_Tick : in Tick.T); +end Interrupt_Action; diff --git a/src/components/interrupt_responder/interrupt_action/linux/.Linux_path b/src/components/interrupt_responder/interrupt_action/linux/.Linux_path new file mode 100644 index 0000000..e69de29 diff --git a/src/components/interrupt_responder/interrupt_action/linux/interrupt_action.adb b/src/components/interrupt_responder/interrupt_action/linux/interrupt_action.adb new file mode 100644 index 0000000..618e2c0 --- /dev/null +++ b/src/components/interrupt_responder/interrupt_action/linux/interrupt_action.adb @@ -0,0 +1,10 @@ +with Ada.Text_IO; use Ada.Text_IO; +with Tick.Representation; + +package body Interrupt_Action is + procedure Do_Action (The_Tick : in Tick.T) is + begin + Put_Line ("Interrupt received: "); + Put_Line (Tick.Representation.Image (The_Tick)); + end Do_Action; +end Interrupt_Action; diff --git a/src/components/interrupt_responder/interrupt_action/pico/.Pico_path b/src/components/interrupt_responder/interrupt_action/pico/.Pico_path new file mode 100644 index 0000000..e69de29 diff --git a/src/components/interrupt_responder/interrupt_action/pico/env.py b/src/components/interrupt_responder/interrupt_action/pico/env.py new file mode 100644 index 0000000..d9cba61 --- /dev/null +++ b/src/components/interrupt_responder/interrupt_action/pico/env.py @@ -0,0 +1 @@ +from environments import pico # noqa: F401 diff --git a/src/components/interrupt_responder/interrupt_action/pico/interrupt_action.adb b/src/components/interrupt_responder/interrupt_action/pico/interrupt_action.adb new file mode 100644 index 0000000..c227104 --- /dev/null +++ b/src/components/interrupt_responder/interrupt_action/pico/interrupt_action.adb @@ -0,0 +1,12 @@ +-- with Ada.Real_Time; use Ada.Real_Time; + +package body Interrupt_Action is + + procedure Do_Action (The_Tick : Tick.T) is + Ignore : Tick.T renames The_Tick; + -- Now : constant Time := Clock; + begin + null; + end Do_Action; + +end Interrupt_Action; diff --git a/src/components/interrupt_responder/interrupt_responder.component.yaml b/src/components/interrupt_responder/interrupt_responder.component.yaml new file mode 100644 index 0000000..f9e6321 --- /dev/null +++ b/src/components/interrupt_responder/interrupt_responder.component.yaml @@ -0,0 +1,13 @@ +--- +description: This is the Interrupt Responder component. +execution: passive +connectors: + - description: The schedule invokee connector + type: Tick.T + kind: recv_sync + - description: The event send connector + type: Event.T + kind: send + - description: The system time is retrieved via this connector. + return_type: Sys_Time.T + kind: get diff --git a/src/components/interrupt_responder/interrupt_responder.events.yaml b/src/components/interrupt_responder/interrupt_responder.events.yaml new file mode 100644 index 0000000..1bca9fa --- /dev/null +++ b/src/components/interrupt_responder/interrupt_responder.events.yaml @@ -0,0 +1,6 @@ +--- +description: Events for the interrupt response component. +events: + - name: Interrupt_Received + description: Received an interrupt. + param_type: Tick.T diff --git a/src/components/oscillator/.all_path b/src/components/oscillator/.all_path new file mode 100644 index 0000000..e69de29 diff --git a/src/components/oscillator/component-oscillator-implementation.adb b/src/components/oscillator/component-oscillator-implementation.adb new file mode 100644 index 0000000..c464a7d --- /dev/null +++ b/src/components/oscillator/component-oscillator-implementation.adb @@ -0,0 +1,131 @@ +-------------------------------------------------------------------------------- +-- Oscillator Component Implementation Body +-------------------------------------------------------------------------------- + +with Packed_F32; +with Ada.Numerics.Generic_Elementary_Functions; +with Sys_Time.Arithmetic; +with Ada.Real_Time; + +package body Component.Oscillator.Implementation is + + --------------------------------------- + -- Invokee connector primitives: + --------------------------------------- + -- The schedule invokee connector + overriding procedure Tick_T_Recv_Sync (Self : in out Instance; Arg : in Tick.T) is + use Ada.Numerics; + use Sys_Time; + use Sys_Time.Arithmetic; + use Ada.Real_Time; + + Float_Time : Short_Float; + Data : Packed_F32.T; + Time_Diff : Time_Span; + Ignore : Natural; + package Float_Functions is new Generic_Elementary_Functions (Short_Float); + begin + -- Update the parameters: + Self.Update_Parameters; + + -- Service the queue for commands: + Ignore := Self.Dispatch_All; + + -- Set the epoch if this is the first time receiving a tick: + if Self.Epoch = (0, 0) then + Self.Epoch := Arg.Time; + end if; + + -- Calculate the time delta since the epoch: + Time_Diff := Arg.Time - Self.Epoch; + Float_Time := Short_Float (To_Duration (Time_Diff)); + + -- Calculate the value of the oscillator based on the timestamp given in the tick: + Data.Value := Self.Offset.Value + Self.Amplitude.Value * Float_Functions.Sin (2.0 * Pi * Self.Frequency.Value * Float_Time); + + -- Send the value out as data product: + Self.Data_Product_T_Send (Self.Data_Products.Oscillator_Value (Self.Sys_Time_T_Get, Data)); + end Tick_T_Recv_Sync; + + -- The command receive connector + overriding procedure Command_T_Recv_Async (Self : in out Instance; Arg : in Command.T) is + -- Execute the command: + Stat : constant Command_Response_Status.E := Self.Execute_Command (Arg); + begin + -- Send the return status: + Self.Command_Response_T_Send_If_Connected ((Source_Id => Arg.Header.Source_Id, Registration_Id => Self.Command_Reg_Id, Command_Id => Arg.Header.Id, Status => Stat)); + end Command_T_Recv_Async; + + -- The parameter update connector. + overriding procedure Parameter_Update_T_Modify (Self : in out Instance; Arg : in out Parameter_Update.T) is + begin + -- Process the parameter update, staging or fetching parameters as requested. + Self.Process_Parameter_Update (Arg); + end Parameter_Update_T_Modify; + + -- This procedure is called when a Command_T_Recv_Async message is dropped due to a full queue. + overriding procedure Command_T_Recv_Async_Dropped (Self : in out Instance; Arg : in Command.T) is + begin + -- Throw event: + Self.Event_T_Send_If_Connected (Self.Events.Dropped_Command ( + Self.Sys_Time_T_Get, Arg.Header + )); + end Command_T_Recv_Async_Dropped; + + ----------------------------------------------- + -- Command handler primitives: + ----------------------------------------------- + -- Description: + -- Commands for the Oscillator component + -- Set the frequency of the oscillator in Hz + overriding function Set_Frequency (Self : in out Instance; Arg : in Packed_F32.T) return Command_Execution_Status.E is use Command_Execution_Status; + begin + Self.Frequency.Value := Arg.Value; + Self.Event_T_Send (Self.Events.Frequency_Value_Set (Self.Sys_Time_T_Get, Arg)); + return Success; + end Set_Frequency; + + -- Set the amplitude of the oscillator + overriding function Set_Amplitude (Self : in out Instance; Arg : in Packed_F32.T) return Command_Execution_Status.E is + use Command_Execution_Status; + begin + Self.Amplitude.Value := Arg.Value; + Self.Event_T_Send (Self.Events.Amplitude_Value_Set (Self.Sys_Time_T_Get, Arg)); + return Success; + end Set_Amplitude; + + -- Set the Y offset of the oscillator + overriding function Set_Offset (Self : in out Instance; Arg : in Packed_F32.T) return Command_Execution_Status.E is + use Command_Execution_Status; + begin + Self.Offset.Value := Arg.Value; + Self.Event_T_Send (Self.Events.Offset_Value_Set (Self.Sys_Time_T_Get, Arg)); + return Success; + end Set_Offset; + + -- Invalid command handler. This procedure is called when a command's arguments are found to be invalid: + overriding procedure Invalid_Command (Self : in out Instance; Cmd : in Command.T; Errant_Field_Number : in Unsigned_32; Errant_Field : in Basic_Types.Poly_Type) is + begin + -- Throw event: + Self.Event_T_Send_If_Connected (Self.Events.Invalid_Command_Received ( + Self.Sys_Time_T_Get, + (Id => Cmd.Header.Id, Errant_Field_Number => Errant_Field_Number, Errant_Field => Errant_Field) + )); + end Invalid_Command; + + ----------------------------------------------- + -- Parameter handlers: + ----------------------------------------------- + -- Description: + -- Parameters for the Oscillator component + -- Invalid Parameter handler. This procedure is called when a parameter's type is found to be invalid: + overriding procedure Invalid_Parameter (Self : in out Instance; Par : in Parameter.T; Errant_Field_Number : in Unsigned_32; Errant_Field : in Basic_Types.Poly_Type) is + begin + -- Throw event: + Self.Event_T_Send_If_Connected (Self.Events.Invalid_Parameter_Received ( + Self.Sys_Time_T_Get, + (Id => Par.Header.Id, Errant_Field_Number => Errant_Field_Number, Errant_Field => Errant_Field) + )); + end Invalid_Parameter; + +end Component.Oscillator.Implementation; diff --git a/src/components/oscillator/component-oscillator-implementation.ads b/src/components/oscillator/component-oscillator-implementation.ads new file mode 100644 index 0000000..34188e6 --- /dev/null +++ b/src/components/oscillator/component-oscillator-implementation.ads @@ -0,0 +1,87 @@ +-------------------------------------------------------------------------------- +-- Oscillator Component Implementation Spec +-------------------------------------------------------------------------------- + +-- Includes: +with Tick; +with Command; +with Parameter_Update; + +-- This is the oscillator component. +package Component.Oscillator.Implementation is + + -- The component class instance record: + type Instance is new Oscillator.Base_Instance with private; + +private + + -- The component class instance record: + type Instance is new Oscillator.Base_Instance with record + Epoch : Sys_Time.T := (0, 0); + end record; + + --------------------------------------- + -- Set Up Procedure + --------------------------------------- + -- Null method which can be implemented to provide some component + -- set up code. This method is generally called by the assembly + -- main.adb after all component initialization and tasks have been started. + -- Some activities need to only be run once at startup, but cannot be run + -- safely until everything is up and running, ie. command registration, initial + -- data product updates. This procedure should be implemented to do these things + -- if necessary. + overriding procedure Set_Up (Self : in out Instance) is null; + + --------------------------------------- + -- Invokee connector primitives: + --------------------------------------- + -- The schedule invokee connector + overriding procedure Tick_T_Recv_Sync (Self : in out Instance; Arg : in Tick.T); + -- The command receive connector + overriding procedure Command_T_Recv_Async (Self : in out Instance; Arg : in Command.T); + -- This procedure is called when a Command_T_Recv_Async message is dropped due to a full queue. + overriding procedure Command_T_Recv_Async_Dropped (Self : in out Instance; Arg : in Command.T); + -- The parameter update connector. + overriding procedure Parameter_Update_T_Modify (Self : in out Instance; Arg : in out Parameter_Update.T); + + --------------------------------------- + -- Invoker connector primitives: + --------------------------------------- + -- This procedure is called when a Command_Response_T_Send message is dropped due to a full queue. + overriding procedure Command_Response_T_Send_Dropped (Self : in out Instance; Arg : in Command_Response.T) is null; + -- This procedure is called when a Data_Product_T_Send message is dropped due to a full queue. + overriding procedure Data_Product_T_Send_Dropped (Self : in out Instance; Arg : in Data_Product.T) is null; + -- This procedure is called when a Event_T_Send message is dropped due to a full queue. + overriding procedure Event_T_Send_Dropped (Self : in out Instance; Arg : in Event.T) is null; + + ----------------------------------------------- + -- Command handler primitives: + ----------------------------------------------- + -- Description: + -- Commands for the Oscillator component + -- Set the frequency of the oscillator in Hz + overriding function Set_Frequency (Self : in out Instance; Arg : in Packed_F32.T) return Command_Execution_Status.E; + -- Set the amplitude of the oscillator + overriding function Set_Amplitude (Self : in out Instance; Arg : in Packed_F32.T) return Command_Execution_Status.E; + -- Set the Y offset of the oscillator + overriding function Set_Offset (Self : in out Instance; Arg : in Packed_F32.T) return Command_Execution_Status.E; + + -- Invalid command handler. This procedure is called when a command's arguments are found to be invalid: + overriding procedure Invalid_Command (Self : in out Instance; Cmd : in Command.T; Errant_Field_Number : in Unsigned_32; Errant_Field : in Basic_Types.Poly_Type); + + ----------------------------------------------- + -- Parameter primitives: + ----------------------------------------------- + -- Description: + -- Parameters for the Oscillator component + + -- Invalid parameter handler. This procedure is called when a parameter's type is found to be invalid: + overriding procedure Invalid_Parameter (Self : in out Instance; Par : in Parameter.T; Errant_Field_Number : in Unsigned_32; Errant_Field : in Basic_Types.Poly_Type); + -- This procedure is called when the parameters of a component have been updated. The default implementation of this + -- subprogram in the implementation package is a null procedure. However, this procedure can, and should be implemented if + -- something special needs to happen after a parameter update. Examples of this might be copying certain parameters to + -- hardware registers, or performing other special functionality that only needs to be performed after parameters have + -- been updated. + overriding procedure Update_Parameters_Action (Self : in out Instance) is null; + +end Component.Oscillator.Implementation; diff --git a/src/components/oscillator/doc/oscillator.pdf b/src/components/oscillator/doc/oscillator.pdf new file mode 100644 index 0000000..632cd16 Binary files /dev/null and b/src/components/oscillator/doc/oscillator.pdf differ diff --git a/src/components/oscillator/doc/oscillator.tex b/src/components/oscillator/doc/oscillator.tex new file mode 100644 index 0000000..b1163b2 --- /dev/null +++ b/src/components/oscillator/doc/oscillator.tex @@ -0,0 +1,83 @@ +\input{common_packages.tex} + +\begin{document} + +\title{\textbf{Oscillator} \\ +\large\textit{Component Design Document}} +\date{} +\maketitle + +\section{Description} +\input{build/tex/oscillator_description.tex} + +\section{Requirements} +\input{build/tex/oscillator_requirements.tex} + +\section{Design} + +\subsection{At a Glance} +\input{build/tex/oscillator_stats.tex} + +\subsection{Diagram} +\begin{figure}[H] + \includegraphics[width=1.0\textwidth,center]{../build/eps/oscillator.eps} + \caption{Oscillator component diagram.} +\end{figure} + +\subsection{Connectors} +\input{build/tex/oscillator_connectors.tex} + +\subsection{Interrupts} + +\input{build/tex/oscillator_interrupts.tex} + +\subsection{Initialization} +\input{build/tex/oscillator_init.tex} + +\subsection{Commands} + +\input{build/tex/oscillator_commands.tex} + +\subsection{Parameters} + +\input{build/tex/oscillator_parameters.tex} + +\subsection{Events} + +\input{build/tex/oscillator_events.tex} + +\subsection{Data Products} + +\input{build/tex/oscillator_data_products.tex} + +\subsection{Data Dependencies} + +\input{build/tex/oscillator_data_dependencies.tex} + +\subsection{Packets} + +\input{build/tex/oscillator_packets.tex} + +\subsection{Faults} + +\input{build/tex/oscillator_faults.tex} + +\section{Unit Tests} + +\input{build/tex/oscillator_unit_test.tex} + +\section{Appendix} + +\subsection{Preamble} + +\input{build/tex/oscillator_preamble.tex} + +\subsection{Packed Types} + +\input{build/tex/oscillator_types.tex} + +\subsection{Enumerations} + +\input{build/tex/oscillator_enums.tex} + +\end{document} diff --git a/src/components/oscillator/oscillator.commands.yaml b/src/components/oscillator/oscillator.commands.yaml new file mode 100644 index 0000000..c83b4e1 --- /dev/null +++ b/src/components/oscillator/oscillator.commands.yaml @@ -0,0 +1,12 @@ +--- +description: Commands for the Oscillator component +commands: + - name: Set_Frequency + description: Set the frequency of the oscillator in Hz + arg_type: Packed_F32.T + - name: Set_Amplitude + description: Set the amplitude of the oscillator + arg_type: Packed_F32.T + - name: Set_Offset + description: Set the Y offset of the oscillator + arg_type: Packed_F32.T diff --git a/src/components/oscillator/oscillator.component.yaml b/src/components/oscillator/oscillator.component.yaml new file mode 100644 index 0000000..b16a37d --- /dev/null +++ b/src/components/oscillator/oscillator.component.yaml @@ -0,0 +1,25 @@ +--- +description: This is the oscillator component. +execution: passive +connectors: + - description: The schedule invokee connector + type: Tick.T + kind: recv_sync + - description: The command receive connector + type: Command.T + kind: recv_async + - description: The parameter update connector. + type: Parameter_Update.T + kind: modify + - description: This connector is used to register the components commands with the command router component. + type: Command_Response.T + kind: send + - description: The data product invoker connector + type: Data_Product.T + kind: send + - description: The event send connector + type: Event.T + kind: send + - description: The system time is retrieved via this connector. + return_type: Sys_Time.T + kind: get diff --git a/src/components/oscillator/oscillator.data_products.yaml b/src/components/oscillator/oscillator.data_products.yaml new file mode 100644 index 0000000..24be004 --- /dev/null +++ b/src/components/oscillator/oscillator.data_products.yaml @@ -0,0 +1,6 @@ +--- +description: Data products for the Oscillator component +data_products: + - name: Oscillator_Value + description: The current value of the oscillator. + type: Packed_F32.T diff --git a/src/components/oscillator/oscillator.events.yaml b/src/components/oscillator/oscillator.events.yaml new file mode 100644 index 0000000..5ff7686 --- /dev/null +++ b/src/components/oscillator/oscillator.events.yaml @@ -0,0 +1,21 @@ +--- +description: Events for the oscillator component +events: + - name: Frequency_Value_Set + description: A new frequency value was set by command + param_type: Packed_F32.T + - name: Amplitude_Value_Set + description: A new amplitude value was set by command + param_type: Packed_F32.T + - name: Offset_Value_Set + description: A new offset value was set by command + param_type: Packed_F32.T + - name: Dropped_Command + description: The component's queue overflowed and the command was dropped. + param_type: Command_Header.T + - name: Invalid_Command_Received + description: A command was received with invalid parameters. + param_type: Invalid_Command_Info.T + - name: Invalid_Parameter_Received + description: A parameter was received with invalid parameters. + param_type: Invalid_Parameter_Info.T diff --git a/src/components/oscillator/oscillator.parameters.yaml b/src/components/oscillator/oscillator.parameters.yaml new file mode 100644 index 0000000..56ce0bc --- /dev/null +++ b/src/components/oscillator/oscillator.parameters.yaml @@ -0,0 +1,15 @@ +--- +description: Parameters for the Oscillator component +parameters: + - name: Frequency + description: The frequency of the oscillator in Hz + type: Packed_F32.T + default: "(Value => 0.175)" # hz + - name: Amplitude + description: The amplitude of the oscillator + type: Packed_F32.T + default: "(Value => 5.0)" + - name: Offset + description: The Y offset of the oscillator + type: Packed_F32.T + default: "(Value => 0.0)" diff --git a/src/components/oscillator/test/component-oscillator-implementation-tester.adb b/src/components/oscillator/test/component-oscillator-implementation-tester.adb new file mode 100644 index 0000000..320738a --- /dev/null +++ b/src/components/oscillator/test/component-oscillator-implementation-tester.adb @@ -0,0 +1,244 @@ +-------------------------------------------------------------------------------- +-- Oscillator Component Tester Body +-------------------------------------------------------------------------------- + +-- Includes: +with Parameter; + +package body Component.Oscillator.Implementation.Tester is + + --------------------------------------- + -- Initialize heap variables: + --------------------------------------- + procedure Init_Base (Self : in out Instance; Queue_Size : in Natural) is + begin + -- Initialize component heap: + Self.Component_Instance.Init_Base (Queue_Size => Queue_Size); + + -- Initialize tester heap: + -- Connector histories: + Self.Command_Response_T_Recv_Sync_History.Init (Depth => 100); + Self.Data_Product_T_Recv_Sync_History.Init (Depth => 100); + Self.Event_T_Recv_Sync_History.Init (Depth => 100); + Self.Sys_Time_T_Return_History.Init (Depth => 100); + -- Event histories: + Self.Frequency_Value_Set_History.Init (Depth => 100); + Self.Amplitude_Value_Set_History.Init (Depth => 100); + Self.Offset_Value_Set_History.Init (Depth => 100); + Self.Dropped_Command_History.Init (Depth => 100); + Self.Invalid_Command_Received_History.Init (Depth => 100); + Self.Invalid_Parameter_Received_History.Init (Depth => 100); + -- Data product histories: + Self.Oscillator_Value_History.Init (Depth => 100); + end Init_Base; + + procedure Final_Base (Self : in out Instance) is + begin + -- Destroy tester heap: + -- Connector histories: + Self.Command_Response_T_Recv_Sync_History.Destroy; + Self.Data_Product_T_Recv_Sync_History.Destroy; + Self.Event_T_Recv_Sync_History.Destroy; + Self.Sys_Time_T_Return_History.Destroy; + -- Event histories: + Self.Frequency_Value_Set_History.Destroy; + Self.Amplitude_Value_Set_History.Destroy; + Self.Offset_Value_Set_History.Destroy; + Self.Dropped_Command_History.Destroy; + Self.Invalid_Command_Received_History.Destroy; + Self.Invalid_Parameter_Received_History.Destroy; + -- Data product histories: + Self.Oscillator_Value_History.Destroy; + + -- Destroy component heap: + Self.Component_Instance.Final_Base; + end Final_Base; + + --------------------------------------- + -- Test initialization functions: + --------------------------------------- + procedure Connect (Self : in out Instance) is + begin + Self.Component_Instance.Attach_Command_Response_T_Send (To_Component => Self'Unchecked_Access, Hook => Self.Command_Response_T_Recv_Sync_Access); + Self.Component_Instance.Attach_Data_Product_T_Send (To_Component => Self'Unchecked_Access, Hook => Self.Data_Product_T_Recv_Sync_Access); + Self.Component_Instance.Attach_Event_T_Send (To_Component => Self'Unchecked_Access, Hook => Self.Event_T_Recv_Sync_Access); + Self.Component_Instance.Attach_Sys_Time_T_Get (To_Component => Self'Unchecked_Access, Hook => Self.Sys_Time_T_Return_Access); + Self.Attach_Tick_T_Send (To_Component => Self.Component_Instance'Unchecked_Access, Hook => Self.Component_Instance.Tick_T_Recv_Sync_Access); + Self.Attach_Command_T_Send (To_Component => Self.Component_Instance'Unchecked_Access, Hook => Self.Component_Instance.Command_T_Recv_Async_Access); + Self.Attach_Parameter_Update_T_Provide (To_Component => Self.Component_Instance'Unchecked_Access, Hook => Self.Component_Instance.Parameter_Update_T_Modify_Access); + end Connect; + + --------------------------------------- + -- Invokee connector primitives: + --------------------------------------- + -- This connector is used to register the components commands with the command router component. + overriding procedure Command_Response_T_Recv_Sync (Self : in out Instance; Arg : in Command_Response.T) is + begin + -- Push the argument onto the test history for looking at later: + Self.Command_Response_T_Recv_Sync_History.Push (Arg); + end Command_Response_T_Recv_Sync; + + -- The data product invoker connector + overriding procedure Data_Product_T_Recv_Sync (Self : in out Instance; Arg : in Data_Product.T) is + begin + -- Push the argument onto the test history for looking at later: + Self.Data_Product_T_Recv_Sync_History.Push (Arg); + -- Dispatch the data product to the correct handler: + Self.Dispatch_Data_Product (Arg); + end Data_Product_T_Recv_Sync; + + -- The event send connector + overriding procedure Event_T_Recv_Sync (Self : in out Instance; Arg : in Event.T) is + begin + -- Push the argument onto the test history for looking at later: + Self.Event_T_Recv_Sync_History.Push (Arg); + -- Dispatch the event to the correct handler: + Self.Dispatch_Event (Arg); + end Event_T_Recv_Sync; + + -- The system time is retrieved via this connector. + overriding function Sys_Time_T_Return (Self : in out Instance) return Sys_Time.T is + -- Return the system time: + To_Return : constant Sys_Time.T := Self.System_Time; + begin + -- Push the argument onto the test history for looking at later: + Self.Sys_Time_T_Return_History.Push (To_Return); + return To_Return; + end Sys_Time_T_Return; + + --------------------------------------- + -- Invoker connector primitives: + --------------------------------------- + -- This procedure is called when a Command_T_Send message is dropped due to a full queue. + overriding procedure Command_T_Send_Dropped (Self : in out Instance; Arg : in Command.T) is + Ignore : Command.T renames Arg; + begin + if not Self.Expect_Command_T_Send_Dropped then + pragma Assert (False, "The component's queue filled up when Command_T_Send was called!"); + else + Self.Command_T_Send_Dropped_Count := Self.Command_T_Send_Dropped_Count + 1; + Self.Expect_Command_T_Send_Dropped := False; + end if; + end Command_T_Send_Dropped; + + ----------------------------------------------- + -- Event handler primitive: + ----------------------------------------------- + -- Description: + -- Events for the oscillator component + -- A new frequency value was set by command + overriding procedure Frequency_Value_Set (Self : in out Instance; Arg : in Packed_F32.T) is + begin + -- Push the argument onto the test history for looking at later: + Self.Frequency_Value_Set_History.Push (Arg); + end Frequency_Value_Set; + + -- A new amplitude value was set by command + overriding procedure Amplitude_Value_Set (Self : in out Instance; Arg : in Packed_F32.T) is + begin + -- Push the argument onto the test history for looking at later: + Self.Amplitude_Value_Set_History.Push (Arg); + end Amplitude_Value_Set; + + -- A new offset value was set by command + overriding procedure Offset_Value_Set (Self : in out Instance; Arg : in Packed_F32.T) is + begin + -- Push the argument onto the test history for looking at later: + Self.Offset_Value_Set_History.Push (Arg); + end Offset_Value_Set; + + -- The component's queue overflowed and the command was dropped. + overriding procedure Dropped_Command (Self : in out Instance; Arg : in Command_Header.T) is + begin + -- Push the argument onto the test history for looking at later: + Self.Dropped_Command_History.Push (Arg); + end Dropped_Command; + + -- A command was received with invalid parameters. + overriding procedure Invalid_Command_Received (Self : in out Instance; Arg : in Invalid_Command_Info.T) is + begin + -- Push the argument onto the test history for looking at later: + Self.Invalid_Command_Received_History.Push (Arg); + end Invalid_Command_Received; + + -- A parameter was received with invalid parameters. + overriding procedure Invalid_Parameter_Received (Self : in out Instance; Arg : in Invalid_Parameter_Info.T) is + begin + -- Push the argument onto the test history for looking at later: + Self.Invalid_Parameter_Received_History.Push (Arg); + end Invalid_Parameter_Received; + + ----------------------------------------------- + -- Data product handler primitive: + ----------------------------------------------- + -- Description: + -- Data products for the Oscillator component + -- The current value of the oscillator. + overriding procedure Oscillator_Value (Self : in out Instance; Arg : in Packed_F32.T) is + begin + -- Push the argument onto the test history for looking at later: + Self.Oscillator_Value_History.Push (Arg); + end Oscillator_Value; + + ----------------------------------------------- + -- Special primitives for activating component + -- queues: + ----------------------------------------------- + -- Force the component to drain the entire queue + not overriding function Dispatch_All (Self : in out Instance) return Natural is + begin + return Self.Component_Instance.Dispatch_All; + end Dispatch_All; + + not overriding function Dispatch_N (Self : in out Instance; N : in Positive := 1) return Natural is + begin + return Self.Component_Instance.Dispatch_N (N); + end Dispatch_N; + + ----------------------------------------------- + -- Special primitives for aiding in the staging, + -- fetching, and updating of parameters + ----------------------------------------------- + not overriding function Stage_Parameter (Self : in out Instance; Par : in Parameter.T) return Parameter_Update_Status.E is + use Parameter_Enums.Parameter_Update_Status; + use Parameter_Enums.Parameter_Operation_Type; + Param_Update : Parameter_Update.T := ( + Operation => Stage, + Status => Success, + Param => Par + ); + begin + Self.Parameter_Update_T_Provide (Param_Update); + return Param_Update.Status; + end Stage_Parameter; + + not overriding function Fetch_Parameter (Self : in out Instance; Id : in Parameter_Types.Parameter_Id; Par : out Parameter.T) return Parameter_Update_Status.E is + use Parameter_Enums.Parameter_Update_Status; + use Parameter_Enums.Parameter_Operation_Type; + Param_Update : Parameter_Update.T := ( + Operation => Fetch, + Status => Success, + Param => (Header => (Id => Id, Buffer_Length => 0), Buffer => (others => 0)) + ); + begin + -- Set the ID to fetch: + Param_Update.Param.Header.Id := Id; + Self.Parameter_Update_T_Provide (Param_Update); + Par := Param_Update.Param; + return Param_Update.Status; + end Fetch_Parameter; + + not overriding function Update_Parameters (Self : in out Instance) return Parameter_Update_Status.E is + use Parameter_Enums.Parameter_Update_Status; + use Parameter_Enums.Parameter_Operation_Type; + Param_Update : Parameter_Update.T := ( + Operation => Update, + Status => Success, + Param => ((0, 0), (others => 0)) + ); + begin + Self.Parameter_Update_T_Provide (Param_Update); + return Param_Update.Status; + end Update_Parameters; + +end Component.Oscillator.Implementation.Tester; diff --git a/src/components/oscillator/test/component-oscillator-implementation-tester.ads b/src/components/oscillator/test/component-oscillator-implementation-tester.ads new file mode 100644 index 0000000..f46c493 --- /dev/null +++ b/src/components/oscillator/test/component-oscillator-implementation-tester.ads @@ -0,0 +1,141 @@ +-------------------------------------------------------------------------------- +-- Oscillator Component Tester Spec +-------------------------------------------------------------------------------- + +-- Includes: +with Component.Oscillator_Reciprocal; +with Sys_Time; +with Printable_History; +with Command_Response.Representation; +with Data_Product.Representation; +with Event.Representation; +with Sys_Time.Representation; +with Data_Product; +with Packed_F32.Representation; +with Event; +with Command_Header.Representation; +with Invalid_Command_Info.Representation; +with Invalid_Parameter_Info.Representation; + +-- This is the oscillator component. +package Component.Oscillator.Implementation.Tester is + + use Component.Oscillator_Reciprocal; + -- Invoker connector history packages: + package Command_Response_T_Recv_Sync_History_Package is new Printable_History (Command_Response.T, Command_Response.Representation.Image); + package Data_Product_T_Recv_Sync_History_Package is new Printable_History (Data_Product.T, Data_Product.Representation.Image); + package Event_T_Recv_Sync_History_Package is new Printable_History (Event.T, Event.Representation.Image); + package Sys_Time_T_Return_History_Package is new Printable_History (Sys_Time.T, Sys_Time.Representation.Image); + + -- Event history packages: + package Frequency_Value_Set_History_Package is new Printable_History (Packed_F32.T, Packed_F32.Representation.Image); + package Amplitude_Value_Set_History_Package is new Printable_History (Packed_F32.T, Packed_F32.Representation.Image); + package Offset_Value_Set_History_Package is new Printable_History (Packed_F32.T, Packed_F32.Representation.Image); + package Dropped_Command_History_Package is new Printable_History (Command_Header.T, Command_Header.Representation.Image); + package Invalid_Command_Received_History_Package is new Printable_History (Invalid_Command_Info.T, Invalid_Command_Info.Representation.Image); + package Invalid_Parameter_Received_History_Package is new Printable_History (Invalid_Parameter_Info.T, Invalid_Parameter_Info.Representation.Image); + + -- Data product history packages: + package Oscillator_Value_History_Package is new Printable_History (Packed_F32.T, Packed_F32.Representation.Image); + + -- Component class instance: + type Instance is new Component.Oscillator_Reciprocal.Base_Instance with record + -- The component instance under test: + Component_Instance : aliased Component.Oscillator.Implementation.Instance; + -- Connector histories: + Command_Response_T_Recv_Sync_History : Command_Response_T_Recv_Sync_History_Package.Instance; + Data_Product_T_Recv_Sync_History : Data_Product_T_Recv_Sync_History_Package.Instance; + Event_T_Recv_Sync_History : Event_T_Recv_Sync_History_Package.Instance; + Sys_Time_T_Return_History : Sys_Time_T_Return_History_Package.Instance; + -- Event histories: + Frequency_Value_Set_History : Frequency_Value_Set_History_Package.Instance; + Amplitude_Value_Set_History : Amplitude_Value_Set_History_Package.Instance; + Offset_Value_Set_History : Offset_Value_Set_History_Package.Instance; + Dropped_Command_History : Dropped_Command_History_Package.Instance; + Invalid_Command_Received_History : Invalid_Command_Received_History_Package.Instance; + Invalid_Parameter_Received_History : Invalid_Parameter_Received_History_Package.Instance; + -- Data product histories: + Oscillator_Value_History : Oscillator_Value_History_Package.Instance; + -- Booleans to control assertion if message is dropped on async queue: + Expect_Command_T_Send_Dropped : Boolean := False; + Command_T_Send_Dropped_Count : Natural := 0; + end record; + type Instance_Access is access all Instance; + + --------------------------------------- + -- Initialize component heap variables: + --------------------------------------- + procedure Init_Base (Self : in out Instance; Queue_Size : in Natural); + procedure Final_Base (Self : in out Instance); + + --------------------------------------- + -- Test initialization functions: + --------------------------------------- + procedure Connect (Self : in out Instance); + + --------------------------------------- + -- Invokee connector primitives: + --------------------------------------- + -- This connector is used to register the components commands with the command router component. + overriding procedure Command_Response_T_Recv_Sync (Self : in out Instance; Arg : in Command_Response.T); + -- The data product invoker connector + overriding procedure Data_Product_T_Recv_Sync (Self : in out Instance; Arg : in Data_Product.T); + -- The event send connector + overriding procedure Event_T_Recv_Sync (Self : in out Instance; Arg : in Event.T); + -- The system time is retrieved via this connector. + overriding function Sys_Time_T_Return (Self : in out Instance) return Sys_Time.T; + + --------------------------------------- + -- Invoker connector primitives: + --------------------------------------- + -- This procedure is called when a Command_T_Send message is dropped due to a full queue. + overriding procedure Command_T_Send_Dropped (Self : in out Instance; Arg : in Command.T); + + ----------------------------------------------- + -- Event handler primitive: + ----------------------------------------------- + -- Description: + -- Events for the oscillator component + -- A new frequency value was set by command + overriding procedure Frequency_Value_Set (Self : in out Instance; Arg : in Packed_F32.T); + -- A new amplitude value was set by command + overriding procedure Amplitude_Value_Set (Self : in out Instance; Arg : in Packed_F32.T); + -- A new offset value was set by command + overriding procedure Offset_Value_Set (Self : in out Instance; Arg : in Packed_F32.T); + -- The component's queue overflowed and the command was dropped. + overriding procedure Dropped_Command (Self : in out Instance; Arg : in Command_Header.T); + -- A command was received with invalid parameters. + overriding procedure Invalid_Command_Received (Self : in out Instance; Arg : in Invalid_Command_Info.T); + -- A parameter was received with invalid parameters. + overriding procedure Invalid_Parameter_Received (Self : in out Instance; Arg : in Invalid_Parameter_Info.T); + + ----------------------------------------------- + -- Data product handler primitives: + ----------------------------------------------- + -- Description: + -- Data products for the Oscillator component + -- The current value of the oscillator. + overriding procedure Oscillator_Value (Self : in out Instance; Arg : in Packed_F32.T); + + ----------------------------------------------- + -- Special primitives for activating component + -- queue: + ----------------------------------------------- + -- Tell the component to dispatch all items off of its queue: + not overriding function Dispatch_All (Self : in out Instance) return Natural; + -- Tell the component to dispatch n items off of its queue: + not overriding function Dispatch_N (Self : in out Instance; N : in Positive := 1) return Natural; + + ----------------------------------------------- + -- Special primitives for aiding in the staging, + -- fetching, and updating of parameters + ----------------------------------------------- + -- Stage a parameter value within the component + not overriding function Stage_Parameter (Self : in out Instance; Par : in Parameter.T) return Parameter_Update_Status.E; + -- Fetch the value of a parameter with the component + not overriding function Fetch_Parameter (Self : in out Instance; Id : in Parameter_Types.Parameter_Id; Par : out Parameter.T) return Parameter_Update_Status.E; + -- Tell the component it is OK to atomically update all of its + -- working parameter values with the staged values. + not overriding function Update_Parameters (Self : in out Instance) return Parameter_Update_Status.E; + +end Component.Oscillator.Implementation.Tester; diff --git a/src/components/oscillator/test/env.py b/src/components/oscillator/test/env.py new file mode 100644 index 0000000..8d5248e --- /dev/null +++ b/src/components/oscillator/test/env.py @@ -0,0 +1 @@ +from environments import test # noqa: F401 diff --git a/src/components/oscillator/test/oscillator.tests.yaml b/src/components/oscillator/test/oscillator.tests.yaml new file mode 100644 index 0000000..7f233ce --- /dev/null +++ b/src/components/oscillator/test/oscillator.tests.yaml @@ -0,0 +1,5 @@ +--- +description: This is a unit test suite for the oscillator component +tests: + - name: Test_Parameters + description: This unit test excersizes the parameters within the component diff --git a/src/components/oscillator/test/oscillator_tests-implementation.adb b/src/components/oscillator/test/oscillator_tests-implementation.adb new file mode 100644 index 0000000..1a4c73a --- /dev/null +++ b/src/components/oscillator/test/oscillator_tests-implementation.adb @@ -0,0 +1,69 @@ +-------------------------------------------------------------------------------- +-- Oscillator Tests Body +-------------------------------------------------------------------------------- + +with Parameter_Enums.Assertion; +use Parameter_Enums.Parameter_Update_Status; +use Parameter_Enums.Assertion; +with Parameter.Assertion; use Parameter.Assertion; + +package body Oscillator_Tests.Implementation is + + ------------------------------------------------------------------------- + -- Fixtures: + ------------------------------------------------------------------------- + + overriding procedure Set_Up_Test (Self : in out Instance) is + begin + -- Allocate heap memory to component: + Self.Tester.Init_Base (Queue_Size => Self.Tester.Component_Instance.Get_Max_Queue_Element_Size * 10); + + -- Make necessary connections between tester and component: + Self.Tester.Connect; + + -- Call the component set up method that the assembly would normally call. + Self.Tester.Component_Instance.Set_Up; + end Set_Up_Test; + + overriding procedure Tear_Down_Test (Self : in out Instance) is + begin + -- Free component heap: + Self.Tester.Final_Base; + end Tear_Down_Test; + + ------------------------------------------------------------------------- + -- Tests: + ------------------------------------------------------------------------- + + -- This unit test excersizes the parameters within the component + overriding procedure Test_Parameters (Self : in out Instance) is + T : Component.Oscillator.Implementation.Tester.Instance_Access renames Self.Tester; + + procedure Check_Parameters (Frequency : in Short_Float; Amplitude : in Short_Float; Offset : in Short_Float) is + Param_Frequency : constant Parameter.T := T.Parameters.Frequency ((Value => Frequency)); + Param_Amplitude : constant Parameter.T := T.Parameters.Amplitude ((Value => Amplitude)); + Param_Offset : constant Parameter.T := T.Parameters.Offset ((Value => Offset)); + Param : Parameter.T; + begin + Parameter_Update_Status_Assert.Eq (T.Fetch_Parameter (T.Parameters.Get_Frequency_Id, Param), Success); + Parameter_Assert.Eq (Param, Param_Frequency); + Parameter_Update_Status_Assert.Eq (T.Fetch_Parameter (T.Parameters.Get_Amplitude_Id, Param), Success); + Parameter_Assert.Eq (Param, Param_Amplitude); + Parameter_Update_Status_Assert.Eq (T.Fetch_Parameter (T.Parameters.Get_Offset_Id, Param), Success); + Parameter_Assert.Eq (Param, Param_Offset); + end Check_Parameters; + begin + -- Make sure parameter values are set to their defaults: + Check_Parameters (0.175, 5.0, 0.0); + + -- Set new parameters: + Parameter_Update_Status_Assert.Eq (T.Stage_Parameter (T.Parameters.Frequency ((Value => 2.9))), Success); + Parameter_Update_Status_Assert.Eq (T.Stage_Parameter (T.Parameters.Amplitude ((Value => 7.8))), Success); + Parameter_Update_Status_Assert.Eq (T.Stage_Parameter (T.Parameters.Offset ((Value => 0.4))), Success); + Parameter_Update_Status_Assert.Eq (T.Update_Parameters, Success); + + -- Make sure parameters changed: + Check_Parameters (2.9, 7.8, 0.4); + end Test_Parameters; + +end Oscillator_Tests.Implementation; diff --git a/src/components/oscillator/test/oscillator_tests-implementation.ads b/src/components/oscillator/test/oscillator_tests-implementation.ads new file mode 100644 index 0000000..dcd1ed9 --- /dev/null +++ b/src/components/oscillator/test/oscillator_tests-implementation.ads @@ -0,0 +1,24 @@ +-------------------------------------------------------------------------------- +-- Oscillator Tests Spec +-------------------------------------------------------------------------------- + +-- This is a unit test suite for the oscillator component +package Oscillator_Tests.Implementation is + + -- Test data and state: + type Instance is new Oscillator_Tests.Base_Instance with private; + type Class_Access is access all Instance'Class; + +private + -- Fixture procedures: + overriding procedure Set_Up_Test (Self : in out Instance); + overriding procedure Tear_Down_Test (Self : in out Instance); + + -- This unit test excersizes the parameters within the component + overriding procedure Test_Parameters (Self : in out Instance); + + -- Test data and state: + type Instance is new Oscillator_Tests.Base_Instance with record + null; + end record; +end Oscillator_Tests.Implementation; diff --git a/src/components/oscillator/test/test.adb b/src/components/oscillator/test/test.adb new file mode 100644 index 0000000..b42dddf --- /dev/null +++ b/src/components/oscillator/test/test.adb @@ -0,0 +1,23 @@ +-------------------------------------------------------------------------------- +-- Oscillator Tests +-------------------------------------------------------------------------------- + +with AUnit.Reporter.Text; +with AUnit.Run; +with Oscillator_Tests.Implementation.Suite; +-- Make sure any terminating tasks are handled and an appropriate +-- error message is printed. +with Unit_Test_Termination_Handler; +pragma Unreferenced (Unit_Test_Termination_Handler); + +procedure Test is + -- Create runner for test suite: + procedure Runner is new AUnit.Run.Test_Runner (Oscillator_Tests.Implementation.Suite.Get); + -- Use the text reporter: + Reporter : AUnit.Reporter.Text.Text_Reporter; +begin + -- Add color output to test run: + AUnit.Reporter.Text.Set_Use_ANSI_Colors (Reporter, True); + -- Run tests: + Runner (Reporter); +end Test; diff --git a/src/components/parameter_manager/.all_path b/src/components/parameter_manager/.all_path new file mode 100644 index 0000000..e69de29 diff --git a/src/components/parameter_manager/component-parameter_manager-implementation.adb b/src/components/parameter_manager/component-parameter_manager-implementation.adb new file mode 100644 index 0000000..691c879 --- /dev/null +++ b/src/components/parameter_manager/component-parameter_manager-implementation.adb @@ -0,0 +1,261 @@ +-------------------------------------------------------------------------------- +-- Parameter_Manager Component Implementation Body +-------------------------------------------------------------------------------- + +with Crc_16; +with Parameter_Enums; +with Parameter_Manager_Enums; +with Packet_Types; + +package body Component.Parameter_Manager.Implementation is + + -------------------------------------------------- + -- Subprogram for implementation init method: + -------------------------------------------------- + -- Initialization parameters for the Parameter Manager. + -- + -- Init Parameters: + -- parameter_Table_Length : Natural - The size of the parameter table in bytes. This must be known to the component so it can construct correct sized memory regions for the downstream components. + -- ticks_Until_Timeout : Natural - The component will wait until it has received at least this many ticks before reporting a timeout error while waiting for a parameter update/fetch response from either the active or default parameter components. For example, if the component is attached to a 10Hz rate group and this value is set to 7, then the component will wait between 700 and 800 ms before declaring a timeout error from an unresponsive downstream component. + -- + overriding procedure Init (Self : in out Instance; Parameter_Table_Length : in Natural; Ticks_Until_Timeout : in Natural) is + begin + -- Just save off the init parameters so we can use them later. + -- The implementation of this component assumes that the parameter table length fits cleanly in a maximum sized packet. + pragma Assert (Self.Parameter_Table_Length + Crc_16.Crc_16_Type'Length <= Packet_Types.Packet_Buffer_Type'Length, "The parameter table must not be larger than the maximum size packet!"); + Self.Parameter_Table_Length := Parameter_Table_Length; + -- Save the ticks until timeout. + Self.Sync_Object.Set_Timeout_Limit (Ticks_Until_Timeout); + + -- Allocate our temporary storage region. See more details in the .ads for why this is needed. + Self.Parameter_Bytes := new Basic_Types.Byte_Array (0 .. Self.Parameter_Table_Length - 1); + -- Create a memory region that points to this buffer: + Self.Parameter_Bytes_Region := (Address => Self.Parameter_Bytes.all'Address, Length => Self.Parameter_Bytes.all'Length); + end Init; + + --------------------------------------- + -- Invokee connector primitives: + --------------------------------------- + -- The component should be attached to a periodic tick that is used to timeout waiting for a parameter update/fetch response. See the ticks_Until_Timeout initialization parameter. + overriding procedure Timeout_Tick_Recv_Sync (Self : in out Instance; Arg : in Tick.T) is + Ignore : Tick.T renames Arg; + begin + -- If the component is currently waiting on a response from a downstream component + -- we need to implement the timeout logic. Otherwise reset our timeout counter. + -- Increment the timeout counter on the sync object. This will only cause a timeout + -- if the sync object is waiting and the timeout counter exceeds the timeout limit. + Self.Sync_Object.Increment_Timeout_If_Waiting; + end Timeout_Tick_Recv_Sync; + + -- The command receive connector. + overriding procedure Command_T_Recv_Async (Self : in out Instance; Arg : in Command.T) is + -- Execute the command: + Stat : constant Command_Response_Status.E := Self.Execute_Command (Arg); + begin + -- Send the return status: + Self.Command_Response_T_Send_If_Connected ((Source_Id => Arg.Header.Source_Id, Registration_Id => Self.Command_Reg_Id, Command_Id => Arg.Header.Id, Status => Stat)); + end Command_T_Recv_Async; + + -- Parameter update/fetch responses are returned synchronously on this connector. The component waits internally for this response, or times out if the response is not received in time. + overriding procedure Parameters_Memory_Region_Release_T_Recv_Sync (Self : in out Instance; Arg : in Parameters_Memory_Region_Release.T) is + begin + -- First set the protected response with the response from the component. + -- In this function we simply store whatever we get. The error handling based on the + -- contents of this response are done by this component's task (executing the command). + Self.Response.Set_Var (Arg); + + -- Ok we have stored the response for the component to look at later. Now we signal + -- to the component that a response has been received and it can read it. + Self.Sync_Object.Release; + + -- Note, there is a possible race condition here. Think, we could set the response + -- within the component, and then release it to allow reading of this data. Before + -- the component reads the data, however, we may receive another response, overwriting + -- the data the component receives before it can read the old data. This sounds serious, + -- but this behavior should never occur, since the downstream components should not ever + -- return a response to this component unprovoked. If for some errant reason this condition + -- does occur, it will likely be caught by the error handling in this component's task, which + -- checks the virtual memory ID for correctness before handling the response. + -- + -- Note, the protected buffer and the sync object are both protected objects, so there + -- is no risk of data corruption (which would be a serious problem), there is just risk of + -- out of order synchronization, which should not occur is the assembly is designed + -- correctly, as described above. If the assembly is not designed correctly, this component's + -- error handling will reveal the problem. + end Parameters_Memory_Region_Release_T_Recv_Sync; + + -- This procedure is called when a Command_T_Recv_Async message is dropped due to a full queue. + overriding procedure Command_T_Recv_Async_Dropped (Self : in out Instance; Arg : in Command.T) is + begin + -- Throw event: + Self.Event_T_Send_If_Connected (Self.Events.Command_Dropped (Self.Sys_Time_T_Get, Arg.Header)); + end Command_T_Recv_Async_Dropped; + + --------------------------------------- + -- Helper functions: + --------------------------------------- + -- Helper which waits for a response from a downstream component after an update/fetch request. This + -- function waits for the response and then does the boiler plate error checking and event throwing + -- that all copy commands must perform. + function Wait_For_Response (Self : in out Instance) return Boolean is + Wait_Timed_Out : Boolean; + begin + -- OK wait for the response. + Self.Sync_Object.Wait (Wait_Timed_Out); + + -- Check the wait return value: + if Wait_Timed_Out then + -- Send info event: + Self.Event_T_Send_If_Connected (Self.Events.Parameter_Table_Copy_Timeout (Self.Sys_Time_T_Get)); + return False; + end if; + + -- Take a look at the response: + declare + use Parameter_Enums.Parameter_Table_Update_Status; + -- Read the response from the protected variable: + Release : constant Parameters_Memory_Region_Release.T := Self.Response.Get_Var; + begin + -- Check the status: + if Release.Status /= Success then + -- Send info event: + Self.Event_T_Send_If_Connected (Self.Events.Parameter_Table_Copy_Failure (Self.Sys_Time_T_Get, Release)); + return False; + end if; + end; + + return True; + end Wait_For_Response; + + -- Helper which sends a memory region request (set/get) to the default store. + function Copy_To_From_Default (Self : in out Instance; Request : in Parameters_Memory_Region.T) return Boolean is + begin + -- First, clear the state of the synchronization + -- object. This prevents us from just "falling through" the + -- wait call below if some errant response was sent through + -- to us while we were not listening. + -- This also resets the timeout counter, so we start + -- fresh. + Self.Sync_Object.Reset; + + -- Send the request to the default component. + Self.Default_Parameters_Memory_Region_Send (Request); + + -- OK now we wait for and check the response. + if not Self.Wait_For_Response then + return False; + end if; + + return True; + end Copy_To_From_Default; + + -- Helper which sends a memory region request (set/get) to the default store. + function Copy_To_From_Working (Self : in out Instance; Request : in Parameters_Memory_Region.T) return Boolean is + begin + -- First, clear the state of the synchronization + -- object. This prevents us from just "falling through" the + -- wait call below if some errant response was sent through + -- to us while we were not listening. + -- This also resets the timeout counter, so we start + -- fresh. + Self.Sync_Object.Reset; + + -- Send the request to the default component. + Self.Working_Parameters_Memory_Region_Send (Request); + + -- OK now we wait for and check the response. + if not Self.Wait_For_Response then + return False; + end if; + + return True; + end Copy_To_From_Working; + + -- Helper function which copies parameter table data from default to working. + function Copy_Default_To_Working (Self : in out Instance) return Command_Execution_Status.E is + use Command_Execution_Status; + use Parameter_Enums.Parameter_Table_Operation_Type; + begin + -- Send a get request to default: + if not Self.Copy_To_From_Default ((Region => Self.Parameter_Bytes_Region, Operation => Get)) then + return Failure; + end if; + + -- + -- Ok, now we have valid parameter data from the source component. Time to send + -- it to the destination. + -- + + -- Send a set request to working: + if not Self.Copy_To_From_Working ((Region => Self.Parameter_Bytes_Region, Operation => Set)) then + return Failure; + end if; + + return Success; + end Copy_Default_To_Working; + + -- Helper function which copies parameter table data from working to default. + function Copy_Working_To_Default (Self : in out Instance) return Command_Execution_Status.E is + use Command_Execution_Status; + use Parameter_Enums.Parameter_Table_Operation_Type; + begin + -- Send a get request to default: + if not Self.Copy_To_From_Working ((Region => Self.Parameter_Bytes_Region, Operation => Get)) then + return Failure; + end if; + + -- + -- Ok, now we have valid parameter data from the source component. Time to send + -- it to the destination. + -- + + -- Send a set request to working: + if not Self.Copy_To_From_Default ((Region => Self.Parameter_Bytes_Region, Operation => Set)) then + return Failure; + end if; + + return Success; + end Copy_Working_To_Default; + + ----------------------------------------------- + -- Command handler primitives: + ----------------------------------------------- + -- Description: + -- These are the commands for the Parameter Store component. + -- Copy parameter table from source to destination based on the enumeration provided. + overriding function Copy_Parameter_Table (Self : in out Instance; Arg : in Packed_Parameter_Table_Copy_Type.T) return Command_Execution_Status.E is + use Command_Execution_Status; + use Parameter_Manager_Enums.Parameter_Table_Copy_Type; + To_Return : Command_Execution_Status.E; + begin + -- Info event: + Self.Event_T_Send_If_Connected (Self.Events.Starting_Parameter_Table_Copy (Self.Sys_Time_T_Get, Arg)); + + -- Determine the copy source and destination and perform copy: + case Arg.Copy_Type is + when Default_To_Working => + To_Return := Self.Copy_Default_To_Working; + when Working_To_Default => + To_Return := Self.Copy_Working_To_Default; + end case; + + -- Check the return status: + if To_Return /= Success then + -- An error event will have already been sent. + return To_Return; + end if; + + -- Info event: + Self.Event_T_Send_If_Connected (Self.Events.Finished_Parameter_Table_Copy (Self.Sys_Time_T_Get, Arg)); + + return Success; + end Copy_Parameter_Table; + + -- Invalid command handler. This procedure is called when a command's arguments are found to be invalid: + overriding procedure Invalid_Command (Self : in out Instance; Cmd : in Command.T; Errant_Field_Number : in Unsigned_32; Errant_Field : in Basic_Types.Poly_Type) is + begin + -- Throw event: + Self.Event_T_Send_If_Connected (Self.Events.Invalid_Command_Received (Self.Sys_Time_T_Get, (Id => Cmd.Header.Id, Errant_Field_Number => Errant_Field_Number, Errant_Field => Errant_Field))); + end Invalid_Command; + +end Component.Parameter_Manager.Implementation; diff --git a/src/components/parameter_manager/component-parameter_manager-implementation.ads b/src/components/parameter_manager/component-parameter_manager-implementation.ads new file mode 100644 index 0000000..cba4ea7 --- /dev/null +++ b/src/components/parameter_manager/component-parameter_manager-implementation.ads @@ -0,0 +1,104 @@ +-------------------------------------------------------------------------------- +-- Parameter_Manager Component Implementation Spec +-------------------------------------------------------------------------------- + +-- Includes: +with Tick; +with Command; +with Parameters_Memory_Region_Release; +with Protected_Variables; +with Task_Synchronization; +with Memory_Region; + +-- This component is responsible for managing the working, scratch, and default parameter tables. Its sole responsibility is to respond to commands to copy parameter tables from one region to another or to dump the scratch region. +package Component.Parameter_Manager.Implementation is + + -- The component class instance record: + type Instance is new Parameter_Manager.Base_Instance with private; + + -------------------------------------------------- + -- Subprogram for implementation init method: + -------------------------------------------------- + -- Initialization parameters for the Parameter Manager. + -- + -- Init Parameters: + -- parameter_Table_Length : Natural - The size of the parameter table in bytes. This must be known to the component so it can construct correct sized memory regions for the downstream components. + -- ticks_Until_Timeout : Natural - The component will wait until it has received at least this many ticks before reporting a timeout error while waiting for a parameter update/fetch response from either the active or default parameter components. For example, if the component is attached to a 10Hz rate group and this value is set to 7, then the component will wait between 700 and 800 ms before declaring a timeout error from an unresponsive downstream component. + -- + overriding procedure Init (Self : in out Instance; Parameter_Table_Length : in Natural; Ticks_Until_Timeout : in Natural); + +private + + -- Create a protected object that holds a memory region release. This will be set synchronously + -- by the responses from the active/default parameter components, and will be read by this + -- component, so must be protected to prevent corruption. + package Protected_Parameters_Memory_Region_Release is new Protected_Variables.Generic_Variable (Parameters_Memory_Region_Release.T); + + -- The component class instance record: + type Instance is new Parameter_Manager.Base_Instance with record + -- Memory region release protected variable, set by downstream components. + Response : Protected_Parameters_Memory_Region_Release.Variable; + -- Variables used for task synchronization and timeouts: + Sync_Object : Task_Synchronization.Wait_Release_Timeout_Counter_Object; + -- Other configuration: + Parameter_Table_Length : Natural := 0; + -- Temporary storage to allow safe copying between Default and Working. + -- We declare this here, instead of as a temporary variable within a function + -- because if a timeout error occurs, we have no gaurantee that the downstream + -- component is not reading/writing from this data. If it is declared here, then + -- at least only this data can be corrupted, and not the stack, which would be + -- a much worse situation. The assembly should be designed that timeout errors + -- never occur in order to fully prevent this issue. + Parameter_Bytes : Basic_Types.Byte_Array_Access; + -- Create a memory region that points to this buffer: + Parameter_Bytes_Region : Memory_Region.T; + end record; + + --------------------------------------- + -- Set Up Procedure + --------------------------------------- + -- Null method which can be implemented to provide some component + -- set up code. This method is generally called by the assembly + -- main.adb after all component initialization and tasks have been started. + -- Some activities need to only be run once at startup, but cannot be run + -- safely until everything is up and running, ie. command registration, initial + -- data product updates. This procedure should be implemented to do these things + -- if necessary. + overriding procedure Set_Up (Self : in out Instance) is null; + + --------------------------------------- + -- Invokee connector primitives: + --------------------------------------- + -- The component should be attached to a periodic tick that is used to timeout waiting for a parameter update/fetch response. See the ticks_Until_Timeout initialization parameter. + overriding procedure Timeout_Tick_Recv_Sync (Self : in out Instance; Arg : in Tick.T); + -- The command receive connector. + overriding procedure Command_T_Recv_Async (Self : in out Instance; Arg : in Command.T); + -- This procedure is called when a Command_T_Recv_Async message is dropped due to a full queue. + overriding procedure Command_T_Recv_Async_Dropped (Self : in out Instance; Arg : in Command.T); + -- Parameter update/fetch responses are returned synchronously on this connector. The component waits internally for this response, or times out if the response is not received in time. + overriding procedure Parameters_Memory_Region_Release_T_Recv_Sync (Self : in out Instance; Arg : in Parameters_Memory_Region_Release.T); + + --------------------------------------- + -- Invoker connector primitives: + --------------------------------------- + -- This procedure is called when a Command_Response_T_Send message is dropped due to a full queue. + overriding procedure Command_Response_T_Send_Dropped (Self : in out Instance; Arg : in Command_Response.T) is null; + -- This procedure is called when a Working_Parameters_Memory_Region_Send message is dropped due to a full queue. + overriding procedure Working_Parameters_Memory_Region_Send_Dropped (Self : in out Instance; Arg : in Parameters_Memory_Region.T) is null; + -- This procedure is called when a Default_Parameters_Memory_Region_Send message is dropped due to a full queue. + overriding procedure Default_Parameters_Memory_Region_Send_Dropped (Self : in out Instance; Arg : in Parameters_Memory_Region.T) is null; + -- This procedure is called when a Event_T_Send message is dropped due to a full queue. + overriding procedure Event_T_Send_Dropped (Self : in out Instance; Arg : in Event.T) is null; + + ----------------------------------------------- + -- Command handler primitives: + ----------------------------------------------- + -- Description: + -- These are the commands for the Parameter Store component. + -- Copy parameter table from source to destination based on the enumeration provided. + overriding function Copy_Parameter_Table (Self : in out Instance; Arg : in Packed_Parameter_Table_Copy_Type.T) return Command_Execution_Status.E; + + -- Invalid command handler. This procedure is called when a command's arguments are found to be invalid: + overriding procedure Invalid_Command (Self : in out Instance; Cmd : in Command.T; Errant_Field_Number : in Unsigned_32; Errant_Field : in Basic_Types.Poly_Type); + +end Component.Parameter_Manager.Implementation; diff --git a/src/components/parameter_manager/doc/parameter_manager.pdf b/src/components/parameter_manager/doc/parameter_manager.pdf new file mode 100644 index 0000000..dd88ca5 Binary files /dev/null and b/src/components/parameter_manager/doc/parameter_manager.pdf differ diff --git a/src/components/parameter_manager/doc/parameter_manager.tex b/src/components/parameter_manager/doc/parameter_manager.tex new file mode 100644 index 0000000..95d948b --- /dev/null +++ b/src/components/parameter_manager/doc/parameter_manager.tex @@ -0,0 +1,58 @@ +\input{common_packages.tex} + +\begin{document} + +\title{\textbf{Parameter Manager} \\ +\large\textit{Component Design Document}} +\date{} +\maketitle + +\section{Description} +\input{build/tex/parameter_manager_description.tex} + +\section{Requirements} +\input{build/tex/parameter_manager_requirements.tex} + +\section{Design} + +\subsection{At a Glance} +\input{build/tex/parameter_manager_stats.tex} + +\subsection{Diagram} +\begin{figure}[H] + \includegraphics[width=1.0\textwidth,center]{../build/eps/parameter_manager.eps} + \caption{Parameter Manager component diagram.} +\end{figure} + +\subsection{Connectors} +\input{build/tex/parameter_manager_connectors.tex} + +\subsection{Initialization} +\input{build/tex/parameter_manager_init.tex} + +\subsection{Commands} + +\input{build/tex/parameter_manager_commands.tex} + +\subsection{Events} + +\input{build/tex/parameter_manager_events.tex} + +\subsection{Packets} + +\input{build/tex/parameter_manager_packets.tex} + +\section{Unit Tests} + +\input{build/tex/parameter_manager_unit_test.tex} + +\section{Appendix} +\subsection{Packed Types} + +\input{build/tex/parameter_manager_types.tex} + +\subsection{Enumerations} + +\input{build/tex/parameter_manager_enums.tex} + +\end{document} diff --git a/src/components/parameter_manager/parameter_manager.commands.yaml b/src/components/parameter_manager/parameter_manager.commands.yaml new file mode 100644 index 0000000..6b95ddb --- /dev/null +++ b/src/components/parameter_manager/parameter_manager.commands.yaml @@ -0,0 +1,6 @@ +--- +description: These are the commands for the Parameter Manager component. +commands: + - name: Copy_Parameter_Table + description: Copy parameter table from source to destination based on the enumeration provided. + arg_type: Packed_Parameter_Table_Copy_Type.T diff --git a/src/components/parameter_manager/parameter_manager.component.yaml b/src/components/parameter_manager/parameter_manager.component.yaml new file mode 100644 index 0000000..8a16651 --- /dev/null +++ b/src/components/parameter_manager/parameter_manager.component.yaml @@ -0,0 +1,40 @@ +--- +description: This component is responsible for managing a working and default parameter table. Its sole responsibility is to respond to commands to copy parameter tables from one region to another. +execution: active +init: + description: Initialization parameters for the Parameter Manager. + parameters: + - name: parameter_Table_Length + type: Natural + description: The size of the parameter table in bytes. This must be known to the component so it can construct correct sized memory regions for the downstream components. + - name: ticks_Until_Timeout + type: Natural + description: The component will wait until it has received at least this many ticks before reporting a timeout error while waiting for a parameter update/fetch response from either the working or default parameter components. For example, if the component is attached to a 10Hz rate group and this value is set to 7, then the component will wait between 700 and 800 ms before declaring a timeout error from an unresponsive downstream component. +connectors: + - description: The component should be attached to a periodic tick that is used to timeout waiting for a parameter update/fetch response. See the ticks_Until_Timeout initialization parameter. + name: Timeout_Tick_Recv_Sync + type: Tick.T + kind: recv_sync + - description: The command receive connector. + type: Command.T + kind: recv_async + - description: This connector is used to send the command response back to the command router. + type: Command_Response.T + kind: send + - name: Working_Parameters_Memory_Region_Send + description: Requests to update/fetch the working parameters are made on this connector. + type: Parameters_Memory_Region.T + kind: send + - name: Default_Parameters_Memory_Region_Send + description: Requests to update/fetch the default parameters are made on this connector. + type: Parameters_Memory_Region.T + kind: send + - description: Parameter update/fetch responses are returned synchronously on this connector. The component waits internally for this response, or times out if the response is not received in time. + type: Parameters_Memory_Region_Release.T + kind: recv_sync + - description: The event send connector + type: Event.T + kind: send + - description: The system time is retrieved via this connector. + return_type: Sys_Time.T + kind: get diff --git a/src/components/parameter_manager/parameter_manager.events.yaml b/src/components/parameter_manager/parameter_manager.events.yaml new file mode 100644 index 0000000..973a9d2 --- /dev/null +++ b/src/components/parameter_manager/parameter_manager.events.yaml @@ -0,0 +1,20 @@ +--- +description: Events for the Parameter Manager component. +events: + - name: Starting_Parameter_Table_Copy + description: Starting parameter table copy from source to destination. + param_type: Packed_Parameter_Table_Copy_Type.T + - name: Finished_Parameter_Table_Copy + description: Finished parameter table copy from source to destination, without errors. + param_type: Packed_Parameter_Table_Copy_Type.T + - name: Invalid_Command_Received + description: A command was received with invalid parameters. + param_type: Invalid_Command_Info.T + - name: Parameter_Table_Copy_Timeout + description: A timeout occured while waiting for a parameter table copy operation to complete. + - name: Parameter_Table_Copy_Failure + description: A parameter table copy failed. + param_type: Parameters_Memory_Region_Release.T + - name: Command_Dropped + description: A command was dropped due to a full queue. + param_type: Command_Header.T diff --git a/src/components/parameter_manager/parameter_manager.requirements.yaml b/src/components/parameter_manager/parameter_manager.requirements.yaml new file mode 100644 index 0000000..44687f5 --- /dev/null +++ b/src/components/parameter_manager/parameter_manager.requirements.yaml @@ -0,0 +1,5 @@ +--- +description: The requirements for the Parameter Manager component are specified below. +requirements: + - text: The component shall copy a parameter table from default to working on command. + - text: The component shall copy a parameter table from working to default on command. diff --git a/src/components/parameter_manager/test/component-parameter_manager-implementation-tester.adb b/src/components/parameter_manager/test/component-parameter_manager-implementation-tester.adb new file mode 100644 index 0000000..df664f0 --- /dev/null +++ b/src/components/parameter_manager/test/component-parameter_manager-implementation-tester.adb @@ -0,0 +1,229 @@ +-------------------------------------------------------------------------------- +-- Parameter_Manager Component Tester Body +-------------------------------------------------------------------------------- + +with String_Util; +with Parameter_Enums; + +package body Component.Parameter_Manager.Implementation.Tester is + + --------------------------------------- + -- Initialize heap variables: + --------------------------------------- + procedure Init_Base (Self : in out Instance; Queue_Size : in Natural) is + begin + -- Initialize component heap: + Self.Component_Instance.Init_Base (Queue_Size => Queue_Size); + + -- Initialize tester heap: + -- Connector histories: + Self.Command_Response_T_Recv_Sync_History.Init (Depth => 100); + Self.Working_Parameters_Memory_Region_Recv_Sync_History.Init (Depth => 100); + Self.Default_Parameters_Memory_Region_Recv_Sync_History.Init (Depth => 100); + Self.Event_T_Recv_Sync_History.Init (Depth => 100); + Self.Sys_Time_T_Return_History.Init (Depth => 100); + -- Event histories: + Self.Starting_Parameter_Table_Copy_History.Init (Depth => 100); + Self.Finished_Parameter_Table_Copy_History.Init (Depth => 100); + Self.Invalid_Command_Received_History.Init (Depth => 100); + Self.Parameter_Table_Copy_Timeout_History.Init (Depth => 100); + Self.Parameter_Table_Copy_Failure_History.Init (Depth => 100); + Self.Command_Dropped_History.Init (Depth => 100); + end Init_Base; + + procedure Final_Base (Self : in out Instance) is + begin + -- Destroy tester heap: + -- Connector histories: + Self.Command_Response_T_Recv_Sync_History.Destroy; + Self.Working_Parameters_Memory_Region_Recv_Sync_History.Destroy; + Self.Default_Parameters_Memory_Region_Recv_Sync_History.Destroy; + Self.Event_T_Recv_Sync_History.Destroy; + Self.Sys_Time_T_Return_History.Destroy; + -- Event histories: + Self.Starting_Parameter_Table_Copy_History.Destroy; + Self.Finished_Parameter_Table_Copy_History.Destroy; + Self.Invalid_Command_Received_History.Destroy; + Self.Parameter_Table_Copy_Timeout_History.Destroy; + Self.Parameter_Table_Copy_Failure_History.Destroy; + Self.Command_Dropped_History.Destroy; + + -- Destroy component heap: + Self.Component_Instance.Final_Base; + end Final_Base; + + --------------------------------------- + -- Test initialization functions: + --------------------------------------- + procedure Connect (Self : in out Instance) is + begin + Self.Component_Instance.Attach_Command_Response_T_Send (To_Component => Self'Unchecked_Access, Hook => Self.Command_Response_T_Recv_Sync_Access); + Self.Component_Instance.Attach_Working_Parameters_Memory_Region_Send (To_Component => Self'Unchecked_Access, Hook => Self.Working_Parameters_Memory_Region_Recv_Sync_Access); + Self.Component_Instance.Attach_Default_Parameters_Memory_Region_Send (To_Component => Self'Unchecked_Access, Hook => Self.Default_Parameters_Memory_Region_Recv_Sync_Access); + Self.Component_Instance.Attach_Event_T_Send (To_Component => Self'Unchecked_Access, Hook => Self.Event_T_Recv_Sync_Access); + Self.Component_Instance.Attach_Sys_Time_T_Get (To_Component => Self'Unchecked_Access, Hook => Self.Sys_Time_T_Return_Access); + Self.Attach_Timeout_Tick_Send (To_Component => Self.Component_Instance'Unchecked_Access, Hook => Self.Component_Instance.Timeout_Tick_Recv_Sync_Access); + Self.Attach_Command_T_Send (To_Component => Self.Component_Instance'Unchecked_Access, Hook => Self.Component_Instance.Command_T_Recv_Async_Access); + Self.Attach_Parameters_Memory_Region_Release_T_Send (To_Component => Self.Component_Instance'Unchecked_Access, Hook => Self.Component_Instance.Parameters_Memory_Region_Release_T_Recv_Sync_Access); + end Connect; + + --------------------------------------- + -- Invokee connector primitives: + --------------------------------------- + -- This connector is used to send the command response back to the command router. + overriding procedure Command_Response_T_Recv_Sync (Self : in out Instance; Arg : in Command_Response.T) is + begin + -- Push the argument onto the test history for looking at later: + Self.Command_Response_T_Recv_Sync_History.Push (Arg); + end Command_Response_T_Recv_Sync; + + -- Requests to update/fetch the working parameters are made on this connector. + overriding procedure Working_Parameters_Memory_Region_Recv_Sync (Self : in out Instance; Arg : in Parameters_Memory_Region.T) is + use Parameter_Enums.Parameter_Table_Operation_Type; + begin + -- If it is a get then fill in the data: + if Arg.Operation = Get then + declare + subtype Safe_Byte_Array_Type is Basic_Types.Byte_Array (0 .. Arg.Region.Length - 1); + Safe_Byte_Array : Safe_Byte_Array_Type with Import, Convention => Ada, Address => Arg.Region.Address; + begin + Safe_Byte_Array := Self.Working; + end; + end if; + + -- Push the argument onto the test history for looking at later: + Self.Working_Parameters_Memory_Region_Recv_Sync_History.Push (Arg); + end Working_Parameters_Memory_Region_Recv_Sync; + + -- Requests to update/fetch the default parameters are made on this connector. + overriding procedure Default_Parameters_Memory_Region_Recv_Sync (Self : in out Instance; Arg : in Parameters_Memory_Region.T) is + use Parameter_Enums.Parameter_Table_Operation_Type; + begin + -- If it is a get then fill in the data: + if Arg.Operation = Get then + declare + subtype Safe_Byte_Array_Type is Basic_Types.Byte_Array (0 .. Arg.Region.Length - 1); + Safe_Byte_Array : Safe_Byte_Array_Type with Import, Convention => Ada, Address => Arg.Region.Address; + begin + Safe_Byte_Array := Self.Default; + end; + end if; + + -- Push the argument onto the test history for looking at later: + Self.Default_Parameters_Memory_Region_Recv_Sync_History.Push (Arg); + end Default_Parameters_Memory_Region_Recv_Sync; + + -- The event send connector + overriding procedure Event_T_Recv_Sync (Self : in out Instance; Arg : in Event.T) is + begin + -- Push the argument onto the test history for looking at later: + Self.Event_T_Recv_Sync_History.Push (Arg); + -- Dispatch the event to the correct handler: + Self.Dispatch_Event (Arg); + end Event_T_Recv_Sync; + + -- The system time is retrieved via this connector. + overriding function Sys_Time_T_Return (Self : in out Instance) return Sys_Time.T is + -- Return the system time: + To_Return : constant Sys_Time.T := Self.System_Time; + begin + -- Push the argument onto the test history for looking at later: + Self.Sys_Time_T_Return_History.Push (To_Return); + return To_Return; + end Sys_Time_T_Return; + + --------------------------------------- + -- Invoker connector primitives: + --------------------------------------- + -- This procedure is called when a Command_T_Send message is dropped due to a full queue. + overriding procedure Command_T_Send_Dropped (Self : in out Instance; Arg : in Command.T) is + Ignore : Command.T renames Arg; + begin + if not Self.Expect_Command_T_Send_Dropped then + pragma Assert (False, "The component's queue filled up when Command_T_Send was called!"); + else + Self.Command_T_Send_Dropped_Count := Self.Command_T_Send_Dropped_Count + 1; + Self.Expect_Command_T_Send_Dropped := False; + end if; + end Command_T_Send_Dropped; + + ----------------------------------------------- + -- Event handler primitive: + ----------------------------------------------- + -- Description: + -- Events for the Parameter Manager component. + -- Starting parameter table copy from source to destination. + overriding procedure Starting_Parameter_Table_Copy (Self : in out Instance; Arg : in Packed_Parameter_Table_Copy_Type.T) is + begin + -- Push the argument onto the test history for looking at later: + Self.Starting_Parameter_Table_Copy_History.Push (Arg); + end Starting_Parameter_Table_Copy; + + -- Finished parameter table copy from source to destination, without errors. + overriding procedure Finished_Parameter_Table_Copy (Self : in out Instance; Arg : in Packed_Parameter_Table_Copy_Type.T) is + begin + -- Push the argument onto the test history for looking at later: + Self.Finished_Parameter_Table_Copy_History.Push (Arg); + end Finished_Parameter_Table_Copy; + + -- A command was received with invalid parameters. + overriding procedure Invalid_Command_Received (Self : in out Instance; Arg : in Invalid_Command_Info.T) is + begin + -- Push the argument onto the test history for looking at later: + Self.Invalid_Command_Received_History.Push (Arg); + end Invalid_Command_Received; + + -- A timeout occured while waiting for a parameter table copy operation to complete. + overriding procedure Parameter_Table_Copy_Timeout (Self : in out Instance) is + Arg : constant Natural := 0; + begin + -- Push the argument onto the test history for looking at later: + Self.Parameter_Table_Copy_Timeout_History.Push (Arg); + end Parameter_Table_Copy_Timeout; + + -- A parameter table copy failed. + overriding procedure Parameter_Table_Copy_Failure (Self : in out Instance; Arg : in Parameters_Memory_Region_Release.T) is + begin + -- Push the argument onto the test history for looking at later: + Self.Parameter_Table_Copy_Failure_History.Push (Arg); + end Parameter_Table_Copy_Failure; + + -- A command was dropped due to a full queue. + overriding procedure Command_Dropped (Self : in out Instance; Arg : in Command_Header.T) is + begin + -- Push the argument onto the test history for looking at later: + Self.Command_Dropped_History.Push (Arg); + end Command_Dropped; + + ----------------------------------------------- + -- Special primitives for activating component + -- queues: + ----------------------------------------------- + -- Force the component to drain the entire queue + not overriding function Dispatch_All (Self : in out Instance) return Natural is + Num_Dispatched : Natural; + begin + Self.Log (" Dispatching all items off queue."); + Num_Dispatched := Self.Component_Instance.Dispatch_All; + Self.Log (" Dispatched " & String_Util.Trim_Both (Natural'Image (Num_Dispatched)) & " items from queue."); + return Num_Dispatched; + end Dispatch_All; + + not overriding function Dispatch_N (Self : in out Instance; N : in Positive := 1) return Natural is + Num_Dispatched : Natural; + begin + Self.Log (" Dispatching up to " & String_Util.Trim_Both (Positive'Image (N)) & " items from queue."); + Num_Dispatched := Self.Component_Instance.Dispatch_N (N); + Self.Log (" Dispatched " & String_Util.Trim_Both (Natural'Image (Num_Dispatched)) & " items from queue."); + return Num_Dispatched; + end Dispatch_N; + + ----------------------------------------------- + -- Custom white-box testing functions: + ----------------------------------------------- + function Get_Parameter_Bytes_Region (Self : in out Instance) return Memory_Region.T is + begin + return Self.Component_Instance.Parameter_Bytes_Region; + end Get_Parameter_Bytes_Region; + +end Component.Parameter_Manager.Implementation.Tester; diff --git a/src/components/parameter_manager/test/component-parameter_manager-implementation-tester.ads b/src/components/parameter_manager/test/component-parameter_manager-implementation-tester.ads new file mode 100644 index 0000000..10c430c --- /dev/null +++ b/src/components/parameter_manager/test/component-parameter_manager-implementation-tester.ads @@ -0,0 +1,125 @@ +-------------------------------------------------------------------------------- +-- Parameter_Manager Component Tester Spec +-------------------------------------------------------------------------------- + +-- Includes: +with Component.Parameter_Manager_Reciprocal; +with Printable_History; +with Command_Response.Representation; +with Parameters_Memory_Region.Representation; +with Event.Representation; +with Sys_Time.Representation; +with Event; +with Packed_Parameter_Table_Copy_Type.Representation; +with Invalid_Command_Info.Representation; +with Parameters_Memory_Region_Release.Representation; +with Command_Header.Representation; + +-- This component is responsible for managing a working and default parameter table. Its sole responsibility is to respond to commands to copy parameter tables from one region to another. +package Component.Parameter_Manager.Implementation.Tester is + + use Component.Parameter_Manager_Reciprocal; + -- Invoker connector history packages: + package Command_Response_T_Recv_Sync_History_Package is new Printable_History (Command_Response.T, Command_Response.Representation.Image); + package Working_Parameters_Memory_Region_Recv_Sync_History_Package is new Printable_History (Parameters_Memory_Region.T, Parameters_Memory_Region.Representation.Image); + package Default_Parameters_Memory_Region_Recv_Sync_History_Package is new Printable_History (Parameters_Memory_Region.T, Parameters_Memory_Region.Representation.Image); + package Event_T_Recv_Sync_History_Package is new Printable_History (Event.T, Event.Representation.Image); + package Sys_Time_T_Return_History_Package is new Printable_History (Sys_Time.T, Sys_Time.Representation.Image); + + -- Event history packages: + package Starting_Parameter_Table_Copy_History_Package is new Printable_History (Packed_Parameter_Table_Copy_Type.T, Packed_Parameter_Table_Copy_Type.Representation.Image); + package Finished_Parameter_Table_Copy_History_Package is new Printable_History (Packed_Parameter_Table_Copy_Type.T, Packed_Parameter_Table_Copy_Type.Representation.Image); + package Invalid_Command_Received_History_Package is new Printable_History (Invalid_Command_Info.T, Invalid_Command_Info.Representation.Image); + package Parameter_Table_Copy_Timeout_History_Package is new Printable_History (Natural, Natural'Image); + package Parameter_Table_Copy_Failure_History_Package is new Printable_History (Parameters_Memory_Region_Release.T, Parameters_Memory_Region_Release.Representation.Image); + package Command_Dropped_History_Package is new Printable_History (Command_Header.T, Command_Header.Representation.Image); + + -- Component class instance: + type Instance is new Component.Parameter_Manager_Reciprocal.Base_Instance with record + -- The component instance under test: + Component_Instance : aliased Component.Parameter_Manager.Implementation.Instance; + -- Connector histories: + Command_Response_T_Recv_Sync_History : Command_Response_T_Recv_Sync_History_Package.Instance; + Working_Parameters_Memory_Region_Recv_Sync_History : Working_Parameters_Memory_Region_Recv_Sync_History_Package.Instance; + Default_Parameters_Memory_Region_Recv_Sync_History : Default_Parameters_Memory_Region_Recv_Sync_History_Package.Instance; + Event_T_Recv_Sync_History : Event_T_Recv_Sync_History_Package.Instance; + Sys_Time_T_Return_History : Sys_Time_T_Return_History_Package.Instance; + -- Event histories: + Starting_Parameter_Table_Copy_History : Starting_Parameter_Table_Copy_History_Package.Instance; + Finished_Parameter_Table_Copy_History : Finished_Parameter_Table_Copy_History_Package.Instance; + Invalid_Command_Received_History : Invalid_Command_Received_History_Package.Instance; + Parameter_Table_Copy_Timeout_History : Parameter_Table_Copy_Timeout_History_Package.Instance; + Parameter_Table_Copy_Failure_History : Parameter_Table_Copy_Failure_History_Package.Instance; + Command_Dropped_History : Command_Dropped_History_Package.Instance; + -- Booleans to control assertion if message is dropped on async queue: + Expect_Command_T_Send_Dropped : Boolean := False; + Command_T_Send_Dropped_Count : Natural := 0; + -- Memory regions for simulation: + Default : Basic_Types.Byte_Array (0 .. 99) := (others => 14); + Working : Basic_Types.Byte_Array (0 .. 99) := (others => 14); + end record; + type Instance_Access is access all Instance; + + --------------------------------------- + -- Initialize component heap variables: + --------------------------------------- + procedure Init_Base (Self : in out Instance; Queue_Size : in Natural); + procedure Final_Base (Self : in out Instance); + + --------------------------------------- + -- Test initialization functions: + --------------------------------------- + procedure Connect (Self : in out Instance); + + --------------------------------------- + -- Invokee connector primitives: + --------------------------------------- + -- This connector is used to send the command response back to the command router. + overriding procedure Command_Response_T_Recv_Sync (Self : in out Instance; Arg : in Command_Response.T); + -- Requests to update/fetch the working parameters are made on this connector. + overriding procedure Working_Parameters_Memory_Region_Recv_Sync (Self : in out Instance; Arg : in Parameters_Memory_Region.T); + -- Requests to update/fetch the default parameters are made on this connector. + overriding procedure Default_Parameters_Memory_Region_Recv_Sync (Self : in out Instance; Arg : in Parameters_Memory_Region.T); + -- The event send connector + overriding procedure Event_T_Recv_Sync (Self : in out Instance; Arg : in Event.T); + -- The system time is retrieved via this connector. + overriding function Sys_Time_T_Return (Self : in out Instance) return Sys_Time.T; + + --------------------------------------- + -- Invoker connector primitives: + --------------------------------------- + -- This procedure is called when a Command_T_Send message is dropped due to a full queue. + overriding procedure Command_T_Send_Dropped (Self : in out Instance; Arg : in Command.T); + + ----------------------------------------------- + -- Event handler primitive: + ----------------------------------------------- + -- Description: + -- Events for the Parameter Manager component. + -- Starting parameter table copy from source to destination. + overriding procedure Starting_Parameter_Table_Copy (Self : in out Instance; Arg : in Packed_Parameter_Table_Copy_Type.T); + -- Finished parameter table copy from source to destination, without errors. + overriding procedure Finished_Parameter_Table_Copy (Self : in out Instance; Arg : in Packed_Parameter_Table_Copy_Type.T); + -- A command was received with invalid parameters. + overriding procedure Invalid_Command_Received (Self : in out Instance; Arg : in Invalid_Command_Info.T); + -- A timeout occured while waiting for a parameter table copy operation to complete. + overriding procedure Parameter_Table_Copy_Timeout (Self : in out Instance); + -- A parameter table copy failed. + overriding procedure Parameter_Table_Copy_Failure (Self : in out Instance; Arg : in Parameters_Memory_Region_Release.T); + -- A command was dropped due to a full queue. + overriding procedure Command_Dropped (Self : in out Instance; Arg : in Command_Header.T); + + ----------------------------------------------- + -- Special primitives for activating component + -- queue: + ----------------------------------------------- + -- Tell the component to dispatch all items off of its queue: + not overriding function Dispatch_All (Self : in out Instance) return Natural; + -- Tell the component to dispatch n items off of its queue: + not overriding function Dispatch_N (Self : in out Instance; N : in Positive := 1) return Natural; + + ----------------------------------------------- + -- Custom white-box testing functions: + ----------------------------------------------- + function Get_Parameter_Bytes_Region (Self : in out Instance) return Memory_Region.T; +end Component.Parameter_Manager.Implementation.Tester; diff --git a/src/components/parameter_manager/test/env.py b/src/components/parameter_manager/test/env.py new file mode 100644 index 0000000..ebe0450 --- /dev/null +++ b/src/components/parameter_manager/test/env.py @@ -0,0 +1,9 @@ +from environments import test # noqa: F401 +import os.path + +this_dir = os.path.dirname(os.path.realpath(__file__)) +os.environ["EXTRA_BUILD_PATH"] = this_dir + os.pathsep \ + + os.path.realpath(os.path.join(this_dir, "test_component_1")) + os.pathsep \ + + os.path.realpath(os.path.join(this_dir, "test_component_2")) + os.pathsep \ + + os.path.realpath(os.path.join(this_dir, "..")) + os.pathsep \ + + os.path.realpath(os.path.join(this_dir, "test_assembly")) diff --git a/src/components/parameter_manager/test/parameter_manager.tests.yaml b/src/components/parameter_manager/test/parameter_manager.tests.yaml new file mode 100644 index 0000000..e66aa02 --- /dev/null +++ b/src/components/parameter_manager/test/parameter_manager.tests.yaml @@ -0,0 +1,15 @@ +--- +description: This is a unit test suite for the Parameter Manager component. +tests: + - name: Test_Nominal_Copy_Default_To_Working + description: This unit test tests the nominal copy command from default to working. + - name: Test_Nominal_Copy_Working_To_Default + description: This unit test tests the nominal copy command from working to default. + - name: Test_Copy_Failure + description: This unit test tests the component's response to a failed parameter table copy. + - name: Test_Copy_Timeout + description: This unit test tests the component's response when the destination component does not respond to a copy command before a timeout occurs. + - name: Test_Full_Queue + description: This unit test tests a command or memory region being dropped due to a full queue. + - name: Test_Invalid_Command + description: This unit test exercises that an invalid command throws the appropriate event. diff --git a/src/components/parameter_manager/test/parameter_manager_tests-implementation.adb b/src/components/parameter_manager/test/parameter_manager_tests-implementation.adb new file mode 100644 index 0000000..40c7f5b --- /dev/null +++ b/src/components/parameter_manager/test/parameter_manager_tests-implementation.adb @@ -0,0 +1,489 @@ +-------------------------------------------------------------------------------- +-- Parameter_Manager Tests Body +-------------------------------------------------------------------------------- + +with Ada.Real_Time; +with Basic_Assertions; use Basic_Assertions; +with Command_Response.Assertion; use Command_Response.Assertion; +with Command_Enums; use Command_Enums.Command_Response_Status; +with Command; +with Interfaces; use Interfaces; +with Memory_Region; +with Parameters_Memory_Region.Assertion; use Parameters_Memory_Region.Assertion; +with Parameters_Memory_Region_Release.Assertion; use Parameters_Memory_Region_Release.Assertion; +with Parameter_Enums; +with Parameter_Manager_Enums; use Parameter_Manager_Enums.Parameter_Table_Copy_Type; +with Basic_Types; +with Invalid_Command_Info.Assertion; use Invalid_Command_Info.Assertion; +with Command_Header.Assertion; use Command_Header.Assertion; +with Packed_Parameter_Table_Copy_Type.Assertion; use Packed_Parameter_Table_Copy_Type.Assertion; +use Parameter_Enums.Parameter_Table_Update_Status; +use Parameter_Enums.Parameter_Table_Operation_Type; + +package body Parameter_Manager_Tests.Implementation is + + -- Globals to control task behavior. There is no thread safety here... but this + -- is testing code. + Task_Send_Response : Boolean := False; + Task_Send_Response_Twice : Boolean := False; + Task_Send_Timeout : Boolean := False; + Task_Response : Parameter_Enums.Parameter_Table_Update_Status.E := Parameter_Enums.Parameter_Table_Update_Status.Success; + Task_Response2 : Parameter_Enums.Parameter_Table_Update_Status.E := Parameter_Enums.Parameter_Table_Update_Status.Success; + + ------------------------------------------------------------------------- + -- Fixtures: + ------------------------------------------------------------------------- + + overriding procedure Set_Up_Test (Self : in out Instance) is + begin + -- Reset globals: + Task_Send_Response := False; + Task_Send_Response_Twice := False; + Task_Send_Timeout := False; + Task_Response := Parameter_Enums.Parameter_Table_Update_Status.Success; + Task_Response2 := Parameter_Enums.Parameter_Table_Update_Status.Success; + + -- Allocate heap memory to component: + Self.Tester.Init_Base (Queue_Size => Self.Tester.Component_Instance.Get_Max_Queue_Element_Size * 3); + + -- Make necessary connections between tester and component: + Self.Tester.Connect; + + -- Call component init here. + Self.Tester.Component_Instance.Init (Parameter_Table_Length => 100, Ticks_Until_Timeout => 3); + + -- Call the component set up method that the assembly would normally call. + Self.Tester.Component_Instance.Set_Up; + end Set_Up_Test; + + overriding procedure Tear_Down_Test (Self : in out Instance) is + begin + -- Free component heap: + Self.Tester.Final_Base; + end Tear_Down_Test; + + ------------------------------------------------------------------------- + -- Task used to simulate downstream components: + ------------------------------------------------------------------------- + + procedure Sleep (Ms : in Natural := 5) is + use Ada.Real_Time; + Sleep_Time : constant Ada.Real_Time.Time_Span := Ada.Real_Time.Milliseconds (Ms); + Wake_Time : constant Ada.Real_Time.Time := Ada.Real_Time.Clock + Sleep_Time; + begin + delay until Wake_Time; + end Sleep; + + -- Task type for active components: + type Boolean_Access is access all Boolean; + task type Simulator_Task ( + Class_Self : Class_Access; + Task_Exit : Boolean_Access + ); + + Sim_Bytes : aliased Basic_Types.Byte_Array := (0 .. 99 => 12); + Sim_Bytes_2 : aliased Basic_Types.Byte_Array := (0 .. 99 => 11); + + task body Simulator_Task is + Ignore : Natural; + Count : Natural := 0; + Tick_Count : Natural := 0; + begin + while not Task_Exit.all and then Count < 2000 loop + + -- Increment variables: + Count := Count + 1; + + if Task_Send_Response then + -- Send a valid response: + Sleep (4); + Class_Self.all.Tester.Parameters_Memory_Region_Release_T_Send (( + Region => (Address => Sim_Bytes'Address, Length => Sim_Bytes'Length), + Status => Task_Response + )); + Task_Send_Response := False; + elsif Task_Send_Response_Twice then + -- Send a valid response: + Sleep (4); + Class_Self.all.Tester.Parameters_Memory_Region_Release_T_Send (( + Region => (Address => Sim_Bytes_2'Address, Length => Sim_Bytes_2'Length), + Status => Task_Response2 + )); + Task_Send_Response_Twice := False; + Task_Send_Response := True; + elsif Task_Send_Timeout then + -- Send a valid response: + Sleep (4); + Class_Self.all.Tester.Timeout_Tick_Send (((0, 0), 0)); + Tick_Count := Tick_Count + 1; + if Tick_Count > 4 then + Tick_Count := 0; + Task_Send_Timeout := False; + end if; + else + -- Sleep: + Sleep (2); + end if; + end loop; + end Simulator_Task; + + ------------------------------------------------------------------------- + -- Tests: + ------------------------------------------------------------------------- + overriding procedure Test_Nominal_Copy_Default_To_Working (Self : in out Instance) is + T : Component.Parameter_Manager.Implementation.Tester.Instance_Access renames Self.Tester; + Task_Exit : aliased Boolean := False; + Sim_Task : Simulator_Task (Self'Unchecked_Access, Task_Exit'Unchecked_Access); + begin + -- Send copy command: + T.Command_T_Send (T.Commands.Copy_Parameter_Table ((Copy_Type => Default_To_Working))); + + -- Execute the command and tell the task to respond. + Task_Send_Response_Twice := True; + Natural_Assert.Eq (T.Dispatch_All, 1); + + -- Copy to working should have occured now. Check data: + Natural_Assert.Eq (T.Default_Parameters_Memory_Region_Recv_Sync_History.Get_Count, 1); + Parameters_Memory_Region_Assert.Eq ( + T.Default_Parameters_Memory_Region_Recv_Sync_History.Get (1), + (Region => T.Get_Parameter_Bytes_Region, Operation => Get) + ); + Natural_Assert.Eq (T.Working_Parameters_Memory_Region_Recv_Sync_History.Get_Count, 1); + Parameters_Memory_Region_Assert.Eq ( + T.Working_Parameters_Memory_Region_Recv_Sync_History.Get (1), + (Region => T.Get_Parameter_Bytes_Region, Operation => Set) + ); + + -- Check region data: + declare + Region : constant Memory_Region.T := T.Get_Parameter_Bytes_Region; + subtype Safe_Byte_Array_Type is Basic_Types.Byte_Array (0 .. Region.Length - 1); + Safe_Byte_Array : Safe_Byte_Array_Type with Import, Convention => Ada, Address => Region.Address; + begin + Byte_Array_Assert.Eq (Safe_Byte_Array, T.Default); + end; + + -- Check events: + Natural_Assert.Eq (T.Event_T_Recv_Sync_History.Get_Count, 2); + Natural_Assert.Eq (T.Starting_Parameter_Table_Copy_History.Get_Count, 1); + Packed_Parameter_Table_Copy_Type_Assert.Eq (T.Starting_Parameter_Table_Copy_History.Get (1), (Copy_Type => Default_To_Working)); + Natural_Assert.Eq (T.Finished_Parameter_Table_Copy_History.Get_Count, 1); + Packed_Parameter_Table_Copy_Type_Assert.Eq (T.Finished_Parameter_Table_Copy_History.Get (1), (Copy_Type => Default_To_Working)); + + -- Check command response: + Natural_Assert.Eq (T.Command_Response_T_Recv_Sync_History.Get_Count, 1); + Command_Response_Assert.Eq (T.Command_Response_T_Recv_Sync_History.Get (1), (Source_Id => 0, Registration_Id => 0, Command_Id => T.Commands.Get_Copy_Parameter_Table_Id, Status => Success)); + + -- Kill our helper task. + Task_Exit := True; + end Test_Nominal_Copy_Default_To_Working; + + overriding procedure Test_Nominal_Copy_Working_To_Default (Self : in out Instance) is + T : Component.Parameter_Manager.Implementation.Tester.Instance_Access renames Self.Tester; + Task_Exit : aliased Boolean := False; + Sim_Task : Simulator_Task (Self'Unchecked_Access, Task_Exit'Unchecked_Access); + begin + -- Send copy command: + T.Command_T_Send (T.Commands.Copy_Parameter_Table ((Copy_Type => Working_To_Default))); + + -- Execute the command and tell the task to respond. + Task_Send_Response_Twice := True; + Natural_Assert.Eq (T.Dispatch_All, 1); + + -- Copy to working should have occured now. Check data: + Natural_Assert.Eq (T.Working_Parameters_Memory_Region_Recv_Sync_History.Get_Count, 1); + Parameters_Memory_Region_Assert.Eq ( + T.Working_Parameters_Memory_Region_Recv_Sync_History.Get (1), + (Region => T.Get_Parameter_Bytes_Region, Operation => Get) + ); + Natural_Assert.Eq (T.Default_Parameters_Memory_Region_Recv_Sync_History.Get_Count, 1); + Parameters_Memory_Region_Assert.Eq ( + T.Default_Parameters_Memory_Region_Recv_Sync_History.Get (1), + (Region => T.Get_Parameter_Bytes_Region, Operation => Set) + ); + + -- Check region data: + declare + Region : constant Memory_Region.T := T.Get_Parameter_Bytes_Region; + subtype Safe_Byte_Array_Type is Basic_Types.Byte_Array (0 .. Region.Length - 1); + Safe_Byte_Array : Safe_Byte_Array_Type with Import, Convention => Ada, Address => Region.Address; + begin + Byte_Array_Assert.Eq (Safe_Byte_Array, T.Working); + end; + + -- Check events: + Natural_Assert.Eq (T.Event_T_Recv_Sync_History.Get_Count, 2); + Natural_Assert.Eq (T.Starting_Parameter_Table_Copy_History.Get_Count, 1); + Packed_Parameter_Table_Copy_Type_Assert.Eq (T.Starting_Parameter_Table_Copy_History.Get (1), (Copy_Type => Working_To_Default)); + Natural_Assert.Eq (T.Finished_Parameter_Table_Copy_History.Get_Count, 1); + Packed_Parameter_Table_Copy_Type_Assert.Eq (T.Finished_Parameter_Table_Copy_History.Get (1), (Copy_Type => Working_To_Default)); + + -- Check command response: + Natural_Assert.Eq (T.Command_Response_T_Recv_Sync_History.Get_Count, 1); + Command_Response_Assert.Eq (T.Command_Response_T_Recv_Sync_History.Get (1), (Source_Id => 0, Registration_Id => 0, Command_Id => T.Commands.Get_Copy_Parameter_Table_Id, Status => Success)); + + -- Kill our helper task. + Task_Exit := True; + end Test_Nominal_Copy_Working_To_Default; + + overriding procedure Test_Copy_Failure (Self : in out Instance) is + T : Component.Parameter_Manager.Implementation.Tester.Instance_Access renames Self.Tester; + Task_Exit : aliased Boolean := False; + Sim_Task : Simulator_Task (Self'Unchecked_Access, Task_Exit'Unchecked_Access); + begin + -- Set task response to something other than success: + Task_Response := Parameter_Enums.Parameter_Table_Update_Status.Parameter_Error; + + -- Send copy command: + T.Command_T_Send (T.Commands.Copy_Parameter_Table ((Copy_Type => Working_To_Default))); + + -- Execute the command and tell the task to respond. + Task_Send_Response := True; + Natural_Assert.Eq (T.Dispatch_All, 1); + + -- Copy from working should have occured now. Check data: + Natural_Assert.Eq (T.Working_Parameters_Memory_Region_Recv_Sync_History.Get_Count, 1); + Parameters_Memory_Region_Assert.Eq ( + T.Working_Parameters_Memory_Region_Recv_Sync_History.Get (1), + (Region => T.Get_Parameter_Bytes_Region, Operation => Get) + ); + -- No copy to default: + Natural_Assert.Eq (T.Default_Parameters_Memory_Region_Recv_Sync_History.Get_Count, 0); + + -- Check events: + Natural_Assert.Eq (T.Event_T_Recv_Sync_History.Get_Count, 2); + Natural_Assert.Eq (T.Starting_Parameter_Table_Copy_History.Get_Count, 1); + Packed_Parameter_Table_Copy_Type_Assert.Eq (T.Starting_Parameter_Table_Copy_History.Get (1), (Copy_Type => Working_To_Default)); + Natural_Assert.Eq (T.Finished_Parameter_Table_Copy_History.Get_Count, 0); + Natural_Assert.Eq (T.Parameter_Table_Copy_Failure_History.Get_Count, 1); + Parameters_Memory_Region_Release_Assert.Eq (T.Parameter_Table_Copy_Failure_History.Get (1), ( + Region => (Address => Sim_Bytes'Address, Length => Sim_Bytes'Length), + Status => Parameter_Enums.Parameter_Table_Update_Status.Parameter_Error + )); + + -- Check command response: + Natural_Assert.Eq (T.Command_Response_T_Recv_Sync_History.Get_Count, 1); + Command_Response_Assert.Eq (T.Command_Response_T_Recv_Sync_History.Get (1), (Source_Id => 0, Registration_Id => 0, Command_Id => T.Commands.Get_Copy_Parameter_Table_Id, Status => Failure)); + + -- Set task response 2 to something other than success: + Task_Response := Parameter_Enums.Parameter_Table_Update_Status.Crc_Error; + Task_Response2 := Parameter_Enums.Parameter_Table_Update_Status.Success; + + -- Send copy command: + T.Command_T_Send (T.Commands.Copy_Parameter_Table ((Copy_Type => Working_To_Default))); + + -- Execute the command and tell the task to respond. + Task_Send_Response_Twice := True; + Natural_Assert.Eq (T.Dispatch_All, 1); + + -- Copy from working should have occured now. Check data: + Natural_Assert.Eq (T.Working_Parameters_Memory_Region_Recv_Sync_History.Get_Count, 2); + Parameters_Memory_Region_Assert.Eq ( + T.Working_Parameters_Memory_Region_Recv_Sync_History.Get (2), + (Region => T.Get_Parameter_Bytes_Region, Operation => Get) + ); + -- Copy to default: + Natural_Assert.Eq (T.Default_Parameters_Memory_Region_Recv_Sync_History.Get_Count, 1); + Parameters_Memory_Region_Assert.Eq ( + T.Default_Parameters_Memory_Region_Recv_Sync_History.Get (1), + (Region => T.Get_Parameter_Bytes_Region, Operation => Set) + ); + + -- Check events: + Natural_Assert.Eq (T.Event_T_Recv_Sync_History.Get_Count, 4); + Natural_Assert.Eq (T.Starting_Parameter_Table_Copy_History.Get_Count, 2); + Packed_Parameter_Table_Copy_Type_Assert.Eq (T.Starting_Parameter_Table_Copy_History.Get (2), (Copy_Type => Working_To_Default)); + Natural_Assert.Eq (T.Finished_Parameter_Table_Copy_History.Get_Count, 0); + Natural_Assert.Eq (T.Parameter_Table_Copy_Failure_History.Get_Count, 2); + Parameters_Memory_Region_Release_Assert.Eq (T.Parameter_Table_Copy_Failure_History.Get (2), ( + Region => (Address => Sim_Bytes'Address, Length => Sim_Bytes'Length), + Status => Parameter_Enums.Parameter_Table_Update_Status.Crc_Error + )); + + -- Check command response: + Natural_Assert.Eq (T.Command_Response_T_Recv_Sync_History.Get_Count, 2); + Command_Response_Assert.Eq (T.Command_Response_T_Recv_Sync_History.Get (2), (Source_Id => 0, Registration_Id => 0, Command_Id => T.Commands.Get_Copy_Parameter_Table_Id, Status => Failure)); + + -- Set task response 2 to something other than success: + Task_Response := Parameter_Enums.Parameter_Table_Update_Status.Crc_Error; + Task_Response2 := Parameter_Enums.Parameter_Table_Update_Status.Success; + + -- Send copy command: + T.Command_T_Send (T.Commands.Copy_Parameter_Table ((Copy_Type => Default_To_Working))); + + -- Execute the command and tell the task to respond. + Task_Send_Response_Twice := True; + Natural_Assert.Eq (T.Dispatch_All, 1); + + -- Copy from working should have occured now. Check data: + Natural_Assert.Eq (T.Default_Parameters_Memory_Region_Recv_Sync_History.Get_Count, 2); + Parameters_Memory_Region_Assert.Eq ( + T.Default_Parameters_Memory_Region_Recv_Sync_History.Get (2), + (Region => T.Get_Parameter_Bytes_Region, Operation => Get) + ); + -- Copy to default: + Natural_Assert.Eq (T.Working_Parameters_Memory_Region_Recv_Sync_History.Get_Count, 3); + Parameters_Memory_Region_Assert.Eq ( + T.Working_Parameters_Memory_Region_Recv_Sync_History.Get (3), + (Region => T.Get_Parameter_Bytes_Region, Operation => Set) + ); + + -- Check events: + Natural_Assert.Eq (T.Event_T_Recv_Sync_History.Get_Count, 6); + Natural_Assert.Eq (T.Starting_Parameter_Table_Copy_History.Get_Count, 3); + Packed_Parameter_Table_Copy_Type_Assert.Eq (T.Starting_Parameter_Table_Copy_History.Get (3), (Copy_Type => Default_To_Working)); + Natural_Assert.Eq (T.Finished_Parameter_Table_Copy_History.Get_Count, 0); + Natural_Assert.Eq (T.Parameter_Table_Copy_Failure_History.Get_Count, 3); + Parameters_Memory_Region_Release_Assert.Eq (T.Parameter_Table_Copy_Failure_History.Get (3), ( + Region => (Address => Sim_Bytes'Address, Length => Sim_Bytes'Length), + Status => Parameter_Enums.Parameter_Table_Update_Status.Crc_Error + )); + + -- Check command response: + Natural_Assert.Eq (T.Command_Response_T_Recv_Sync_History.Get_Count, 3); + Command_Response_Assert.Eq (T.Command_Response_T_Recv_Sync_History.Get (3), (Source_Id => 0, Registration_Id => 0, Command_Id => T.Commands.Get_Copy_Parameter_Table_Id, Status => Failure)); + + -- Set task response 2 to something other than success: + Task_Response := Parameter_Enums.Parameter_Table_Update_Status.Length_Error; + Task_Response2 := Parameter_Enums.Parameter_Table_Update_Status.Success; + + -- Send copy command: + T.Command_T_Send (T.Commands.Copy_Parameter_Table ((Copy_Type => Default_To_Working))); + + -- Execute the command and tell the task to respond. + Task_Send_Response := True; + Natural_Assert.Eq (T.Dispatch_All, 1); + + -- Copy from working should have occured now. Check data: + Natural_Assert.Eq (T.Default_Parameters_Memory_Region_Recv_Sync_History.Get_Count, 3); + Parameters_Memory_Region_Assert.Eq ( + T.Default_Parameters_Memory_Region_Recv_Sync_History.Get (3), + (Region => T.Get_Parameter_Bytes_Region, Operation => Get) + ); + -- Copy to default: + Natural_Assert.Eq (T.Working_Parameters_Memory_Region_Recv_Sync_History.Get_Count, 3); + + -- Check events: + Natural_Assert.Eq (T.Event_T_Recv_Sync_History.Get_Count, 8); + Natural_Assert.Eq (T.Starting_Parameter_Table_Copy_History.Get_Count, 4); + Packed_Parameter_Table_Copy_Type_Assert.Eq (T.Starting_Parameter_Table_Copy_History.Get (3), (Copy_Type => Default_To_Working)); + Natural_Assert.Eq (T.Finished_Parameter_Table_Copy_History.Get_Count, 0); + Natural_Assert.Eq (T.Parameter_Table_Copy_Failure_History.Get_Count, 4); + Parameters_Memory_Region_Release_Assert.Eq (T.Parameter_Table_Copy_Failure_History.Get (4), ( + Region => (Address => Sim_Bytes'Address, Length => Sim_Bytes'Length), + Status => Parameter_Enums.Parameter_Table_Update_Status.Length_Error + )); + + -- Check command response: + Natural_Assert.Eq (T.Command_Response_T_Recv_Sync_History.Get_Count, 4); + Command_Response_Assert.Eq (T.Command_Response_T_Recv_Sync_History.Get (4), (Source_Id => 0, Registration_Id => 0, Command_Id => T.Commands.Get_Copy_Parameter_Table_Id, Status => Failure)); + + -- Kill our helper task. + Task_Exit := True; + end Test_Copy_Failure; + + overriding procedure Test_Copy_Timeout (Self : in out Instance) is + T : Component.Parameter_Manager.Implementation.Tester.Instance_Access renames Self.Tester; + Task_Exit : aliased Boolean := False; + Sim_Task : Simulator_Task (Self'Unchecked_Access, Task_Exit'Unchecked_Access); + begin + -- Send copy command: + T.Command_T_Send (T.Commands.Copy_Parameter_Table ((Copy_Type => Working_To_Default))); + + -- Execute the command and tell the task to respond with timeout + Task_Send_Timeout := True; + Natural_Assert.Eq (T.Dispatch_All, 1); + + -- Copy from working should have occured now. Check data: + Natural_Assert.Eq (T.Working_Parameters_Memory_Region_Recv_Sync_History.Get_Count, 1); + Parameters_Memory_Region_Assert.Eq ( + T.Working_Parameters_Memory_Region_Recv_Sync_History.Get (1), + (Region => T.Get_Parameter_Bytes_Region, Operation => Get) + ); + -- No copy to default: + Natural_Assert.Eq (T.Default_Parameters_Memory_Region_Recv_Sync_History.Get_Count, 0); + + -- Check events: + Natural_Assert.Eq (T.Event_T_Recv_Sync_History.Get_Count, 2); + Natural_Assert.Eq (T.Starting_Parameter_Table_Copy_History.Get_Count, 1); + Packed_Parameter_Table_Copy_Type_Assert.Eq (T.Starting_Parameter_Table_Copy_History.Get (1), (Copy_Type => Working_To_Default)); + Natural_Assert.Eq (T.Finished_Parameter_Table_Copy_History.Get_Count, 0); + Natural_Assert.Eq (T.Parameter_Table_Copy_Timeout_History.Get_Count, 1); + + -- Check command response: + Natural_Assert.Eq (T.Command_Response_T_Recv_Sync_History.Get_Count, 1); + Command_Response_Assert.Eq (T.Command_Response_T_Recv_Sync_History.Get (1), (Source_Id => 0, Registration_Id => 0, Command_Id => T.Commands.Get_Copy_Parameter_Table_Id, Status => Failure)); + + -- Send copy command: + T.Command_T_Send (T.Commands.Copy_Parameter_Table ((Copy_Type => Default_To_Working))); + + -- Execute the command and tell the task to respond with timeout + -- Wait a bit to make sure our simulator task is reset and ready to go + Sleep (50); + Task_Send_Timeout := True; + Natural_Assert.Eq (T.Dispatch_All, 1); + + -- Copy from working should have occured now. Check data: + Natural_Assert.Eq (T.Working_Parameters_Memory_Region_Recv_Sync_History.Get_Count, 1); + -- No copy to default: + Natural_Assert.Eq (T.Default_Parameters_Memory_Region_Recv_Sync_History.Get_Count, 1); + Parameters_Memory_Region_Assert.Eq ( + T.Default_Parameters_Memory_Region_Recv_Sync_History.Get (1), + (Region => T.Get_Parameter_Bytes_Region, Operation => Get) + ); + + -- Check events: + Natural_Assert.Eq (T.Event_T_Recv_Sync_History.Get_Count, 4); + Natural_Assert.Eq (T.Starting_Parameter_Table_Copy_History.Get_Count, 2); + Packed_Parameter_Table_Copy_Type_Assert.Eq (T.Starting_Parameter_Table_Copy_History.Get (2), (Copy_Type => Default_To_Working)); + Natural_Assert.Eq (T.Finished_Parameter_Table_Copy_History.Get_Count, 0); + Natural_Assert.Eq (T.Parameter_Table_Copy_Timeout_History.Get_Count, 2); + + -- Check command response: + Natural_Assert.Eq (T.Command_Response_T_Recv_Sync_History.Get_Count, 2); + Command_Response_Assert.Eq (T.Command_Response_T_Recv_Sync_History.Get (2), (Source_Id => 0, Registration_Id => 0, Command_Id => T.Commands.Get_Copy_Parameter_Table_Id, Status => Failure)); + + -- Kill our helper task. + Task_Exit := True; + end Test_Copy_Timeout; + + overriding procedure Test_Full_Queue (Self : in out Instance) is + T : Component.Parameter_Manager.Implementation.Tester.Instance_Access renames Self.Tester; + Cmd : Command.T; + begin + -- Send 3 commands to fill up queue. + Cmd.Header.Arg_Buffer_Length := Cmd.Arg_Buffer'Length; + T.Command_T_Send (Cmd); + T.Command_T_Send (Cmd); + T.Command_T_Send (Cmd); + + -- OK the next command should overflow the queue. + T.Expect_Command_T_Send_Dropped := True; + T.Command_T_Send (Cmd); + + -- Make sure event thrown: + Natural_Assert.Eq (T.Event_T_Recv_Sync_History.Get_Count, 1); + Natural_Assert.Eq (T.Command_Dropped_History.Get_Count, 1); + Command_Header_Assert.Eq (T.Command_Dropped_History.Get (1), Cmd.Header); + end Test_Full_Queue; + + overriding procedure Test_Invalid_Command (Self : in out Instance) is + T : Component.Parameter_Manager.Implementation.Tester.Instance_Access renames Self.Tester; + Cmd : Command.T := T.Commands.Copy_Parameter_Table ((Copy_Type => Working_To_Default)); + begin + -- Make the command invalid by modifying its length. + Cmd.Header.Arg_Buffer_Length := 22; + + -- Send bad command and expect bad response: + T.Command_T_Send (Cmd); + Natural_Assert.Eq (T.Dispatch_All, 1); + Natural_Assert.Eq (T.Command_Response_T_Recv_Sync_History.Get_Count, 1); + Command_Response_Assert.Eq (T.Command_Response_T_Recv_Sync_History.Get (1), (Source_Id => 0, Registration_Id => 0, Command_Id => T.Commands.Get_Copy_Parameter_Table_Id, Status => Length_Error)); + + -- Make sure some events were thrown: + Natural_Assert.Eq (T.Event_T_Recv_Sync_History.Get_Count, 1); + Natural_Assert.Eq (T.Invalid_Command_Received_History.Get_Count, 1); + Invalid_Command_Info_Assert.Eq (T.Invalid_Command_Received_History.Get (1), (Id => T.Commands.Get_Copy_Parameter_Table_Id, Errant_Field_Number => Interfaces.Unsigned_32'Last, Errant_Field => (0, 0, 0, 0, 0, 0, 0, 22))); + end Test_Invalid_Command; + +end Parameter_Manager_Tests.Implementation; diff --git a/src/components/parameter_manager/test/parameter_manager_tests-implementation.ads b/src/components/parameter_manager/test/parameter_manager_tests-implementation.ads new file mode 100644 index 0000000..e1b2607 --- /dev/null +++ b/src/components/parameter_manager/test/parameter_manager_tests-implementation.ads @@ -0,0 +1,34 @@ +-------------------------------------------------------------------------------- +-- Parameter_Manager Tests Spec +-------------------------------------------------------------------------------- + +-- This is a unit test suite for the Parameter Manager component. +package Parameter_Manager_Tests.Implementation is + + -- Test data and state: + type Instance is new Parameter_Manager_Tests.Base_Instance with private; + type Class_Access is access all Instance'Class; + +private + -- Fixture procedures: + overriding procedure Set_Up_Test (Self : in out Instance); + overriding procedure Tear_Down_Test (Self : in out Instance); + + -- This unit test tests the nominal copy command from default to working. + overriding procedure Test_Nominal_Copy_Default_To_Working (Self : in out Instance); + -- This unit test tests the nominal copy command from working to default. + overriding procedure Test_Nominal_Copy_Working_To_Default (Self : in out Instance); + -- This unit test tests the component's response to a failed parameter table copy. + overriding procedure Test_Copy_Failure (Self : in out Instance); + -- This unit test tests the component's response when the destination component does not respond to a copy command before a timeout occurs. + overriding procedure Test_Copy_Timeout (Self : in out Instance); + -- This unit test tests a command or memory region being dropped due to a full queue. + overriding procedure Test_Full_Queue (Self : in out Instance); + -- This unit test exercises that an invalid command throws the appropriate event. + overriding procedure Test_Invalid_Command (Self : in out Instance); + + -- Test data and state: + type Instance is new Parameter_Manager_Tests.Base_Instance with record + null; + end record; +end Parameter_Manager_Tests.Implementation; diff --git a/src/components/parameter_manager/test/test.adb b/src/components/parameter_manager/test/test.adb new file mode 100644 index 0000000..addafc6 --- /dev/null +++ b/src/components/parameter_manager/test/test.adb @@ -0,0 +1,23 @@ +-------------------------------------------------------------------------------- +-- Parameter_Manager Tests +-------------------------------------------------------------------------------- + +with AUnit.Reporter.Text; +with AUnit.Run; +with Parameter_Manager_Tests.Implementation.Suite; +-- Make sure any terminating tasks are handled and an appropriate +-- error message is printed. +with Unit_Test_Termination_Handler; +pragma Unreferenced (Unit_Test_Termination_Handler); + +procedure Test is + -- Create runner for test suite: + procedure Runner is new AUnit.Run.Test_Runner (Parameter_Manager_Tests.Implementation.Suite.Get); + -- Use the text reporter: + Reporter : AUnit.Reporter.Text.Text_Reporter; +begin + -- Add color output to test run: + AUnit.Reporter.Text.Set_Use_ANSI_Colors (Reporter, True); + -- Run tests: + Runner (Reporter); +end Test; diff --git a/src/components/parameter_manager/types/.all_path b/src/components/parameter_manager/types/.all_path new file mode 100644 index 0000000..e69de29 diff --git a/src/components/parameter_manager/types/packed_parameter_table_copy_type.record.yaml b/src/components/parameter_manager/types/packed_parameter_table_copy_type.record.yaml new file mode 100644 index 0000000..3b89028 --- /dev/null +++ b/src/components/parameter_manager/types/packed_parameter_table_copy_type.record.yaml @@ -0,0 +1,7 @@ +--- +description: Packed record which holds the Parameter Manager copy type. +fields: + - name: Copy_Type + description: This enumeration describes the source and destination of the Parameter Manager copy command. + type: Parameter_Manager_Enums.Parameter_Table_Copy_Type.E + format: E8 diff --git a/src/components/parameter_manager/types/parameter_manager_enums.enums.yaml b/src/components/parameter_manager/types/parameter_manager_enums.enums.yaml new file mode 100644 index 0000000..f45bb82 --- /dev/null +++ b/src/components/parameter_manager/types/parameter_manager_enums.enums.yaml @@ -0,0 +1,12 @@ +--- +description: These are enumerations defined for the Parameter Manager. +enums: + - name: Parameter_Table_Copy_Type + description: This enumeration describes the source and destination of the Parameter Manager copy command. + literals: + - name: Default_To_Working + value: 0 + description: Copy the parameter table from Default (NVRAM) to Working (RAM). + - name: Working_To_Default + value: 1 + description: Copy the parameter table from Working (RAM) to Default (NVRAM). diff --git a/src/last_chance_handler/linux/.Linux_path b/src/last_chance_handler/linux/.Linux_path new file mode 100644 index 0000000..e69de29 diff --git a/src/last_chance_handler/linux/last_chance_handler.adb b/src/last_chance_handler/linux/last_chance_handler.adb new file mode 100644 index 0000000..93a6a9d --- /dev/null +++ b/src/last_chance_handler/linux/last_chance_handler.adb @@ -0,0 +1,32 @@ +with GNAT.IO; +with System.Storage_Elements; + +package body Last_Chance_Handler is + + ------------------------- + -- Last_Chance_Handler -- + ------------------------- + + procedure Last_Chance_Handler (Msg : System.Address; Line : Integer) is + -- pragma Unreferenced (Msg, Line); + use System.Storage_Elements; -- make "+" visible for System.Address + + function Peek (Addr : System.Address) return Character is + C : Character with + Address => Addr; + begin + return C; + end Peek; + A : System.Address := Msg; + begin + GNAT.IO.Put ("LCH called => "); + while Peek (A) /= ASCII.NUL loop + GNAT.IO.Put (Peek (A)); + A := A + 1; + end loop; + GNAT.IO.Put (": "); + GNAT.IO.Put (Line); -- avoid the secondary stack for Line'Image + GNAT.IO.New_Line; + end Last_Chance_Handler; + +end Last_Chance_Handler; diff --git a/src/last_chance_handler/linux/last_chance_handler.ads b/src/last_chance_handler/linux/last_chance_handler.ads new file mode 100644 index 0000000..9930a51 --- /dev/null +++ b/src/last_chance_handler/linux/last_chance_handler.ads @@ -0,0 +1,10 @@ +with System; + +package Last_Chance_Handler is + + procedure Last_Chance_Handler (Msg : System.Address; Line : Integer) + with Export => True, + Convention => C, + External_Name => "__gnat_last_chance_handler"; + +end Last_Chance_Handler; diff --git a/src/last_chance_handler/pico/.Pico_path b/src/last_chance_handler/pico/.Pico_path new file mode 100644 index 0000000..e69de29 diff --git a/src/last_chance_handler/pico/env.py b/src/last_chance_handler/pico/env.py new file mode 100644 index 0000000..d9cba61 --- /dev/null +++ b/src/last_chance_handler/pico/env.py @@ -0,0 +1 @@ +from environments import pico # noqa: F401 diff --git a/src/last_chance_handler/pico/last_chance_handler.adb b/src/last_chance_handler/pico/last_chance_handler.adb new file mode 100644 index 0000000..4455e3c --- /dev/null +++ b/src/last_chance_handler/pico/last_chance_handler.adb @@ -0,0 +1,215 @@ +-- with Ada.Exceptions.Traceback; use Ada.Exceptions.Traceback; +-- with Stack_Trace_Addresses; +-- with Packed_Address; +-- with GNAT.Debug_Utilities; use GNAT.Debug_Utilities; +with Pico_Uart; +with Ccsds_Space_Packet; +with Ccsds_Primary_Header; use Ccsds_Primary_Header; +with Ccsds_Enums; +with Interfaces; use Interfaces; +with Ada.Unchecked_Conversion; +with Crc_16; use Crc_16; +with Sys_Time; +with Packed_Exception_Occurrence; +with Basic_Types; +with Component.Ccsds_Serial_Interface.Implementation; -- grab sync pattern from here +with System.Storage_Elements; use System.Storage_Elements; +with Pico; + +-- +-- Info on Ada Exception_Occurence type: +-- https://www.radford.edu/~nokie/classes/320/std_lib_html/ada-exceptions.html#49 +-- + +package body Last_Chance_Handler is + + -- This helper function creates a packed record which holds all the information + -- related to the exception_occurance. + function Form_Exception_Data (Error : in Exception_Occurrence) return Packed_Exception_Occurrence.T is + -- Function to convert a character to a byte: + function Char_To_Byte is new Ada.Unchecked_Conversion (Source => Character, Target => Unsigned_8); + + -- Grab some information from the Error data structure: + Name : constant String := Exception_Name (Error); + Msg : constant String := Exception_Message (Error); + + -- Exception data packed record: + Packed_Exception_Data : Packed_Exception_Occurrence.T := ( + Exception_Name => (others => 0), + Exception_Message => (others => 0), + Stack_Trace_Depth => 0, + Stack_Trace => (others => (Address => To_Address (Integer_Address (0)))) + ); + begin + -- Copy the name into the first section. + declare + Copy_Idx : Natural := Packed_Exception_Data.Exception_Name'First; + begin + for Char of Name loop + -- Copy each character: + Packed_Exception_Data.Exception_Name (Copy_Idx) := Char_To_Byte (Char); + + -- Don't overflow. + Copy_Idx := Copy_Idx + 1; + if Copy_Idx > Packed_Exception_Data.Exception_Name'Last then + exit; + end if; + end loop; + end; + + -- Copy the message into the next section. + declare + Copy_Idx : Natural := Packed_Exception_Data.Exception_Message'First; + begin + for Char of Msg loop + -- Copy each character: + Packed_Exception_Data.Exception_Message (Copy_Idx) := Char_To_Byte (Char); + + -- Don't overflow. + Copy_Idx := Copy_Idx + 1; + if Copy_Idx > Packed_Exception_Data.Exception_Message'Last then + exit; + end if; + end loop; + end; + + -- Copy the stack trace into the next section: + declare + -- Copy_Idx : Stack_Trace_Addresses.Unconstrained_Index_Type := Packed_Exception_Data.Stack_Trace'First; + -- Stack_Depth_Count : constant Interfaces.Unsigned_32 := 0; + Stack_Depth_Count : constant Interfaces.Unsigned_32 := 0; + begin + -- Call to Tracebacks not currently working on the Pico + -- for Call_Stack_Address of Tracebacks (Error) loop + -- declare + -- Addr : constant Packed_Address.T := (Address => Call_Stack_Address); + -- begin + -- Packed_Exception_Data.Stack_Trace (Copy_Idx) := Addr; + -- end; + + -- -- Increment stack depth counter: + -- Stack_Depth_Count := Stack_Depth_Count + 1; + + -- -- Don't overflow: + -- Copy_Idx := Copy_Idx + 1; + -- if Copy_Idx > Packed_Exception_Data.Stack_Trace'Last then + -- exit; + -- end if; + -- end loop; + + -- Save off the stack depth: + Packed_Exception_Data.Stack_Trace_Depth := Stack_Depth_Count; + end; + + return Packed_Exception_Data; + end Form_Exception_Data; + + procedure Last_Wishes (Error : Exception_Occurrence) is + begin + -- Set the LED: + Pico.LED.Set; + + No_Exceptions_Propagated : + begin + -- Print the exception information to serial port. This will + -- likely get dropped by the ground system, since this is a malformed + -- packet. But if we are not running a ground system, and are just + -- looking at the serial port in ASCII view, then this will + -- be a valuable print out. + -- Pico_Uart.Put_Line (Exception_Information (Error)); + + -- We don't need to call these since the Exception_Information + -- function above prints all these details, but leaving them + -- here as documentation on what is possible. + -- Pico_Uart.Put_Line (Exception_Name(Error)); + -- Pico_Uart.Put_Line ("Exception_Message: "); + -- Pico_Uart.Put_Line (Exception_Message(Error)); + -- Pico_Uart.Put_Line ("Call Stack Addresses: "); + -- for Call_Stack_Address of Tracebacks (Error) loop + -- Pico_Uart.Put_Line (Image_C (Call_Stack_Address)); + -- end loop; + + -- Create packet for diagnostic serial port. + declare + -- Generate the exception data packed record: + Packed_Exception_Data : constant Packed_Exception_Occurrence.T := Form_Exception_Data (Error); + -- Packed_Exception_Data : Packed_Exception_Occurrence.T; + Packed_Exception_Data_Bytes : constant Packed_Exception_Occurrence.Serialization.Byte_Array + with Import, Convention => Ada, Address => Packed_Exception_Data'Address; + begin + -- Now create telemetry packet: + declare + use Basic_Types; + + -- Declare packet: + Pkt : Ccsds_Space_Packet.T := ( + Header => ( + Version => 0, + Packet_Type => Ccsds_Enums.Ccsds_Packet_Type.Telemetry, + Secondary_Header => Ccsds_Enums.Ccsds_Secondary_Header_Indicator.Secondary_Header_Present, + Apid => 97, -- This matches definition in example.assembly.yaml + Sequence_Flag => Ccsds_Enums.Ccsds_Sequence_Flag.Unsegmented, + Sequence_Count => 0, + Packet_Length => Unsigned_16 (Sys_Time.Size_In_Bytes + Packed_Exception_Data_Bytes'Length + Crc_16_Type'Length - 1) + ), + Data => (others => 0) + ); + -- Sequence count: + Cnt : Ccsds_Primary_Header.Ccsds_Sequence_Count_Type := 0; + + -- Overlay a byte array with the Ccsds_Packet: + pragma Warnings (Off, "overlay changes scalar storage order"); + Pkt_Bytes : Basic_Types.Byte_Array (0 .. Natural (Pkt.Header.Packet_Length) + Ccsds_Primary_Header.Size_In_Bytes) + with Import, Convention => Ada, Address => Pkt'Address; + pragma Warnings (On, "overlay changes scalar storage order"); + begin + -- Fill packet with exception data (skip timestamp location): + Pkt.Data ( + Pkt.Data'First + Sys_Time.Size_In_Bytes .. + Pkt.Data'First + Sys_Time.Size_In_Bytes + Packed_Exception_Data_Bytes'Length - 1 + ) := Packed_Exception_Data_Bytes; + + -- Send out packet continuously over serial port and 1553: + loop + -- Flash LED rapidly: + Pico.LED.Toggle; + + -- Set sequence count: + Pkt.Header.Sequence_Count := Cnt; + + -- Compute and fill in crc: + declare + -- Overlay a byte array with the Ccsds_Packet: + pragma Warnings (Off, "overlay changes scalar storage order"); + Overlay : Basic_Types.Byte_Array (0 .. Natural (Pkt.Header.Packet_Length) + Ccsds_Primary_Header.Size_In_Bytes - Crc_16_Type'Length) + with Import, Convention => Ada, Address => Pkt'Address; + pragma Warnings (On, "overlay changes scalar storage order"); + Crc : constant Crc_16_Type := Compute_Crc_16 (Overlay); + begin + Pkt.Data ( + Pkt.Data'First + Natural (Pkt.Header.Packet_Length) - Crc_16_Type'Length + 1 .. + Pkt.Data'First + Natural (Pkt.Header.Packet_Length) + ) := Crc; + end; + + -- Send the packet over serial: + Pico_Uart.Send_Byte_Array (Component.Ccsds_Serial_Interface.Implementation.Sync_Pattern & Pkt_Bytes); + + -- Increment sequence count: + Cnt := Cnt + 1; + end loop; + end; + end; + + exception + when others => + null; + end No_Exceptions_Propagated; + + loop + -- Loop forever... + null; + end loop; + end Last_Wishes; + +end Last_Chance_Handler; diff --git a/src/last_chance_handler/pico/last_chance_handler.ads b/src/last_chance_handler/pico/last_chance_handler.ads new file mode 100644 index 0000000..73ef96b --- /dev/null +++ b/src/last_chance_handler/pico/last_chance_handler.ads @@ -0,0 +1,9 @@ +with Ada.Exceptions; use Ada.Exceptions; + +package Last_Chance_Handler is + + procedure Last_Wishes (Error : Exception_Occurrence); + pragma Export (C, Last_Wishes, "__gnat_last_chance_handler"); + pragma No_Return (Last_Wishes); + +end Last_Chance_Handler; diff --git a/src/pico_util/adc/all.do b/src/pico_util/adc/all.do new file mode 100644 index 0000000..203faa4 --- /dev/null +++ b/src/pico_util/adc/all.do @@ -0,0 +1 @@ +redo-ifchange build/bin/Pico/main.uf2 diff --git a/src/pico_util/adc/env.py b/src/pico_util/adc/env.py new file mode 100644 index 0000000..d9cba61 --- /dev/null +++ b/src/pico_util/adc/env.py @@ -0,0 +1 @@ +from environments import pico # noqa: F401 diff --git a/src/pico_util/adc/main.adb b/src/pico_util/adc/main.adb new file mode 100644 index 0000000..2238983 --- /dev/null +++ b/src/pico_util/adc/main.adb @@ -0,0 +1,42 @@ +with RP.Device; use RP.Device; +with RP.GPIO; use RP.GPIO; +with RP.ADC; use RP.ADC; +with RP.Clock; +with Pico; +with Pico_Uart; + +procedure Main is + Vsys : Microvolts; +begin + -- Initialize the Pico internal clock: + RP.Clock.Initialize (Pico.XOSC_Frequency); + RP.Clock.Enable (RP.Clock.PERI); + + -- Initialize the UART. This needs to be done + -- after clock initialization, so cannot be done + -- at elaboration time: + Pico_Uart.Initialize; + + -- The Pico's power regulator dynamically adjusts it's switching frequency + -- based on load. This introduces noise that can affect ADC readings. The + -- Pico datasheet recommends setting Power Save pin high while performing + -- ADC measurements to minimize this noise, at tne expense of higher power + -- consumption. + Pico.SMPS_PS.Configure (Output, Pull_Up); + Pico.SMPS_PS.Clear; + + RP.ADC.Enable; + RP.ADC.Configure (0); + RP.ADC.Configure (Pico.VSYS_DIV_3); + + RP.Device.Timer.Enable; + loop + Pico.SMPS_PS.Set; + Vsys := RP.ADC.Read_Microvolts (Pico.VSYS_DIV_3) * 3; + Pico_Uart.Put_Line ("Channel 0: " & RP.ADC.Read_Microvolts (0)'Image & "μv"); + Pico_Uart.Put_Line ("VSYS: " & Vsys'Image & "μv"); + Pico_Uart.Put_Line ("Temperature:" & RP.ADC.Temperature'Image & "°C"); + Pico.SMPS_PS.Clear; + RP.Device.Timer.Delay_Milliseconds (1000); + end loop; +end Main; diff --git a/src/pico_util/hello_pico/all.do b/src/pico_util/hello_pico/all.do new file mode 100644 index 0000000..203faa4 --- /dev/null +++ b/src/pico_util/hello_pico/all.do @@ -0,0 +1 @@ +redo-ifchange build/bin/Pico/main.uf2 diff --git a/src/pico_util/hello_pico/env.py b/src/pico_util/hello_pico/env.py new file mode 100644 index 0000000..d9cba61 --- /dev/null +++ b/src/pico_util/hello_pico/env.py @@ -0,0 +1 @@ +from environments import pico # noqa: F401 diff --git a/src/pico_util/hello_pico/hello_pico.gpr b/src/pico_util/hello_pico/hello_pico.gpr new file mode 100644 index 0000000..3cb8447 --- /dev/null +++ b/src/pico_util/hello_pico/hello_pico.gpr @@ -0,0 +1,39 @@ +with "../../../config/adamant_example_config.gpr"; +with "ravenscar_build.gpr"; + +-- This project simply compiles a hello world to make sure the alire environment +-- for the Adamant example is functioning properly. This alire environment contains +-- the cross compile dependencies for the Raspberry Pi Pico. +project Hello_Pico is + + -- Use the arm-eabi-elf cross compiler with a Ravenscar tasking + -- runtime. + for Target use "arm-eabi"; + for Runtime ("Ada") use Ravenscar_Build'Runtime ("Ada"); + + -- Add the Raspberry Pi Pico hello world as source file. + for Source_Dirs use (".", "../../../config/"); + for Object_Dir use "build/alire/obj/" & Adamant_Example_Config.Build_Profile; + for Create_Missing_Dirs use "True"; + for Exec_Dir use "build/alire/bin"; + for Main use ("main.adb"); + + package Compiler is + for Default_Switches ("Ada") use Adamant_Example_Config.Ada_Compiler_Switches; + end Compiler; + + package Binder is + for Switches ("Ada") use ("-Es"); -- Symbolic traceback + end Binder; + + package Install is + for Artifacts (".") use ("share"); + end Install; + + package Linker is + for Switches ("Ada") use + ("-Wl,-print-memory-usage", + "-Wl,-gc-sections"); + end Linker; + +end Hello_Pico; diff --git a/src/pico_util/hello_pico/main.adb b/src/pico_util/hello_pico/main.adb new file mode 100644 index 0000000..dae1ad1 --- /dev/null +++ b/src/pico_util/hello_pico/main.adb @@ -0,0 +1,67 @@ +with RP.GPIO; use RP.GPIO; +with RP.Clock; +with Ada.Real_Time; use Ada.Real_Time; +with Pico; +with RP.Device; use RP.Device; +with RP.UART; +with HAL.UART; use HAL.UART; + +-- +-- This hello world program blinks the LED on a Raspberry Pi Pico and +-- prints "Hello, Pico!" to UART0 on GP16 (TX) and GP17 (RX). +-- +procedure Main is + Test_Error : exception; + The_UART : RP.UART.UART_Port renames RP.Device.UART_0; + Uart_Tx : RP.GPIO.GPIO_Point renames Pico.GP16; -- White wire + Uart_Rx : RP.GPIO.GPIO_Point renames Pico.GP17; -- Green wire + Status : UART_Status; + + procedure Send_Hello is + Hello : constant String := "Hello, Pico!" & ASCII.CR & ASCII.LF; + Hello_Bytes : UART_Data_8b (1 .. Hello'Length); + begin + for I in Hello'Range loop + Hello_Bytes (I) := Character'Pos (Hello (I)); + end loop; + + The_UART.Transmit (Hello_Bytes, Status); + if Status /= Ok then + raise Test_Error with "Send_Hello transmit failed with status " & Status'Image; + end if; + end Send_Hello; + + Period : constant Time_Span := Milliseconds (250); + Release : Time; +begin + RP.Clock.Initialize (Pico.XOSC_Frequency); + RP.Clock.Enable (RP.Clock.PERI); + -- RP.Device.Timer.Enable; + RP.GPIO.Enable; + Pico.LED.Configure (RP.GPIO.Output); + Pico.LED.Set; + + -- I don't know if the pull up is needed, but it doesn't hurt? + Uart_Tx.Configure (Output, Pull_Up, RP.GPIO.UART); + Uart_Rx.Configure (Input, Floating, RP.GPIO.UART); + The_UART.Configure + (Config => + (Baud => 115_200, + Word_Size => 8, + Parity => False, + Stop_Bits => 1, + others => <>)); + + -- Compute the first release time + Release := Clock + Period; + loop + delay until Release; + Pico.LED.Toggle; + --delay 0.2; + + -- Next release time + Release := Release + Period; + Send_Hello; + -- RP.Device.Timer.Delay_Milliseconds (250); + end loop; +end Main; diff --git a/src/pico_util/hello_pico/program.sh b/src/pico_util/hello_pico/program.sh new file mode 100755 index 0000000..fde0ef8 --- /dev/null +++ b/src/pico_util/hello_pico/program.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +openocd -f interface/cmsis-dap.cfg -f target/rp2040.cfg -c "adapter speed 5000" -c "program build/bin/Pico/main.elf verify reset exit" diff --git a/src/pico_util/interrupts/.skip_style b/src/pico_util/interrupts/.skip_style new file mode 100644 index 0000000..e69de29 diff --git a/src/pico_util/interrupts/all.do b/src/pico_util/interrupts/all.do new file mode 100644 index 0000000..203faa4 --- /dev/null +++ b/src/pico_util/interrupts/all.do @@ -0,0 +1 @@ +redo-ifchange build/bin/Pico/main.uf2 diff --git a/src/pico_util/interrupts/env.py b/src/pico_util/interrupts/env.py new file mode 100644 index 0000000..d9cba61 --- /dev/null +++ b/src/pico_util/interrupts/env.py @@ -0,0 +1 @@ +from environments import pico # noqa: F401 diff --git a/src/pico_util/interrupts/handlers.adb b/src/pico_util/interrupts/handlers.adb new file mode 100644 index 0000000..0468566 --- /dev/null +++ b/src/pico_util/interrupts/handlers.adb @@ -0,0 +1,10 @@ +with Pico; + +package body Handlers is + protected body Protected_Handler is + procedure Handler is + begin + Pico.Led.Toggle; + end Handler; + end Protected_Handler; +end Handlers; diff --git a/src/pico_util/interrupts/handlers.ads b/src/pico_util/interrupts/handlers.ads new file mode 100644 index 0000000..282b26a --- /dev/null +++ b/src/pico_util/interrupts/handlers.ads @@ -0,0 +1,13 @@ +with System; +with Ada.Interrupts.Names; + +package Handlers is + + protected type Protected_Handler is + pragma Interrupt_Priority (System.Interrupt_Priority'Last); + private + procedure Handler; + pragma Attach_Handler (Handler, Ada.Interrupts.Names.Io_Irq_Bank0_Interrupt_Cpu_1); + end Protected_Handler; + +end Handlers; diff --git a/src/pico_util/interrupts/main.adb b/src/pico_util/interrupts/main.adb new file mode 100644 index 0000000..e13f6e7 --- /dev/null +++ b/src/pico_util/interrupts/main.adb @@ -0,0 +1,26 @@ +with Rp.Gpio; use Rp.Gpio; +--with RP.GPIO.Interrupts; +with Rp.Clock; +with Pico; + +with Handlers; + +procedure Main is +begin + Rp.Clock.Initialize (Pico.Xosc_Frequency); + Rp.Gpio.Enable; + + -- GP9 is connected to a normally open button that connects to GND when pressed + -- debouncing is an exercise left to the reader + Pico.Gp9.Configure (Input, Pull_Up); + + -- RP.GPIO.Interrupts.Attach_Handler (Pico.GP9, Handlers.Toggle_LED'Access); + Pico.Gp9.Enable_Interrupt (Falling_Edge); + + Pico.Led.Configure (Output); + Pico.Led.Set; + + loop + null; + end loop; +end Main; diff --git a/src/pico_util/uart/.Pico_path b/src/pico_util/uart/.Pico_path new file mode 100644 index 0000000..e69de29 diff --git a/src/pico_util/uart/README.md b/src/pico_util/uart/README.md new file mode 100644 index 0000000..81981eb --- /dev/null +++ b/src/pico_util/uart/README.md @@ -0,0 +1,4 @@ +This directory includes the default implementation of ~/adamant/src/components/ccsds_serial_interface/uart/default +for use on Linux and provides a Pico specific implementation for use on the Raspberry Pi Pico. + +~/adamant/src/components/ccsds_serial_interface/uart/default has been removed from the build path in env.py. diff --git a/src/pico_util/uart/diagnostic_uart.adb b/src/pico_util/uart/diagnostic_uart.adb new file mode 100644 index 0000000..1c05e15 --- /dev/null +++ b/src/pico_util/uart/diagnostic_uart.adb @@ -0,0 +1,28 @@ +with Pico_Uart; + +package body Diagnostic_Uart is + + function Get return Basic_Types.Byte is + begin + return Pico_Uart.Receive_Byte; + end Get; + + procedure Get (Bytes : out Basic_Types.Byte_Array) is + begin + for B of Bytes loop + B := Pico_Uart.Receive_Byte; + end loop; + end Get; + + procedure Put (B : in Basic_Types.Byte) is + Bytes : constant Basic_Types.Byte_Array (0 .. 0) := (0 => B); + begin + Pico_Uart.Send_Byte_Array (To_Send => Bytes); + end Put; + + procedure Put (Bytes : in Basic_Types.Byte_Array) is + begin + Pico_Uart.Send_Byte_Array (To_Send => Bytes); + end Put; + +end Diagnostic_Uart; diff --git a/src/pico_util/uart/diagnostic_uart.ads b/src/pico_util/uart/diagnostic_uart.ads new file mode 100644 index 0000000..3a08915 --- /dev/null +++ b/src/pico_util/uart/diagnostic_uart.ads @@ -0,0 +1,43 @@ +with Basic_Types; + +-- +-- Many GNAT bare board implementations hook Ada.Text_IO to a diagnostic UART. +-- This module uses Ada.Text_IO under the hood but allows raw byte array communication +-- over the diagnostic UART. The default implementation included in the default/ +-- subdirectory can be used to provide a quick and dirty (non-flight) +-- backdoor for commanding and telemetry. +-- +-- Note that when using the default implementation of this package, +-- a Put_Line somewhere else in the system will conflict with output of this +-- package, since both will send data out of the same serial port. In other +-- words, DO NOT use Text_IO and this package concurrently, or bad things +-- will happen. +-- +-- If you do not want to use the default implementation, you can write your +-- own implementation of diagnostic_uard.adb and remove the default implementation +-- from the build path via: +-- +-- $ export REMOVE_BUILD_PATH=~/adamant/src/components/ccsds_serial_interface/uart/default +-- +-- and make sure your implementation is included instead. +-- + +package Diagnostic_Uart is + + -- Get a single byte from the serial port. This function + -- will block until Rx is ready, so check first if needed. + function Get return Basic_Types.Byte; + + -- Receive multiple bytes over the serial port. The byte array + -- will be filled completely before this function returns. It will + -- block until all bytes are filled. + procedure Get (Bytes : out Basic_Types.Byte_Array); + + -- Send a single byte to the serial port. This function + -- will block until Tx is ready, so check first if needed. + procedure Put (B : in Basic_Types.Byte); + + -- Send multiple bytes over the serial port: + procedure Put (Bytes : in Basic_Types.Byte_Array); + +end Diagnostic_Uart; diff --git a/src/pico_util/uart/env.py b/src/pico_util/uart/env.py new file mode 100644 index 0000000..d9cba61 --- /dev/null +++ b/src/pico_util/uart/env.py @@ -0,0 +1 @@ +from environments import pico # noqa: F401 diff --git a/src/pico_util/uart/pico_uart.adb b/src/pico_util/uart/pico_uart.adb new file mode 100644 index 0000000..0f93dd9 --- /dev/null +++ b/src/pico_util/uart/pico_uart.adb @@ -0,0 +1,77 @@ +with HAL.UART; use HAL.UART; +with RP.Device; use RP.Device; +with RP.GPIO; use RP.GPIO; +with RP.UART; +with Pico; + +package body Pico_Uart is + + Test_Error : exception; + The_UART : RP.UART.UART_Port renames RP.Device.UART_0; + + procedure Initialize is + Uart_Tx : RP.GPIO.GPIO_Point renames Pico.GP16; -- White wire + Uart_Rx : RP.GPIO.GPIO_Point renames Pico.GP17; -- Green wire + begin + -- I don't know if the pull up is needed, but it doesn't hurt? + Uart_Tx.Configure (Output, Pull_Up, RP.GPIO.UART); + Uart_Rx.Configure (Input, Floating, RP.GPIO.UART); + The_UART.Configure + (Config => + (Baud => 115_200, + Word_Size => 8, + Parity => False, + Stop_Bits => 1, + others => <>)); + end Initialize; + + -- Byte arrays don't have a "scalar storage order" since they are an array of single byte + -- items. So this warning doesn't apply. We can safely overlay a byte array with any type + -- no matter the underlying scalar storage order. + pragma Warnings (Off, "overlay changes scalar storage order"); + + procedure Send_Byte_Array (To_Send : in Basic_Types.Byte_Array) is + To_Send_Bytes : UART_Data_8b (1 .. To_Send'Length) with Import, Convention => Ada, Address => To_Send'Address; + Status : UART_Status; + begin + The_UART.Transmit (To_Send_Bytes, Status, Timeout => 0); + if Status /= Ok then + raise Test_Error with "UART transmit failed with status " & Status'Image; + end if; + end Send_Byte_Array; + + procedure Put_Line (To_Send : in String) is + To_Send_El : constant String := To_Send & ASCII.CR & ASCII.LF; + To_Send_Array : Basic_Types.Byte_Array (0 .. To_Send_El'Length - 1) with Import, Convention => Ada, Address => To_Send_El'Address; + begin + Send_Byte_Array (To_Send_Array); + end Put_Line; + + function Receive_Byte return Basic_Types.Byte is + Byte : UART_Data_8b (0 .. 0); + To_Return : Basic_Types.Byte with Import, Convention => Ada, Address => Byte'Address; + Status : UART_Status; + begin + The_UART.Receive (Byte, Status, Timeout => 0); + case Status is + when Err_Error => + raise Test_Error with "Echo receive failed with status " & Status'Image; + when Err_Timeout => + raise Test_Error with "Unexpected Err_Timeout with timeout disabled!"; + when Busy => + -- Busy indicates a Break condition- RX held low for a full + -- word time. This may be detected unintentionally if a + -- transmitter is not connected. Break is used by some + -- protocols (eg. LIN bus) to indicate the end of a frame. + -- + -- For this example, we just ignore it. + null; + when Ok => + null; + end case; + return To_Return; + end Receive_Byte; + + pragma Warnings (On, "overlay changes scalar storage order"); + +end Pico_Uart; diff --git a/src/pico_util/uart/pico_uart.ads b/src/pico_util/uart/pico_uart.ads new file mode 100644 index 0000000..ff03789 --- /dev/null +++ b/src/pico_util/uart/pico_uart.ads @@ -0,0 +1,29 @@ +with Basic_Types; + +package Pico_Uart is + + -- Set up the UART with the following default configuration: + -- + -- GP16 = TX + -- GP17 = RX + -- Baud = 115200 + -- Parity = False + -- Stop bits = 1 + -- Word size = 8 + -- + procedure Initialize; + + -- Transmit raw data bytes over the UART: + procedure Send_Byte_Array (To_Send : in Basic_Types.Byte_Array); + + -- Transmit a string over the UART. This appends a return line to + -- the transmitted string. + procedure Put_Line (To_Send : in String); + + -- Receive a byte from UART. This will block until a byte is + -- received or an error is encountered. It spins on the serial, + -- so if you use this function make sure it is in the lowest + -- priority task on the system. + function Receive_Byte return Basic_Types.Byte; + +end Pico_Uart;