title capitalization
[msc-thesis1617.git] / arch.example.tex
index 4b4f48e..c905ead 100644 (file)
@@ -1 +1,210 @@
-Here comes a description of the demo program.
+\subsection{Framework}
+Systems built with support for \gls{mTask} often follow the same design
+pattern. First the devices are created --- with or without the interaction of
+the user --- and they are then connected. When all devices are registered, the
+\gls{mTask}-\glspl{Task} can be sent and \gls{iTasks}-\glspl{Task} can be
+started to monitor the output. When everything is finished, the devices are
+removed and the system is shut down.
+
+\begin{lstlisting}[language=Clean,label={lst:framework},
+       caption={\gls{mTask} framework for building applications}]
+w :: Task ()
+w =         makeDevice "dev1" (...) >>= connectDevice
+       >>= \dev1->makeDevice "dev2" (...) >>= connectDevice
+       >>= \dev2->...
+       ...
+       >>* [OnAction (Action "Shutdown") $ always
+               $   deleteDevice dev1 >>| deleteDevice dev2
+               >>| ...
+               >>| shutDown 0
+       ]
+\end{lstlisting}
+
+\subsection{Thermostat}
+The thermostat is a classic example program for showing interactions between
+peripherals. The following program shows a system containing two devices. The
+first device --- the sensor --- contains a temperature sensor that measures the
+room temperature. The second device --- the actor --- contains a heater,
+connected to the digital pin \CI{D5}. Moreover, this device contains an
+\gls{LED} to indicate whether the heater is on. The following code shows an
+implementation for this. The code makes use of all the aspects of the
+framework. Note that a little bit of type twiddling is required to fully use
+the result from the \gls{SDS}. This approach is still type safe due to the type
+safety of \CI{Dynamic}s.
+
+\begin{lstlisting}[caption={Thermostat example}]
+thermos :: Task ()
+thermos =           makeDevice "nodeM" nodeMCU >>= connectDevice
+       >>= \nod->      makeDevice "stm32" stm32   >>= connectDevice
+       >>= \stm->      sendTaskToDevice "sensing" sensing (nod, OnInterval 1000)
+       >>= \(st, [t])->sendTaskToDevice "acting" acting (stm, OnInterval 1000)
+                       (\(BCValue s)->set (BCValue $ dynInt (dynamic s) > 0) (shareShare nod a))
+       >>* [OnAction (Action "Shutdown") $ always $ deleteDevice nod >>| deleteDevice stm >>| shutDown 0]
+where
+       dynInt :: Dynamic -> Int
+       dynInt (a :: Int) = a
+
+       sensing = sds \x=0 In {main=
+                       x =. analogRead A0 :. pub x
+               }
+       acting = sds \cool=False In {main=
+                       IF cool (ledOn LED1) (ledOff LED1) :.
+                       digitalWrite D5 cool
+               }
+       nodeMCU = TCP
+\end{lstlisting}
+
+\subsection[Lifting mTasks to iTasks-Tasks]%
+       {Lifting \gls{mTask}-\glspl{Task} to \gls{iTasks}-\glspl{Task}}
+If the user does not want to know where and when an \gls{mTask} is actually
+executed and is just interested in the results, it can lift the \gls{mTask} to
+an \gls{iTasks}-\gls{Task}. The function is called with a name, \gls{mTask},
+device and interval specification and it will return a \gls{Task} that finishes
+if and only if the \gls{mTask} has returned.
+
+\begin{lstlisting}[caption={Lifting \gls{mTask}-\glspl{Task} to \gls{iTasks}}]
+liftmTask :: String (Main (ByteCode () Stmt)) (MTaskDevice, MTaskInterval) -> Task [MTaskShare]
+liftmTask wta mTask c=:(dev, _)= sendTaskToDevice wta mTask c
+       >>= \(t, shs)->wait "Waiting for mTask to return" (taskRemoved t) (deviceShare dev)
+       >>| viewInformation "Done!" [] ()
+       >>| treturn shs
+where
+       taskRemoved t d = isNothing $ find (\t1->t1.ident==t.ident) d.deviceTasks
+\end{lstlisting}
+
+The factorial function example from Chapter~\ref{chp:mtaskcont} can then be
+lifted to a real \gls{iTasks}-\gls{Task} with the following code:
+\begin{lstlisting}[caption={Lifting the factorial \gls{Task} to \gls{iTasks}}]
+factorial :: MTaskDevice -> Task BCValue
+factorial dev = enterInformation "Factorial of ?" []
+       >>= \fac->liftmTask "fact" (fact fac) (dev, OnInterval 100)
+       @         fromJust o find (\x->x.humanName == "result")
+       @         \s->s.MTaskShare.value
+where
+       fact i = sds \y=i
+               In namedsds \x=(1 Named "result")
+               In {main = IF (y <=. lit 1)
+                       ( pub x :. retrn                  )
+                       ( x =. x *. y :.  y =. y -. lit 1 )}
+\end{lstlisting}
+
+\subsection{Heartbeat \& Oxygen Saturation Sensor}
+As an example, the addition of a new sensor will be demonstrated. The heartbeat
+and oxygen saturation sensor add-on is a \textsc{PCB} the size of a fingernail
+with a red \gls{LED} and a light sensor on it. Moreover, it contains an
+\textsc{I2C} chip to communicate. The company producing the chip provides the
+programmer with example code for \gls{Arduino} and \gls{mbed}. The sensor
+emits red light and measures the intensity of the light returned. The
+microcontroller hosting the device has to keep track of four seconds of samples
+to determine the heartbeat. In the \gls{mTask}-system, an abstraction is made.
+The current implementation runs on \gls{mbed} supported devices.
+
+\subsubsection{\gls{mTask} Classes}
+First, a class has to be devised to store the functionality of the sensor. The
+heartbeat sensor updates four values continuously, namely the heartbeat, the
+oxygen saturation and the validity of the two. For every value a function is
+added to the new \CI{hb} class. Moreover, the introduced datatype housing the
+values should implement the \CI{mTaskType} classes. The definition is as
+follows:
+
+\begin{lstlisting}[caption={The \texttt{hb} class}]
+:: Heartbeat = HB Int
+:: SP02      = SP02 Int
+
+instance toByteCode Heartbeat, SP02
+instance fromByteCode Heartbeat, SP02
+derive class iTask Heartbeat, SP02
+
+class hb v where
+       getHb     :: (v Heartbeat Expr)
+       validHb   :: (v Bool Expr)
+       getSp02   :: (v SP02 Expr)
+       validSp02 :: (v Bool Expr)
+\end{lstlisting}
+
+\subsubsection{Bytecode Implementation}
+The class is available now, and the implementation can be created. The
+implementation is trivial since the functionality is limited to retrieving
+single values and no assignment is possible. The following code shows the
+implementation. Dedicated bytecode instructions have been added to support the
+functionality.
+
+\begin{lstlisting}[caption={The \texttt{hb} bytecode instance}]
+:: BC
+       = BCNop
+       | ...
+       | BCGetHB
+       | BCValidHB
+       | BCGetSP02
+       | BCValidSP02
+
+instance hb ByteCode where
+       getHb = tell` [BCGetHB]
+       validHb = tell` [BCValidHB]
+       getSp02 = tell` [BCGetSP02]
+       validSp02 = tell` [BCValidSP02]
+\end{lstlisting}
+
+\subsubsection{Device Interface}
+The bytecode instructions are added but still the functionality needs to be
+added to the device interface to be implemented by clients. The following
+addition to \CI{interface.h} and the interpreter shows the added instructions.
+When adding a peripheral, the devices not having the peripheral do not need to
+have their code recompiled. New instructions always get a higher bytecode
+number if added correctly. The peripheral byte in the device specification by
+default shows a negative flag for every peripheral. Only the peripherals added
+will be flagged positive.
+
+\begin{lstlisting}[caption={Adding the device interface}]
+// interface.h
+...
+#if HAVEHB == 1
+uint16_t get_hb();
+bool     valid_hb();
+uint16_t get_spo2();
+bool     valid_spo2();
+#endif
+...
+
+// interpret.c
+       while(pc < plen){
+               switch(program[pc++]){
+               ...
+#if HAVEHB == 1
+               case BCGETHB:
+                       stack[sp++] = get_hb();
+                       break;
+               case BCVALIDHB:
+                       stack[sp++] = valid_hb();
+                       break;
+               case BCGETSP02:
+                       stack[sp++] = get_spo2();
+                       break;
+               case BCVALIDSP02:
+                       stack[sp++] = valid_spo2();
+                       break;
+#endif
+               ...
+\end{lstlisting}
+
+\subsubsection{Client Software}
+The device client software always executes the \CI{real\_setup} in which the
+client software can setup the connection and peripherals. In the case of the
+heartbeat peripheral it starts a thread running the calculations. The thread
+started in the setup will set the global heartbeat and oxygen level variables
+so that the interface functions for it can access it. The code is then as
+follows:
+
+\begin{lstlisting}[language=C,caption={}]
+Serial pc;
+Thread thread;
+
+void heartbeat_thread(void) {
+       // Constant heartbeat calculations
+}
+
+void real_setup(void) {
+       pc.baud(19200);
+       thread.start(heartbeat_thread);
+}
+\end{lstlisting}