\documentclass[../thesis.tex]{subfiles}

\input{subfilepreamble}

\begin{document}
\input{subfileprefix}

\chapter{Integration with \texorpdfstring{\gls{ITASK}}{iTask}}%
\label{chp:integration_with_itask}
\begin{chapterabstract}
	This chapter shows the integration of \gls{MTASK} with \gls{ITASK} by showing:
	\begin{itemize}
		\item an architectural overview \gls{MTASK} applications;
		\item on the interface for connecting devices;
		\item the interface for lifting \gls{MTASK} tasks to \gls{ITASK} tasks;
		\item and interface for lifting \gls{ITASK} \glspl{SDS} to \gls{MTASK} \glspl{SDS}.
	\end{itemize}
\end{chapterabstract}

The \gls{MTASK} language is a multi-view \gls{DSL}, i.e.\ there are multiple interpretations possible for a single \gls{MTASK} term.
Using the byte code compiler (\cleaninline{BCInterpret}) \gls{DSL} interpretation, \gls{MTASK} tasks can be fully integrated in \gls{ITASK}.
They are executed as if they are regular \gls{ITASK} tasks and they communicate may access \glspl{SDS} from \gls{ITASK} as well.
\Gls{MTASK} devices contain a domain-specific \gls{OS} and are little \gls{TOP} engines in their own respect, being able to execute tasks.
\Cref{fig:mtask_integration} shows the architectural layout of a typical \gls{IOT} system created with \gls{ITASK} and \gls{MTASK}.
The entire system is written as a single \gls{CLEAN} specification where multiple tasks are executed at the same time.
Tasks can access \glspl{SDS} according to many-to-many communication and multiple clients can work on the same task.
Devices are integrated into the system using the \cleaninline{withDevice} function (see \cref{sec:withdevice}).
Using \cleaninline{liftmTask}, \gls{MTASK} tasks are lifted to a device (see \cref{sec:liftmtask}).
\Gls{ITASK} \glspl{SDS} are lifted to the \gls{MTASK} device using \cleaninline{liftsds} (see \cref{sec:liftmtask}).

