Skip to content

Commit

Permalink
Adding GDS development guide (#2577)
Browse files Browse the repository at this point in the history
* Adding GDS development guide

* Review comments

* sp
  • Loading branch information
LeStarch authored Mar 12, 2024
1 parent 8fe3022 commit a73bff2
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 0 deletions.
164 changes: 164 additions & 0 deletions docs/HowTo/develop-gds-plugins.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
# How-To: F´ GDS Plugin Development

This guide will walk through the process of developing GDS plugins. GDS plugins allow users to select an implementation
for key functions within the GDS. These selections allow users to tailor the behavior of the GDS without affecting the
top-level flow of data throughout the system.

## Plugin System Design

GDS plugins are built on top of the [pluggy](https://pluggy.readthedocs.io/en/stable/). This means that each implementor
of a GDS plugin must define a function for behavior and mark that function with an implementation decorator.

The GDS defines several categories of plugins that the user may implement:

1. Framing plugins: used to change the framing of uplink and downlink packets
2. Communication plugins: used to change the interface for reading bytes from the spacecraft

Plugins should define a function called `register_<category>_plugin` that would return a concrete subclass of the
category's virtual-class that performs the work of the plugin. These classes may define `get_arguments`, `get_name`,
and `check_arguments` functions used by the plugin system to provide and validate arguments from the CLI.

This guide will walk through the development of a framing plugin.

## Developing a Framing Plugin

The first step in developing a framing plugin is to determine the function that must be implemented and the class that
must be derived to develop the plugin. This information is available in
[`fprime_gds.plugin.definitions`](https://github.com/fprime-community/fprime-gds/blob/devel/src/fprime_gds/plugin/definitions.py).

For the case of a `framing` plugin, the `register_framing_plugin` function contains the needed information: our function
must be named `register_framing_plugin` and return a concrete subclass of `FramerDeframer`.

```python
@gds_plugin_specification
def register_framing_plugin() -> Type["FramerDeframer"]:
```

### Basic Plugin Skeleton

Most GDS plugins define a class that inherits from the necessary virtual-class and implements virtual functions. These
classes also define a properly decorated class method for the registration function, and may define the other class
methods used for CLI interaction.

A basic framing plugin skeleton would thus look like:
**`src/my_plugin.py`:**
```python
from fprime_gds.common.communication.framing import FramerDeframer
from fprime_gds.plugin.definitions import gds_plugin_implementation

class MyPlugin(FramerDeframer):
# TODO: implement virtual functions
@classmethod
def get_name(cls):
""" Name of this implementation provided to CLI """
return "my-plugin"

@classmethod
def get_arguments(cls):
""" Arguments to request from the CLI """
return {}

@classmethod
def check_arguments(cls):
""" Check arguments from the CLI """
pass

@classmethod
@gds_plugin_implementation
def register_framing_plugin(cls):
""" Register the MyPlugin plugin """
return cls
```

### Implementing Virtual Functions

Each plugin virtual-class (e.g. `FramerDeframer`) has a set of virtual methods that plugin implementors *must* implement
in order to support the plugin implementation. These functions are marked as ` @abc.abstractmethod` and can be found in
the virtual class definition.

[FramerDeframer virtual functions](https://github.com/fprime-community/fprime-gds/blob/devel/src/fprime_gds/common/communication/framing.py#L29-L51)
consist of a `frame` and `deframe` method. This guide will use no-op functions.

**`src/my_plugin.py`:**
```python
from fprime_gds.common.communication.framing import FramerDeframer
from fprime_gds.plugin.definitions import gds_plugin_implementation

class MyPlugin(FramerDeframer):

def frame(self, data):
""" Frames data by no-op """
return b"" + data # Forces a copy

def deframe(self, data, no_copy=False):
""" Deframe data by no-op """
if no_copy:
return data
return b"" + data # Forces a copy

@classmethod
def get_name(cls):
""" Name of this implementation provided to CLI """
return "my-plugin"

@classmethod
def get_arguments(cls):
""" Arguments to request from the CLI """
return {}

@classmethod
def check_arguments(cls):
""" Check arguments from the CLI """
pass

@classmethod
@gds_plugin_implementation
def register_framing_plugin(cls):
""" Register the MyPlugin plugin """
return cls
```

This is the basic implementation of a no-argument framing plugin. Next, this guide will cover how to integrate this
plugin via python packaging. Then arguments will be covered.

### Distributing Plugins

Plugins are supplied as python packages with an entrypoint used to load the plugin. In the root of the package a basic
python package will need to be configured. This consists of two files: pyproject.toml representing the package, and
setup.py for backwards compatibility.

The project structure should look like:
```
src/my_plugin.py
pyproject.toml
setup.py
```

A sample pyproject.toml file would look like:

```toml
[build-system]
requires = ["setuptools", "setuptools_scm[toml]>=6.2", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "fprime-gds-my-plugin"
dynamic = ["version"]
dependencies = [
"pluggy>=1.3.0",
"fprime-gds>=3.4.4"
]

[project.entry_points."fprime_gds"]
my_plugin = "my_plugin:MyPlugin"

[tool.setuptools_scm]
```

A sample `setup.py` would look like:
```python
from setuptools import setup

# Configuration is in pyproject.toml
setup()
```
9 changes: 9 additions & 0 deletions docs/HowTo/general.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# F´ How-To Guides

This section of the documentation captures how-to guides for various F´ development tasks!


| Table of Contents |
|--------------------------------------------|
| [F´ GDS Plugins](./develop-gds-plugins.md) |

4 changes: 4 additions & 0 deletions docs/_includes/toc.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,7 @@
<li><a href="/fprime/Design/package-implementations.html">Package Implementations</a></li>
<li><a href="/fprime/Design/fpp-json-dict.html">FPP JSON Dictionary Specification</a></li>
</ul>
<h4><a href="/fprime/Design/general.html">How-To Guides</a></h4>
<ul>
<li><a href="/fprime/HowTo/develop-gds-plugins.html">F´ GDS Plugin Development</a></li>
</ul>
1 change: 1 addition & 0 deletions docs/latest.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ This is the documentation for the latest F´ framework. It is kept consistent wi
| Tutorials | [Tutorials](./Tutorials/README.md) |
| User Guide | [User Guide](./UsersGuide/guide.md) |
| Design and Philosophy | [Design](./Design/general.md) |
| How-To Guides | [How-To](./How-To/general.md) |

0 comments on commit a73bff2

Please sign in to comment.