Creating a Flight Software Project
This guide will show you the process of creating a flight software project using FSDK. We will cover setting up a component library project, defining and generating Component Types, and building a Deployment.
Before You Begin
The GEN1_ROOT environment variable should be set to the FSDK root directory. This is used by codegen to locate the necessary files and directories.
Open a terminal in the FSDK root directory and navigate to the Documentation/Tutorials directory using the following command.
cd Documentation/Tutorials
Execute the script to set the GEN1_ROOT environment variable.
. set_gen1_root.sh
Echo the GEN1_ROOT environment variable to confirm it has been set to the correct directory.
echo $GEN1_ROOT
|
If this command fails, check that |
component library
A component library is needed to store Components. This can be done using the codegen CLI tooling.
Create a New component library
Open a new terminal window in the fsdk_demo directory and execute the following command:
codegen library new components
This command will generate a new directory called components in your project directory.
Your project directory structure should now look like this:
Show the project directory structure
fsdk_demo
└── components
├── Makefile
├── config
│ └── project.mk
├── inc
├── src
└── test
└── src
└── common
└── deployment
└── Deployment.c
Update the component library Dependencies
You will need to link the component library's configuration file to include FSDK dependencies.
Update the project.mk file located at fsdk_demo/components/config/project.mk to include the app and framework directories as dependencies.
- DEPEND_DIRS = ../app ../framework
+ DEPEND_DIRS = $(OBSW_ROOT)/app $(OBSW_ROOT)/framework
Change the log level for our component library to 3. This will log more information to the console.
- CPPFLAGS += -DUTIL_LOG_LEVEL=2
+ CPPFLAGS += -DUTIL_LOG_LEVEL=3
Components
Components are the building blocks of FSDK. Components can be anything from a simple data store to a complex control system. A machine-readable model for each Component is created in XML - this is known as a Component Type. Component Types describe the Component's functionality, interfaces, and dependencies.
Creating a New Component Type
It is a matter of personal preference where Components are created. FSDK doesn’t enforce a specific location for Components.
It may be more fitting to create a new Component in the OBSW/Source/app directory, the OBSW/Source/framework directory, the project directory, or even in a separate directory outside of the FSDK archive.
|
The The Refer to the Directory Structure documentation for more information about the |
To keep things simple, we will create a Component in the component library we created earlier.
Execute the following codegen command to create a new Component Type called MessagePrinter within the component library:
codegen componenttype new components -n MessagePrinter
The project directory has been updated to include the new componentType.xml definition file.
Show the project directory structure
fsdk_demo
└── components
├── Makefile
├── config
│ └── project.mk
├── inc
│ └── MessagePrinter
│ └── componentType.xml
├── src
└── test
└── src
└── common
└── deployment
└── Deployment.c
|
Refer to the Component Type Definition documentation for information about how to add elements to a Component Type. |
Generating a Component
After you have finished adding elements to your componentType.xml file, you can generate it and create the associated implementation code.
Execute the following codegen command to generate the skeleton code for the MessagePrinter Component Type:
codegen componenttype generate components -n MessagePrinter
codegen generates the required header and source files required to deploy the Component. Your project directory should look something like this:
Show the project directory structure
fsdk_demo
└── components
├── Makefile
├── config
│ └── project.mk
├── inc
│ └── MessagePrinter
│ ├── componentType.xml
│ ├── MessagePrinter.h
│ ├── MessagePrinter_config.h
│ ├── MessagePrinter_Container.h
│ ├── MessagePrinter_Container_package.h
│ ├── MessagePrinter_sizes.h
│ └── MessagePrinter_types.h
├── src
│ └── MessagePrinter
│ ├── MessagePrinter.c
│ └── MessagePrinter_Container.c
└── test
└── src
└── common
└── deployment
└── Deployment.c
|
Additional files may be present if you added elements to the Ensure the implementation within Continue to the next section if you didn’t add any elements into the |
Deployments
Deployments are collections of Components that are connected together to form runnable flight software. From the Deployment, we are able to configure our component instances and pass initialisation data to them.
Execute the following codegen command in your project directory:
codegen deployment new demo
You will see that codegen has created a new Deployment directory within the project called demo.
Show the project directory structure
fsdk_demo
└── components
│ ├── Makefile
│ ├── config
│ │ └── project.mk
│ ├── inc
│ │ └── MessagePrinter
│ │ ├── componentType.xml
│ │ ├── MessagePrinter.h
│ │ ├── MessagePrinter_config.h
│ │ ├── MessagePrinter_Container.h
│ │ ├── MessagePrinter_Container_package.h
│ │ ├── MessagePrinter_sizes.h
│ │ └── MessagePrinter_types.h
│ ├── src
│ │ └── MessagePrinter
│ │ ├── MessagePrinter.c
│ │ └── MessagePrinter_Container.c
│ └── test
│ └── src
│ └── common
│ └── deployment
│ └── Deployment.c
└── demo
├── config
│ └── project.mk
├── deployment.xml
├── inc
├── Makefile
└── src
We need to add the FSDK dependencies to our project.mk file to allow the Deployment to locate the relevant FSDK component libraries.
Update the project.mk file located in your Deployment directory.
- DEPEND_DIRS = ../app ../framework
+ DEPEND_DIRS = $(OBSW_ROOT)/app $(OBSW_ROOT)/framework ../components
|
The Deployment needs to reference the |
Again, change the log level to 3.
- CPPFLAGS += -DUTIL_LOG_LEVEL=2
+ CPPFLAGS += -DUTIL_LOG_LEVEL=3
Creating a new Deployment
Similar to Components, a machine-readable model for each Deployment is created in XML.
We can configure the Deployment by editing the deployment.xml file. This file defines the structure of the Deployment and describes which Components will be used and how they talk to one another.
To communicate with the tmtclab ground software, the deployment.xml file needs module definitions which detail how the flight software should respond to telecommands and create/send telemetry data.
We recommend you re-use a working deployment.xml which contains the necessary communication stack declarations used for basic telecomuniction. We can use the demo_linux sample provided below Deployment for this.
|
The |
Edit the existing deployment.xml file with one that contains our MessagePrinter Component Type and the basic communication stack definitions. Replace the contents of the file with the following:
Show the modified demo_linux deployment.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--
This file describes the demo_linux deployment.
Copyright (c) Bright Ascension Ltd, 2012
Licensed Material - Property of Bright Ascension Ltd
-->
<ModelElement xmlns="http://www.brightascension.com/schemas/gen1/model"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Deployment name="demo">
<Description>
This is an example deployment of GenerationOne for Linux.
</Description>
<!-- Component type imports -->
<Import>
<!-- The component types used by this deployment -->
<Use type="Version" />
<Use type="storage.Storage" />
<Use type="ConfigManager" />
<Use type="io.driver.OSTime" />
<Use type="storage.config.FileConfigStore" />
<Use type="storage.fs.PosixFS" />
<Use type="storage.FileStorageProvider" />
<Use type="storage.FileSystemManager" />
<Use type="event.EventDispatcher" />
<Use type="io.net.tcp.TCPClient" />
<Use type="io.net.PacketStream" />
<Use type="io.net.SpacePacket" />
<Use type="io.net.pus.PUSCore" />
<Use type="io.net.pus.PUSHK" />
<Use type="io.net.pus.PUSEvent" />
<Use type="io.net.pus.PUSLDT" />
<Use type="io.net.pus.PUSAMS" />
<Use type="io.net.CFDP" />
<Use type="tmtc.TMBeacon" />
<Use type="tmtc.TMDebug" />
<Use type="tmtc.TMTCEvent" />
<Use type="io.net.ParamTransfer" />
<Use type="component.AAS.AASTarget" />
<Use type="component.PAS.PASTarget" />
<Use type="subsys.OBT" />
<Use type="Dummy" />
<Use type="logging.CommandLogger" />
<Use type="logging.EventLogger" />
<Use type="DataPool" />
<Use type="Sampler" />
<Use type="Aggregator" />
<Use type="Monitor" />
<Use type="logging.DataLogger" />
<Use type="auto.EventAction" />
<Use type="auto.TimeAction" />
<Use type="auto.PeriodicAction" />
<Use type="MessagePrinter" />
</Import>
<!-- Component deployment -->
<Deploy>
<!-- Component Groups -->
<ComponentGroup name="cdh">
<Description>
Command and data handling group.
</Description>
<Documentation>
<Text>
Contains the components used to assist with the function of the
spacecraft such as loggers, autonomous components and TMTC components.
</Text>
</Documentation>
</ComponentGroup>
<ComponentGroup name="cdh.logging">
<Description>
Group containing the logging components.
</Description>
<Documentation>
<Markdown>
For demo_linux, the included logging components are:
- BaseLogger (used for logging data)
- EventLogger (used to log raised events)
- TCLogger (used for logging Telecommands)
</Markdown>
</Documentation>
</ComponentGroup>
<ComponentGroup name="cdh.tmtc">
<Description>
Group containing the components that handle TMTC.
</Description>
<Documentation>
<Text>
TMTC Components are used to connect the comms stack to the components
so that action/parameter/event interactions can occur.
</Text>
</Documentation>
</ComponentGroup>
<ComponentGroup name="comms">
<Description>
The communications stack group.
</Description>
<Documentation>
<Markdown>
Contains the components used to form the comms stack.
For demo_linux, this includes:
- TCP Client
- PacketStream
- SpacePacket
- PUS components
</Markdown>
</Documentation>
</ComponentGroup>
<ComponentGroup name="comms.pus">
<Description>
Group containing the PUS components.
</Description>
<Documentation>
<Text>
PUS components are used to provide functionality that corresponds to
the PUS standard. See ECSS-E-70-41A.
</Text>
</Documentation>
</ComponentGroup>
<ComponentGroup name="comms.services">
<Description>
Group containing the service proxy components.
</Description>
<Documentation>
<Text>
Service proxies allow services to be provided to external systems and
allow this deployment to access services provided externally.
</Text>
</Documentation>
</ComponentGroup>
<ComponentGroup name="core">
<Description>
Group containing the core components for the deployment.
</Description>
<Documentation>
<Text>
Contains components integral to the functionality of the OBSW.
</Text>
</Documentation>
</ComponentGroup>
<ComponentGroup name="platform">
<Description>
Group containing the components integral to the platform being deployed.
</Description>
<Documentation>
<Text>
For demo_linx, no platform specific hardware or software is required,
however DummySubsys can be used to simulate TMTC with a component.
</Text>
</Documentation>
</ComponentGroup>
<!-- Component Instances -->
<Component name="Version" type="Version" />
<Component name="core.Storage" type="storage.Storage" />
<Component name="core.ConfigurationManager" type="ConfigManager" />
<Component name="core.Time" type="io.driver.OSTime" />
<Component name="core.OBT" type="subsys.OBT">
<Connections>
<Services>
<Service name="time" component="core.Time" service="time" />
</Services>
</Connections>
</Component>
<Component name="core.FileSystem" type="storage.fs.PosixFS" />
<Component name="core.FileConfigStore" type="storage.config.FileConfigStore">
<Connections>
<Services>
<Service name="fs" component="core.FileSystem" service="fs" />
</Services>
</Connections>
</Component>
<Component name="core.FileStorageProvider" type="storage.FileStorageProvider">
<Connections>
<Services>
<Service name="fs" component="core.FileSystem" service="fs" />
</Services>
</Connections>
</Component>
<Component name="core.FileSystemManager" type="storage.FileSystemManager">
<Connections>
<Services>
<Service name="fs" component="core.FileSystem" service="fs" />
</Services>
</Connections>
<Tasks>
<SporadicTask name="decompress" priority="3" />
</Tasks>
</Component>
<Component name="core.EventDispatcher" type="event.EventDispatcher">
<Tasks>
<PeriodicTask name="dispatcher" period="1.0" priority="2" />
</Tasks>
</Component>
<Component name="comms.TCPClient" type="io.net.tcp.TCPClient">
<Tasks>
<InterruptTask name="receive" priority="3" />
<InterruptTask name="transmit" priority="3" />
<SporadicTask name="receiveTimeout" priority="3" />
<SporadicTask name="transmitTimeout" priority="3" />
</Tasks>
</Component>
<Component name="comms.PacketStream" type="io.net.PacketStream">
<Connections>
<Services>
<Service name="stream" component="comms.TCPClient" service="data" />
</Services>
</Connections>
<Tasks>
<SporadicTask name="receive" priority="3" />
<SporadicTask name="receiveTimeout" priority="3" />
</Tasks>
</Component>
<Component name="comms.SpacePacket" type="io.net.SpacePacket">
<Connections>
<Services>
<Service name="spacePacket" component="comms.PacketStream" service="packet" />
</Services>
</Connections>
<Tasks>
<SporadicTask name="transmit" priority="3" />
<SporadicTask name="transmitTimeout" priority="3" />
<SporadicTask name="receive" priority="3" />
<SporadicTask name="receiveTimeout" priority="3" />
</Tasks>
</Component>
<Component name="comms.pus.PUSCore" type="io.net.pus.PUSCore">
<Connections>
<Services>
<Service name="pusPacket" component="comms.SpacePacket" service="dataPacket" />
</Services>
</Connections>
<Tasks>
<SporadicTask name="transmit" priority="3" />
<SporadicTask name="transmitTimeout" priority="3" />
<SporadicTask name="receive" priority="3" />
<SporadicTask name="receiveTimeout" priority="3" />
</Tasks>
</Component>
<Component name="comms.pus.PUSHK" type="io.net.pus.PUSHK">
<Connections>
<Services>
<Service name="pusSend" component="comms.pus.PUSCore" service="dataPacket" channel="0" />
<Service name="pusReceive" component="comms.pus.PUSCore" service="dataPacket"
channel="0" />
</Services>
</Connections>
<Tasks>
<SporadicTask name="transmit" priority="3" />
<SporadicTask name="receive" priority="3" />
</Tasks>
</Component>
<Component name="comms.pus.PUSEvent" type="io.net.pus.PUSEvent">
<Connections>
<Services>
<Service name="pusSend" component="comms.pus.PUSCore" service="dataPacket" channel="1" />
<Service name="pusReceive" component="comms.pus.PUSCore" service="dataPacket"
channel="1" />
</Services>
</Connections>
<Tasks>
<SporadicTask name="transmit" priority="3" />
<SporadicTask name="receive" priority="3" />
</Tasks>
</Component>
<Component name="comms.pus.PUSLDT" type="io.net.pus.PUSLDT">
<Connections>
<Services>
<Service name="pusPacket" component="comms.pus.PUSCore" service="dataPacket" channel="2" />
</Services>
</Connections>
<Tasks>
<SporadicTask name="transmit" priority="3" />
<SporadicTask name="transmitTimeout" priority="3" />
<SporadicTask name="transmitTransferTimeout" priority="3" />
<SporadicTask name="receive" priority="3" />
<SporadicTask name="receiveTimeout" priority="3" />
<SporadicTask name="receiveTransferTimeout" priority="3" />
</Tasks>
</Component>
<Component name="comms.pus.PUSToAAS" type="io.net.pus.PUSAMS">
<Connections>
<Services>
<Service name="pusSend" component="comms.pus.PUSCore" service="dataPacket" channel="4" />
<Service name="pusReceive" component="comms.pus.PUSCore" service="dataPacket"
channel="4" />
<Service name="target" component="comms.services.AASTarget" service="remote" />
</Services>
</Connections>
<Tasks>
<SporadicTask name="transmit" priority="3" />
<SporadicTask name="receive" priority="3" />
<SporadicTask name="requestCompleteTarget" priority="3" />
</Tasks>
</Component>
<Component name="comms.services.AASTarget" type="component.AAS.AASTarget" />
<Component name="comms.pus.PUSToPAS" type="io.net.pus.PUSAMS">
<Connections>
<Services>
<Service name="pusSend" component="comms.pus.PUSCore" service="dataPacket" channel="5" />
<Service name="pusReceive" component="comms.pus.PUSCore" service="dataPacket"
channel="5" />
<Service name="target" component="comms.services.PASTarget" service="remote" />
</Services>
</Connections>
<Tasks>
<SporadicTask name="transmit" priority="3" />
<SporadicTask name="receive" priority="3" />
<SporadicTask name="requestCompleteTarget" priority="3" />
</Tasks>
</Component>
<Component name="comms.services.PASTarget" type="component.PAS.PASTarget" />
<Component name="comms.pus.PUSToParamTransfer" type="io.net.pus.PUSAMS">
<Connections>
<Services>
<Service name="pusSend" component="comms.pus.PUSCore" service="dataPacket" channel="6" />
<Service name="pusReceive" component="comms.pus.PUSCore" service="dataPacket"
channel="6" />
<Service name="target" component="comms.ParamTransfer" service="remote" />
</Services>
</Connections>
<Tasks>
<SporadicTask name="transmit" priority="3" />
<SporadicTask name="receive" priority="3" />
<SporadicTask name="requestCompleteTarget" priority="3" />
</Tasks>
</Component>
<Component name="comms.ParamTransfer" type="io.net.ParamTransfer">
<Connections>
<Services>
<Service name="ldt" component="comms.pus.PUSLDT" service="dataPacket" />
</Services>
</Connections>
<Tasks>
<SporadicTask name="transmit" priority="3" />
<SporadicTask name="receive" priority="3" />
</Tasks>
</Component>
<Component name="comms.CFDP" type="io.net.CFDP">
<Connections>
<Services>
<Service name="fs" component="core.FileSystem" service="fs" />
<Service name="ut" component="comms.SpacePacket" service="dataPacket" channel="1" />
</Services>
</Connections>
<Tasks>
<SporadicTask name="transmit" priority="4" />
<SporadicTask name="receive" priority="4" />
<SporadicTask name="timer" priority="4" />
<SporadicTask name="remoteRequestComplete" priority="4" />
</Tasks>
</Component>
<Component name="cdh.tmtc.TMBeacon" type="tmtc.TMBeacon">
<Connections>
<Services>
<Service name="hkHandler" component="comms.pus.PUSHK" service="hkReporting" />
</Services>
</Connections>
<Tasks>
<PeriodicTask name="send" period="5.0" priority="2" />
</Tasks>
</Component>
<Component name="cdh.tmtc.TMDebug" type="tmtc.TMDebug">
<Connections>
<Services>
<Service name="pusSend" component="comms.pus.PUSCore" service="dataPacket" channel="3" />
</Services>
</Connections>
<Tasks>
<SporadicTask name="transmit" priority="3" />
</Tasks>
</Component>
<Component name="cdh.tmtc.TMTCEvent" type="tmtc.TMTCEvent">
<Connections>
<Components>
<Component name="eventHandler" component="comms.pus.PUSEvent" />
</Components>
</Connections>
</Component>
<Component name="cdh.logging.TCLogger" type="logging.CommandLogger">
<Connections>
<Services>
<Service name="timestamp" component="core.Time" service="time" />
</Services>
</Connections>
<Tasks>
<PeriodicTask name="store" period="10.0" priority="2" />
</Tasks>
</Component>
<Component name="platform.DummySubsys1" type="Dummy" />
<Component name="cdh.logging.EventLogger" type="logging.EventLogger">
<Connections>
<Services>
<Service name="timestamp" component="core.Time" service="time" />
</Services>
</Connections>
<Tasks>
<PeriodicTask name="store" period="10.0" priority="2" />
</Tasks>
</Component>
<Component name="cdh.DataPool" type="DataPool">
<ParameterAliases>
<ParameterBlock blockName="poolParameters">
<ComponentParameter name="DummySubsys1" component="platform.DummySubsys1"
parameter="dummyParam8" />
<ComponentParameter name="DummySubsys1" component="platform.DummySubsys1"
parameter="dummyParam16" />
<ComponentParameter name="DummySubsys1" component="platform.DummySubsys1"
parameter="dummyParam32" />
</ParameterBlock>
</ParameterAliases>
</Component>
<Component name="cdh.BeaconAggregator" type="Aggregator" />
<Component name="cdh.BaseSampler" type="Sampler">
<Connections>
<Components>
<Component name="DataPool" component="cdh.DataPool" />
</Components>
</Connections>
<Tasks>
<PeriodicTask name="sample" period="5.0" priority="2" />
</Tasks>
</Component>
<Component name="cdh.BaseAggregator" type="Aggregator" />
<Component name="cdh.BaseMonitor" type="Monitor">
<Tasks>
<PeriodicTask name="refresh" period="5.0" priority="2" />
</Tasks>
</Component>
<Component name="cdh.logging.BaseLogger" type="logging.DataLogger">
<Connections>
<Services>
<Service name="timestamp" component="core.Time" service="time" />
</Services>
</Connections>
<Tasks>
<PeriodicTask name="sample" period="1.0" priority="2" />
<PeriodicTask name="store" period="6.0" priority="2" />
</Tasks>
</Component>
<Component name="cdh.EventAction" type="auto.EventAction" />
<Component name="cdh.TimeAction" type="auto.TimeAction">
<Connections>
<Services>
<Service name="time" component="core.Time" service="time" />
</Services>
</Connections>
<Tasks>
<PeriodicTask name="main" period="1.0" priority="2" />
</Tasks>
</Component>
<Component name="cdh.PeriodicAction" type="auto.PeriodicAction">
<Tasks>
<PeriodicTask name="cycle" period="60.0" priority="2" />
</Tasks>
</Component>
<Component name="MyMessagePrinter" type="MessagePrinter">
</Component>
</Deploy>
</Deployment>
</ModelElement>
The demo_linux Deployment has been modified to include the MessagePrinter Component using: <Use type="MessagePrinter">.
The MessagePrinter Component Type is then instantiated as MyMessagePrinter using: <Component name="MyMessagePrinter" type="MessagePrinter"><Component>.
Lastly, the demo_linux Deployment has been renamed as demo.
|
Refer to the Deployment Definition documentation for further information about |
Generating the Deployment
Before building a Deployment, we recommend you generate it first. The generation step produces a spacecraft_database (SCDB). The SCDB contains a description of all the Components within the Deployment. It allows tmtclab to interact with the flight software without requiring the labour-intensive construction of a packet database.
Execute the following codegen command to generate the demo Deployment:
codegen deployment generate demo
A large number of files have been generated for us from this simple command:
-
The
srcdirectory contains the Deployment's source code. -
The
incdirectory contains the Deployment's header files. -
The
src/initdirectory contains the Deployment's initialisation data. This is passed to the component instances.
|
Ensure the Deployment's initialisation data matches any additional functionality you defined within the Continue to the next section if you didn’t add any elements into the |
Initialisation Data
Our deployment contains a src/init directory which contains the initialisation data for the component instances. We have used demo_linux as a template, which has provided us with a very basic flight software configuration, including a communicaiton stack. These component instances require initialisation data to be passed to them, otherwise they will not function correctly.
Copy the initialisation data from the demo_linux Deployment to the demo Deployment:
cp -r $OBSW_ROOT/demo_linux/src/init $OBSW_ROOT/fsdk_demo/demo/src
Building the Deployment
With the SCDB generated and initialisation data provided the Deployment can now be built.
Execute the following make command in your project directory to build the demo Deployment:
make -C demo force target
|
|
Relevant Documents
With the execution of the make command, you have successfully created a binary for the Linux platform. The binary file is located in the demo/bin/linux directory.
Refer to the Interacting with Flight Software how-to guide for instructions on how to interact with the flight software using tmtclab.