+
+The \CI{deviceResource} component of the record must implement the
+\CI{MTaskDuplex} interface that provides a function that launches a \gls{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 exceptions and errors as they are
+thrown by setting the \CI{deviceError} field. All communication goes via these
+channels. To send a message to the device, the system 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 a device connected by a serial connection, 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, the compiler state (see
+Section~\ref{sec:compiler}) and the according \glspl{SDS}. Finally, it stores
+the specification of the device that is received when connecting. All of this
+is given in Listing~\ref{lst:mtaskdevice}. The definitions of the message
+format are explained in the following section.
+
+\subsection{Shares}
+The system keeps track of the \glspl{SDS} stored on
+the client in a big \gls{SDS} containing a list of devices. Client-\glspl{SDS}
+can be stored on one device at the same time. This means that if an \gls{SDS}
+updates, everyone watching it will be notified. This would result in a lot
+of notifications that are not meant for the watcher. Moreover, when a client
+updates the \gls{SDS} this is processed by the connection handler and results
+in an update of the real \gls{SDS}. Finally, the \gls{SDS} of a client must be
+synchronized with the actual device. Thus, when an \gls{iTasks}-\gls{Task}
+writes the client-\gls{SDS}, it must be propagated to the real device. There
+are several ways of tackling this problem each with their own level of
+granularity.
+
+First an actual \gls{iTasks}-\gls{SDS} for every \gls{SDS} used in a client can
+be instantiated with one \gls{iTasks}-\gls{Task} listening to the \gls{SDS} and
+synchronizing it with the device when an update occurred. This approach is very
+expensive as it requires a lot of listening \glspl{Task}.
+
+Improved on this, a single \gls{iTasks}-\gls{SDS} can be created for every
+devices that stores the respective \glspl{SDS}. Using the \CI{mapReadWrite}
+functions, a single \gls{SDS} per device can be created as a lens that allows
+mapping on a single client-\gls{SDS}. However, this approach still requires
+\glspl{Task} listening to the \gls{SDS} and when an \gls{SDS} is written,
+everyone is notified, even if the \gls{Task} only uses the value of a single
+different \gls{SDS}.
+
+Finally, the current approach --- a single \gls{SDS} for the entire system
+--- was explored. To create \glspl{SDS} per device or per client-\glspl{SDS} a
+\CI{mapReadWrite} can be used but it suffers from the same problem as mentioned
+before. Moreover, a \gls{Task} still has to watch the \gls{SDS} and communicate
+the client-\gls{SDS} updates to the actual device. Both of these problems can
+be solved by using a tailor made \gls{SDS} that heavily depends on parametric
+lenses.
+
+\subsection{Parametric Lenses}
+The type for the parametric lens of the big \gls{SDS} is \CI{Maybe
+(MTaskDevice, Int)}. The \gls{SDS} is responsible for storing the entire list
+of devices, from now on global. Moreover, the \gls{SDS} can focus on a single
+device, from now on local. A local \gls{SDS} can also specifically focus on a
+single \gls{SDS} on a single device, from now on called local-share. The
+implementation of the real \gls{SDS} is given in Listing~\ref{lst:actualdev}.
+The \gls{SDS} is a lens on an actual \gls{SDS} that writes to a file or memory.
+Reading the \gls{SDS} is nothing more than reading the real \gls{SDS}. Writing
+the \gls{SDS} is a little bit more involved. If the write operation originated
+from an \gls{SDS} focussed on a single client-\gls{SDS}, the write action must
+also be relayed to the actual device. If the write originated from an \gls{SDS}
+focussed the devices or on one device only, nothing needs to be done. The
+notification predicate determines whether a watcher gets a notification update.
+
+\begin{lstlisting}[label={lst:actualdev},%
+ caption={Device \gls{SDS}}]
+deviceStore :: RWShared (Maybe (MTaskDevice, Int)) [MTaskDevice] [MTaskDevice]
+deviceStore = SDSSource {SDSSource | name="deviceStore", read = realRead, write= realWrite}
+where
+ realRead :: (Maybe (MTaskDevice,Int)) *IWorld -> (MaybeError TaskException [MTaskDevice], *IWorld)
+ realRead p iw = read realDeviceStore iw
+
+ realWrite :: (Maybe (MTaskDevice,Int)) [MTaskDevice] *IWorld -> (MaybeError TaskException (SDSNotifyPred (Maybe (MTaskDevice,Int))), *IWorld)
+ realWrite mi w iw
+ # (merr, iw) = write w realDeviceStore iw
+ | isError merr || isNothing mi = (merr $> notifyPred mi, iw)
+ # (Just (dev, ident)) = mi
+ | ident == -1 = (merr $> notifyPred mi, iw)
+ = case find ((==)dev) w of
+ Nothing = (Error $ exception "Device lost", iw)
+ Just {deviceShares} = case find (\d->d.identifier == ident) deviceShares of
+ Nothing = (Error $ exception "Share lost", iw)
+ Just s = case sendMessagesIW [MTUpd ident s.MTaskShare.value] dev iw of
+ (Error e, iw) = (Error e, iw)
+ (Ok _, iw) = (Ok $ notifyPred mi, iw)
+
+ notifyPred :: (Maybe (MTaskDevice, Int)) (Maybe (MTaskDevice, Int)) -> Bool
+ notifyPred Nothing Nothing = True // Global watcher looking at a global event
+ notifyPred Nothing (Just _) = False // Global watcher looking at a local event
+ notifyPred (Just _) Nothing = False // Local watcher looking at a global event
+ // Local device watcher looking at a local event
+ notifyPred (Just (d1, -1)) (Just (d2, _)) = d1 == d2
+ // Local share watcher looking at a local share event
+ notifyPred (Just (d1, i1)) (Just (d2, i2)) = d1 == d2 && i1 == i2
+
+ realDeviceStore :: Shared [MTaskDevice]
+ realDeviceStore = sharedStore "mTaskDevices" []
+\end{lstlisting}
+
+\subsubsection{Global \glspl{SDS}}
+Accessing the global \gls{SDS} is just a matter of focussing the
+\CI{deviceStore} with the \CI{Nothing} parameter as follows:
+
+\begin{lstlisting}[caption={Global \gls{SDS}}]
+deviceStoreNP :: Shared [MTaskDevice]
+deviceStoreNP = sdsFocus Nothing deviceStore
+\end{lstlisting}
+
+\subsubsection{Local \glspl{SDS}}
+Accessing a single device can be done using the \CI{mapReadWrite} function.
+Since device comparison is shallow, the device that is given is allowed to be
+an old version. The identification of devices is solely done on the name of the
+channels and is unique throughout the system. The implementation is as follows:
+
+\begin{lstlisting}[caption={Local \gls{SDS}}]
+deviceShare :: MTaskDevice -> Shared MTaskDevice
+deviceShare d = mapReadWriteError
+ ( \ds->case find ((==)d) of
+ Nothing = exception "Device lost"
+ Just d = Ok d)
+ , \w ds->case splitWith ((==)d) ds of
+ ([], _) = Error $ exception "Device lost"
+ ([_:_], ds) = Ok $ Just [w:ds])
+ $ sdsFocus (Just (d, -1)) deviceStore
+\end{lstlisting}
+
+\subsubsection{Local-\gls{SDS} specific \glspl{SDS}}
+A single \gls{SDS} on a single device can be accessed using the \CI{shareShare}
+function. This function focusses the real big \gls{SDS} on a single \gls{SDS}
+and uses the \CI{mapReadWrite} functions to serve the correct part of the
+information.
+
+\begin{lstlisting}[caption={Local \gls{SDS}}]
+shareShare :: MTaskDevice MTaskShare -> Shared BCValue
+shareShare dev share = sdsFocus ()
+ $ mapReadWriteError (read, write)
+ $ sdsFocus (Just (dev, share.identifier))
+ $ deviceStore
+where
+ read :: [MTaskDevice] -> MaybeError TaskException BCValue
+ read devs = case find ((==)dev) devs of
+ Nothing = exception "Device lost"
+ Just d = case find ((==)share) d.deviceShares of
+ Nothing = exception "Share lost"
+ Just s = Ok s.MTaskShare.value
+
+ write :: BCValue [MTaskDevice] -> MaybeError TaskException (Maybe [MTaskDevice])
+ write val devs = case partition ((==)dev) devs of
+ ([], _) = Error $ exception "Device doesn't exist anymore"
+ ([_,_:_], _) = Error $ exception "Multiple matching devices"
+ ([d=:{deviceShares}], devs) = case partition ((==)share) deviceShares of
+ ([], _) = Error $ exception "Share doesn't exist anymore"
+ ([_,_:_], _) = Error $ exception "Multiple matching shares"
+ ([s], shares) = Ok $ Just [{MTaskDevice | d &
+ deviceShares=[{MTaskShare | s & value=val}:shares]}:devs]
+\end{lstlisting}
+
+\section{Communication}
+The communication from the server to the client and vice versa is just a
+character stream containing encoded \gls{mTask} messages. The \CI{synFun}
+belonging to the device is responsible for sending the content in the left
+channel and putting received messages in the right channel. Moreover, the
+boolean value should be set to \CI{True} when the connection is terminated. The
+specific encoding of the messages is visible in
+Appendix~\ref{app:communication-protocol}. The type holding the messages is
+shown in Listing~\ref{lst:avmsg}. Detailed explanation about the message types
+and according actions will be given in the following subsections.
+
+\begin{lstlisting}[label={lst:avmsg},caption={Available messages}]
+:: MTaskId :== Int
+:: MSDSId :== Int
+:: MTaskFreeBytes :== Int
+:: MTaskMSGRecv
+ = MTTaskAck MTaskId MTaskFreeBytes | MTTaskDelAck MTaskId
+ | MTSDSAck MSDSId | MTSDSDelAck MSDSId
+ | MTPub MSDSId BCValue | MTMessage String
+ | MTDevSpec MTaskDeviceSpec | MTEmpty
+
+:: MTaskMSGSend
+ = MTTask MTaskInterval String | MTTaskDel MTaskId
+ | MTShutdown | MTSds MSDSId BCValue
+ | MTUpd MSDSId 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} (\CI{synFun}), 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 device functionality
+heavily depends on the specific \CI{deviceShare} function that generates an
+\gls{SDS} for a specific device. This allows giving an old device record to the
+function and still update the latest instance. Listing~\ref{lst:connectDevice}
+shows the connection function.
+
+\begin{lstlisting}[label={lst:connectDevice},%
+ caption={Connect a device}]
+connectDevice :: (MTaskDevice (Shared Channels) -> Task ()) MTaskDevice -> Task Channels
+connectDevice procFun device = let ch = channels device
+ in traceValue "connectDevice" >>| appendTopLevelTask 'DM'.newMap True
+ ( procFun device ch -||- catchAll (getSynFun device.deviceData ch) errHdl)
+ >>= \tid->upd (\d->{d&deviceTask=Just tid,deviceError=Nothing}) (deviceShare device)
+ >>| upd (\(r,s,ss)->(r,s++[MTSpec],ss)) ch
+where
+ errHdl e = upd (\d->{d & deviceTask=Nothing, deviceError=Just e}) (deviceShare device) @! ()
+\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]
+ \centering
+ \begin{sequencediagram}
+ \newthread{s}{Server}
+ \newinst[4]{c}{Client}
+ \begin{call}{s}{MTSpec}{c}{MTDevSpec}
+ \end{call}
+ \end{sequencediagram}
+ \caption{Connect a device}\label{fig:handshake}
+\end{figure}
+
+\subsection{\glspl{Task} \& \glspl{SDS}}
+When a \gls{Task} is sent to the device it is added to the device record
+without an identifier. The actual identifier is added to the record when the
+acknowledgement of the \gls{Task} by the device is received. The connection
+diagram is shown in Figure~\ref{fig:tasksend}.
+
+\begin{figure}[H]
+ \centering
+ \begin{sequencediagram}
+ \newthread{s}{Server}
+ \newinst[4]{c}{Client}
+ \begin{call}{s}{MTSDS}{c}{MTSDSAck}
+ \end{call}
+ \begin{call}{s}{MTTask}{c}{MTTaskAck}
+ \end{call}
+ \end{sequencediagram}
+ \caption{Sending a \gls{Task} to a device}\label{fig:tasksend}
+\end{figure}
+
+The function for sending a \gls{Task} to the device is shown in
+Listing~\ref{lst:sendtask}. First the \gls{Task} is compiled into messages. The
+details of the compilation process are given in Section~\ref{sec:compiler}.
+The new \glspl{SDS} that were generated during compilation are merged with the
+existing device's \glspl{SDS}. Furthermore the messages are placed in the
+channel \gls{SDS} of the device. This will result in sending the actual \gls{SDS}
+specification and \gls{Task} specifications to the device. A \gls{Task} record
+is created with the identifier $-1$ to denote a \gls{Task} not yet
+acknowledged. Finally the device itself is updated with the new state and with
+the new \gls{Task}. After waiting for the acknowledgement the device is
+updated again and the \gls{Task} returns.
+
+\begin{lstlisting}[label={lst:sendtask},%
+ caption={Sending a \gls{Task} to a device}]
+makeTask :: String Int -> Task MTaskTask
+makeTask name ident = get currentDateTime @ \dt->{MTaskTask | name=name, ident=ident, dateAdded=dt}
+
+makeShare :: String Int BCValue -> MTaskShare
+makeShare withTask identifier value = {MTaskShare | withTask=[withTask], identifier=identifier, value=value}
+
+sendTaskToDevice :: String (Main (ByteCode a Stmt)) (MTaskDevice, MTaskInterval) -> Task MTaskTask
+sendTaskToDevice wta mTask (device, timeout)
+# (msgs, newState=:{sdss}) = toMessages timeout mTask device.deviceState
+# shares = [makeShare wta "" sdsi sdsval\\{sdsi,sdsval}<-sdss, (MTSds sdsi` _)<-msgs | sdsi == sdsi`]
+= updateShares device ((++) shares)
+ >>| sendMessages msgs device
+ >>| makeTask wta -1
+ >>= \t->upd (addTaskUpState newState t) (deviceShare device)
+ >>| wait "Waiting for task to be acked" (taskAcked t) (deviceShare device)
+ >>| treturn t
+where
+ addTaskUpState :: BCState MTaskTask MTaskDevice -> MTaskDevice
+ addTaskUpState st task device = {MTaskDevice | device & deviceState=st, deviceTasks=[task:device.deviceTasks]}
+ taskAcked t d = maybe True (\t->t.ident <> -1) $ find (eq t) d.deviceTasks
+ eq t1 t2 = t1.dateAdded == t2.dateAdded && t1.MTaskTask.name == t2.MTaskTask.name
+\end{lstlisting}
+
+\subsection{Miscellaneous Messages}
+One special type of message is available which is sent to the device only when
+it needs to reboot. When the server wants to stop the bond with the device it
+sends the \CI{MTShutdown} message. The device will then clear its memory, thus
+losing all the \glspl{SDS} and \glspl{Task} that were stored and reset itself.
+Shortly after the shutdown message a new server can connect to the device
+because the device is back in listening mode.
+
+\subsection{Integration}
+When the system starts up, the devices from the previous execution still
+residing in the \gls{SDS} must be cleaned up. It might be the case that they
+contain \glspl{Task}, \glspl{SDS} or errors that are no longer applicable in
+this run. A user or programmer can later choose to reconnect to some devices.
+
+\begin{lstlisting}[caption={Starting up the devices},%
+ label={lst:startupdevs}]
+startupDevices :: Task [MTaskDevice]
+startupDevices = upd (map reset) deviceStoreNP
+ where reset d = {d & deviceTask=Nothing, deviceTasks=[], deviceError=Nothing}
+\end{lstlisting}
+
+The system's management is done through the interface of a single \gls{Task}
+called \CI{mTaskManager}. To manage the system, a couple of different
+functionalities are necessary and are launched. An image of the management
+interface is shown in Figure~\ref{lst:manage}. The left sidebar of the
+interface shows the list of example \glspl{Task} that are present in the
+system. When clicking a \gls{Task}, a dialog opens in which a device can be
+selected to send the \gls{Task} to. The dialog might contain user specified
+variables. All example \gls{mTask}-\glspl{Task} are of the type \CI{Task (Main
+(ByteCode () Stmt))} and can thus ask for user input first if needed for
+parameterized \gls{mTask}-\glspl{Task}. The bottom panel shows the device
+information. In this panel, the devices can be created and modified. Moreover,
+this panel allows the user to reconnect with a device after a restart of the
+server application.
+
+\begin{figure}[H]
+ \centering
+ \includegraphics[width=\linewidth]{manage}
+ \caption{The device management interface}\label{lst:manage}
+\end{figure}
+
+\section[Lifting mTasks to iTasks-Tasks]%
+ {Lifting \gls{mTask}-\glspl{Task} to \gls{iTasks}-\glspl{Task}}
+If the user does not want to know where and when a \gls{mTask} is actually
+executed and is just interested in the results it can lift the \gls{mTask} to
+an \gls{iTasks}-\glspl{Task}. The function is called with a name, \gls{mTask},
+device and interval specification and it will return a \gls{Task} that finishes
+if and only if the \gls{mTask} has returned.
+
+\begin{lstlisting}[caption={Starting up the devices}]
+liftmTask :: String (Main (ByteCode () Stmt)) (MTaskDevice, MTaskInterval) -> Task ()
+liftmTask wta mTask c=:(dev, _)= sendTaskToDevice wta mTask c
+ >>= \t->wait "Waiting for mTask to return" (taskRemoved t) (deviceShare dev)
+ >>| viewInformation "Done!" [] ()
+where
+ taskRemoved t d = isNothing $ find (\t1->t1.ident==t.ident) d.deviceTasks
+\end{lstlisting}
+
+\section{Examples}
+\todo{example program (demo)}