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