update abstract and acks
[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 the
6 \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 also just a program on the same
17 machine as the server.
18 \item Server, \gls{iTasks}-System
19
20 The actual executable serving the \gls{iTasks} interfaces. 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 system handles the communication
30 with the server and interprets the \glspl{Task}.
31 \end{itemize}
32
33
34 \section{Devices}
35 The engine for the devices is compiled from one codebase. For a device to
36 be eligible for \glspl{mTask}, it must be able to compile the shared codebase
37 and implement (part of) the device specific interface. The shared codebase only
38 uses standard \gls{C} and no special libraries or tricks are used. Therefore
39 the code is compilable for almost any device or system. Note that it is not
40 needed to implement a full interface. The full interface --- excluding the
41 device specific settings --- is listed in Appendix~\ref{app:device-interface}.
42 The interface works in a similar fashion as the \gls{EDSL}. Devices do not have
43 to implement all functionality, this is analogous to the fact that views do not
44 have to implement all type classes in the \gls{EDSL}. When the device connects
45 for the first time with a server the specifications of what is implemented is
46 communicated.
47
48 At the time of writing the following device families are supported and can run
49 the device software.
50 \begin{itemize}
51 \item \texttt{POSIX} compatible systems
52
53 This includes systems running \emph{Linux} and \emph{MacOS}.
54 \item \texttt{STM32} family microcontrollers supported by \texttt{ChibiOS}.
55
56 This is tested in particular on the \texttt{STM32f7x} series \gls{ARM}
57 development board.
58 \item Microcontrollers programmable by the \gls{Arduino} \gls{IDE}.\\
59
60 This does not only include \gls{Arduino} compatible boards but also
61 other boards capable of running \gls{Arduino} code. The code
62 has been found working on the \texttt{ESP8266} powered \emph{NodeMCU}.
63 It is tested on devices as small as the regular \gls{Arduino}
64 \emph{UNO} board that only boasts a meager \emph{2K} of \emph{RAM}.
65 \end{itemize}
66
67 \section{Specification}
68 The server stores a description for every device available in a record type
69 which are stored in a \gls{SDS}. From the macro settings in
70 the interface file, a profile is created for the device that describes the
71 specification. When a connection between the server and a client is established
72 the server will send a request for specification. The client will serialize his
73 specification and send it to the server so that the server knows what the
74 client is capable of. The exact specification is shown in
75 Listing~\ref{lst:devicespec}
76
77 \begin{lstlisting}[label={lst:devicespec},
78 caption={Device specification for \glspl{mTask}}]
79 :: MTaskDeviceSpec =
80 { haveLed :: Bool
81 , haveAio :: Bool
82 , haveDio :: Bool
83 , bytesMemory :: Int
84 }
85 \end{lstlisting}
86
87 \section{Device Storage}
88 All devices available in the system are stored in a big \gls{SDS} that contains
89 a list of \CI{MTaskDevice}s. The exact specification is defined as in
90 Listing~\ref{lst:mtaskdevice} with the accompanying classes and types.
91
92 The \CI{deviceResource} component of the record must implement the
93 \CI{MTaskDuplex} interface that provides a function that launches a \gls{Task}
94 used for synchronizing the channels. The \CI{deviceTask} stores the
95 \gls{Task}-id for this \gls{Task} when active so that it can be checked upon.
96 This top-level task has the duty to report exceptions and errors as they are
97 thrown by setting the \CI{deviceError} field. All communication goes via these
98 channels. If the system wants to send a message to the device, it just puts it
99 in the channels. Messages sent from the client to the server are also placed
100 in there. In the case of the \gls{TCP} device type, the \gls{Task} is just a
101 simple wrapper around the existing \CI{tcpconnect} function in \gls{iTasks}. In
102 case of a device connected by a serial connection, it uses the newly developed
103 serial port library of \gls{Clean}\footnote{\url{%
104 https://gitlab.science.ru.nl/mlubbers/CleanSerial}}.
105
106 Besides all the communication information, the record also keeps track of the
107 \glspl{Task} currently on the device, the compiler state (see
108 Section~\ref{sec:compiler}) and the according \glspl{SDS}. Finally, it stores
109 the specification of the device that is received when connecting. All of this
110 is given in Listing~\ref{lst:mtaskdevice}. The definitions of the message
111 format are explained in the following section.
112
113 \begin{lstlisting}[caption={Device type},label={lst:mtaskdevice}]
114 deviceStoreNP :: Shared [MTaskDevice]
115
116 :: Channels :== ([MTaskMSGRecv], [MTaskMSGSend], Bool)
117 :: BCState = ... // Compiler state, explained in later sections
118 :: MTaskResource
119 = TCPDevice TCPSettings
120 | SerialDevice TTYSettings
121 :: MTaskDevice =
122 { deviceTask :: Maybe TaskId
123 , deviceError :: Maybe String
124 , deviceChannels :: String
125 , deviceName :: String
126 , deviceState :: BCState
127 , deviceTasks :: [MTaskTask]
128 , deviceData :: MTaskResource
129 , deviceSpec :: Maybe MTaskDeviceSpec
130 , deviceShares :: [MTaskShare]
131 }
132
133 channels :: MTaskDevice -> Shared Channels
134
135 class MTaskDuplex a where
136 synFun :: a (Shared Channels) -> Task ()
137 \end{lstlisting}
138
139 \section{Communication}
140 The communication from the server to the client and vice versa is just a
141 character stream containing encoded \gls{mTask} messages. The specific encoding
142 is visible in Appendix~\ref{app:communication-protocol}. The type holding the
143 messages in Listing~\ref{lst:avmsg}. Detailed explaination about the message
144 types will be given in the following subsections.
145
146 \begin{lstlisting}[label={lst:avmsg},caption={Available messages}]
147 :: MTaskId :== Int
148 :: MSDSId :== Int
149 :: MTaskFreeBytes :== Int
150 :: MTaskMSGRecv
151 = MTTaskAck MTaskId MTaskFreeBytes | MTTaskDelAck MTaskId
152 | MTSDSAck MSDSId | MTSDSDelAck MSDSId
153 | MTPub MSDSId BCValue | MTMessage String
154 | MTDevSpec MTaskDeviceSpec | MTEmpty
155
156 :: MTaskMSGSend
157 = MTTask MTaskInterval String | MTTaskDel MTaskId
158 | MTShutdown | MTSds MSDSId BCValue
159 | MTUpd MSDSId BCValue | MTSpec
160
161 :: MTaskInterval = OneShot | OnInterval Int | OnInterrupt Int
162 \end{lstlisting}
163
164 \subsection{Add a device}
165 A device can be added by filling in the \CI{MTaskDevice} record as much as
166 possible and running the \CI{connectDevice} function. This function grabs the
167 channels, starts the synchronization \gls{Task}, makes sure the errors are
168 handled when needed and runs a processing function in parallel to react on the
169 incoming messages. Moreover, it sends a specification request to the device in
170 question to determine the details of the device and updates the record to
171 contain the top-level \gls{Task}-id. All the device functionality heavily
172 depends on the \CI{withDevices} function that applies a function a device in
173 the \gls{SDS} when they are equal. Device equality is defined as equality on
174 their channels. This allows you to give an old device record to the function
175 and still update the latest instance. Listing~\ref{lst:connectDevice} shows the
176 connection function.
177
178 \begin{lstlisting}[label={lst:connectDevice},%
179 caption={Connect a device}]
180 withDevices :: MTaskDevice (MTaskDevice -> MTaskDevice) -> Task [MTaskDevice]
181
182 connectDevice :: (MTaskDevice (Shared Channels) -> Task ()) MTaskDevice -> Task Channels
183 connectDevice procFun device = let ch = channels device
184 in appendTopLevelTask 'DM'.newMap True
185 (procFun device ch -||- catchAll (getSynFun d.deviceData ch) errHdl)
186 >>= \tid->withDevices device (\d->{d&deviceTask=Just tid,deviceError=Nothing})
187 >>| upd (\(r,s,ss)->(r,s++[MTSpec],ss)) ch
188 where
189 errHdl e = withDevices device (\d->{d & deviceTask=Nothing, deviceError=Just e}) @! ()
190 \end{lstlisting}
191
192 Figure~\ref{fig:handshake} shows the connection diagram. The client responds to
193 the server with their device specification. This is detected by the processing
194 function and the record is updated accordingly.
195
196 \begin{figure}[H]
197 \centering
198 \begin{sequencediagram}
199 \newthread{s}{Server}
200 \newinst[4]{c}{Client}
201 \begin{call}{s}{MTSpec}{c}{MTDevSpec}
202 \end{call}
203 \end{sequencediagram}
204 \caption{Connect a device}\label{fig:handshake}
205 \end{figure}
206
207 \subsection{\glspl{Task} \& \glspl{SDS}}
208 When a \gls{Task} is sent to the device it is added to the device record
209 without an identifier. The actual identifier is added to the record when the
210 acknowledgement of the \gls{Task} by the device is received. The connection
211 diagram is shown in Figure~\ref{fig:tasksend}.
212
213 \begin{figure}[H]
214 \centering
215 \begin{sequencediagram}
216 \newthread{s}{Server}
217 \newinst[4]{c}{Client}
218 \begin{call}{s}{MTSDS}{c}{MTSDSAck}
219 \end{call}
220 \begin{call}{s}{MTTask}{c}{MTTaskAck}
221 \end{call}
222 \end{sequencediagram}
223 \caption{Sending a \gls{Task} to a device}\label{fig:tasksend}
224 \end{figure}
225
226 The function for sending a \gls{Task} to the device is shown in
227 Listing~\ref{lst:sendtask}. First the \gls{Task} is compiled into messages. The
228 details of the compilation process are given in Section~\ref{sec:compiler}.
229 The new \glspl{SDS} that were made during compilation are added to the
230 deviceshares that were made during the compilation are merged with the existing
231 shares on the device. Furthermore the messages are placed in the channel share
232 of the device. This will result in sending the actual \gls{SDS} specification
233 and \gls{Task} specifications to the device. A \gls{Task} record is created
234 with the identifier $-1$ to denote a \gls{Task} not yet acknowledged. Finally
235 the device itself is updated with the new state and with the new \gls{Task}.
236 When the device returns an acknowledgement the \gls{Task} is updated
237 accordingly.
238
239 \begin{lstlisting}[label={lst:sendtask},%
240 caption={Sending a \gls{Task} to a device}]
241 makeTask :: String Int -> Task MTaskTask
242 makeTask name ident = get currentDateTime @ \dt->{MTaskTask | name=name, ident=ident, dateAdded=dt}
243
244 makeShare :: String Int BCValue -> MTaskShare
245 makeShare withTask identifier value = {MTaskShare | withTask=[withTask], identifier=identifier, value=value}
246
247 sendTaskToDevice :: String (Main (ByteCode a Stmt)) (MTaskDevice, MTaskInterval) -> Task [MTaskDevice]
248 sendTaskToDevice wta mTask (device, timeout)
249 # (msgs, newState) = toMessages timeout mTask device.deviceState
250 # shares = [makeShare wta sdsi sdsval\\{sdsi,sdsval}<-newState.sdss, (MTSds sdsi` _)<-msgs | sdsi == sdsi`]
251 = updateShares device ((++) shares)
252 >>| sendMessages msgs device
253 >>| makeTask wta -1
254 >>= withDevices device o addTaskUpState newState
255 where
256 addTaskUpState :: BCState MTaskTask MTaskDevice -> MTaskDevice
257 addTaskUpState st task device = {MTaskDevice | device &
258 deviceState=st, deviceTasks=[task:device.deviceTasks]}
259 \end{lstlisting}
260
261 \subsection{Miscellaneous Messages}
262 There exists one special type of message that is sent to the device only when
263 it needs to reboot. When the server wants to stop the bond with the device it
264 sends the \CI{MTShutdown} message. The device will then clear his memory, thus
265 losing all the \glspl{SDS} and \glspl{Task} that were stored and reset itself.
266 Shortly after the shutdown message a new server can connect to the device
267 because the device is back in listening mode.