X-Git-Url: https://git.martlubbers.net/?a=blobdiff_plain;f=arch.example.tex;h=b8ef049501f06cf2e90f9e679fd7e4683b36548f;hb=2498dced580be1e7af31a662dadee26c4fd159ed;hp=a65ffd55039bb72885a04221f674bfa9e6ce66da;hpb=e7ac45e3faf8a5a7bb33a02c6122afa09fe29209;p=msc-thesis1617.git diff --git a/arch.example.tex b/arch.example.tex index a65ffd5..b8ef049 100644 --- a/arch.example.tex +++ b/arch.example.tex @@ -1,5 +1,5 @@ \subsection{Framework} -Systems built with support for \gls{mTask} are often following the same design +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 @@ -25,20 +25,21 @@ 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 a led to -indicate whether the heater is on. The following code shows an implementation -for this. The code fully uses the framework. Note that a little bit of type -twiddling is required to fully us 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}] +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}[language=Clean,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)) - >>| treturn () + >>* [OnAction (Action "Shutdown") $ always $ deleteDevice nod >>| deleteDevice stm >>| shutDown 0] where dynInt :: Dynamic -> Int dynInt (a :: Int) = a @@ -50,18 +51,21 @@ where IF cool (ledOn LED1) (ledOff LED1) :. digitalWrite D5 cool } - nodeMCU = TCP + nodeMCU = makeDevice "NodeMCU" + (TCPDevice {host="192.168.0.12", port=8888}) + stm32 = makeDevice "Stm32" + (SerialDevice {devicePath="/dev/ttyUSB0", baudrate=B9600, ...} \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 a \gls{mTask} is actually -executed and is just interested in the results it can lift the \gls{mTask} to +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}}] +\begin{lstlisting}[language=Clean,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) @@ -72,8 +76,8 @@ where \end{lstlisting} The factorial function example from Chapter~\ref{chp:mtaskcont} can then be -lifted to a real \gls{iTasks}-\gls{mTask} with the following code: -\begin{lstlisting}[caption={Lifting the factorial \gls{Task} to \gls{iTasks}}] +lifted to a real \gls{iTasks}-\gls{Task} with the following code: +\begin{lstlisting}[language=Clean,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) @@ -92,33 +96,41 @@ 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 \textsc{mbed}. The sensor -emits red light and measures the returning light intensity. 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 \textsc{mbed} supported devices. +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 -validity of the reading, the oxygen saturation and the validity of it. For -every value a function is added to the new \CI{hb} class. Moreover, the +oxygen saturation and the validity of the two. The real value and the validity +are combined in an \gls{ADT} and functions are added for both of them in the +new \CI{hb} class. The values are combined in such a way that they fit in a 16 +bit integer with the last bit representing the validity of the reading. 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 +\begin{lstlisting}[language=Clean,% + caption={The \texttt{hb} class and class implementations}] +:: Heartbeat = HB Int Bool +:: SP02 = SP02 Int Bool + +instance toByteCode Heartbeat + where toByteCode (HB i b) = "h" +++ (to16bit $ (i << 1) bitand (if b 1 0)) +instance toByteCode SP02 where ... + +instance fromByteCode Heartbeat + where fromByteCode s = let i = fromByteCode s //The Int from bytecode + in HB (i >> 1) (i bitand 1 > 0) +instance fromByteCode SP02 where ... -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} @@ -128,36 +140,34 @@ 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}] +\begin{lstlisting}[language=Clean,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}] +\begin{lstlisting}[language=Clean,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 ... @@ -169,15 +179,9 @@ bool valid_spo2(); 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} @@ -187,10 +191,13 @@ 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: +so that the interface functions for it can access it. This is listed in +Listing~\ref{lst:hbding}. If interrupts were implemented, the \glspl{Task} +using the heartbeat sensor could be executed on interrupt. The heartbeat thread +can fire an interrupt everytime it calculated a new heartbeat. -\begin{lstlisting}[language=C,caption={}] +\begin{lstlisting}[label={lst:hbding},language=C,% + caption={Heartbeat code in the client}] Serial pc; Thread thread; @@ -204,5 +211,30 @@ void real_setup(void) { } \end{lstlisting} -\subsubsection{Example Program} -% todo +\subsubsection{Example} +The following code shows a complete example of a \gls{Task} controlling an +\emph{STM} microcontroller containing a heartbeat sensor. The web application +belonging to the server shows the heartbeat value and starts an alert +\gls{Task} when it exceeds the value given or is no longer valid. +This example also shows how named \gls{SDS} are handled. + +\begin{lstlisting}[language=Clean,caption={Heartbeat example}] +hbwatch :: (Task a) Int -> Task () +hbwatch alert lim + = makeDevice "stm32" stm32 + >>= connectDevice + >>= \stm ->sendTaskToDevice "monitor" monitor (stm, OnInterval 200) + >>= \(t, sh)->mon (fromJust $ find (\x->x.name == "hb") sh) + >>* [OnAction (Action "Shutdown") $ always $ deleteDevice stm >>| shutDown 0] +where + mon :: (Shared BCValue) -> Task () + mon b = whileUnchanged (mapRead dynHB b) + \hb=:(HB i valid)->if (not valid || i > lim) + alert (viewInformation "HB Okay" [] hb) + + dynHB :: Dynamic -> HeartBeat + dynHB (a :: HeartBeat) = a + + monitor = namedsds \hb=(0 Named hb) In + {main= hb = getHB :. pub hb } +\end{lstlisting}