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