You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
72 lines
4.8 KiB
72 lines
4.8 KiB
\subsection{Build infrastructure and automatic deployment}
|
|
|
|
The CI system, which is based on \textit{drone} \cite{drone} allows to execute commands, whenever a new version is published into the \textit{Git} repository.
|
|
A corresponding \textit{drone} configuration file has been added to the source code as \texttt{.drone.yml} (Listing~\ref{lst:drone}).
|
|
Within this configuration file, settings relevant to the build process are provided to the build environment.
|
|
First, the \texttt{CONFIG=maglab} option lets the build system use an additional configuration file (\texttt{Configurion.mk.maglab}), which is stored inside the framework repository and provides information, such as the WiFi SSID.
|
|
To keep the WiFi password secret, it is not written down in the configuration file.
|
|
Instead, to include secrets into a build process while allowing to keep the configuration public, \textit{drone} allows to encrypt these with a repository specific key.
|
|
Using this method, the password is stored as \texttt{.drone.sec} file inside the repository from where it is injected into the build environment.
|
|
Also noticeable in Listing~\ref{lst:drone} is the firmware version, which is configured to be the first 8 letters of the \textit{Git} commit hash uniquely identifying a version of the source code.
|
|
|
|
\begin{lstlisting}[language=,
|
|
caption={The \textit{drone} configuration for the \textit{ESPer} project.},
|
|
label=lst:drone, basicstyle=\ttfamily\scriptsize]
|
|
build:
|
|
image: maglab/sming
|
|
environment:
|
|
- CONFIG=maglab
|
|
- WIFI_PWD=$$WIFI_PWD
|
|
- VERSION=$${COMMIT:0:8}
|
|
commands:
|
|
- make clean
|
|
- make
|
|
publish:
|
|
sftp:
|
|
host: eddie.maglab.space
|
|
username: esper
|
|
files:
|
|
- dist/*
|
|
destination_path: './'
|
|
when:
|
|
branch: master
|
|
\end{lstlisting}
|
|
|
|
For deployment, only the master branch is considered.
|
|
After a successful build, all distribution files (the binary firmware and meta-data files) of all device types are copied to the repository server, where they are served by a HTTP server.
|
|
The configuration file (\texttt{Configurion.mk.maglab}) references this repository server as the source for updates.
|
|
|
|
Support for multiple devices of different type is implemented in both, the \textit{ESPer} framework itself and the build system.
|
|
The framework keeps control over the application life-cycle.
|
|
It ensures that device unspecific code is executed at the right time and provides an API for device specific functionality.
|
|
For this, a simple interface is specified by the framework, which must be implemented by each device.
|
|
A single function \texttt{Device* getDevice()} must be defined exactly once in each device specific folder.
|
|
To implement this interface, a static instance of \texttt{Device} is created and returned.
|
|
Each \texttt{Device} is populated with device specific \texttt{Feature} instances.
|
|
While the \texttt{Feature}-API leverages common runtime polymorphism to share functionality between features, the initial \texttt{Device} creation uses compile-time polymorphism, which reduces the need for memory management and increases performance by avoiding virtual function tables.
|
|
Listing~\ref{lst:create_device_socket} shows the complete device specific code used for a simple power socket, which is mainly confined to the device type and its capabilities (i.e., the number of GPIO pins).
|
|
|
|
\begin{lstlisting}[caption={Device specific code for a socket driver.},
|
|
label=lst:create_device_socket, basicstyle=\ttfamily\scriptsize]
|
|
#include "Device.h"
|
|
#include "features/Socket.h"
|
|
|
|
Device device:
|
|
|
|
constexpr const char NAME[] = "socket";
|
|
constexpr const uint16_t GPIO = 12;
|
|
OnOffFeature<NAME, GPIO, false, 1> socket(&device);
|
|
|
|
Device* getDevice() {
|
|
return &device;
|
|
}
|
|
\end{lstlisting}
|
|
|
|
The actual compilation of the source code is mainly controlled using two \textit{Makefiles}.
|
|
The main \textit{Makefile} is built to accept a parameter for device type identifiers called \texttt{DEVICE}, and to create its whole output inside a subdirectory specific to the device type.
|
|
An additional \textit{Makefile} scans a project subdirectory and uses each directory in there as a container for device specific code.
|
|
For each of these directories, the main \textit{Makefile} is called and the subdirectories name is used as the value of the \texttt{DEVICE} parameter.
|
|
By splitting the build and recompiling the framework each time before intermixing it with the device specific code, the device type identifier can be used inside the shared framework code.
|
|
While building a devices firmware, the meta-information file used during updates is also created and stored beside the binary firmware image.
|
|
For development, each device can be build separately by using the device type identifier as \textit{Makefile} target.
|
|
In addition, the prefix \texttt{/flash} can be used to flash a specific firmware.
|