\section{Devices}
The client code for the devices is compiled from one codebase. For a device to
be eligible for \glspl{mTask}, it must be able to compile the shared codebase
and implement (part of) the device specific interface. The shared codebase only
uses standard \gls{C} and no special libraries or tricks are used. Therefore
the code is compilable for almost any device or system. Note that it is not
needed to implement a full interface. The full interface --- excluding the
device specific settings --- is listed in Appendix~\ref{app:device-interface}.
The interface works in a similar fashion as the \gls{EDSL}. Devices do not have
to implement all functionality, this is analogous to the fact that views do not
have to implement all type classes in the \gls{EDSL}.  When the device connects
for the first time with a server the specifications of what is implemented is
communicated.

At the time of writing the following device families are supported and can run
the device software.
\begin{itemize}
	\item \texttt{POSIX} compatible systems
		
		This includes systems running \emph{Linux} and \emph{MacOS}.
	\item \texttt{STM32} family microcontrollers supported by \texttt{ChibiOS}.

		This is tested in particular on the \texttt{STM32f7x} series \gls{ARM}
		development board.
	\item Microcontrollers programmable by the \gls{Arduino} \gls{IDE}.\\
		
		This does not only include \gls{Arduino} compatible boards but also
		other boards capable of running \gls{Arduino} code. The code
		has been found working on the \texttt{ESP8266} powered \emph{NodeMCU}.
		It is tested on devices as small as the regular \gls{Arduino}
		\emph{UNO} board that only boasts a meager \emph{2K} of \emph{RAM}.
\end{itemize}

\section{Specification}
Devices are stored in a record type and all devices in the system are stored in
a \gls{SDS} containing all devices. From the macro settings in the interface
file a profile is created for the device that describes the specification. When
a connection between the server and a client is established the server will
send a request for specification. The client will serialize his specification
and send it to the server so that the server knows what the client is capable
of. The exact specification is listed in Listing~\ref{lst:devicespec}

\begin{lstlisting}[language=Clean,label={lst:devicespec},
	caption={Device specification for \glspl{mTask}}]
:: MTaskDeviceSpec =
	{haveLed     :: Bool
	,haveAio     :: Bool
	,haveDio     :: Bool
	,bytesMemory :: Int
	}
\end{lstlisting}

\section{Device Storage}
All devices available in the system are stored in a big \gls{SDS} that contains
a list of \CI{MTaskDevice}s. The exact specification is listed in
Listing~\ref{lst:mtaskdevice} with the accompanying classes and types.

The \CI{deviceResource} component of the record must implement the
\CI{MTaskDuplex} interface that provides a function that launches a task used
for synchronizing the channels.  The \CI{deviceTask} stores the \gls{Task}-id
for this \gls{Task} when active so that it can be checked upon. This top-level
task has the duty to report set the \CI{deviceError} field whenever an error
occurs. All communication goes via these channels. If the system wants to send
a message to the device it just puts it in the channels. Messages sent from the
client to the server are also placed in there. In the case of the \gls{TCP}
device type the \gls{Task} is just a simple wrapper around the existing
\CI{tcpconnect} function in \gls{iTasks}. In case of the serial device type it
uses the newly developed serial port library of \gls{Clean}\footnote{\url{%
https://gitlab.science.ru.nl/mlubbers/CleanSerial}}.

Besides all the communication information the record also keeps track of the
\glspl{Task} currently on the device and the according \glspl{SDS}. Finally it
stores the specification of the device that is received when connecting.
All of this is listed in Listing~\ref{lst:mtaskdevice}. The definitions of the
message format are explained in the following section.

\begin{lstlisting}[language=Clean,caption={Device type},label={lst:mtaskdevice}]
deviceStore :: Shared [MTaskDevice]

:: Channels :== ([MTaskMSGRecv], [MTaskMSGSend], Bool)
:: MTaskResource 
	= TCPDevice TCPSettings
	| SerialDevice TTYSettings
:: MTaskDevice =
		{ deviceTask :: Maybe TaskId
		, deviceError :: Maybe String
		, deviceChannels :: String
		, deviceName :: String
		, deviceTasks :: [MTaskTask]
		, deviceData :: MTaskResource
		, deviceSpec :: Maybe MTaskDeviceSpec
		, deviceShares :: [MTaskShare]
	}

channels :: MTaskDevice -> Shared Channels

class MTaskDuplex a where
	synFun :: a (Shared Channels) -> Task ()
\end{lstlisting}

\section{Communication}
All \gls{mTask} messages are encoded following the specification given in
Appendix~\ref{app:communication-protocol}. Available messages are:
\begin{lstlisting}[language=Clean,caption={Available messages}]
:: MTaskMSGRecv
	= MTTaskAck Int Int           | MTTaskDelAck Int
	| MTSDSAck Int                | MTSDSDelAck Int
	| MTPub Int BCValue           | MTMessage String
	| MTDevSpec MTaskDeviceSpec   | MTEmpty

:: MTaskMSGSend
	= MTTask MTaskInterval String | MTTaskDel Int
	| MTShutdown                  | MTSds Int BCValue
	| MTUpd Int BCValue           | MTSpec

:: MTaskInterval = OneShot | OnInterval Int | OnInterrupt Int
\end{lstlisting}

\subsection{Add a device}
A device can be added by filling in the \CI{MTaskDevice} record as much as
possible and running the \CI{connectDevice} function. This function grabs the
channels, starts the synchronization \gls{Task}, makes sure the errors are
handled when needed and runs a processing function in parallel to react on the
incoming messages. Moreover, it sends a specification request to the device in
question to determine the details of the device and updates the record to
contain the top-level \gls{Task}-id. All the device functionality heavily
depends on the \CI{withDevices} function that applies a function a device in
the \gls{SDS} when they are equal. Device equality is defined as equality on
their channels. This allows you to give an old device record to the function
and still update the latest instance. Listing~\ref{lst:connectDevice} shows the
connection function.

\begin{lstlisting}[language=Clean,label={lst:connectDevice},%
	caption={Connect a device}]
withDevices :: MTaskDevice (MTaskDevice -> MTaskDevice) -> Task [MTaskDevice]

connectDevice :: (MTaskDevice (Shared Channels) -> Task ()) MTaskDevice -> Task Channels
connectDevice procFun device = let ch = channels device
	in appendTopLevelTask 'DM'.newMap True
		(procFun device ch -||- catchAll (getSynFun d.deviceData ch) errHdl)
		>>= \tid->withDevices device (\d->{d&deviceTask=Just tid,deviceError=Nothing})
		>>| upd (\(r,s,ss)->(r,s++[MTSpec],ss)) ch
	where
		errHdl e = withDevices device (\d->{d & deviceTask=Nothing, deviceError=Just e}) @! ()
\end{lstlisting}

Figure~\ref{fig:handshake} shows the connection diagram. The client responds to
the server with their device specification. This is detected by the processing
function and the record is updated accordingly.

\begin{figure}[H]
	\begin{sequencediagram}
		\newthread{c}{Server}
		\newinst[4]{s}{Client}
		\mess{c}{MTSpec}{s}
		\mess{s}{MTDevSpec d}{c}
	\end{sequencediagram}
	\caption{Connect a device}\label{fig:handshake}
\end{figure}

\subsection{\glspl{Task}}
\subsection{\glspl{SDS}}
\todo{Connectie, hoe gaat dat in zijn werk}
