CFLAGS:=-g -Wall -Wextra -Werror
-all: mTaskSymbols.h int
+PROG:=main
+OBJS:=interpret.o sds.o task.o
+
+all: mTaskSymbols.h $(PROG)
+
+$(PROG): $(PROG).c $(OBJS) misc.h
+ $(LINK.c) $(LDLIBS) $^ $(OUTPUT_OPTION)
mTaskSymbols.h:
CLMFLAGS=-nr make -BC .. mTaskInterpret
../mTaskInterpret > $@
+
+clean:
+ $(RM) $(OBJS) $(PROG)
+++ /dev/null
-#include <netdb.h>
-#include <netinet/in.h>
-#include <signal.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <unistd.h>
-
-#include "mTaskSymbols.h"
-
-#define MAXTASKS 5
-#define MAXTASKSIZE 1024
-#define MAXSDS 50
-#define STACKSIZE 1024
-
-#define MSG_TASK 't'
-#define MSG_DELTASK 'd'
-#define MSG_SDS 's'
-
-#define DEBUG
-
-#ifdef DEBUG
-#define debug(s, ...) printf(s, ##__VA_ARGS__);
-#define trace(op, ...) printf("pc: %d, sp: %d, op: " op, pc, sp, ##__VA_ARGS__);
-#else
-#define debug(s, ...) ;
-#define trace(pc, sp, op) ;
-#endif
-
-#define pdie(s) {perror(s); exit(1);}
-#define die(s, ...) {fprintf(stderr, s, ##__VA_ARGS__); exit(1);}
-
-struct task {
- uint8_t bc[MAXTASKSIZE];
- uint16_t tlen;
- uint16_t interval;
- long lastrun;
- bool used;
-};
-
-struct timeval tv1;
-struct task tasks[MAXTASKS] = {0};
-int sock_fd = -1;
-int fd = -1;
-int port = 8123;
-
-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(fd, &fds);
- if (select(fd+1, &fds, NULL, NULL, &tv) == -1)
- pdie("select");
- return FD_ISSET(fd, &fds);
-}
-
-long millis() {
- if (gettimeofday(&tv1, NULL) == -1)
- pdie("gettimeofday");
- return tv1.tv_sec*1000 + tv1.tv_usec/1000;
-}
-
-void read_message(int fd_in, int fd_out)
-{
- //Find next task
- uint8_t c, ct;
-
- for(ct = 0; ct<MAXTASKS; ct++)
- if(!tasks[ct].used)
- break;
- if(ct == MAXTASKS)
- die("Trying to add too much tasks...\n");
-
- debug("Receiving input for task %d\n", ct);
- read(fd_in, &c, 1);
- switch(c){
- case MSG_SDS:
- debug("Receiving an sds\n");
- break;
- case MSG_DELTASK:
- debug("Receiving a delete task request\n");
- //Read task number and set unused
- read(fd_in, &c, 1);
- tasks[ct].used = false;
- break;
- case MSG_TASK:
- debug("Receiving a task\n");
- bzero(&tasks[ct], sizeof(struct task));
- //Read interval
- read(fd_in, &c, 1);
- tasks[ct].interval = 256*c;
- read(fd_in, &c, 1);
- tasks[ct].interval += c;
- //Read tasklength
- read(fd_in, &c, 1);
- tasks[ct].tlen = 256*c;
- read(fd_in, &c, 1);
- tasks[ct].tlen += c;
- if(tasks[ct].tlen > MAXTASKSIZE)
- die("Task is too long: %d\n", tasks[ct].tlen);
- //Read task bytecode
- for(int i = 0; i<tasks[ct].tlen; i++){
- debug("Read %d\n", i);
- read(fd_in, tasks[ct].bc+i, 1);
- debug("t[][%i]: %d\n", i,
- tasks[ct].bc[i]);
- }
- //Return the task number for later removal
- write(fd_out, (void *)&ct, 1);
- debug("Received a task of length %d\n", tasks[ct].tlen);
- tasks[ct].used = true;
- break;
- default:
- debug("Unknown message: %X?\n", c);
- }
-}
-
-void run_task(int tasknum)
-{
- uint8_t *program = tasks[tasknum].bc;
- int plen = tasks[tasknum].tlen;
- int pc = 0;
- int sp = 0;
- char stack[STACKSIZE] = {0};
- printf("Running task: %d\nWith length: %d\n", tasknum, plen);
- while(pc != plen){
- printf("program: %x\n", program[pc]);
- switch(program[pc++]){
- case BCNOP: trace("nop\n");
- break;
- case BCPUSH: trace("push %d\n", program[pc]);
- stack[sp++] = program[pc++];
- break;
- case BCPOP: trace("pop\n");
- sp--;
- break;
- case BCSDSSTORE: trace("sds store\n");
- break;
- case BCSDSFETCH: trace("sds fetch\n");
- break;
- case BCSDSPUBLISH: trace("sds publish\n");
- break;
- case BCNOT: trace("not\n");
- stack[sp] = stack[sp] > 0 ? 0 : 1;
- break;
- case BCADD: trace("add\n");
- stack[sp-1] = stack[sp] + stack[sp-1];
- sp -= 1;
- break;
- case BCSUB: trace("sub\n");
- stack[sp-1] = stack[sp] - stack[sp-1];
- sp -= 1;
- break;
- case BCMUL: trace("mul\n");
- stack[sp-1] = stack[sp] * stack[sp-1];
- sp -= 1;
- break;
- case BCDIV: trace("div\n");
- stack[sp-1] = stack[sp] / stack[sp-1];
- sp -= 1;
- break;
- case BCAND: trace("and\n");
- stack[sp-1] = stack[sp] && stack[sp-1];
- sp -= 1;
- break;
- case BCOR: trace("or\n");
- stack[sp-1] = stack[sp] || stack[sp-1];
- sp -= 1;
- break;
- case BCEQ: trace("eq\n");
- stack[sp-1] = stack[sp] == stack[sp-1];
- sp -= 1;
- break;
- case BCNEQ: trace("neq\n");
- stack[sp-1] = stack[sp] != stack[sp-1];
- sp -= 1;
- break;
- case BCLES: trace("les\n");
- stack[sp-1] = stack[sp] < stack[sp-1];
- sp -= 1;
- break;
- case BCGRE: trace("gre\n");
- stack[sp-1] = stack[sp] > stack[sp-1];
- sp -= 1;
- break;
- case BCLEQ: trace("leq\n");
- stack[sp-1] = stack[sp] <= stack[sp-1];
- sp -= 1;
- break;
- case BCGEQ: trace("geq\n");
- stack[sp-1] = stack[sp] >= stack[sp-1];
- sp -= 1;
- break;
- case BCJMP: trace("jmp to %d\n", program[pc]);
- pc = pc + program[pc];
- break;
- case BCJMPT: trace("jmpt to %d\n", program[pc]);
- pc += stack[sp] ? program[pc] : 1;
- break;
- case BCJMPF: trace("jmpf to %d\n", program[pc]);
- pc += stack[sp] ? 1 : program[pc];
- break;
- case BCSERIALAVAIL: trace("SerialAvailable()\n");
- break;
- case BCSERIALPRINT: trace("SerialPrint()\n");
- break;
- case BCSERIALPRINTLN: trace("SerialPrintln()\n");
- break;
- case BCSERIALREAD: trace("SerialRead()\n");
- break;
- case BCSERIALPARSEINT: trace("SerialParseInt()\n");
- break;
- case BCANALOGREAD: trace("AnalogRead(%d)\n", program[pc]);
- pc++;
- break;
- case BCANALOGWRITE: trace("AnalogWrite(%d)\n", program[pc]);
- pc++;
- break;
- case BCDIGITALREAD: trace("DigitalRead(%d)\n", program[pc]);
- pc++;
- break;
- case BCDIGITALWRITE: trace("DigitalWrite(%d)\n", program[pc]);
- pc++;
- break;
- default:
- die("Unrecognized command: %d\n", program[--pc]);
- }
- }
- debug("Task %d terminated\n", tasknum);
-}
-
-void open_filedescriptors()
-{
- struct sockaddr_in sa;
-
- bzero((char *) &sa, sizeof(sa));
- sa.sin_family = AF_INET;
- sa.sin_addr.s_addr = INADDR_ANY;
- sa.sin_port = htons(port);
-
- if((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
- pdie("socket");
- if(bind(sock_fd, (struct sockaddr*)&sa, sizeof(sa)) == -1)
- pdie("bind\n");
- if(listen(sock_fd, 10) == -1)
- pdie("bind\n");
-
- printf("Listening on %d\n", port);
- fflush(stdout);
- if((fd = accept(sock_fd, (struct sockaddr*)NULL, NULL)) == -1)
- pdie("accept");
-}
-
-void usage(FILE *o, char *arg0){
- fprintf(o,
- "Usage: %s [opts]\n"
- "\n"
- "Options\n"
- "-p PORT Custom port number, default: 8123\n"
- , arg0);
-}
-
-int main(int argc, char *argv[])
-{
- int ct;
-
- //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");
- }
-
- //Command line arguments
- int opt;
- while((opt = getopt(argc, argv, "hp:")) != -1){
- switch(opt){
- case 'p':
- port = atoi(optarg);
- if(port < 1)
- die("Port numbers are > 1\n");
- break;
- case 'h':
- usage(stdout, argv[0]);
- exit(EXIT_SUCCESS);
- default:
- usage(stderr, argv[0]);
- exit(EXIT_FAILURE);
- }
-
- }
-
- open_filedescriptors();
-
- long cyclestart;
- while(true){
- //Check for new tasks
- if(input_available(fd))
- read_message(fd, fd);
- //Run tasks
- cyclestart = millis();
- for(ct = 0; ct<MAXTASKS; ct++){
- //See whether the task is even in use
- if(!tasks[ct].used){
- debug("Task %d not implemented\n", ct);
- continue;
- }
- //See whether the task interval has passed
- if(cyclestart-tasks[ct].lastrun < tasks[ct].interval){
- debug("Task %d not scheduled\n", ct);
- continue;
- }
-#ifdef DEBUG
- printf("Current task to run: %d\n", ct);
- printf("Enter to continue, s to step\n");
- switch(getchar()){
- case 'd':
- die("Killed\n");
- case 's':
- printf("step\n");
- break;
- default:
- break;
- }
-#endif
- run_task(ct);
- }
- usleep(10);
- }
- return 0;
-}
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "mTaskSymbols.h"
+#include "interpret.h"
+#include "misc.h"
+#include "task.h"
+
+void run_task(struct task *t)
+{
+ uint8_t *program = t->bc;
+ int plen = t->tlen;
+ int pc = 0;
+ int sp = 0;
+ char stack[STACKSIZE] = {0};
+ printf("Running task with length: %d\n", plen);
+ while(pc != plen){
+ printf("program: %x\n", program[pc]);
+ switch(program[pc++]){
+ case BCNOP: trace("nop\n");
+ break;
+ case BCPUSH: trace("push %d\n", program[pc]);
+ stack[sp++] = program[pc++];
+ break;
+ case BCPOP: trace("pop\n");
+ sp--;
+ break;
+ case BCSDSSTORE: trace("sds store\n");
+ break;
+ case BCSDSFETCH: trace("sds fetch\n");
+ break;
+ case BCSDSPUBLISH: trace("sds publish\n");
+ break;
+ case BCNOT: trace("not\n");
+ stack[sp] = stack[sp] > 0 ? 0 : 1;
+ break;
+ case BCADD: trace("add\n");
+ stack[sp-1] = stack[sp] + stack[sp-1];
+ sp -= 1;
+ break;
+ case BCSUB: trace("sub\n");
+ stack[sp-1] = stack[sp] - stack[sp-1];
+ sp -= 1;
+ break;
+ case BCMUL: trace("mul\n");
+ stack[sp-1] = stack[sp] * stack[sp-1];
+ sp -= 1;
+ break;
+ case BCDIV: trace("div\n");
+ stack[sp-1] = stack[sp] / stack[sp-1];
+ sp -= 1;
+ break;
+ case BCAND: trace("and\n");
+ stack[sp-1] = stack[sp] && stack[sp-1];
+ sp -= 1;
+ break;
+ case BCOR: trace("or\n");
+ stack[sp-1] = stack[sp] || stack[sp-1];
+ sp -= 1;
+ break;
+ case BCEQ: trace("eq\n");
+ stack[sp-1] = stack[sp] == stack[sp-1];
+ sp -= 1;
+ break;
+ case BCNEQ: trace("neq\n");
+ stack[sp-1] = stack[sp] != stack[sp-1];
+ sp -= 1;
+ break;
+ case BCLES: trace("les\n");
+ stack[sp-1] = stack[sp] < stack[sp-1];
+ sp -= 1;
+ break;
+ case BCGRE: trace("gre\n");
+ stack[sp-1] = stack[sp] > stack[sp-1];
+ sp -= 1;
+ break;
+ case BCLEQ: trace("leq\n");
+ stack[sp-1] = stack[sp] <= stack[sp-1];
+ sp -= 1;
+ break;
+ case BCGEQ: trace("geq\n");
+ stack[sp-1] = stack[sp] >= stack[sp-1];
+ sp -= 1;
+ break;
+ case BCJMP: trace("jmp to %d\n", program[pc]);
+ pc = pc + program[pc];
+ break;
+ case BCJMPT: trace("jmpt to %d\n", program[pc]);
+ pc += stack[sp] ? program[pc] : 1;
+ break;
+ case BCJMPF: trace("jmpf to %d\n", program[pc]);
+ pc += stack[sp] ? 1 : program[pc];
+ break;
+ case BCSERIALAVAIL: trace("SerialAvailable()\n");
+ break;
+ case BCSERIALPRINT: trace("SerialPrint()\n");
+ break;
+ case BCSERIALPRINTLN: trace("SerialPrintln()\n");
+ break;
+ case BCSERIALREAD: trace("SerialRead()\n");
+ break;
+ case BCSERIALPARSEINT: trace("SerialParseInt()\n");
+ break;
+ case BCANALOGREAD: trace("AnalogRead(%d)\n", program[pc]);
+ pc++;
+ break;
+ case BCANALOGWRITE: trace("AnalogWrite(%d)\n", program[pc]);
+ pc++;
+ break;
+ case BCDIGITALREAD: trace("DigitalRead(%d)\n", program[pc]);
+ pc++;
+ break;
+ case BCDIGITALWRITE: trace("DigitalWrite(%d)\n", program[pc]);
+ pc++;
+ break;
+ default:
+ die("Unrecognized command: %d\n", program[--pc]);
+ }
+ }
+ debug("Task terminated\n");
+}
--- /dev/null
+#ifndef INTEPRET_H
+#define INTEPRET_H
+
+#define STACKSIZE 1024
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "task.h"
+
+void run_task(struct task *task);
+
+#endif
--- /dev/null
+#include <netdb.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "interpret.h"
+#include "mTaskSymbols.h"
+#include "sds.h"
+#include "task.h"
+#include "misc.h"
+
+#define MAXSDS 50
+
+#define MSG_GET_TASK 't'
+#define MSG_DEL_TASK 'd'
+#define MSG_SDS_SPEC 's'
+#define MSG_SDS_UPD 'u'
+
+struct timeval tv1;
+int sock_fd = -1;
+int fd = -1;
+int port = 8123;
+
+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(fd, &fds);
+ if (select(fd+1, &fds, NULL, NULL, &tv) == -1)
+ pdie("select");
+ return FD_ISSET(fd, &fds);
+}
+
+long millis() {
+ if (gettimeofday(&tv1, NULL) == -1)
+ pdie("gettimeofday");
+ return tv1.tv_sec*1000 + tv1.tv_usec/1000;
+}
+
+void read_message(int fd_in, int fd_out)
+{
+ uint8_t c;
+ //Find next task
+
+ read(fd_in, &c, 1);
+ debug("Receiving input: %c\n", c);
+ switch(c){
+ case MSG_SDS_SPEC:
+ debug("Receiving an sds\n");
+ sds_register(fd_in);
+ break;
+ case MSG_SDS_UPD:
+ debug("Receiving an sds\n");
+ //TODO do something with the return value
+ sds_update(fd_in);
+ break;
+ case MSG_DEL_TASK:
+ debug("Receiving a delete task request\n");
+ task_delete(fd);
+ break;
+ case MSG_GET_TASK:
+ debug("Receiving a task\n");
+ c = task_register(fd_in);
+ write(fd_out, &c, 1);
+ break;
+ default:
+ debug("Unknown message: %X?\n", c);
+ }
+}
+
+void open_filedescriptors()
+{
+ struct sockaddr_in sa;
+
+ bzero((char *) &sa, sizeof(sa));
+ sa.sin_family = AF_INET;
+ sa.sin_addr.s_addr = INADDR_ANY;
+ sa.sin_port = htons(port);
+
+ if((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
+ pdie("socket");
+ if(bind(sock_fd, (struct sockaddr*)&sa, sizeof(sa)) == -1)
+ pdie("bind\n");
+ if(listen(sock_fd, 10) == -1)
+ pdie("bind\n");
+
+ printf("Listening on %d\n", port);
+ fflush(stdout);
+ if((fd = accept(sock_fd, (struct sockaddr*)NULL, NULL)) == -1)
+ pdie("accept");
+}
+
+void usage(FILE *o, char *arg0){
+ fprintf(o,
+ "Usage: %s [opts]\n"
+ "\n"
+ "Options\n"
+ "-p PORT Custom port number, default: 8123\n"
+ , arg0);
+}
+
+int main(int argc, char *argv[])
+{
+ int ct;
+
+ //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");
+ }
+
+ //Command line arguments
+ int opt;
+ while((opt = getopt(argc, argv, "hp:")) != -1){
+ switch(opt){
+ case 'p':
+ port = atoi(optarg);
+ if(port < 1)
+ die("Port numbers are > 1\n");
+ break;
+ case 'h':
+ usage(stdout, argv[0]);
+ exit(EXIT_SUCCESS);
+ default:
+ usage(stderr, argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ }
+
+ open_filedescriptors();
+
+ long cyclestart;
+ struct task *curtask;
+ while(true){
+ //Check for new tasks
+ if(input_available(fd))
+ read_message(fd, fd);
+ //Run tasks
+ cyclestart = millis();
+ for(ct = 0; ct<MAXTASKS; ct++){
+ //See whether the task is even in use
+ if((curtask = task_get(ct)) == NULL){
+ debug("Task %d not implemented\n", ct);
+ continue;
+ }
+ //See whether the task interval has passed
+ if(cyclestart-curtask->lastrun < curtask->interval){
+ debug("Task %d not scheduled\n", ct);
+ continue;
+ }
+#ifdef DEBUG
+ printf("Current task to run: %d\n", ct);
+ getchar();
+#endif
+ run_task(curtask);
+ }
+ usleep(10);
+ }
+ return 0;
+}
--- /dev/null
+#ifndef MISC_H
+#define MISC_H
+
+#define DEBUG
+
+#ifdef DEBUG
+#define debug(s, ...) printf(s, ##__VA_ARGS__);
+#define trace(op, ...) printf("pc: %d, sp: %d, op: " op, pc, sp, ##__VA_ARGS__);
+#else
+#define debug(s, ...) ;
+#define trace(pc, sp, op) ;
+#endif
+
+#define pdie(s) {perror(s); exit(1);}
+#define die(s, ...) {fprintf(stderr, s, ##__VA_ARGS__); exit(1);}
+
+#endif
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "mTaskSymbols.h"
+#include "interpret.h"
+#include "misc.h"
+#include "sds.h"
+
+struct sds sdss[MAXSDSS] = {0};
+uint8_t c;
+
+void sds_register(int fd)
+{
+ uint8_t cs;
+ for(cs = 0; cs<MAXSDSS; cs++)
+ if(!sdss[cs].used)
+ break;
+
+ if(cs == MAXSDSS)
+ die("Trying to add too much tasks...\n");
+
+ memset(&sdss[cs], 0, sizeof(struct sds));
+ //Read identifier
+ read(fd, &c, 1);
+ sdss[cs].id = c;
+
+ //Read value
+ read(fd, &c, 1);
+ sdss[cs].value = 255*c;
+ read(fd, &c, 1);
+ sdss[cs].value += c;
+
+ debug("Received sds %d: %d\n", sdss[cs].id, sdss[cs].value);
+ sdss[cs].used = true;
+}
+
+bool sds_update(int fd)
+{
+ uint8_t cs, id;
+ //Read identifier
+ read(fd, &id, 1);
+
+ for(cs = 0; cs<MAXSDSS; cs++){
+ if(!sdss[cs].used)
+ continue;
+ if(sdss[cs].id == id){
+ //Read value
+ read(fd, &c, 1);
+ sdss[cs].value = 255*c;
+ read(fd, &c, 1);
+ sdss[cs].value += c;
+ return true;
+ }
+ }
+ return false;
+}
--- /dev/null
+#ifndef SDS_H
+#define SDS_H
+
+#include <stdbool.h>
+
+#define MAXSDSS 100
+
+struct sds {
+ int id;
+ int value;
+ bool used;
+};
+
+void sds_register(int fd);
+bool sds_update(int fd);
+
+#endif
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "misc.h"
+#include "task.h"
+
+struct task tasks[MAXTASKS] = {0};
+uint8_t c;
+
+int task_register(int fd)
+{
+ uint8_t ct;
+
+ for(ct = 0; ct<MAXTASKS; ct++)
+ if(!tasks[ct].used)
+ break;
+ if(ct == MAXTASKS)
+ die("Trying to add too much tasks...\n");
+
+ memset(&tasks[ct], 0, sizeof(struct task));
+ //Read interval
+ read(fd, &c, 1);
+ tasks[ct].interval = 256*c;
+ read(fd, &c, 1);
+ tasks[ct].interval += c;
+ //Read tasklength
+ read(fd, &c, 1);
+ tasks[ct].tlen = 256*c;
+ read(fd, &c, 1);
+ tasks[ct].tlen += c;
+ if(tasks[ct].tlen > MAXTASKSIZE)
+ die("Task is too long: %d\n", tasks[ct].tlen);
+ //Read task bytecode
+ for(int i = 0; i<tasks[ct].tlen; i++){
+ debug("Read %d\n", i);
+ read(fd, tasks[ct].bc+i, 1);
+ debug("t[][%i]: %d\n", i,
+ tasks[ct].bc[i]);
+ }
+ //Return the task number for later removal
+ debug("Received a task of length %d\n", tasks[ct].tlen);
+ tasks[ct].used = true;
+ return ct;
+}
+
+void task_delete(int fd)
+{
+ read(fd, &c, 1);
+ tasks[c].used = false;
+}
+
+struct task *task_get(int num)
+{
+ return tasks[num].used ? &tasks[num] : NULL;
+}
--- /dev/null
+#ifndef TASK_H
+#define TASK_H
+
+#define MAXTASKS 5
+#define MAXTASKSIZE 1024
+
+#include <stdint.h>
+#include <stdbool.h>
+
+struct task {
+ uint8_t bc[MAXTASKSIZE];
+ uint16_t tlen;
+ uint16_t interval;
+ long lastrun;
+ bool used;
+};
+
+int task_register(int fd);
+void task_delete(int fd);
+struct task *task_get(int num);
+
+#endif