\begin{figure}[ht]
	\centering
	\includestandalone{mtask_integration}
	\caption{\Gls{MTASK}'s integration with \gls{ITASK}.}%
	\label{fig:mtask_integration}
\end{figure}

\section{Connecting edge devices}\label{sec:withdevice}
When interpreted by the byte code compiler view, an \gls{MTASK} task produces a compiler.
This compiler is exceuted at run time so that the resulting byte code can be sent to an edge device.
All communication with this device happens through a so-called \emph{channels} \gls{SDS}.
The channels contain three fields, a queue of messages that are received, a queue of messages to send and a stop flag.
Every communication method that implements the \cleaninline{channelSync} class can provide the communication with an \gls{MTASK} device.
As of now, serial port communication, direct \gls{TCP} communication and \gls{MQTT} over \gls{TCP} are supported as communication providers (see \cref{lst:connection_types}).
The \cleaninline{withDevice} function transforms such a communication provider and a task that does something with this device to an \gls{ITASK} task.
Internally, the task sets up the communication, exchanges specifications with the device, executes the inner task while handling errors, and finally cleans up after closing.
\Cref{lst:mtask_device} shows the types and interface to connecting devices.

\begin{lstClean}[label={lst:mtask_device},caption={Device communication interface in \gls{MTASK}.}]
:: MTDevice //abstract
:: Channels :== ([MTMessageFro], [MTMessageTo], Bool)

class channelSync a :: a (Shared sds Channels) -> Task () | RWShared sds

withDevice :: a (MTDevice -> Task b)
	-> Task b | iTask b & channelSync, iTask a
\end{lstClean}

\todo{v.b.\ voor withDevice}

\subsection{Implementation}
The \cleaninline{MTDevice} abstract type is internally represented as three \gls{ITASK} \gls{SDS} that contain all the current information about the tasks.
The first \gls{SDS} is the information about the \gls{RTS} of the device, i.e.\ metadata on the tasks that are executing, the hardware specification and capabilities, and a list of fresh task identifiers.
The second \gls{SDS} is a map storing downstream \gls{SDS} updates.
When a lifted \gls{SDS} is updated on the device, a message is sent to the server.
This message is initially queued in the map to allow for asynchronous handling of multiple updates.
Finally, the \cleaninline{MTDevices} type contains the communication channels.

The \cleaninline{withDevice} task itself first constructs the \glspl{SDS} using the \gls{ITASK} function \cleaninline{withShared} to create anonymous local \glspl{SDS}.
Then, it performs the following four tasks in parallel to monitor the edge device.
\begin{enumerate}
	\item It synchronises the channels using the \cleaninline{channelSync} overloaded function.
		Errors that occur here are converted to the proper \gls{MTASK} exception.
	\item Watches the channels for the shutdown flag.
		If the connection is lost with the device unexpectedly, an \gls{MTASK} exception is thrown.
	\item Watches the channels for messages and processes them accordingly by changing the device information \gls{SDS} or adding the lifted \gls{SDS} updates to the corresponding \gls{SDS} update queue.
	\item Sends a request for a specification. Once the specification is received, the device task is run.
		The task value of this device task is then used as the task value of the \cleaninline{withDevice} task.
\end{enumerate}

If at any stage an unrecoverable device error occurs, an \gls{ITASK} exception is thrown on the \cleaninline{withDevice} task.
This exception can be caught in order to device some kind of fail-safe mechanism.
For example, when a device fails, the tasks can be sent to another device.
\todo[inline]{Example of failsafe?}

%withDevice spec deviceTask
%	withShared newMap \sdsupdates->
%	withShared ([], [MTTSpecRequest], False) \channels->
%	withShared default \dev->parallel
%		[ channelSync spec // unexpected disconnect
%		, watchForShutdown // unexpected disconnect
%		, watchChannels    // process messages
%		, waitForSpecification
%			>>| deviceTask
%			>>* [ifStable: issueShutdown]
%		]

\section{Lifting \texorpdfstring{\gls{MTASK}}{mTask} tasks}\label{sec:liftmtask}
Once the connection with the device is established, \gls{MTASK} tasks can be lifted to \gls{MTASK} tasks using the \cleaninline{liftmTask} family of functions (see \cref{lst:liftmtask}).
Given an \gls{MTASK} task in the \cleaninline{BCInterpret} view and a device obtained from \cleaninline{withDevice}, an \gls{ITASK} task is returned.
This \gls{ITASK} task tethers the \gls{MTASK} task that is executed on the microcontroller.
Hence, when for example observing the task value, the actual task value from the microcontroller is observed.

\begin{lstClean}[label={lst:liftmtask},caption={The interface for lifting \gls{MTASK} tasks to \gls{ITASK} tasks.}]
liftmTask :: (Main (MTask BCInterpret u)) MTDevice -> Task u | iTask u
\end{lstClean}

Under the hood, \cleaninline{liftmTask}:
\begin{itemize}
	\item Generates a fresh task identifier for the device.
	\item Compiles the task and fetches the values for the tethered \glspl{SDS}.
	\item Sends the task to the device
	\item Watches, in parallel: the tethered \glspl{SDS} in \gls{ITASK}, if they are updated, a message is sent to the device; the \gls{SDS} update queue, if there is a downstream update, the \gls{ITASK} \gls{SDS} it references is updated as well; and the task value.
\end{itemize}

The task value of the \cleaninline{liftmTask} task is the task value of the task on the edge device.

\todo{v.b.\ voor liftmtask}

\section{Lifting \texorpdfstring{\gls{ITASK}}{iTask} \texorpdfstring{\glsxtrlongpl{SDS}}{shared data sources}}\label{sec:liftsds}
Lifting \gls{ITASK} \glspl{SDS} to \gls{MTASK} \glspl{SDS} is something that mostly happens at the compiler level using the \cleaninline{liftsds} function (see \cref{lst:mtask_itasksds}).
\Glspl{SDS} in \gls{MTASK} must always have an initial value.
For regular \gls{SDS} this value is given in the source code, for lifted \gls{ITASK} \glspl{SDS} this value is obtained by reading the values once just before sending the task to the edge device.
On the device itself, there is just one difference between lifted \glspl{SDS} and regular \glspl{SDS}: after changing \pgls{SDS}, a message is sent to the server containing this new value.
The \cleaninline{withDevice} task (see \cref{sec:withdevice}) receives and processes this message by writing to the \gls{ITASK} \gls{SDS}.
Tasks watching this \gls{SDS} get notified then through the normal notification mechanism of \gls{ITASK}.

\begin{lstClean}[label={lst:mtask_itasksds},caption={Lifted \gls{ITASK} \glspl{SDS} in \gls{MTASK}.}]
class liftsds v where
	liftsds :: ((v (Sds t)) -> In (Shared sds t) (Main (MTask v u)))
		-> Main (MTask v u) | RWShared sds
\end{lstClean}

The compilation of the code and the serialisation of the data throws away all typing information.
\Glspl{SDS} are stored in the compiler state as a map from identifiers to either an initial value or an \cleaninline{MTLens}.
The \cleaninline{MTLens} is a type synonym for a \gls{SDS} that represents the typeless serialised value of the underlying \gls{SDS}.
This is done so that the \cleaninline{withDevice} task can write the received \gls{SDS} updates to the according \gls{SDS} independently.
\Gls{ITASK}'s notification mechanism then takes care of the rest.
Such a \gls{SDS} is created by using the \cleaninline{mapReadWriteError} which, given a pair of read and write functions with error handling, produces a \gls{SDS} with the lens embedded.
The read function transforms, the function that converts a typed value to a typeless serialised value, just applies the serialisation.
The write function, the function that, given the new serialised value and the old typed value, produces a new typed value.
It tries to decode the serialised value, if that succeeds, it is written to the underlying \gls{SDS}, an error is thrown otherwise.
\Cref{lst:mtask_itasksds_lens} provides the implementation for this:

% VimTeX: SynIgnore on
\begin{lstClean}[label={lst:mtask_itasksds_lens},caption={Lens applied to lifted \gls{ITASK} \glspl{SDS} in \gls{MTASK}.}]
lens :: (Shared sds a) -> MTLens | type a & RWShared sds
lens sds = mapReadWriteError
	( \r->Ok (fromString (toByteCode{|*|} r)
	, \w r-> ?Just <$> iTasksDecode (toString w)
	) ?None sds
\end{lstClean}
% VimTeX: SynIgnore off

\Cref{lst:mtask_itasksds_lift} shows the code for the implementation of \cleaninline{liftsds} that uses the \cleaninline{lens} function shown earlier.
First, the \gls{SDS} to be lifted is extracted from the expression by bootstrapping the fixed point with a dummy value.
This is safe because the expression on the right-hand side of the \cleaninline{In} is never used.
Then, using \cleaninline{addSdsIfNotExist}, the identifier for this particular \gls{SDS} is either retrieved from the compiler state or generated freshly.
This identifier is then used to provide a reference to the \cleaninline{def} definition to evaluate the main expression.

% VimTeX: SynIgnore on
\begin{lstClean}[label={lst:mtask_itasksds_lift},caption={Lens applied to lifted \gls{ITASK} \glspl{SDS} in \gls{MTASK}.}]
	liftsds def = {main =
			let (t In _) = def (abort "liftsds: expression too strict")
			in addSdsIfNotExist (Right $ lens t)
				>>= \sdsi->let (_ In e) = def (pure (Sds sdsi)) in e.main
		}
	where
\end{lstClean}
% VimTeX: SynIgnore off

\todo{v.b.\ voor lifted sdss}

\section{Home automation}
This section presents a interactive home automation program (\Cref{lst:example_home_automation}) to illustrate \gls{MTASK}'s integration with \gls{ITASK}.
It consists of a web interface for the user to control which tasks may be executed on either of two connected devices: an \gls{ARDUINO} UNO, connected via a serial port; and an ESP8266 based prototyping board called NodeMCU, connected via \gls{TCP} over WiFi.

\Crefrange{lst:example:spec1}{lst:example:spec2} show the specification for the devices followed by \crefrange{lst:example:task1}{lst:example:task2} containing the actual task.
This task first connects the devices (\crefrange{lst:example:conn1}{lst:example:conn2}) followed by a \cleaninline{parallel} task that is visualized as a tabbed window with a shutdown button to terminate the program (\crefrange{lst:example:par1}{lst:example:par2}).
The \cleaninline{chooseTask} task (\crefrange{lst:example:ct1}{lst:example:ct2}) allows the user to pick a task, sending it to the specified device.
Tasks are picked from the \cleaninline{tasks} list (\crefrange{lst:example:tasks1}{lst:example:tasks2}).
For example, the \cleaninline{temperature} task shows the current temperature to the user.
When the temperature changes, the \gls{DHT} sensor reports it and the task value for the \cleaninline{temperature} task changes.
This change in task value is reflected in the \gls{ITASK} server and the task value of the \cleaninline{liftmTask} task changes accordingly.
The task is lifted to an \gls{ITASK} task and the \cleaninline{>\&>}\footnotemark{} \gls{ITASK} combinator transforms the task value into an \gls{SDS} that is displayed to the user using \cleaninline{viewSharedInformation}.
\footnotetext{\cleaninline{(>\&>) infixl 1 :: (Task a) ((SDSLens () (? a) ()) -> Task b) -> Task b \| iTask a \& iTask b}}
Screenshots of the application are given in \cref{fig:example_screenshots}.

\begin{figure}[ht]
	\centering
	\begin{subfigure}[b]{.3\linewidth}
		\includegraphics[width=\linewidth]{home_auto1}
		\caption{Select task.}
	\end{subfigure}
	\begin{subfigure}[b]{.3\linewidth}
		\includegraphics[width=\linewidth]{home_auto2}
		\caption{Select device.}
	\end{subfigure}
	\begin{subfigure}[b]{.3\linewidth}
		\includegraphics[width=\linewidth]{home_auto3}
		\caption{View result.}
	\end{subfigure}
	\caption{Screenshots of the home automation example program in action.}%
	\label{fig:example_screenshots}
\end{figure}

\begin{figure}
	\cleaninputlisting[firstline=12,lastline=52,numbers=left,belowskip=0pt,escapeinside={/*}{*/}]{lst/example.icl}
	\begin{lstClean}[numbers=left,firstnumber=42,aboveskip=0pt,caption={An example of a home automation program.},label={lst:example_home_automation}]
		, ...][+\label{lst:example:tasks2}+]
	\end{lstClean}
\end{figure}

\section{Conclusion}


\input{subfilepostamble}
\end{document}
