Skip to content

Commit

Permalink
Significant update to get docs in a usable state, pull in updates fro…
Browse files Browse the repository at this point in the history
…m the component template, and fix a handful of bugs.

* Full revamp of documentation.

* Pull in updates from the component template.

* Fix active component definition.

* Add selectable multi-platform support for the exerciser component.

* Numerous spelling fixes.

* Move from ``assembly`` to ``slug`` for deployment name.

* Update template to use ``cookiecutter`` plugin ``slugify``.

* Add ``.cookiecutterrc`` file to make regeneration of the template easier.

* Fix bug where compiling without ``FW_OBJECT_NAMES == 1`` fails to provide a valid constructor, instead calling the Base component.

* Fix component path definition to F Prime root.

Closes #3, closes #4, and closes #5.
  • Loading branch information
SterlingPeet committed Oct 6, 2020
1 parent 572ebe6 commit 7fc90d5
Show file tree
Hide file tree
Showing 23 changed files with 377 additions and 228 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Changelog

Use cookiecutter's ``--checkout`` options to use a specific version.

v1.0 (2020-08-15)
v1.0 (2020-10-06)
-----------------

* Initial Release
117 changes: 91 additions & 26 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ 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:** Beta version, the documentation is not up to date yet (working on it, but needed to crank out some test deployments internally. Sorry!).

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.
Expand Down Expand Up @@ -67,41 +65,89 @@ You will be asked for these fields:

Can be set in your ``~/.cookiecutterrc`` config file.

* - ``component_name``
* - ``deployment_display_name``
- .. code:: python

"My Example"
- The printed name of this component for documentation and strings. It should be concise and convey the purpose of the component.
- The printed name of this deployment for documentation and strings. It should be concise and convey the purpose of the deployment.

* - ``deployment_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.

* - ``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.

* - ``path_to_fprime_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.

* - ``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.

* - ``short_description``
* - ``component_short_description``
- .. code:: python

"An example component [...]"
- One line description of the project (used in headers and comments).
- 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_class_name``
* - ``component_slug``
- .. code:: python

"MyExampleComponent"
- The name of this component's class in the code. It should be ``CamelCase``. The autocoder requires the suffix ``Component`` to function properly.
"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_suffix``
* - ``component_impl_suffix``
- .. code:: python

""
- If preferred, the files and classes can be appended with the suffix ``Impl``.
"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.

* - ``component_path``
* - ``component_path_to_fprime_root``
- .. code:: python

"Prjct/Grp"
- This is the path from the F Prime root to the current directory, not including the component's folder.
"../../.."
- 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).

* - ``component_namespace``
- .. code:: python
Expand All @@ -112,8 +158,32 @@ You will be asked for these fields:
* - ``component_kind``
- .. code:: python

"active"
- You can choose and active or passive component type. If you change your mind, is it set in the Autocoder input file.
"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"
- This is the variable name given to the instantiation of your component in the topology.

* - ``startup_arduino_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``
- .. code:: python

"Serial"
- This is the ``Arduino`` stream where the debug statements for the main deployment will print.

* - ``license``
- .. code:: python
Expand All @@ -127,24 +197,19 @@ You will be asked for these fields:

What license to pick? https://choosealicense.com/

You will still need to run ``fprime-util`` to generate the templates from your autocoder input file.
You should now have a basic deployment that can be compiled and run.

This requires your component to be included in a deployment.
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 can edit your ``MyExampleComponentAi.xml`` file define the component to your liking, and generate the implementation boilerplate::

cd MyExample
fprime-util impl -b {path/to/your/deployment}

Next, copy the ``-template`` code contents into your ``.hpp`` and ``.cpp`` files.
Try not to overwrite the freshly generated comments at the top!
Now you should be able to run the executable from the build folder.


