From 2925b1f5ecee47e6d0893e5640323ff694c4cd28 Mon Sep 17 00:00:00 2001 From: Mart Lubbers Date: Fri, 18 Nov 2022 15:42:26 +0100 Subject: [PATCH] updates --- back/research_data_management.tex | 2 +- dsl/class_deep_embedding.tex | 4 +- dsl/first-class_datatypes.tex | 12 +- front/titlepage.tex | 2 +- glossaries.tex | 7 +- intro/intro.tex | 16 +- preamble.tex | 5 +- subfileprefix.tex | 4 +- top/green.tex | 383 +++++++++++++++++++++++++----- top/top.tex | 8 +- tvt/tvt.tex | 2 +- 11 files changed, 360 insertions(+), 85 deletions(-) diff --git a/back/research_data_management.tex b/back/research_data_management.tex index 68c4ae3..52de648 100644 --- a/back/research_data_management.tex +++ b/back/research_data_management.tex @@ -6,7 +6,7 @@ \chapter{Research Data Management}% \label{chp:research_data_management} -This thesis research has been carried out under the research data management policy of the Institute for Computing and Information Science of Radboud University, the Netherlands\footnote{\url{https://www.ru.nl/icis/research-data-management/}, last accessed \formatdate{20}{1}{2020}.}. +This thesis research has been carried out under the research data management policy of the Institute for Computing and Information Science of Radboud University, the Netherlands.\footnote{\url{https://www.ru.nl/icis/research-data-management/}, last accessed \formatdate{20}{1}{2020}.} The following research datasets have been produced during this PhD research: \begin{itemize} diff --git a/dsl/class_deep_embedding.tex b/dsl/class_deep_embedding.tex index 1cd911f..e39a88e 100644 --- a/dsl/class_deep_embedding.tex +++ b/dsl/class_deep_embedding.tex @@ -263,7 +263,7 @@ e2p = Ext_2 (Lit_2 42 `Sub_2` Lit_2 1) \subsection{Unbraiding the semantics from the data} This approach does reveal a minor problem. Namely, that all semantics type classes are braided into our datatypes via the \haskelllhstexinline{Ext_2} constructor. -Say if we add the printer again, the \haskelllhstexinline{Ext_2} constructor has to be modified to contain the printer type class constraint as well\footnote{Resulting in the following constructor: \haskelllhstexinline{forall x.(Eval_2 x, Print_2 x) => Ext_2 x}.}. %chktex 36 +Say if we add the printer again, the \haskelllhstexinline{Ext_2} constructor has to be modified to contain the printer type class constraint as well.\footnote{Resulting in the following constructor: \haskelllhstexinline{forall x.(Eval_2 x, Print_2 x) => Ext_2 x}.} %chktex 36 Thus, if we add semantics, the main data type's type class constraints in the \haskelllhstexinline{Ext_2} constructor need to be updated. To avoid this, the type classes can be bundled in a type class alias or type class collection as follows. @@ -805,7 +805,7 @@ instance (c (d c0), CreateRecord (d c0) cs) => The class constraints for the interpretation instances can now be greatly simplified, as shown in the evaluation instance for \haskelllhstexinline{Expr}. The implementation remains the same, only that for the extension case, a trick needs to be applied to convince the compiler of the correct instances. Using \haskelllhstexinline{`In`}'s \haskelllhstexinline{project} function, a dictionary can be brought into scope. -This dictionary can then subsequently be used to apply the type class function on the extension using the \haskelllhstexinline{withDict} function from the \haskelllhstexinline{Data.Constraint} library\footnote{\haskelllhstexinline{withDict :: Dict c -> (c => r) -> r}}. +This dictionary can then subsequently be used to apply the type class function on the extension using the \haskelllhstexinline{withDict} function from the \haskelllhstexinline{Data.Constraint} library.\footnote{\haskelllhstexinline{withDict :: Dict c -> (c => r) -> r}} The \GHCmod{ScopedTypeVariables} extension is used to make sure the existentially quantified type variable for the extension is matched to the type of the dictionary. Furthermore, because the class constraint is not smaller than the instance head, \GHCmod{UndecidableInstances} should be enabled. diff --git a/dsl/first-class_datatypes.tex b/dsl/first-class_datatypes.tex index 4c7f06f..e269a22 100644 --- a/dsl/first-class_datatypes.tex +++ b/dsl/first-class_datatypes.tex @@ -74,7 +74,7 @@ infixl 6 +. The implementation of a view on the \gls{DSL} is achieved by implementing the type classes with the data type representing the view. In the case of our example \gls{DSL}, an interpreter accounting for failure may be implemented as an instance for the \haskellinline{Maybe} type. -The standard infix functor application and infix sequential application are used so that potential failure is abstracted away from\footnotemark{}. +The standard infix functor application and infix sequential application are used so that potential failure is abstracted away from.\footnotemark{} \begin{lrbox}{\LstBox} \begin{lstHaskell}[frame=] <$> :: (a -> b) -> f a -> f b @@ -113,7 +113,7 @@ instance Div Maybe where \subsection{Adding semantics} To add semantics to the \gls{DSL}, the existing classes are implemented with a novel data type representing the view on the \gls{DSL}. -First a data type representing the semantics is defined. In this case, the printer is kept very simple for brevity and just defined as a \haskellinline{newtype} of a string to store the printed representation\footnotemark{}. +First a data type representing the semantics is defined. In this case, the printer is kept very simple for brevity and just defined as a \haskellinline{newtype} of a string to store the printed representation.\footnotemark{} \footnotetext{% In this case a \haskellinline{newtype} is used instead of regular \haskellinline{data} declarations. \haskellinline{newtype}s are special data types only consisting a single constructor with one field to which the type is isomorphic. @@ -152,7 +152,7 @@ data In a b = a :- b infix 1 :- \end{lstHaskell} -Using the \haskellinline{Function} type class can be used to define functions with little syntactic overhead\footnote{The \GHCmod{LambdaCase} extension of GHC is used to reduce the number of brackets that allows lambda's to be an argument to a function without brackets or explicit function application using \haskellinline{\$}}. +Using the \haskellinline{Function} type class can be used to define functions with little syntactic overhead.\footnote{The \GHCmod{LambdaCase} extension of GHC is used to reduce the number of brackets that allows lambda's to be an argument to a function without brackets or explicit function application using \haskellinline{\$}} The following listing shows an expression in the \gls{DSL} utilising two user-defined functions: \begin{lstHaskell} @@ -345,7 +345,7 @@ The \haskellinline{Info} type is an \gls{ADT} containing all the---known to the With the power of metaprogramming, we can generate the boilerplate code for our user-defined data types automatically at compile time. To generate the code required for the \gls{DSL}, we define the \haskellinline{genDSL} function. The type belonging to the name passed as an argument to this function is made available for the \gls{DSL} by generating the \haskellinline{typeDSL} class and view instances. -For the \haskellinline{List} type it is called as: \haskellinline{\$(genDSL ''List)}\footnotemark{}. +For the \haskellinline{List} type it is called as: \haskellinline{\$(genDSL ''List)}.\footnotemark{} \footnotetext{ \haskellinline{''} is used instead of \haskellinline{'} to instruct the compiler to look up the information for \haskellinline{List} as a type and not as a constructor. } @@ -494,7 +494,7 @@ The interpreter is a view on the \gls{DSL} that immediately executes all operati Therefore, the constructor function can be implemented by lifting the actual constructor to the \haskellinline{Maybe} type using sequential application. I.e.\ for a constructor $C_k$ this results in the following constructor: \haskellinline{ck a0 ... am = pure Ck <*> a0 <*> ... <*> am}. To avoid accidental shadowing, fresh names for all the arguments are generated. -The \haskellinline{ifx} function is used as a shorthand for defining infix expressions\footnotemark{} +The \haskellinline{ifx} function is used as a shorthand for defining infix expressions.\footnotemark{} \begin{lrbox}{\LstBox} \begin{lstHaskell}[frame=] ifx :: String -> Q Exp -> Q Exp -> Q Exp @@ -518,7 +518,7 @@ In the case of a deconstructor a function with two arguments is created: the obj To avoid accidental shadowing first fresh names for the arguments and fields are generated. Then, a function is created with the two arguments. First \haskellinline{d} is evaluated and bound to a host language function that deconstructs the constructor and passes the fields to \haskellinline{f}. -I.e.\ a deconstructor function $C_k$ is defined as: \haskellinline{unCk d f = d >>= \\(Ck a0 .. am)->f (pure a0) ... (pure am))}\footnotemark{}. +I.e.\ a deconstructor function $C_k$ is defined as: \haskellinline{unCk d f = d >>= \\(Ck a0 .. am)->f (pure a0) ... (pure am))}.\footnotemark{} \footnotetext{ The \haskellinline{nameBase :: Name -> String} function from the \gls{TH} library is used to convert a name to a string. } diff --git a/front/titlepage.tex b/front/titlepage.tex index 37cf871..0dc88e3 100644 --- a/front/titlepage.tex +++ b/front/titlepage.tex @@ -57,7 +57,7 @@ \begin{itemize}[wide,label={},leftmargin=*,itemsep=\baselineskip] \item Promotor: \begin{itemize}[label={}] - \item prof.em.\ dr.\ dr.h.c.\ ir.\ M.J.\ (Rinus)\ Plasmeijer\todo{em.\ erbij of niet?} + \item prof.\ dr.\ dr.h.c.\ ir.\ M.J.\ (Rinus)\ Plasmeijer\todo{em.\ erbij of niet?} \end{itemize} \item Copromotoren: \begin{itemize}[label={}] diff --git a/glossaries.tex b/glossaries.tex index 4b09424..345d351 100644 --- a/glossaries.tex +++ b/glossaries.tex @@ -29,7 +29,8 @@ \myacronym{IOT}{Io\kern-.3mmT}{internet of things} \myacronym{IDE}{IDE}{integrated development environment} \myacronym{IO}{I/O}{input/output} -\myacronym{IR}{IL}{intermediate representation} +\myacronym{IR}{IR}{intermediate representation} +\myacronym{ISR}{ISR}{interrupt service routine} \myacronym{LEAN}{LEAN}{language of East-Anglia and Nijmegen} \myacronym[prefixfirst={a\ },prefix={an\ }]{LED}{LED}{light-emitting diode} \myacronym{OLED}{OLED}{organic \glsxtrlong{LED}} @@ -103,11 +104,11 @@ } \newglossaryentry{I2C}{ name=I\textsuperscript{2}C, - description={is a simple serial communication protocol often used to connect sensors to microcontrollers} + description={(Inter-Integrated Circuit) is a simple serial communication protocol often used to connect sensors to microcontrollers} } \newglossaryentry{SPI}{ name=SPI, - description={is a synchronous serial communication protocol often used to connect sensors to microcontrollers} + description={(Serial Peripheral Interface) is a synchronous serial communication protocol often used to connect sensors to microcontrollers} } \newglossaryentry{TINYML}{ name=TinyML, diff --git a/intro/intro.tex b/intro/intro.tex index 7896e62..608cb8a 100644 --- a/intro/intro.tex +++ b/intro/intro.tex @@ -15,7 +15,7 @@ \end{itemize} \end{chapterabstract} -There are at least 13.4 billion devices connected to the internet at the time of writing\footnote{\url{https://transformainsights.com/research/tam/market}, accessed on: \formatdate{13}{10}{2022}}. +There are at least 13.4 billion devices connected to the internet at the time of writing.\footnote{\url{https://transformainsights.com/research/tam/market}, accessed on: \formatdate{13}{10}{2022}} Each and every one of those devices senses, acts, or otherwise interacts with people, other computers, and the environment surrounding us. Even though there is a substantial variety among these devices, they have one thing in common: they all computers to some degree and for this reason require software to operate. @@ -322,19 +322,19 @@ It provides a gentle introduction to the \gls{MTASK} system elaborates on \gls{T While the language was a lot different from later versions, the integration mechanism is still used in \gls{MTASK} today. % \paragraph{Contribution} % The research in this paper and writing the paper was performed by me, though there were weekly meetings with Pieter Koopman and Rinus Plasmeijer in which we discussed and refined the ideas. - \item \emph{Multitasking on Microcontrollers using Task Oriented Programming} \citep{lubbers_multitasking_2019}\footnote{% + \item \emph{Multitasking on Microcontrollers using Task Oriented Programming} \citep{lubbers_multitasking_2019}.\footnote{% This work acknowledges the support of the ERASMUS+ project ``Focusing Education on Composability, Comprehensibility and Correctness of Working Software'', no. 2017--1--SK01--KA203--035402 - }. + } This paper was a short paper on the multitasking capabilities of \gls{MTASK} in contrast to traditional multitasking methods for \gls{ARDUINO}. % \paragraph{Contribution} % The research in this paper and writing the paper was performed by me, though there were weekly meetings with Pieter Koopman and Rinus Plasmeijer. - \item \emph{Simulation of a Task-Based Embedded Domain Specific Language for the Internet of Things} \citep{koopman_simulation_2018}\footnotemark[\value{footnote}]. + \item \emph{Simulation of a Task-Based Embedded Domain Specific Language for the Internet of Things} \citep{koopman_simulation_2018}.\footnotemark[\value{footnote}] These revised lecture notes are from a course on the \gls{MTASK} simulator was provided at the 2018 \gls{CEFP}/\gls{3COWS} winter school in Ko\v{s}ice, Slovakia. % \paragraph{Contribution} % Pieter Koopman wrote and taught it, I helped with the software and research. - \item \emph{Writing Internet of Things Applications with Task Oriented Programming} \citep{lubbers_writing_2019}\footnotemark[\value{footnote}]. + \item \emph{Writing Internet of Things Applications with Task Oriented Programming} \citep{lubbers_writing_2019}.\footnotemark[\value{footnote}] These revised lecture notes are from a course on programming in \gls{MTASK} provided at the 2019 \gls{CEFP}/\gls{3COWS} summer school in Budapest, Hungary. % \paragraph{Contribution} @@ -351,8 +351,8 @@ It provides a gentle introduction to the \gls{MTASK} system elaborates on \gls{T % \paragraph{Contribution} % The research was carried out by \citet{crooijmans_reducing_2021} during his Master's thesis. % I did the daily supervision and helped with the research, Pieter Koopman was the formal supervisor and wrote most of the paper. - \item \emph{Green Computing for the Internet of Things}\footnote{ - This work acknowledges the support of the Erasmus+ project ``SusTrainable---Promoting Sustainability as a Fundamental Driver in Software Development Training and Education'', no. 2020--1--PT01--KA203--078646}. + \item \emph{Green Computing for the Internet of Things}.\footnote{ + This work acknowledges the support of the Erasmus+ project ``SusTrainable---Promoting Sustainability as a Fundamental Driver in Software Development Training and Education'', no. 2020--1--PT01--KA203--078646} % \paragraph{Contribution} % These revised lecture notes are from a course on sustainable programming using \gls{MTASK} provided at the 2022 SusTrainable summer school in Rijeka, Croatia. @@ -367,7 +367,7 @@ The paper of which I am first author are written by me. \subsection{\nameref{prt:tvt}} \Cref{prt:tvt} is based on a journal paper that quantitatively and qualitatively compares traditional \gls{IOT} architectures with \gls{IOT} systems using \gls{TOP} and contains a single chapter. -This chapter is based on the journal paper: \emph{Could Tierless Programming Reduce IoT Development Grief?} \citep{lubbers_could_2022}\footnote{This work is an extension of the conference article: \emph{Tiered versus Tierless IoT Stacks: Comparing Smart Campus Software Architectures} \citep{lubbers_tiered_2020}\footnotemark{}}. +This chapter is based on the journal paper: \emph{Could Tierless Programming Reduce IoT Development Grief?} \citep{lubbers_could_2022}.\footnote{This work is an extension of the conference article: \emph{Tiered versus Tierless IoT Stacks: Comparing Smart Campus Software Architectures} \citep{lubbers_tiered_2020}.\footnotemark{}} \footnotetext{This paper was partly funded by the Radboud-Glasgow Collaboration Fund.} It compares programming traditional tiered architectures to tierless architectures by showing a qualitative and a quantitative four-way comparison of a smart-campus application. diff --git a/preamble.tex b/preamble.tex index ea67fd6..965fc41 100644 --- a/preamble.tex +++ b/preamble.tex @@ -20,6 +20,7 @@ \everymath{\it\/} \DeclareMathSymbol{\shortminus}{\mathbin}{AMSa}{"39} %chktex 18 \newcommand{\dcolon}[0]{\mathbin{::}} +\newcommand{\refreshrate}[2]{\langle{}#1, #2\rangle{}} % Internationalisation \usepackage[dutch,russian,british]{babel} @@ -161,7 +162,7 @@ % Code % Pseudocode -\usepackage[algochapter]{algorithm2e} +\usepackage[algochapter,linesnumbered,lined,boxed]{algorithm2e} % Fix the algorithm font \renewcommand\AlCapFnt{\normalfont} \usepackage{listings} @@ -191,7 +192,6 @@ tabsize=4, upquote=true, numberstyle=\tiny, - texcl=true; } \usepackage{lstlangclean} \usepackage{lstlanghaskell} @@ -276,6 +276,7 @@ \usepackage{nameref} % to reference names of chapters \newcommand{\fullref}[1]{\cref{#1}: \nameref{#1}} \newcommand{\Fullref}[1]{\Cref{#1}: \nameref{#1}} +\creflabelformat{equation}{#2\textup{#1}#3} % Glossaries and acronyms \usepackage[nolangwarn,abbreviations,nonumberlist,prefix]{glossaries-extra} diff --git a/subfileprefix.tex b/subfileprefix.tex index b28e519..4ff83ee 100644 --- a/subfileprefix.tex +++ b/subfileprefix.tex @@ -1,5 +1,3 @@ \ifSubfilesClassLoaded{% \tableofcontents -}{ - -} +}{} diff --git a/top/green.tex b/top/green.tex index fed73ef..a755798 100644 --- a/top/green.tex +++ b/top/green.tex @@ -25,6 +25,8 @@ Determining when exactly and for how long it is possible to sleep is expensive i \begin{table} \centering + \caption{Current use in \unit{\milli\ampere} of two microprocessor boards in various sleep modes.}% + \label{tbl:top_sleep} \small \begin{tabular}{ccccccccc} \toprule @@ -40,8 +42,6 @@ Determining when exactly and for how long it is possible to sleep is expensive i current & 100--240 & 15 & 0.5 & 0.002 & 90--300 & 5 & 2 & 0.005\\ \bottomrule \end{tabular} - \caption{Current use in \unit{\milli\ampere} of two microprocessor boards in various sleep modes.}% - \label{tbl:top_sleep} \end{table} \Cref{tbl:top_sleep} shows the properties and current consumption of two commonly used microcontrollers. @@ -75,8 +75,6 @@ For example, the \gls{RTS} never attempts to sleep during an \gls{I2C} communica An \gls{MTASK} program is dynamically transformed to byte code. This byte code and the initial \gls{MTASK} expression are shipped to \gls{MTASK} \gls{IOT} node. -For the example in \cref{lst:blink} there is byte code representing the \cleaninline{blink} function and \cleaninline{main} determines the initial expression. - The \gls{MTASK} rewrite engine rewrites the current expression just a single rewrite step at a time. When subtasks are composed in parallel, all subtasks are rewritten unless the result of the first rewrite step makes the result of the other tasks superfluous. The task design ensures such that all time critical communication with peripherals is within a single rewrite step. @@ -86,7 +84,7 @@ This is very convenient, since the system can inspect the current state of all \ Even infinite sequences rewrite steps, as in the \cleaninline{blink} example, are perfectly fine. The \gls{MTASK} system does proper tail-call optimizations to facilitate this. -\section{Task scheduling} +\section{Task scheduling in the \gls{MTASK} language} Some \gls{MTASK} examples contain one or more explicit \cleaninline{delay} primitives, offering a natural place for the node executing it to pause. However, there are many \gls{MTASK} programs that just specify a repeated set of primitives. A typical example is the program that reads the temperature for a sensor and sets the system \gls{LED} if the reading is below some given \cleaninline{goal}. @@ -94,10 +92,8 @@ A typical example is the program that reads the temperature for a sensor and set \begin{lstClean}[caption={A basic thermostat task.},label={lst:thermostat}] thermostat :: Main (MTask v Bool) | mtask v thermostat = DHT I2Caddr \dht-> - {main = rpeat ( - temperature dht >>~. \temp. - writeD builtInLED (goal <. temp) - )} + {main = rpeat ( temperature dht >>~. \temp. + writeD builtInLED (goal <. temp))} \end{lstClean} This program repeatedly reads the \gls{DHT} sensor and sets the on-board \gls{LED} based on the comparison with the \cleaninline{goal} as fast as possible on the \gls{MTASK} node. @@ -115,7 +111,7 @@ Both solutions rely on an explicit action of the programmer. Fortunately, \gls{MTASK} also contains machinery to do this automatically. The key of this solution is to associate dynamically an evaluation interval with each task. -The interval $\left\langle low, high \right\rangle$ indicates that the evaluation can be safely delayed by any number of milliseconds in that range. +The interval $\refreshrate{low}{high}$ indicates that the evaluation can be safely delayed by any number of milliseconds in that range. Such an interval is just a hint for the \gls{RTS}. It is not a guarantee that the evaluation takes place in the given interval. Other parts of the task expression can force an earlier evaluation of this part of the task. @@ -127,26 +123,26 @@ This has the advantage that the programmer does not have to deal with them and t We start by assigning default refresh rates to basic tasks. These refresh rates reflect the expected change rates of sensors and other inputs. -Writing to basic \gls{GPIO} pins and actuators has refresh rate $\langle 0, 0 \rangle$, this is never delayed. +Writing to basic \gls{GPIO} pins and actuators has refresh rate $\refreshrate{0}{0}$, this is never delayed. \begin{table} \centering + \caption{Default refresh rates of basic tasks.}% + \label{tbl:refresh} \begin{tabular}{ll} \toprule task & default interval \\ \midrule - reading \pgls{SDS} & $\langle 0, 2000 \rangle$ \\ - slow sensor, like temperature & $\langle 0, 2000 \rangle$ \\ - gesture sensor & $\langle 0, 1000 \rangle$ \\ - fast sensor, like sound or light & $\langle 0, 100 \rangle$ \\ - reading GPIO pins & $\langle 0, 100 \rangle$ \\ + reading \pgls{SDS} & $\refreshrate{0}{2000}$ \\ + slow sensor, like temperature & $\refreshrate{0}{2000}$ \\ + gesture sensor & $\refreshrate{0}{1000}$ \\ + fast sensor, like sound or light & $\refreshrate{0}{100}$ \\ + reading GPIO pins & $\refreshrate{0}{100}$ \\ \bottomrule \end{tabular} - \caption{Default refresh rates of basic tasks.}% - \label{tbl:refresh} \end{table} -\subsection{Deriving Refresh Rates} +\subsection{Deriving Refresh Rates}\label{sec:deriving_refresh_rates} Based on these refresh rates, the system can automatically derive refresh rates for composed \gls{MTASK} expressions using $\mathcal{R}$. We use the operator $\cap_{\textit{safe}}$ to compose refresh ranges. When the ranges overlap the result is the overlapping range. @@ -155,27 +151,27 @@ The rationale is that subtasks should not be delayed longer than their refresh r Evaluating a task earlier should not change its result but can consume more energy. \begin{align} - \cap_{\textit{safe}} :: \langle \mathit{Int}, \mathit{Int} \rangle \; \langle \mathit{Int}, \mathit{Int} \rangle & \shortrightarrow \langle \mathit{Int}, \mathit{Int} \rangle & \notag \\ + \cap_{\textit{safe}} :: \refreshrate{\mathit{Int}}{\mathit{Int}} \; \refreshrate{\mathit{Int}}{\mathit{Int}} & \shortrightarrow \refreshrate{\mathit{Int}}{\mathit{Int}} & \notag \\ R_1 \cap_{\textit{safe}} R_2 & = R_1 \cap R_2 & \text{if } R_1 \cap R_2 \neq \emptyset \\ - \langle l_1, h_1 \rangle \cap_{\textit{safe}} \langle l_2, h_2 \rangle & = \langle l_2, h_2 \rangle & \text{if } h_2 < l_1 \\ + \refreshrate{l_1}{h_1} \cap_{\textit{safe}} \refreshrate{l_2}{h_2} & = \refreshrate{l_2}{h_2} & \text{if } h_2 < l_1 \\ R_1 \cap_{\textit{safe}} R_2 & = R_1 & \text{otherwise} \end{align} \begin{align} - \mathcal{R} :: (\mathit{MTask}~v~a) & \shortrightarrow \langle \mathit{Int}, \mathit{Int} \rangle \notag \\ + \mathcal{R} :: (\mathit{MTask}~v~a) & \shortrightarrow \refreshrate{\mathit{Int}}{\mathit{Int}} \notag \\ \mathcal{R} (t_1~{.||.}~t_2) & = \mathcal{R}(t_1) \cap_{\textit{safe}} \mathcal{R}(t_2) \label{R:or} \\ \mathcal{R}(t_1~{.\&\&.}~t_2) & = \mathcal{R}(t_1) \cap_{\textit{safe}} \mathcal{R}(t_2) \label{R:and}\\ \mathcal{R}(t_1~{>\!\!>\!|.}~t_2) & = \mathcal{R}(t_1) \label{R:seq} \\ \mathcal{R}(t~{>\!\!>\!=.}~f) & = \mathcal{R}(t) \label{R:bind} \\ \mathcal{R}(t~{>\!\!>\!\!*.}~[a_1 \ldots a_n]) & = \mathcal{R}(t) \label{R:step} \\ - \mathcal{R}(\mathit{rpeat}~t) & = \langle 0, 0 \rangle \label{R:rpeat} \\ - \mathcal{R}(\mathit{rpeatEvery}~d~t) & = \langle 0, 0 \rangle \label{R:rpeatevery} \\ - \mathcal{R}(delay~d) & = \langle d, d \rangle \label{R:delay} \\ + \mathcal{R}(\mathit{rpeat}~t) & = \refreshrate{0}{0} \label{R:rpeat} \\ + \mathcal{R}(\mathit{rpeatEvery}~d~t) & = \refreshrate{0}{0} \label{R:rpeatevery} \\ + \mathcal{R}(delay~d) & = \refreshrate{d}{d} \label{R:delay} \\ \mathcal{R}(t) & = \left\{% \begin{array}{ll} - \langle \infty, \infty \rangle~& \text{if}~t~\text{is Stable} \\ - \langle r_l, r_u \rangle & \text{otherwise} + \refreshrate{\infty}{\infty}~& \text{if}~t~\text{is Stable} \\ + \refreshrate{r_l}{r_u} & \text{otherwise} \end{array} \right.\label{R:other} \end{align} @@ -213,6 +209,8 @@ Only the actual reading of the sensor with \cleaninline{temperature dht} offers %%\begin{table}[tb] \begin{table} \centering + \caption{Rewrite steps of the thermostat from \cref{lst:thermostat} and associated intervals.}% + \label{tbl:intervals} \begin{tabular}{cp{20em}c} \toprule Step & Expression & Interval \\ @@ -223,7 +221,7 @@ rpeat ( temperature dht >>~. \temp. writeD builtInLED (goal <. temp) )\end{lstClean} & - $\langle 0, 0 \rangle$ \\ + $\refreshrate{0}{0}$ \\ %\hline 1 & \begin{lstClean}[aboveskip=-2ex,belowskip=-2ex,frame=] @@ -232,7 +230,7 @@ writeD builtInLED (goal <. temp) >>|. rpeat ( temperature dht >>~. \temp. writeD builtInLED (goal <. temp) )\end{lstClean} - & $\langle 0, 2000 \rangle$ \\ + & $\refreshrate{0}{2000}$ \\ %\hline 2 & \begin{lstClean}[aboveskip=-2ex,belowskip=-2ex,frame=] @@ -240,18 +238,35 @@ writeD builtInLED false >>|. rpeat ( temperature dht >>~. \temp. writeD builtInLED (goal <. temp) )\end{lstClean} - & $\langle 0, 0 \rangle$ \\ + & $\refreshrate{0}{0}$ \\ \bottomrule \end{tabular} - \caption{Rewrite steps of the thermostat from \cref{lst:thermostat} and associated intervals.}% - \label{tbl:intervals} \end{table} \subsection{User Defined Refresh Rates} -In some applications, it is necessary to read sensors at a different rate than the default rate given in \cref{tbl:refresh}, i.e.\ to customise the refresh rate. +A tailor-made \gls{ADT} (see \cref{lst:interval}) determines the timing intervals for which the value is determined at runtime but the constructor is known at compile time. +During compilation, the constructor of the \gls{ADT} is checked and code is generated accordingly. +If it is \cleaninline{Default}, no extra code is generated. +In the other cases, code is generated to wrap the task tree node in a \emph{tune rate} node. +In the case that there is a lower bound, i.e.\ the task must not be executed before this lower bound, an extra \emph{rate limit} task tree node is generated that performs a no-op rewrite if the lower bound has not passed but caches the task value. + +\begin{lstClean}[caption={The \gls{ADT} for timing intervals in \gls{MTASK}.},label={lst:interval}] +:: TimingInterval v = Default + | BeforeMs (v Int) // yields [+$\refreshrate{0}{x}$+] + | BeforeS (v Int) // yields [+$\refreshrate{0}{x \times 1000}$+] + | ExactMs (v Int) // yields [+$\refreshrate{x}{x}$+] + | ExactS (v Int) // yields [+$\refreshrate{0}{x \times 1000}$+] + | RangeMs (v Int) (v Int) // yields [+$\refreshrate{x}{y}$+] + | RangeS (v Int) (v Int) // yields [+$\refreshrate{x \times 1000}{y \times 1000}$+] +\end{lstClean} + +\subsubsection{Sensors and \texorpdfstring{\glspl{SDS}}{shared data sources}} +In some applications, it is necessary to read sensors or \glspl{SDS} at a different rate than the default rate given in \cref{tbl:refresh}, i.e.\ to customise the refresh rate. This is achieved by calling the access functions with a custom refresh rate as an additional argument (suffixed with the backtick (\cleaninline{`})) +The adaptions to other classes are similar and omitted for brevity. +\Cref{lst:dht_ext} shows the extended \cleaninline{dht} and \cleaninline{dio} class definition with functions for custom refresh rates. -\begin{lstClean}[caption={Auxiliary definitions to \cref{lst:gpio} for \gls{DHT} sensors and digital \gls{GPIO} with custom timing intervals.},label={lst:dht}] +\begin{lstClean}[caption={Auxiliary definitions to \cref{lst:gpio,lst:dht} for \gls{DHT} sensors and digital \gls{GPIO} with custom timing intervals.},label={lst:dht_ext}] class dht v where ... temperature` :: (TimingInterval v) (v DHT) -> MTask v Real @@ -265,37 +280,297 @@ class dio p v | pin p where readD :: (v p) -> MTask v Bool | pin p \end{lstClean} -A tailor-made \gls{ADT} determines the timing intervals. - -% doordat texcl aanstaat in listings zijn comments automatisch al in LaTeX -\begin{lstlisting}[language=Clean,caption={The \gls{ADT} for timing intervals in \gls{MTASK}.},label={lst:interval}] -:: TimingInterval v = Default - | BeforeMs (v Int) // yields $\langle 0, x \rangle $ - | BeforeS (v Int) // yields $\langle 0, x \times 1000 \rangle $ - | ExactMs (v Int) // yields $\langle x, x \rangle $ - | ExactS (v Int) // yields $\langle 0, x \times 1000 \rangle $ - | RangeMs (v Int) (v Int) // yields $\langle x, y \rangle $ - | RangeS (v Int) (v Int) // yields $\langle x \times 1000, y \times 1000 \rangle $ -\end{lstlisting} - As example, we define an \gls{MTASK} that updates the \gls{SDS} \cleaninline{tempSds} in \gls{ITASK} in a tight loop. The \cleaninline{temperature`} reading requires that this happens at least once per minute. Without other tasks on the \gls{IOT} node, the temperature \gls{SDS} is updated once per minute. Other tasks can cause a slightly more frequent update. -\begin{lstClean}[caption={Updating \pgls{SDS} in \gls{ITASK} at most once per minute.},label={lst:updatesds2}] +\begin{lstClean}[caption={Updating \pgls{SDS} in \gls{ITASK} at least once per minute.},label={lst:updatesds2}] +delayTime :: TimingInterval v | mtask v delayTime = BeforeS (lit 60) // 1 minute in seconds devTask :: Main (MTask v Real) | mtask, dht, liftsds v -devTask = DHT (DHT_DHT pin DHT11) \dht = - liftsds \localSds = tempSds - In {main = rpeat (temperature` delayTime dht >>~. setSds localSds)} +devTask = + DHT (DHT_DHT pin DHT11) \dht = + liftsds \localSds = tempSds + In {main = rpeat (temperature` delayTime dht >>~. setSds localSds)} +\end{lstClean} + +\subsubsection{Repeating tasks} +The task combinator \cleaninline{rpeat} restarts the child task in the evaluation if the previous produced a stable result. +However, in some cases it is desirable to postpone the restart of the child. +For this, the \cleaninline{rpeatEvery} task is introduced which receives an extra argument, the refresh rate, as shown in \cref{lst:rpeatevery}. +Instead of immediately restarting the child once it yields a stable value, it checks whether the lower bound of the provided timing interval has passed since the start of the task.\footnotemark{} +\footnotetext{In reality, it also compensates for time drift by taking into account the upper bound of the timing interval. +If the task takes longer to stabilise than the upper bound of the timing interval, this upper bound is taken as the start of the task instead of the actual start.} + +\begin{lstClean}[caption={Repeat task combinator with a timing interval.},label={lst:rpeatevery}] +class rpeat v where + rpeatEvery v :: (TimingInterval v) (MTask v t) -> MTask v t + rpeat :: (MTask v t) -> MTask v t +\end{lstClean} + +\Cref{lst:rpeateveryex} shows an example of an \gls{MTASK} task utilising the \cleaninline{rpeatEvery} combinator that would be impossible to create with the regular \cleaninline{rpeat}. +The \cleaninline{timedPulse} function creates a task that sends a \qty{50}{\ms} pulse to the \gls{GPIO} pin 0 every second. +The task created by the \cleaninline{timedPulseNaive} functions emulates the behaviour by using \cleaninline{rpeat} and \cleaninline{delay}. +However, this results in a time drift because rewriting tasks trees takes some time and the time it takes can not always be reliably predicted due to external factors. +E.g.\ writing to \gls{GPIO} pins takes some time, interrupts may slow down the program (see \cref{lst:interrupts}), or communication may occur in between task evaluations. + +\begin{lstClean}[caption={Example program for the repeat task combinator with a timing interval.},label={lst:rpeateveryex}] +timedPulse :: Main (MTask v Bool) | mtask v +timedPulse = declarePin D0 PMOutput \d0-> + in {main = rpeatEvery (ExactSec (lit 1)) ( + writeD d0 true + >>|. delay (lit 50) + >>|. writeD d0 false + ) + } + +timedPulseNaive :: Main (MTask v Bool) | mtask v +timedPulseNaive = declarePin D0 PMOutput \d0-> + {main = rpeat ( + writeD d0 true + >>|. delay (lit 50) + >>|. writeD d0 false + >>|. delay (lit 950)) + } +\end{lstClean} + +\section{Task scheduling in the \texorpdfstring{\gls{MTASK}}{mTask} engine} +The refresh rates from the previous section only tell us how much the next evaluation of the task can be delayed. +An \gls{IOT} edge devices executes multiple tasks may run interleaved. +In addition, it has to communicate with a server to collect new tasks and updates of \glspl{SDS}. +Hence, the refresh intervals cannot be used directly to let the microcontroller sleep. +Our scheduler has the following objectives. +\begin{itemize} + \item + Meet the deadline whenever possible, i.e.\ the system tries to execute every task before the end of its refresh interval. + Only too much work on the device might cause an overflow of the deadline. + \item + Achieve long sleep times. Waking up from sleep consumes some energy and takes some time. + Hence, we prefer a single long sleep over splitting this interval into several smaller pieces. + \item + The scheduler tries to avoid unnecessary evaluations of tasks as much as possible. + A task should not be evaluated now when its execution can also be delayed until the next time that the device is active. + That is, a task should preferably not be executed before the start of its refresh interval. + Whenever possible, task execution should even be delayed when we are inside the refresh interval as long as we can execute the task before the end of the interval. + \item + The optimal power state should be selected. + Although a system uses less power in a deep sleep mode, it also takes more time and energy to wake up from deep sleep. + When the system knows that it can sleep only a short time it is better to go to light sleep mode since waking up from light sleep is faster and consumes less energy. +\end{itemize} + +The algorithm $\mathcal{R}$ from \cref{sec:deriving_refresh_rates} computes the evaluation rate of the current tasks. +For the scheduler, we transform this interval to an absolute evaluation interval; the lower and upper bound of the start time of that task measured in the time of the \gls{IOT} edge device. +We obtain those bounds by adding the current system time to the bounds of the computed refresh interval by algorithm $\mathcal{R}$. + +For the implementation, it is important to note that the evaluation of a task takes time. +Some tasks are extremely fast, but other tasks require long computations and time-consuming communication with peripherals as well as with the server. +These execution times can yield a considerable and noticeable time drift in \gls{MTASK} programs. +For instance, a task like \cleaninline{rpeatEvery (ExactMs 1) t} should repeat \cleaninline{t} every millisecond. +The programmer might expect that \cleaninline{t} will be executed for the ${(N+1)}^{th}$ time after $N$ milliseconds. +Uncompensated time drift might make this considerably later. +\Gls{MTASK} does not pretend to be a hard real-time \gls{OS}, and cannot give firm guarantees with respect to evaluation time. +Nevertheless, we try to make time handling as reliable as possible. +This is achieved by adding the start time of this round of task evaluations rather than the current time to compute absolute execution intervals. + +\subsection{Scheduling Tasks} +Apart from the task to execute, the \gls{IOT} device has to maintain the connection with the server and check there for new tasks and updates of \gls{SDS}. +When the microcontroller is active, it checks the connection and updates from the server and executes the task if it is in its execution window. +Next, the microcontroller goes to light sleep for the minimum of a predefined interval and the task delay. + +In general, the microcontroller node executes multiple \gls{MTASK} tasks at the same time. +\Gls{MTASK} nodes repeatedly check for inputs from servers and execute all tasks that cannot be delayed to the next evaluation round one step. +The tasks are stored in a priority queue to check efficiently which of them need to be stepped. +The \gls{MTASK} tasks are ordered at their absolute latest start time in this queue; the earliest deadline first. +We use the earliest deadline to order tasks with equal latest deadline. + +It is very complicated to make an optimal scheduling algorithm for tasks to minimize the energy consumption. +We use a simple heuristic to evaluate tasks and determine sleep time rather than wasting energy on a fancy evaluation algorithm. +\Cref{lst:evalutionRound} gives this algorithm in pseudo code. +First the \gls{MTASK} node checks for new tasks and updates of \glspl{SDS}. +This communication adds any task to the queue. +The \cleaninline{stepped} set contains all tasks evaluated in this evaluation round. +Next, we evaluate tasks from the queue until we encounter a task that has an evaluation interval that is not started. +This might evaluate tasks earlier than required, but maximizes the opportunities to sleep after this evaluation round. +%Using the \prog{stepped} set ensures that we evaluate each task at most once during an evaluation round. +Executed tasks are temporarily stored in the \cleaninline{stepped} set instead of inserted directly into the queue to ensure that they are evaluated at most once in a evaluation round to ensure that there is frequent communication with the server. +A task that produces a stable value is completed and is not queued again. + +\begin{algorithm} +\DontPrintSemicolon +\SetKwProg{Repeatt}{repeat}{}{end} +\KwData{queue = []\;} +\Begin{ + \Repeatt{}{ + queue += communicateWithServer\; + stepped = []\tcp*{tasks stepped in this round} + \While{notEmpty(queue) $\wedge$ earliestDeadline(top(queue)) $\leq$ currentTime}{ + (task, queue) = pop(queue)\; + task2 = step(task)\tcp*{computes new execution interval} + \If{$\neg$ isStable(task2)\tcp*{not finished after step}}{ + stepped += task2\; + } + } + queue = merge(queue, stepped)\; + sleep(queue)\; + } +} +\caption{Pseudo code for the evaluation round of tasks in the queue.} +\label{lst:evalutionRound} +\end{algorithm} + +The \cleaninline{sleep} function determines the maximum sleep time based on the top of the queue. +The computed sleep time and the characteristics of the microprocessor determine the length and depth of the sleep. +For very short sleep times it might not be worthwhile to sleep. +In the current \gls{MTASK} \gls{RTS}, the thresholds are determined by experimentation but can be tuned by the programmer. +On systems that lose the content of their \gls{RAM} it is not possible to go to deep sleep mode. + +\section{Interrupts}\label{lst:interrupts} +Most microcontrollers have built-in support for processor interrupts. +These interrupts are hard-wired signals that can interrupt the normal flow of the program to execute a small piece of code, the \gls{ISR}. +While the \glspl{ISR} look like regular functions, they do come with some limitations. +For example, they must be very short, in order not to miss future interrupts; can only do very limited \gls{IO}; cannot reliably check the clock; and they operate in their own stack, and thus communication must happen via global variables. +After the execution of the \gls{ISR}, the normal program flow is resumed. +Interrupts are heavily used internally in the \gls{RTS} of the microcontrollers to perform timing critical operations such as WiFi, \gls{I2C}, or \gls{SPI} communication; completed \gls{ADC} conversions, software timers; exception handling; \etc. + +Interrupts offer two substantial benefits: fewer missed events and better energy usage. +Sometimes an external event such as a button press only occurs for a very small duration, making it possible to miss it due to it happening right between two polls. +Using interrupts is not a fool-proof way of never missing an event. +Events may still be missed if they occur during the execution of an \gls{ISR} or while the microcontroller is still in the process of waking up from a triggered interrupt. +There are also some sensors, such as the CCS811 air quality sensor, with support for triggering interrupts when a value exceeds a critical limit. + +There are several different types of interrupts possible. +\begin{table} + \centering + \caption{Overview of \gls{GPIO} interrupt types.}% + \label{tbl:gpio_interrupts} + \begin{tabular}{ll} + \toprule + type & triggers\\ + \midrule + change & input changes\\ + falling & input becomes low\\ + rising & input becomes high\\ + low & input is low\\ + high & input is high\\ + \bottomrule + \end{tabular} +\end{table} + +\subsection{\Gls{ARDUINO} platform} +\Cref{lst:arduino_interrupt} shows an exemplatory program utilising interrupts written in \gls{ARDUINO}'s \gls{CPP} dialect. +The example shows a debounced light switch for the built-in \gls{LED} connected to \gls{GPIO} pin 13. +When the user presses the button connected to \gls{GPIO} pin 11, the state of the \gls{LED} changes. +As buttons sometimes induce noise shortly after pressing, events within \qty{30}{\ms} after pressing are ignored. +In between the button presses, the device goes into deep sleep using the \arduinoinline{LowPower} library. + +\Crefrange{lst:arduino_interrupt:defs_fro}{lst:arduino_interrupt:defs_to} defines the pin and debounce constants. +\Cref{lst:arduino_interrupt:state} defines the current state of the \gls{LED}, it is declared \arduinoinline{volatile} to exempt it from compiler optimisations because it is accessed in the interrupt handler. +\Cref{lst:arduino_interrupt:cooldown} flags whether the program is in debounce state, i.e.\ events should be ignored for a short period of time. + +In the \arduinoinline{setup} function (\crefrange{lst:arduino_interrupt:setup_fro}{lst:arduino_interrupt:setup_to}), the pinmode of the \gls{LED} and interrupt pins are set. +Furthermore, the microcontroller is instructed to wake up from sleep mode when a \emph{rising} interrupt occurs on the interrupt pin and to call the \gls{ISR} at \crefrange{lst:arduino_interrupt:isr_fro}{lst:arduino_interrupt:isr_to}. +This \gls{ISR} checks if the program is in cooldown state. +If this is not the case, the state of the \gls{LED} is toggled. +In any case, the program goes into cooldown state afterwards. + +In the \arduinoinline{loop} function, the microcontroller goes to low-power sleep immediately and indefinitely. +Only when an interrupt triggers, the program continues, writes the state to the \gls{LED}, waits for the debounce time, and finally disables the \arduinoinline{cooldown} state. + +\begin{lstArduino}[numbers=left,label={lst:arduino_interrupt},caption={Light switch using interrupts.}] +#define LEDPIN 13[+\label{lst:arduino_interrupt:defs_fro}+] +#define INTERRUPTPIN 11 +#define DEBOUNCE 30[+\label{lst:arduino_interrupt:defs_to}+] + +volatile byte state = LOW;[+\label{lst:arduino_interrupt:state}+] +volatile bool cooldown = true;[+\label{lst:arduino_interrupt:cooldown}+] + +void setup() {[+\label{lst:arduino_interrupt:setup_fro}+] + pinMode(LEDPIN, OUTPUT); + pinMode(INTERRUPTPIN, INPUT); + LowPower.attachInterruptWakeup(INTERRUPTPIN, buttonPressed, RISING); +}[+\label{lst:arduino_interrupt:setup_to}+] + +void loop() {[+\label{lst:arduino_interrupt:loop_fro}+] + LowPower.sleep(); + digitalWrite(LEDPIN, state); + delay(DEBOUNCE); + cooldown = false; +}[+\label{lst:arduino_interrupt:loop_to}+] + +void buttonPressed() {[+\label{lst:arduino_interrupt:isr_fro}+] + if (!cooldown) + state = !state; + cooldown = true; +}[+\label{lst:arduino_interrupt:isr_to}+] +\end{lstArduino} + +\subsection{\texorpdfstring{\Gls{MTASK}}{MTask} language} +\Cref{lst:mtask_interrupts} shows the interrupt interface in \gls{MTASK}. +The \cleaninline{interrupt} class contains a single function that, given an interrupt mode and a \gls{GPIO} pin, produces a task that represents this interrupt. +Lowercase variants of the various interrupt modes such as \cleaninline{change :== lit Change} are available as convenience macros (see \cref{sec:expressions}). + +\begin{lstClean}[label={lst:mtask_interrupts},caption={The interrupt interface in \gls{MTASK}.}] +class interrupt v where + interrupt :: (v InterruptMode) (v p) -> MTask v Bool | pin p + +:: InterruptMode = Change | Rising | Falling | Low | High \end{lstClean} -\subsection{Language} -\subsection{Device} +When the \gls{MTASK} device executes this task, it installs an \gls{ISR} and sets the refresh rate of the task to infinity, $\refreshrate{\infty}{\infty}$. +The interrupt handler is set up in such a way that the refresh rate is changed to $\refreshrate{0}{0}$ once the interrupt triggers. +As a consequence, the task is executed on the next execution cycle. + +The \cleaninline{pirSwitch} function in \cref{lst:pirSwitch} creates, given an interval in \unit{\ms}, a task that reacts to motion detection by a \gls{PIR} sensor (connected to \gls{GPIO} pin 0) by lighting the \gls{LED} connected to \gls{GPIO} pin 13 for the given interval. +The system lightens the \gls{LED} again when there is still motion detected after this interval. +By changing the interrupt mode in this program text from \cleaninline{High} to \cleaninline{Rising} the system lights the \gls{LED} only one interval when it detects motion no matter how long this signal is present at the \gls{PIR} pin. + +\begin{lstClean}[caption={Example of a toggle light switch using interrupts.},label={lst:pirSwitch}] +pirSwitch :: Int -> Main (MTask v Bool) | mtask v +pirSwitch = + declarePin D13 PMOutput \ledpin-> + declarePin D0 PMInput \pirpin-> + {main = rpeat ( interrupt high pirpin + >>|. writeD ledpin false + >>|. delay (lit interval) + >>|. writeD ledpin true) } +\end{lstClean} -\section{Interrupts} +\subsection{\texorpdfstring{\Gls{MTASK}}{MTask} engine} + +While interrupt tasks have their own node type in the task tree, they differ slightly from other node types because they require a more elaborate setup and teardown. +Enabling and disabling interrupts is done in a general way in which tasks register themselves after creation and deregister after deletion. +Interrupts should be disabled when there are no tasks waiting for that kind of interrupt because unused interrupts can lead to unwanted wake ups, and only one kind of interrupt can be attached to a pin. + +\subsubsection{Event registration} +The \gls{MTASK} \gls{RTS} contains an event administration to register which task is waiting on which event. +During the setup of an interrupt task, the event administration in the \gls{MTASK} \gls{RTS} is checked to determine whether a new \gls{ISR} for the particular pin needs to be registered. +Furthermore, this registration allows for a quick lookup in the \gls{ISR} to find the tasks listening to the events. +Conversely, during the teardown, the \gls{ISR} is disabled again when the last interrupt task of that kind is deleted. +The registration is light-weight and consists only of an event identifier and task identifier. +This event registration is stored as a linked list of task tree nodes so that the garbage collector can clean them up when they become unused. + +Registering and deregistering interrupts is a device specific procedure, although most supported devices use the \gls{ARDUINO} \gls{API} for this. +Which pins support which interrupt differs greatly from device to device but this information is known at compile time. +At the time of registration, the \gls{RTS} checks whether the interrupt is valid and throws an \gls{MTASK} exception if it is not. +Moreover, an exception is thrown if multiple types of interrupts are registered on the same pin. + +\subsubsection{Triggering interrupts} +Once an interrupt fires, tasks registered to that interrupt are not immediately evaluated because it is usually not safe to do. +For example, the interrupt could fire in the middle of a garbage collection process, resulting in incorrect pointers. +Furthermore, as the \gls{ISR} is supposed to be be very short, just a flag in the event administration is set. +Interrupt event flags are processed at the beginning of the event loop, before tasks are executed. +For each subscribed task, the task tree is searched for nodes listening for the particular interrupt. +When found, the node is flagged and the pin status is written. +Afterwards, the evaluation interval of the task is set to $\refreshrate{0}{0}$ and the task is reinsterted at the front of the scheduling queue to ensure rapid evaluation of the task. +Finally, the event is removed from the registration and the interrupt is disabled. +The interrupt can be disabled as all tasks waiting for the interrupt become stable after firing. +More occurrences of the interrupts do not change the value of the task as stable tasks keep the same value forever. +Therefore, it is no longer necessary to keep the interrupt enabled, and it is relatively cheap to enable it again if needed in the future. +Evaluating interrupt task node in the task tree is trivial because all of the work was already done when the interrupt was triggered. +The task emits the status of the pin as a stable value if the information in the task shows that it was triggered. +Otherwise, no value is emitted. \input{subfilepostamble} \end{document} diff --git a/top/top.tex b/top/top.tex index bdc8100..913dfc7 100644 --- a/top/top.tex +++ b/top/top.tex @@ -26,6 +26,8 @@ The programs are usually cyclic executives instead of tasks running in an operat \Cref{tbl:mcu_laptop} compares the hardware properties of a typical laptop with two very popular microcontrollers. \begin{table} + \caption{Hardware characteristics of typical microcontrollers and laptops.}% + \label{tbl:mcu_laptop} \begin{tabular}{llll} \toprule & Laptop & Atmega328P & ESP8266\\ @@ -38,8 +40,6 @@ The programs are usually cyclic executives instead of tasks running in an operat Price & \euro{1500} & \euro{3} & \euro{4}\\ \bottomrule \end{tabular} - \caption{Hardware characteristics of typical microcontrollers and laptops.}% - \label{tbl:mcu_laptop} \end{table} Each type of microcontrollers comes with vendor-provided drivers, compilers and \glspl{RTS} but there are many platform that abstract away from this such as \gls{MBED} and \gls{ARDUINO} of which \gls{ARDUINO} is specifically designed for education and prototyping and hence used here. @@ -268,6 +268,8 @@ The class constraints for values in \gls{MTASK} are omnipresent in all functions \begin{table}[ht] \centering + \caption{Mapping from \gls{CLEAN}/\gls{MTASK} data types to \gls{CPP} datatypes.}% + \label{tbl:mtask-c-datatypes} \begin{tabular}{lll} \toprule \gls{CLEAN}/\gls{MTASK} & \gls{CPP} type & \textnumero{}bits\\ @@ -280,8 +282,6 @@ The class constraints for values in \gls{MTASK} are omnipresent in all functions \cleaninline{:: T = A \| B \| C} & \cinline{enum} & 16\\ \bottomrule \end{tabular} - \caption{Mapping from \gls{CLEAN}/\gls{MTASK} data types to \gls{CPP} datatypes.}% - \label{tbl:mtask-c-datatypes} \end{table} \Cref{lst:constraints} contains the definitions for the auxiliary types and type constraints (such as \cleaninline{type} an \cleaninline{basicType}) that are used to construct \gls{MTASK} expressions. diff --git a/tvt/tvt.tex b/tvt/tvt.tex index 222b09e..5e7356c 100644 --- a/tvt/tvt.tex +++ b/tvt/tvt.tex @@ -950,7 +950,7 @@ The exchange of data, user interface, and communication are all automatically ge Another reason that the tierless \gls{CLEAN} implementations are concise is because they use powerful higher order \gls{IOT} programming abstractions. For comprehensibility the simple temperature sensor from \cref{sec_t4t:mtasks} (\cref{lst_t4t:mtasktemp}) is used to compare the expressive power of \gls{CLEAN} and \gls{PYTHON}-based \gls{IOT} programming abstractions. There are implementations for all four configurations: \gls{PRTS} (\gls{PYTHON} Raspberry Pi Temperature Sensor)\footnotemark, \gls{PWTS}\footnotemark[\value{footnote}] -\footnotetext{Lubbers, M.; Koopman, P.; Ramsingh, A.; Singer, J.; Trinder, P. (2021): Source code, line counts and memory stats for PRS, PWS, PRT and PWT.\ Zenodo.\ \href{https://doi.org/10.5281/zenodo.5081386}{10.5281/zenodo.5081386}.}, \gls{CRTS}\footnotemark{} and \gls{CWTS}\footnotemark[\value{footnote}]. +\footnotetext{Lubbers, M.; Koopman, P.; Ramsingh, A.; Singer, J.; Trinder, P. (2021): Source code, line counts and memory stats for PRS, PWS, PRT and PWT.\ Zenodo.\ \href{https://doi.org/10.5281/zenodo.5081386}{10.5281/zenodo.5081386}.}, \gls{CRTS}\footnotemark{} and \gls{CWTS}.\footnotemark[\value{footnote}] \footnotetext{Lubbers, M.; Koopman, P.; Ramsingh, A.; Singer, J.; Trinder, P. (2021): Source code, line counts and memory stats for CRS, CWS, CRTS and CWTS.\ Zenodo.\ \href{https://doi.org/10.5281/zenodo.5040754}{10.5281/zenodo.5040754}.} but as the programming abstractions are broadly similar, we compare only the \gls{PWTS} and \gls{CWTS} implementations. -- 2.20.1