From 0332001b9ea37665f067c7168b4fa59442435b02 Mon Sep 17 00:00:00 2001 From: Sterling Peet Date: Fri, 24 Sep 2021 15:52:56 -0400 Subject: [PATCH] Significant updates to defacto standard template in preparation for release v1.0 * Remove support for old make build system * Add Deployment Docs folder and boilerplate contents * Optionally add boilerplate text to the README * Add DEVELOPER NOTES for better quality assurance * Include gds.ini file for optionally adding context to the GDS invocation * Add example environment.ini file * Change project paths to support F Prime as a library * Add deployment configuration and settings files * Add default toolchain option * Add hidden binary name variable to enforce cmake name requirements * Include parameter database if parameter support is desired * Update schema path * Improve Arduino Main.cpp output with DEBUG and LogMsg configuration * Integrate Linux and Arduino platforms into Main.cpp * Add target platform support option * Add option to create schedule contexts header file or leave contexts blank * Update Rate Group Components to match Ref deployment * Add option to include support for the command sequencer * Add option to include support for file transfers * Add option to include support for component health subsystem * Removed deployment directory name option because the build system now assumes it must be the same as the project name which is covered by the ``project_slug`` options * Updated project to generate Components.hpp by correctly searching F Prime root and project for header files * Add bootstrap script to create CI testing matrix * Check for minimum version of cookiecutter tool above 1.5.0 because dictionary variables are in use * Fix default inputs to generate a correct/consistent project * LICENSE file exists and generates proper text based on selection * Correctly handle splitting multi-level namespace definitions to avoid C++17 warnings * Refactored several generated output sections into conditional jinja loops, moving the potential for mistakes away from random files and into the cookiecutter.json file * Remove use of deprecated GroundInterface component and switch to Framer and Deframer for Native/Linux/Darwin targets Closes #1, #2, and #6 --- .gitignore | 22 + DEVELOPER_NOTES.rst | 30 + LICENSE | 27 +- README.rst | 162 +++- ci/bootstrap.py | 202 +++++ ci/check_rendered_config.py | 50 ++ ci/env_test.py | 127 +++ ci/envs/1-defaults.cookiecutterrc | 3 + ci/readme.json | 141 +++ ci/render.py | 80 ++ ci/setup.cfg | 69 ++ ci/templates/README.rst | 101 +++ ci/templates/tox.ini | 41 + cookiecutter.json | 839 +++++++++++++++++- hooks/post_gen_project.py | 40 +- hooks/pre_gen_project.py | 34 +- tox.ini | 258 ++++++ .../.gitignore | 2 - .../CMakeLists.txt | 74 -- {{cookiecutter.deployment_dir_name}}/Makefile | 10 - .../README.md | 10 - .../Top/Components.hpp | 13 - .../Top/Main.cpp | 49 - .../Top/Makefile | 11 - .../Top/Topology.cpp | 141 --- .../Top/arduino.cpp | 15 - .../Top/mod.mk | 3 - ...ecutter.deployment_slug}}TopologyAppAi.xml | 344 ------- .../Makefile | 16 - .../mod.mk | 23 - .../.cookiecutterrc | 6 +- {{cookiecutter.deployment_slug}}/.gitignore | 12 + .../.internal_use | 10 + .../CMakeLists.txt | 90 ++ {{cookiecutter.deployment_slug}}/LICENSE | 35 + {{cookiecutter.deployment_slug}}/PrmDb.dat | Bin 0 -> 47 bytes {{cookiecutter.deployment_slug}}/README.md | 77 ++ .../Top/.gitignore | 0 .../Top/CMakeLists.txt | 18 +- .../Top/Components.hpp | 38 + {{cookiecutter.deployment_slug}}/Top/Main.cpp | 227 +++++ .../Top/Topology.cpp | 267 ++++++ ...ecutter.deployment_slug}}SchedContexts.hpp | 9 +- ...ecutter.deployment_slug}}TopologyAppAi.xml | 378 ++++++++ .../config/AcConstants.ini | 23 + .../docs/.gitignore | 1 + .../docs/doxygen.txt | 20 + {{cookiecutter.deployment_slug}}/docs/sdd.md | 18 + .../docs/{{cookiecutter.deployment_slug}}.md | 31 + .../environment.ini | 9 + .../fplint.yml | 0 {{cookiecutter.deployment_slug}}/gds.ini | 2 + {{cookiecutter.deployment_slug}}/settings.ini | 25 + .../CMakeLists.txt | 0 .../README.md | 0 .../docs/.gitignore | 0 .../docs/sdd.md | 0 .../docs/{{cookiecutter.component_slug}}.md | 0 ...okiecutter.component_slug}}ComponentAi.xml | 14 +- ...{{cookiecutter.component_impl_suffix}}.cpp | 17 +- ...{{cookiecutter.component_impl_suffix}}.cpp | 17 +- ...{{cookiecutter.component_impl_suffix}}.cpp | 17 +- ...{{cookiecutter.component_impl_suffix}}.cpp | 29 +- ...{{cookiecutter.component_impl_suffix}}.hpp | 30 +- 64 files changed, 3556 insertions(+), 801 deletions(-) create mode 100644 .gitignore create mode 100644 DEVELOPER_NOTES.rst create mode 100755 ci/bootstrap.py create mode 100755 ci/check_rendered_config.py create mode 100755 ci/env_test.py create mode 100644 ci/envs/1-defaults.cookiecutterrc create mode 100644 ci/readme.json create mode 100755 ci/render.py create mode 100644 ci/setup.cfg create mode 100644 ci/templates/README.rst create mode 100644 ci/templates/tox.ini create mode 100644 tox.ini delete mode 100644 {{cookiecutter.deployment_dir_name}}/.gitignore delete mode 100644 {{cookiecutter.deployment_dir_name}}/CMakeLists.txt delete mode 100644 {{cookiecutter.deployment_dir_name}}/Makefile delete mode 100644 {{cookiecutter.deployment_dir_name}}/README.md delete mode 100644 {{cookiecutter.deployment_dir_name}}/Top/Components.hpp delete mode 100644 {{cookiecutter.deployment_dir_name}}/Top/Main.cpp delete mode 100644 {{cookiecutter.deployment_dir_name}}/Top/Makefile delete mode 100644 {{cookiecutter.deployment_dir_name}}/Top/Topology.cpp delete mode 100644 {{cookiecutter.deployment_dir_name}}/Top/arduino.cpp delete mode 100644 {{cookiecutter.deployment_dir_name}}/Top/mod.mk delete mode 100644 {{cookiecutter.deployment_dir_name}}/Top/{{cookiecutter.deployment_slug}}TopologyAppAi.xml delete mode 100644 {{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/Makefile delete mode 100644 {{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/mod.mk rename {{{cookiecutter.deployment_dir_name}} => {{cookiecutter.deployment_slug}}}/.cookiecutterrc (78%) create mode 100644 {{cookiecutter.deployment_slug}}/.gitignore create mode 100644 {{cookiecutter.deployment_slug}}/.internal_use create mode 100644 {{cookiecutter.deployment_slug}}/CMakeLists.txt create mode 100644 {{cookiecutter.deployment_slug}}/LICENSE create mode 100644 {{cookiecutter.deployment_slug}}/PrmDb.dat create mode 100644 {{cookiecutter.deployment_slug}}/README.md rename {{{cookiecutter.deployment_dir_name}} => {{cookiecutter.deployment_slug}}}/Top/.gitignore (100%) rename {{{cookiecutter.deployment_dir_name}} => {{cookiecutter.deployment_slug}}}/Top/CMakeLists.txt (50%) create mode 100644 {{cookiecutter.deployment_slug}}/Top/Components.hpp create mode 100644 {{cookiecutter.deployment_slug}}/Top/Main.cpp create mode 100644 {{cookiecutter.deployment_slug}}/Top/Topology.cpp rename {{{cookiecutter.deployment_dir_name}} => {{cookiecutter.deployment_slug}}}/Top/{{cookiecutter.deployment_slug}}SchedContexts.hpp (60%) create mode 100644 {{cookiecutter.deployment_slug}}/Top/{{cookiecutter.deployment_slug}}TopologyAppAi.xml create mode 100644 {{cookiecutter.deployment_slug}}/config/AcConstants.ini create mode 100644 {{cookiecutter.deployment_slug}}/docs/.gitignore create mode 100644 {{cookiecutter.deployment_slug}}/docs/doxygen.txt create mode 100644 {{cookiecutter.deployment_slug}}/docs/sdd.md create mode 100644 {{cookiecutter.deployment_slug}}/docs/{{cookiecutter.deployment_slug}}.md create mode 100644 {{cookiecutter.deployment_slug}}/environment.ini rename {{{cookiecutter.deployment_dir_name}} => {{cookiecutter.deployment_slug}}}/fplint.yml (100%) create mode 100644 {{cookiecutter.deployment_slug}}/gds.ini create mode 100644 {{cookiecutter.deployment_slug}}/settings.ini rename {{{cookiecutter.deployment_dir_name}} => {{cookiecutter.deployment_slug}}}/{{cookiecutter.component_dir_name}}/CMakeLists.txt (100%) rename {{{cookiecutter.deployment_dir_name}} => {{cookiecutter.deployment_slug}}}/{{cookiecutter.component_dir_name}}/README.md (100%) rename {{{cookiecutter.deployment_dir_name}} => {{cookiecutter.deployment_slug}}}/{{cookiecutter.component_dir_name}}/docs/.gitignore (100%) rename {{{cookiecutter.deployment_dir_name}} => {{cookiecutter.deployment_slug}}}/{{cookiecutter.component_dir_name}}/docs/sdd.md (100%) rename {{{cookiecutter.deployment_dir_name}} => {{cookiecutter.deployment_slug}}}/{{cookiecutter.component_dir_name}}/docs/{{cookiecutter.component_slug}}.md (100%) rename {{{cookiecutter.deployment_dir_name}} => {{cookiecutter.deployment_slug}}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}ComponentAi.xml (84%) rename {{{cookiecutter.deployment_dir_name}} => {{cookiecutter.deployment_slug}}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}AVR{{cookiecutter.component_impl_suffix}}.cpp (57%) rename {{{cookiecutter.deployment_dir_name}} => {{cookiecutter.deployment_slug}}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}Arduino{{cookiecutter.component_impl_suffix}}.cpp (57%) rename {{{cookiecutter.deployment_dir_name}} => {{cookiecutter.deployment_slug}}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}Linux{{cookiecutter.component_impl_suffix}}.cpp (57%) rename {{{cookiecutter.deployment_dir_name}} => {{cookiecutter.deployment_slug}}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}{{cookiecutter.component_explicit_common}}{{cookiecutter.component_impl_suffix}}.cpp (77%) rename {{{cookiecutter.deployment_dir_name}} => {{cookiecutter.deployment_slug}}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}{{cookiecutter.component_impl_suffix}}.hpp (76%) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..784fae8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,22 @@ +# Accidental Project stuff +MyExample +Reference + +# Testing Folders +test-envs +test-proj + +# tox progress info +.progress + +# backup files +*.bak +*.orig + +# Python Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# Tox +.tox diff --git a/DEVELOPER_NOTES.rst b/DEVELOPER_NOTES.rst new file mode 100644 index 0000000..1afafdc --- /dev/null +++ b/DEVELOPER_NOTES.rst @@ -0,0 +1,30 @@ + + +Items to Test/Check: +-------------------- + + * Main README file looks correct with/without boilerplate. + * SDD links go to the correct place. + * Using the ``.cookiecutterrc`` file regenerates the same output. (this doesn't work with fancy input selection) + * Parameter database is only created when support is requested + * Make sure output builds with Arduino + * Make sure output builds with Onion + +Open Questions: +--------------- + + * Bootstrap the bootstrapper? Basically pick a set of configs that only need to be generated as one variation from the base env, make that an input step to build the setup.cfg that ``matrix`` uses for all the combination envs + * Re-write the render.py script to call cookiecutter via the command line, because thats how the user does it, and its not always renderec quite the same way with the same effects. Found the click dependency this way, and would be a better way to get around the rendered field bug instead of using the workaround of re-writing the cookiecutter.json file. + * Make CLI an option? + * Run the resulting binary and try to send it some commands? + * make second and third rate groups optionally added by template + * Write a cookiecutter_lint script to check the internal_use cookiecutter dictionary for obvious problems + * Reformat the fplint.yaml file to include only the components present in the rendered output + + +Development Strategies +---------------------- + +Discussion about how to organize and refactor features defined in the cookiecutter json and how componenents and their instance names are affected. liberal use of dunder-variables is recommended to make the template code more readable. + +When handling component related text generation: use the components dictionary in the cookiecutter.json file to define the behavior, then generate the expected text in the output with a jinja loop that conditionally puts each component into the rendered output text. DO NOT manually define if/else statements for each case, it gets way too unweildy and hard to read/maintain. diff --git a/LICENSE b/LICENSE index 047358a..22ec60c 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,14 @@ -MIT License -Copyright (c) 2020 Sterling Peet + Copyright 2021 Sterling Lewis Peet -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: + 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 -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. + http://www.apache.org/licenses/LICENSE-2.0 -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. + 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/README.rst b/README.rst index 9dfab7a..c2a5b48 100644 --- a/README.rst +++ b/README.rst @@ -1,19 +1,35 @@ +.. DO NOT EDIT THIS FILE DIRECTLY!!! Edit the template in ci/templates/README.rst +.. and then regenerate this file by running the ci/bootstrap.py script. +.. =============================== Cookiecutter: F Prime Component =============================== -**WARNING:** The template is currently intended to support ATmega specific deployments, so if that is not your goal, the results may be somewhat unexpected. +**WARNING:** This template uses the dictionary feature, which requires cookiecutter 1.5.0 or higher, *AND* there is a bug that requires ``click`` to be less than version 8.0.0. +For more information, see Cookiecutter_ `GitHub issue # 1558 `_. +To install a compatible version of ``click``: +:: + + pip install click==7.1.2 Cookiecutter_ template for a `F Prime`_ deployment, to help with reducing the copy-pasta effect while creating new deployments. There are just enough pieces to remember to change/fix, that it is rather challenging to do without a template. -So here is a template to fill in all the major adjustments, so you can spend time develping a deployment or writing a component instead of scratching your head over why you get weird errors. +So here is a template to fill in all the major adjustments, so you can spend time developing a deployment or writing a component instead of scratching your head over why you get weird errors. + +This template currently supports only "F Prime as a library" style deployements where F Prime is probably a git submodule in the project. +If enough interest is generated for the old-style clone-and-own deplyments, we will look into adding that support. .. contents:: Table of Contents Features -------- -* Choice of various licenses. (maybe, eventually) +* Working deployment created by running the Cookiecutter_. +* Options to include or exclude several F Prime services, like health pinging. +* Creates a single deployment-owned component, especially useful for excercising a utility component that is under development. +* Choice of multiple target platforms for platform specific tweaks. +* Option to generate an Arduino platfrom deployment. +* Choice of various licenses. Requirements ------------ @@ -26,7 +42,7 @@ To get quickly started on a new system, just install Cookiecutter_. You should do this in your ``fprime-venv``. To install it, just run this in your shell or command prompt, within the ``venv`` environment:: - pip install cookiecutter + pip install cookiecutter click==7.1.2 Usage and options ----------------- @@ -53,7 +69,8 @@ You will be asked for these fields: - .. code:: python "Sterling Peet" - - Main author of this component. + + - Main author of this deployment. Can be set in your ``~/.cookiecutterrc`` config file. @@ -61,6 +78,7 @@ You will be asked for these fields: - .. code:: python "noreply@nospam.com" + - Contact email of the author. Can be set in your ``~/.cookiecutterrc`` config file. @@ -69,132 +87,217 @@ You will be asked for these fields: - .. code:: python "My Example" + - The printed name of this deployment for documentation and strings. It should be concise and convey the purpose of the deployment. - * - ``deployment_short_description`` + * - ``dep_short_description`` - .. code:: python "An example deployment [...]" + - One line description of the deployment's purpose (used in headers and comments). * - ``deployment_slug`` - .. code:: python "MyExample" - - A slug_ is a simplified version of the ``deployment_name``, which will be used for the topology assembly name and file names within the deployment folder structure. It should be ``TitleCase`` with no spaces or special characters. - - * - ``deployment_dir_name`` - - .. code:: python - "MyExample" - - This is the name of the deployment's main directory. The obvious choice is to use your ``deployment_slug`` for this field. + - A slug_ is a simplified version of the ``deployment_name``, which will be used for the topology assembly name and file names within the deployment folder structure. It should be ``TitleCase`` with no spaces or special characters. * - ``deployment_path`` - .. code:: python "example/path" + - This is the path from the F Prime root to the current directory, not including the deployment's folder. Do not add a ``/`` to the front or back of the path. - * - ``deployment_path_to_fprime_root`` + * - ``deployment_path_to_project_root`` - .. code:: python - "../.." - - This is the path from the current directory to the F Prime root, not including the deployment's folder. Do not add a ``/`` to the front or back of the path. + ".." + + - This is the path from inside the deployment folder to the main project root. This is usually just up one directory. + + * - ``deployment_path_to_fprime_framework`` + - .. code:: python + + "../fprime" + + - This is the path from inside the deployment folder to the folder containing F Prime. In most cases, these two folders are adjacent in the project root folder. + + * - ``deployment_target_platform_support`` + - .. code:: python + + "Native" + + - Target platform for the deployment. This gets used in the ``settings.ini`` file to avoid typing the platform when invoking ``fprimt-util``. + + * - ``deployment_baremetal_scheduler`` + - .. code:: python + + "no" + + - Select the bare metal scheduler instead of the normal Pthreads scheduler. Small platforms may not support Pthreads, and true bare metal platforms may not even have threading support at all. If you don't know that you want the bare metal schedular, you don't. + + * - ``deployment_rg_sched_contexts_hpp`` + - .. code:: python + + "no" + + - Use a separate contexts header file to define the deployment's rate group contexts. * - ``deployment_parameter_support`` - .. code:: python "yes" + - Include components and connections to support persistent parameter storage using the F Prime parameter subsystem. + * - ``deployment_command_sequence_support`` + - .. code:: python + + "yes" + + - Include the components and connections needed for command sequence support. + + * - ``deployment_event_text_log_support`` + - .. code:: python + + "yes" + + - Include the components and connections needed for for local text logging of events. + + * - ``deployment_file_xfer_support`` + - .. code:: python + + "yes" + + - Include the components and connections needed for file uplink and downlink support. + + * - ``deployment_health_support`` + - .. code:: python + + "yes" + + - Include the components and connections needed for component health check/ping support. + + * - ``deployment_ref_doc_boilerplate`` + - .. code:: python + + "no" + + - Extra boilerplate documentation to support better understanding of the project. + * - ``component_name`` - .. code:: python "Led Blinker" - - The printed name of this exerciser component for documentation and strings. It should be concise and convey the purpose of the component. + + - The printed name of this internal deployment component for documentation and strings. It should be concise and convey the purpose of the component. * - ``component_short_description`` - .. code:: python "An example component [...]" + - One line description of the project (used in headers and comments). This should describe the purpose of the component in the Imperetive Voice, not the context where the component is used. * - ``component_slug`` - .. code:: python "LedBlinker" + - A slug_ is a simplified version of the ``component_name``, which will be used for the class name and file names within the component folder structure. It should be ``TitleCase`` with no spaces or special characters. * - ``component_dir_name`` - .. code:: python "LedBlinker" + - This is the name of the component's main directory. The obvious choice is to use your ``deployment_slug`` for this field. * - ``component_explicit_component_suffix`` - .. code:: python "Component" + - The general convention is for F Prime components to have the ``Component`` suffix for file names and class names. While it is not required, the Autocoder will assume this format, and Autocoder provided templates may be more difficult to adapt if this is not selected. * - ``component_explicit_common`` - .. code:: python "" + - If preferred, the cpp file with the common implementation code can be appended with the suffix ``Common``. * - ``component_impl_suffix`` - .. code:: python - "Impl" - - The general convention is for F Prime components to have the ``Impl`` suffix for file names and class names. While it is not required, the Autocoder will assume this format, and Autocoder provided templates may be more difficult to adapt if this is not selected. + "" + + - Some F Prime components use the ``Impl`` suffix for component class names and files. It is redundant because the autocoded base file always uses the suffix ``Base``, but is available for backwards compatibility and completeness. * - ``component_path_to_fprime_root`` - .. code:: python - "../../.." - - This is the path from the current directory to the F Prime root, not including the components's folder. Do not add a ``/`` to the front or back of the path (this should auto-populate from the deployment path). + "../.." + + - This is the path from inside the component's folder to the F Prime root. Do not add a ``/`` to the front or back of the path (this should auto-populate from the deployment path). * - ``component_namespace`` - .. code:: python - "Prjct::Grp" - - This is the namespace where your component's implementation class resides. It is usually the same but can be different from the path. + "MyExample" + + - This is the namespace where your component's implementation class resides. It is usually the same but can be different from the path. If you want multiple levels of namespace, use the ``::`` notation. * - ``component_kind`` - .. code:: python "passive" + - You can choose and active or passive component type. If you change your mind, is it set in the Autocoder input file (and some of the component's port kinds may also affected). * - ``component_multiplatform_support`` - .. code:: python "no" + - If you need different implementations of your component based on the target platform, choose ``yes`` to get additional support file templates. * - ``component_instance_name`` - .. code:: python - "ledblinker" + "ledBlinker" + - This is the variable name given to the instantiation of your component in the topology. - * - ``startup_arduino_delay_msec`` + * - ``startup_delay_msec`` - .. code:: python "2000" + - Startup delay during the deployment startup, so you can tell if you got the deployment into a boot loop. This is only available on the ``Arduino`` platform. - * - ``startup_arduino_log_stream`` + * - ``startup_arduino_led_flash`` + - .. code:: python + + "yes" + + - Flash the onboard LED to signal the startup process has worked. Only available on Arduino. + + * - ``arduino_log_stream`` - .. code:: python "Serial" + - This is the ``Arduino`` stream where the debug statements for the main deployment will print. * - ``license`` - .. code:: python "None" + - License to use. Available options: * None (no license text, assume project level license) @@ -203,6 +306,14 @@ You will be asked for these fields: What license to pick? https://choosealicense.com/ + * - ``internal_use`` + - .. code:: python + + "default" + + - This variable is an autogenerated dictionary built from the previous answers. You should not need to adjust it, but if you are getting stuck, see the very top of this README for a solution. + + You should now have a basic deployment that can be compiled and run. If you want to add components to the deployment, you can do that next. @@ -225,3 +336,4 @@ See `CHANGELOG.rst 0: + err_str = ['\n\033[1;36mERROR: The following keys are missing:\033[0m'] + for key in missing: + err_str.append('\033[1;36m * {}\033[0m'.format(key)) + err_str.append('\033[1;36m {}\033[0m'.format(context)) + raise Exception('\n'.join(err_str)) + + +def write_conf_file(alias, conf_dict): + '''Writes a config file to the disk.''' + import yaml + with open(repo_path.joinpath('ci', 'envs', alias + '.cookiecutterrc'), 'w') as fh: + fh.write(yaml.safe_dump( + dict(default_context={k: v for k, v in conf_dict.items() if v}), + default_flow_style=False + )) + + +def readme_conf_loader(path): + '''Loads a config for rendering the README template.''' + if not path.exists(): + print('** readme.yaml config file not found, generating template...') + with open(repo_path.joinpath('cookiecutter.json'), 'r') as fh: + cc_config = json.load(fh) + # reformat for config dictionary structure + starter_conf = {'variables_table': OrderedDict()} + for key, value in cc_config.items(): + val = None + if type(value) == str: + val = value + elif type(value) == list: + val = value[0] + elif type(value) == dict: + val = 'default' + starter_conf['variables_table'][key] = { + 'default_value': val, 'help': help_boileplate} + with open(path, 'w') as fh: + json.dump(starter_conf, fh, indent=4) + + with open(path, 'r') as fh: + config = json.load(fh) + return config + + +def exec_in_env(): + '''Use or create an env to execute this script without polluting + the users site-packages. + ''' + env_path = repo_path.joinpath('.tox', 'bootstrap') + if sys.platform == 'win32': + bin_path = env_path.joinpath('Scripts') + else: + bin_path = env_path.joinpath('bin') + if not env_path.exists(): + print('Creating bootstrap env in {} ...'.format(env_path)) + try: + check_call([sys.executable, '-m', 'venv', str(env_path)]) + except subprocess.CalledProcessError: + try: + check_call([sys.executable, '-m', 'virtualenv', str(env_path)]) + except subprocess.CalledProcessError: + check_call(['virtualenv', str(env_path)]) + print('Installing bootstrap dependencies jinja2, matrix, pyyaml, into bootstrap environment...') + check_call([str(bin_path.joinpath('pip')), + 'install', 'jinja2', 'matrix', 'pyyaml']) + python_bin = bin_path.joinpath('python') + if not python_bin.exists(): + python_bin = bin_path.joinpath('python.exe') + + print('Re-executing with: {}'.format(python_bin)) + print('Running: exec {} {} --no-env'.format(python_bin, __file__)) + re_exec(python_bin, [str(python_bin), __file__, '--no-env']) + + +def main(): + import jinja2 + import matrix + import yaml + + jinja = jinja2.Environment( + loader=jinja2.FileSystemLoader(repo_path.joinpath('ci', 'templates')), + trim_blocks=True, + lstrip_blocks=True) + + # Load README config for documentation consistency check + readme_in_path = repo_path.joinpath('ci', 'readme.json') + readme_inputs = readme_conf_loader(readme_in_path) + with open(repo_path.joinpath('cookiecutter.json'), 'r') as fh: + cc_vars = json.load(fh) + # check for keys missing from readme input + context = 'Please add them to {}\033[0m\n\033[1;36m or delete it and re-run this script.'.format( + readme_in_path) + find_missing_keys(cc_vars, readme_inputs['variables_table'], context) + # check for extra keys in the readme input + context = 'Please remove the extra keys from {}\033[0m\n\033[1;36m or delete it and re-run this script.'.format( + readme_in_path) + find_missing_keys(readme_inputs["variables_table"], cc_vars, context) + + # Remove old env configurations + tox_envs = {} + for old_env in repo_path.joinpath('ci', 'envs').iterdir(): + unlink(old_env) + + # Stages: + # 1: default output + # 2: single variations from default + # 3: matrix of component variations + # 4: matrix of deployment variations + # define starting point + # base_variant = + # define table of single changes + # define variants from starting point + # add variants to the dict + # check for duplicates in the matrix + + default_inputs = {'deployment_display_name': 'Reference', + 'deployment_slug': 'Reference'} + tox_envs['1-defaults'] = default_inputs + write_conf_file('1-defaults', default_inputs) + + long_inputs_file = {'deployment_display_name': 'Reference', + 'deployment_slug': 'Reference', + 'component_namespace': 'verylong::silly::naming::space'} + tox_envs['2-long-component-namespace'] = long_inputs_file + write_conf_file('2-long-component-namespace', long_inputs_file) + + # Make new cookiecutterrc for each env + for (alias, conf) in matrix.from_file(repo_path.joinpath('ci', 'setup.cfg')).items(): + alias = '3-{}'.format(alias) + tox_envs[alias] = conf + if 'deployment_slug' not in conf.keys(): + conf['deployment_slug'] = 'MyExample' + path_to_dep = conf['deployment_path'] + if path_to_dep == '' or path_to_dep == '.': + conf['deployment_path_to_project_root'] = '..' + else: + conf['deployment_path_to_project_root'] = '/'.join( + ['..' for k in path_to_dep.split('/')]) + write_conf_file(alias, conf) + + # Constitute templates from bootstrapped configuration + for templ in repo_path.joinpath('ci', 'templates').iterdir(): + with open(repo_path.joinpath(templ.name), 'w') as fh: + fh.write(jinja.get_template(templ.name).render( + tox_environments=tox_envs, + variables_table=readme_inputs['variables_table'])) + print('Generated {}'.format(templ.name)) + print('Done.') + + # Check for boilerplate help strings in the readme without + # preventing it from being rendered: + bp = [] + for key, value in readme_inputs['variables_table'].items(): + if value['help'][0] == help_boileplate: + bp.append(key) + if len(bp) > 0: + err_str = ['\n\033[33mWARNING: Boilerplate help strings found for the following variables:\033[0m'] + for var in bp: + err_str.append('\033[33m * {}\033[0m'.format(var)) + raise Exception('\n'.join(err_str)) + + +if __name__ == "__main__": + args = sys.argv[1:] + args = parser.parse_args(args=args) + if args.no_env: + main() + else: + exec_in_env() diff --git a/ci/check_rendered_config.py b/ci/check_rendered_config.py new file mode 100755 index 0000000..c37f638 --- /dev/null +++ b/ci/check_rendered_config.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +import argparse +from pathlib import Path +import sys +import yaml + +parser = argparse.ArgumentParser( + description='checks that the rendered output is the same configuration options as specified in the input configuration file.') +parser.add_argument('ENV_NAME', + help='name of testing env, used to find the config file') +parser.add_argument('-e', '--envdir', default=Path().joinpath('ci', 'envs'), + help='path to dir containing env configuration files') +parser.add_argument('-o', '--outdir', default=Path().joinpath('test-proj'), + help='path to folder where cookiecutter was run') + + +def main(env, envdir, outdir): + input_file = envdir.joinpath( + '{}.cookiecutterrc'.format(env)) + print("Reading env input conf file: {}".format(input_file)) + with open(input_file, 'r') as fh: + input_conf = yaml.safe_load(fh) + + output_file = outdir.joinpath(input_conf['default_context']['deployment_slug' + ], '.cookiecutterrc') + print("Reading env output conf file: {}".format(output_file)) + with open(output_file, 'r') as fh: + output_conf = yaml.safe_load(fh) + + # check for discrepencies + err_flag = False + for key in input_conf['default_context']: + in_val = input_conf['default_context'][key] + out_val = output_conf['default_context'][key] + if in_val != out_val: + err_flag = True + err_str = '** ERROR: key {} mismatch, input[\'{}\'] output[\'{}\']' + print(err_str.format(key, in_val, out_val)) + + if err_flag: + sys.exit(1) + + +if __name__ == "__main__": + args = sys.argv[1:] + args = parser.parse_args(args=args) + main(env=args.ENV_NAME, + envdir=Path(args.envdir), + outdir=Path(args.outdir)) diff --git a/ci/env_test.py b/ci/env_test.py new file mode 100755 index 0000000..1bffb2c --- /dev/null +++ b/ci/env_test.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +import argparse +import json +from os import chdir +from os import system as shell_cmd +from pathlib import Path +import subprocess +from shutil import rmtree as rm_r +import sys + +stamp_dir_name = '.progress' +this_path = Path(__file__).resolve() +repo_path = Path(*this_path.parts[:-2]) +stamp_dir = repo_path.joinpath(stamp_dir_name) +sys.path.insert(1, str(repo_path.joinpath('ci'))) + +import check_rendered_config +import render + +env_dir = repo_path.joinpath('ci', 'envs') + +parser = argparse.ArgumentParser( + description='Environment test runner for template render verification.') +parser.add_argument('ENV_NAME', + help='name of testing env, used to find the config file') +parser.add_argument('--no-env', action='store_true', + help='Execute in local context rather than venv') +parser.add_argument('-w', '--working-dir', default=repo_path.joinpath('test-proj'), + help='Path to directory containing F Prime project') + + +def check_call(args): + print('Running: ' + ' '.join(args)) + subprocess.check_call(args) + + +def run_shell_cmd(cmd): + print("Running: {}".format(cmd)) + res = shell_cmd(cmd) + if res != 0: + raise Exception('\033[1;36mFailed command: {}\033[0m'.format(cmd)) + + +def main(env, working_dir): + import yaml + + render_path = Path() + env_conf = {} + + # https://stackoverflow.com/questions/6195877/python-colour-printing-with-decorator-in-a-function + print('\033[1;36m================================\033[0m') + print('\033[1;36m================================ Testing: {}\033[0m'.format( + args.ENV_NAME)) + print('\033[1;36m================================\033[0m') + + print('CWD: {}'.format(Path.cwd())) + + if not stamp_dir.exists(): + stamp_dir.mkdir() + start_stamp = stamp_dir.joinpath('{}.start'.format(args.ENV_NAME)) + with start_stamp.open('w') as fh: + fh.write('\n') # TODO: anthing else? + + with open(repo_path.joinpath('ci', 'envs', args.ENV_NAME + '.cookiecutterrc'), 'r') as fh: + env_conf_str = fh.read() + env_conf = yaml.safe_load(env_conf_str) + print(env_conf_str) + + render_path = working_dir.joinpath( + env_conf['default_context']['deployment_slug']) + print('Render path: {}'.format(render_path)) + if render_path.exists(): + rm_r(render_path) + working_dir.mkdir(parents=True, exist_ok=True) + chdir(working_dir) + if not working_dir.joinpath('fprime').exists(): + raise Exception( + '\033[1;36mERROR: Need to checkout fprime from git\033[0m') + else: + print('F Prime already cloned.') + + render.main(envname=env, + envdir=env_dir, + outdir=working_dir, + templatedir=repo_path, + force=True) + + check_rendered_config.main(env=env, + envdir=env_dir, + outdir=working_dir) + + chdir(render_path) + + print('Checking for fprime-extras installation...') + try: + import fprime_extras + except ModuleNotFoundError: + print('System Executable: {}'.format(sys.executable)) + check_call([sys.executable, '-m', 'pip', 'install', + str(repo_path.joinpath('test-proj', 'python-fprime-extras'))]) + + print('CWD: {}'.format(Path.cwd())) + + assembly_file = 'Top/{}TopologyAppAi.xml'.format( + (env_conf['default_context']['deployment_slug'])) + run_shell_cmd( + 'fprime-extras lint {} ../fprime --config fplint.yml'.format(assembly_file)) + + run_shell_cmd('fprime-util generate') + run_shell_cmd('fprime-util build') + + stop_stamp = stamp_dir.joinpath('{}.stop'.format(args.ENV_NAME)) + with stop_stamp.open('w') as fh: + fh.write('\n') # TODO: anthing else? + + +if __name__ == "__main__": + args = sys.argv[1:] + args = parser.parse_args(args=args) + + if args.ENV_NAME == 'clean': + # Special cleaning target + if stamp_dir.exists(): + rm_r(stamp_dir) + else: + main(env=args.ENV_NAME, working_dir=Path(args.working_dir)) diff --git a/ci/envs/1-defaults.cookiecutterrc b/ci/envs/1-defaults.cookiecutterrc new file mode 100644 index 0000000..2609325 --- /dev/null +++ b/ci/envs/1-defaults.cookiecutterrc @@ -0,0 +1,3 @@ +default_context: + deployment_display_name: Reference + deployment_slug: Reference diff --git a/ci/readme.json b/ci/readme.json new file mode 100644 index 0000000..9c88fba --- /dev/null +++ b/ci/readme.json @@ -0,0 +1,141 @@ +{ + "variables_table": { + "full_name": { + "default_value": "Sterling Peet", + "help": "Main author of this deployment.\n\n Can be set in your ``~/.cookiecutterrc`` config file." + }, + "email": { + "default_value": "noreply@nospam.com", + "help": "Contact email of the author.\n\n Can be set in your ``~/.cookiecutterrc`` config file." + }, + "deployment_display_name": { + "default_value": "My Example", + "help": "The printed name of this deployment for documentation and strings. It should be concise and convey the purpose of the deployment." + }, + "dep_short_description": { + "default_value": "An example deployment [...]", + "help": "One line description of the deployment's purpose (used in headers and comments)." + }, + "deployment_slug": { + "default_value": "MyExample", + "help": "A slug_ is a simplified version of the ``deployment_name``, which will be used for the topology assembly name and file names within the deployment folder structure. It should be ``TitleCase`` with no spaces or special characters." + }, + "deployment_path": { + "default_value": "example/path", + "help": "This is the path from the F Prime root to the current directory, not including the deployment's folder. Do not add a ``/`` to the front or back of the path." + }, + "deployment_path_to_project_root": { + "default_value": "..", + "help": "This is the path from inside the deployment folder to the main project root. This is usually just up one directory." + + }, + "deployment_path_to_fprime_framework": { + "default_value": "../fprime", + "help": "This is the path from inside the deployment folder to the folder containing F Prime. In most cases, these two folders are adjacent in the project root folder." + }, + "deployment_target_platform_support": { + "default_value": "Native", + "help": "Target platform for the deployment. This gets used in the ``settings.ini`` file to avoid typing the platform when invoking ``fprimt-util``." + }, + "deployment_baremetal_scheduler": { + "default_value": "no", + "help": "Select the bare metal scheduler instead of the normal Pthreads scheduler. Small platforms may not support Pthreads, and true bare metal platforms may not even have threading support at all. If you don't know that you want the bare metal schedular, you don't." + }, + "deployment_rg_sched_contexts_hpp": { + "default_value": "no", + "help": "Use a separate contexts header file to define the deployment's rate group contexts." + }, + "deployment_parameter_support": { + "default_value": "yes", + "help": "Include components and connections to support persistent parameter storage using the F Prime parameter subsystem." + }, + "deployment_command_sequence_support": { + "default_value": "yes", + "help": "Include the components and connections needed for command sequence support." + }, + "deployment_event_text_log_support": { + "default_value": "yes", + "help": "Include the components and connections needed for for local text logging of events." + }, + "deployment_file_xfer_support": { + "default_value": "yes", + "help": "Include the components and connections needed for file uplink and downlink support." + }, + "deployment_health_support": { + "default_value": "yes", + "help": "Include the components and connections needed for component health check/ping support." + }, + "deployment_ref_doc_boilerplate": { + "default_value": "no", + "help": "Extra boilerplate documentation to support better understanding of the project." + }, + "component_name": { + "default_value": "Led Blinker", + "help": "The printed name of this internal deployment component for documentation and strings. It should be concise and convey the purpose of the component." + }, + "component_short_description": { + "default_value": "An example component [...]", + "help": "One line description of the project (used in headers and comments). This should describe the purpose of the component in the Imperetive Voice, not the context where the component is used." + }, + "component_slug": { + "default_value": "LedBlinker", + "help": "A slug_ is a simplified version of the ``component_name``, which will be used for the class name and file names within the component folder structure. It should be ``TitleCase`` with no spaces or special characters." + }, + "component_dir_name": { + "default_value": "LedBlinker", + "help": "This is the name of the component's main directory. The obvious choice is to use your ``deployment_slug`` for this field." + }, + "component_explicit_component_suffix": { + "default_value": "Component", + "help": "The general convention is for F Prime components to have the ``Component`` suffix for file names and class names. While it is not required, the Autocoder will assume this format, and Autocoder provided templates may be more difficult to adapt if this is not selected." + }, + "component_explicit_common": { + "default_value": "", + "help": "If preferred, the cpp file with the common implementation code can be appended with the suffix ``Common``." + }, + "component_impl_suffix": { + "default_value": "", + "help": "Some F Prime components use the ``Impl`` suffix for component class names and files. It is redundant because the autocoded base file always uses the suffix ``Base``, but is available for backwards compatibility and completeness." + }, + "component_path_to_fprime_root": { + "default_value": "../..", + "help": "This is the path from inside the component's folder to the F Prime root. Do not add a ``/`` to the front or back of the path (this should auto-populate from the deployment path)." + }, + "component_namespace": { + "default_value": "MyExample", + "help": "This is the namespace where your component's implementation class resides. It is usually the same but can be different from the path. If you want multiple levels of namespace, use the ``::`` notation." + }, + "component_kind": { + "default_value": "passive", + "help": "You can choose and active or passive component type. If you change your mind, is it set in the Autocoder input file (and some of the component's port kinds may also affected)." + }, + "component_multiplatform_support": { + "default_value": "no", + "help": "If you need different implementations of your component based on the target platform, choose ``yes`` to get additional support file templates." + }, + "component_instance_name": { + "default_value": "ledBlinker", + "help": "This is the variable name given to the instantiation of your component in the topology." + }, + "startup_delay_msec": { + "default_value": "2000", + "help": "Startup delay during the deployment startup, so you can tell if you got the deployment into a boot loop. This is only available on the ``Arduino`` platform." + }, + "startup_arduino_led_flash": { + "default_value": "yes", + "help": "Flash the onboard LED to signal the startup process has worked. Only available on Arduino." + }, + "arduino_log_stream": { + "default_value": "Serial", + "help": "This is the ``Arduino`` stream where the debug statements for the main deployment will print." + }, + "license": { + "default_value": "None", + "help": "License to use. Available options:\n\n * None (no license text, assume project level license)\n * BSD license\n * MIT license\n\n What license to pick? https://choosealicense.com/" + }, + "internal_use": { + "default_value": "default", + "help": "This variable is an autogenerated dictionary built from the previous answers. You should not need to adjust it, but if you are getting stuck, see the very top of this README for a solution." + } + } +} diff --git a/ci/render.py b/ci/render.py new file mode 100755 index 0000000..8310380 --- /dev/null +++ b/ci/render.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +import argparse +import json +from pathlib import Path +from os import unlink +import shutil +import sys +import yaml + +from cookiecutter.main import cookiecutter + +parser = argparse.ArgumentParser( + description='Renders the template using the specified env configuration for testing.') +parser.add_argument('ENV_NAME', + help='name of testing env, used to find the config file') +parser.add_argument('-e', '--envdir', default=Path().joinpath('ci', 'envs'), + help='path to dir containing env configuration files') +parser.add_argument('-o', '--outdir', default=Path().joinpath('test-proj'), + help='path to folder where cookiecutter was run') +parser.add_argument('-t', '--template', default=Path('.'), + help='location of template to render') +parser.add_argument('-f', '--force', action='store_true', + help='manually re-write the cookiecutter.json file with environment variables') + + +def main(envname, envdir, outdir, templatedir, force=False): + input_file = envdir.joinpath( + '{}.cookiecutterrc'.format(envname)) + print("Reading env input conf file: {}".format(input_file)) + with open(input_file, 'r') as fh: + input_conf = yaml.safe_load(fh) + + if force: + # Manually merge the keys + temp_conf_save = templatedir.joinpath('cookiecutter.json.orig') + temp_conf = templatedir.joinpath('cookiecutter.json') + temp_conf_dict = {} + with open(temp_conf, 'r') as fh: + temp_conf_dict = json.load(fh) + + for key in temp_conf_dict: + if key in input_conf['default_context'].keys(): + print("Updating json key [{}] to value [{}]".format( + key, input_conf['default_context'][key])) + temp_conf_dict[key] = input_conf['default_context'][key] + + # Save a copy of the original file + shutil.copy(temp_conf, temp_conf_save) + + try: + with open(temp_conf, 'w') as fh: + json.dump(temp_conf_dict, fh, indent=4) + template = cookiecutter(template=str(templatedir), + no_input=True, + overwrite_if_exists=True, + output_dir=outdir, + config_file=input_file) + except Exception as exc: + raise + finally: + # Put the original back, regardless of problems. + shutil.copy(temp_conf_save, temp_conf) + + else: + template = cookiecutter(template=str(templatedir), + no_input=True, + overwrite_if_exists=True, + output_dir=outdir, + config_file=input_file) + + +if __name__ == "__main__": + args = sys.argv[1:] + args = parser.parse_args(args=args) + main(envname=args.ENV_NAME, + envdir=Path(args.envdir), + outdir=Path(args.outdir), + templatedir=Path(args.template), + force=args.force) diff --git a/ci/setup.cfg b/ci/setup.cfg new file mode 100644 index 0000000..aa75f1d --- /dev/null +++ b/ci/setup.cfg @@ -0,0 +1,69 @@ +[matrix] +deployment_target_platform_support = + native: Native + arduino: Arduino +deployment_path = +# exmpl2path: example/path +# exmplepath: example + dotpath: . +# nopath: +deployment_baremetal_scheduler = + : no !deployment_target_platform_support[Arduino] + baremetal: yes !deployment_target_platform_support[Native] +# deployment_rg_sched_contexts_hpp = +# schedhpp: yes +# noschedhpp: no +deployment_parameter_support = + params: yes + : no +deployment_command_sequence_support = + seqencer: yes !deployment_target_platform_support[Arduino] + : no +deployment_file_xfer_support = + xfer: yes !deployment_target_platform_support[Arduino] + : no +deployment_health_support = + health: yes !deployment_target_platform_support[Arduino] + : no +deployment_ref_doc_boilerplate = + refdoc: yes + : no +# component_explicit_component_suffix = +# compsuffix: Component +# nocompsuffix: +# component_explicit_common = +# commsuffix: Common +# nocommsuffix: +# component_impl_suffix = +# implsuffix: Impl +# noimplsuffix: +component_kind = + active: active + passive: passive +# component_multiplatform_support = +# multip: yes +# singlep: no +# startup_delay_msec = +# delay500: 500 !deployment_target_platform_support[Arduino] +# delay0: 0 !deployment_target_platform_support[Arduino] +# startup_arduino_led_flash = +# startflash: yes !deployment_target_platform_support[Arduino] +# nostartflash: no !deployment_target_platform_support[Arduino] +# arduino_log_stream = +# serial: Serial !deployment_target_platform_support[Arduino] +# serial1: Serial1 !deployment_target_platform_support[Arduino] + +# dependencies = +# python-signalfd +# python-signalfd gevent !python_versions[3.*] +# python-signalfd eventlet !python_versions[3.*] +# eventlet !python_versions[3.*] +# gevent !python_versions[3.*] +# - +# coverage_flags = +# cover: true +# nocover: false +# # only use PATCH_THREAD=yes when 'event' is in dependencies +# environment_variables = +# patchthread: PATCH_THREAD=yes &dependencies[*event*] +# - diff --git a/ci/templates/README.rst b/ci/templates/README.rst new file mode 100644 index 0000000..eb21300 --- /dev/null +++ b/ci/templates/README.rst @@ -0,0 +1,101 @@ +.. DO NOT EDIT THIS FILE DIRECTLY!!! Edit the template in ci/templates/README.rst +.. and then regenerate this file by running the ci/bootstrap.py script. +.. +=============================== +Cookiecutter: F Prime Component +=============================== + +**WARNING:** This template uses the dictionary feature, which requires cookiecutter 1.5.0 or higher, *AND* there is a bug that requires ``click`` to be less than version 8.0.0. +For more information, see Cookiecutter_ `GitHub issue # 1558 `_. +To install a compatible version of ``click``: +:: + + pip install click==7.1.2 + +Cookiecutter_ template for a `F Prime`_ deployment, to help with reducing the copy-pasta effect while creating new deployments. +There are just enough pieces to remember to change/fix, that it is rather challenging to do without a template. +So here is a template to fill in all the major adjustments, so you can spend time developing a deployment or writing a component instead of scratching your head over why you get weird errors. + +This template currently supports only "F Prime as a library" style deployements where F Prime is probably a git submodule in the project. +If enough interest is generated for the old-style clone-and-own deplyments, we will look into adding that support. + +.. contents:: Table of Contents + +Features +-------- + +* Working deployment created by running the Cookiecutter_. +* Options to include or exclude several F Prime services, like health pinging. +* Creates a single deployment-owned component, especially useful for excercising a utility component that is under development. +* Choice of multiple target platforms for platform specific tweaks. +* Option to generate an Arduino platfrom deployment. +* Choice of various licenses. + +Requirements +------------ + +Projects using this template have these minimal dependencies: + +* Cookiecutter_ - just for creating the project + +To get quickly started on a new system, just install Cookiecutter_. You +should do this in your ``fprime-venv``. To install it, just run this +in your shell or command prompt, within the ``venv`` environment:: + + pip install cookiecutter click==7.1.2 + +Usage and options +----------------- + +This template is intended to make it easy to generate all the boilerplate required for a `F Prime`_ deployment and a single component internal to that deployment. +A collection of components along with a mission/project configuration [deployment] completes the framework to fill out a robotic software project; e.g.: a balloon payload, an wheeled rover, or maybe a satellite. + +First navigate to the directory where you want to add your deployment. +The template is going to create the folder containing your component in the current directory (you should *not* try to create the folder ahead of the template). +Next, generate the deployment's boilerplate:: + + cookiecutter gh:SterlingPeet/cookiecutter-fprime-deployment + +You will be asked for these fields: + +.. list-table:: + :header-rows: 1 + + * - Template variable + - Default + - Description + +{% for field, contents in variables_table.items() %} + * - ``{{ field }}`` + - .. code:: python + + "{{ contents.default_value }}" + + - {{ contents.help }} + +{% endfor %} + +You should now have a basic deployment that can be compiled and run. + +If you want to add components to the deployment, you can do that next. +This can be done by adding a line like this, near the bottom of the deployment's ``CMakeLists.txt`` file:: + + add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/../Prjct/Grp/MyExample") + +Then you need to (possibly purge) and generate the new cmake config in that deployment:: + + fprime-util generate + fprime-util build + +Now you should be able to run the executable from the build folder. + + +Changelog +--------- + +See `CHANGELOG.rst `_. + +.. _Cookiecutter: https://github.gatech.edu/audreyr/cookiecutter +.. _F Prime: https://github.com/nasa/fprime/ +.. _slug: https://en.wikipedia.org/wiki/Clean_URL#Slug + diff --git a/ci/templates/tox.ini b/ci/templates/tox.ini new file mode 100644 index 0000000..13b586b --- /dev/null +++ b/ci/templates/tox.ini @@ -0,0 +1,41 @@ +; DO NOT EDIT THIS FILE DIRECTLY!!! Edit the template in ci/templates/tox.ini +; and then regenerate this file by running the ci/bootstrap.py script. +; +[tox] +envlist = + {{ '{' }}clean,{{ tox_environments|sort|join(',') }}{{ '}' }} +skipsdist = true + +[testenv] +passenv = + * +basepython = + {env:TOXPYTHON:python3} +envdir = + {toxworkdir}/py +deps = + cookiecutter + fprime-tools + lxml + tox + pyyaml + click==7.1.2 + +[testenv:bootstrap] +deps = + jinja2 + matrix + pyyaml + click==7.1.2 +commands = + {toxinidir}/ci/bootstrap.py --no-env + +[testenv:clean] +commands = + {toxinidir}/ci/env_test.py clean + +{% for env, config in tox_environments|dictsort %} +[testenv:{{env}}] +commands = + {toxinidir}/ci/env_test.py {{ env }} +{% endfor %} diff --git a/cookiecutter.json b/cookiecutter.json index 1ab1372..a09c54a 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -4,10 +4,18 @@ "deployment_display_name": "My Example", "dep_short_description": "Example deployment for F Prime FSW framework.", "deployment_slug": "{{ cookiecutter.deployment_display_name|slugify(separator='', lowercase=False) }}", - "deployment_dir_name": "{{ cookiecutter.deployment_slug }}", - "deployment_path": "example/path", - "deployment_path_to_fprime_root": "../..", + "deployment_path": ".", + "deployment_path_to_project_root": "..", + "deployment_path_to_fprime_framework": "{{ cookiecutter.deployment_path_to_project_root }}/fprime", + "deployment_target_platform_support": ["Native", "Linux", "Darwin", "Arduino"], + "deployment_baremetal_scheduler": ["{% if cookiecutter.deployment_target_platform_support == 'Arduino' %}yes{% else %}no{% endif %}", "{% if cookiecutter.deployment_target_platform_support != 'Arduino' %}yes{% else %}no{% endif %}"], + "deployment_rg_sched_contexts_hpp": ["no", "yes"], "deployment_parameter_support": ["yes", "no"], + "deployment_command_sequence_support": ["{% if cookiecutter.deployment_target_platform_support != 'Arduino' %}yes{% else %}no{% endif %}", "{% if cookiecutter.deployment_target_platform_support == 'Arduino' %}yes{% else %}no{% endif %}"], + "deployment_event_text_log_support": ["{% if cookiecutter.deployment_target_platform_support != 'Arduino' %}yes{% else %}no{% endif %}", "{% if cookiecutter.deployment_target_platform_support == 'Arduino' %}yes{% else %}no{% endif %}"], + "deployment_file_xfer_support": ["{% if cookiecutter.deployment_target_platform_support != 'Arduino' %}yes{% else %}no{% endif %}", "{% if cookiecutter.deployment_target_platform_support == 'Arduino' %}yes{% else %}no{% endif %}"], + "deployment_health_support": ["{% if cookiecutter.deployment_target_platform_support != 'Arduino' %}yes{% else %}no{% endif %}", "{% if cookiecutter.deployment_target_platform_support == 'Arduino' %}yes{% else %}no{% endif %}"], + "deployment_ref_doc_boilerplate": ["no", "yes"], "component_name": "Led Blinker", "component_short_description": "Example component to support {{ cookiecutter.deployment_display_name }} deployment.", "component_slug": "{{ cookiecutter.component_name|slugify(separator='', lowercase=False) }}", @@ -15,14 +23,829 @@ "component_explicit_component_suffix": ["Component", ""], "component_explicit_common": ["", "Common"], "component_impl_suffix": ["", "Impl"], - "component_path_to_fprime_root": "{{ cookiecutter.deployment_path_to_fprime_root }}/..", - "component_namespace": "{{ cookiecutter.deployment_path|replace('/','::')|replace('\\\\','::') }}", + "component_path_to_fprime_root": "../{{ cookiecutter.deployment_path_to_project_root }}", + "component_namespace": "{{ cookiecutter.deployment_slug }}", "component_kind": ["passive", "active"], "component_multiplatform_support": ["no", "yes"], - "component_instance_name": "{{ cookiecutter.component_slug|lower }}", + "component_instance_name": "{{ cookiecutter.component_slug[0]|lower }}{{ cookiecutter.component_slug[1:] }}", "startup_delay_msec": ["2000", "1000", "500", "0"], "startup_arduino_led_flash": ["yes", "no"], "arduino_log_stream": ["Serial", "Serial1", "Serial2", "Serial3"], - "license": ["None", "MIT license", "BSD 2-Clause License", "BSD 3-Clause License"] + "license": ["None", "Apache 2.0 license", "MIT license", "BSD 2-Clause License", "BSD 3-Clause License"], + "internal_use": { + "dep_path": "{% if (cookiecutter.deployment_path == '.') or (cookiecutter.deployment_path == '') %}''{% else %}{{ cookiecutter.deployment_path }}{% endif %}", + "base_id": { + "init": 1, + "interval": 40 + }, + "thread_stack_size": "10*1024", + "prm_comp": "{% if cookiecutter.deployment_target_platform_support == 'Arduino' -%}eePrmDb{% else %}prmDb{% endif %}", + "components": [ + { + "instance": "assertResetter", + "namespace": "ATmega", + "type": "AssertReset", + "class": "AssertResetComponent", + "kind": "passive", + "base_id_window": "20", + "cmds": { + "connect": "no" + }, + "tlm": "no", + "events": "no", + "textevents": "no", + "time": "no", + "health": { + "connect": "no" + }, + "args": { + "instance": "", + "init": "" + }, + "ai_def": "ATmega/Svc/AssertReset/AssertResetComponentAi.xml", + "hpp": "ATmega/Svc/AssertReset/AssertResetComponent.hpp", + "group": "cdh", + "use": "{% if cookiecutter.deployment_target_platform_support == 'Arduino' %}yes{% else %}no{% endif %}" + }, + { + "instance": "fatalHandler", + "namespace": "Svc", + "type": "FatalHandler", + "class": "FatalHandlerComponentImpl", + "kind": "passive", + "base_id_window": "20", + "cmds": { + "connect": "no" + }, + "tlm": "no", + "events": "no", + "textevents": "no", + "time": "no", + "health": { + "connect": "no" + }, + "args": { + "instance": "", + "init": "0" + }, + "ai_def": "Svc/FatalHandler/FatalHandlerComponentAi.xml", + "hpp": "Svc/FatalHandler/FatalHandlerComponentImpl.hpp", + "group": "cdh", + "use": "{% if cookiecutter.deployment_target_platform_support == 'Arduino' %}no{% else %}yes{% endif %}" + }, + { + "instance": "fatalAdapter", + "namespace": "Svc", + "type": "AssertFatalAdapter", + "class": "AssertFatalAdapterComponentImpl", + "kind": "passive", + "base_id_window": "20", + "cmds": { + "connect": "no" + }, + "tlm": "no", + "events": "Log", + "textevents": "LogText", + "time": "Time", + "health": { + "connect": "no" + }, + "args": { + "instance": "", + "init": "0" + }, + "ai_def": "Svc/AssertFatalAdapter/AssertFatalAdapterComponentAi.xml", + "hpp": "Svc/AssertFatalAdapter/AssertFatalAdapterComponentImpl.hpp", + "group": "cdh", + "use": "{% if cookiecutter.deployment_target_platform_support == 'Arduino' %}no{% else %}yes{% endif %}" + }, + { + "instance": "blockDrv", + "namespace": "Drv", + "type": "BlockDriver", + "class": "BlockDriverImpl", + "kind": "active", + "base_id_window": "20", + "cmds": { + "connect": "no" + }, + "tlm": "Tlm", + "events": "no", + "textevents": "no", + "time": "Time", + "health": { + "connect": "yes", + "in": "PingIn", + "out": "PingOut" + }, + "args": { + "instance": "", + "init": "10" + }, + "ai_def": "Drv/BlockDriver/BlockDriverComponentAi.xml", + "hpp": "Drv/BlockDriver/BlockDriverImpl.hpp", + "group": "dep", + "use": "{% if cookiecutter.deployment_target_platform_support == 'Arduino' %}no{% else %}yes{% endif %}" + }, + { + "instance": "hardwareRateDriver", + "namespace": "Arduino", + "type": "HardwareRateDriver", + "class": "HardwareRateDriver", + "kind": "passive", + "base_id_window": "20", + "cmds": { + "connect": "no" + }, + "tlm": "no", + "events": "no", + "textevents": "no", + "time": "no", + "health": { + "connect": "no" + }, + "args": { + "instance": ", 100", + "init": "0" + }, + "ai_def": "ATmega/Drv/HardwareRateDriver/HardwareRateDriverComponentAi.xml", + "hpp": "ATmega/Drv/HardwareRateDriver/HardwareRateDriver.hpp", + "group": "dep", + "use": "{% if cookiecutter.deployment_target_platform_support == 'Arduino' %}yes{% else %}no{% endif %}" + }, + { + "instance": "rateGroupDriverComp", + "namespace": "Svc", + "type": "RateGroupDriver", + "class": "RateGroupDriverImpl", + "kind": "passive", + "base_id_window": "20", + "cmds": { + "connect": "no" + }, + "tlm": "no", + "events": "no", + "textevents": "no", + "time": "no", + "health": { + "connect": "no" + }, + "args": { + "instance": ",rgDivs,FW_NUM_ARRAY_ELEMENTS(rgDivs)", + "init": "" + }, + "ai_def": "Svc/RateGroupDriver/RateGroupDriverComponentAi.xml", + "hpp": "Svc/RateGroupDriver/RateGroupDriverImpl.hpp", + "group": "rg", + "use": "yes" + }, + { + "instance": "rateGroup1Comp", + "namespace": "Svc", + "type": "ActiveRateGroup", + "class": "ActiveRateGroupImpl", + "kind": "active", + "base_id_window": "20", + "cmds": { + "connect": "no" + }, + "tlm": "Tlm", + "events": "Log", + "textevents": "LogText", + "time": "Time", + "health": { + "connect": "yes", + "in": "PingIn", + "out": "PingOut" + }, + "args": { + "instance": ",rg1Context,FW_NUM_ARRAY_ELEMENTS(rg1Context)", + "init": "10, 0" + }, + "ai_def": "Svc/ActiveRateGroup/ActiveRateGroupComponentAi.xml", + "hpp": "Svc/ActiveRateGroup/ActiveRateGroupImpl.hpp", + "group": "rg", + "use": "yes" + }, + { + "instance": "cmdDisp", + "namespace": "Svc", + "type": "CommandDispatcher", + "class": "CommandDispatcherImpl", + "kind": "active", + "base_id_window": "20", + "cmds": { + "connect": "yes", + "reg": "CmdReg", + "disp": "CmdDisp", + "reply": "CmdStatus" + }, + "tlm": "Tlm", + "events": "Log", + "textevents": "LogText", + "time": "Time", + "health": { + "connect": "yes", + "in": "pingIn", + "out": "pingOut" + }, + "args": { + "instance": "", + "init": "{% if cookiecutter.deployment_target_platform_support == 'Arduino' %}2{% else %}20{% endif %}, 0" + }, + "ai_def": "Svc/CmdDispatcher/CommandDispatcherComponentAi.xml", + "hpp": "Svc/CmdDispatcher/CommandDispatcherImpl.hpp", + "group": "cdh", + "use": "yes" + }, + { + "instance": "cmdSeq", + "namespace": "Svc", + "type": "CmdSequencer", + "class": "CmdSequencerComponentImpl", + "kind": "active", + "base_id_window": "23", + "cmds": { + "connect": "yes", + "reg": "cmdRegOut", + "disp": "cmdIn", + "reply": "cmdResponseOut" + }, + "tlm": "tlmOut", + "events": "logOut", + "textevents": "LogText", + "time": "timeCaller", + "health": { + "connect": "yes", + "in": "pingIn", + "out": "pingOut" + }, + "args": { + "instance": "", + "init": "10, 0);\n cmdSeq.allocateBuffer(0, mallocator, 5*1024" + }, + "ai_def": "Svc/CmdSequencer/CmdSequencerComponentAi.xml", + "hpp": "Svc/CmdSequencer/CmdSequencerImpl.hpp", + "group": "cdh", + "use": "{% if cookiecutter.deployment_command_sequence_support == 'yes' %}yes{% else %}no{% endif %}" + }, + { + "instance": "chanTlm", + "namespace": "Svc", + "type": "TlmChan", + "class": "TlmChanImpl", + "kind": "active", + "base_id_window": "20", + "cmds": { + "connect": "no" + }, + "tlm": "no", + "events": "no", + "textevents": "no", + "time": "no", + "health": { + "connect": "yes", + "in": "pingIn", + "out": "pingOut" + }, + "args": { + "instance": "", + "init": "{% if cookiecutter.deployment_target_platform_support == 'Arduino' %}4{% else %}10{% endif %}, 0" + }, + "ai_def": "Svc/TlmChan/TlmChanComponentAi.xml", + "hpp": "Svc/TlmChan/TlmChanImpl.hpp", + "group": "cdh", + "use": "yes" + }, + { + "instance": "eventLogger", + "namespace": "Svc", + "type": "ActiveLogger", + "class": "ActiveLoggerImpl", + "kind": "active", + "base_id_window": "20", + "cmds": { + "connect": "yes", + "reg": "CmdReg", + "disp": "CmdDisp", + "reply": "CmdStatus" + }, + "tlm": "no", + "events": "Log", + "textevents": "no", + "time": "Time", + "health": { + "connect": "yes", + "in": "pingIn", + "out": "pingOut" + }, + "args": { + "instance": "", + "init": "{% if cookiecutter.deployment_target_platform_support == 'Arduino' %}4{% else %}10{% endif %}, 0" + }, + "ai_def": "Svc/ActiveLogger/ActiveLoggerComponentAi.xml", + "hpp": "Svc/ActiveLogger/ActiveLoggerImpl.hpp", + "group": "cdh", + "use": "yes" + }, + { + "instance": "textLogger", + "namespace": "Svc", + "type": "PassiveTextLogger", + "class": "ConsoleTextLoggerImpl", + "kind": "passive", + "base_id_window": "20", + "cmds": { + "connect": "no" + }, + "tlm": "no", + "events": "no", + "textevents": "no", + "time": "no", + "health": { + "connect": "no" + }, + "args": { + "instance": "", + "init": "" + }, + "ai_def": "Svc/PassiveConsoleTextLogger/PassiveTextLoggerComponentAi.xml", + "hpp": "Svc/PassiveConsoleTextLogger/ConsoleTextLoggerImpl.hpp", + "group": "cdh", + "use": "{% if cookiecutter.deployment_event_text_log_support == 'yes' %}yes{% else %}no{% endif %}" + }, + { + "instance": "eePrmDb", + "namespace": "ATmega", + "type": "EePrmDb", + "class": "EePrmDbComponentImpl", + "kind": "passive", + "base_id_window": "20", + "cmds": { + "connect": "yes", + "reg": "CmdReg", + "disp": "CmdDisp", + "reply": "CmdStatus" + }, + "tlm": "no", + "events": "Log", + "textevents": "LogText", + "time": "Time", + "health": { + "connect": "no", + "in": "pingIn", + "out": "pingOut" + }, + "args": { + "instance": "", + "init": "0, 32, 1024" + }, + "ai_def": "ATmega/Svc/EePrmDb/EePrmDbComponentAi.xml", + "hpp": "ATmega/Svc/EePrmDb/EePrmDbComponentImpl.hpp", + "group": "cdh", + "use": "{% if cookiecutter.deployment_parameter_support == 'yes' %}{% if cookiecutter.deployment_target_platform_support == 'Arduino' %}yes{% else %}no{% endif %}{% else %}no{% endif %}" + }, + { + "instance": "prmDb", + "namespace": "Svc", + "type": "PrmDb", + "class": "PrmDbImpl", + "kind": "active", + "base_id_window": "20", + "cmds": { + "connect": "yes", + "reg": "CmdReg", + "disp": "CmdDisp", + "reply": "CmdStatus" + }, + "tlm": "no", + "events": "Log", + "textevents": "LogText", + "time": "Time", + "health": { + "connect": "{% if cookiecutter.deployment_target_platform_support == 'Arduino' %}no{% else %}yes{% endif %}", + "in": "pingIn", + "out": "pingOut" + }, + "args": { + "instance": ",\"PrmDb.dat\"", + "init": "10, 0" + }, + "ai_def": "Svc/PrmDb/PrmDbComponentAi.xml", + "hpp": "Svc/PrmDb/PrmDbImpl.hpp", + "group": "cdh", + "use": "{% if cookiecutter.deployment_parameter_support == 'no' %}no{% else %}{% if cookiecutter.deployment_target_platform_support == 'Arduino' %}no{% else %}yes{% endif %}{% endif %}" + }, + { + "instance": "arduinoTime", + "namespace": "Svc", + "type": "Time", + "class": "LinuxTimeImpl", + "kind": "passive", + "base_id_window": "20", + "cmds": { + "connect": "no" + }, + "tlm": "no", + "events": "no", + "textevents": "no", + "time": "no", + "health": { + "connect": "no" + }, + "args": { + "instance": "", + "init": "0" + }, + "ai_def": "Svc/Time/TimeComponentAi.xml", + "hpp": "ATmega/Svc/ATmegaTime/ArduinoTimeImpl.hpp", + "group": "cdh", + "use": "{% if cookiecutter.deployment_target_platform_support == 'Arduino' %}yes{% else %}no{% endif %}" + }, + { + "instance": "linuxTime", + "namespace": "Svc", + "type": "Time", + "class": "LinuxTimeImpl", + "kind": "passive", + "base_id_window": "20", + "cmds": { + "connect": "no" + }, + "tlm": "no", + "events": "no", + "textevents": "no", + "time": "no", + "health": { + "connect": "no" + }, + "args": { + "instance": "", + "init": "0" + }, + "ai_def": "Svc/Time/TimeComponentAi.xml", + "hpp": "Svc/LinuxTime/LinuxTimeImpl.hpp", + "group": "cdh", + "use": "{% if cookiecutter.deployment_target_platform_support == 'Arduino' %}no{% else %}yes{% endif %}" + }, + { + "instance": "fileUplink", + "namespace": "Svc", + "type": "FileUplink", + "class": "FileUplink", + "kind": "active", + "base_id_window": "20", + "cmds": { + "connect": "no" + }, + "tlm": "tlmOut", + "events": "eventOut", + "textevents": "LogText", + "time": "timeCaller", + "health": { + "connect": "yes", + "in": "pingIn", + "out": "pingOut" + }, + "args": { + "instance": "", + "init": "30, 0" + }, + "ai_def": "Svc/FileUplink/FileUplinkComponentAi.xml", + "hpp": "Svc/FileUplink/FileUplink.hpp", + "group": "cdh", + "use": "{% if cookiecutter.deployment_file_xfer_support == 'yes' %}yes{% else %}no{% endif %}" + }, + { + "instance": "fileUplinkBufferManager", + "namespace": "Svc", + "type": "BufferManager", + "class": "BufferManagerComponentImpl", + "kind": "passive", + "base_id_window": "20", + "cmds": { + "connect": "no" + }, + "tlm": "tlmOut", + "events": "eventOut", + "textevents": "textEventOut", + "time": "timeCaller", + "health": { + "connect": "no" + }, + "args": { + "instance": "", + "init": "0" + }, + "ai_def": "Svc/BufferManager/BufferManagerComponentAi.xml", + "hpp": "Svc/BufferManager/BufferManagerComponentImpl.hpp", + "group": "cdh", + "use": "{% if cookiecutter.deployment_file_xfer_support == 'yes' %}yes{% else %}no{% endif %}" + }, + { + "instance": "fileDownlink", + "namespace": "Svc", + "type": "FileDownlink", + "class": "FileDownlink", + "kind": "active", + "base_id_window": "20", + "cmds": { + "connect": "yes", + "reg": "cmdRegOut", + "disp": "cmdIn", + "reply": "cmdResponseOut" + }, + "tlm": "tlmOut", + "events": "eventOut", + "textevents": "textEventOut", + "time": "timeCaller", + "health": { + "connect": "yes", + "in": "pingIn", + "out": "pingOut" + }, + "args": { + "instance": "", + "init": "30, 0);\n fileDownlink.configure(1000, 1000, 1000, 10" + }, + "ai_def": "Svc/FileDownlink/FileDownlinkComponentAi.xml", + "hpp": "Svc/FileDownlink/FileDownlink.hpp", + "group": "cdh", + "use": "{% if cookiecutter.deployment_file_xfer_support == 'yes' %}yes{% else %}no{% endif %}" + }, + { + "instance": "fileManager", + "namespace": "Svc", + "type": "FileManager", + "class": "FileManager", + "kind": "active", + "base_id_window": "20", + "cmds": { + "connect": "yes", + "reg": "cmdRegOut", + "disp": "cmdIn", + "reply": "cmdResponseOut" + }, + "tlm": "tlmOut", + "events": "eventOut", + "textevents": "LogText", + "time": "timeCaller", + "health": { + "connect": "yes", + "in": "pingIn", + "out": "pingOut" + }, + "args": { + "instance": "", + "init": "30, 0" + }, + "ai_def": "Svc/FileManager/FileManagerComponentAi.xml", + "hpp": "Svc/FileManager/FileManager.hpp", + "group": "cdh", + "use": "{% if cookiecutter.deployment_file_xfer_support == 'yes' %}yes{% else %}no{% endif %}" + }, + { + "instance": "staticMemory", + "namespace": "Svc", + "type": "StaticMemory", + "class": "StaticMemoryComponentImpl", + "kind": "passive", + "base_id_window": "20", + "cmds": { + "connect": "no" + }, + "tlm": "no", + "events": "no", + "textevents": "no", + "time": "no", + "health": { + "connect": "no" + }, + "args": { + "instance": "", + "init": "0" + }, + "ai_def": "Svc/StaticMemory/StaticMemoryComponentAi.xml", + "hpp": "Svc/StaticMemory/StaticMemoryComponentImpl.hpp", + "group": "cdh", + "use": "{% if cookiecutter.deployment_target_platform_support == 'Arduino' %}no{% else %}yes{% endif %}" + }, + { + "instance": "health", + "namespace": "Svc", + "type": "Health", + "class": "HealthImpl", + "kind": "queued", + "base_id_window": "20", + "cmds": { + "connect": "yes", + "reg": "CmdReg", + "disp": "CmdDisp", + "reply": "CmdStatus" + }, + "tlm": "Tlm", + "events": "Log", + "textevents": "LogText", + "time": "Time", + "health": { + "connect": "no" + }, + "args": { + "instance": "", + "init": "25, 0" + }, + "ai_def": "Svc/Health/HealthComponentAi.xml", + "hpp": "Svc/Health/HealthComponentImpl.hpp", + "group": "cdh", + "use": "{% if cookiecutter.deployment_health_support == 'yes' %}yes{% else %}no{% endif %}" + }, + { + "instance": "comm", + "namespace": "Drv", + "type": "ByteStreamDriverModel", + "class": "TcpClientComponentImpl", + "kind": "passive", + "base_id_window": "20", + "cmds": { + "connect": "no" + }, + "tlm": "no", + "events": "no", + "textevents": "no", + "time": "no", + "health": { + "connect": "no" + }, + "args": { + "instance": "", + "init": "0" + }, + "ai_def": "Drv/ByteStreamDriverModel/ByteStreamDriverComponentAi.xml", + "hpp": "Drv/TcpClient/TcpClientComponentImpl.hpp", + "group": "com", + "use": "{% if cookiecutter.deployment_target_platform_support == 'Arduino' %}no{% else %}yes{% endif %}" + }, + { + "instance": "uartDriver", + "namespace": "Drv", + "type": "ATmegaSerialDriver", + "class": "ATmegaSerialDriverComponentImpl", + "kind": "passive", + "base_id_window": "20", + "cmds": { + "connect": "no" + }, + "tlm": "Tlm", + "events": "no", + "textevents": "no", + "time": "no", + "health": { + "connect": "no" + }, + "args": { + "instance": "", + "init": "0" + }, + "ai_def": "ATmega/Drv/ATmegaSerialDriver/ATmegaSerialDriverComponentAi.xml", + "hpp": "ATmega/Drv/ATmegaSerialDriver/ATmegaSerialDriverComponentImpl.hpp", + "group": "com", + "use": "{% if cookiecutter.deployment_target_platform_support == 'Arduino' %}yes{% else %}no{% endif %}" + }, + { + "instance": "downlink", + "namespace": "Svc", + "type": "Framer", + "class": "FramerComponentImpl", + "kind": "passive", + "base_id_window": "20", + "cmds": { + "connect": "no" + }, + "tlm": "no", + "events": "no", + "textevents": "no", + "time": "no", + "health": { + "connect": "no" + }, + "args": { + "instance": "", + "init": "0);\n downlink.setup(framing" + }, + "ai_def": "Svc/Framer/FramerComponentAi.xml", + "hpp": "Svc/Framer/FramerComponentImpl.hpp", + "group": "cdh", + "use": "{% if cookiecutter.deployment_target_platform_support == 'Arduino' %}no{% else %}yes{% endif %}" + }, + { + "instance": "uplink", + "namespace": "Svc", + "type": "Deframer", + "class": "DeframerComponentImpl", + "kind": "passive", + "base_id_window": "20", + "cmds": { + "connect": "no" + }, + "tlm": "no", + "events": "no", + "textevents": "no", + "time": "no", + "health": { + "connect": "no" + }, + "args": { + "instance": "", + "init": "0);\n uplink.setup(deframing" + }, + "ai_def": "Svc/Deframer/DeframerComponentAi.xml", + "hpp": "Svc/Deframer/DeframerComponentImpl.hpp", + "group": "cdh", + "use": "{% if cookiecutter.deployment_target_platform_support == 'Arduino' %}no{% else %}yes{% endif %}" + }, + { + "instance": "groundInterface", + "namespace": "Svc", + "type": "GroundInterface", + "class": "GroundInterfaceComponentImpl", + "kind": "passive", + "base_id_window": "20", + "cmds": { + "connect": "no" + }, + "tlm": "no", + "events": "Log", + "textevents": "LogText", + "time": "Time", + "health": { + "connect": "no" + }, + "args": { + "instance": "", + "init": "0" + }, + "ai_def": "Svc/GroundInterface/GroundInterfaceComponentAi.xml", + "hpp": "Svc/GroundInterface/GroundInterface.hpp", + "group": "cdh", + "use": "{% if cookiecutter.deployment_target_platform_support == 'Arduino' %}yes{% else %}no{% endif %}" + }, + { + "instance": "ledGpio", + "namespace": "Drv", + "type": "ATmegaGpioDriver", + "class": "ATmegaGpioDriverComponentImpl", + "kind": "passive", + "base_id_window": "20", + "cmds": { + "connect": "no" + }, + "tlm": "no", + "events": "no", + "textevents": "no", + "time": "no", + "health": { + "connect": "no" + }, + "args": { + "instance": "", + "init": "0" + }, + "ai_def": "ATmega/Drv/ATmegaGpioDriver/ATmegaGpioDriverComponentAi.xml", + "hpp": "ATmega/Drv/ATmegaGpioDriver/ATmegaGpioDriverComponentImpl.hpp", + "group": "dep", + "use": "{% if cookiecutter.deployment_target_platform_support == 'Arduino' %}yes{% else %}no{% endif %}" + }, + { + "instance": "{{ cookiecutter.component_instance_name }}", + "namespace": "{{ cookiecutter.component_namespace }}", + "type": "{{cookiecutter.component_slug}}", + "class": "{{ cookiecutter.component_slug }}{{ cookiecutter.component_explicit_component_suffix }}{{ cookiecutter.component_impl_suffix }}", + "kind": "{{ cookiecutter.component_kind }}", + "base_id_window": "20", + "cmds": { + "connect": "{% if cookiecutter.deployment_parameter_support == 'yes' %}yes{% else %}no{% endif %}", + "reg": "CmdReg", + "disp": "CmdDisp", + "reply": "CmdStatus" + }, + "tlm": "Tlm", + "events": "{% if cookiecutter.deployment_parameter_support == 'yes' %}Log{% else %}no{% endif %}", + "textevents": "{% if cookiecutter.deployment_parameter_support == 'yes' %}LogText{% else %}no{% endif %}", + "time": "Time", + "health": { + "connect": "{% if cookiecutter.component_kind == 'active' %}yes{% else %}no{% endif %}", + "in": "pingIn", + "out": "pingOut" + }, + "args": { + "instance": "", + "init": "0" + }, + "ai_def": "{% if (cookiecutter.deployment_path == '.') or (cookiecutter.deployment_path == '') %}{% else %}{{ [cookiecutter.deployment_path, '/']|join() }}{% endif %}{{cookiecutter.deployment_slug}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}ComponentAi.xml", + "hpp": "{{ cookiecutter.deployment_slug }}/{{ cookiecutter.component_dir_name }}/{{ cookiecutter.component_slug }}{{ cookiecutter.component_explicit_component_suffix }}{{ cookiecutter.component_impl_suffix }}.hpp", + "group": "dep", + "use": "yes" + } + ] + } } - diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py index 47f03c9..0420283 100644 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -38,7 +38,9 @@ def get_class_name(comp_type, hpp_list): # Set some dates today = datetime.date.today() replace_contents(join('{{ cookiecutter.component_dir_name }}', 'docs', 'sdd.md'), '', today.strftime("%m/%d/%Y")) + replace_contents(join('docs', 'sdd.md'), '', today.strftime("%m/%d/%Y")) replace_contents('README.md', '', today.strftime("%m/%d/%Y")) + replace_contents('LICENSE', '', today.strftime('%Y')) # Delete multi-platform component files, if not desired {% if cookiecutter.component_multiplatform_support == "no" %} @@ -48,6 +50,20 @@ def get_class_name(comp_type, hpp_list): os.unlink(mp_str.format(i)) {% endif %} + # Delete rate group schedule contexts file if not in use +{% if cookiecutter.deployment_rg_sched_contexts_hpp == "no" %} + os.unlink('Top/{{cookiecutter.deployment_slug}}SchedContexts.hpp') +{% endif %} + + # Delete parameter database file if not in use +{% if (cookiecutter.deployment_parameter_support == "no") or (cookiecutter.deployment_target_platform_support == "Arduino") %} + os.unlink('PrmDb.dat') +{% endif %} + +{%- if cookiecutter.license == "None" %} + os.unlink('LICENSE') +{% endif %} + # Populate Components.hpp topology_filename = join('Top', '{{cookiecutter.deployment_slug}}TopologyAppAi.xml') components_hpp_filename = join('Top', 'Components.hpp') @@ -71,8 +87,16 @@ def get_class_name(comp_type, hpp_list): # This is a hack because Time components don't follow the modern pattern if 'TimeComponent' in str(include_path): include_path = Path('Svc/LinuxTime/LinuxTimeImpl.hpp') - folder = Path('..' + os.sep + '{{cookiecutter.deployment_path_to_fprime_root}}' + os.sep + str(include_path.parent)) - hpps = glob(str(folder) + os.sep + '*.hpp') + # This is a hack because ByteStreamDrivers are abstracted and don't get + # defined directly in the Toplogy xml file any more + if 'ByteStreamDriverModel' in str(include_path): + include_path = Path('Drv/TcpClient/TcpClientComponentImpl.hpp') + # Future Self: might need to include libraries in the search path too + folder = Path('{{cookiecutter.deployment_path_to_fprime_framework}}' + os.sep + str(include_path.parent)) + Fw_hpps = glob(str(folder) + os.sep + '*.hpp') + folder = Path('{{cookiecutter.deployment_path_to_project_root}}' + os.sep + str(include_path.parent)) + Prj_hpps = glob(str(folder) + os.sep + '*.hpp') + hpps = Fw_hpps + Prj_hpps for hpp in hpps: if hpp[-7:] != 'Cfg.hpp': long_hpp = Path(hpp) @@ -84,6 +108,14 @@ def get_class_name(comp_type, hpp_list): comp_include_declarations = '\n'.join(comp_incl_list) for comp in comp_list: class_name = get_class_name(comp.get('type'), comp_incl_paths) + # This is a hack because ByteStreamDrivers are abstracted and don't get + # defined directly in the Toplogy xml file any more + if class_name == 'ByteStreamDriverModel': + class_name = 'TcpClientComponentImpl' + if class_name == 'PassiveTextLogger': + class_name = 'ConsoleTextLoggerImpl' + if comp.get('type') == 'Time': + class_name = 'LinuxTimeImpl' comp_inst_list.append('extern {}::{} {};'.format( comp.get('namespace'), class_name, @@ -116,7 +148,9 @@ def get_class_name(comp_type, hpp_list): You've used these cookiecutter parameters: {% for key, value in cookiecutter.items()|sort %} + {%- if key != "internal_use" %} {{ "{0:26}".format(key + ":") }} {{ "{0!r}".format(value).strip("u") }} + {%- endif %} {%- endfor %} ################################################################################ @@ -127,7 +161,7 @@ def get_class_name(comp_type, hpp_list): next. This can be done by adding a line like this, near the bottom of the deployment's CMakeLists.txt file: - add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/{{ cookiecutter.deployment_path_to_fprime_root }}/{{ cookiecutter.deployment_path }}/{{ cookiecutter.component_dir_name }}") + add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/{{ cookiecutter.deployment_path_to_project_root }}/{{ cookiecutter.deployment_path }}/{{ cookiecutter.component_dir_name }}") Then you need to (possibly purge) and generate the new cmake config in the deployment: diff --git a/hooks/pre_gen_project.py b/hooks/pre_gen_project.py index 3fd5d76..89bd73a 100644 --- a/hooks/pre_gen_project.py +++ b/hooks/pre_gen_project.py @@ -1,8 +1,28 @@ -try: - import fprime_extras -except ImportError: - print('ERROR: fprime-extras must be installed to use this template!') - print('ERROR: install it from https://github.com/SterlingPeet/python-fprime-extras') - print('ERROR:') - exit(1) +# try: +# import fprime_extras +# except ImportError: +# print('ERROR: fprime-extras must be installed to use this template!') +# print('ERROR: install it from https://github.com/SterlingPeet/python-fprime-extras') +# print('ERROR:') +# exit(1) +import click +import cookiecutter + +cc_version = cookiecutter.__version__.split('.') +cc_major = 1 +cc_minor = 5 + +# dictionary variables were added in version 1.5.0 +if int(cc_version[0]) <= cc_major and int(cc_version[1]) <= cc_minor: + err_str = '\033[1;36mERROR: cookiecutter must be version {}.{}.0 or above, found version {}\033[0m' + raise Exception(err_str.format( + cc_major, cc_minor, cookiecutter.__version__)) + +# click versions above 8.0 cause dictionalry variables to stop working +click_version = click.__version__.split('.') +if int(click_version[0]) > 7: + err_str1 = '\033[1;36mERROR: click must be below version 8.0.0, found version {}\033[0m'.format(click.__version__) + err_str2 = '\033[1;36mERROR: reinstall click via \'pip install click==7.1.2\'\033[0m' + err_str3 = '\033[1;36mERROR: for details, see https://github.com/cookiecutter/cookiecutter/issues/1558\033[0m' + raise Exception('{}\n{}\n{}'.format(err_str1, err_str2, err_str3)) diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..425c15b --- /dev/null +++ b/tox.ini @@ -0,0 +1,258 @@ +; DO NOT EDIT THIS FILE DIRECTLY!!! Edit the template in ci/templates/tox.ini +; and then regenerate this file by running the ci/bootstrap.py script. +; +[tox] +envlist = + {clean,1-defaults,2-long-component-namespace,3-arduino-dotpath-baremetal-active,3-arduino-dotpath-baremetal-params-active,3-arduino-dotpath-baremetal-params-passive,3-arduino-dotpath-baremetal-params-refdoc-active,3-arduino-dotpath-baremetal-params-refdoc-passive,3-arduino-dotpath-baremetal-passive,3-arduino-dotpath-baremetal-refdoc-active,3-arduino-dotpath-baremetal-refdoc-passive,3-native-dotpath-active,3-native-dotpath-health-active,3-native-dotpath-health-passive,3-native-dotpath-health-refdoc-active,3-native-dotpath-health-refdoc-passive,3-native-dotpath-params-active,3-native-dotpath-params-health-active,3-native-dotpath-params-health-passive,3-native-dotpath-params-health-refdoc-active,3-native-dotpath-params-health-refdoc-passive,3-native-dotpath-params-passive,3-native-dotpath-params-refdoc-active,3-native-dotpath-params-refdoc-passive,3-native-dotpath-params-seqencer-active,3-native-dotpath-params-seqencer-health-active,3-native-dotpath-params-seqencer-health-passive,3-native-dotpath-params-seqencer-health-refdoc-active,3-native-dotpath-params-seqencer-health-refdoc-passive,3-native-dotpath-params-seqencer-passive,3-native-dotpath-params-seqencer-refdoc-active,3-native-dotpath-params-seqencer-refdoc-passive,3-native-dotpath-params-seqencer-xfer-active,3-native-dotpath-params-seqencer-xfer-health-active,3-native-dotpath-params-seqencer-xfer-health-passive,3-native-dotpath-params-seqencer-xfer-health-refdoc-active,3-native-dotpath-params-seqencer-xfer-health-refdoc-passive,3-native-dotpath-params-seqencer-xfer-passive,3-native-dotpath-params-seqencer-xfer-refdoc-active,3-native-dotpath-params-seqencer-xfer-refdoc-passive,3-native-dotpath-params-xfer-active,3-native-dotpath-params-xfer-health-active,3-native-dotpath-params-xfer-health-passive,3-native-dotpath-params-xfer-health-refdoc-active,3-native-dotpath-params-xfer-health-refdoc-passive,3-native-dotpath-params-xfer-passive,3-native-dotpath-params-xfer-refdoc-active,3-native-dotpath-params-xfer-refdoc-passive,3-native-dotpath-passive,3-native-dotpath-refdoc-active,3-native-dotpath-refdoc-passive,3-native-dotpath-seqencer-active,3-native-dotpath-seqencer-health-active,3-native-dotpath-seqencer-health-passive,3-native-dotpath-seqencer-health-refdoc-active,3-native-dotpath-seqencer-health-refdoc-passive,3-native-dotpath-seqencer-passive,3-native-dotpath-seqencer-refdoc-active,3-native-dotpath-seqencer-refdoc-passive,3-native-dotpath-seqencer-xfer-active,3-native-dotpath-seqencer-xfer-health-active,3-native-dotpath-seqencer-xfer-health-passive,3-native-dotpath-seqencer-xfer-health-refdoc-active,3-native-dotpath-seqencer-xfer-health-refdoc-passive,3-native-dotpath-seqencer-xfer-passive,3-native-dotpath-seqencer-xfer-refdoc-active,3-native-dotpath-seqencer-xfer-refdoc-passive,3-native-dotpath-xfer-active,3-native-dotpath-xfer-health-active,3-native-dotpath-xfer-health-passive,3-native-dotpath-xfer-health-refdoc-active,3-native-dotpath-xfer-health-refdoc-passive,3-native-dotpath-xfer-passive,3-native-dotpath-xfer-refdoc-active,3-native-dotpath-xfer-refdoc-passive} +skipsdist = true + +[testenv] +passenv = + * +basepython = + {env:TOXPYTHON:python3} +envdir = + {toxworkdir}/py +deps = + cookiecutter + fprime-tools + lxml + tox + pyyaml + click==7.1.2 + +[testenv:bootstrap] +deps = + jinja2 + matrix + pyyaml + click==7.1.2 +commands = + {toxinidir}/ci/bootstrap.py --no-env + +[testenv:clean] +commands = + {toxinidir}/ci/env_test.py clean + +[testenv:1-defaults] +commands = + {toxinidir}/ci/env_test.py 1-defaults +[testenv:2-long-component-namespace] +commands = + {toxinidir}/ci/env_test.py 2-long-component-namespace +[testenv:3-arduino-dotpath-baremetal-active] +commands = + {toxinidir}/ci/env_test.py 3-arduino-dotpath-baremetal-active +[testenv:3-arduino-dotpath-baremetal-params-active] +commands = + {toxinidir}/ci/env_test.py 3-arduino-dotpath-baremetal-params-active +[testenv:3-arduino-dotpath-baremetal-params-passive] +commands = + {toxinidir}/ci/env_test.py 3-arduino-dotpath-baremetal-params-passive +[testenv:3-arduino-dotpath-baremetal-params-refdoc-active] +commands = + {toxinidir}/ci/env_test.py 3-arduino-dotpath-baremetal-params-refdoc-active +[testenv:3-arduino-dotpath-baremetal-params-refdoc-passive] +commands = + {toxinidir}/ci/env_test.py 3-arduino-dotpath-baremetal-params-refdoc-passive +[testenv:3-arduino-dotpath-baremetal-passive] +commands = + {toxinidir}/ci/env_test.py 3-arduino-dotpath-baremetal-passive +[testenv:3-arduino-dotpath-baremetal-refdoc-active] +commands = + {toxinidir}/ci/env_test.py 3-arduino-dotpath-baremetal-refdoc-active +[testenv:3-arduino-dotpath-baremetal-refdoc-passive] +commands = + {toxinidir}/ci/env_test.py 3-arduino-dotpath-baremetal-refdoc-passive +[testenv:3-native-dotpath-active] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-active +[testenv:3-native-dotpath-health-active] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-health-active +[testenv:3-native-dotpath-health-passive] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-health-passive +[testenv:3-native-dotpath-health-refdoc-active] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-health-refdoc-active +[testenv:3-native-dotpath-health-refdoc-passive] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-health-refdoc-passive +[testenv:3-native-dotpath-params-active] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-params-active +[testenv:3-native-dotpath-params-health-active] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-params-health-active +[testenv:3-native-dotpath-params-health-passive] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-params-health-passive +[testenv:3-native-dotpath-params-health-refdoc-active] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-params-health-refdoc-active +[testenv:3-native-dotpath-params-health-refdoc-passive] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-params-health-refdoc-passive +[testenv:3-native-dotpath-params-passive] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-params-passive +[testenv:3-native-dotpath-params-refdoc-active] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-params-refdoc-active +[testenv:3-native-dotpath-params-refdoc-passive] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-params-refdoc-passive +[testenv:3-native-dotpath-params-seqencer-active] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-params-seqencer-active +[testenv:3-native-dotpath-params-seqencer-health-active] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-params-seqencer-health-active +[testenv:3-native-dotpath-params-seqencer-health-passive] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-params-seqencer-health-passive +[testenv:3-native-dotpath-params-seqencer-health-refdoc-active] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-params-seqencer-health-refdoc-active +[testenv:3-native-dotpath-params-seqencer-health-refdoc-passive] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-params-seqencer-health-refdoc-passive +[testenv:3-native-dotpath-params-seqencer-passive] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-params-seqencer-passive +[testenv:3-native-dotpath-params-seqencer-refdoc-active] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-params-seqencer-refdoc-active +[testenv:3-native-dotpath-params-seqencer-refdoc-passive] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-params-seqencer-refdoc-passive +[testenv:3-native-dotpath-params-seqencer-xfer-active] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-params-seqencer-xfer-active +[testenv:3-native-dotpath-params-seqencer-xfer-health-active] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-params-seqencer-xfer-health-active +[testenv:3-native-dotpath-params-seqencer-xfer-health-passive] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-params-seqencer-xfer-health-passive +[testenv:3-native-dotpath-params-seqencer-xfer-health-refdoc-active] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-params-seqencer-xfer-health-refdoc-active +[testenv:3-native-dotpath-params-seqencer-xfer-health-refdoc-passive] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-params-seqencer-xfer-health-refdoc-passive +[testenv:3-native-dotpath-params-seqencer-xfer-passive] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-params-seqencer-xfer-passive +[testenv:3-native-dotpath-params-seqencer-xfer-refdoc-active] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-params-seqencer-xfer-refdoc-active +[testenv:3-native-dotpath-params-seqencer-xfer-refdoc-passive] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-params-seqencer-xfer-refdoc-passive +[testenv:3-native-dotpath-params-xfer-active] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-params-xfer-active +[testenv:3-native-dotpath-params-xfer-health-active] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-params-xfer-health-active +[testenv:3-native-dotpath-params-xfer-health-passive] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-params-xfer-health-passive +[testenv:3-native-dotpath-params-xfer-health-refdoc-active] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-params-xfer-health-refdoc-active +[testenv:3-native-dotpath-params-xfer-health-refdoc-passive] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-params-xfer-health-refdoc-passive +[testenv:3-native-dotpath-params-xfer-passive] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-params-xfer-passive +[testenv:3-native-dotpath-params-xfer-refdoc-active] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-params-xfer-refdoc-active +[testenv:3-native-dotpath-params-xfer-refdoc-passive] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-params-xfer-refdoc-passive +[testenv:3-native-dotpath-passive] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-passive +[testenv:3-native-dotpath-refdoc-active] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-refdoc-active +[testenv:3-native-dotpath-refdoc-passive] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-refdoc-passive +[testenv:3-native-dotpath-seqencer-active] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-seqencer-active +[testenv:3-native-dotpath-seqencer-health-active] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-seqencer-health-active +[testenv:3-native-dotpath-seqencer-health-passive] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-seqencer-health-passive +[testenv:3-native-dotpath-seqencer-health-refdoc-active] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-seqencer-health-refdoc-active +[testenv:3-native-dotpath-seqencer-health-refdoc-passive] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-seqencer-health-refdoc-passive +[testenv:3-native-dotpath-seqencer-passive] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-seqencer-passive +[testenv:3-native-dotpath-seqencer-refdoc-active] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-seqencer-refdoc-active +[testenv:3-native-dotpath-seqencer-refdoc-passive] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-seqencer-refdoc-passive +[testenv:3-native-dotpath-seqencer-xfer-active] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-seqencer-xfer-active +[testenv:3-native-dotpath-seqencer-xfer-health-active] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-seqencer-xfer-health-active +[testenv:3-native-dotpath-seqencer-xfer-health-passive] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-seqencer-xfer-health-passive +[testenv:3-native-dotpath-seqencer-xfer-health-refdoc-active] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-seqencer-xfer-health-refdoc-active +[testenv:3-native-dotpath-seqencer-xfer-health-refdoc-passive] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-seqencer-xfer-health-refdoc-passive +[testenv:3-native-dotpath-seqencer-xfer-passive] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-seqencer-xfer-passive +[testenv:3-native-dotpath-seqencer-xfer-refdoc-active] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-seqencer-xfer-refdoc-active +[testenv:3-native-dotpath-seqencer-xfer-refdoc-passive] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-seqencer-xfer-refdoc-passive +[testenv:3-native-dotpath-xfer-active] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-xfer-active +[testenv:3-native-dotpath-xfer-health-active] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-xfer-health-active +[testenv:3-native-dotpath-xfer-health-passive] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-xfer-health-passive +[testenv:3-native-dotpath-xfer-health-refdoc-active] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-xfer-health-refdoc-active +[testenv:3-native-dotpath-xfer-health-refdoc-passive] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-xfer-health-refdoc-passive +[testenv:3-native-dotpath-xfer-passive] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-xfer-passive +[testenv:3-native-dotpath-xfer-refdoc-active] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-xfer-refdoc-active +[testenv:3-native-dotpath-xfer-refdoc-passive] +commands = + {toxinidir}/ci/env_test.py 3-native-dotpath-xfer-refdoc-passive diff --git a/{{cookiecutter.deployment_dir_name}}/.gitignore b/{{cookiecutter.deployment_dir_name}}/.gitignore deleted file mode 100644 index a7a6a7b..0000000 --- a/{{cookiecutter.deployment_dir_name}}/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# ignore backup files -*.bak diff --git a/{{cookiecutter.deployment_dir_name}}/CMakeLists.txt b/{{cookiecutter.deployment_dir_name}}/CMakeLists.txt deleted file mode 100644 index 3c580ba..0000000 --- a/{{cookiecutter.deployment_dir_name}}/CMakeLists.txt +++ /dev/null @@ -1,74 +0,0 @@ -#### -# {{cookiecutter.deployment_display_name}} Deployment: -# -# This sets up the {{cookiecutter.deployment_display_name}} deployment using CMake -# for use with F prime. -# -# This file has several sections. -# -# 1. Header Section: define basic properties of the build -# 2. F´ core: includes all F´ core components, and build-system properties -# 3. Local subdirectories: contains all deployment specific directory additions -#### - -## -# Section 1: Basic Project Setup -# -# This contains the basic project information. Specifically, a cmake version and -# project definition. -# -# The project name does need to take into account the path to the deployment folder, -# if it is not at the F Prime root, e.g.: path_to_{{cookiecutter.deployment_dir_name}} -# not having this will confuse the `fprime-util` tool. -## -project({{cookiecutter.deployment_path|replace('/','_')}}_{{cookiecutter.deployment_dir_name}} C CXX ASM) -cmake_minimum_required(VERSION 3.5) - -set(FPRIME_FRAMEWORK_PATH "${CMAKE_CURRENT_LIST_DIR}/../{{cookiecutter.deployment_path_to_fprime_root}}" CACHE PATH "Location of F prime framework" FORCE) -set(FPRIME_PROJECT_ROOT "${CMAKE_CURRENT_LIST_DIR}/../{{cookiecutter.deployment_path_to_fprime_root}}" CACHE PATH "Root path of F prime project" FORCE) - -set(BAREMETAL_SCHEDULER CACHE BOOL ON "Uses the baremetal scheduler") - -# Use file hashes instead of full file paths in the compiled binary. This can be -# converted back to a filename with the `fprime-util hashes` tool. -add_definitions(-DFW_ASSERT_LEVEL=2) - - -## -# Section 2: F´ Core -# -# This includes all of the F´ core components, and imports the make-system. F´ core -# components will be placed in the F-Prime binary subdirectory to keep them from -# colliding with deployment specific items. -## -include("${CMAKE_CURRENT_LIST_DIR}/../{{cookiecutter.deployment_path_to_fprime_root}}/cmake/FPrime.cmake") -# NOTE: register custom targets between these two lines -include("${CMAKE_CURRENT_LIST_DIR}/../{{cookiecutter.deployment_path_to_fprime_root}}/cmake/FPrime-Code.cmake") -# Note: when building a deployment outside of the F´ core directories, then the -# build root must be re-mapped for use with the standard build system components. -# -# In this way, the module names can be predicted as an offset from the (new) build -# root, without breaking the standard locations of F´. -# -# Uncomment the following lines, and set them to the BUILD_ROOT of your deployment, -# which is typically one directory up from the CMakeLists.txt in the deployment dir. -set(FPRIME_CURRENT_BUILD_ROOT "${CMAKE_CURRENT_LIST_DIR}/../{{cookiecutter.deployment_path_to_fprime_root}}") -message(STATUS "F´ BUILD_ROOT currently set to: ${FPRIME_CURRENT_BUILD_ROOT}") - -## -# Section 3: Components and Topology -# -# This section includes deployment specific directories. This allows use of non- -# core components in the topology, which is also added here. -## -# Add component subdirectories -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/../{{cookiecutter.deployment_path_to_fprime_root}}/ATmega/AssertReset/") -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/../{{cookiecutter.deployment_path_to_fprime_root}}/ATmega/HardwareRateDriver/") -{%- if cookiecutter.deployment_parameter_support == "yes" %} -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/../{{cookiecutter.deployment_path_to_fprime_root}}/ATmega/EePrmDb/") -{% endif -%} -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/{{cookiecutter.component_dir_name}}/") - -# Add Topology subdirectory -add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Top/") - diff --git a/{{cookiecutter.deployment_dir_name}}/Makefile b/{{cookiecutter.deployment_dir_name}}/Makefile deleted file mode 100644 index 4d2f765..0000000 --- a/{{cookiecutter.deployment_dir_name}}/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# Makefile to run global make. -DEPLOYMENT := {{cookiecutter.deployment_slug}} -BUILD_ROOT ?= $(subst /$(DEPLOYMENT),,$(CURDIR)) - -export BUILD_ROOT - -default_build: all dict_install - -include $(BUILD_ROOT)/mk/makefiles/deployment_makefile.mk - diff --git a/{{cookiecutter.deployment_dir_name}}/README.md b/{{cookiecutter.deployment_dir_name}}/README.md deleted file mode 100644 index aa75b3a..0000000 --- a/{{cookiecutter.deployment_dir_name}}/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# {{cookiecutter.deployment_display_name}} F Prime Deployment - -{{cookiecutter.dep_short_description}} - -## 6. Change Log - -Date | Description ----- | ----------- - | Initial Deployment Design - diff --git a/{{cookiecutter.deployment_dir_name}}/Top/Components.hpp b/{{cookiecutter.deployment_dir_name}}/Top/Components.hpp deleted file mode 100644 index 66eba5d..0000000 --- a/{{cookiecutter.deployment_dir_name}}/Top/Components.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef __{{cookiecutter.deployment_slug|upper}}_COMPONENTS_HEADER__ -#define __{{cookiecutter.deployment_slug|upper}}_COMPONENTS_HEADER__ - - - -void constructApp(void); -void construct{{cookiecutter.deployment_slug}}Architecture(void); -void exitTasks(void); - - -// extern Svc::ActiveRateGroupImpl rateGroup1HzComp; - -#endif // end __{{cookiecutter.deployment_slug|upper}}_COMPONENTS_HEADER__ diff --git a/{{cookiecutter.deployment_dir_name}}/Top/Main.cpp b/{{cookiecutter.deployment_dir_name}}/Top/Main.cpp deleted file mode 100644 index 64c077f..0000000 --- a/{{cookiecutter.deployment_dir_name}}/Top/Main.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include <{{cookiecutter.deployment_path}}/{{cookiecutter.deployment_dir_name}}/Top/Components.hpp> -#ifdef ARDUINO - #include - #include - #include -#endif - -#define STARTUP_DELAY_MS {{cookiecutter.startup_delay_msec}} - -/** - * Main function. - */ -int main(int argc, char* argv[]) { -#ifdef ARDUINO - init(); - // initVariant(); // Seems to cause main() duplicate to show up... - - {{cookiecutter.arduino_log_stream}}.begin(115200); - Os::setArduinoStreamLogHandler(&{{cookiecutter.arduino_log_stream}}); - Serial.println("Started!"); - - delay({{cookiecutter.startup_delay_msec}}); -{%- if cookiecutter.startup_arduino_led_flash == 'yes' %} - // Two quick flashes for viz indication - pinMode(13, OUTPUT); - digitalWrite(13, HIGH); - delay(100); - digitalWrite(13, LOW); - delay(100); - digitalWrite(13, HIGH); - delay(100); - digitalWrite(13, LOW); - delay(600); -{%- else %} - // // Two quick flashes for viz indication - // pinMode(13, OUTPUT); - // digitalWrite(13, HIGH); - // delay(100); - // digitalWrite(13, LOW); - // delay(100); - // digitalWrite(13, HIGH); - // delay(100); - // digitalWrite(13, LOW); - // delay(600); -{%- endif %} -#endif - constructApp(); - return 0; -} diff --git a/{{cookiecutter.deployment_dir_name}}/Top/Makefile b/{{cookiecutter.deployment_dir_name}}/Top/Makefile deleted file mode 100644 index 527f6a7..0000000 --- a/{{cookiecutter.deployment_dir_name}}/Top/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# derive module name from directory - -MODULE_DIR = {{cookiecutter.deployment_dir_name}}/Top -MODULE = $(subst /,,$(MODULE_DIR)) - -BUILD_ROOT ?= $(subst /$(MODULE_DIR),,$(CURDIR)) -export BUILD_ROOT - -include $(BUILD_ROOT)/mk/makefiles/module_targets.mk - -# Add module specific targets here diff --git a/{{cookiecutter.deployment_dir_name}}/Top/Topology.cpp b/{{cookiecutter.deployment_dir_name}}/Top/Topology.cpp deleted file mode 100644 index 9afefb5..0000000 --- a/{{cookiecutter.deployment_dir_name}}/Top/Topology.cpp +++ /dev/null @@ -1,141 +0,0 @@ -#include -#include <{{cookiecutter.deployment_slug}}SchedContexts.hpp> -#include -#include -#include -#include -#include -#ifdef ARDUINO - #include -#else - volatile uint8_t DDRB = 2; - volatile uint8_t PORTB = 2; - #define PB0 0 - #define PB1 1 - #define PB2 2 - #define PB3 3 - #define PB4 4 - #define PB5 5 - #define PB6 6 - #define PB7 7 -#endif - -// Setup the rate group driver used to drive all the ActiveRateGroups connected to it. -// For each active rate group, there is a rate divisor that represents how often it is run. -static NATIVE_INT_TYPE rate_divisors[] = {1, 10}; -Svc::RateGroupDriverImpl rateGroupDriverComp("RGDRV", rate_divisors, FW_NUM_ARRAY_ELEMENTS(rate_divisors)); - -// Context array variables are passed to rate group members if needed to distinguish one call from another -// These context must match the rate group members connected in ArduinoTopologyAi.xml -static NATIVE_UINT_TYPE rg10HzContext[] = { {{cookiecutter.deployment_slug}}::CONTEXT_{{cookiecutter.deployment_slug|upper}}_10Hz, 0, 0, 0}; -Svc::ActiveRateGroupImpl rateGroup10HzComp("RG10Hz",rg10HzContext,FW_NUM_ARRAY_ELEMENTS(rg10HzContext)); -// static NATIVE_UINT_TYPE rg1HzContext[] = {0, 0, {{cookiecutter.deployment_slug}}::CONTEXT_{{cookiecutter.deployment_slug|upper}}_1Hz, 0}; -// Svc::ActiveRateGroupImpl rateGroup1HzComp("RG1Hz",rg1HzContext,FW_NUM_ARRAY_ELEMENTS(rg1HzContext)); - -// Standard system components -ATmega::AssertResetComponent assertResetter("assertResetter"); -Svc::CommandDispatcherImpl cmdDisp("cmdDisp"); -Svc::TlmChanImpl chanTlm("chanTlm"); -Svc::ActiveLoggerImpl eventLogger("eventLogger"); -{%- if cookiecutter.deployment_parameter_support == "yes" %} -ATmega::EePrmDbComponentImpl eePrmDb("eePrmDb"); -{%- endif %} -Svc::GroundInterfaceComponentImpl groundIf("groundIf"); -Drv::ATmegaSerialDriverComponentImpl uartDriver("uartDriver"); -Svc::LinuxTimeImpl linuxTime("linuxTime"); - -// Arduino specific components -{{cookiecutter.component_namespace}}::{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}{{cookiecutter.component_impl_suffix}} {{cookiecutter.component_instance_name}}("{{cookiecutter.component_instance_name}}"); -Arduino::HardwareRateDriver hardwareRateDriver("RateDr", 100); -Drv::ATmegaGpioDriverComponentImpl ledGpio("ledGpio"); - -// Baremetal setup for the task runner -Os::TaskRunner taskRunner; - -/** - * Construct App: - * - * Constructs the App. It initialize components, call for command registration and - * starts tasks. This is the initialization of the application, so new tasks and - * memory can be acquired here, but should not be created at a later point. - */ -void constructApp(void) { - - // Initialize each component instance in memory - uartDriver.init(0); - - rateGroupDriverComp.init(); - - rateGroup10HzComp.init(10, 0); - // rateGroup1HzComp.init(10, 1); -{% if cookiecutter.deployment_parameter_support == "yes" %} - eePrmDb.init(0, 32, 1024); -{% endif %} - eventLogger.init(4,0); - - linuxTime.init(0); - - cmdDisp.init(2,0); - - chanTlm.init(4,0); - - groundIf.init(0); - - {{cookiecutter.component_instance_name}}.init(0); - - ledGpio.init(0); - -#ifndef ARDUINO - printf("Constructing Architecture.\n"); -#endif - // Callback to initialize architecture, connect ports, etc. - // The contents of the function are autocoded from the - // {{cookiecutter.deployment_slug}}TopologyAppAi.xml, and - // incorporates the assembly name. - construct{{cookiecutter.deployment_slug}}Architecture(); - - /* Register commands */ - eventLogger.regCommands(); - cmdDisp.regCommands(); -{%- if cookiecutter.deployment_parameter_support == "yes" %} - eePrmDb.regCommands(); -{%- endif %} - {{cookiecutter.component_instance_name}}.regCommands(); -{% if cookiecutter.deployment_parameter_support == "yes" %} - // read parameters - {{cookiecutter.component_instance_name}}.loadParameters(); -{% endif %} - // configure things - uartDriver.open(Drv::ATmegaSerialDriverComponentImpl::DEVICE::USART0, - Drv::ATmegaSerialDriverComponentImpl::BAUD_RATE::BAUD_115K, - Drv::ATmegaSerialDriverComponentImpl::PARITY::PARITY_NONE); - ledGpio.setup(DDRB, PORTB, PB5, Drv::ATmegaGpioDriverComponentImpl::GPIO_OUT); - - // Start all active components' tasks thus finishing the setup portion of this code - hardwareRateDriver.start(); - rateGroup10HzComp.start(0, 120, 10 * 1024); - // rateGroup1HzComp.start(0, 119, 10 * 1024); - cmdDisp.start(0,101,10*1024); - eventLogger.start(0,98,10*1024); - chanTlm.start(0,97,10*1024); - - // Start the task for the rate group -#ifndef ARDUINO - printf("Starting TaskRunner.\n"); -#endif - while(1){taskRunner.run();} -} - -/** - * Exit Tasks: - * - * Exits the tasks in preparation for stopping the software. This is likely - * not needed for Arduino projects, as they run forever, however; it is here - * for completeness. - */ -void exitTasks(void) { - // rateGroup1HzComp.exit(); - rateGroup10HzComp.exit(); - eventLogger.exit(); - chanTlm.exit(); -} diff --git a/{{cookiecutter.deployment_dir_name}}/Top/arduino.cpp b/{{cookiecutter.deployment_dir_name}}/Top/arduino.cpp deleted file mode 100644 index cc9b993..0000000 --- a/{{cookiecutter.deployment_dir_name}}/Top/arduino.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include - - -unsigned int millis() { - struct timeval tv; - gettimeofday(&tv, 0); - unsigned long long millis = ((unsigned long long)(tv.tv_sec) * 1000000ll) + (unsigned long long)(tv.tv_usec); - return millis/1000; -} -unsigned int micros() { - struct timeval tv; - gettimeofday(&tv, 0); - unsigned long long millis = ((unsigned long long)(tv.tv_sec) * 1000000ll) + (unsigned long long)(tv.tv_usec); - return millis; -} diff --git a/{{cookiecutter.deployment_dir_name}}/Top/mod.mk b/{{cookiecutter.deployment_dir_name}}/Top/mod.mk deleted file mode 100644 index 4c8efae..0000000 --- a/{{cookiecutter.deployment_dir_name}}/Top/mod.mk +++ /dev/null @@ -1,3 +0,0 @@ -SRC = Main.cpp \ - Topology.cpp \ - {{cookiecutter.deployment_slug}}TopologyAppAi.xml diff --git a/{{cookiecutter.deployment_dir_name}}/Top/{{cookiecutter.deployment_slug}}TopologyAppAi.xml b/{{cookiecutter.deployment_dir_name}}/Top/{{cookiecutter.deployment_slug}}TopologyAppAi.xml deleted file mode 100644 index 9f3c4e9..0000000 --- a/{{cookiecutter.deployment_dir_name}}/Top/{{cookiecutter.deployment_slug}}TopologyAppAi.xml +++ /dev/null @@ -1,344 +0,0 @@ - - - - - - - ATmega/AssertReset/AssertResetComponentAi.xml - Svc/ActiveRateGroup/ActiveRateGroupComponentAi.xml - Svc/RateGroupDriver/RateGroupDriverComponentAi.xml - Svc/TlmChan/TlmChanComponentAi.xml - Svc/CmdDispatcher/CommandDispatcherComponentAi.xml - Svc/GroundInterface/GroundInterfaceComponentAi.xml - Svc/ActiveLogger/ActiveLoggerComponentAi.xml - Drv/ATmegaSerialDriver/ATmegaSerialDriverComponentAi.xml -{%- if cookiecutter.deployment_parameter_support == "yes" %} - ATmega/EePrmDb/EePrmDbComponentAi.xml -{%- endif %} - ATmega/HardwareRateDriver/HardwareRateDriverComponentAi.xml - Drv/ATmegaGpioDriver/ATmegaGpioDriverComponentAi.xml - {{cookiecutter.deployment_path}}/{{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}ComponentAi.xml - Svc/Time/TimeComponentAi.xml - - - - - - - - - -{%- if cookiecutter.deployment_parameter_support == "yes" %} - -{%- endif %} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -{%- if cookiecutter.deployment_parameter_support == "yes" %} - - - - -{%- endif %} - - - - - - - - - - - - - - - -{%- if cookiecutter.deployment_parameter_support == "yes" %} - - - - -{%- endif %} - - - - - - - - - - - - - - - -{%- if cookiecutter.deployment_parameter_support == "yes" %} - - - - -{%- endif %} - - - - - - - - - - - - - - - - - - - - - -{%- if cookiecutter.deployment_parameter_support == "yes" %} - - - - -{%- endif %} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -{% if cookiecutter.deployment_parameter_support == "yes" %} - - - - - - - - -{%- endif %} - - -{% if cookiecutter.deployment_parameter_support == "yes" %} - - - - -{%- endif %} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/{{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/Makefile b/{{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/Makefile deleted file mode 100644 index 698eb0e..0000000 --- a/{{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -# This Makefile goes in each module, and allows building of an individual -# module library. -# It is expected that each developer will add targets of their own for -# building and running tests, for example. - -# derive module name from directory - -MODULE_DIR = {{cookiecutter.deployment_path}}/{{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}} -MODULE = $(subst /,,$(MODULE_DIR)) - -BUILD_ROOT ?= $(subst /$(MODULE_DIR),,$(CURDIR)) -export BUILD_ROOT - -include $(BUILD_ROOT)/mk/makefiles/module_targets.mk - -# Add module specific targets here diff --git a/{{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/mod.mk b/{{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/mod.mk deleted file mode 100644 index eda33bb..0000000 --- a/{{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/mod.mk +++ /dev/null @@ -1,23 +0,0 @@ -# This is a template for the mod.mk file that goes in each module -# and each module's subdirectories. -# With a fresh checkout, "make gen_make" should be invoked. It should also be -# run if any of the variables are updated. Any unused variables can -# be deleted from the file. - -# There are some standard files that are included for reference - - -SRC = {{cookiecutter.component_slug}}ComponentAi.xml \ - {{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}{{cookiecutter.component_explicit_common}}{{cookiecutter.component_impl_suffix}}.cpp -{% if cookiecutter.component_multiplatform_support == "yes" %} -SRC_LINUX = {{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}Linux{{cookiecutter.component_impl_suffix}}.cpp - -SRC_CYGWIN = {{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}CygWin{{cookiecutter.component_impl_suffix}}.cpp - -SRC_DARWIN = {{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}Darwin{{cookiecutter.component_impl_suffix}}.cpp - -SRC_RASPIAN = {{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}Linux{{cookiecutter.component_impl_suffix}}.cpp -{% endif %} -HDR = {{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}{{cookiecutter.component_impl_suffix}}.hpp - -SUBDIRS = diff --git a/{{cookiecutter.deployment_dir_name}}/.cookiecutterrc b/{{cookiecutter.deployment_slug}}/.cookiecutterrc similarity index 78% rename from {{cookiecutter.deployment_dir_name}}/.cookiecutterrc rename to {{cookiecutter.deployment_slug}}/.cookiecutterrc index 37b3660..1a15857 100644 --- a/{{cookiecutter.deployment_dir_name}}/.cookiecutterrc +++ b/{{cookiecutter.deployment_slug}}/.cookiecutterrc @@ -5,16 +5,18 @@ # automatically for any template). To use it: # # pip install cookiepatcher -# cookiepatcher gh:sterlingpeet/cookiecutter-fprime-deployment {{cookiecutter.deployment_dir_name}} +# cookiepatcher gh:sterlingpeet/cookiecutter-fprime-deployment {{cookiecutter.deployment_slug}} # # See: # https://pypi.org/project/cookiepatcher # # Alternatively, you can run: # -# cookiecutter --overwrite-if-exists --config-file={{cookiecutter.deployment_dir_name}}/.cookiecutterrc gh:sterlingpeet/cookiecutter-fprime-deployment +# cookiecutter --overwrite-if-exists --config-file={{cookiecutter.deployment_slug}}/.cookiecutterrc gh:sterlingpeet/cookiecutter-fprime-deployment default_context: {% for key, value in cookiecutter.items()|sort %} + {%- if key != "internal_use" %} {{ "{0:26}".format(key + ":") }} {{ "{0!r}".format(value).strip("u") }} + {%- endif %} {%- endfor %} diff --git a/{{cookiecutter.deployment_slug}}/.gitignore b/{{cookiecutter.deployment_slug}}/.gitignore new file mode 100644 index 0000000..823d888 --- /dev/null +++ b/{{cookiecutter.deployment_slug}}/.gitignore @@ -0,0 +1,12 @@ +# Evironment files are local, meant for overriding the +# project settings and not for general purpose use +environment.ini + +# The internal use dictionary is available for debugging +# but is not needed for any part of normal usage nor for +# regenerating the deployment with an updated template. +.internal_use + +# ignore backup files +*.bak +*.log diff --git a/{{cookiecutter.deployment_slug}}/.internal_use b/{{cookiecutter.deployment_slug}}/.internal_use new file mode 100644 index 0000000..10e22ac --- /dev/null +++ b/{{cookiecutter.deployment_slug}}/.internal_use @@ -0,0 +1,10 @@ +# This file exists so for debugging purposes only. +# It does not need to be committed to git. +# + +default_context: +{% for key, value in cookiecutter.items()|sort %} + {%- if key == "internal_use" %} + {{ "{0:26}".format(key + ":") }} {{ "{0!r}".format(value).strip("u") }} + {%- endif %} +{%- endfor %} diff --git a/{{cookiecutter.deployment_slug}}/CMakeLists.txt b/{{cookiecutter.deployment_slug}}/CMakeLists.txt new file mode 100644 index 0000000..84e54cb --- /dev/null +++ b/{{cookiecutter.deployment_slug}}/CMakeLists.txt @@ -0,0 +1,90 @@ +{% if (cookiecutter.deployment_path == '.') or (cookiecutter.deployment_path == '') %} + {%- set __deployment_bin_name = cookiecutter.deployment_slug -%} +{% else %} + {%- set __deployment_bin_name = [cookiecutter.deployment_path|replace('/','_'), cookiecutter.deployment_slug]|join('_') -%} +{%- endif %} +#### +# {{cookiecutter.deployment_display_name}} Deployment: +# +# This sets up the {{cookiecutter.deployment_display_name}} deployment using CMake +# for use with F prime. +# +# This file has several sections. +# +# 1. Header Section: define basic properties of the build +# 2. F´ core: includes all F´ core components, and build-system properties +# 3. Local subdirectories: contains all deployment specific directory additions +#### + +## +# Section 1: Basic Project Setup +# +# This contains the basic project information. Specifically, a cmake version and +# project definition. +# +# The project name does need to take into account the path to the deployment folder, +# if it is not at the F Prime root, e.g.: path_to_{{cookiecutter.deployment_slug}} +# not having this will confuse the `fprime-util` tool. +## +project({{ __deployment_bin_name }} C CXX ASM) +cmake_minimum_required(VERSION 3.5) + +set(FPRIME_FRAMEWORK_PATH "${CMAKE_CURRENT_LIST_DIR}/{{cookiecutter.deployment_path_to_fprime_framework}}" CACHE PATH "Location of F prime framework" FORCE) +set(FPRIME_PROJECT_ROOT "${CMAKE_CURRENT_LIST_DIR}/{{cookiecutter.deployment_path_to_project_root}}" CACHE PATH "Root path of F prime project" FORCE) + +set(BAREMETAL_SCHEDULER CACHE BOOL ON "Uses the baremetal scheduler") + +# Use file hashes instead of full file paths in the compiled binary. This can be +# converted back to a filename with the `fprime-util hashes` tool. +add_definitions(-DFW_ASSERT_LEVEL=2) + +{% if cookiecutter.deployment_target_platform_support == "Arduino" -%} +# Space Saving Measures +add_definitions(-DAssertArg=U16 -DFwPacketDescriptorType=U16 -DFwOpcodeType=U16 -DFwChanIdType=U16 -DFwEventIdType=U16 -DFwPrmIdType=U16 -DFwEnumStoreType=I32 -DFW_OBJECT_REGISTRATION=0 -DFW_QUEUE_REGISTRATION=0 -DFW_PORT_TRACING=0 -DFW_PORT_SERIALIZATION=0) +add_definitions(-DFW_COM_BUFFER_MAX_SIZE=64 -DFW_CMD_STRING_MAX_SIZE=28 -DFW_LOG_STRING_MAX_SIZE=28 -DFW_TLM_STRING_MAX_SIZE=28 -DFW_PARAM_STRING_MAX_SIZE=28) +{%- endif %} + +## +# Section 2: F´ Core +# +# This includes all of the F´ core components, and imports the make-system. F´ core +# components will be placed in the F-Prime binary subdirectory to keep them from +# colliding with deployment specific items. +## +include("${CMAKE_CURRENT_LIST_DIR}/{{cookiecutter.deployment_path_to_fprime_framework}}/cmake/FPrime.cmake") +# NOTE: register custom targets between these two lines +include("${CMAKE_CURRENT_LIST_DIR}/{{cookiecutter.deployment_path_to_fprime_framework}}/cmake/FPrime-Code.cmake") +# Note: when building a deployment outside of the F´ core directories, then the +# build root must be re-mapped for use with the standard build system components. +# +# In this way, the module names can be predicted as an offset from the (new) build +# root, without breaking the standard locations of F´. +# +# Uncomment the following lines, and set them to the BUILD_ROOT of your deployment, +# which is typically one directory up from the CMakeLists.txt in the deployment dir. +set(FPRIME_CURRENT_BUILD_ROOT "${CMAKE_CURRENT_LIST_DIR}/{{cookiecutter.deployment_path_to_project_root}}") +message(STATUS "F´ BUILD_ROOT currently set to: ${FPRIME_CURRENT_BUILD_ROOT}") + +## +# Section 3: Components and Topology +# +# This section includes deployment specific directories. This allows use of non- +# core components in the topology, which is also added here. +## +# Add component subdirectories +{% if cookiecutter.deployment_target_platform_support == 'Arduino' %} +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/{{cookiecutter.deployment_path_to_project_root}}/fprime-arduino/ATmega/ATmegaOs") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/{{cookiecutter.deployment_path_to_project_root}}/fprime-arduino/ATmega/Drv/ATmegaGpioDriver") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/{{cookiecutter.deployment_path_to_project_root}}/fprime-arduino/ATmega/Drv/ATmegaSerialDriver") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/{{cookiecutter.deployment_path_to_project_root}}/fprime-arduino/ATmega/Svc/ATmegaTime") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/{{cookiecutter.deployment_path_to_project_root}}/fprime-arduino/ATmega/Svc/AssertReset/") +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/{{cookiecutter.deployment_path_to_project_root}}/fprime-arduino/ATmega/Drv/HardwareRateDriver/") +{%- if cookiecutter.deployment_parameter_support == "yes" %} +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/{{cookiecutter.deployment_path_to_project_root}}/fprime-arduino/ATmega/Svc/EePrmDb/") +{%- endif %} +{%- endif %} +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/{{cookiecutter.component_dir_name}}/") + +# Add Topology subdirectory +add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/Top/") + diff --git a/{{cookiecutter.deployment_slug}}/LICENSE b/{{cookiecutter.deployment_slug}}/LICENSE new file mode 100644 index 0000000..79f31d8 --- /dev/null +++ b/{{cookiecutter.deployment_slug}}/LICENSE @@ -0,0 +1,35 @@ +{{ cookiecutter.deployment_display_name }} F Prime Deployment + +Copyright {{ cookiecutter.full_name }} + +{% if cookiecutter.license == 'Apache 2.0 license' -%} +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. +{% elif cookiecutter.license == 'MIT license' -%} +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +{% elif (cookiecutter.license == 'BSD 2-Clause License') or cookiecutter.license == 'BSD 3-Clause License' -%} +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +{%- if cookiecutter.license == 'BSD 3-Clause License' %} + +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. +{%- endif %} + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +{% endif -%} diff --git a/{{cookiecutter.deployment_slug}}/PrmDb.dat b/{{cookiecutter.deployment_slug}}/PrmDb.dat new file mode 100644 index 0000000000000000000000000000000000000000..aa1b20d9f02057a2cdea675edba1555e8ee256ba GIT binary patch literal 47 ocmZ3=z`(!(#Hm2cuoQ^dfH;kT8^mM<;y@k{3#1~*G03(M0CM;Rb^rhX literal 0 HcmV?d00001 diff --git a/{{cookiecutter.deployment_slug}}/README.md b/{{cookiecutter.deployment_slug}}/README.md new file mode 100644 index 0000000..e2f3cdf --- /dev/null +++ b/{{cookiecutter.deployment_slug}}/README.md @@ -0,0 +1,77 @@ +# {{cookiecutter.deployment_display_name}} F Prime Deployment + +{{cookiecutter.dep_short_description}} +{%- if cookiecutter.deployment_ref_doc_boilerplate == "yes" %} +The purpose of this application is to demonstrate a completely assembled application for use on Linux, and macOS. This allows the user to get +up and running quickly, test the installation, and work with the code before embedded hardware may be available. Should the user be interested in +cross-compiling, please see the [RPI](../RPI/README.md) reference. + +## Prerequisites + +Understanding the reference application has a few minimal prerequisites. + +**Installing F´** + +Please follow the install guide for F´ found here: [INSTALL.md](../docs/INSTALL.md). + +## Building and Running the {{cookiecutter.deployment_display_name}} Application + +In order to build the {{cookiecutter.deployment_display_name}} application, or any other F´ application, we first need to generate a build directory. F´ uses CMake under the hood, +which requires a directory to work in. To generate a build directory, we will use the `fprime-util` (a wrapper for CMake to streamline standard +F´ processes). This can be done with the following commands: + +``` +cd {{cookiecutter.deployment_slug}} +fprime-util generate +``` + +Now that the build directory has been generated, the user need not run `fprime-util generate` again unless the build directory has been removed. + +The next step is to build the {{cookiecutter.deployment_display_name}} application's code. This is done for the current system that the user is running on. This is handled by CMake +and will produce a binary that can be run on the user's system. This is accomplished by using the `build` subcommand of `fprime-util`. + +## Running the F´ Ground System and Code + +F´ ships with a browser-based test ground system. This system is designed to help developers of F´ +projects quickly test and work with F´ code without much overhead. This ground system can be run +with the following commands. Please note: the {{cookiecutter.deployment_display_name}} application's binary will also be run +automatically. This allows for quick testing on Linux and macOS. Before running the GDS, make sure +that you have built the {{cookiecutter.deployment_display_name}} example. + +``` +cd {{cookiecutter.deployment_slug}} +fprime-gds +``` + +The user may now explore the "Commanding", "Event", and "Channels" tabs to see the F´ code in action. The "Logs" tab has logs for the running +application should an error arise. See: Logs -> Ref.log to see standard output of the {{cookiecutter.deployment_display_name}} app. + +To run the ground system without starting the {{cookiecutter.deployment_display_name}} app: +``` +cd {{cookiecutter.deployment_slug}} +fprime-gds --no-app +``` + +The {{cookiecutter.deployment_display_name}} app may then be run independently from the created 'bin' directory. + +``` +cd fprime/{{cookiecutter.deployment_path}}/build-artifacts//bin/ +./{{cookiecutter.deployment_display_name}} -a 127.0.0.1 -p 50000 +``` + +## Quick Tips + +- The F´ GDS defaults to port 50000. More information can be found with `fprime-gds --help` +- The F´ utility's build command can build individual components too. +- The 'generate' command can take a toolchain argument for quickly generating a cross-compile `fprime-util generate raspberrypi` for example. + +Further work with the F´ utility can be found in the [Getting Started](../docs/Tutorials/GettingStarted/Tutorial.md) tutorial. Other tutorials +for many aspects of F´ are available [here](../docs/Tutorials/README.md). +{%- endif %} + +## Change Log + +Date | Description +---- | ----------- + | Initial Deployment Design + diff --git a/{{cookiecutter.deployment_dir_name}}/Top/.gitignore b/{{cookiecutter.deployment_slug}}/Top/.gitignore similarity index 100% rename from {{cookiecutter.deployment_dir_name}}/Top/.gitignore rename to {{cookiecutter.deployment_slug}}/Top/.gitignore diff --git a/{{cookiecutter.deployment_dir_name}}/Top/CMakeLists.txt b/{{cookiecutter.deployment_slug}}/Top/CMakeLists.txt similarity index 50% rename from {{cookiecutter.deployment_dir_name}}/Top/CMakeLists.txt rename to {{cookiecutter.deployment_slug}}/Top/CMakeLists.txt index 6823335..1645f2b 100644 --- a/{{cookiecutter.deployment_dir_name}}/Top/CMakeLists.txt +++ b/{{cookiecutter.deployment_slug}}/Top/CMakeLists.txt @@ -14,13 +14,27 @@ set(SOURCE_FILES # Note: supply non-explicit dependencies here set(MOD_DEPS Fw/Logger +{%- if cookiecutter.deployment_target_platform_support != 'Arduino' %} Svc/LinuxTime - # Os +{% else %} + ATmega/Svc/ATmegaTime +{%- endif %} +{%- if cookiecutter.deployment_baremetal_scheduler == 'yes' %} Os/Baremetal/TaskRunner +{%- endif %} +{%- if cookiecutter.deployment_target_platform_support != 'Arduino' %} + # Communication Implementations + Drv/Udp + Drv/TcpClient +{%- endif %} ) register_fprime_executable() +{%- if cookiecutter.deployment_target_platform_support == 'Arduino' %} if(${CMAKE_SYSTEM_NAME} STREQUAL "Arduino") - add_arduino_dependency("${PROJECT_NAME}") + set(ARDUINO_DEPENDENCY_TARGET_TOP "${PROJECT_NAME}") + add_arduino_dependency("${PROJECT_NAME}_exe") + unset(ARDUINO_DEPENDENCY_TARGET_TOP) endif() +{%- endif %} diff --git a/{{cookiecutter.deployment_slug}}/Top/Components.hpp b/{{cookiecutter.deployment_slug}}/Top/Components.hpp new file mode 100644 index 0000000..6ced21b --- /dev/null +++ b/{{cookiecutter.deployment_slug}}/Top/Components.hpp @@ -0,0 +1,38 @@ +{%- if cookiecutter.deployment_target_platform_support != 'Arduino' -%} + {%- set __deployment_cli = 'yes' -%} +{% else %} + {%- set __deployment_cli = 'no' -%} +{%- endif -%} +#ifndef __{{cookiecutter.deployment_slug|upper}}_COMPONENTS_HEADER__ +#define __{{cookiecutter.deployment_slug|upper}}_COMPONENTS_HEADER__ + +#include +{%- for component in cookiecutter.internal_use.components|sort(attribute='hpp') %} + {%- if component.use == 'yes' %} +#include <{{ component.hpp }}> + {%- endif -%} +{%- endfor %} +{% if cookiecutter.deployment_baremetal_scheduler == 'yes' -%} +#include +{%- endif %} + +{% if __deployment_cli == 'yes' -%} +bool constructApp(bool dump, U32 port_number, char* hostname); +{%- else %} +void constructApp(void); +{%- endif %} +void construct{{cookiecutter.deployment_slug}}Architecture(void); +void exitTasks(void); + +{% for component in cookiecutter.internal_use.components|sort(attribute='type')|sort(attribute='namespace') %} + {%- if component.use == 'yes' %} +extern {{ component.namespace }}::{{ component.class }} {{ component.instance }}; + {%- endif -%} +{%- endfor %} +// extern Svc::ActiveRateGroupImpl rg2Context; +// extern Svc::ActiveRateGroupImpl rg3Context; +{% if cookiecutter.deployment_baremetal_scheduler == 'yes' -%} +// Scheduler definition +extern Os::TaskRunner taskRunner; +{%- endif %} +#endif // end __{{cookiecutter.deployment_slug|upper}}_COMPONENTS_HEADER__ diff --git a/{{cookiecutter.deployment_slug}}/Top/Main.cpp b/{{cookiecutter.deployment_slug}}/Top/Main.cpp new file mode 100644 index 0000000..22bcea8 --- /dev/null +++ b/{{cookiecutter.deployment_slug}}/Top/Main.cpp @@ -0,0 +1,227 @@ +{%- if (cookiecutter.deployment_path == '.') or (cookiecutter.deployment_path == '') %} + {%- set __deployment_path = '' -%} +{% else %} + {%- set __deployment_path = [cookiecutter.deployment_path, '/']|join() -%} +{%- endif -%} +{%- if cookiecutter.deployment_target_platform_support != 'Arduino' %} + {%- set __deployment_cli = 'yes' %} +{% else %} + {%- set __deployment_cli = 'no' %} +{%- endif -%} +{%- if __deployment_cli == 'yes' %} +#include +#include +#include +#include +#include + +{% endif -%} +#include <{{__deployment_path}}{{cookiecutter.deployment_slug}}/Top/Components.hpp> +#include +#include +{%- if cookiecutter.deployment_target_platform_support == 'Arduino' %} +#ifdef ARDUINO + #include + #include + #include +#endif + +#define STARTUP_DELAY_MS {{cookiecutter.startup_delay_msec}} + +#if defined (DEBUG_TOP_FREE_RAM) || defined (DEBUG_TOP_SETUP) + #ifdef ARDUINO + // #include + #include + #endif + #ifndef DEBUG_Serial + #define DEBUG_Serial {{cookiecutter.arduino_log_stream}} + #endif +#endif +{%- endif %} + +/** + * In a production deployment, the following version definitions should + * be kept in a component that can telemeter the values on-demand, and + * those definitions can be used directly in the logMsg call rather than + * being re-defined below. + */ +#define {{cookiecutter.deployment_slug|upper}}_VERSION_MAJOR 0 +#define {{cookiecutter.deployment_slug|upper}}_VERSION_MINOR 0 +#define {{cookiecutter.deployment_slug|upper}}_VERSION_PATCH 1 + +{%- if __deployment_cli == 'yes' %} +void print_usage(const char* app) { + (void) printf("Usage: ./%s [options]\n-p\tport_number\n-a\thostname/IP address\n",app); +} + + +volatile sig_atomic_t terminate = 0; + +static void sighandler(int signum) { + exitTasks(); + terminate = 1; +} + +void run1cycle(void) { + // call interrupt to emulate a clock + blockDrv.callIsr(); + Os::Task::delay(1000); //10Hz +} + +void runcycles(NATIVE_INT_TYPE cycles) { + if (cycles == -1) { + while (true) { + run1cycle(); + } + } + + for (NATIVE_INT_TYPE cycle = 0; cycle < cycles; cycle++) { + run1cycle(); + } +} +{%- endif %} + +/** + * Main function for {{cookiecutter.deployment_display_name}} Deployment executable. + */ +int main(int argc, char* argv[]) { +{%- if __deployment_cli == 'yes' %} + U32 port_number; + I32 option; + char *hostname; + port_number = 0; // Invalid port number forced + option = 0; + hostname = NULL; + bool dump = false; + + while ((option = getopt(argc, argv, "hdp:a:")) != -1){ + switch(option) { + case 'h': + print_usage(argv[0]); + return 0; + break; + case 'p': + port_number = atoi(optarg); + break; + case 'a': + hostname = optarg; + break; + case '?': + return 1; + case 'd': + dump = true; + break; + default: + print_usage(argv[0]); + return 1; + } + } + + (void) printf("Hit Ctrl-C to quit\n"); +{%- endif %} + +{%- if cookiecutter.deployment_target_platform_support == 'Arduino' %} +#ifdef ARDUINO + init(); +#endif + +#ifdef ARDUINO + #ifndef LOG_Serial + #ifndef DEBUG_Serial + #define LOG_Serial {{cookiecutter.arduino_log_stream}} + #else + #define LOG_Serial DEBUG_Serial + #endif + #endif + + LOG_Serial.begin(115200); + Os::setArduinoStreamLogHandler(&LOG_Serial); +#endif +{%- endif %} + Os::Log logger; + +#ifndef RELEASE_BUILD + Fw::Logger::logMsg("\r\n{{cookiecutter.deployment_slug}} Version %d.%d.%d-devel\r\n", + {{cookiecutter.deployment_slug|upper}}_VERSION_MAJOR, + {{cookiecutter.deployment_slug|upper}}_VERSION_MINOR, + {{cookiecutter.deployment_slug|upper}}_VERSION_PATCH); +#else + Fw::Logger::logMsg("\r\n{{cookiecutter.deployment_slug}} Version %d.%d.%d\r\n", + {{cookiecutter.deployment_slug|upper}}_VERSION_MAJOR, + {{cookiecutter.deployment_slug|upper}}_VERSION_MINOR, + {{cookiecutter.deployment_slug|upper}}_VERSION_PATCH); +#endif + +{%- if cookiecutter.deployment_target_platform_support == 'Arduino' %} + delay({{cookiecutter.startup_delay_msec}}); + +#ifdef ARDUINO +{%- if cookiecutter.startup_arduino_led_flash == 'yes' %} + // Two quick flashes for viz indication + pinMode(13, OUTPUT); + digitalWrite(13, HIGH); + delay(100); + digitalWrite(13, LOW); + delay(100); + digitalWrite(13, HIGH); + delay(100); + digitalWrite(13, LOW); + delay(600); +{%- else %} + // // Two quick flashes for viz indication + // pinMode(13, OUTPUT); + // digitalWrite(13, HIGH); + // delay(100); + // digitalWrite(13, LOW); + // delay(100); + // digitalWrite(13, HIGH); + // delay(100); + // digitalWrite(13, LOW); + // delay(600); +{%- endif %} +#endif + +#ifdef DEBUG_TOP_FREE_RAM + #ifdef ARDUINO + DEBUG_Serial.print("\nFree RAM: "); + DEBUG_Serial.println(freeMemory()); + #endif +#endif + + constructApp(); +{%- endif %} +{%- if __deployment_cli == 'yes' %} + bool quit = constructApp(dump, port_number, hostname); + if (quit) { + return 0; + } + + // register signal handlers to exit program + signal(SIGINT,sighandler); + signal(SIGTERM,sighandler); + + int cycle = 0; + + // Alternate option from RPI example: + //linuxTimer.startTimer(100); //!< 10Hz + while (!terminate) { + // (void) printf("Cycle %d\n",cycle); + runcycles(1); + cycle++; + } + + // Give time for threads to exit + (void) printf("Waiting for threads...\n"); + Os::Task::delay(1000); + + (void) printf("Exiting...\n"); +{% else %} +{# Maybe this should be done differently? #} +#ifndef ARDUINO + (void) printf("Starting TaskRunner.\n"); +#endif + while(1){taskRunner.run();} +{%- endif %} + + return 0; +} diff --git a/{{cookiecutter.deployment_slug}}/Top/Topology.cpp b/{{cookiecutter.deployment_slug}}/Top/Topology.cpp new file mode 100644 index 0000000..dbee373 --- /dev/null +++ b/{{cookiecutter.deployment_slug}}/Top/Topology.cpp @@ -0,0 +1,267 @@ +{%- if cookiecutter.deployment_target_platform_support != 'Arduino' %} + {%- set __deployment_cli = 'yes' %} +{%- else %} + {%- set __deployment_cli = 'no' %} +{%- endif -%} +{%- set __dep_cmdseq_comp = cookiecutter.deployment_command_sequence_support -%} +{%- set __dep_health_comp = cookiecutter.deployment_health_support -%} +{%- if cookiecutter.deployment_target_platform_support != 'Arduino' %} + {%- set __dep_time_comp = 'linuxTime' %} +{%- else %} + {%- set __dep_time_comp = 'arduinoTime' %} +{%- endif -%} +#include +#include +{%- if cookiecutter.deployment_baremetal_scheduler == 'yes' %} +#include +{%- endif %} +#include +#include +#include +#include +{% if __deployment_cli == 'yes' -%} +#include +{%- endif %} +{%- if cookiecutter.deployment_rg_sched_contexts_hpp == "yes" %} +#include <{{cookiecutter.deployment_slug}}SchedContexts.hpp> +{%- endif %} +{% if cookiecutter.deployment_target_platform_support != 'Arduino' -%} +#include +{%- endif %} +{% if cookiecutter.deployment_target_platform_support == 'Arduino' -%} +#ifdef ARDUINO + #include +#else + volatile uint8_t DDRB = 2; + volatile uint8_t PORTB = 2; + #define PB0 0 + #define PB1 1 + #define PB2 2 + #define PB3 3 + #define PB4 4 + #define PB5 5 + #define PB6 6 + #define PB7 7 +#endif +{%- endif %} + +#if defined TGT_OS_TYPE_LINUX || TGT_OS_TYPE_DARWIN +#include +#include +#include +#endif + +// List of context IDs +enum { + UPLINK_BUFFER_STORE_SIZE = 3000, + UPLINK_BUFFER_QUEUE_SIZE = 30, + UPLINK_BUFFER_MGR_ID = 200 +}; + +Os::Log osLogger; +{% if cookiecutter.deployment_target_platform_support != 'Arduino' -%} +Svc::FprimeDeframing deframing; +Svc::FprimeFraming framing; +{%- endif %} +{%- if (__dep_cmdseq_comp == "yes") or (cookiecutter.deployment_file_xfer_support == 'yes') %} +Fw::MallocAllocator mallocator; +{%- endif %} + +// Registry +#if FW_OBJECT_REGISTRATION == 1 +static Fw::SimpleObjRegistry simpleReg; +#endif + +// Component instance pointers + +// Setup the rate group driver used to drive all the ActiveRateGroups connected to it. +// For each active rate group, there is a rate divisor that represents how often it is run. +static NATIVE_INT_TYPE rgDivs[] = {% if cookiecutter.deployment_rg_sched_contexts_hpp == "yes" %}{1, 10};{% else %}{1, 2, 4};{% endif %} +Svc::RateGroupDriverImpl rateGroupDriverComp(FW_OPTIONAL_NAME("RGDvr"),rgDivs,FW_NUM_ARRAY_ELEMENTS(rgDivs)); + +// Context array variables are passed to rate group members if needed to distinguish one call from another +// These context must match the rate group members connected in {{cookiecutter.deployment_slug}}TopologyAi.xml +static NATIVE_UINT_TYPE rg1Context[] = {{ '{' }}{% if cookiecutter.deployment_rg_sched_contexts_hpp == "yes" %}{{cookiecutter.deployment_slug}}::CONTEXT_{{cookiecutter.deployment_slug|upper}}_10Hz{% else %}0{% endif %},0,0,0,0,0,0,0,0,0{{ '}' }}; +Svc::ActiveRateGroupImpl rateGroup1Comp(FW_OPTIONAL_NAME("RG1"),rg1Context,FW_NUM_ARRAY_ELEMENTS(rg1Context)); + +// static NATIVE_UINT_TYPE rg2Context[] = {{ '{' }}{% if cookiecutter.deployment_rg_sched_contexts_hpp == "yes" %}{{cookiecutter.deployment_slug}}::CONTEXT_{{cookiecutter.deployment_slug|upper}}_5Hz{% else %}0{% endif %},0,0,0,0,0,0,0,0,0{{ '}' }}; +// Svc::ActiveRateGroupImpl rateGroup2Comp(FW_OPTIONAL_NAME("RG2"),rg2Context,FW_NUM_ARRAY_ELEMENTS(rg2Context)); + +// static NATIVE_UINT_TYPE rg3Context[] = {{ '{' }}{% if cookiecutter.deployment_rg_sched_contexts_hpp == "yes" %}{{cookiecutter.deployment_slug}}::CONTEXT_{{cookiecutter.deployment_slug|upper}}_1Hz{% else %}0{% endif %},0,0,0,0,0,0,0,0,0{{ '}' }}; +// Svc::ActiveRateGroupImpl rateGroup3Comp(FW_OPTIONAL_NAME("RG3"),rg3Context,FW_NUM_ARRAY_ELEMENTS(rg3Context)); +{% for component in cookiecutter.internal_use.components -%} + {%- if (component.use == 'yes') and (component.group != 'rg') %} + {%- if component.instance == "textLogger" %} +#if FW_ENABLE_TEXT_LOGGING +{{ component.namespace }}::{{ component.class }} {{ component.instance }}(FW_OPTIONAL_NAME("{{ component.instance }}"){{ component.args.instance }}); +#endif + {%- else %} +{{ component.namespace }}::{{ component.class }} {{ component.instance }}(FW_OPTIONAL_NAME("{{ component.instance }}"){{ component.args.instance }}); + {%- endif -%} + {%- endif -%} +{%- endfor %} +{% if cookiecutter.deployment_baremetal_scheduler == 'yes' %} +// Baremetal setup for the task runner +Os::TaskRunner taskRunner; +{%- endif %} +{% if cookiecutter.deployment_health_support == "yes" %} +const char* getHealthName(Fw::ObjBase& comp) { + #if FW_OBJECT_NAMES == 1 + return comp.getObjName(); + #else + return "[no object name]" + #endif +} +{%- endif %} + +/** + * Construct App: + * + * Constructs the App. It initialize components, call for command registration and + * starts tasks. This is the initialization of the application, so new tasks and + * memory can be acquired here, but should not be created at a later point. + */ +{%- if __deployment_cli == 'yes' %} +bool constructApp(bool dump, U32 port_number, char* hostname) { +{% else %} +void constructApp(void) { +{%- endif %} + +#if FW_PORT_TRACING + Fw::PortBase::setTrace(false); +#endif + + // Initialize each component instance in memory +{%- for component in cookiecutter.internal_use.components %} + {%- if component.use == 'yes' %} + {%- if component.instance == "textLogger" %} +#if FW_ENABLE_TEXT_LOGGING + {{ component.instance }}.init({{ component.args.init }}); +#endif + {%- else %} + {{ component.instance }}.init({{ component.args.init }}); + {%- endif -%} + {%- endif -%} +{%- endfor %} + + Fw::Logger::logMsg("Constructing Architecture.\n"); + + // Callback to initialize architecture, connect ports, etc. + // The contents of the function are autocoded from the + // {{cookiecutter.deployment_slug}}TopologyAppAi.xml, and + // incorporates the assembly name. + construct{{cookiecutter.deployment_slug}}Architecture(); + +{%- if __deployment_cli == 'yes' %} + // dump topology if requested + if (dump) { +#if FW_OBJECT_REGISTRATION == 1 + simpleReg.dump(); +#endif + return true; + } +{%- endif %} + + /* Register commands */ +{%- for component in cookiecutter.internal_use.components %} + {%- if (component.use == 'yes') and (component.kind == 'active') and (component.cmds.connect != 'no') %} + {{ component.instance }}.regCommands(); + {%- endif -%} +{%- endfor %} +{%- if cookiecutter.deployment_parameter_support == "yes" %} + + // read parameters +{%- if cookiecutter.deployment_target_platform_support != "Arduino" %} + prmDb.readParamFile(); +{%- endif %} + {{cookiecutter.component_instance_name}}.loadParameters(); +{% endif %} +{% if cookiecutter.deployment_file_xfer_support == "yes" %} + // set up BufferManager instances + Svc::BufferManagerComponentImpl::BufferBins upBuffMgrBins; + memset(&upBuffMgrBins,0,sizeof(upBuffMgrBins)); + upBuffMgrBins.bins[0].bufferSize = UPLINK_BUFFER_STORE_SIZE; + upBuffMgrBins.bins[0].numBuffers = UPLINK_BUFFER_QUEUE_SIZE; + fileUplinkBufferManager.setup(UPLINK_BUFFER_MGR_ID,0,mallocator,upBuffMgrBins); +{%- endif %} + +{%- if cookiecutter.deployment_health_support == "yes" %} + // set health ping entries + Svc::HealthImpl::PingEntry pingEntries[] = { +{%- set health_count = [] -%}{#- Counting list length is needed to defeat jinja scoping rules -#} +{%- for component in cookiecutter.internal_use.components %} + {%- if (component.use == 'yes') and (component.health.connect == 'yes') %} + {3,5,getHealthName({{ component.instance }})}, // {{ health_count|length }} + {%- set __ = health_count.append(1) -%} + {%- endif -%} +{%- endfor %} + }; + + // register ping table + health.setPingEntries(pingEntries,FW_NUM_ARRAY_ELEMENTS(pingEntries),0x123); +{%- endif %} + +{%- if cookiecutter.deployment_target_platform_support == "Arduino" %} + // Configure hardware + uartDriver.open(Drv::ATmegaSerialDriverComponentImpl::DEVICE::USART0, + Drv::ATmegaSerialDriverComponentImpl::BAUD_RATE::BAUD_115K, + Drv::ATmegaSerialDriverComponentImpl::PARITY::PARITY_NONE); + ledGpio.setup(DDRB, PORTB, PB5, Drv::ATmegaGpioDriverComponentImpl::GPIO_OUT); +{%- endif %} + + // Active component startup + // The .start() function has the following arguments: + // 1. Thread ID, unique value for each thread, not used for Linux or Baremetal + // 2. Thread Priority, passed to underlying OS + // 3. Thread Stack Size, passed to underlying OS, not used for Baremetal +{%- set priority_count = [] -%}{#- Counting list length is needed to defeat jinja scoping rules -#} +{%- for component in cookiecutter.internal_use.components %} + {%- if (component.use == 'yes') and (component.kind == 'active') %} + {{ component.instance }}.start({{ priority_count|length }}, {{ 100 - priority_count|length }}, {{ cookiecutter.internal_use.thread_stack_size }}); + {%- set __ = priority_count.append(1) -%} + {%- endif -%} +{%- endfor %} +{% if __deployment_cli == 'yes' %} + // Initialize socket server if and only if there is a valid specification + if (hostname != NULL && port_number != 0) { + Fw::EightyCharString name("ReceiveTask"); + // Uplink is configured for receive so a socket task is started + comm.configure(hostname, port_number); + comm.startSocketTask(name, 100, 10 * 1024); + } + return false; +{%- endif %} +} + +/** + * Exit Tasks: + * + * Exits the tasks in preparation for stopping the software.{% if cookiecutter.deployment_target_platform_support == 'Arduino' %} This is likely + * not needed for Arduino projects, as they run forever, however; it is here + * for completeness.{% endif %} + */ +void exitTasks(void) { +{%- for component in cookiecutter.internal_use.components %} + {%- if (component.use == 'yes') and (component.kind == 'active') %} + {{ component.instance }}.exit(); + {%- endif -%} +{%- endfor %} +{%- if cookiecutter.deployment_baremetal_scheduler == "no" %} + // join the component threads with NULL pointers to free them +{%- for component in cookiecutter.internal_use.components %} + {%- if (component.use == 'yes') and (component.kind == 'active') %} + (void) {{ component.instance }}.ActiveComponentBase::join(NULL); + {%- endif -%} +{%- endfor %} +{%- endif %} +{% if cookiecutter.deployment_target_platform_support != "Arduino" %} + comm.stopSocketTask(); + (void) comm.joinSocketTask(NULL); +{%- endif %} +{%- if __dep_cmdseq_comp == "yes" %} + cmdSeq.deallocateBuffer(mallocator); +{%- endif %} +{%- if cookiecutter.deployment_file_xfer_support == "yes" %} + fileUplinkBufferManager.cleanup(); +{%- endif %} +} diff --git a/{{cookiecutter.deployment_dir_name}}/Top/{{cookiecutter.deployment_slug}}SchedContexts.hpp b/{{cookiecutter.deployment_slug}}/Top/{{cookiecutter.deployment_slug}}SchedContexts.hpp similarity index 60% rename from {{cookiecutter.deployment_dir_name}}/Top/{{cookiecutter.deployment_slug}}SchedContexts.hpp rename to {{cookiecutter.deployment_slug}}/Top/{{cookiecutter.deployment_slug}}SchedContexts.hpp index 6758b8b..ca43a15 100644 --- a/{{cookiecutter.deployment_dir_name}}/Top/{{cookiecutter.deployment_slug}}SchedContexts.hpp +++ b/{{cookiecutter.deployment_slug}}/Top/{{cookiecutter.deployment_slug}}SchedContexts.hpp @@ -5,15 +5,16 @@ // ====================================================================== -#ifndef {{cookiecutter.deployment_dir_name|upper}}_TOP_{{cookiecutter.deployment_slug|upper}}SCHEDCONTEXTS_HPP_ -#define {{cookiecutter.deployment_dir_name|upper}}_TOP_{{cookiecutter.deployment_slug|upper}}SCHEDCONTEXTS_HPP_ +#ifndef {{cookiecutter.deployment_slug|upper}}_TOP_{{cookiecutter.deployment_slug|upper}}SCHEDCONTEXTS_HPP_ +#define {{cookiecutter.deployment_slug|upper}}_TOP_{{cookiecutter.deployment_slug|upper}}SCHEDCONTEXTS_HPP_ namespace {{cookiecutter.deployment_slug}} { // A list of contexts for the rate groups enum { - // CONTEXT_{{cookiecutter.deployment_slug|upper}}_1Hz = 10, // 1 Hz cycle CONTEXT_{{cookiecutter.deployment_slug|upper}}_10Hz = 11 // 10 Hz cycle + // CONTEXT_{{cookiecutter.deployment_slug|upper}}_5Hz = 10, // 1 Hz cycle + // CONTEXT_{{cookiecutter.deployment_slug|upper}}_1Hz = 9, // 1 Hz cycle }; } // end {{cookiecutter.deployment_slug}} -#endif /* {{cookiecutter.deployment_dir_name|upper}}_TOP_{{cookiecutter.deployment_slug|upper}}SCHEDCONTEXTS_HPP_ */ +#endif /* {{cookiecutter.deployment_slug|upper}}_TOP_{{cookiecutter.deployment_slug|upper}}SCHEDCONTEXTS_HPP_ */ diff --git a/{{cookiecutter.deployment_slug}}/Top/{{cookiecutter.deployment_slug}}TopologyAppAi.xml b/{{cookiecutter.deployment_slug}}/Top/{{cookiecutter.deployment_slug}}TopologyAppAi.xml new file mode 100644 index 0000000..94a2dbe --- /dev/null +++ b/{{cookiecutter.deployment_slug}}/Top/{{cookiecutter.deployment_slug}}TopologyAppAi.xml @@ -0,0 +1,378 @@ + + + + + +{% set import_paths = [] -%}{#- variable to store list of import paths -#} +{%- for component in cookiecutter.internal_use.components %} + {%- if component.use == 'yes' -%} + {%- set __ = import_paths.append(component.ai_def) -%} + {%- endif -%} +{%- endfor %} +{%- for path in import_paths|sort %} + {{ path }} +{%- endfor %} + + + + +{% set base_id = { 'value': cookiecutter.internal_use.base_id.init } -%} +{%- for component in cookiecutter.internal_use.components %} + {%- if (component.use == 'yes') and (component.group == 'cdh') %} + + {%- set __ = base_id.update({'value': base_id.value|int + cookiecutter.internal_use.base_id.interval|int }) -%} + {%- endif -%} +{%- endfor %} + + +{%- if cookiecutter.deployment_target_platform_support != "Arduino" %} + +{%- endif %} +{% for component in cookiecutter.internal_use.components %} + {%- if (component.use == 'yes') and (component.group == 'com') %} + + {%- set __ = base_id.update({'value': base_id.value|int + cookiecutter.internal_use.base_id.interval|int }) -%} + {%- endif -%} +{%- endfor %} + + +{% for component in cookiecutter.internal_use.components %} + {%- if (component.use == 'yes') and (component.group == 'rg') %} + + {%- set __ = base_id.update({'value': base_id.value|int + cookiecutter.internal_use.base_id.interval|int }) -%} + {%- endif -%} +{%- endfor %} + + +{% for component in cookiecutter.internal_use.components %} + {%- if (component.use == 'yes') and (component.group == 'dep') %} + + {%- set __ = base_id.update({'value': base_id.value|int + cookiecutter.internal_use.base_id.interval|int }) -%} + {%- endif -%} +{%- endfor %} + + + + +{% if cookiecutter.deployment_target_platform_support == "Arduino" %} + + + + + + + + +{%- else %} + + + + + + + + + + + + +{%- endif %} + + + + +{%- if cookiecutter.deployment_target_platform_support == "Arduino" %} + +{%- else %} + +{%- endif %} + + +{%- if cookiecutter.deployment_file_xfer_support == "yes" %} + + + + + + + + + + + + + + + + +{%- endif %} + + +{% if cookiecutter.deployment_target_platform_support == "Arduino" %} +{%- else %} + + + + + + + + + + + + +{%- endif %} + + + + + +{%- if cookiecutter.deployment_target_platform_support == "Arduino" %} + +{%- else %} + +{%- endif %} + + + +{%- if cookiecutter.deployment_target_platform_support == "Arduino" %} + +{%- else %} + +{%- endif %} + +{%- if cookiecutter.deployment_file_xfer_support == "yes" %} + + + + + + + + +{%- endif %} + + + + +{% set cmd_count = [] -%}{#- Counting list length is needed to defeat jinja scoping rules -#} +{%- for component in cookiecutter.internal_use.components %} + {%- if (component.use == 'yes') and (component.cmds.connect != 'no') %} + + + + + {%- set __ = cmd_count.append(1) -%} + {%- endif -%} +{%- endfor %} + + +{% set cmd_count = [] -%}{#- Counting list length is needed to defeat jinja scoping rules -#} +{%- for component in cookiecutter.internal_use.components %} + {%- if (component.use == 'yes') and (component.cmds.connect != 'no') %} + + + + + {%- set __ = cmd_count.append(1) -%} + {%- endif -%} +{%- endfor %} + + +{% for component in cookiecutter.internal_use.components %} + {%- if (component.use == 'yes') and (component.cmds.connect != 'no') %} + + + + + {%- endif -%} +{%- endfor %} + + +{% if cookiecutter.deployment_command_sequence_support == "yes" %} + + + + + + + + + +{%- endif %} + + +{% for component in cookiecutter.internal_use.components %} + {%- if (component.use == 'yes') and (component.events != 'no') %} + + + + + {%- endif -%} +{%- endfor %} + + +{% if cookiecutter.deployment_event_text_log_support == "yes" %} +{%- for component in cookiecutter.internal_use.components %} + {%- if (component.use == 'yes') and (component.textevents != 'no') %} + + + + + {%- endif -%} +{%- endfor %} +{%- endif %} + + +{% for component in cookiecutter.internal_use.components %} + {%- if (component.use == 'yes') and (component.tlm != 'no') %} + + + + + {%- endif -%} +{%- endfor %} + + +{% if cookiecutter.deployment_parameter_support == "yes" %} + + + + + + + + +{%- endif %} + + +{% for component in cookiecutter.internal_use.components %} + {%- if (component.use == 'yes') and (component.time != 'no') %} + + + + + {%- endif -%} +{%- endfor %} +{% if cookiecutter.deployment_target_platform_support == "Arduino" %} + + + + + +{%- endif %} + + + +{%- if cookiecutter.deployment_target_platform_support == "Arduino" %} + + + + + +{%- endif %} + + + + + + + + + + + +{%- if cookiecutter.deployment_target_platform_support == "Arduino" %} + + + + + + + + +{%- endif %} + + + + +{%- if cookiecutter.deployment_file_xfer_support == "yes" %} + + + + +{%- endif %} +{% if cookiecutter.deployment_health_support == "yes" -%} + + + + +{%- endif %} + + + + + + +{%- if cookiecutter.deployment_file_xfer_support == "yes" %} + + +{%- endif %} + + +{% if cookiecutter.deployment_health_support == "yes" %} + + + +{% set health_count = [] -%}{#- Counting list length is needed to defeat jinja scoping rules -#} +{%- for component in cookiecutter.internal_use.components %} + {%- if (component.use == 'yes') and (component.health.connect == 'yes') %} + + + + + + + + + {%- set __ = health_count.append(1) -%} + {%- endif -%} +{%- endfor %} +{%- endif %} + + +{% if cookiecutter.deployment_target_platform_support != "Arduino" %} + + + + +{%- endif %} + + diff --git a/{{cookiecutter.deployment_slug}}/config/AcConstants.ini b/{{cookiecutter.deployment_slug}}/config/AcConstants.ini new file mode 100644 index 0000000..a3de80c --- /dev/null +++ b/{{cookiecutter.deployment_slug}}/config/AcConstants.ini @@ -0,0 +1,23 @@ +# Syntax in the file follows the Python ConfigParser INI file specification + +[Component] + +# Define numbers of ports +ActiveRateGroupOutputPorts = 10 ; Number of rate group member output ports for ActiveRateGroup +CmdDispatcherComponentCommandPorts = 30 ; Used for command and registration ports +CmdDispatcherSequencePorts = 5 ; Used for uplink/sequencer buffer/response ports +RateGroupDriverRateGroupPorts = 3 ; Used to drive rate groups +HealthPingPorts = 25 ; Used to ping active components +FileDownCompletePorts = 1 ; Used for broadcasting completed file downlinks + +; Hub connections. Connections on all deployments should mirror these settings. +GenericHubInputPorts = 10 +GenericHubOutputPorts = 10 +GenericHubInputBuffers = 10 +GenericHubOutputBuffers = 10 + +; Outputs from the generic repeater. +GenericRepeaterOutputPorts = 2 + + +StaticMemoryAllocations = 4 \ No newline at end of file diff --git a/{{cookiecutter.deployment_slug}}/docs/.gitignore b/{{cookiecutter.deployment_slug}}/docs/.gitignore new file mode 100644 index 0000000..0b84df0 --- /dev/null +++ b/{{cookiecutter.deployment_slug}}/docs/.gitignore @@ -0,0 +1 @@ +*.html \ No newline at end of file diff --git a/{{cookiecutter.deployment_slug}}/docs/doxygen.txt b/{{cookiecutter.deployment_slug}}/docs/doxygen.txt new file mode 100644 index 0000000..d5efbd8 --- /dev/null +++ b/{{cookiecutter.deployment_slug}}/docs/doxygen.txt @@ -0,0 +1,20 @@ +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "{{cookiecutter.deployment_display_name}}" + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "{{cookiecutter.dep_short_description}}" + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = diff --git a/{{cookiecutter.deployment_slug}}/docs/sdd.md b/{{cookiecutter.deployment_slug}}/docs/sdd.md new file mode 100644 index 0000000..0c86540 --- /dev/null +++ b/{{cookiecutter.deployment_slug}}/docs/sdd.md @@ -0,0 +1,18 @@ +# Reference Deployment + +## 1. Description + +The reference deployment application is to demonstrate a collection of F Prime components interconnected to form a deployment. The deployment represents a "reference" spacecraft that includes commanding, events, telemetry channels and parameters. + +## 2. Topology + +The topology of the reference example is the interconnection of all the components used in the reference deployment (a deployment is a set of components connected together and compiled into a binary). There are a large number of connections so it is not feasible to show them all in one diagram. The following sections have views of the topology that show the connections for a particular purpose. The topology diagrams will be broken down into the core set of Command and Data Handling (C&DH) connections that would be reused from project to project as well as the connections unique to the reference example. + +## 3. Change Log + +Date | Description +---------- | ----------- + | Initial version + + + diff --git a/{{cookiecutter.deployment_slug}}/docs/{{cookiecutter.deployment_slug}}.md b/{{cookiecutter.deployment_slug}}/docs/{{cookiecutter.deployment_slug}}.md new file mode 100644 index 0000000..9e8c7b1 --- /dev/null +++ b/{{cookiecutter.deployment_slug}}/docs/{{cookiecutter.deployment_slug}}.md @@ -0,0 +1,31 @@ +# {{cookiecutter.deployment_display_name}} Deployment + +## SDD Links + +### Deployment + +[{{cookiecutter.deployment_display_name}} SDD](sdd.md) + +### Modules +|Module|Link] +|---|---| +|{{cookiecutter.deployment_slug}}/Top|[Link](../../{{cookiecutter.deployment_slug}}/Top/docs/sdd.md)| +|Svc/CmdDispatcher|[Link](../../Svc/CmdDispatcher/docs/sdd.md)| +|Svc/CmdSequencer|[Link](../../Svc/CmdSequencer/docs/sdd.md)| +|Svc/GndIf|[Link](../../Svc/GndIf/docs/sdd.md)| +|Svc/ActiveRateGroup|[Link](../../Svc/ActiveRateGroup/docs/sdd.md)| +|Svc/RateGroupDriver|[Link](../../Svc/RateGroupDriver/docs/sdd.md)| +|Svc/Sched|[Link](../../Svc/Sched/docs/sdd.md)| +|Svc/ComLogger|[Link](../../Svc/ComLogger/docs/sdd.md)| +|Svc/CmdRecord|[Link](../../Svc/CmdRecord/docs/sdd.md)| +|Svc/SocketGndIf|[Link](../../Svc/SocketGndIf/docs/sdd.md)| +|Svc/BuffGndSockIf|[Link](../../Svc/BuffGndSockIf/docs/sdd.md)| +|Svc/TlmChan|[Link](../../Svc/TlmChan/docs/sdd.md)| +|Svc/PassiveTextLogger|[Link](../../Svc/PassiveTextLogger/docs/sdd.md)| +|Svc/PassiveConsoleTextLogger|[Link](../../Svc/PassiveConsoleTextLogger/docs/sdd.md)| +|Svc/Time|[Link](../../Svc/Time/docs/sdd.md)| +|Svc/Cycle|[Link](../../Svc/Cycle/docs/sdd.md)| +|Svc/LinuxTime|[Link](../../Svc/LinuxTime/docs/sdd.md)| +|Svc/ActiveLogger|[Link](../../Svc/ActiveLogger/docs/sdd.md)| +|Svc/Fatal|[Link](../../Svc/Fatal/docs/sdd.md)| + diff --git a/{{cookiecutter.deployment_slug}}/environment.ini b/{{cookiecutter.deployment_slug}}/environment.ini new file mode 100644 index 0000000..963b194 --- /dev/null +++ b/{{cookiecutter.deployment_slug}}/environment.ini @@ -0,0 +1,9 @@ +; The format for the environment file option is similar to settings.ini +; Each key in the file will be set as environmental +; variable for the project build. + +[environment] +; WIND_BASE=/opt/WindRiver/vxworks-6.7 +; LINK_BIN_PRE=/opt/sparc-wrs-vxworks/bin/ccsparc +; LINK_BIN_PRE_FLAGS=-r -nostdlib -Wl,-X +; LINK_BIN_PRE_TO=-o diff --git a/{{cookiecutter.deployment_dir_name}}/fplint.yml b/{{cookiecutter.deployment_slug}}/fplint.yml similarity index 100% rename from {{cookiecutter.deployment_dir_name}}/fplint.yml rename to {{cookiecutter.deployment_slug}}/fplint.yml diff --git a/{{cookiecutter.deployment_slug}}/gds.ini b/{{cookiecutter.deployment_slug}}/gds.ini new file mode 100644 index 0000000..055aa15 --- /dev/null +++ b/{{cookiecutter.deployment_slug}}/gds.ini @@ -0,0 +1,2 @@ +[misc] +test: test config value [IN FILE] diff --git a/{{cookiecutter.deployment_slug}}/settings.ini b/{{cookiecutter.deployment_slug}}/settings.ini new file mode 100644 index 0000000..5693e44 --- /dev/null +++ b/{{cookiecutter.deployment_slug}}/settings.ini @@ -0,0 +1,25 @@ +[fprime] + +; Path from this folder to the root of the project/repository +project_root: {{cookiecutter.deployment_path_to_project_root}} + +; Path from this folder to the F Prime framework root +framework_path: {{cookiecutter.deployment_path_to_fprime_framework}} + +; Colon separated list of paths to libraries +{% if cookiecutter.deployment_target_platform_support != "Arduino" %}; library_locations: {{cookiecutter.deployment_path_to_project_root}}/library1:{{cookiecutter.deployment_path_to_project_root}}/library2{% else -%} +library_locations: {{cookiecutter.deployment_path_to_project_root}}/fprime-arduino{% endif %} + +; Default target toolchain for this deployment +{% if cookiecutter.deployment_target_platform_support != "Arduino" %}; {% endif %}default_toolchain: {{cookiecutter.deployment_target_platform_support}} + +; Path to the file with custom environment variables +; environment_file: ./environment.ini + +; Autocoder constants specific to this deployment +ac_constants: ./config/AcConstants.ini + +; This directory contains all of the config hpp files if they +; are not located in the F Prime framework. It might be config +; or Cfg locally, the framework uses fprime/config or fprime/Fw/Cfg +; config_directory: config diff --git a/{{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/CMakeLists.txt b/{{cookiecutter.deployment_slug}}/{{cookiecutter.component_dir_name}}/CMakeLists.txt similarity index 100% rename from {{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/CMakeLists.txt rename to {{cookiecutter.deployment_slug}}/{{cookiecutter.component_dir_name}}/CMakeLists.txt diff --git a/{{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/README.md b/{{cookiecutter.deployment_slug}}/{{cookiecutter.component_dir_name}}/README.md similarity index 100% rename from {{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/README.md rename to {{cookiecutter.deployment_slug}}/{{cookiecutter.component_dir_name}}/README.md diff --git a/{{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/docs/.gitignore b/{{cookiecutter.deployment_slug}}/{{cookiecutter.component_dir_name}}/docs/.gitignore similarity index 100% rename from {{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/docs/.gitignore rename to {{cookiecutter.deployment_slug}}/{{cookiecutter.component_dir_name}}/docs/.gitignore diff --git a/{{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/docs/sdd.md b/{{cookiecutter.deployment_slug}}/{{cookiecutter.component_dir_name}}/docs/sdd.md similarity index 100% rename from {{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/docs/sdd.md rename to {{cookiecutter.deployment_slug}}/{{cookiecutter.component_dir_name}}/docs/sdd.md diff --git a/{{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/docs/{{cookiecutter.component_slug}}.md b/{{cookiecutter.deployment_slug}}/{{cookiecutter.component_dir_name}}/docs/{{cookiecutter.component_slug}}.md similarity index 100% rename from {{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/docs/{{cookiecutter.component_slug}}.md rename to {{cookiecutter.deployment_slug}}/{{cookiecutter.component_dir_name}}/docs/{{cookiecutter.component_slug}}.md diff --git a/{{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}ComponentAi.xml b/{{cookiecutter.deployment_slug}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}ComponentAi.xml similarity index 84% rename from {{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}ComponentAi.xml rename to {{cookiecutter.deployment_slug}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}ComponentAi.xml index 840309e..fbfaa38 100644 --- a/{{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}ComponentAi.xml +++ b/{{cookiecutter.deployment_slug}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}ComponentAi.xml @@ -4,7 +4,9 @@ Svc/Sched/SchedPortAi.xml Drv/GpioDriverPorts/GpioWritePortAi.xml - {{cookiecutter.component_short_description}} +{%- if cookiecutter.component_kind == 'active' %} + Svc/Ping/PingPortAi.xml +{%- endif %} @@ -16,6 +18,16 @@ +{%- if cookiecutter.component_kind == 'active' %} + + + Ping input port for health + + + + Ping output port for health + +{%- endif %} {%- if cookiecutter.deployment_parameter_support == "yes" %} diff --git a/{{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}AVR{{cookiecutter.component_impl_suffix}}.cpp b/{{cookiecutter.deployment_slug}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}AVR{{cookiecutter.component_impl_suffix}}.cpp similarity index 57% rename from {{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}AVR{{cookiecutter.component_impl_suffix}}.cpp rename to {{cookiecutter.deployment_slug}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}AVR{{cookiecutter.component_impl_suffix}}.cpp index ee1fb1d..bdc76b6 100644 --- a/{{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}AVR{{cookiecutter.component_impl_suffix}}.cpp +++ b/{{cookiecutter.deployment_slug}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}AVR{{cookiecutter.component_impl_suffix}}.cpp @@ -1,15 +1,22 @@ +{%- if (cookiecutter.deployment_path == '.') or (cookiecutter.deployment_path == '') %} + {%- set __deployment_path = '' -%} +{% else %} + {%- set __deployment_path = [cookiecutter.deployment_path, '/']|join() -%} +{%- endif -%} // ====================================================================== // \title {{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}AVR{{cookiecutter.component_impl_suffix}} // \author {{cookiecutter.full_name}} <{{cookiecutter.email}}> // \brief {{cookiecutter.component_short_description}} // ====================================================================== -#include <{{cookiecutter.deployment_path}}/{{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}{{cookiecutter.component_impl_suffix}}.hpp> +#include <{{__deployment_path}}{{cookiecutter.deployment_slug}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}{{cookiecutter.component_impl_suffix}}.hpp> #include "Fw/Types/BasicTypes.hpp" // #include -namespace {{cookiecutter.component_namespace}} { - +{% set namespaces = cookiecutter.component_namespace.split('::') -%} +{% for name in namespaces -%} +namespace {{ name }} { +{% endfor %} void {{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}{{cookiecutter.component_impl_suffix}} :: init( const NATIVE_INT_TYPE instance @@ -24,4 +31,6 @@ namespace {{cookiecutter.component_namespace}} { this->gpio_out(0, m_state); } -} // end namespace {{cookiecutter.component_namespace}} +{% for name in namespaces|reverse -%} +} // end namespace {{ name }} +{% endfor %} diff --git a/{{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}Arduino{{cookiecutter.component_impl_suffix}}.cpp b/{{cookiecutter.deployment_slug}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}Arduino{{cookiecutter.component_impl_suffix}}.cpp similarity index 57% rename from {{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}Arduino{{cookiecutter.component_impl_suffix}}.cpp rename to {{cookiecutter.deployment_slug}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}Arduino{{cookiecutter.component_impl_suffix}}.cpp index e100732..485756c 100644 --- a/{{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}Arduino{{cookiecutter.component_impl_suffix}}.cpp +++ b/{{cookiecutter.deployment_slug}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}Arduino{{cookiecutter.component_impl_suffix}}.cpp @@ -1,15 +1,22 @@ +{%- if (cookiecutter.deployment_path == '.') or (cookiecutter.deployment_path == '') %} + {%- set __deployment_path = '' -%} +{% else %} + {%- set __deployment_path = [cookiecutter.deployment_path, '/']|join() -%} +{%- endif -%} // ====================================================================== // \title {{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}Arduino{{cookiecutter.component_impl_suffix}}.cpp // \author {{cookiecutter.full_name}} <{{cookiecutter.email}}> // \brief {{cookiecutter.component_short_description}} // ====================================================================== -#include <{{cookiecutter.deployment_path}}/{{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}{{cookiecutter.component_impl_suffix}}.hpp> +#include <{{__deployment_path}}{{cookiecutter.deployment_slug}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}{{cookiecutter.component_impl_suffix}}.hpp> #include "Fw/Types/BasicTypes.hpp" // #include -namespace {{cookiecutter.component_namespace}} { - +{% set namespaces = cookiecutter.component_namespace.split('::') -%} +{% for name in namespaces -%} +namespace {{ name }} { +{% endfor %} void {{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}{{cookiecutter.component_impl_suffix}} :: init( const NATIVE_INT_TYPE instance @@ -24,4 +31,6 @@ namespace {{cookiecutter.component_namespace}} { this->gpio_out(0, m_state); } -} // end namespace {{cookiecutter.component_namespace}} +{% for name in namespaces|reverse -%} +} // end namespace {{ name }} +{% endfor %} diff --git a/{{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}Linux{{cookiecutter.component_impl_suffix}}.cpp b/{{cookiecutter.deployment_slug}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}Linux{{cookiecutter.component_impl_suffix}}.cpp similarity index 57% rename from {{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}Linux{{cookiecutter.component_impl_suffix}}.cpp rename to {{cookiecutter.deployment_slug}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}Linux{{cookiecutter.component_impl_suffix}}.cpp index 4583054..ceb6449 100644 --- a/{{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}Linux{{cookiecutter.component_impl_suffix}}.cpp +++ b/{{cookiecutter.deployment_slug}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}Linux{{cookiecutter.component_impl_suffix}}.cpp @@ -1,15 +1,22 @@ +{%- if (cookiecutter.deployment_path == '.') or (cookiecutter.deployment_path == '') %} + {%- set __deployment_path = '' -%} +{% else %} + {%- set __deployment_path = [cookiecutter.deployment_path, '/']|join() -%} +{%- endif -%} // ====================================================================== // \title {{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}Linux{{cookiecutter.component_impl_suffix}}.cpp // \author {{cookiecutter.full_name}} <{{cookiecutter.email}}> // \brief {{cookiecutter.component_short_description}} // ====================================================================== -#include <{{cookiecutter.deployment_path}}/{{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}{{cookiecutter.component_impl_suffix}}.hpp> +#include <{{__deployment_path}}{{cookiecutter.deployment_slug}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}{{cookiecutter.component_impl_suffix}}.hpp> #include "Fw/Types/BasicTypes.hpp" // #include -namespace {{cookiecutter.component_namespace}} { - +{% set namespaces = cookiecutter.component_namespace.split('::') -%} +{% for name in namespaces -%} +namespace {{ name }} { +{% endfor %} void {{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}{{cookiecutter.component_impl_suffix}} :: init( const NATIVE_INT_TYPE instance @@ -24,4 +31,6 @@ namespace {{cookiecutter.component_namespace}} { this->gpio_out(0, m_state); } -} // end namespace {{cookiecutter.component_namespace}} +{% for name in namespaces|reverse -%} +} // end namespace {{ name }} +{% endfor %} diff --git a/{{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}{{cookiecutter.component_explicit_common}}{{cookiecutter.component_impl_suffix}}.cpp b/{{cookiecutter.deployment_slug}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}{{cookiecutter.component_explicit_common}}{{cookiecutter.component_impl_suffix}}.cpp similarity index 77% rename from {{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}{{cookiecutter.component_explicit_common}}{{cookiecutter.component_impl_suffix}}.cpp rename to {{cookiecutter.deployment_slug}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}{{cookiecutter.component_explicit_common}}{{cookiecutter.component_impl_suffix}}.cpp index 3bb568b..380ec54 100644 --- a/{{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}{{cookiecutter.component_explicit_common}}{{cookiecutter.component_impl_suffix}}.cpp +++ b/{{cookiecutter.deployment_slug}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}{{cookiecutter.component_explicit_common}}{{cookiecutter.component_impl_suffix}}.cpp @@ -1,3 +1,8 @@ +{%- if (cookiecutter.deployment_path == '.') or (cookiecutter.deployment_path == '') %} + {%- set __deployment_path = '' -%} +{% else %} + {%- set __deployment_path = [cookiecutter.deployment_path, '/']|join() -%} +{%- endif -%} // ====================================================================== // \title {{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}{{cookiecutter.component_explicit_common}}{{cookiecutter.component_impl_suffix}}.cpp // \author {{cookiecutter.full_name}} <{{cookiecutter.email}}> @@ -5,11 +10,13 @@ // ====================================================================== -#include <{{cookiecutter.deployment_path}}/{{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}{{cookiecutter.component_impl_suffix}}.hpp> +#include <{{__deployment_path}}{{cookiecutter.deployment_slug}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}{{cookiecutter.component_impl_suffix}}.hpp> #include "Fw/Types/BasicTypes.hpp" -namespace {{cookiecutter.component_namespace}} { - +{% set namespaces = cookiecutter.component_namespace.split('::') -%} +{% for name in namespaces -%} +namespace {{ name }} { +{% endfor %} // ---------------------------------------------------------------------- // Construction, initialization, and destruction // ---------------------------------------------------------------------- @@ -67,7 +74,9 @@ namespace {{cookiecutter.component_namespace}} { {%- endif %} blink(); m_state = !m_state; +{%- if cookiecutter.deployment_parameter_support == "yes" %} m_blinkDecimateCntrl = 0; +{%- endif %} if(m_state) { @@ -114,4 +123,16 @@ namespace {{cookiecutter.component_namespace}} { } } {% endif %} -} // end namespace {{cookiecutter.component_namespace}} + +{%- if cookiecutter.component_kind == 'active' %} + // ---------------------------------------------------------------------- + // Health Pinger Handler + // ---------------------------------------------------------------------- + void {{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}{{cookiecutter.component_impl_suffix}}::pingIn_handler(NATIVE_INT_TYPE portNum, U32 key) { + // return the key to health + this->pingOut_out(0,key); + } +{%- endif %} +{% for name in namespaces|reverse -%} +} // end namespace {{ name }} +{% endfor %} diff --git a/{{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}{{cookiecutter.component_impl_suffix}}.hpp b/{{cookiecutter.deployment_slug}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}{{cookiecutter.component_impl_suffix}}.hpp similarity index 76% rename from {{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}{{cookiecutter.component_impl_suffix}}.hpp rename to {{cookiecutter.deployment_slug}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}{{cookiecutter.component_impl_suffix}}.hpp index 4e3cded..73ec5c9 100644 --- a/{{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}{{cookiecutter.component_impl_suffix}}.hpp +++ b/{{cookiecutter.deployment_slug}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}{{cookiecutter.component_impl_suffix}}.hpp @@ -1,3 +1,8 @@ +{%- if (cookiecutter.deployment_path == '.') or (cookiecutter.deployment_path == '') %} + {%- set __deployment_path = '' -%} +{% else %} + {%- set __deployment_path = [cookiecutter.deployment_path, '/']|join() -%} +{%- endif -%} // ====================================================================== // \title {{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}{{cookiecutter.component_impl_suffix}}.hpp // \author {{cookiecutter.full_name}} <{{cookiecutter.email}}> @@ -7,10 +12,12 @@ #ifndef {{cookiecutter.component_slug}}Component_HPP #define {{cookiecutter.component_slug}}Component_HPP -#include "{{cookiecutter.deployment_path}}/{{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}ComponentAc.hpp" - -namespace {{cookiecutter.component_namespace}} { +#include "{{__deployment_path}}{{cookiecutter.deployment_slug}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}ComponentAc.hpp" +{% set namespaces = cookiecutter.component_namespace.split('::') -%} +{% for name in namespaces -%} +namespace {{ name }} { +{% endfor %} class {{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}{{cookiecutter.component_impl_suffix}} : public {{cookiecutter.component_slug}}ComponentBase { @@ -66,6 +73,18 @@ namespace {{cookiecutter.component_namespace}} { const NATIVE_INT_TYPE portNum, /*!< The port number*/ NATIVE_UINT_TYPE context /*!< The call order*/ ); + +{%- if cookiecutter.component_kind == 'active' %} + //! \brief Input ping port handler + //! + //! This port is called by the health task to verify task aliveness + //! + //! \param portNum incoming port call. For this class, should always be zero + //! \param key value returned to health task to verify round trip + + void pingIn_handler(NATIVE_INT_TYPE portNum, U32 key); +{%- endif %} + {%- if cookiecutter.deployment_parameter_support == "yes" %} //! parameter update notification //! @@ -78,6 +97,7 @@ namespace {{cookiecutter.component_namespace}} { {%- endif %} }; -} // end namespace {{cookiecutter.component_namespace}} - +{% for name in namespaces|reverse -%} +} // end namespace {{ name }} +{% endfor %} #endif // end {{cookiecutter.component_slug}}Component_HPP