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} |
\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