change document structure to a more intuitive one
[msc-thesis1617.git] / results.arch.tex
1 \section{Overview \& Terminology}
2 The goal of the architecture is to facilitate an ecosystem in which an
3 \gls{iTasks}-system can add, change and remove devices at runtime. Moreover,
4 the \gls{iTasks}-system can send \glspl{mTask} --- compiled at runtime to
5 bytecode --- to the device. The device runs an interpreter which can execute
6 the \gls{Task}'s bytecode. Devices are persistent during reboots of the
7 \gls{iTasks}-system. The methods of interacting with \glspl{mTask} is analogous
8 to interacting with \gls{iTasks}-\glspl{Task} and programmers can access the
9 \glspl{SDS} made for a device in the same way as a regular \glspl{SDS}. The
10 following terms will be used throughout the architecture description.
11
12 \begin{itemize}
13 \item Device, Client
14
15 This is the actual device connected to the system. This can be a real
16 device such as a microcontroller but it can also just be a program on
17 the same machine as the server.
18 \item Server, \gls{iTasks}-System
19
20 The actual executable serving the \gls{iTasks} application. The system
21 will contain \glspl{Task} taking care of the communication with the
22 clients.
23 \item System
24
25 The complete ecosystem, thus containing both the server and client
26 programs.
27 \item Engine
28
29 The runtime system of the client. This program handles the
30 communication with the server and interprets the \glspl{Task}.
31 \end{itemize}
32
33 \section{Devices}
34 The engine for the devices is compiled from one codebase. For a device to
35 be eligible for \glspl{mTask}, it must be able to compile the shared codebase
36 and implement (part of) the device specific interface. The shared codebase only
37 uses standard \gls{C} and no special libraries or tricks are used. Therefore
38 the code is compilable for almost any device or system. Note that it is not
39 needed to implement a full interface. The full interface --- excluding the
40 device specific settings --- is listed in Appendix~\ref{app:device-interface}.
41 The interface works in a similar fashion as the \gls{EDSL}. Devices do not have
42 to implement all functionality, this is analogous to the fact that views do not
43 have to implement all type classes in the \gls{EDSL}. When the device connects
44 for the first time with a server the specifications of what is implemented is
45 communicated.
46
47 At the time of writing the following device families are supported and can run
48 the device software.
49 \begin{itemize}
50 \item \texttt{POSIX} compatible systems
51
52 This includes systems running \emph{Linux} and \emph{MacOS}.
53 \item \texttt{STM32} family microcontrollers supported by \texttt{ChibiOS}.
54
55 This is tested in particular on the \texttt{STM32f7x} series \gls{ARM}
56 development board.
57 \item Microcontrollers who are programmable in the \gls{Arduino} \gls{IDE}.\\
58
59 This does not only include \gls{Arduino} compatible boards but also
60 other boards capable of running \gls{Arduino} code. The code
61 has been found working on the \texttt{ESP8266} powered \emph{NodeMCU}.
62 It is tested on devices as small as the regular \gls{Arduino}
63 \emph{UNO} board that only boasts a meager \emph{2K} of \emph{RAM}.
64 \end{itemize}
65
66 \subsection{Interpreter}
67 \todo{Structuur}
68 The client contains an interpreter to execute a \gls{Task}'s bytecode.
69
70 Before execution some preparatory work is done. The stack will be initialized
71 and the program counter and stack pointer are set to zero and the bottom
72 respectively. Then, the interpreter executes one step at the time while the
73 program counter is smaller than the program length. The code for this is listed
74 in Listing~\ref{lst:interpr}. One execution step is basically a big switch
75 statement going over all possible bytecode instructions. Some instructions are
76 detailed upon in the listing. The \CI{BCPush} instruction is a little more
77 complicated in real life because some decoding will take place as not all
78 \CI{BCValue}'s are of the same length.
79
80 \begin{lstlisting}[language=C,label={lst:interpr},%
81 caption={Rough code outline for interpretation}]
82 #define f16(p) program[pc]*265+program[pc+1]
83
84 void run_task(struct task *t){
85 uint8_t *program = t->bc;
86 int plen = t->tasklength;
87 int pc = 0;
88 int sp = 0;
89 while(pc < plen){
90 switch(program[pc++]){
91 case BCNOP:
92 break;
93 case BCPUSH:
94 stack[sp++] = pc++ //Simplified
95 break;
96 case BCPOP:
97 sp--;
98 break;
99 case BCSDSSTORE:
100 sds_store(f16(pc), stack[--sp]);
101 pc+=2;
102 break;
103 // ...
104 case BCADD: trace("add");
105 stack[sp-2] = stack[sp-2] + stack[sp-1];
106 sp -= 1;
107 break;
108 // ...
109 case BCJMPT: trace("jmpt to %d", program[pc]);
110 pc = stack[--sp] ? program[pc]-1 : pc+1;
111 break;
112 }
113 \end{lstlisting}
114
115 \subsection{Specification}
116 The server stores a description for every device available in a record type
117 which are stored in a \gls{SDS}. From the macro settings in
118 the interface file, a profile is created for the device that describes the
119 specification. When a connection between the server and a client is established
120 the server will send a request for specification. The client will serialize his
121 specification and send it to the server so that the server knows what the
122 client is capable of. The exact specification is shown in
123 Listing~\ref{lst:devicespec} and stores the peripheral availability, the memory
124 available for storing \glspl{Task} and \glspl{SDS} and the size of the stack.
125
126 \begin{lstlisting}[label={lst:devicespec},
127 caption={Device specification for \glspl{mTask}}]
128 :: MTaskDeviceSpec =
129 { haveLed :: Bool
130 , haveLcd :: Bool
131 , have...
132 , bytesMemory :: Int
133 , stackSize :: Int
134 , aPins :: Int
135 , dPins :: Int
136 }
137 \end{lstlisting}
138
139 \subsection{Device Storage}
140 All devices available in the system are stored in a big \gls{SDS} that contains
141 a list of \CI{MTaskDevice}s. The exact specification is defined as in
142 Listing~\ref{lst:mtaskdevice} accompanied with the used classes and types.
143
144 The \CI{deviceResource} component of the record must implement the
145 \CI{MTaskDuplex} interface that provides a function that launches a \gls{Task}
146 used for synchronizing the channels. The \CI{deviceTask} stores the
147 \gls{Task}-id for this \gls{Task} when active so that it can be checked upon.
148 This top-level task has the duty to report exceptions and errors as they are
149 thrown by setting the \CI{deviceError} field. All communication goes via these
150 channels. If the system wants to send a message to the device, it just puts it
151 in the channels. Messages sent from the client to the server are also placed
152 in there. In the case of the \gls{TCP} device type, the \gls{Task} is just a
153 simple wrapper around the existing \CI{tcpconnect} function in \gls{iTasks}. In
154 case of a device connected by a serial connection, it uses the newly developed
155 serial port library of \gls{Clean}\footnote{\url{%
156 https://gitlab.science.ru.nl/mlubbers/CleanSerial}}.
157
158 Besides all the communication information, the record also keeps track of the
159 \glspl{Task} currently on the device, the compiler state (see
160 Section~\ref{sec:compiler}) and the according \glspl{SDS}. Finally, it stores
161 the specification of the device that is received when connecting. All of this
162 is given in Listing~\ref{lst:mtaskdevice}. The definitions of the message
163 format are explained in the following section. Specialized shares are available
164 per device. The internal mechanism for this is given in
165 Chapter~\ref{chp:itasksint}.
166
167 \begin{lstlisting}[caption={Device type},label={lst:mtaskdevice}]
168 deviceStoreNP :: Shared [MTaskDevice]
169 deviceShare :: MTaskDevice -> Shared MTaskDevice
170
171 :: Channels :== ([MTaskMSGRecv], [MTaskMSGSend], Bool)
172 :: BCState = ... // Compiler state, explained in later sections
173 :: MTaskResource
174 = TCPDevice TCPSettings
175 | SerialDevice TTYSettings
176 :: MTaskDevice =
177 { deviceTask :: Maybe TaskId
178 , deviceError :: Maybe String
179 , deviceChannels :: String
180 , deviceName :: String
181 , deviceState :: BCState
182 , deviceTasks :: [MTaskTask]
183 , deviceData :: MTaskResource
184 , deviceSpec :: Maybe MTaskDeviceSpec
185 , deviceShares :: [MTaskShare]
186 }
187
188 channels :: MTaskDevice -> Shared Channels
189
190 class MTaskDuplex a where
191 synFun :: a (Shared Channels) -> Task ()
192 \end{lstlisting}
193
194 \section{iTasks}
195 The server part of the system is written in \gls{iTasks}. Functions for
196 managing devices, \glspl{Task} and \glspl{SDS} have been created to support the
197 functionality. An interactive application has been created that allows an
198 interactive management console for the \gls{mTask} system. This interface
199 provides functionality to list \glspl{SDS}, add \glspl{Task}, remove
200 \glspl{Task}, administrate devices and view the state of the system.
201
202 \subsection{Integration}
203 When the system starts up the devices from the previous execution still
204 residing in the \gls{SDS} must be cleaned up. It might be the case that they
205 contain \glspl{Task}, \glspl{SDS} or errors that are no longer applicable in
206 this run. A user or programmer can later choose to reconnect to some devices.
207
208 \begin{lstlisting}[caption={Starting up the devices},%
209 label={lst:startupdevs}]
210 startupDevices :: Task [MTaskDevice]
211 startupDevices = upd (map reset) deviceStoreNP
212 where reset d = {d & deviceTask=Nothing, deviceTasks=[], deviceError=Nothing}
213 \end{lstlisting}
214
215 An image of the management interface is shown in Figure~\ref{lst:manage}.
216 The system management is done by a single \gls{Task} called \CI{mTaskManager}.
217 To manage the system, a couple of different functionalities are needed and
218 are launched. The left sidebar of the interface shows the list of example
219 \glspl{Task} that are present in the system. When clicking a \gls{Task}, a
220 dialog opens in which you can select the device to send the \gls{Task} to. The
221 dialog might contain user specified variables. All example \glspl{mTask} are of
222 the type \CI{Task (Main (ByteCode () Stmt))} and can thus ask for user input
223 first.
224
225 The bottom panel shows the device information. In this panel, the devices can
226 be created and modified. Moreover, this panel allows the user to reconnect with
227 a device after a restart of the server application.
228
229 \begin{figure}[H]
230 \centering
231 \includegraphics[width=\linewidth]{manage}
232 \caption{The device management interface}\label{lst:manage}
233 \end{figure}
234
235 \subsection{Shares}
236 The architecture of the system needs to keep track of the \glspl{SDS} stored on
237 the client. \glspl{SDS} can be stored on only one device at the same time.
238 that also stores the of devices. This means that if a \gls{SDS} updates,
239 everyone watching it will be notified. This would result in to a lot of
240 notifications that are not ment to be for the listener. Moreover, when a client
241 updates the \gls{SDS} this is processed by the connection handler and results
242 in an update of the real \gls{SDS}.
243 Finally, the \gls{SDS} of a client must be synchronized with the actual device.
244 There are several ways of tackling this problem each with their own pros and
245 cons and their own level of abstraction.
246
247 \begin{itemize}
248 \item Instantiate an actual \gls{iTasks}-\gls{SDS} for every \gls{SDS} used
249 in a client.
250
251 \item Instantiate a \gls{iTasks}-\gls{SDS} for every device that stores all
252 their \glspl{SDS}.
253
254 \item Use only one \gls{iTasks}-\gls{SDS} for all devices.
255 \end{itemize}
256
257 \begin{lstlisting}[label={lst:actualdev},%
258 caption={Real types for the device \gls{SDS}}]
259 deviceStoreNP :: Shared [MTaskDevice]
260 deviceStore :: RWShared (Maybe (MTaskDevice, Int)) [MTaskDevice] [MTaskDevice]
261 \end{lstlisting}
262
263 \subsection{Parametric Lenses}
264 The type of the parametric lens is \CI{Maybe (MTaskDevice, Int)}. The \gls{SDS}
265 can be responsible for the entire list of devices, from now on global.
266 Moreover, the \gls{SDS} can focus on a single device, from now on local. A
267 local \gls{SDS} can also specifically focus on a single \gls{SDS} on a single
268 device, from now on called local-share.
269
270 \paragraph{Global \glspl{SDS}: }
271 Accessing the global \gls{SDS} is just a matter of focussing the
272 \CI{deviceStore} with the \CI{Nothing} parameter. The signature for
273 \CI{deviceStore} was given in Chapter~\ref{chp:arch}. The actual implementation
274 is as in Listing~\ref{lst:global}
275
276 \begin{lstlisting}[label={lst:shareimpl},%
277 caption={Base share implementation}]
278 deviceStoreNP :: RWShared (Maybe (MTaskDevice, Int)) [MTaskDevice] [MTaskDevice]
279 deviceStoreNP = sdsFocus Nothing deviceStore
280 \end{lstlisting}
281
282
283
284
285 \paragraph{Local \glspl{SDS}: }
286 \paragraph{Local-share specific \glspl{SDS}: }
287
288 The implementation for the share is shown in Listing~\ref{lst:shareimpl}. The
289 \CI{realDeviceStore} \gls{SDS} is not exported through the header files. This
290 \gls{SDS} contains the actual \gls{SDS} that writes to disk or memory.
291 \CI{Int} is the identifier of the \gls{SDS}. The \gls{iTasks} way of applying
292 lenses is through the \CI{sdsFocus} function and through the \CI{sdsLens}
293 functions. \CI{sdsFocus} allows the programmer to fix the parameter.
294 \CI{sdsLens} is basically a \CI{mapReadWrite} that has access to the parameter.
295 This allows the programmer to create filters and lenses. Both of the methods
296 are not good enough for the device \gls{SDS} because they do not achieve the
297 writing to the actual device. Writing to a device requires being able to write
298 to \glspl{SDS}. To solve this problem, a real base \gls{SDS} is created. All
299 the details are visible in Listing~\ref{lst:shareimpl}.
300
301 \section{Communication}
302 The communication from the server to the client and vice versa is just a
303 character stream containing encoded \gls{mTask} messages. The specific encoding
304 is visible in Appendix~\ref{app:communication-protocol}. The type holding the
305 messages in Listing~\ref{lst:avmsg}. Detailed explanation about the message
306 types will be given in the following subsections.
307
308 \begin{lstlisting}[label={lst:avmsg},caption={Available messages}]
309 :: MTaskId :== Int
310 :: MSDSId :== Int
311 :: MTaskFreeBytes :== Int
312 :: MTaskMSGRecv
313 = MTTaskAck MTaskId MTaskFreeBytes | MTTaskDelAck MTaskId
314 | MTSDSAck MSDSId | MTSDSDelAck MSDSId
315 | MTPub MSDSId BCValue | MTMessage String
316 | MTDevSpec MTaskDeviceSpec | MTEmpty
317
318 :: MTaskMSGSend
319 = MTTask MTaskInterval String | MTTaskDel MTaskId
320 | MTShutdown | MTSds MSDSId BCValue
321 | MTUpd MSDSId BCValue | MTSpec
322
323 :: MTaskInterval = OneShot | OnInterval Int | OnInterrupt Int
324 \end{lstlisting}
325
326 \subsection{Add a device}
327 A device can be added by filling in the \CI{MTaskDevice} record as much as
328 possible and running the \CI{connectDevice} function. This function grabs the
329 channels, starts the synchronization \gls{Task}, makes sure the errors are
330 handled when needed and runs a processing function in parallel to react on the
331 incoming messages. Moreover, it sends a specification request to the device in
332 question to determine the details of the device and updates the record to
333 contain the top-level \gls{Task}-id. All the device functionality heavily
334 depends on the specific \CI{deviceShare} function that applies a function a device in
335 the \gls{SDS} when they are equal. Device equality is defined as equality on
336 their channels. This allows you to give an old device record to the function
337 and still update the latest instance. Listing~\ref{lst:connectDevice} shows the
338 connection function.
339
340 \begin{lstlisting}[label={lst:connectDevice},%
341 caption={Connect a device}]
342 withDevices :: MTaskDevice (MTaskDevice -> MTaskDevice) -> Task [MTaskDevice]
343
344 connectDevice :: (MTaskDevice (Shared Channels) -> Task ()) MTaskDevice -> Task Channels
345 connectDevice procFun device = let ch = channels device
346 in appendTopLevelTask 'DM'.newMap True
347 (procFun device ch -||- catchAll (getSynFun d.deviceData ch) errHdl)
348 >>= \tid->withDevices device (\d->{d&deviceTask=Just tid,deviceError=Nothing})
349 >>| upd (\(r,s,ss)->(r,s++[MTSpec],ss)) ch
350 where
351 errHdl e = withDevices device (\d->{d & deviceTask=Nothing, deviceError=Just e}) @! ()
352 \end{lstlisting}
353
354 Figure~\ref{fig:handshake} shows the connection diagram. The client responds to
355 the server with their device specification. This is detected by the processing
356 function and the record is updated accordingly.
357
358 \begin{figure}[H]
359 \centering
360 \begin{sequencediagram}
361 \newthread{s}{Server}
362 \newinst[4]{c}{Client}
363 \begin{call}{s}{MTSpec}{c}{MTDevSpec}
364 \end{call}
365 \end{sequencediagram}
366 \caption{Connect a device}\label{fig:handshake}
367 \end{figure}
368
369 \subsection{\glspl{Task} \& \glspl{SDS}}
370 When a \gls{Task} is sent to the device it is added to the device record
371 without an identifier. The actual identifier is added to the record when the
372 acknowledgement of the \gls{Task} by the device is received. The connection
373 diagram is shown in Figure~\ref{fig:tasksend}.
374
375 \begin{figure}[H]
376 \centering
377 \begin{sequencediagram}
378 \newthread{s}{Server}
379 \newinst[4]{c}{Client}
380 \begin{call}{s}{MTSDS}{c}{MTSDSAck}
381 \end{call}
382 \begin{call}{s}{MTTask}{c}{MTTaskAck}
383 \end{call}
384 \end{sequencediagram}
385 \caption{Sending a \gls{Task} to a device}\label{fig:tasksend}
386 \end{figure}
387
388 The function for sending a \gls{Task} to the device is shown in
389 Listing~\ref{lst:sendtask}. First the \gls{Task} is compiled into messages. The
390 details of the compilation process are given in Section~\ref{sec:compiler}.
391 The new \glspl{SDS} that were made during compilation are added to the
392 deviceshares that were made during the compilation are merged with the existing
393 shares on the device. Furthermore the messages are placed in the channel share
394 of the device. This will result in sending the actual \gls{SDS} specification
395 and \gls{Task} specifications to the device. A \gls{Task} record is created
396 with the identifier $-1$ to denote a \gls{Task} not yet acknowledged. Finally
397 the device itself is updated with the new state and with the new \gls{Task}.
398 When the device returns an acknowledgement the \gls{Task} is updated
399 accordingly.
400
401 \begin{lstlisting}[label={lst:sendtask},%
402 caption={Sending a \gls{Task} to a device}]
403 makeTask :: String Int -> Task MTaskTask
404 makeTask name ident = get currentDateTime @ \dt->{MTaskTask | name=name, ident=ident, dateAdded=dt}
405
406 makeShare :: String Int BCValue -> MTaskShare
407 makeShare withTask identifier value = {MTaskShare | withTask=[withTask], identifier=identifier, value=value}
408
409 sendTaskToDevice :: String (Main (ByteCode a Stmt)) (MTaskDevice, MTaskInterval) -> Task [MTaskDevice]
410 sendTaskToDevice wta mTask (device, timeout)
411 # (msgs, newState) = toMessages timeout mTask device.deviceState
412 # shares = [makeShare wta sdsi sdsval\\{sdsi,sdsval}<-newState.sdss, (MTSds sdsi` _)<-msgs | sdsi == sdsi`]
413 = updateShares device ((++) shares)
414 >>| sendMessages msgs device
415 >>| makeTask wta -1
416 >>= withDevices device o addTaskUpState newState
417 where
418 addTaskUpState :: BCState MTaskTask MTaskDevice -> MTaskDevice
419 addTaskUpState st task device = {MTaskDevice | device &
420 deviceState=st, deviceTasks=[task:device.deviceTasks]}
421 \end{lstlisting}
422
423 \subsection{Miscellaneous Messages}
424 There exists one special type of message that is sent to the device only when
425 it needs to reboot. When the server wants to stop the bond with the device it
426 sends the \CI{MTShutdown} message. The device will then clear his memory, thus
427 losing all the \glspl{SDS} and \glspl{Task} that were stored and reset itself.
428 Shortly after the shutdown message a new server can connect to the device
429 because the device is back in listening mode.
430
431 \section{Lifting mTask to iTasks}
432 \todo{task lifting}
433
434 \section{Examples}
435 \todo{example program (demo)}