Changelog
Expand Down
19 changes: 11 additions & 8 deletions cookiecutter.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,22 @@
"email": "[email protected]",
"deployment_display_name": "My Example",
"dep_short_description": "Example deployment for F Prime FSW framework.",
"deployment_assembly": "{{ cookiecutter.deployment_display_name|replace(' ','')|replace('-','')|replace('_','') }}",
"deployment_dir_name": "{{ cookiecutter.deployment_assembly }}",
"deployment_slug": "{{ cookiecutter.deployment_display_name|slugify(separator='', lowercase=False) }}",
"deployment_dir_name": "{{ cookiecutter.deployment_slug }}",
"deployment_path": "example/path",
"path_to_fprime_root": "../..",
"component_display_name": "Led Blinker",
"component_name": "Led Blinker",
"component_short_description": "Example component to support {{ cookiecutter.deployment_display_name }} deployment.",
"component_name": "{{ cookiecutter.component_display_name|replace(' ','')|replace('-','')|replace('_','') }}",
"component_dir_name": "{{ cookiecutter.component_name }}",
"component_slug": "{{ cookiecutter.component_name|slugify(separator='', lowercase=False) }}",
"component_dir_name": "{{ cookiecutter.component_slug }}",
"component_explicit_component_suffix": ["Component", ""],
"component_explicit_common": ["", "Common"],
"component_suffix": ["", "Impl"],
"component_impl_suffix": ["", "Impl"],
"component_path_to_fprime_root": "{{ cookiecutter.path_to_fprime_root }}/..",
"component_namespace": "{{ cookiecutter.deployment_path|replace('/','::')|replace('\\\\','::') }}",
"component_kind": ["active", "passive"],
"component_instance_name": "{{ cookiecutter.component_name|replace(' ','_')|replace('-','_') }}",
"component_kind": ["passive", "active"],
"component_multiplatform_support": ["no", "yes"],
"component_instance_name": "{{ cookiecutter.component_slug|lower }}",
"startup_delay_msec": ["2000", "1000", "500", "0"],
"startup_arduino_led_flash": ["yes", "no"],
"arduino_log_stream": ["Serial", "Serial1", "Serial2", "Serial3"],
Expand Down
33 changes: 16 additions & 17 deletions hooks/post_gen_project.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import print_function

import datetime
# import os
import os
# import shutil
# import subprocess
# import sys
Expand Down Expand Up @@ -29,6 +29,13 @@ def replace_contents(filename, what, replacement):
replace_contents(join('{{ cookiecutter.component_dir_name }}', 'docs', 'sdd.md'), '<TODAY>', today.strftime("%m/%d/%Y"))
replace_contents('README.md', '<TODAY>', today.strftime("%m/%d/%Y"))

{% if cookiecutter.component_multiplatform_support == "no" %}
mp_str = '{{cookiecutter.component_dir_name}}/{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}{}{{cookiecutter.component_impl_suffix}}.cpp'
rm_list = ['Arduino', 'AVR', 'Linux']
for i in rm_list:
os.unlink(mp_str.format(i))
{% endif %}

