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}]
+\begin{lstlisting}[language=Clean,caption={Thermostat example}]
thermos :: Task ()
thermos = makeDevice "nodeM" nodeMCU >>= connectDevice
>>= \nod-> makeDevice "stm32" stm32 >>= connectDevice
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)
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}}]
+\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)
\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:
+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}[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 ...
-\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}
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}
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
...
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}
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;
thread.start(heartbeat_thread);
}
\end{lstlisting}
+
+\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}