Sven Reissmann
8 years ago
6 changed files with 79 additions and 99 deletions
-
75-concept.tex
-
726-1-build_and_deploy.tex
-
416-1-multidevice_build_structure.tex
-
446-2-automatic-deployment.tex
-
06-2-update_mechanism.tex
-
146-implementation.tex
@ -0,0 +1,72 @@ |
|||
\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. |
@ -1,41 +0,0 @@ |
|||
\subsection{Multi-Device build infrastructure} |
|||
|
|||
|
|||
\subsubsection{Framework integration} |
|||
The framework is build to keep control over the application life-cycle. |
|||
It ensures that the device unspecific code is executed at the right time and provides an API for device specific functionality. |
|||
|
|||
The framework specifies a simple interface, 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. |
|||
|
|||
\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} |
|||
|
|||
|
|||
\subsubsection{Build system} |
|||
The \textit{Makefile} is build 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. |
|||
Another \textit{Makefile} has been created which scans a project subdirectory and uses each directory in there as container for device specific code. |
|||
For each of these directories, the other \textit{Makefile} is called and the subdirectories name is used as \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. |
@ -1,44 +0,0 @@ |
|||
\subsection{Automatic deployment and roll-out} |
|||
|
|||
%The source code of the \textit{ESPer} project is published into a \textit{GIT} source code repository which is provided by the hackerspace. |
|||
%To avoid interferences between different build environments on developers computers and roll out new versions as early as possible, the code has been integrated into a continuous integration (CI) system. |
|||
%The CI, which is based on \textit{drone}\cite{drone} and provided as part of the hackerspace infrastructure, allows to execute commands on each version published into the \textit{GIT} repository. |
|||
%Therefore a \textit{drone} configuration file as shown in Listing~\ref{lst:drone} has been added to the source code as \texttt{.drone.yml}. |
|||
|
|||
\begin{sloppypar} |
|||
As shown in the configuration Snippet, the build environment includes some special settings. |
|||
First, the \texttt{CONFIG=maglab} option lets the build system use \texttt{Configurion.mk.maglab} instead of the default configuration file. |
|||
This configuration file is stored inside the repository, too. |
|||
To keep the WiFi password secret, it is not written down in the configuration, but must be specified in the environment. |
|||
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. |
|||
At last, the firmware version is configured to be made out of the first 8 letters of the \textit{GIT} commit hash, which uniquely identifies a version of the source code. |
|||
\end{sloppypar} |
|||
|
|||
\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 files and the version files) of all devices are copied to the machine running the home automation controller software into a directory served by a HTTP server. |
|||
The used configuration file references this server as source of updates. |
|||
|
@ -1,11 +1,9 @@ |
|||
\section{Implementation} |
|||
|
|||
Implementing \textit{OTA} updates under the given requirements involves three different components, which interact closely. |
|||
Implementing \textit{OTA} updates under the given requirements involves multiple components, which interact closely. |
|||
The continuous integration system is in charge of building the firmware from source, calculating cryptographic signatures, and publishing the built binary images. |
|||
The deployment infrastructure provides resources for downloading the binary firmware images and triggering the update on all devices. |
|||
Finally, the implementation of the update mechanism as a part of the firmware running on the embedded device is responsible for downloading and installing the updates. |
|||
|
|||
The first component is the build system which is in charge of building the firmware from source and publishing the built binary images. |
|||
Second, the deployment provides infrastructure for downloading the binary firmware images and triggering the update on all devices. |
|||
Finally, the implementation of the update mechanism as part of the firmware running on the embedded device which is responsible for downloading and checking the updates and installing them. |
|||
|
|||
\input{6-1-multidevice_build_structure} |
|||
\input{6-2-automatic-deployment} |
|||
\input{6-3-update_mechanism} |
|||
\input{6-1-build_and_deploy} |
|||
\input{6-2-update_mechanism} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue