--- /dev/null
-The engine starts with no tasks. To send a new task the following protocol must
-be adhered.
+ # mTask
+
+ ### Introduction
+ *mTasks* are small imperative tasks that can be run on an embedded device like
+ arduino/ESPxxx/Nucleo arm boards. They are communicated to the device in
+ bytecode which is interpreted by the engine that has to be programmed on the
+ device.
+
+ The devices suitable for *mTasks* are not limited to embedded devices. In the
+ `int` folder is a `C` reference implementation available for intel machines.
+
+ *mTasks* are written in [clean][clean] and specifically using the
+ [iTasks][itasks] library.
+
+ ### Workings of an *mTask* system
+ *mTasks* are routines that are executed in a round robin fashion
+
+ ### Communication back to the server via shared data sources
+ When a shared data source is updated the *mTask* can publish this data back to
+ the server. This is usefull when for example a temperature reaches a certain
+ threshhold. How this communication will be done is yet to be researched.
+ **TODO**
+
+ ### Usage
+ All programs can be built by running `make`. Note that you need the latest
+ `clm` version if you want to use the `Makefile` since hierarchical modules are
+ used. This version can be found [here][clm].
+
+ The following programs are available as of now:
+ - `mTaskExamples`
+
+ This compiles a list of mTask examples to `C` code.
+
+ - `mTaskMakeSymbols`
+
+ This creates the `mTaskSymbols.h` header file
+
+ - `mTaskInterpret`
+
+ This compiles a subset of *mTasks* to bytecode.
+
+ ### Protocol
-Since the system consists only of stores and tasks they are send in different
-ways.
-**TODO**
++The server can send task specifications to the microcontroller by sending:
++| id | length
++| 's' | n | n bytes | newline
+
++Where n is a 16bit integer.
+
+ ### Bytecode operations
+ The header file for the interpreter with the corresponding bytevalues can be
+ generated by running `mTaskMakeSymbols`.
+
+ ### Author(s)
+ Initial work has been done by Pieter Koopman. Extensions have been made by Mart
+ Lubbers.
+
+ [clm]: https://svn.cs.ru.nl/repos/clean-tools/trunk/clm
+ [clean]: clean.cs.ru.nl
+ [itasks]: clean.cs.ru.nl/ITasks
generic consIndex a :: a -> Int
derive consIndex CONS of {gcd_index},UNIT,PAIR,EITHER,OBJECT,Int,Bool,Char,String
-conses :: [a] | gconses{|*|} a
-generic gconses a :: Bool -> [a]
-derive gconses CONS,UNIT,PAIR,EITHER,OBJECT,FIELD,RECORD,Int,Bool,Char,Real,String,(),{},{!},[],[! ],[ !],[!!],(->)
+generic conses a :: [a]
- derive conses CONS,UNIT,PAIR,EITHER,OBJECT,FIELD,RECORD,Int,Bool,Char,Real,String,(),{},{!},[],[! ],[ !],[!!]
++derive conses CONS,UNIT,PAIR,EITHER,OBJECT,FIELD,RECORD,Int,Bool,Char,Real,String,(),{},{!},[],[! ],[ !],[!!],(->)
consIndex{|Char|} c = toInt c
consIndex{|String|} _ = 0
- import StdMisc, StdDebug
-conses :: [a] | gconses{|*|} a
-conses = gconses{|*|} True
--
-generic gconses a :: Bool -> [a]
-gconses{|CONS|} f True = map CONS (f False)
-gconses{|CONS|} f b = [CONS (hd (f b))]
-gconses{|UNIT|} _ = [UNIT]
-gconses{|PAIR|} f g _ = []
-gconses{|EITHER|} f g b = map LEFT (f b) ++ map RIGHT (g b)
-gconses{|OBJECT|} f b = map OBJECT (f b)
-gconses{|RECORD|} f b = map RECORD (f b)
-gconses{|FIELD|} f b = map FIELD (f b)
-gconses{|Int|} _ = [0]
-gconses{|Bool|} _ = [True]
-gconses{|Char|} _ = ['\0']
-gconses{|Real|} _ = [0.0]
-gconses{|String|} _ = [""]
-gconses{|[]|} _ _ = [[ ]]
-gconses{|[!]|} _ _ = [[!]]
-gconses{|[ !]|} _ _ = [[ !]]
-gconses{|[!!]|} _ _ = [[!!]]
-gconses{|{}|} _ _ = [{}]
-gconses{|{!}|} _ _ = [{!}]
-gconses{|()|} _ = [()]
-gconses{|(->)|} _ _ _ = [const undef]
+generic conses a :: [a]
- conses{|CONS|} f = map CONS f
++conses{|CONS|} f = [CONS (hd f)]
+conses{|UNIT|} = [UNIT]
+conses{|PAIR|} f g = []
+conses{|EITHER|} f g = map LEFT f ++ map RIGHT g
+conses{|OBJECT|} f = map OBJECT f
+conses{|RECORD|} f = map RECORD f
+conses{|FIELD|} f = map FIELD f
+conses{|Int|} = [0]
+conses{|Bool|} = [True]
+conses{|Char|} = ['\0']
+conses{|Real|} = [0.0]
+conses{|String|} = [""]
+conses{|[]|} _ = [[ ]]
+conses{|[!]|} _ = [[!]]
+conses{|[ !]|} _ = [[ !]]
+conses{|[!!]|} _ = [[!!]]
+conses{|{}|} _ = [{}]
+conses{|{!}|} _ = [{!}]
+conses{|()|} = [()]
++conses{|(->)|} _ _ = [const undef]
#include <stdio.h>
+#include <stdbool.h>
++#include <stdlib.h>
++#include <signal.h>
++#include <string.h>
++#include <unistd.h>
++#include <stdint.h>
#include "mTaskSymbols.h"
++#define MAXTASKS 5
++#define MAXTASKSIZE 1024
++#define MAXSDS 50
#define STACKSIZE 1024
--#define PROGRAMSIZE 1024
#define DEBUG
#ifdef DEBUG
#define debug(s, ...) ;
#endif
--#define die(s, ...) {fprintf(stderr, s, ##__VA_ARGS__); return 1;}
++#define pdie(s) {perror(s); exit(1);}
++#define die(s, ...) {fprintf(stderr, s, ##__VA_ARGS__); exit(1);}
--char program[PROGRAMSIZE+1] = {0};
--int stack[STACKSIZE+1] = {0};
++char tasks[MAXTASKS][MAXTASKSIZE] = {0};
+
- bool input_available(){
++void killHandler(int i)
++{
++ printf("%s caught, Bye...\n", strsignal(i));
++ exit(1);
++}
++
++bool input_available(int fd){
+ struct timeval tv;
+ fd_set fds;
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ FD_ZERO(&fds);
- FD_SET(0, &fds);
- select(1, &fds, NULL, NULL, &tv);
- return FD_ISSET(0, &fds);
++ FD_SET(fd, &fds);
++ if(select(fd+1, &fds, NULL, NULL, &tv) == -1){
++ pdie("select");
++ }
++ return FD_ISSET(fd, &fds);
+}
-
int main(void)
{
-- char c;
-- int pl, sp, pc;
++ uint8_t c;
++// char taskindex = 0;
++// int pl, sp, pc;
++//
++ int fd_in = 0;
++ int next_free_new_task = 0;
++ uint16_t tasklen = 0;
++
++ //Register signal handler
++ if(signal(SIGINT, killHandler) == SIG_ERR){
++ die("Couldn't register signal handler...\n");
++ }
++ if(signal(SIGTERM, killHandler) == SIG_ERR){
++ die("Couldn't register signal handler...\n");
++ }
++
++ while(true){
++ if(input_available(fd_in)){
++ printf("Receiving input\n");
++ read(fd_in, &c, 1);
++ if((char) c == 's'){
++ debug("Receiving an sds\n");
++ } else if((char) c == 't'){
++ read(fd_in, &c, 1);
++ tasklen = 256*c;
++ read(fd_in, &c, 1);
++ tasklen += c;
++ if(tasklen > MAXTASKSIZE){
++ die("Task is too long: %d\n", tasklen);
++ }
++ for(int i = 0; i<tasklen; i++){
++ debug("Read %d\n", i);
++ read(fd_in, tasks[next_free_new_task]+i, 1);
++ read(fd_in, tasks[next_free_new_task]+i, 1);
++ debug("t[][%i]: %d\n", i, tasks[next_free_new_task][i]);
++ }
++ debug("Receiving a task of length %d\n", tasklen);
++ } else {
++ die("Unknown message: %c?\n", c);
++ }
++ exit(1);
++ }
++ usleep(1);
++ }
-- //Read program
++/* //Read program
pc = 0;
while ((c = getchar()) != EOF && pc < PROGRAMSIZE)
program[pc++] = c;
sp = 0;
while(pc != pl){
switch(program[pc++]){
-- case BCNop:;
++ case BCNOP:;
break;
-- case BCPush:
++ case BCPUSH:
stack[sp++] = program[pc++];
break;
-- case BCPop:
++ case BCPOP:
sp--;
break;
-- case BCNot:
++ case BCNOT:
stack[sp] = stack[sp] > 0 ? 0 : 1;
break;
-- case BCAdd:
++ case BCADD:
stack[sp-1] = stack[sp] + stack[sp-1];
sp -= 1;
break;
-- case BCSub:
++ case BCSUB:
stack[sp-1] = stack[sp] - stack[sp-1];
sp -= 1;
break;
-- case BCMul:
++ case BCMUL:
stack[sp-1] = stack[sp] * stack[sp-1];
sp -= 1;
break;
-- case BCDiv:
++ case BCDIV:
stack[sp-1] = stack[sp] / stack[sp-1];
sp -= 1;
break;
-- case BCAnd:
++ case BCAND:
stack[sp-1] = stack[sp] && stack[sp-1];
sp -= 1;
break;
-- case BCOr:
++ case BCOR:
stack[sp-1] = stack[sp] || stack[sp-1];
sp -= 1;
break;
-- case BCEq:
++ case BCEQ:
stack[sp-1] = stack[sp] == stack[sp-1];
sp -= 1;
break;
-- case BCNeq:
++ case BCNEQ:
stack[sp-1] = stack[sp] != stack[sp-1];
sp -= 1;
break;
-- case BCLes:
-- stack[sp-1] = stack[sp] < stack[sp-1];
++ case BCLES: stack[sp-1] = stack[sp] < stack[sp-1];
sp -= 1;
break;
-- case BCGre:
++ case BCGRE:
stack[sp-1] = stack[sp] > stack[sp-1];
sp -= 1;
break;
-- case BCLeq:
++ case BCLEQ:
stack[sp-1] = stack[sp] <= stack[sp-1];
sp -= 1;
break;
-- case BCGeq:
++ case BCGEQ:
stack[sp-1] = stack[sp] >= stack[sp-1];
sp -= 1;
break;
-- case BCJmp:
++ case BCJMP:
pc = pc + program[pc];
break;
-- case BCJmpT:
++ case BCJMPT:
pc += stack[sp] ? program[pc] : 1;
break;
-- case BCJmpF:
++ case BCJMPF:
pc += stack[sp] ? 1 : program[pc];
break;
case BCSERIALAVAIL:
die("Unrecognized command: %X\n", program[--pc]);
}
}
++*/
return 0;
}
#ifndef MTASK_H
#define MTASK_H
- #define BCNOP 0
- #define BCPUSH 1
- #define BCPOP 2
- #define BCNOT 3
- #define BCADD 4
- #define BCSUB 5
- #define BCMUL 6
- #define BCDIV 7
- #define BCAND 8
- #define BCOR 9
- #define BCEQ 10
- #define BCNEQ 11
- #define BCLES 12
- #define BCGRE 13
- #define BCLEQ 14
- #define BCGEQ 15
- #define BCJMP 16
- #define BCJMPT 17
- #define BCJMPF 18
- #define BCSERIALAVAIL 19
- #define BCSERIALPRINT 20
- #define BCSERIALPRINTLN 21
- #define BCSERIALREAD 22
- #define BCSERIALPARSEINT 23
- #define BCANALOGREAD 24
- #define BCANALOGWRITE 25
- #define BCDIGITALREAD 26
- #define BCDIGITALWRITE 27
- #define BCTEST 28
+ #define BCNOP 1
+ #define BCPUSH 2
+ #define BCPOP 3
+ #define BCNOT 4
+ #define BCADD 5
+ #define BCSUB 6
+ #define BCMUL 7
+ #define BCDIV 8
+ #define BCAND 9
+ #define BCOR 10
+ #define BCEQ 11
+ #define BCNEQ 12
+ #define BCLES 13
+ #define BCGRE 14
+ #define BCLEQ 15
+ #define BCGEQ 16
+ #define BCJMP 17
+ #define BCJMPT 18
+ #define BCJMPF 19
+ #define BCSERIALAVAIL 20
+ #define BCSERIALPRINT 21
+ #define BCSERIALPRINTLN 22
+ #define BCSERIALREAD 23
+ #define BCSERIALPARSEINT 24
+ #define BCANALOGREAD 25
+ #define BCANALOGWRITE 26
+ #define BCDIGITALREAD 27
+ #define BCDIGITALWRITE 28
+#define BCTEST 29
- #define BCTEST 30
- #define BCTEST 31
- #define BCTEST 32
- #define BCTEST 33
#endif
Start w
# (io, w) = stdio w
# io = io <<< "#ifndef MTASK_H\n#define MTASK_H\n"
- # io = io <<< join "\n" (map (uncurry toDefine) (zip2 [0..] conses{|*|}))
-# io = io <<< join "\n" $ zipWith toDefine [1..] conses
++# io = io <<< join "\n" (zipWith toDefine [1..] conses{|*|})
# (ok, w) = fclose (io <<< "\n#endif\n") w
| not ok = abort "Couldn't close stdio"
= w