Hello World 1
Introduction
In this tutorial, we will introduce some of the basic ideas used in Flightkit, and how they can be used to produce flight software.
When you have completed this tutorial, you’ll have built and run a piece of flight software which, in principle, is ready for launch.
|
In this tutorial, you will:
|
Before You Begin
Guidance on the styles and conventions used in these tutorials is available here.
Unless otherwise directed, all commands in this tutorial must be run in the the_basics/HelloWorld1 workspace.
You must have Flightkit installed as described in the Getting Started Guide.
Navigate to the the_basics/HelloWorld1 workspace in a terminal and run hfk workspace prepare to ensure it is ready to use.
Components, Deployments and Missions
All software environments and languages include concepts which allow software reuse. C has functions. Java and other object-oriented languages have classes and modules. Critically, these concepts provide reuse via encapsulation.
In Flightkit, we make our software reusable by encapsulating functionality in Component Types. A Component Type for processing Space Packets, for example, contains all the logic and packet details for that communication protocol. It may be used any time that handling of Space Packets is required.
|
In this tutorial, you’ll look at a simple Component Type called
In real flight software, much more complex functionality is usually needed. In future tutorials you’ll learn how to write Component Types capable of fulfilling those requirements. |
Component Types are used by instantiating them. Each time you instantiate a Component Type a new Component Instance is created.
To produce executable flight software with Flightkit, you must create what’s known as a Deployment Type. This is a reusable collection of Component Instances, along with the connections between them.
Much like Component Types, Deployment Types are used by instantiating them, creating, as you might expect, Deployment Instances.
Deployment Types are instantiated in the context of a Mission. To instantiate a Deployment Type you must provide Initialisation Data for each of its Component Instances. Initialisation Data is used to control the behaviour of Component Instances at run time.
Deployment Instances can be built and run. If they contain the necessary Component Instances, then your ground software will be able to interact with them.
In this tutorial, we’ll illustrate these abstract ideas with examples.
The MessagePrinter Component Type
A Component Type is defined by two things:
-
Its
componentType.xml. This is a file which describes how the "outside world" must interact with it. It’s written in XML so that it can be read by the Flightkit Tooling for code generation purposes. It also usually contains documentation about what the Component Type is for, and how to use it. -
Its implementation. This determines the behaviour of the Component Type and dictates the way in which the Component Type fulfils the obligations described in its
componentType.xml. In Flightkit, Component Implementations are written in C.
For this tutorial, we’ve provided a complete MessagePrinter Component Type.
This includes both its componentType.xml and its MessagePrinter.c
implementation.
You’ll be using its printGreeting Action. Actions are one of the
mechanisms you can use to execute a Component Type's functionality on
command.
Let’s take a look at how printGreeting is both defined and implemented.
Navigate to the library/component_types/MessagePrinter directory.
This directory contains both the componentType.xml and the implementation for
MessagePrinter. It also contains the headers which MessagePrinter includes
to interact with the outside world.
Open the componentType.xml file found in the MessagePrinter directory.
|
If you can’t find the
|
In the componentType.xml, you’ll find the following Action definition:
<Action name="printGreeting">
<Description>
Print a greeting, specified in initialisation data, to the console.
</Description>
<Documentation><Markdown>
The message to print is set by the `z_Greeting` member of the
`MessagePrinter` component type's initialisation data.
</Markdown></Documentation>
</Action>
As you can see, the componentType.xml contains the name and documentation for
the Action. When it’s implemented, the Component Implementation must
provide functionality matching what’s described here.
The implementation of printGreeting, which we’ve provided, can be found by
opening the Component Type's main implementation file, MessagePrinter.c.
Open the MessagePrinter.c file found in the MessagePrinter directory and
navigate to the MessagePrinter_printGreeting() function.
You should find the following function implementation:
/*---------------------------------------------------------------------------*
* Print a greeting, specified in initialisation data, to the console.
*---------------------------------------------------------------------------*/
status_t MessagePrinter_printGreeting
(
MessagePrinter_t *pt_MessagePrinter
)
{
/* Get the greeting from the MessagePrinter initialisation data */
cstring_t z_Greeting =
MESSAGEPRINTER_CONTAINER_INIT_DATA(pt_MessagePrinter)->z_Greeting;
/* Print out the greeting using the info logging macro */
MESSAGEPRINTER_CONTAINER_LOG_INFO(
pt_MessagePrinter, "greeting says '%s'", z_Greeting);
/* Nothing can possibly go wrong */
return STATUS_SUCCESS;
}
As you can see, when the MessagePrinter_printGreeting() function is called,
it will print out the message from the Initialisation Data, just as described
in the componentType.xml.
We use specific terminology to describe the calling of a function which
implements an Action. We says that the printGreeting Action is
invoked.
In order to make use of the MessagePrinter Component Type, and invoke its
printGreeting Action at runtime, it needs to be instantiated in a
Deployment Type.
The MessagePrinterDemo Deployment Type
As described above, Deployment Types are a collection of connected Component Instances. Choices about which Component Types to instantiate, and how those instances are connected, determine how the Deployment Type will behave when it is itself instantiated in a Mission.
Deployment Types are described by a deploymentType.xml file.
We have provided the MessagePrinterDemo Deployment Type which
instantiates the MessagePrinter Component Type introduced above.
Open the MessagePrinterDemo deploymentType.xml, found here:
library/deployment_types/MessagePrinterDemo/deploymentType.xml
This file contains a handful of Component Instances required to support communication with the ground software. For the purposes of this tutorial you can safely ignore these Component Instances.
|
If you would like to learn more about some of the communications Component Types we provide as part of Flightkit, you can refer to our Communication Protocols Reference. |
It also contains an instance of the MessagePrinter Component Type. Since
MessagePrinter has no requirements on other Component Types, the XML
required to instantiate it is simple. It can be found near the bottom of the
deploymentType.xml:
<Component name="MyMessagePrinter" type="MessagePrinter">
<Description>
An instance of the MessagePrinter which will print your message
</Description>
</Component>
Note that we specify both the Component Type to instantiate, and the name to give the Component Instance which we’re creating.
The HelloWorld1 Mission
Having constructed a Deployment Type from Component Instances, that Deployment Type can be instantiated in a Mission to produce runnable flight software.
To do so, Initialisation Data must be provided for each Component Instance in the Deployment Type. This allows a single Deployment Type to be reused in different situations, each time with its own set of Initialisation Data.
To allow you to use the MessagePrinterDemo Deployment Type, We have
provided the HelloWorld1 Mission. It is again described by an XML file,
mission.xml, which can be found here:
missions/HelloWorld1/mission.xml
You will now provide the MyMessagePrinter instance with the message it’s
going to print.
Setting up MyMessagePrinter
As described in the MessagePrinter componentType.xml, the
Initialisation Data is used to specify the message to print.
The Initialisation Data for each Component Instance in a Mission is set
in that Deployment Instance's init directory:
missions/HelloWorld1/MessagePrinterDemo/Default/
├── init
│ ├── comms
│ │ ├── PacketStream_Init.c
│ │ ├── services
│ │ │ ├── AASMessaging_Init.c
│ │ │ ├── AASTarget_Init.c
│ │ │ ├── PASMessaging_Init.c
│ │ │ └── PASTarget_Init.c
│ │ ├── SpacePacket_Init.c
│ │ └── TCPServer_Init.c
│ ├── MyMessagePrinter_Init.c
│ └── Version_Init.c
├── lib_config
│ └── meson.build
└── meson.build
Each of the C files in the init directory is associated with a
Component Instance and contains the Initialisation Data for that instance.
Open missions/HelloWorld1/MessagePrinterDemo/Default/init/MyMessagePrinter_Init.c.
This file contains a MessagePrinter_Init_t structure. This is a type which is
generated by the Flightkit Tooling when a new Component Type is created.
|
If you’re curious, the definition of
The members of this structure are chosen by the author of the Component Type, so each type can have whatever Initialisation Data it requires. The values, however, are set on a per-instance basis, by the author of the Mission and its Initialisation Data. This allows instances of the same Component Type to behave differently from each other when used in different situations. |
Notice the TODO in the MyMessagePrinter Initialisation Data.
Provide a value for z_Greeting, as follows:
/** The MyMessagePrinter initialisation data */
const MessagePrinter_Init_t gt_MyMessagePrinterInit =
{
.z_Greeting = "Help, I'm trapped in a tutorial factory!"
};
You may set z_Greeting to any string you wish.
The communications Component Instances are already configured, so now you just need to build the Mission.
Building HelloWorld1
The Flightkit Tooling provides functionality for building your Mission. When doing so it generates a Mission Database (MDB). This database fully describes the flight software contained within your Mission. It is used by the ground software to enable interaction with the flight software without needing to manually construct a packet database.
To generate and build the HelloWorld1 Mission, run the
following command in the the_basics/HelloWorld1 directory:
hfk mission build HelloWorld1
Show expected output
...
[153/153] Linking target generated/missions/HelloWorld1/...
Installing generated/missions/HelloWorld1/...
[INFO] Successfully built the HelloWorld1 mission
Once the build has succeeded you have some completed flight software. You’re ready to set up the ground software, run the flight software, and connect the two together.
Using Helix Lab
Flightkit includes a tool called Helix Lab which you can use to interact with your flight software during development.
You will now launch Lab and use it to invoke the printGreeting Action.
Run Helix Lab by clicking the "Helix Lab" icon in your applications menu.
|
In order to run, Lab requires:
|
Upon start up, Lab always defaults to displaying the 'Mission & Config' view. The right-hand side of this view contains an information panel named 'Configuring your Mission' which explains the steps required to start interacting with your spacecraft. We will walk you through these steps now.
First you need to load the MDB associated with your Mission.
Click the Add mission database button to load the MDB.
Select the MDB you generated above: output/missions/HelloWorld1/HelloWorld1_0_0_0.missiondb,
then click Open.
This provides Lab with all the information it requires to determine what your Mission contains, and how to interact with it.
Bringing Everything Together
It’s now time to run the flight software you built above.
Execute your flight software binary by running the following command in the
the_basics/HelloWorld1 directory, in your terminal:
./output/missions/HelloWorld1/MessagePrinterDemo/Default/Default
Show expected output
INF: Deployment.c:298 Running deployment:
INF: Deployment.c:299 - Deployment instance: Default
INF: Deployment.c:300 - Deployment type: MessagePrinterDemo
INF: Deployment.c:301 - Target: MessagePrinterDemo
INF: Deployment.c:302 - Mission: HelloWorld1
INF: Deployment.c:427 Deployment initialisation successful
The Default Deployment Instance is now running and awaiting commands from
the ground software. To command it, you’ll need to connect to it from Lab.
Switch back to Lab, select the HelloWorld1.LinuxAsset Asset from the list of
available Assets, and click Connect.
Enter the Hostname of the device on which your deployment instance is running,
and the Port number specified by the initialisation data of your deployment
instance’s TCP server.
Their values should be 127.0.0.1 and 51423 respectively.
Connect to the deployment by clicking the Connect now button.
On the left-hand side of Lab's main window, click on the 'Commanding' tab.
This opens the 'Commanding' view which is used to issue commands to the spacecraft.
On the left hand side of this view you will see the 'Commanding Explorer'. This is used to navigate through all the available commands within your Mission. The explorer is structured as follows:
-
The top level of the explorer displays the names of the different Hosts on your spacecraft.
-
Clicking on a Host reveals the different Targets which use that Host.
-
Clicking on a Target reveals the different Deployment Instances on that Target.
-
Clicking on a Deployment Instance reveals the different Component Instances running on that Deployment Instance.
-
Clicking on a Component Instance reveals the different Actions and Parameters associated with it.
Navigate through the 'Commanding Explorer' to find the printGreeting Action
associated with the MyMessagePrinter Component Instance in your
Deployment Instance.
Once located, click on the printGreeting Action.
Clicking on the Action adds a command card representing that Action to the 'My Commands' section of the view. Command cards added to this section can be rearranged and used when required.
Clicking on a command card expands the layout to reveal additional fields which are associated with that command.
Expand the printGreeting command card by clicking on it.
Invoke the printGreeting Action by clicking the Invoke button.
To confirm that the Action was invoked successfully, you can check the returned status displayed in the 'Command History' section, on the right-hand side of the view.
Expand the 'Command History' section by clicking on it.
You should be able to see the Action you just invoked with a green success indicator next to it.
The Default Deployment Instance should also have printed your message to
the terminal in which it is running.
Confirm that the Action performed as expected by checking that the correct
message has been printed to the terminal in which the Default
Deployment Instance is running.
You can see the raw details of the telecommand and telemetry packets sent between the ground and flight software by looking at the 'Packet Log' view.
Open the 'Packet Log' view by clicking on the 'Communication' tab on the left-hand side of Lab's main window, and ensuring 'Packet Log' is selected.
Notice how the MDB has enabled Lab to generate telecommands and interpret telemetry automatically, without the need for explicit packet configuration.
Once you are happy the Action is working, disconnect from the Deployment Instance by clicking the Disconnect button on the 'Mission & Config' view.
To terminate the Deployment Instance, press CTRL+C in the terminal in which
it is running.
Wrap Up
In this tutorial we have:
-
Introduced Component Types as encapsulated software functionality which can be reused.
-
Seen how a Component Type can be understood in terms of its
componentType.xmlfile and its implementation. -
Introduced Deployment Types as sets of connected Component Instances.
-
Introduced Missions as sets of Deployment Instances along with their Initialisation Data.
-
Set up an example
MessagePrinterComponent Instance calledMyMessagePrinterin ourHelloWorld1Mission. -
Seen how to configure Lab to communicate with a Deployment Instance.
-
Used Lab to invoke an action, and seen its effect on the running flight software.
In the next tutorial, you’ll learn how to make changes to Component Types so that you can introduce your own functionality into your flight software.
Click here to move on to that now.