X-Git-Url: https://git.martlubbers.net/?a=blobdiff_plain;f=arch.example.tex;h=c905ead0a23eaca28605d476d771df59610c2bf7;hb=4f4b21c04bc99e4e7d55a1dcbedbd371d97b2a05;hp=4627aab513943726950eab2c3508e5c345e38ce3;hpb=8e8a168c6713926d7ad7594aefb35dbc84fb46c2;p=msc-thesis1617.git diff --git a/arch.example.tex b/arch.example.tex index 4627aab..c905ead 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,11 +25,12 @@ 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. +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 () @@ -38,7 +39,7 @@ thermos = makeDevice "nodeM" nodeMCU >>= 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 @@ -55,8 +56,8 @@ where \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. @@ -72,7 +73,7 @@ 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: +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 ?" [] @@ -92,9 +93,118 @@ 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. -%TODO Adding peripheral is supposedly simple. +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}