added sds operators, timing and task deletion
[mTask.git] / int / int.c
1 #include <netdb.h>
2 #include <netinet/in.h>
3 #include <signal.h>
4 #include <stdbool.h>
5 #include <stdint.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <sys/socket.h>
10 #include <sys/types.h>
11 #include <sys/time.h>
12 #include <unistd.h>
13
14 #include "mTaskSymbols.h"
15
16 #define MAXTASKS 5
17 #define MAXTASKSIZE 1024
18 #define MAXSDS 50
19 #define STACKSIZE 1024
20
21 #define MSG_TASK 't'
22 #define MSG_DELTASK 'd'
23 #define MSG_SDS 's'
24
25 #define DEBUG
26
27 #ifdef DEBUG
28 #define debug(s, ...) printf(s, ##__VA_ARGS__);
29 #define trace(op, ...) printf("pc: %d, sp: %d, op: " op, pc, sp, ##__VA_ARGS__);
30 #else
31 #define debug(s, ...) ;
32 #define trace(pc, sp, op) ;
33 #endif
34
35 #define pdie(s) {perror(s); exit(1);}
36 #define die(s, ...) {fprintf(stderr, s, ##__VA_ARGS__); exit(1);}
37
38 struct task {
39 uint8_t bc[MAXTASKSIZE];
40 uint16_t tlen;
41 uint16_t interval;
42 long lastrun;
43 bool used;
44 };
45
46 struct timeval tv1;
47 struct task tasks[MAXTASKS] = {0};
48 int sock_fd = -1;
49 int fd = -1;
50 int port = 8123;
51
52 void killHandler(int i)
53 {
54 printf("%s caught, Bye...\n", strsignal(i));
55 exit(1);
56 }
57
58 bool input_available(int fd){
59 struct timeval tv;
60 fd_set fds;
61 tv.tv_sec = 0;
62 tv.tv_usec = 0;
63 FD_ZERO(&fds);
64 FD_SET(fd, &fds);
65 if (select(fd+1, &fds, NULL, NULL, &tv) == -1)
66 pdie("select");
67 return FD_ISSET(fd, &fds);
68 }
69
70 long millis() {
71 if (gettimeofday(&tv1, NULL) == -1)
72 pdie("gettimeofday");
73 return tv1.tv_sec*1000 + tv1.tv_usec/1000;
74 }
75
76 void read_message(int fd_in, int fd_out)
77 {
78 //Find next task
79 uint8_t c, ct;
80
81 for(ct = 0; ct<MAXTASKS; ct++)
82 if(!tasks[ct].used)
83 break;
84 if(ct == MAXTASKS)
85 die("Trying to add too much tasks...\n");
86
87 debug("Receiving input for task %d\n", ct);
88 read(fd_in, &c, 1);
89 switch(c){
90 case MSG_SDS:
91 debug("Receiving an sds\n");
92 break;
93 case MSG_DELTASK:
94 debug("Receiving a delete task request\n");
95 //Read task number and set unused
96 read(fd_in, &c, 1);
97 tasks[ct].used = false;
98 break;
99 case MSG_TASK:
100 debug("Receiving a task\n");
101 bzero(&tasks[ct], sizeof(struct task));
102 //Read interval
103 read(fd_in, &c, 1);
104 tasks[ct].interval = 256*c;
105 read(fd_in, &c, 1);
106 tasks[ct].interval += c;
107 //Read tasklength
108 read(fd_in, &c, 1);
109 tasks[ct].tlen = 256*c;
110 read(fd_in, &c, 1);
111 tasks[ct].tlen += c;
112 if(tasks[ct].tlen > MAXTASKSIZE)
113 die("Task is too long: %d\n", tasks[ct].tlen);
114 //Read task bytecode
115 for(int i = 0; i<tasks[ct].tlen; i++){
116 debug("Read %d\n", i);
117 read(fd_in, tasks[ct].bc+i, 1);
118 debug("t[][%i]: %d\n", i,
119 tasks[ct].bc[i]);
120 }
121 //Return the task number for later removal
122 write(fd_out, (void *)&ct, 1);
123 debug("Received a task of length %d\n", tasks[ct].tlen);
124 tasks[ct].used = true;
125 break;
126 default:
127 debug("Unknown message: %X?\n", c);
128 }
129 }
130
131 void run_task(int tasknum)
132 {
133 uint8_t *program = tasks[tasknum].bc;
134 int plen = tasks[tasknum].tlen;
135 int pc = 0;
136 int sp = 0;
137 char stack[STACKSIZE] = {0};
138 printf("Running task: %d\nWith length: %d\n", tasknum, plen);
139 while(pc != plen){
140 printf("program: %x\n", program[pc]);
141 switch(program[pc++]){
142 case BCNOP: trace("nop\n");
143 break;
144 case BCPUSH: trace("push %d\n", program[pc]);
145 stack[sp++] = program[pc++];
146 break;
147 case BCPOP: trace("pop\n");
148 sp--;
149 break;
150 case BCSDSSTORE: trace("sds store\n");
151 break;
152 case BCSDSFETCH: trace("sds fetch\n");
153 break;
154 case BCSDSPUBLISH: trace("sds publish\n");
155 break;
156 case BCNOT: trace("not\n");
157 stack[sp] = stack[sp] > 0 ? 0 : 1;
158 break;
159 case BCADD: trace("add\n");
160 stack[sp-1] = stack[sp] + stack[sp-1];
161 sp -= 1;
162 break;
163 case BCSUB: trace("sub\n");
164 stack[sp-1] = stack[sp] - stack[sp-1];
165 sp -= 1;
166 break;
167 case BCMUL: trace("mul\n");
168 stack[sp-1] = stack[sp] * stack[sp-1];
169 sp -= 1;
170 break;
171 case BCDIV: trace("div\n");
172 stack[sp-1] = stack[sp] / stack[sp-1];
173 sp -= 1;
174 break;
175 case BCAND: trace("and\n");
176 stack[sp-1] = stack[sp] && stack[sp-1];
177 sp -= 1;
178 break;
179 case BCOR: trace("or\n");
180 stack[sp-1] = stack[sp] || stack[sp-1];
181 sp -= 1;
182 break;
183 case BCEQ: trace("eq\n");
184 stack[sp-1] = stack[sp] == stack[sp-1];
185 sp -= 1;
186 break;
187 case BCNEQ: trace("neq\n");
188 stack[sp-1] = stack[sp] != stack[sp-1];
189 sp -= 1;
190 break;
191 case BCLES: trace("les\n");
192 stack[sp-1] = stack[sp] < stack[sp-1];
193 sp -= 1;
194 break;
195 case BCGRE: trace("gre\n");
196 stack[sp-1] = stack[sp] > stack[sp-1];
197 sp -= 1;
198 break;
199 case BCLEQ: trace("leq\n");
200 stack[sp-1] = stack[sp] <= stack[sp-1];
201 sp -= 1;
202 break;
203 case BCGEQ: trace("geq\n");
204 stack[sp-1] = stack[sp] >= stack[sp-1];
205 sp -= 1;
206 break;
207 case BCJMP: trace("jmp to %d\n", program[pc]);
208 pc = pc + program[pc];
209 break;
210 case BCJMPT: trace("jmpt to %d\n", program[pc]);
211 pc += stack[sp] ? program[pc] : 1;
212 break;
213 case BCJMPF: trace("jmpf to %d\n", program[pc]);
214 pc += stack[sp] ? 1 : program[pc];
215 break;
216 case BCSERIALAVAIL: trace("SerialAvailable()\n");
217 break;
218 case BCSERIALPRINT: trace("SerialPrint()\n");
219 break;
220 case BCSERIALPRINTLN: trace("SerialPrintln()\n");
221 break;
222 case BCSERIALREAD: trace("SerialRead()\n");
223 break;
224 case BCSERIALPARSEINT: trace("SerialParseInt()\n");
225 break;
226 case BCANALOGREAD: trace("AnalogRead(%d)\n", program[pc]);
227 pc++;
228 break;
229 case BCANALOGWRITE: trace("AnalogWrite(%d)\n", program[pc]);
230 pc++;
231 break;
232 case BCDIGITALREAD: trace("DigitalRead(%d)\n", program[pc]);
233 pc++;
234 break;
235 case BCDIGITALWRITE: trace("DigitalWrite(%d)\n", program[pc]);
236 pc++;
237 break;
238 default:
239 die("Unrecognized command: %d\n", program[--pc]);
240 }
241 }
242 debug("Task %d terminated\n", tasknum);
243 }
244
245 void open_filedescriptors()
246 {
247 struct sockaddr_in sa;
248
249 bzero((char *) &sa, sizeof(sa));
250 sa.sin_family = AF_INET;
251 sa.sin_addr.s_addr = INADDR_ANY;
252 sa.sin_port = htons(port);
253
254 if((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
255 pdie("socket");
256 if(bind(sock_fd, (struct sockaddr*)&sa, sizeof(sa)) == -1)
257 pdie("bind\n");
258 if(listen(sock_fd, 10) == -1)
259 pdie("bind\n");
260
261 printf("Listening on %d\n", port);
262 fflush(stdout);
263 if((fd = accept(sock_fd, (struct sockaddr*)NULL, NULL)) == -1)
264 pdie("accept");
265 }
266
267 void usage(FILE *o, char *arg0){
268 fprintf(o,
269 "Usage: %s [opts]\n"
270 "\n"
271 "Options\n"
272 "-p PORT Custom port number, default: 8123\n"
273 , arg0);
274 }
275
276 int main(int argc, char *argv[])
277 {
278 int ct;
279
280 //Register signal handler
281 if(signal(SIGINT, killHandler) == SIG_ERR){
282 die("Couldn't register signal handler...\n");
283 }
284 if(signal(SIGTERM, killHandler) == SIG_ERR){
285 die("Couldn't register signal handler...\n");
286 }
287
288 //Command line arguments
289 int opt;
290 while((opt = getopt(argc, argv, "hp:")) != -1){
291 switch(opt){
292 case 'p':
293 port = atoi(optarg);
294 if(port < 1)
295 die("Port numbers are > 1\n");
296 break;
297 case 'h':
298 usage(stdout, argv[0]);
299 exit(EXIT_SUCCESS);
300 default:
301 usage(stderr, argv[0]);
302 exit(EXIT_FAILURE);
303 }
304
305 }
306
307 open_filedescriptors();
308
309 long cyclestart;
310 while(true){
311 //Check for new tasks
312 if(input_available(fd))
313 read_message(fd, fd);
314 //Run tasks
315 cyclestart = millis();
316 for(ct = 0; ct<MAXTASKS; ct++){
317 //See whether the task is even in use
318 if(!tasks[ct].used){
319 debug("Task %d not implemented\n", ct);
320 continue;
321 }
322 //See whether the task interval has passed
323 if(cyclestart-tasks[ct].lastrun < tasks[ct].interval){
324 debug("Task %d not scheduled\n", ct);
325 continue;
326 }
327 #ifdef DEBUG
328 printf("Current task to run: %d\n", ct);
329 printf("Enter to continue, s to step\n");
330 switch(getchar()){
331 case 'd':
332 die("Killed\n");
333 case 's':
334 printf("step\n");
335 break;
336 default:
337 break;
338 }
339 #endif
340 run_task(ct);
341 }
342 usleep(10);
343 }
344 return 0;
345 }