roy's comments: chapter 5
[msc-thesis1617.git] / results.arch.tex
1 The goal of the total system is to facilitate an ecosystem in which an
2 \gls{iTasks}-system can add, change and remove devices at runtime. Moreover,
3 the \gls{iTasks}-system can send \glspl{mTask} --- compiled at runtime to
4 bytecode by the \gls{mTask}-view --- to the device. The device runs an
5 interpreter which can execute the \gls{Task}'s bytecode. Device profiles should
6 be persistent during reboots of the \gls{iTasks}-system. The methods of
7 interacting with \glspl{mTask} should be analogous to interacting with
8 \gls{iTasks}-\glspl{Task}. Meaning that programmers can access the \glspl{SDS}
9 made for a device in the same way as a regular \gls{SDS} and they can execute
10 \glspl{mTask} as if it where a normal \gls{iTasks}-\gls{Task}.
11
12 The following terms will be used throughout the following chapter:
13 \begin{itemize}
14 \item Device, Client
15
16 This denotes the actual device connected to the system. This can be a
17 real device such as a microcontroller but it can also just be a program
18 on the same machine as the server functioning as a client.
19 \item Server, \gls{iTasks}-System
20
21 This is the actual executable serving the \gls{iTasks} application. The
22 system contains \glspl{Task} taking care of the communication with the
23 clients.
24 \item System
25
26 The system describes the complete ecosystem, containing both the server
27 and the clients including the communication between them.
28 \item Engine
29
30 The runtime system of the client is called the engine. This program
31 handles communicating with the server and runs the interpreter for the
32 \glspl{Task} on the client.
33 \end{itemize}
34
35 \section{Devices}
36 A device is suitable for the system if it can run the engine.
37 The engine is compiled from one codebase and devices implement (part of) the
38 device specific interface. The shared codebase only uses standard \gls{C} and
39 no special libraries or tricks are used. Therefore, the code is compilable for
40 almost any device or system. Note that it is not needed to implement a full
41 interface. The full interface --- excluding the device specific settings --- is
42 listed in Appendix~\ref{app:device-interface}. The interface works in a
43 similar fashion as the \gls{EDSL}. Devices do not have to implement all
44 functionality, this is analogous to the fact that views do not have to
45 implement all type classes in the \gls{EDSL}. When the device connects for the
46 first time with a server the specifications of what is implemented is
47 communicated.
48
49 At the time of writing the following device families are supported and can run
50 the device software.
51 \begin{itemize}
52 \item \texttt{POSIX} compatible systems connected via \gls{TCP}.
53
54 This includes systems running \emph{Linux} and \emph{MacOS}.
55 \item \texttt{STM32} family microcontrollers supported by \texttt{ChibiOS}
56 connected via serial communication.
57
58 This is tested in particular on the \texttt{STM32f7x} series \gls{ARM}
59 development board.
60 \item Microcontrollers who are programmable in the \gls{Arduino} \gls{IDE}
61 connected via serial communication or via \gls{TCP} over WiFi.
62
63 This does not only include \gls{Arduino} compatible boards but also
64 other boards capable of running \gls{Arduino} code. A port of the
65 client has been made for the \texttt{ESP8266} powered \emph{NodeMCU}
66 that is connected via \gls{TCP} over WiFi. A port also has been made
67 for the regular \gls{Arduino} \emph{UNO} board which only boasts a
68 meager \emph{2K} of \emph{RAM}. The stack size and storage for such
69 small amount of \emph{RAM} have to be smaller than default but it still
70 suitable to hold a hand full of \glspl{Task}.
71 \end{itemize}
72
73 \subsection{Client}
74 \subsubsection{Engine}
75 The client is in a constant loop listening for input and waiting to execute
76 \gls{Task}. The pseudocode for this is shown in Algorithm~\ref{alg:client}. The
77 \CI{input\_available} function waits for input, but has a timeout set which can
78 be interrupted. The timeout of the function determines the amount of loops per
79 time interval and is a parameter that can be set during compilation for a
80 device.
81
82 \begin{algorithm}[H]
83 \KwData{
84 \textbf{list} $tasks$,
85 \textbf{time} $t$
86 }
87
88 \Begin{
89 \While{true}{
90 \If{input\_available$()$}{
91 receive\_data()\;
92 }
93
94 $t\leftarrow \text{now}()$\;
95 \ForEach{$t\leftarrow tasks$}{
96 \uIf{is\_interrupt$(t) \&\& $had\_interrupt$(t)$}{
97 run\_task$(t)$\;
98 }
99 \ElseIf{$t-t.\text{lastrun} > t.\text{interval}$}{
100 run\_task$(t)$\;
101 \uIf{$t.\text{interval}==0$}{
102 delete\_task$(t)$\;
103 }\Else{
104 $t.\text{lastrun}\leftarrow t$\;
105 }
106 }
107 }
108 }
109 }
110 \caption{Engine pseudocode}\label{alg:client}
111 \end{algorithm}
112
113 \subsubsection{Storage}
114 \glspl{Task} and \glspl{SDS} are stored on the client in one big memory space
115 that is reserved at the start of the program. The space could also have been
116 dynamically allocated but that would require using the heap which is unwanted
117 in small memory environments. \Glspl{Task} grow from the bottom up and
118 \glspl{SDS} grow from the top down. When a \gls{Task} or \gls{SDS} is removed,
119 all \glspl{Task} are relocated in the memory space to not leave holes. Both
120 \glspl{Task} and \glspl{SDS} are stored as structures that are linked in the
121 memory space, helper functions are available to loop through them without
122 having to fiddle in the memory space itself. The instance for \glspl{Task} and
123 \glspl{SDS} are shown in Listing~\ref{lst:structs} accompanied by the helper
124 functions for \glspl{Task}. \Glspl{Task} consist the length, interval, last run
125 time, id and the bytecode. \Glspl{SDS} consist just of an id, value and type.
126 The pointer to the bytecode of the \gls{Task} always points to the location in
127 the memory space.
128
129 \begin{lstlisting}[language=C,label={lst:structs},%
130 caption={The data type storing the \glspl{Task}}]
131 struct task {
132 uint16_t tasklength;
133 uint16_t interval;
134 unsigned long lastrun;
135 uint8_t taskid;
136 uint8_t *bc;
137 };
138
139 struct task *task_head(void);
140 struct task *task_next(struct task *t);
141
142 struct sds {
143 int id;
144 int value;
145 char type;
146 };
147
148 struct sds *sds_head(void);
149 struct sds *sds_next(struct sds *s);
150 \end{lstlisting}
151
152 \subsubsection{Interpretation}
153 The execution of a \gls{Task} is started by running the \CI{run\_task} function
154 and always start with prepared the stack and the program counter and stack
155 pointer are set to zero and the bottom respectively. When finished, the
156 interpreter executes one step at the time while the program counter is smaller
157 than the program length. The code for this is listed in
158 Listing~\ref{lst:interpr}. One execution step is basically a big switch
159 statement going over all possible bytecode instructions. Some instructions are
160 detailed upon in the listing. The \CI{BCPush} instruction is a little more
161 complicated in the real code because some decoding will take place as not all
162 \CI{BCValue}s are of the same length and are encoded.
163
164 \begin{lstlisting}[language=C,label={lst:interpr},%
165 caption={Rough code outline for interpretation}]
166 #define f16(p) program[pc]*265+program[pc+1]
167
168 void run_task(struct task *t){
169 uint8_t *program = t->bc;
170 int plen = t->tasklength;
171 int pc = 0;
172 int sp = 0;
173 while(pc < plen){
174 switch(program[pc++]){
175 case BCNOP:
176 break;
177 case BCPUSH:
178 stack[sp++] = pc++ //Simplified
179 break;
180 case BCPOP:
181 sp--;
182 break;
183 case BCSDSSTORE:
184 sds_store(f16(pc), stack[--sp]);
185 pc+=2;
186 break;
187 // ...
188 case BCADD: trace("add");
189 stack[sp-2] = stack[sp-2] + stack[sp-1];
190 sp -= 1;
191 break;
192 // ...
193 case BCJMPT: trace("jmpt to %d", program[pc]);
194 pc = stack[--sp] ? program[pc]-1 : pc+1;
195 break;
196 }
197 \end{lstlisting}
198
199 \subsection{Specification}
200 The server stores a description for every device available in a record type.
201 From the macro settings in the interface file, a profile is created that
202 describes the specification of the device. When the connection between the
203 server and a client is established, the server will send a request for
204 specification. The client will serialize his specification and send it to the
205 server so that the server knows what the client is capable of. The exact
206 specification is shown in Listing~\ref{lst:devicespec} and stores the
207 peripheral availability, the memory available for storing \glspl{Task} and
208 \glspl{SDS} and the size of the stack.
209
210 \begin{lstlisting}[label={lst:devicespec},
211 caption={Device specification for \glspl{mTask}}]
212 :: MTaskDeviceSpec =
213 { haveLed :: Bool
214 , haveLCD :: Bool
215 , have...
216 , bytesMemory :: Int
217 , stackSize :: Int
218 , aPins :: Int
219 , dPins :: Int
220 }
221 \end{lstlisting}
222
223 \section{iTasks}
224 The server part of the system is written in \gls{iTasks}. Functions for
225 managing devices, \glspl{Task} and \glspl{SDS} have been created to support the
226 functionality. An interactive application has been created that allows an
227 interactive management console for the \gls{mTask} system. This interface
228 provides functionality to list \glspl{SDS}, add \glspl{Task}, remove
229 \glspl{Task}, administrate devices and view the state of the system.
230
231 \subsection{Device Storage}
232 Everything that a device encompasses is stored in the \CI{MTaskDevice} record
233 type. This includes management for the \glspl{SDS} and \glspl{Task} stored on
234 the device. The \CI{MTaskDevice} definition is shown in
235 Listing~\ref{lst:mtaskdevice} accompanied with the necessary classes and sub
236 types.
237
238 \begin{lstlisting}[caption={Device type},label={lst:mtaskdevice}]
239 :: Channels :== ([MTaskMSGRecv], [MTaskMSGSend], Bool)
240 :: BCState = ... // Compiler state, explained in later sections
241 :: MTaskResource
242 = TCPDevice TCPSettings
243 | SerialDevice TTYSettings
244 | ...
245 :: MTaskDevice =
246 { deviceTask :: Maybe TaskId
247 , deviceError :: Maybe String
248 , deviceChannels :: String
249 , deviceName :: String
250 , deviceState :: BCState
251 , deviceTasks :: [MTaskTask]
252 , deviceData :: MTaskResource
253 , deviceSpec :: Maybe MTaskDeviceSpec
254 , deviceShares :: [MTaskShare]
255 }
256
257 channels :: MTaskDevice -> Shared Channels
258
259 class MTaskDuplex a where
260 synFun :: a (Shared Channels) -> Task ()
261 \end{lstlisting}
262
263 The \CI{deviceResource} component of the record must implement the
264 \CI{MTaskDuplex} interface that provides a function that launches a \gls{Task}
265 used for synchronizing the channels. The \CI{deviceTask} stores the
266 \gls{Task}-id for this \gls{Task} when active so that it can be checked upon.
267 This top-level task has the duty to report exceptions and errors as they are
268 thrown by setting the \CI{deviceError} field. All communication goes via these
269 channels. If the system wants to send a message to the device, it just puts it
270 in the channels. Messages sent from the client to the server are also placed
271 in there. In the case of the \gls{TCP} device type, the \gls{Task} is just a
272 simple wrapper around the existing \CI{tcpconnect} function in \gls{iTasks}. In
273 case of a device connected by a serial connection, it uses the newly developed
274 serial port library of \gls{Clean}\footnote{\url{%
275 https://gitlab.science.ru.nl/mlubbers/CleanSerial}}.
276
277 Besides all the communication information, the record also keeps track of the
278 \glspl{Task} currently on the device, the compiler state (see
279 Section~\ref{sec:compiler}) and the according \glspl{SDS}. Finally, it stores
280 the specification of the device that is received when connecting. All of this
281 is given in Listing~\ref{lst:mtaskdevice}. The definitions of the message
282 format are explained in the following section.
283
284 \subsection{Shares}
285 The architecture of the system keeps track of the \glspl{SDS} stored on
286 the client in a big \gls{SDS} containing a list of devices. Client-\glspl{SDS}
287 can be stored on one device at the same time. This means that if a \gls{SDS}
288 updates, everyone watching it will be notified. This would result in to a lot
289 of notifications that are not meant for the listener. Moreover, when a client
290 updates the \gls{SDS} this is processed by the connection handler and results
291 in an update of the real \gls{SDS}. Finally, the \gls{SDS} of a client must be
292 synchronized with the actual device. Thus, when an \gls{iTasks}-\gls{Task}
293 writes the client-\gls{SDS}, it must be propagated to the real device. There
294 are several ways of tackling this problem each with their own pros and cons and
295 their own level of abstraction.
296
297 First an actual \gls{iTasks}-\gls{SDS} for every \gls{SDS} used in a client can
298 be instantiated with one \gls{iTasks}-\gls{Task} listening to the \gls{SDS} and
299 synchronizing it with the device when an update occured. This approach is very
300 expensive as it requires a lot of listening \glspl{Task}.
301
302 Improved on this, a single \gls{iTasks}-\gls{SDS} can be created for every
303 devices that stores the respective \glspl{SDS}. Using the \CI{mapReadWrite}
304 functions, a single \gls{SDS} per device can be created as a lens that allows
305 mapping on a single client-\gls{SDS}. However, This approach still requires
306 \glspl{Task} listening to the \gls{SDS} and when a \gls{SDS} is written,
307 everyone is notified, even if the \gls{Task} wanted to only watch a single
308 different \gls{SDS}.
309
310 Ultimately, the current approach --- a single \gls{SDS} for the entire system
311 --- was explored. To create \glspl{SDS} per device or per client-\glspl{SDS} a
312 \CI{mapReadWrite} can be used but it suffers the same problem as mentioned
313 before. Moreover, a \gls{Task} still has to watch the \gls{SDS} and communicate
314 the client-\gls{SDS} updates to the actual device. Both of these problems can
315 be solved by using a tailor made share that heavily depends on parametric
316 lenses.
317
318 \subsection{Parametric Lenses}
319 The type of the parametric lens is \CI{Maybe (MTaskDevice, Int)}. The \gls{SDS}
320 can be responsible for the entire list of devices, from now on global.
321 Moreover, the \gls{SDS} can focus on a single device, from now on local. A
322 local \gls{SDS} can also specifically focus on a single \gls{SDS} on a single
323 device, from now on called local-share. The implementation of the real
324 \gls{SDS} is given in Listing~\ref{lst:actualdev}. The \gls{SDS} is a lens on
325 an actual \gls{SDS} that writes to a file or memory. Reading the \gls{SDS} is
326 nothing more than reading the real \gls{SDS}. Writing the \gls{SDS} is a little
327 bit more involved. If the write operation originated from a \gls{SDS} focussed
328 on a single client-\gls{SDS}, the write action must also be relayed to the
329 actual device. If the write originated from a \gls{SDS} focussed the devices or
330 on one device only, nothing needs to be done. The notification predicate
331 determines whether a watcher gets a notification update.
332
333 \begin{lstlisting}[label={lst:actualdev},%
334 caption={Device \gls{SDS}}]
335 deviceStore :: RWShared (Maybe (MTaskDevice, Int)) [MTaskDevice] [MTaskDevice]
336 deviceStore = SDSSource {SDSSource | name="deviceStore", read = realRead, write= realWrite}
337 where
338 realRead :: (Maybe (MTaskDevice,Int)) *IWorld -> (MaybeError TaskException [MTaskDevice], *IWorld)
339 realRead p iw = read realDeviceStore iw
340
341 realWrite :: (Maybe (MTaskDevice,Int)) [MTaskDevice] *IWorld -> (MaybeError TaskException (SDSNotifyPred (Maybe (MTaskDevice,Int))), *IWorld)
342 realWrite mi w iw
343 # (merr, iw) = write w realDeviceStore iw
344 | isError merr || isNothing mi = (merr $> notifyPred mi, iw)
345 # (Just (dev, ident)) = mi
346 | ident == -1 = (merr $> notifyPred mi, iw)
347 = case find ((==)dev) w of
348 Nothing = (Error $ exception "Device lost", iw)
349 Just {deviceShares} = case find (\d->d.identifier == ident) deviceShares of
350 Nothing = (Error $ exception "Share lost", iw)
351 Just s = case sendMessagesIW [MTUpd ident s.MTaskShare.value] dev iw of
352 (Error e, iw) = (Error e, iw)
353 (Ok _, iw) = (Ok $ notifyPred mi, iw)
354
355 notifyPred :: (Maybe (MTaskDevice, Int)) (Maybe (MTaskDevice, Int)) -> Bool
356 notifyPred Nothing Nothing = True // Global watcher looking at a global event
357 notifyPred Nothing (Just _) = False // Global watcher looking at a local event
358 notifyPred (Just _) Nothing = False // Local watcher looking at a global event
359 // Local device watcher looking at a local event
360 notifyPred (Just (d1, -1)) (Just (d2, _)) = d1 == d2
361 // Local share watcher looking at a local share event
362 notifyPred (Just (d1, i1)) (Just (d2, i2)) = d1 == d2 && i1 == i2
363
364 realDeviceStore :: Shared [MTaskDevice]
365 realDeviceStore = sharedStore "mTaskDevices" []
366 \end{lstlisting}
367
368 \subsubsection{Global \glspl{SDS}}
369 Accessing the global \gls{SDS} is just a matter of focussing the
370 \CI{deviceStore} with the \CI{Nothing} parameter as follows:
371
372 \begin{lstlisting}[caption={Global \gls{SDS}}]
373 deviceStoreNP :: Shared [MTaskDevice]
374 deviceStoreNP = sdsFocus Nothing deviceStore
375 \end{lstlisting}
376
377 \subsubsection{Local \glspl{SDS}}
378 Accessing a single device can be done using the \CI{mapReadWrite} function.
379 Since device comparison is shallow, the device that is given is allowed to be
380 an old version. The identification of devices is solely done on the name of the
381 channels and is unique throughout the system. The implementation is as follows:
382
383 \begin{lstlisting}[caption={Local \gls{SDS}}]
384 deviceShare :: MTaskDevice -> Shared MTaskDevice
385 deviceShare d = mapReadWriteError
386 ( \ds->case find ((==)d) of
387 Nothing = exception "Device lost"
388 Just d = Ok d)
389 , \w ds->case splitWith ((==)d) ds of
390 ([], _) = Error $ exception "Device lost"
391 ([_:_], ds) = Ok $ Just [w:ds])
392 $ sdsFocus (Just (d, -1)) deviceStore
393 \end{lstlisting}
394
395 \subsubsection{Local-share specific \glspl{SDS}}
396 A single \gls{SDS} on a single device can be accessed using the \CI{shareShare}
397 function. This function focusses the real big \gls{SDS} on a single share and
398 uses the \CI{mapReadWrite} functions to serve the correct part of the
399 information.
400
401 \begin{lstlisting}[caption={Local \gls{SDS}}]
402 shareShare :: MTaskDevice MTaskShare -> Shared BCValue
403 shareShare dev share = sdsFocus ()
404 $ mapReadWriteError (read, write)
405 $ sdsFocus (Just (dev, share.identifier))
406 $ deviceStore
407 where
408 read :: [MTaskDevice] -> MaybeError TaskException BCValue
409 read devs = case find ((==)dev) devs of
410 Nothing = exception "Device lost"
411 Just d = case find ((==)share) d.deviceShares of
412 Nothing = exception "Share lost"
413 Just s = Ok s.MTaskShare.value
414
415 write :: BCValue [MTaskDevice] -> MaybeError TaskException (Maybe [MTaskDevice])
416 write val devs = case partition ((==)dev) devs of
417 ([], _) = Error $ exception "Device doesn't exist anymore"
418 ([_,_:_], _) = Error $ exception "Multiple matching devices"
419 ([d=:{deviceShares}], devs) = case partition ((==)share) deviceShares of
420 ([], _) = Error $ exception "Share doesn't exist anymore"
421 ([_,_:_], _) = Error $ exception "Multiple matching shares"
422 ([s], shares) = Ok $ Just [{MTaskDevice | d &
423 deviceShares=[{MTaskShare | s & value=val}:shares]}:devs]
424 \end{lstlisting}
425
426 \section{Communication}
427 The communication from the server to the client and vice versa is just a
428 character stream containing encoded \gls{mTask} messages. The \CI{synFun}
429 belonging to the device is responsible for sending the content in the left
430 channel and putting received messages in the right channel. Moreover, it should
431 set the boolean value to \CI{True} when the connection is terminated. The
432 specific encoding of the messages is visible in
433 Appendix~\ref{app:communication-protocol}. The type holding the messages in
434 Listing~\ref{lst:avmsg}. Detailed explanation about the message types and
435 according actions will be given in the following subsections.
436
437 \begin{lstlisting}[label={lst:avmsg},caption={Available messages}]
438 :: MTaskId :== Int
439 :: MSDSId :== Int
440 :: MTaskFreeBytes :== Int
441 :: MTaskMSGRecv
442 = MTTaskAck MTaskId MTaskFreeBytes | MTTaskDelAck MTaskId
443 | MTSDSAck MSDSId | MTSDSDelAck MSDSId
444 | MTPub MSDSId BCValue | MTMessage String
445 | MTDevSpec MTaskDeviceSpec | MTEmpty
446
447 :: MTaskMSGSend
448 = MTTask MTaskInterval String | MTTaskDel MTaskId
449 | MTShutdown | MTSds MSDSId BCValue
450 | MTUpd MSDSId BCValue | MTSpec
451
452 :: MTaskInterval = OneShot | OnInterval Int | OnInterrupt Int
453 \end{lstlisting}
454
455 \subsection{Add a device}
456 A device can be added by filling in the \CI{MTaskDevice} record as much as
457 possible and running the \CI{connectDevice} function. This function grabs the
458 channels, starts the synchronization \gls{Task} (\CI{synFun}), makes sure the
459 errors are handled when needed and runs a processing function in parallel to
460 react on the incoming messages. Moreover, it sends a specification request to
461 the device in question to determine the details of the device and updates the
462 record to contain the top-level \gls{Task}-id. All the device functionality
463 heavily depends on the specific \CI{deviceShare} function that generates a
464 \gls{SDS} for a specific device. This allows giving an old device record to the
465 function and still update the latest instance. Listing~\ref{lst:connectDevice}
466 shows the connection function.
467
468 \begin{lstlisting}[label={lst:connectDevice},%
469 caption={Connect a device}]
470 connectDevice :: (MTaskDevice (Shared Channels) -> Task ()) MTaskDevice -> Task Channels
471 connectDevice procFun device = let ch = channels device
472 in traceValue "connectDevice" >>| appendTopLevelTask 'DM'.newMap True
473 ( procFun device ch -||- catchAll (getSynFun device.deviceData ch) errHdl)
474 >>= \tid->upd (\d->{d&deviceTask=Just tid,deviceError=Nothing}) (deviceShare device)
475 >>| upd (\(r,s,ss)->(r,s++[MTSpec],ss)) ch
476 where
477 errHdl e = upd (\d->{d & deviceTask=Nothing, deviceError=Just e}) (deviceShare device) @! ()
478 \end{lstlisting}
479
480 Figure~\ref{fig:handshake} shows the connection diagram. The client responds to
481 the server with their device specification. This is detected by the processing
482 function and the record is updated accordingly.
483
484 \begin{figure}[H]
485 \centering
486 \begin{sequencediagram}
487 \newthread{s}{Server}
488 \newinst[4]{c}{Client}
489 \begin{call}{s}{MTSpec}{c}{MTDevSpec}
490 \end{call}
491 \end{sequencediagram}
492 \caption{Connect a device}\label{fig:handshake}
493 \end{figure}
494
495 \subsection{\glspl{Task} \& \glspl{SDS}}
496 When a \gls{Task} is sent to the device it is added to the device record
497 without an identifier. The actual identifier is added to the record when the
498 acknowledgement of the \gls{Task} by the device is received. The connection
499 diagram is shown in Figure~\ref{fig:tasksend}.
500
501 \begin{figure}[H]
502 \centering
503 \begin{sequencediagram}
504 \newthread{s}{Server}
505 \newinst[4]{c}{Client}
506 \begin{call}{s}{MTSDS}{c}{MTSDSAck}
507 \end{call}
508 \begin{call}{s}{MTTask}{c}{MTTaskAck}
509 \end{call}
510 \end{sequencediagram}
511 \caption{Sending a \gls{Task} to a device}\label{fig:tasksend}
512 \end{figure}
513
514 The function for sending a \gls{Task} to the device is shown in
515 Listing~\ref{lst:sendtask}. First the \gls{Task} is compiled into messages. The
516 details of the compilation process are given in Section~\ref{sec:compiler}.
517 The new \glspl{SDS} that were made during compilation are added to the
518 deviceshares that were made during the compilation are merged with the existing
519 shares on the device. Furthermore the messages are placed in the channel share
520 of the device. This will result in sending the actual \gls{SDS} specification
521 and \gls{Task} specifications to the device. A \gls{Task} record is created
522 with the identifier $-1$ to denote a \gls{Task} not yet acknowledged. Finally
523 the device itself is updated with the new state and with the new \gls{Task}.
524 After waiting for the acknowledgement the device is updated again and the
525 \gls{Task} returns.
526
527 \begin{lstlisting}[label={lst:sendtask},%
528 caption={Sending a \gls{Task} to a device}]
529 makeTask :: String Int -> Task MTaskTask
530 makeTask name ident = get currentDateTime @ \dt->{MTaskTask | name=name, ident=ident, dateAdded=dt}
531
532 makeShare :: String Int BCValue -> MTaskShare
533 makeShare withTask identifier value = {MTaskShare | withTask=[withTask], identifier=identifier, value=value}
534
535 sendTaskToDevice :: String (Main (ByteCode a Stmt)) (MTaskDevice, MTaskInterval) -> Task MTaskTask
536 sendTaskToDevice wta mTask (device, timeout)
537 # (msgs, newState=:{sdss}) = toMessages timeout mTask device.deviceState
538 # shares = [makeShare wta "" sdsi sdsval\\{sdsi,sdsval}<-sdss, (MTSds sdsi` _)<-msgs | sdsi == sdsi`]
539 = updateShares device ((++) shares)
540 >>| sendMessages msgs device
541 >>| makeTask wta -1
542 >>= \t->upd (addTaskUpState newState t) (deviceShare device)
543 >>| wait "Waiting for task to be acked" (taskAcked t) (deviceShare device)
544 >>| treturn t
545 where
546 addTaskUpState :: BCState MTaskTask MTaskDevice -> MTaskDevice
547 addTaskUpState st task device = {MTaskDevice | device & deviceState=st, deviceTasks=[task:device.deviceTasks]}
548 taskAcked t d = maybe True (\t->t.ident <> -1) $ find (eq t) d.deviceTasks
549 eq t1 t2 = t1.dateAdded == t2.dateAdded && t1.MTaskTask.name == t2.MTaskTask.name
550 \end{lstlisting}
551
552 \subsection{Miscellaneous Messages}
553 There exists one special type of message that is sent to the device only when
554 it needs to reboot. When the server wants to stop the bond with the device it
555 sends the \CI{MTShutdown} message. The device will then clear his memory, thus
556 losing all the \glspl{SDS} and \glspl{Task} that were stored and reset itself.
557 Shortly after the shutdown message a new server can connect to the device
558 because the device is back in listening mode.
559
560 \subsection{Integration}
561 When the system starts up, the devices from the previous execution still
562 residing in the \gls{SDS} must be cleaned up. It might be the case that they
563 contain \glspl{Task}, \glspl{SDS} or errors that are no longer applicable in
564 this run. A user or programmer can later choose to reconnect to some devices.
565
566 \begin{lstlisting}[caption={Starting up the devices},%
567 label={lst:startupdevs}]
568 startupDevices :: Task [MTaskDevice]
569 startupDevices = upd (map reset) deviceStoreNP
570 where reset d = {d & deviceTask=Nothing, deviceTasks=[], deviceError=Nothing}
571 \end{lstlisting}
572
573 The system's management is done through the interface of a single \gls{Task}
574 called \CI{mTaskManager}. To manage the system, a couple of different
575 functionalities are needed and are launched. An image of the management
576 interface is shown in Figure~\ref{lst:manage}. The left sidebar of the
577 interface shows the list of example \glspl{Task} that are present in the
578 system. When clicking a \gls{Task}, a dialog opens in which you can select the
579 device to send the \gls{Task} to. The dialog might contain user specified
580 variables. All example \glspl{mTask} are of the type \CI{Task (Main (ByteCode
581 () Stmt))} and can thus ask for user input first if needed for parameterized
582 \glspl{mTask}. The bottom panel shows the device information. In this panel,
583 the devices can be created and modified. Moreover, this panel allows the user
584 to reconnect with a device after a restart of the server application.
585
586 \todo{redo this image}
587 \begin{figure}[H]
588 \centering
589 \includegraphics[width=\linewidth]{manage}
590 \caption{The device management interface}\label{lst:manage}
591 \end{figure}
592
593 \section[Lifting mTasks to iTasks-Tasks]%
594 {Lifting \glspl{mTask} to \gls{iTasks}-\glspl{Task}}
595 If the user does not want to know where and when a \gls{mTask} is actually
596 executed and is just interested in the results it can lift the \gls{mTask} to
597 an \gls{iTasks}-\glspl{Task}. The function is called with a name, \gls{mTask},
598 device and interval specification and it will return a \gls{Task} that finishes
599 if and only if the \gls{mTask} has returned.
600
601 \begin{lstlisting}[caption={Starting up the devices}]
602 liftmTask :: String (Main (ByteCode () Stmt)) (MTaskDevice, MTaskInterval) -> Task ()
603 liftmTask wta mTask c=:(dev, _)= sendTaskToDevice wta mTask c
604 >>= \t->wait "Waiting for mTask to return" (taskRemoved t) (deviceShare dev)
605 >>| viewInformation "Done!" [] ()
606 where
607 taskRemoved t d = isNothing $ find (\t1->t1.ident==t.ident) d.deviceTasks
608 \end{lstlisting}
609
610 \section{Examples}
611 \todo{example program (demo)}