add system overview
[msc-thesis1617.git] / arch.devices
1 A device is suitable for the system if it can run the engine.
2 The engine is compiled from one codebase and devices implement (part of) the
3 device specific interface. The shared codebase only uses standard \gls{C} and
4 no special libraries or tricks are used. Therefore, the code is compilable for
5 almost any device or system. Note that it is not needed to implement a full
6 interface. The full interface --- excluding the device specific settings --- is
7 listed in Appendix~\ref{app:device-interface}. The interface works in a
8 similar fashion as the \gls{EDSL}. Devices do not have to implement all
9 functionality, this is analogous to the fact that views do not have to
10 implement all type classes in the \gls{EDSL}. When the device connects with
11 the server for the first time, the specifications of what is implemented is
12 communicated.
13
14 At the time of writing the following device families are supported and can run
15 the device software.
16 \begin{itemize}
17 \item \texttt{POSIX} compatible systems connected via the \gls{TCP}.
18
19 This includes systems running \emph{Linux} and \emph{MacOS}.
20 \item The \texttt{STM32} microcontrollers family supported by
21 \texttt{ChibiOS} connected via serial communication.
22
23 This is tested in particular on the \texttt{STM32f7x} series \gls{ARM}
24 development board.
25 \item Microcontrollers which are programmable in the \gls{Arduino} \gls{IDE}
26 connected via serial communication or via \gls{TCP} over WiFi or
27 Ethernet.
28
29 This does not only include \gls{Arduino} compatible boards but also
30 other boards capable of running \gls{Arduino} code. A port of the
31 client has been made for the \texttt{ESP8266} powered \emph{NodeMCU}
32 that is connected via \gls{TCP} over WiFi. A port also has been made
33 for the regular \gls{Arduino} \emph{UNO} board which only boasts a
34 meager \emph{2K} \emph{RAM}. The stack size and storage available for
35 devices boasting this little \emph{RAM} has to be smaller than default
36 but are still suitable to hold a hand full of \glspl{Task}.
37 \end{itemize}
38
39 \subsection{Client}
40 \subsubsection{Engine}
41 The client is in a constant loop listening for input and waiting to execute
42 \glspl{Task}. The pseudocode for this is shown in Algorithm~\ref{alg:client}.
43 The \CI{input\_available} function waits for input, but has a timeout set which
44 can be interrupted. The timeout of the function determines the amount of loops
45 per time interval and is a parameter that can be set during compilation for a
46 device.
47
48 \begin{algorithm}
49 \KwData{
50 \textbf{list} $tasks$,
51 \textbf{time} $tm$
52 }
53
54 \Begin{
55 \While{true}{
56 \If{input\_available$()$}{
57 receive\_data()\;
58 }
59
60 $tm\leftarrow \text{now}()$\;
61 \ForEach{$t\leftarrow tasks$}{
62 \uIf{is\_interrupt$(t)$ \textbf{and} had\_interrupt$(t)$}{
63 run\_task$(t)$\;
64 }
65 \ElseIf{$tm-t.\text{lastrun} > t.\text{interval}$}{
66 run\_task$(t)$\;
67 \uIf{$t.\text{interval}==0$}{
68 delete\_task$(t)$\;
69 }\Else{
70 $t.\text{lastrun}\leftarrow t$\;
71 }
72 }
73 }
74 }
75 }
76 \caption{Engine pseudocode}\label{alg:client}
77 \end{algorithm}
78
79 \subsubsection{Storage}
80 \glspl{Task} and \glspl{SDS} are stored on the client in memory. Some devices
81 have very little memory and therefore memory space is very expensive and needs
82 to be used optimally. Almost all microcontrollers support heaps nowadays,
83 however, the functions for allocating and freeing the memory on the heap are
84 not very space optimal and often leave holes in the heap if allocations are not
85 freed in reverse order. To overcome this problem the client will allocate a big
86 memory segment in the global data block. This block of memory resides under the
87 stack and its size can be set in the interface implementation. This block of
88 memory will be managed in a similar way as the entire memory space of the
89 device is managed. \Glspl{Task} will grow from the bottom up and \glspl{SDS}
90 will grow from the top down.
91
92 When a \gls{Task} is received, the program will traverse the memory space from
93 the bottom up, jumping over all \glspl{Task}. A \gls{Task} is stored as the
94 structure followed directly by its bytecode. Therefore it only takes two jumps
95 to determine the size of the \gls{Task}. When the program arrived at the last
96 \gls{Task}, this place is returned and the newly received \gls{Task} can be
97 copied to there. This method is analogously applied for \glspl{SDS}, however,
98 the \glspl{SDS} grow from the bottom down.
99
100 When a \gls{Task} or \gls{SDS} is removed, all remaining objects are compressed
101 again. This means that if the first received \gls{Task} is removed, all
102 \glspl{Task} received later will have to move back. Obviously, this is quite
103 time intensive but it can not be permitted to leave holes in the memory since
104 the memory space is so limited. This techniques allows for even the smallest
105 tested microcontrollers with only $2K$ \emph{RAM} to hold several \glspl{Task}
106 and \glspl{SDS}. If this technique would not be used the memory space will
107 decrease over time and the client can then not run for very long since holes
108 are evidently created at some point.
109
110 The structure instances and helper functions for traversing them in memory for
111 \glspl{Task} and \glspl{SDS} are shown in Listing~\ref{lst:structs}.
112
113 \begin{lstlisting}[language=C,label={lst:structs},%
114 caption={The data type storing the \glspl{Task}},float]
115 struct task {
116 uint16_t tasklength;
117 uint16_t interval;
118 unsigned long lastrun;
119 uint8_t taskid;
120 uint8_t *bc;
121 };
122
123 struct task *task_head(void);
124 struct task *task_next(struct task *t);
125
126 struct sds {
127 int id;
128 int value;
129 char type;
130 };
131
132 struct sds *sds_head(void);
133 struct sds *sds_next(struct sds *s);
134 \end{lstlisting}
135
136 \subsubsection{Interpretation}
137 The execution of a \gls{Task} is started by running the \CI{run\_task} function
138 and always starts with setting the program counter and stack
139 pointer to zero and the bottom respectively. When finished, the
140 interpreter executes one step at the time while the program counter is smaller
141 than the program length. This code is listed in Listing~\ref{lst:interpr}. One
142 execution step is basically a big switch statement going over all possible
143 bytecode instructions. Of some instructions, the implementations are shown in
144 the listing. The \CI{BCPush} instruction is a little more complicated in the
145 real code because some decoding will take place as not all \CI{BCValue}s are of
146 the same length and are encoded.
147
148 \begin{lstlisting}[language=C,label={lst:interpr},%
149 caption={Rough code outline for interpretation}]
150 #define f16(p) program[pc]*265+program[pc+1]
151
152 void run_task(struct task *t){
153 uint8_t *program = t->bc;
154 int plen = t->tasklength;
155 int pc = 0;
156 int sp = 0;
157 while(pc < plen){
158 switch(program[pc++]){
159 case BCNOP:
160 break;
161 case BCPUSH:
162 stack[sp++] = pc++ //Simplified
163 break;
164 case BCPOP:
165 sp--;
166 break;
167 case BCSDSSTORE:
168 sds_store(f16(pc), stack[--sp]);
169 pc+=2;
170 break;
171 // ...
172 case BCADD: trace("add");
173 stack[sp-2] = stack[sp-2] + stack[sp-1];
174 sp -= 1;
175 break;
176 // ...
177 case BCJMPT: trace("jmpt to %d", program[pc]);
178 pc = stack[--sp] ? program[pc]-1 : pc+1;
179 break;
180 }
181 \end{lstlisting}
182
183 \subsection{Specification}
184 The server stores a description for every device available in a record type.
185 From the macro settings in the interface file, a profile is created that
186 describes the specification of the device. When the connection between the
187 server and a client is established, the server will send a request for
188 specification. The client serializes its specification and send it to the
189 server so that the server knows what the client is capable of. The exact
190 specification is shown in Listing~\ref{lst:devicespec} and stores the
191 peripheral availability, the memory available for storing \glspl{Task} and
192 \glspl{SDS} and the size of the stack.
193
194 \begin{lstlisting}[label={lst:devicespec},
195 caption={Device specification for \gls{mTask}-\glspl{Task}}]
196 :: MTaskDeviceSpec =
197 { haveLed :: Bool
198 , haveLCD :: Bool
199 , have...
200 , bytesMemory :: Int
201 , stackSize :: Int
202 , aPins :: Int
203 , dPins :: Int
204 }
205 \end{lstlisting}