X-Git-Url: https://git.martlubbers.net/?a=blobdiff_plain;f=arch.example.tex;h=c905ead0a23eaca28605d476d771df59610c2bf7;hb=1a485d8cb25f32306de56dcdf1305599aadbb909;hp=4b4f48e1e798b1d0a0ee1d51ab2ab52999e819c2;hpb=6548a5ec9ce8e0df67fc4019625ab5238eb1bf71;p=msc-thesis1617.git diff --git a/arch.example.tex b/arch.example.tex index 4b4f48e..c905ead 100644 --- a/arch.example.tex +++ b/arch.example.tex @@ -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}