note about peripherals
[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.
8
9 \begin{lstlisting}[language=Clean,label={lst:framework},
10 caption={\gls{mTask} framework for building applications}]
11 w :: Task ()
12 w = makeDevice "dev1" (...) >>= connectDevice
13 >>= \dev1->makeDevice "dev2" (...) >>= connectDevice
14 >>= \dev2->...
15 ...
16 >>* [OnAction (Action "Shutdown") $ always
17 $ deleteDevice dev1 >>| deleteDevice dev2
18 >>| ...
19 >>| shutDown 0
20 ]
21 \end{lstlisting}
22
23 \subsection{Thermostat}
24 The thermostat is a classic example program for showing interactions between
25 peripherals. The following program shows a system containing two devices. The
26 first device --- the sensor --- contains a temperature sensor that measures the
27 room temperature. The second device --- the actor --- contains a heater,
28 connected to the digital pin \CI{D5}. Moreover, this device contains an
29 \gls{LED} to indicate whether the heater is on. The following code shows an
30 implementation for this. The code makes use of all the aspects of the
31 framework. Note that a little bit of type twiddling is required to fully use
32 the result from the \gls{SDS}. This approach is still type safe due to the type
33 safety of \CI{Dynamic}s.
34
35 \begin{lstlisting}[caption={Thermostat example}]
36 thermos :: Task ()
37 thermos = makeDevice "nodeM" nodeMCU >>= connectDevice
38 >>= \nod-> makeDevice "stm32" stm32 >>= connectDevice
39 >>= \stm-> sendTaskToDevice "sensing" sensing (nod, OnInterval 1000)
40 >>= \(st, [t])->sendTaskToDevice "acting" acting (stm, OnInterval 1000)
41 (\(BCValue s)->set (BCValue $ dynInt (dynamic s) > 0) (shareShare nod a))
42 >>| treturn ()
43 where
44 dynInt :: Dynamic -> Int
45 dynInt (a :: Int) = a
46
47 sensing = sds \x=0 In {main=
48 x =. analogRead A0 :. pub x
49 }
50 acting = sds \cool=False In {main=
51 IF cool (ledOn LED1) (ledOff LED1) :.
52 digitalWrite D5 cool
53 }
54 nodeMCU = TCP
55 \end{lstlisting}
56
57 \subsection[Lifting mTasks to iTasks-Tasks]%
58 {Lifting \gls{mTask}-\glspl{Task} to \gls{iTasks}-\glspl{Task}}
59 If the user does not want to know where and when an \gls{mTask} is actually
60 executed and is just interested in the results, it can lift the \gls{mTask} to
61 an \gls{iTasks}-\gls{Task}. The function is called with a name, \gls{mTask},
62 device and interval specification and it will return a \gls{Task} that finishes
63 if and only if the \gls{mTask} has returned.
64
65 \begin{lstlisting}[caption={Lifting \gls{mTask}-\glspl{Task} to \gls{iTasks}}]
66 liftmTask :: String (Main (ByteCode () Stmt)) (MTaskDevice, MTaskInterval) -> Task [MTaskShare]
67 liftmTask wta mTask c=:(dev, _)= sendTaskToDevice wta mTask c
68 >>= \(t, shs)->wait "Waiting for mTask to return" (taskRemoved t) (deviceShare dev)
69 >>| viewInformation "Done!" [] ()
70 >>| treturn shs
71 where
72 taskRemoved t d = isNothing $ find (\t1->t1.ident==t.ident) d.deviceTasks
73 \end{lstlisting}
74
75 The factorial function example from Chapter~\ref{chp:mtaskcont} can then be
76 lifted to a real \gls{iTasks}-\gls{Task} with the following code:
77 \begin{lstlisting}[caption={Lifting the factorial \gls{Task} to \gls{iTasks}}]
78 factorial :: MTaskDevice -> Task BCValue
79 factorial dev = enterInformation "Factorial of ?" []
80 >>= \fac->liftmTask "fact" (fact fac) (dev, OnInterval 100)
81 @ fromJust o find (\x->x.humanName == "result")
82 @ \s->s.MTaskShare.value
83 where
84 fact i = sds \y=i
85 In namedsds \x=(1 Named "result")
86 In {main = IF (y <=. lit 1)
87 ( pub x :. retrn )
88 ( x =. x *. y :. y =. y -. lit 1 )}
89 \end{lstlisting}
90
91 \subsection{Heartbeat \& Oxygen Saturation Sensor}
92 As an example, the addition of a new sensor will be demonstrated. The heartbeat
93 and oxygen saturation sensor add-on is a \textsc{PCB} the size of a fingernail
94 with a red \gls{LED} and a light sensor on it. Moreover, it contains an
95 \textsc{I2C} chip to communicate. The company producing the chip provides the
96 programmer with example code for \gls{Arduino} and \gls{mbed}. The sensor
97 emits red light and measures the intensity of the light returned. The
98 microcontroller hosting the device has to keep track of four seconds of samples
99 to determine the heartbeat. In the \gls{mTask}-system, an abstraction is made.
100 The current implementation runs on \gls{mbed} supported devices.
101
102 \subsubsection{\gls{mTask} Classes}
103 First, a class has to be devised to store the functionality of the sensor. The
104 heartbeat sensor updates four values continuously, namely the heartbeat, the
105 oxygen saturation and the validity of the two. For every value a function is
106 added to the new \CI{hb} class. Moreover, the introduced datatype housing the
107 values should implement the \CI{mTaskType} classes. The definition is as
108 follows:
109
110 \begin{lstlisting}[caption={The \texttt{hb} class}]
111 :: Heartbeat = HB Int
112 :: SP02 = SP02 Int
113
114 instance toByteCode Heartbeat, SP02
115 instance fromByteCode Heartbeat, SP02
116 derive class iTask Heartbeat, SP02
117
118 class hb v where
119 getHb :: (v Heartbeat Expr)
120 validHb :: (v Bool Expr)
121 getSp02 :: (v SP02 Expr)
122 validSp02 :: (v Bool Expr)
123 \end{lstlisting}
124
125 \subsubsection{Bytecode Implementation}
126 The class is available now, and the implementation can be created. The
127 implementation is trivial since the functionality is limited to retrieving
128 single values and no assignment is possible. The following code shows the
129 implementation. Dedicated bytecode instructions have been added to support the
130 functionality.
131
132 \begin{lstlisting}[caption={The \texttt{hb} bytecode instance}]
133 :: BC
134 = BCNop
135 | ...
136 | BCGetHB
137 | BCValidHB
138 | BCGetSP02
139 | BCValidSP02
140
141 instance hb ByteCode where
142 getHb = tell` [BCGetHB]
143 validHb = tell` [BCValidHB]
144 getSp02 = tell` [BCGetSP02]
145 validSp02 = tell` [BCValidSP02]
146 \end{lstlisting}
147
148 \subsubsection{Device Interface}
149 The bytecode instructions are added but still the functionality needs to be
150 added to the device interface to be implemented by clients. The following
151 addition to \CI{interface.h} and the interpreter shows the added instructions.
152 When adding a peripheral, the devices not having the peripheral do not need to
153 have their code recompiled. New instructions always get a higher bytecode
154 number if added correctly. The peripheral byte in the device specification by
155 default shows a negative flag for every peripheral. Only the peripherals added
156 will be flagged positive.
157
158 \begin{lstlisting}[caption={Adding the device interface}]
159 // interface.h
160 ...
161 #if HAVEHB == 1
162 uint16_t get_hb();
163 bool valid_hb();
164 uint16_t get_spo2();
165 bool valid_spo2();
166 #endif
167 ...
168
169 // interpret.c
170 while(pc < plen){
171 switch(program[pc++]){
172 ...
173 #if HAVEHB == 1
174 case BCGETHB:
175 stack[sp++] = get_hb();
176 break;
177 case BCVALIDHB:
178 stack[sp++] = valid_hb();
179 break;
180 case BCGETSP02:
181 stack[sp++] = get_spo2();
182 break;
183 case BCVALIDSP02:
184 stack[sp++] = valid_spo2();
185 break;
186 #endif
187 ...
188 \end{lstlisting}
189
190 \subsubsection{Client Software}
191 The device client software always executes the \CI{real\_setup} in which the
192 client software can setup the connection and peripherals. In the case of the
193 heartbeat peripheral it starts a thread running the calculations. The thread
194 started in the setup will set the global heartbeat and oxygen level variables
195 so that the interface functions for it can access it. The code is then as
196 follows:
197
198 \begin{lstlisting}[language=C,caption={}]
199 Serial pc;
200 Thread thread;
201
202 void heartbeat_thread(void) {
203 // Constant heartbeat calculations
204 }
205
206 void real_setup(void) {
207 pc.baud(19200);
208 thread.start(heartbeat_thread);
209 }
210 \end{lstlisting}