1 \documentclass[../thesis.tex
]{subfiles
}
4 \ifSubfilesClassLoaded{
8 \chapter{Introduction to
\texorpdfstring{\gls{IOT
}}{IoT
} programming
}%
10 \todo{betere chapter naam
}
11 \begin{chapterabstract
}
12 This chapter introduces
\gls{MTASK
} and puts it into perspective compared to traditional microprocessor programming.
15 Traditionally, the first program that one writes when trying a new language is the so called
\emph{Hello World!
} program.
16 This program has the single task of printing the text
\emph{Hello World!
} to the screen and exiting again, useful to become familiarised with the syntax and verify that the toolchain and runtime environment is working.
17 On microprocessors, there often is no screen for displaying text.
18 Nevertheless, almost always there is a monochrome $
1\times1$ pixel screen, namely an---often builtin---
\gls{LED
}.
19 The
\emph{Hello World!
} equivalent on microprocessors blinks this
\gls{LED
}.
21 \Cref{lst:arduinoBlink
} shows how the logic of a blink program might look when using
\gls{ARDUINO
}'s
\gls{CPP
} dialect.
22 Every
\gls{ARDUINO
} program contains a
\arduinoinline{setup
} and a
\arduinoinline{loop
} function.
23 The
\arduinoinline{setup
} function is executed only once on boot, the
\arduinoinline{loop
} function is continuously called afterwards and contains the event loop.
24 After setting the
\gls{GPIO
} pin to the correct mode, blink's
\arduinoinline{loop
} function alternates the state of the pin representing the
\gls{LED
} between
\arduinoinline{HIGH
} and
\arduinoinline{LOW
}, turning the
\gls{LED
} off and on respectively.
25 In between it waits for
500 milliseconds so that the blinking is actually visible for the human eye.
26 Compiling this results in a binary firmware that needs to be flashed onto the program memory.
28 Translating the traditional blink program to
\gls{MTASK
} can almost be done by simply substituting some syntax as seen in
\cref{lst:blinkImp
}.
29 E.g.\
\arduinoinline{digitalWrite
} becomes
\cleaninline{writeD
}, literals are prefixed with
\cleaninline{lit
} and the pin to blink is changed to represent the actual pin for the builtin
\gls{LED
} of the device used in the exercises.
30 In contrast to the imperative
\gls{CPP
} dialect,
\gls{MTASK
} is a
\gls{TOP
} language and therefore there is no such thing as a loop, only task combinators to combine tasks.
31 To simulate a loop, the
\cleaninline{rpeat
} task can be used, this task executes the argument task and, when stable, reinstates it.
32 The body of the
\cleaninline{rpeat
} contains similarly named tasks to write to the pins and to wait in between.
33 The tasks are connected using the sequential
\cleaninline{>>|.
} combinator that for all current intents and purposes executes the tasks after each other.
36 \begin{subfigure
}[b
]{.5\linewidth}
37 \begin{lstArduino
}[caption=
{Blink program.
},label=
{lst:arduinoBlink
}]
43 digitalWrite(D2, HIGH);
45 digitalWrite(D2, LOW);
49 \begin{subfigure
}[b
]{.5\linewidth}
50 \begin{lstClean
}[caption=
{Blink program.
},label=
{lst:blinkImp
}]
51 blink :: Main (MTask v ()) | mtask v
53 declarePin D2 PMOutput
\d2->
63 \section{Threaded blinking
}
64 Now say that we want to blink multiple blinking patterns on different
\glspl{LED
} concurrently.
65 For example, blink three
\glspl{LED
} connected to
\gls{GPIO
} pins $
1,
2$ and $
3$ at intervals of $
500,
300$ and $
800$ milliseconds.
66 Intuitively you want to lift the blinking behaviour to a function and call this function three times with different parameters as done in
\cref{lst:blinkthreadno
}
68 \begin{lstArduino
}[caption=
{Naive approach to multiple blinking patterns.
},label=
{lst:blinkthreadno
}]
71 void blink (int pin, int wait)
{
72 digitalWrite(pin, HIGH);
74 digitalWrite(pin, LOW);
84 Unfortunately, this does not work because the
\arduinoinline{delay
} function blocks all further execution.
85 The resulting program will blink the
\glspl{LED
} after each other instead of at the same time.
86 To overcome this, it is necessary to slice up the blinking behaviour in very small fragments so it can be manually interleaved~
\citep{feijs_multi-tasking_2013
}.
87 Listing~
\ref{lst:blinkthread
} shows how three different blinking patterns might be achieved in
\gls{ARDUINO
} using the slicing method.
88 If we want the blink function to be a separate parametrizable function we need to explicitly provide all references to the required state.
89 Furthermore, the
\arduinoinline{delay
} function can not be used and polling
\arduinoinline{millis
} is required.
90 The
\arduinoinline{millis
} function returns the number of milliseconds that have passed since the boot of the microprocessor.
91 Some devices use very little energy when in
\arduinoinline{delay
} or sleep state.
92 Resulting in
\arduinoinline{millis
} potentially affects power consumption since the processor is basically busy looping all the time.
93 In the simple case of blinking three
\glspl{LED
} on fixed intervals, it might be possible to calculate the delays in advance using static analysis and generate the appropriate
\arduinoinline{delay
} code.
94 Unfortunately, this is very hard when for example the blinking patterns are determined at runtime.
96 \begin{lstArduino
}[label=
{lst:blinkthread
},caption=
{Threading three blinking patterns.
}]
97 long led1 =
0, led2 =
0, led3 =
0;
98 bool st1 = false, st2 = false, st3 = false;
100 void blink(int pin, int dlay, long *lastrun, bool *st)
{
101 if (millis() - *lastrun > dlay)
{
102 digitalWrite(pin, *st = !*st);
108 blink(D1,
500, &led1, &st1);
109 blink(D2,
300, &led2, &st1);
110 blink(D3,
800, &led3, &st1);
113 This method is very error prone, requires a lot of pointer juggling and generally results into spaghetti code.
114 Furthermore, it is very difficult to represent dependencies between threads, often state machines have to be explicitly programmed by hand to achieve this.
116 \section{Blinking in
\texorpdfstring{\gls{MTASK
}}{mTask
}}
117 The
\cleaninline{delay
} \emph{task
} does not block the execution but
\emph{just
} emits no value when the target waiting time has not yet passed and emits a stable value when the time is met.
118 In contrast, the
\arduinoinline{delay()
} \emph{function
} on the
\gls{ARDUINO
} is blocking which prohibits interleaving.
119 To make code reuse possible and make the implementation more intuitive, the blinking behaviour is lifted to a recursive function instead of using the imperative
\cleaninline{rpeat
} construct.
120 The function is parametrized with the current state, the pin to blink and the waiting time.
121 Creating recursive functions like this is not possible in the
\gls{ARDUINO
} language because the program would run out of stack in an instant and nothing can be interleaved.
122 With a parallel combinator, tasks can be executed in an interleaved fashion.
123 Therefore, blinking three different blinking patterns is as simple as combining the three calls to the
\cleaninline{blink
} function with their arguments as seen in
\cref{lst:blinkthreadmtask
}.
125 % VimTeX: SynIgnore on
126 \begin{lstClean
}[label=
{lst:blinkthreadmtask
},caption=
{Threaded blinking.
}]
127 blinktask :: MTask v () | mtask v
129 declarePin D1 PMOutput
\d1->
130 declarePin D2 PMOutput
\d2->
131 declarePin D3 PMOutput
\d3->
132 fun
\blink=(\(st, pin, wait)->
135 >>|. blink (Not st, pin, wait)) In
136 {main = blink (true, d1, lit
500)
137 .||. blink (true, d2, lit
300)
138 .||. blink (true, d3, lit
800)
140 % VimTeX: SynIgnore off
142 \chapter{The
\texorpdfstring{\gls{MTASK
}}{mTask
} \texorpdfstring{\gls{DSL
}}{DSL
}}%
143 \label{chp:mtask_dsl
}
144 \begin{chapterabstract
}
145 This chapter serves as a complete guide to the
\gls{MTASK
} language, from an
\gls{MTASK
} programmer's perspective.
146 \end{chapterabstract
}
148 The
\gls{MTASK
} system is a
\gls{TOP
} programming environment for programming microprocessors.
149 It is implemented as an
\gls{EDSL
} in
\gls{CLEAN
} using class-based---or tagless-final---embedding (See
\cref{ssec:tagless
}).
150 Due to the nature of the embedding technique, it is possible to have multiple interpretations of---or views on---programs written in the
\gls{MTASK
} language.
151 The following interpretations are available for
\gls{MTASK
}.
156 This interpretation converts the expression to a string representation.
159 The simulator converts the expression to a ready-for-work
\gls{ITASK
} simulation in which the user can inspect and control the simulated peripherals and see the internal state of the tasks.
162 The compiler compiles the
\gls{MTASK
} program at runtime to a specialised bytecode.
163 Using a handful of integration functions and tasks,
\gls{MTASK
} tasks can be executed on microprocessors and integrated in
\gls{ITASK
} as if they were regular
\gls{ITASK
} tasks.
164 Furthermore, with special language constructs,
\glspl{SDS
} can be shared between
\gls{MTASK
} and
\gls{ITASK
} programs.
167 When using the compiler interpretation in conjunction with the
\gls{ITASK
} integration,
\gls{MTASK
} is a heterogeneous
\gls{DSL
}.
168 I.e.\ some components---e.g.\ the
\gls{RTS
} on the microprocessor---is largely unaware of the other components in the system.
169 Furthermore, it is executed on a completely different architecture.
170 The
\gls{MTASK
} language consists of a host language---a simply-typed $
\lambda$-calculua with support for some basic types, function definition and data types (see
\cref{sec:expressions
})---enriched with a task language (see
\cref{sec:top
}).
173 To leverage the type checker of the host language, types in the
\gls{MTASK
} language are expressed as types in the host language, to make the language type safe.
174 However, not all types in the host language are suitable for microprocessors that may only have
\qty{2}{\kibi\byte} of
\gls{RAM
} so class constraints are therefore added to the
\gls{DSL
} functions.
175 The most used class constraint is the
\cleaninline{type
} class collection containing functions for serialization, printing,
\gls{ITASK
} constraints etc.
176 Many of these functions can be derived using generic programming.
177 An even stronger restriction on types is defined for types that have a stack representation.
178 This
\cleaninline{basicType
} class has instances for many
\gls{CLEAN
} basic types such as
\cleaninline{Int
},
\cleaninline{Real
} and
\cleaninline{Bool
}.
179 The class constraints for values in
\gls{MTASK
} are omnipresent in all functions and therefore often omitted throughout throughout the chapters for brevity and clarity.
185 \gls{CLEAN
}/
\gls{MTASK
} &
\gls{CPP
} type &
\textnumero{}bits\\
187 \cleaninline{Bool
} &
\cinline{bool
} &
16\\
188 \cleaninline{Char
} &
\cinline{char
} &
16\\
189 \cleaninline{Int
} &
\cinline{int16_t
} &
16\\
190 \cleaninline{:: Long
} &
\cinline{int32_t
} &
32\\
191 \cleaninline{Real
} &
\cinline{float
} &
32\\
192 \cleaninline{:: T = A \| B \| C
} &
\cinline{enum
} &
16\\
195 \caption{Mapping from
\gls{CLEAN
}/
\gls{MTASK
} data types to
\gls{CPP
} datatypes.
}%
196 \label{tbl:mtask-c-datatypes
}
199 The
\gls{MTASK
} language consists of a core collection of type classes bundled in the type class
\cleaninline{class mtask
}.
200 Every interpretation implements the type classes in the
\cleaninline{mtask
} class
201 There are also
\gls{MTASK
} extensions that not every interpretation implements such as peripherals and integration with
\gls{ITASK
}.
203 \Cref{lst:constraints
} contains the definitions for the type constraints and shows some example type signatures for typical
\gls{MTASK
} expressions and tasks.
206 \begin{lstClean
}[caption=
{Classes and class collections for the
\gls{MTASK
} language.
},label=
{lst:constraints
}]
207 :: Main a =
{ main :: a
}
208 :: In a b = (In) infix
0 a b
210 class type t | iTask, ... ,fromByteCode, toByteCode t
211 class basicType t | type t where ...
213 class mtask v | expr, ..., int, real, long v
215 someExpr :: v Int | mtask v
218 someTask :: MTask v Int | mtask v
220 sensor1 config1
\sns1->
221 sensor2 config2
\sns2->
223 In fun
\fun2= ( ... )
227 \section{Expressions
}\label{sec:expressions
}
228 \Cref{lst:expressions
} shows the
\cleaninline{expr
} class containing the functionality to lift values from the host language to the
\gls{MTASK
} language (
\cleaninline{lit
}); perform number and boolean arithmetics; do comparisons; and conditional execution.
229 For every common arithmetic operator in the host language, an
\gls{MTASK
} variant is present, suffixed by a period to not clash with
\gls{CLEAN
}'s builtin operators.
231 \begin{lstClean
}[caption=
{The
\gls{MTASK
} class for expressions
},label=
{lst:expressions
}]
233 lit :: t -> v t | type t
234 (+.) infixl
6 :: (v t) (v t) -> v t | basicType, +, zero t
236 (&.) infixr
3 :: (v Bool) (v Bool) -> v Bool
237 (|.) infixr
2 :: (v Bool) (v Bool) -> v Bool
238 Not :: (v Bool) -> v Bool
239 (==.) infix
4 :: (v a) (v a) -> v Bool | Eq, basicType a
241 If :: (v Bool) (v t) (v t) -> v t | type t
244 Conversion to-and-fro data types is available through the overloaded functions
\cleaninline{int
},
\cleaninline{long
} and
\cleaninline{real
}.
246 \begin{lstClean
}[caption=
{Type conversion functions in
\gls{MTASK
}.
}]
247 class int v a :: (v a) -> v Int
248 class real v a :: (v a) -> v Real
249 class long v a :: (v a) -> v Long
252 Finally, values from the host language must be explicitly lifted to the
\gls{MTASK
} language using the
\cleaninline{lit
} function.
253 For convenience, there are many lower-cased macro definitions for often used constants such as
\cleaninline{true :== lit True
},
\cleaninline{false :== lit False
},
\etc.
255 \Cref{lst:example_exprs
} shows some examples of these expressions.
256 \cleaninline{e0
} defines the literal $
42$,
\cleaninline{e1
} calculates the literal $
42.0$ using real numbers.
257 \cleaninline{e2
} compares
\cleaninline{e0
} and
\cleaninline{e1
} as integers and if they are equal it returns the
\cleaninline{e2
}$/
2$ and
\cleaninline{e0
} otherwise.
258 \cleaninline{approxEqual
} performs an approximate equality---albeit not taking into account all floating point pecularities---and demonstrates that
\gls{CLEAN
} can be used as a macro language, i.e.\ maximise linguistic reuse~
\cite{krishnamurthi_linguistic_2001
}.
259 \todo{uitzoeken waar dit handig is
}
260 When calling
\cleaninline{approxEqual
} in an
\gls{MTASK
} function, the resulting code is inlined.
262 \begin{lstClean
}[label=
{lst:example_exprs
},caption=
{Example
\gls{MTASK
} expressions.
}]
266 e1 :: v Real | expr v
267 e1 = lit
38.0 + real (lit
4)
270 e2 = if' (e0 ==. int e1)
273 approxEqual :: (v Real) (v Real) (v Real) -> v Real | expr v
274 approxEqual x y eps = if' (x == y) true
281 \subsection{Data Types
}
282 Most of
\gls{CLEAN
}'s basic types have been mapped on
\gls{MTASK
} types.
283 However, it can be useful to have access to compound types as well.
284 All types in
\gls{MTASK
} must have a fixed size representation on the stack so sum types are not (yet) supported.
285 While it is possible to lift types using the
\cleaninline{lit
} function, you cannot do anything with the types besides passing them around but they are being produced by some parallel task combinators (see
\cref{sssec:combinators_parallel
}).
286 To be able to use types as first class citizens, constructors and field selectors are required.
287 \Cref{lst:tuple_exprs
} shows the scaffolding for supporting tuples in
\gls{MTASK
}.
288 Besides the constructors and field selectors, there is also a helper function available that transforms a function from a tuple of
\gls{MTASK
} expressions to an
\gls{MTASK
} expression of a tuple.
290 \begin{lstClean
}[label=
{lst:tuple_exprs
},caption=
{Tuple constructor and field selectors in
\gls{MTASK
}.
}]
292 tupl :: (v a) (v b) -> v (a, b) | type a & type b
293 first :: (v (a, b)) -> v a | type a & type b
294 second :: (v (a, b)) -> v b | type a & type b
296 tupopen f :==
\v->f (first v, second v)
299 \subsection{Functions
}
300 Adding functions to the language is achieved by one multi-parameter class to the
\gls{DSL
}.
301 By using
\gls{HOAS
}, both the function definition and the calls to the function can be controlled by the
\gls{DSL
}~
\citep{pfenning_higher-order_1988,chlipala_parametric_2008
}.
302 As
\gls{MTASK
} only supports first-order functions and does not allow partial function application.
303 Using a type class of this form, this restriction can be enforced on the type level.
304 Instead of providing one instance for all functions, a single instance per function arity is defined.
305 Also,
\gls{MTASK
} only supports top-level functions which is enforced by the
\cleaninline{Main
} box.
306 The definition of the type class and the instances for an example interpretation are as follows:
309 \begin{lstClean
}[caption=
{Functions in
\gls{MTASK
}.
}]
310 class fun a v :: ((a -> v s) -> In (a -> v s) (Main (MTask v u)))
313 instance fun () Inter where ...
314 instance fun (Inter a) Inter | type a where ...
315 instance fun (Inter a, Inter b) Inter | type a where ...
316 instance fun (Inter a, Inter b, Inter c) Inter | type a where ...
320 Deriving how to define and use functions from the type is quite the challenge even though the resulting syntax is made easier using the infix type
\cleaninline{In
}.
321 \Cref{lst:function_examples
} show the factorial function, a tail-call optimised factorial function and a function with zero arguments to demonstrate the syntax.
322 Splitting out the function definition for each single arity means that that for every function arity and combination of arguments, a separate class constraint must be created.
323 Many of the often used functions are already bundled in the
\cleaninline{mtask
} class constraint collection.
324 \cleaninline{factorialtail
} shows a manually added class constraint.
325 Definiting zero arity functions is shown in the
\cleaninline{zeroarity
} expression.
326 Finally,
\cleaninline{swapTuple
} shows an example of a tuple being swapped.
328 % VimTeX: SynIgnore on
329 \begin{lstClean
}[label=
{lst:function_examples
},caption=
{Function examples in
\gls{MTASK
}.
}]
330 factorial :: Main (v Int) | mtask v
332 fun
\fac=(
\i->if' (i <. lit
1)
334 (i *. fac (i -. lit
1)))
335 In
{main = fac (lit
5)
}
337 factorialtail :: Main (v Int) | mtask v & fun (v Int, v Int) v
339 fun
\facacc=(\(acc, i)->if' (i <. lit
1)
341 (fac (acc *. i, i -. lit
1)))
342 In fun
\fac=(
\i->facacc (lit
1, i))
343 In
{main = fac (lit
5)
}
345 zeroarity :: Main (v Int) | mtask v
347 fun
\fourtytwo=(\()->lit
42)
348 In fun
\add=(\(x, y)->x +. y)
349 In
{main = add (fourtytwo (), lit
9)
}
351 swapTuple :: Main (v (Int, Bool)) | mtask v
353 fun
\swap=(tupopen \(x, y)->tupl y x)
354 In
{main = swap (tupl true (lit
42))
}
356 % VimTeX: SynIgnore off
358 \section{Tasks
}\label{sec:top
}
359 \Gls{MTASK
}'s task language can be divided into three categories, namely
361 \item Basic tasks, in most
\gls{TOP
} systems, the basic tasks are called editors, modelling the interactivity with the user.
362 In
\gls{MTASK
}, there are no
\emph{editors
} in that sense but there is interaction with the outside world through microprocessor peripherals such as sensors and actuators.
363 \item Task combinators provide a way of describing the workflow.
364 They combine one or more tasks into a compound task.
365 \item \glspl{SDS
} in
\gls{MTASK
} can be seen as references to data that can be shared using many-to-many communication and are only accessible from within the task language to ensure atomicity.
368 As
\gls{MTASK
} is integrated with
\gls{ITASK
}, the same stability distinction is made for task values.
369 A task in
\gls{MTASK
} is denoted by the
\gls{DSL
} type synonym shown in
\cref{lst:task_type
}.
371 \begin{lstClean
}[label=
{lst:task_type
},caption=
{Task type in
\gls{MTASK
}.
}]
372 :: MTask v a :== v (TaskValue a)
378 \subsection{Basic tasks
}
379 The most rudimentary basic tasks are the
\cleaninline{rtrn
} and
\cleaninline{unstable
} tasks.
380 They lift the value from the
\gls{MTASK
} expression language to the task domain either as a stable value or an unstable value.
381 There is also a special type of basic task for delaying execution.
382 The
\cleaninline{delay
} task---given a number of milliseconds---yields an unstable value while the time has not passed.
383 Once the specified time has passed, the time it overshot the planned time is yielded as a stable task value.
385 \begin{lstClean
}[label=
{lst:basic_tasks
},caption=
{Function examples in
\gls{MTASK
}.
}]
386 class rtrn v :: (v t) -> MTask v t
387 class unstable v :: (v t) -> MTask v t
388 class delay v :: (v n) -> MTask v n | long v n
391 \subsubsection{Peripherals
}\label{sssec:peripherals
}
392 For every sensor or actuator, basic tasks are available that allow interaction with the specific peripheral.
393 The type classes for these tasks are not included in the
\cleaninline{mtask
} class collection as not all devices nor all language interpretations have such peripherals connected.
394 \todo{Historically, peripheral support has been added
\emph{by need
}.
}
396 \Cref{lst:dht
} and
\cref{lst:gpio
} show the type classes for
\glspl{DHT
} sensors and
\gls{GPIO
} access.
397 Other peripherals have similar interfaces, they are available in the
\cref{sec:aux_peripherals
}.
398 For the
\gls{DHT
} sensor there are two basic tasks,
\cleaninline{temperature
} and
\cleaninline{humidity
}, that---will given a
\cleaninline{DHT
} object---produce a task that yields the observed temperature in
\unit{\celcius} or relative humidity as a percentage as an unstable value.
399 Currently, two different types of
\gls{DHT
} sensors are supported, the
\emph{DHT
} family of sensors connect through $
1$-wire protocol and the
\emph{SHT
} family of sensors connected using
\gls{I2C
} protocol.
400 Creating such a
\cleaninline{DHT
} object is very similar to creating functions in
\gls{MTASK
} and uses
\gls{HOAS
} to make it type safe.
402 \begin{lstClean
}[label=
{lst:dht
},caption
{The
\gls{MTASK
} interface for
\glspl{DHT
} sensors.
}]
405 = DHT_DHT Pin DHTtype
407 :: DHTtype = DHT11 | DHT21 | DHT22
409 DHT :: DHTInfo ((v DHT) -> Main (v b)) -> Main (v b) | type b
410 temperature :: (v DHT) -> MTask v Real
411 humidity :: (v DHT) -> MTask v Real
413 measureTemp :: Main (MTask v Real) | mtask v & dht v
414 measureTemp = DHT (DHT_SHT (i2c
0x36))
\dht->
415 {main=temperature dht
}
418 \Gls{GPIO
} access is divided into three classes: analog, digital and pin modes.
419 For all pins and pin modes an
\gls{ADT
} is available that enumerates the pins.
420 The analog
\gls{GPIO
} pins of a microprocessor are connected to an
\gls{ADC
} that translates the voltage to an integer.
421 Analog
\gls{GPIO
} pins can be either read or written to.
422 Digital
\gls{GPIO
} pins only
report a high or a low value.
423 The type class definition is a bit more complex since analog
\gls{GPIO
} pins can be used as digital
\gls{GPIO
} pins as well.
424 Therefore, if the
\cleaninline{p
} type implements the
\cleaninline{pin
} class---i.e.\ either
\cleaninline{APin
} or
\cleaninline{DPin
}---the
\cleaninline{dio
} class can be used.
425 \Gls{GPIO
} pins usually operate according to a certain pin mode that states whether the pin acts as an input pin, an input with an internal pull-up resistor or an output pin.
426 This setting can be applied using the
\cleaninline{pinMode
} class by hand or by using the
\cleaninline{declarePin
} \gls{GPIO
} pin constructor.
427 Setting the pin mode is a task that immediately finisheds and fields a stable unit value.
428 Writing to a pin is also a task that immediately finishes but yields the written value instead.
429 Reading a pin is a task that yields an unstable value---i.e.\ the value read from the actual pin.
431 \begin{lstClean
}[label=
{lst:gpio
},caption
{The
\gls{MTASK
} interface for
\gls{GPIO
} access.
}]
432 :: APin = A0 | A1 | A2 | A3 | A4 | A5
433 :: DPin = D0 | D1 | D2 | D3 | D4 | D5 | D6 | D7 | D8 | D9 | D10 | D11 | D12 | D13
434 :: PinMode = PMInput | PMOutput | PMInputPullup
435 :: Pin = AnalogPin APin | DigitalPin DPin
436 class pin p :: p -> Pin
439 writeA :: (v APin) (v Int) -> MTask v Int
440 readA :: (v APin) -> MTask v Int
442 class dio p v | pin p where
443 writeD :: (v p) (v Bool) -> MTask v Bool
444 readD :: (v p) -> MTask v Bool | pin p
446 class pinMode v where
447 pinMode :: (v PinMode) (v p) -> MTask v () | pin p
448 declarePin :: p PinMode ((v p) -> Main (v a)) -> Main (v a) | pin p
451 \subsection{Task combinators
}
452 Task combinators are used to combine multiple tasks into one to describe workflows.
453 There are three main types of task combinators, namely:
455 \item Sequential combinators that execute tasks one after the other, possibly using the result of the left hand side.
456 \item Parallel combinators that execute tasks at the same time combining the result.
457 \item Miscellaneous combinators that change the semantics of a task---e.g.\ repeat it or delay execution.
460 \subsubsection{Sequential
}
461 Sequential task combination allows the right-hand side task to observe the left-hand side task value.
462 All seqential task combinators are expressed in the
\cleaninline{expr
} class and can be---and are by default---derived from the Swiss army knife step combinator
\cleaninline{>>*.
}.
463 This combinator has a single task on the left-hand side and a list of
\emph{task continuations
} on the right-hand side.
464 The list of task continuations is checked every rewrite step and if one of the predicates matches, the task continues with the result of this combination.
465 \cleaninline{>>=.
} is a shorthand for the bind operation, if the left-hand side is stable, the right-hand side function is called to produce a new task.
466 \cleaninline{>>|.
} is a shorthand for the sequence operation, if the left-hand side is stable, it continues with the right-hand side task.
467 The
\cleaninline{>>~.
} and
\cleaninline{>>..
} combinators are variants of the ones above that ignore the stability and continue on an unstable value as well.
469 \begin{lstClean
}[label=
{lst:mtask_sequential
},caption=
{Sequential task combinators in
\gls{MTASK
}.
}]
470 class step v | expr v where
471 (>>*.) infixl
1 :: (MTask v t)
[Step v t u
] -> MTask v u
472 (>>=.) infixl
0 :: (MTask v t) ((v t) -> MTask v u) -> MTask v u
473 (>>|.) infixl
0 :: (MTask v t) (MTask v u) -> MTask v u
474 (>>~.) infixl
0 :: (MTask v t) ((v t) -> MTask v u) -> MTask v u
475 (>>..) infixl
0 :: (MTask v t) (MTask v u) -> MTask v u
478 = IfValue ((v t) -> v Bool) ((v t) -> MTask v u)
479 | IfStable ((v t) -> v Bool) ((v t) -> MTask v u)
480 | IfUnstable ((v t) -> v Bool) ((v t) -> MTask v u)
484 \todo{more examples step?
}
486 The following listing shows an example of a step in action.
487 The
\cleaninline{readPinBin
} function produces an
\gls{MTASK
} task that classifies the value of an analogue pin into four bins.
488 It also shows that the nature of embedding allows the host language to be used as a macro language.
491 \begin{lstClean
}[label=
{lst:mtask_readpinbin
},caption=
{Read an analog pin and bin the value in
\gls{MTASK
}.
}]
492 readPinBin :: Int -> Main (MTask v Int) | mtask v
493 readPinBin lim = declarePin PMInput A2
\a2->
494 { main = readA a2 >>*.
495 [ IfValue (
\x->x <. lim) (
\_->rtrn (lit bin))
496 \\ lim <-
[64,
128,
192,
256]
500 \subsubsection{Parallel
}\label{sssec:combinators_parallel
}
501 The result of a parallel task combination is a compound that actually executes the tasks at the same time.
503 There are two types of parallel task combinators (see
\cref{lst:mtask_parallel
}).
504 The conjunction combinator (
\cleaninline{.&&.
}) combines the result by putting the values from both sides in a tuple.
505 The stability of the task depends on the stability of both children.
506 If both children are stable, the result is stable, otherwise the result is unstable.
507 The disjunction combinator (
\cleaninline{.\|\|.
}) combines the results by picking the leftmost, most stable task.
508 The semantics are easily described using
\gls{CLEAN
} functions shown in
\cref{lst:semantics_con,lst:semantics_dis
}.
512 \begin{subfigure
}[t
]{.5\textwidth}
513 \begin{lstClean
}[caption=
{Semantics of the\
\conjunction combinator.
},label=
{lst:semantics_con
}]
514 con :: (TaskValue a) (TaskValue b)
516 con NoValue r = NoValue
517 con l NoValue = NoValue
518 con (Value l ls) (Value r rs)
519 = Value (l, r) (ls && rs)
523 \begin{subfigure
}[t
]{.5\textwidth}
524 \begin{lstClean
}[caption=
{Semantics of the\
\disjunction combinator.
},label=
{lst:semantics_dis
}]
525 dis :: (TaskValue a) (TaskValue a)
529 dis (Value l ls) (Value r rs)
531 | otherwise = Value l ls
536 \begin{lstClean
}[label=
{lst:mtask_parallel
},caption=
{Parallel task combinators in
\gls{MTASK
}.
}]
537 class (.&&.) infixr
4 v :: (MTask v a) (MTask v b) -> MTask v (a, b)
538 class (.||.) infixr
3 v :: (MTask v a) (MTask v a) -> MTask v a
541 \Cref{lst:mtask_parallel_example
} gives an example of the parallel task combinator.
542 This program will read two pins at the same time, returning when one of the pins becomes
\arduinoinline{HIGH
}.
543 If the combinator was the
\cleaninline{.&&.
} instead, the type would be
\cleaninline{MTask v (Bool, Bool)
} and the task would only return when both pins have been
\arduinoinline{HIGH
} but not necessarily at the same time.
545 \begin{lstClean
}[label=
{lst:mtask_parallel_example
},caption=
{Parallel task combinator example in
\gls{MTASK
}.
}]
548 declarePin D0 PMInput
\d0->
549 declarePin D1 PMInput
\d1->
550 let monitor pin = readD pin >>*.
[IfValue (
\x->x)
\x->rtrn x
]
551 In
{main = monitor d0 .||. monitor d1
}
554 \subsubsection{Repeat
}
555 The
\cleaninline{rpeat
} combinator executes the child task.
556 If a stable value is observed, the task is reinstated.
557 The functionality of
\cleaninline{rpeat
} can also be simulated by using functions and sequential task combinators and even made to be stateful as can be seen in
\cref{lst:blinkthreadmtask
}.
559 \begin{lstClean
}[label=
{lst:mtask_repeat
},caption=
{Repeat task combinators in
\gls{MTASK
}.
}]
561 rpeat :: (MTask v a) -> MTask v a
564 To demonstrate the combinator,
\cref{lst:mtask_repeat_example
} show
\cleaninline{rpeat
} in use.
565 This task will mirror the value read from analog
\gls{GPIO
} pin
\cleaninline{A1
} to pin
\cleaninline{A2
} by constantly reading the pin and writing the result.
567 \begin{lstClean
}[label=
{lst:mtask_repeat_example
},caption=
{Exemplatory repeat task in
\gls{MTASK
}.
}]
568 task :: MTask v Int | mtask v
570 declarePin A1 PMInput
\a1->
571 declarePin A2 PMOutput
\a2->
572 {main = rpeat (readA a1 >>~. writeA a2)
}
575 \subsection{\texorpdfstring{\Acrlongpl{SDS
}}{Shared data sources
}}
576 \Glspl{SDS
} in
\gls{MTASK
} are by default references to shared memory.
577 Similar to peripherals (see
\cref{sssec:peripherals
}), they are constructed at the top level and are accessed through interaction tasks.
578 The
\cleaninline{getSds
} task yields the current value of the
\gls{SDS
} as an unstable value.
579 This behaviour is similar to the
\cleaninline{watch
} task in
\gls{ITASK
}.
580 Writing a new value to an
\gls{SDS
} is done using
\cleaninline{setSds
}.
581 This task yields the written value as a stable result after it is done writing.
582 Getting and immediately after setting an
\gls{SDS
} is not an
\emph{atomic
} operation.
583 It is possible that another task accesses the
\gls{SDS
} in between.
584 To circumvent this issue,
\cleaninline{updSds
} is created, this task atomically updates the value of the
\gls{SDS
}.
586 \begin{lstClean
}[label=
{lst:mtask_sds
},caption=
{\Glspl{SDS
} in
\gls{MTASK
}.
}]
589 sds :: ((v (Sds t)) -> In t (Main (MTask v u))) -> Main (MTask v u)
590 getSds :: (v (Sds t)) -> MTask v t
591 setSds :: (v (Sds t)) (v t) -> MTask v t
592 updSds :: (v (Sds t)) ((v t) -> v t) -> MTask v t
597 \chapter{Green computing with
\texorpdfstring{\gls{MTASK
}}{mTask
}}%
598 \label{chp:green_computing_mtask
}
600 \chapter{Integration with
\texorpdfstring{\gls{ITASK
}}{iTask
}}%
601 \label{chp:integration_with_itask
}
602 The
\gls{MTASK
} language is a multi-view
\gls{DSL
}, i.e.\ there are multiple interpretations possible for a single
\gls{MTASK
} expression.
603 Using the byte code compiler (
\cleaninline{BCInterpret
})
\gls{DSL
} interpretation,
\gls{MTASK
} tasks can be fully integrated in
\gls{ITASK
} and executed as if they were regular
\gls{ITASK
} tasks, sharing data using
\gls{ITASK
} \glspl{SDS
}.
605 \Cref{fig:mtask_integration
} shows the
609 \includestandalone{mtask_integration
}
610 \caption{\Gls{MTASK
}'s integration with
\gls{ITASK
}.
}%
611 \label{fig:mtask_integration
}
615 \Gls{MTASK
} tasks in the byte code compiler view are always executed on a certain device.
616 All communication with this device happens through a so-called
\emph{channels
} \gls{SDS
}.
617 The channels contain three fields, a queue of messages that are received, a queue of messages to send and a stop flag.
618 Every communication method that implements the
\cleaninline{channelSync
} class can provide the communication with an
\gls{MTASK
} device.
619 As of now, serial port communication, direct
\gls{TCP
} communication and
\gls{MQTT
} over
\gls{TCP
} are supported as communication providers.
620 The
\cleaninline{withDevice
} function transforms a communication provider and a task that does something with this device to an
\gls{ITASK
} task.
621 This task sets up the communication, exchanges specifications, handles errors and cleans up after closing.
622 \Cref{lst:mtask_device
} shows the types and interface to connecting devices.
624 \begin{lstClean
}[label=
{lst:mtask_device
},caption=
{Device communication interface in
\gls{MTASK
}.
}]
625 :: MTDevice //abstract
626 :: Channels :== (
[MTMessageFro
],
[MTMessageTo
], Bool)
628 class channelSync a :: a (sds () Channels Channels) -> Task () | RWShared sds
630 withDevice :: (a (MTDevice -> Task b) -> Task b) | iTask b & channelSync, iTask a
634 \section{Lifting tasks
}
635 Once the connection with the device is established,
\ldots
637 liftmTask :: (Main (BCInterpret (TaskValue u))) MTDevice -> Task u | iTask u
640 \section{Lifting
\texorpdfstring{\acrlongpl{SDS
}}{shared data sources
}}
641 \begin{lstClean
}[label=
{lst:mtask_itasksds
},caption=
{Lifted
\gls{ITASK
} \glspl{SDS
} in
\gls{MTASK
}.
}]
642 class liftsds v where
643 liftsds :: ((v (Sds t))->In (Shared sds t) (Main (MTask v u)))
644 -> Main (MTask v u) | RWShared sds
647 \chapter{Implementation
}%
648 \label{chp:implementation
}
649 IFL19 paper, bytecode instructieset~
\cref{chp:bytecode_instruction_set
}
651 \section{Integration with
\texorpdfstring{\gls{ITASK
}}{iTask
}}
654 \chapter{\texorpdfstring{\gls{MTASK
}}{mTask
} history
}
655 \section{Generating
\texorpdfstring{\gls{C
}/
\gls{CPP
}}{C/C++
} code
}
656 A first throw at a class-based shallowly
\gls{EDSL
} for microprocessors was made by
\citet{plasmeijer_shallow_2016
}.
657 The language was called
\gls{ARDSL
} and offered a type safe interface to
\gls{ARDUINO
} \gls{CPP
} dialect.
658 A
\gls{CPP
} code generation backend was available together with an
\gls{ITASK
} simulation backend.
659 There was no support for tasks or even functions.
660 Some time later in the
2015 \gls{CEFP
} summer school, an extended version was created that allowed the creation of imperative tasks,
\glspl{SDS
} and the usage of functions~
\citep{koopman_type-safe_2019
}.
661 The name then changed from
\gls{ARDSL
} to
\gls{MTASK
}.
663 \section{Integration with
\texorpdfstring{\gls{ITASK
}}{iTask
}}
664 Mart Lubbers extended this in his Master's Thesis by adding integration with
\gls{ITASK
} and a bytecode compiler to the language~
\citep{lubbers_task_2017
}.
665 \Gls{SDS
} in
\gls{MTASK
} could be accessed on the
\gls{ITASK
} server.
666 In this way, entire
\gls{IOT
} systems could be programmed from a single source.
667 However, this version used a simplified version of
\gls{MTASK
} without functions.
668 This was later improved upon by creating a simplified interface where
\glspl{SDS
} from
\gls{ITASK
} could be used in
\gls{MTASK
} and the other way around~
\citep{lubbers_task_2018
}.
669 It was shown by Matheus Amazonas Cabral de Andrade that it was possible to build real-life
\gls{IOT
} systems with this integration~
\citep{amazonas_cabral_de_andrade_developing_2018
}.
670 Moreover, a course on the
\gls{MTASK
} simulator was provided at the
2018 \gls{CEFP
}/
\gls{3COWS
} winter school in Ko
\v{s
}ice, Slovakia~
\citep{koopman_simulation_2018
}.
672 \section{Transition to
\texorpdfstring{\gls{TOP
}}{TOP
}}
673 The
\gls{MTASK
} language as it is now was introduced in
2018~
\citep{koopman_task-based_2018
}.
674 This paper updated the language to support functions, tasks and
\glspl{SDS
} but still compiled to
\gls{CPP
} \gls{ARDUINO
} code.
675 Later the bytecode compiler and
\gls{ITASK
} integration was added to the language~
\citep{lubbers_interpreting_2019
}.
676 Moreover, it was shown that it is very intuitive to write
\gls{MCU
} applications in a
\gls{TOP
} language~
\citep{lubbers_multitasking_2019
}.
677 One reason for this is that a lot of design patterns that are difficult using standard means are for free in
\gls{TOP
} (e.g.\ multithreading).
678 In
2019, the
\gls{CEFP
} summer school in Budapest, Hungary hosted a course on developing
\gls{IOT
} applications with
\gls{MTASK
} as well~
\citep{lubbers_writing_2019
}.
680 \section{\texorpdfstring{\gls{TOP
}}{TOP
}}
681 In
2022, the SusTrainable summer school in Rijeka, Croatia hosted a course on developing greener
\gls{IOT
} applications using
\gls{MTASK
} as well (the lecture notes are to be written).
682 Several students worked on extending
\gls{MTASK
} with many useful features:
683 Erin van der Veen did preliminary work on a green computer analysis, built a simulator and explored the possibilities for adding bounded datatypes~
\citep{veen_van_der_mutable_2020
}; Michel de Boer investigated the possibilities for secure communication channels~
\citep{boer_de_secure_2020
}; and Sjoerd Crooijmans added abstractions for low-power operation to
\gls{MTASK
} such as hardware interrupts and power efficient scheduling~
\citep{crooijmans_reducing_2021
}.
684 Elina Antonova defined a preliminary formal semantics for a subset of
\gls{MTASK
}~
\citep{antonova_MTASK_2022
}.
685 Moreover, plans for student projects and improvements include exploring integrating
\gls{TINYML
} into
\gls{MTASK
}; and adding intermittent computing support to
\gls{MTASK
}.
687 In
2023, the SusTrainable summer school in Coimbra, Portugal will host a course on
\gls{MTASK
} as well.
689 \section{\texorpdfstring{\gls{MTASK
}}{mTask
} in practise
}
690 Funded by the Radboud-Glasgow Collaboration Fund, collaborative work was executed with Phil Trinder, Jeremy Singer and Adrian Ravi Kishore Ramsingh.
691 An existing smart campus application was developed using
\gls{MTASK
} and quantitively and qualitatively compared to the original application that was developed using a traditional
\gls{IOT
} stack~
\citep{lubbers_tiered_2020
}.
692 The collaboration is still ongoing and a journal article is under review comparing four approaches for the edge layer:
\gls{PYTHON
},
\gls{MICROPYTHON
},
\gls{ITASK
} and
\gls{MTASK
}.
693 Furthermore, power efficiency behaviour of traditional versus
\gls{TOP
} \gls{IOT
} stacks is being compared as well adding a
\gls{FREERTOS
} implementation to the mix as well
695 \input{subfilepostamble
}