\subsection{Multi-Device build infrastructure}

The firmware for all \textit{ESP8266} based devices in the hackerspace are all based on the same framework.
\textit{Sming} provides the base library for this framework.
In addition, components and functionality shared by all devices has been identified and are providing a framework for the existing and possible further devices.
This framework provides a functional base for all devices and allows to reuse code providing functionality which is common in multiple devices.
The framework also includes a build system, which allows to configure some basic parameters for all devices.
Including, but not limited to, the Wi-Fi access parameters, the \textit{MQTT} connection settings and the updater URLs.
By sharing the same code, all devices ensure to have a common behavior when it comes to reporting the device status or interacting with the home-automation controller.
This eases configuration and allows to collect information about all devices at a central location.

Each device firmware exists as a separate project and includes a link to the framework.
As development on these devices happens in cycles, older projects are missing updates of the framework and therefor do not benefit from newly added features or fixed problems.
Updating the framework version and rebuilding the firmware would often result in an easy gain of these benefits, but requires manual interaction.
More problems will arise if the application programming interface (API) of the framework changes.
In this situation, the device firmware must be updated to use the changed API, which can be an unpleasant and complex task and leads to higher latency for firmware updates.

To prevent these problems the device firmware of all devices in the hackerspace is now integrated with the framework into a larger project.
By doing so, each device specific code is always linked to the latest version of the framework.
Device specific code is now organized as a folder for each device type.
The build system has been modified to scan for all device specific folders and call the original build process for each of them.


\subsubsection{Framework integration}

The framework has been changed 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 SOCKET_NAME[] = "socket";
constexpr const uint16_t SOCKET_GPIO = 12;
OnOffFeature<SOCKET_NAME, SOCKET_GPIO, false, 1> socket(&device);

Device* getDevice() {
  return &device;
}
\end{lstlisting}


\subsubsection{Build system}

The existing \textit{Makefile} has been refactored 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 version identifier 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.
