Merge branch 'master' of git.martlubbers.net:msc-thesis1617
[msc-thesis1617.git] / arch.example.tex
1 \subsection{Framework}
2 Systems built with support for \gls{mTask} often follow the same design
3 pattern. First the devices are created --- with or without the interaction of
4 the user --- and they are then connected. When all devices are registered, the
5 \gls{mTask}-\glspl{Task} can be sent and \gls{iTasks}-\glspl{Task} can be
6 started to monitor the output. When everything is finished, the devices are
7 removed and the system is shut down. To illustrate this, a demo blinking
8 application is shown in Listing~\ref{lst:framework}. The application is a
9 complete \gls{iTasks} application.
10
11 \begin{lstlisting}[language=Clean,label={lst:framework},
12 caption={\gls{mTask} framework for building applications}]
13 module blinkdemo
14
15 import iTasks
16 import mTask
17 import Devices.mTaskDevice
18
19 from Data.Func import $
20
21 Start world = startEngine blink world
22
23 blink :: Task ()
24 blink = addDevice
25 >>= connectDevice
26 >>= \stm->sendTaskToDevice "blink" blinkTask (stm, OnInterval 1000)
27 >>= \(st, [_,t])->forever (
28 updateSharedInformation "Which led to blink" [] (shareShare stm t)
29 ) >>* [OnAction (Action "Shutdown") $ always
30 $ deleteDevice stm >>| shutDown 0
31 ]
32 where
33 blinkTask = sds \led=LED1 In sds \x=True In {main =
34 ledOff led1 :. ledOff led2 :. ledOff led3 :.
35 IF x (ledOff led) (ledOn led) :.
36 x =. Not x}
37 \end{lstlisting}
38
39 \subsection{Thermostat}
40 The thermostat is a classic example program for showing interactions between
41 peripherals. The following program shows a system containing two devices. The
42 first device --- the sensor --- contains a temperature sensor that measures the
43 room temperature. The second device --- the actor --- contains a heater,
44 connected to the digital pin \CI{D5}. Moreover, this device contains an
45 \gls{LED} to indicate whether the heater is on. The following code shows an
46 implementation for this. The code makes use of all the aspects of the
47 framework. Note that a little bit of type twiddling is required to fully use
48 the result from the \gls{SDS}. This approach is still type safe due to the type
49 safety of \CI{Dynamic}s.
50
51 \begin{lstlisting}[language=Clean,caption={Thermostat example}]
52 thermos :: Task ()
53 thermos = makeDevice "nodeM" nodeMCU >>= connectDevice
54 >>= \nod-> makeDevice "stm32" stm32 >>= connectDevice
55 >>= \stm-> sendTaskToDevice "sensing" sensing (nod, OnInterval 1000)
56 >>= \(st, [t])->sendTaskToDevice "acting" acting (stm, OnInterval 1000)
57 (\(BCValue s)->set (BCValue $ dynInt (dynamic s) > 0) (shareShare nod a))
58 >>* [OnAction (Action "Shutdown") $ always $ deleteDevice nod >>| deleteDevice stm >>| shutDown 0]
59 where
60 dynInt :: Dynamic -> Int
61 dynInt (a :: Int) = a
62
63 sensing = sds \x=0 In {main=
64 x =. analogRead A0 :. pub x
65 }
66 acting = sds \cool=False In {main=
67 IF cool (ledOn LED1) (ledOff LED1) :.
68 digitalWrite D5 cool
69 }
70 nodeMCU = makeDevice "NodeMCU"
71 (TCPDevice {host="192.168.0.12", port=8888})
72 stm32 = makeDevice "Stm32"
73 (SerialDevice {devicePath="/dev/ttyUSB0", baudrate=B9600, ...}
74 \end{lstlisting}
75
76 \subsection[Lifting mTasks to iTasks-Tasks]%
77 {Lifting \gls{mTask}-\glspl{Task} to \gls{iTasks}-\glspl{Task}}
78 If the user does not want to know where and when an \gls{mTask} is actually
79 executed and is just interested in the results, it can lift the \gls{mTask} to
80 an \gls{iTasks}-\gls{Task}. The function is called with a name, \gls{mTask},
81 device and interval specification and it will return a \gls{Task} that finishes
82 if and only if the \gls{mTask} has returned.
83
84 \begin{lstlisting}[language=Clean,caption={Lifting \gls{mTask}-\glspl{Task} to \gls{iTasks}}]
85 liftmTask :: String (Main (ByteCode () Stmt)) (MTaskDevice, MTaskInterval) -> Task [MTaskShare]
86 liftmTask wta mTask c=:(dev, _)= sendTaskToDevice wta mTask c
87 >>= \(t, shs)->wait "Waiting for mTask to return" (taskRemoved t) (deviceShare dev)
88 >>| viewInformation "Done!" [] ()
89 >>| treturn shs
90 where
91 taskRemoved t d = isNothing $ find (\t1->t1.ident==t.ident) d.deviceTasks
92 \end{lstlisting}
93
94 The factorial function example from Chapter~\ref{chp:mtaskcont} can then be
95 lifted to a real \gls{iTasks}-\gls{Task} with the following code:
96 \begin{lstlisting}[language=Clean,caption={Lifting the factorial \gls{Task} to \gls{iTasks}}]
97 factorial :: MTaskDevice -> Task BCValue
98 factorial dev = enterInformation "Factorial of ?" []
99 >>= \fac->liftmTask "fact" (fact fac) (dev, OnInterval 100)
100 @ fromJust o find (\x->x.humanName == "result")
101 @ \s->s.MTaskShare.value
102 where
103 fact i = sds \y=i
104 In namedsds \x=(1 Named "result")
105 In {main = IF (y <=. lit 1)
106 ( pub x :. retrn )
107 ( x =. x *. y :. y =. y -. lit 1 )}
108 \end{lstlisting}
109
110 \subsection{Heartbeat \& Oxygen Saturation Sensor}
111 As an example, the addition of a new sensor will be demonstrated. The heartbeat
112 and oxygen saturation sensor add-on is a \textsc{PCB} the size of a fingernail
113 with a red \gls{LED} and a light sensor on it. Moreover, it contains an
114 \textsc{I2C} chip to communicate. The company producing the chip provides the
115 programmer with example code for \gls{Arduino} and \gls{mbed}. The sensor
116 emits red light and measures the intensity of the light returned. The
117 microcontroller hosting the device has to keep track of four seconds of samples
118 to determine the heartbeat. In the \gls{mTask}-system, an abstraction is made.
119 The current implementation runs on \gls{mbed} supported devices.
120
121 \subsubsection{\gls{mTask} Classes}
122 First, a class has to be devised to store the functionality of the sensor. The
123 heartbeat sensor updates four values continuously, namely the heartbeat, the
124 oxygen saturation and the validity of the two. The real value and the validity
125 are combined in an \gls{ADT} and functions are added for both of them in the
126 new \CI{hb} class. The values are combined in such a way that they fit in a 16
127 bit integer with the last bit representing the validity of the reading. The
128 introduced datatype housing the values should implement the \CI{mTaskType}
129 classes. The definition is as follows:
130
131 \begin{lstlisting}[language=Clean,%
132 caption={The \texttt{hb} class and class implementations}]
133 :: Heartbeat = HB Int Bool
134 :: SP02 = SP02 Int Bool
135
136 instance toByteCode Heartbeat
137 where toByteCode (HB i b) = "h" +++ (to16bit $ (i << 1) bitand (if b 1 0))
138 instance toByteCode SP02 where ...
139
140 instance fromByteCode Heartbeat
141 where fromByteCode s = let i = fromByteCode s //The Int from bytecode
142 in HB (i >> 1) (i bitand 1 > 0)
143 instance fromByteCode SP02 where ...
144
145 derive class iTask Heartbeat, SP02
146
147 class hb v where
148 getHb :: (v Heartbeat Expr)
149 getSp02 :: (v SP02 Expr)
150 \end{lstlisting}
151
152 \subsubsection{Bytecode Implementation}
153 The class is available now, and the implementation can be created. The
154 implementation is trivial since the functionality is limited to retrieving
155 single values and no assignment is possible. The following code shows the
156 implementation. Dedicated bytecode instructions have been added to support the
157 functionality.
158
159 \begin{lstlisting}[language=Clean,caption={The \texttt{hb} bytecode instance}]
160 :: BC
161 = BCNop
162 | ...
163 | BCGetHB
164 | BCGetSP02
165
166 instance hb ByteCode where
167 getHb = tell` [BCGetHB]
168 getSp02 = tell` [BCGetSP02]
169 \end{lstlisting}
170
171 \subsubsection{Device Interface}
172 The bytecode instructions are added but still the functionality needs to be
173 added to the device interface to be implemented by clients. The following
174 addition to \CI{interface.h} and the interpreter shows the added instructions.
175 When adding a peripheral, the devices not having the peripheral do not need to
176 have their code recompiled. New instructions always get a higher bytecode
177 number if added correctly. The peripheral byte in the device specification by
178 default shows a negative flag for every peripheral. Only the peripherals added
179 will be flagged positive.
180
181 \begin{lstlisting}[language=Clean,caption={Adding the device interface}]
182 // interface.h
183 ...
184 #if HAVEHB == 1
185 uint16_t get_hb();
186 uint16_t get_spo2();
187 #endif
188 ...
189
190 // interpret.c
191 while(pc < plen){
192 switch(program[pc++]){
193 ...
194 #if HAVEHB == 1
195 case BCGETHB:
196 stack[sp++] = get_hb();
197 break;
198 case BCGETSP02:
199 stack[sp++] = get_spo2();
200 break;
201 #endif
202 ...
203 \end{lstlisting}
204
205 \subsubsection{Client Software}
206 The device client software always executes the \CI{real\_setup} in which the
207 client software can setup the connection and peripherals. In the case of the
208 heartbeat peripheral it starts a thread running the calculations. The thread
209 started in the setup will set the global heartbeat and oxygen level variables
210 so that the interface functions for it can access it. This is listed in
211 Listing~\ref{lst:hbding}. If interrupts were implemented, the \glspl{Task}
212 using the heartbeat sensor could be executed on interrupt. The heartbeat thread
213 can fire an interrupt everytime it calculated a new heartbeat.
214
215 \begin{lstlisting}[label={lst:hbding},language=C,%
216 caption={Heartbeat code in the client}]
217 Serial pc;
218 Thread thread;
219
220 void heartbeat_thread(void) {
221 // Constant heartbeat calculations
222 }
223
224 void real_setup(void) {
225 pc.baud(19200);
226 thread.start(heartbeat_thread);
227 }
228 \end{lstlisting}
229
230 \subsubsection{Example}
231 The following code shows a complete example of a \gls{Task} controlling an
232 \emph{STM} microcontroller containing a heartbeat sensor. The web application
233 belonging to the server shows the heartbeat value and starts an alert
234 \gls{Task} when it exceeds the value given or is no longer valid.
235 This example also shows how named \gls{SDS} are handled.
236
237 \begin{lstlisting}[language=Clean,caption={Heartbeat example}]
238 hbwatch :: (Task a) Int -> Task ()
239 hbwatch alert lim
240 = makeDevice "stm32" stm32
241 >>= connectDevice
242 >>= \stm ->sendTaskToDevice "monitor" monitor (stm, OnInterval 200)
243 >>= \(t, sh)->mon (fromJust $ find (\x->x.name == "hb") sh)
244 >>* [OnAction (Action "Shutdown") $ always $ deleteDevice stm >>| shutDown 0]
245 where
246 mon :: (Shared BCValue) -> Task ()
247 mon b = whileUnchanged (mapRead dynHB b)
248 \hb=:(HB i valid)->if (not valid || i > lim)
249 alert (viewInformation "HB Okay" [] hb)
250
251 dynHB :: Dynamic -> HeartBeat
252 dynHB (a :: HeartBeat) = a
253
254 monitor = namedsds \hb=(0 Named hb) In
255 {main= hb = getHB :. pub hb }
256 \end{lstlisting}