# /{/% if cookiecutter.sphinx_docs == "no" %}
# shutil.rmtree('docs')
# /{/% endif %}
Expand All @@ -53,29 +60,21 @@ def replace_contents(filename, what, replacement):
################################################################################
You will still need to run `fprime-util` to generate the templates
from your autocoder input file.
You should now have a basic deployment that can be compiled and run.
This requires your component to be included in a deployment. This
can be done by adding a line like this, near the bottom of the
deployment's CMakeLists.txt file:
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}/../{{ cookiecutter.deployment_path }}/{{ cookiecutter.component_dir_name }}/{{ cookiecutter.component_dir_name }}")
add_fprime_subdirectory("${CMAKE_CURRENT_LIST_DIR}/../{{ cookiecutter.deployment_path }}/{{ cookiecutter.component_dir_name }}")
Then you need to (possibly purge) and generate the new cmake config
in that deployment:
in the deployment:
fprime-util generate
fprime-util build
Now you can edit your {{ cookiecutter.component_name }}ComponentAi.xml file
define the component to your liking, and generate the implementation
boilerplate:
cd {{ cookiecutter.component_dir_name }}
fprime-util impl -b {path/to/your/deployment}
Next, copy the `-template` code contents into your .hpp and .cpp files.
Try not to overwrite the freshly generated comments at the top!
Now you should be able to run the executable from the build folder.
""")

20 changes: 20 additions & 0 deletions {{cookiecutter.deployment_dir_name}}/.cookiecutterrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# This file exists so you can easily regenerate your project.
#
# `cookiepatcher` is a convenient shim around `cookiecutter`
# for regenerating projects (it will generate a .cookiecutterrc
# automatically for any template). To use it:
#
# pip install cookiepatcher
# cookiepatcher gh:sterlingpeet/cookiecutter-fprime-deployment {{cookiecutter.deployment_dir_name}}
#
# 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

default_context:
{% for key, value in cookiecutter.items()|sort %}
{{ "{0:26}".format(key + ":") }} {{ "{0!r}".format(value).strip("u") }}
{%- endfor %}
2 changes: 1 addition & 1 deletion {{cookiecutter.deployment_dir_name}}/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
####
# {{cookiecutter.deployment_display_name}} Deployment:
#
# This sets up the {{cookiecutter.deployment_display_name}} deployment using CMake
# This sets up the {{cookiecutter.deployment_display_name}} deployment using CMake
# for use with F prime.
#
# This file has several sections.
Expand Down
16 changes: 8 additions & 8 deletions {{cookiecutter.deployment_dir_name}}/Top/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@
# Note: using PROJECT_NAME as EXECUTABLE_NAME
####
set(SOURCE_FILES
"${CMAKE_CURRENT_LIST_DIR}/{{cookiecutter.deployment_assembly}}TopologyAppAi.xml"
"${CMAKE_CURRENT_LIST_DIR}/Main.cpp"
"${CMAKE_CURRENT_LIST_DIR}/Topology.cpp"
"${CMAKE_CURRENT_LIST_DIR}/{{cookiecutter.deployment_slug}}TopologyAppAi.xml"
"${CMAKE_CURRENT_LIST_DIR}/Main.cpp"
"${CMAKE_CURRENT_LIST_DIR}/Topology.cpp"
)
# Note: supply non-explicit dependencies here
set(MOD_DEPS
Fw/Logger
# Svc/GroundInterface
Svc/LinuxTime
Os
Os/Baremetal/TaskRunner
Fw/Logger
# Svc/GroundInterface
Svc/LinuxTime
Os
Os/Baremetal/TaskRunner
)

register_fprime_executable()
Expand Down
19 changes: 7 additions & 12 deletions {{cookiecutter.deployment_dir_name}}/Top/Components.hpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
#ifndef __{{cookiecutter.deployment_assembly|upper}}_COMPONENTS_HEADER__
#define __{{cookiecutter.deployment_assembly|upper}}_COMPONENTS_HEADER__
#ifndef __{{cookiecutter.deployment_slug|upper}}_COMPONENTS_HEADER__
#define __{{cookiecutter.deployment_slug|upper}}_COMPONENTS_HEADER__

#define COMM_SERIAL

void construct{{cookiecutter.deployment_assembly}}Architecture(void);
void construct{{cookiecutter.deployment_slug}}Architecture(void);
void exitTasks(void);
void constructApp();

Expand All @@ -13,17 +11,14 @@ void constructApp();
#include <Svc/RateGroupDriver/RateGroupDriverImpl.hpp>

#include <ATmega/HardwareRateDriver/HardwareRateDriver.hpp>
#include <{{cookiecutter.deployment_path}}/{{cookiecutter.deployment_dir_name}}/{{cookiecutter.component_dir_name}}/{{cookiecutter.component_name}}Component{{cookiecutter.component_suffix}}.hpp>
#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>

// Core components
extern Drv::ATmegaGpioDriverComponentImpl ledGpio;
extern Svc::RateGroupDriverImpl rateGroupDriverComp;
// extern Svc::ActiveRateGroupImpl rateGroup1HzComp;
extern Svc::ActiveRateGroupImpl rateGroup10HzComp;
extern Arduino::HardwareRateDriver hardwareRateDriver;
extern {{cookiecutter.component_namespace}}::{{cookiecutter.component_name}}Component{{cookiecutter.component_suffix}} {{cookiecutter.component_instance_name}};

// #ifdef COMM_SERIAL
// extern Arduino::SerialDriverComponentImpl comm;
// #endif
extern {{cookiecutter.component_namespace}}::{{cookiecutter.component_slug}}{{cookiecutter.component_explicit_component_suffix}}{{cookiecutter.component_impl_suffix}} {{cookiecutter.component_instance_name}};

#endif // end __{{cookiecutter.deployment_assembly|upper}}_COMPONENTS_HEADER__
#endif // end __{{cookiecutter.deployment_slug|upper}}_COMPONENTS_HEADER__
Loading

0 comments on commit 7fc90d5

Please sign in to comment.