Created
April 12, 2021 19:52
-
-
Save CurlyMoo/0ba1bceb26913266ba5c6c8df6c349f1 to your computer and use it in GitHub Desktop.
Rules library implementation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Flash ide size: 4194304 bytes | |
//Flash ide speed: 40000000 Hz | |
//Flash ide mode: DIO | |
//Flash Chip configuration ok. | |
#include <FS.h> | |
#include <stdlib.h> | |
#include <sys/time.h> | |
#include <time.h> | |
#include <Arduino.h> | |
#include <EasyNTPClient.h> | |
#include <WiFiUdp.h> | |
#include <ESP8266WiFi.h> | |
#include <PubSubClient.h> | |
#include <LittleFS.h> | |
#include "mem.h" | |
#include "rules.h" | |
#include "commands.h" | |
#include "decode.h" | |
#include "timerqueue.h" | |
typedef struct vm_gvchar_t { | |
VM_GENERIC_FIELDS | |
uint8_t rule; | |
char value[]; | |
} __attribute__((packed)) vm_gvchar_t; | |
typedef struct vm_gvnull_t { | |
VM_GENERIC_FIELDS | |
uint8_t rule; | |
} __attribute__((packed)) vm_gvnull_t; | |
typedef struct vm_gvinteger_t { | |
VM_GENERIC_FIELDS | |
uint8_t rule; | |
int value; | |
} __attribute__((packed)) vm_gvinteger_t; | |
typedef struct vm_gvfloat_t { | |
VM_GENERIC_FIELDS | |
uint8_t rule; | |
float value; | |
} __attribute__((packed)) vm_gvfloat_t; | |
struct timerqueue_t **timerqueue = NULL; | |
struct timerqueue_t timerqueue_prev; | |
int timerqueue_size = 0; | |
struct tm lt; | |
struct tm st; | |
unsigned long nexttime = 0; | |
const char *ssid = "xxxx"; | |
const char *password = "xxxx"; | |
const char *mqttServer = "x.x.x.x"; | |
const int mqttPort = 1883; | |
WiFiClient espClient; | |
PubSubClient mqtt_client(espClient); | |
WiFiUDP ntpUDP; | |
EasyNTPClient ntpClient(ntpUDP, "pool.ntp.org", 7200); // + 2 hours due to DST | |
static struct rules_t **rules = NULL; | |
static int nrrules = 0; | |
static char out[512]; | |
char hp_values[NUMBER_OF_TOPICS][255]; | |
typedef struct varstack_t { | |
unsigned char *stack; | |
unsigned int nrbytes; | |
unsigned int bufsize; | |
} varstack_t; | |
static struct varstack_t global_varstack; | |
static struct vm_vinteger_t vinteger; | |
static struct vm_vfloat_t vfloat; | |
static struct vm_vnull_t vnull; | |
struct rule_options_t rule_options; | |
static void vm_global_value_prt(char *out, int size); | |
static int strnicmp(char const *a, char const *b, size_t len) { | |
int i = 0; | |
if(a == NULL || b == NULL) { | |
return -1; | |
} | |
if(len == 0) { | |
return 0; | |
} | |
for(;i++<len; a++, b++) { | |
int d = tolower(*a) - tolower(*b); | |
if(d != 0 || !*a || i == len) { | |
return d; | |
} | |
} | |
return -1; | |
} | |
static int stricmp(char const *a, char const *b) { | |
int i = 0; | |
if(a == NULL || b == NULL) { | |
return -1; | |
} | |
for(;a; a++, b++) { | |
int d = tolower(*a) - tolower(*b); | |
if(d != 0 || !*a) { | |
return d; | |
} | |
} | |
return -1; | |
} | |
static int get_event(struct rules_t *obj) { | |
struct vm_tstart_t *start = (struct vm_tstart_t *)&obj->ast.buffer[0]; | |
if(obj->ast.buffer[start->go] != TEVENT) { | |
return -1; | |
} else { | |
return start->go; | |
} | |
} | |
static int is_variable(char *text, int *pos, int size) { | |
int i = 1, x = 0, match = 0; | |
if(text[*pos] == '$' || text[*pos] == '#' || text[*pos] == '@' || text[*pos] == '%') { | |
while(isalnum(text[*pos+i])) { | |
i++; | |
} | |
if(text[*pos] == '%') { | |
if(strnicmp(&text[(*pos)+1], "hour", 4) == 0) { | |
return 5; | |
} | |
} | |
if(text[*pos] == '@') { | |
int nrcommands = sizeof(commands)/sizeof(commands[0]); | |
for(x=0;x<nrcommands;x++) { | |
if(strnicmp(&text[(*pos)+1], commands[x].name, strlen(commands[x].name)) == 0) { | |
i = strlen(commands[x].name)+1; | |
match = 1; | |
break; | |
} | |
} | |
for(x=0;x<NUMBER_OF_TOPICS;x++) { | |
if(strnicmp(&text[(*pos)+1], topics[x], strlen(topics[x])) == 0) { | |
i = strlen(topics[x])+1; | |
match = 1; | |
break; | |
} | |
} | |
if(match == 0) { | |
return -1; | |
} | |
} | |
return i; | |
} | |
return -1; | |
} | |
static int is_event(char *text, int *pos, int size) { | |
int i = 1, x = 0, match = 0; | |
if(text[*pos] == '@') { | |
int nrcommands = sizeof(commands)/sizeof(commands[0]); | |
for(x=0;x<nrcommands;x++) { | |
if(strnicmp(&text[(*pos)+1], commands[x].name, strlen(commands[x].name)) == 0) { | |
i = strlen(commands[x].name)+1; | |
match = 1; | |
break; | |
} | |
} | |
for(x=0;x<NUMBER_OF_TOPICS;x++) { | |
if(strnicmp(&text[(*pos)+1], topics[x], strlen(topics[x])) == 0) { | |
i = strlen(topics[x])+1; | |
match = 1; | |
break; | |
} | |
} | |
if(match == 0) { | |
return -1; | |
} | |
return i; | |
} | |
// for(x=0;x<nrrules;x++) { | |
// for(i=0;i<rules[x]->nrbytes;i++) { | |
// if(rules[x]->ast.buffer[0] == TEVENT) { | |
// if(strnicmp(&text[(*pos)], (char *)&rules[x]->ast.buffer[1], strlen((char *)&rules[x]->ast.buffer[1])) == 0) { | |
// return strlen((char *)&rules[x]->ast.buffer[1]); | |
// } | |
// } | |
// break; | |
// } | |
// } | |
// return -1; | |
return size; | |
} | |
static int event_cb(struct rules_t *obj, char *name) { | |
struct rules_t *called = NULL; | |
int i = 0, x = 0; | |
if(obj->caller > 0 && name == NULL) { | |
called = rules[obj->caller-1]; | |
obj->caller = 0; | |
// sprintf((char *)&out, "...1 %p NULL", obj); | |
// Serial.println(out); | |
return rule_run(called, 0); | |
} else { | |
for(x=0;x<nrrules;x++) { | |
if(get_event(rules[x]) > -1) { | |
if(strnicmp(name, (char *)&rules[x]->ast.buffer[get_event(rules[x])+5], strlen((char *)&rules[x]->ast.buffer[get_event(rules[x])+5])) == 0) { | |
called = rules[x]; | |
break; | |
} | |
} | |
if(called != NULL) { | |
break; | |
} | |
} | |
// sprintf((char *)&out, "...2 %p %s %p", obj, name, called); | |
// Serial.println(out); | |
if(called != NULL) { | |
called->caller = obj->nr; | |
return rule_run(called, 0); | |
} else { | |
return rule_run(obj, 0); | |
} | |
} | |
} | |
static void vm_value_clr(struct rules_t *obj, uint16_t token) { | |
struct varstack_t *varstack = (struct varstack_t *)obj->userdata; | |
struct vm_tvar_t *var = (struct vm_tvar_t *)&obj->ast.buffer[token]; | |
if(var->token[1] == '$') { | |
var->value = 0; | |
} | |
} | |
static void vm_value_cpy(struct rules_t *obj, uint16_t token) { | |
struct varstack_t *varstack = (struct varstack_t *)obj->userdata; | |
struct vm_tvar_t *var = (struct vm_tvar_t *)&obj->ast.buffer[token]; | |
int x = 0; | |
if(var->token[0] == '$') { | |
varstack = (struct varstack_t *)obj->userdata; | |
for(x=4;alignedbytes(x)<varstack->nrbytes;x++) { | |
x = alignedbytes(x); | |
switch(varstack->stack[x]) { | |
case VINTEGER: { | |
struct vm_vinteger_t *val = (struct vm_vinteger_t *)&varstack->stack[x]; | |
struct vm_tvar_t *foo = (struct vm_tvar_t *)&obj->ast.buffer[val->ret]; | |
if(strcmp((char *)foo->token, (char *)&var->token) == 0 && val->ret != token) { | |
var->value = foo->value; | |
val->ret = token; | |
foo->value = 0; | |
return; | |
} | |
x += sizeof(struct vm_vinteger_t)-1; | |
} break; | |
case VFLOAT: { | |
struct vm_vfloat_t *val = (struct vm_vfloat_t *)&varstack->stack[x]; | |
struct vm_tvar_t *foo = (struct vm_tvar_t *)&obj->ast.buffer[val->ret]; | |
if(strcmp((char *)foo->token, (char *)var->token) == 0 && val->ret != token) { | |
var->value = foo->value; | |
val->ret = token; | |
foo->value = 0; | |
return; | |
} | |
x += sizeof(struct vm_vfloat_t)-1; | |
} break; | |
case VNULL: { | |
struct vm_vnull_t *val = (struct vm_vnull_t *)&varstack->stack[x]; | |
struct vm_tvar_t *foo = (struct vm_tvar_t *)&obj->ast.buffer[val->ret]; | |
if(strcmp((char *)foo->token, (char *)&var->token) == 0 && val->ret != token) { | |
var->value = foo->value; | |
val->ret = token; | |
foo->value = 0; | |
return; | |
} | |
x += sizeof(struct vm_vnull_t)-1; | |
} break; | |
default: { | |
return; | |
} break; | |
} | |
} | |
} else if(var->token[0] == '#') { | |
varstack = &global_varstack; | |
for(x=4;alignedbytes(x)<varstack->nrbytes;x++) { | |
x = alignedbytes(x); | |
switch(varstack->stack[x]) { | |
case VINTEGER: { | |
struct vm_gvinteger_t *val = (struct vm_gvinteger_t *)&varstack->stack[x]; | |
struct vm_tvar_t *foo = (struct vm_tvar_t *)&rules[val->rule-1]->ast.buffer[val->ret]; | |
if(strcmp((char *)foo->token, (char *)var->token) == 0 && val->ret != token) { | |
var->value = x; | |
val->ret = token; | |
val->rule = obj->nr; | |
return; | |
} | |
x += sizeof(struct vm_gvinteger_t)-1; | |
} break; | |
case VFLOAT: { | |
struct vm_gvfloat_t *val = (struct vm_gvfloat_t *)&varstack->stack[x]; | |
struct vm_tvar_t *foo = (struct vm_tvar_t *)&rules[val->rule-1]->ast.buffer[val->ret]; | |
if(strcmp((char *)foo->token, (char *)var->token) == 0 && val->ret != token) { | |
var->value = x; | |
val->ret = token; | |
val->rule = obj->nr; | |
return; | |
} | |
x += sizeof(struct vm_gvfloat_t)-1; | |
} break; | |
case VNULL: { | |
struct vm_gvnull_t *val = (struct vm_gvnull_t *)&varstack->stack[x]; | |
struct vm_tvar_t *foo = (struct vm_tvar_t *)&rules[val->rule-1]->ast.buffer[val->ret]; | |
if(strcmp((char *)foo->token, (char *)var->token) == 0 && val->ret != token) { | |
var->value = x; | |
val->ret = token; | |
val->rule = obj->nr; | |
return; | |
} | |
x += sizeof(struct vm_gvnull_t)-1; | |
} break; | |
default: { | |
return; | |
} break; | |
} | |
} | |
} | |
} | |
static unsigned char *vm_value_get(struct rules_t *obj, uint16_t token) { | |
struct vm_tvar_t *node = (struct vm_tvar_t *)&obj->ast.buffer[token]; | |
int i = 0; | |
if(node->token[0] == '$') { | |
struct varstack_t *varstack = (struct varstack_t *)obj->userdata; | |
if(node->value == 0) { | |
int ret = varstack->nrbytes, suffix = 0; | |
// sprintf((char *)&out, ".. %s %d %d", __FUNCTION__, __LINE__, ret); | |
// Serial.println(out); | |
unsigned int size = alignedbytes(varstack->nrbytes + sizeof(struct vm_vnull_t)); | |
if((varstack->stack = (unsigned char *)REALLOC(varstack->stack, alignedbuffer(size))) == NULL) { | |
OUT_OF_MEMORY /*LCOV_EXCL_LINE*/ | |
} | |
struct vm_vnull_t *value = (struct vm_vnull_t *)&varstack->stack[ret]; | |
value->type = VNULL; | |
value->ret = token; | |
node->value = ret; | |
varstack->nrbytes = size; | |
varstack->bufsize = alignedbuffer(size); | |
} | |
const char *key = (char *)node->token; | |
switch(varstack->stack[node->value]) { | |
case VINTEGER: { | |
struct vm_vinteger_t *na = (struct vm_vinteger_t *)&varstack->stack[node->value]; | |
// sprintf((char *)&out, ".. %s %d %s = %d", __FUNCTION__, node->value, key, (int)na->value); | |
// Serial.println(out); | |
} break; | |
case VFLOAT: { | |
struct vm_vfloat_t *na = (struct vm_vfloat_t *)&varstack->stack[node->value]; | |
// sprintf((char *)&out, ".. %s %d %s = %g", __FUNCTION__, node->value, key, na->value); | |
// Serial.println(out); | |
} break; | |
case VNULL: { | |
struct vm_vnull_t *na = (struct vm_vnull_t *)&varstack->stack[node->value]; | |
// sprintf((char *)&out, ".. %s %d %s = NULL", __FUNCTION__, node->value, key); | |
// Serial.println(out); | |
} break; | |
case VCHAR: { | |
struct vm_vchar_t *na = (struct vm_vchar_t *)&varstack->stack[node->value]; | |
// sprintf((char *)&out, ".. %s %d %s = %s", __FUNCTION__, node->value, key, na->value); | |
// Serial.println(out); | |
} break; | |
} | |
return &varstack->stack[node->value]; | |
} | |
if(node->token[0] == '#') { | |
struct varstack_t *varstack = &global_varstack; | |
if(node->value == 0) { | |
int ret = varstack->nrbytes, suffix = 0; | |
// sprintf((char *)&out, ".. %s %d %d", __FUNCTION__, __LINE__, ret); | |
// Serial.println(out); | |
unsigned int size = alignedbytes(varstack->nrbytes + sizeof(struct vm_gvnull_t)); | |
if((varstack->stack = (unsigned char *)REALLOC(varstack->stack, alignedbuffer(size))) == NULL) { | |
OUT_OF_MEMORY /*LCOV_EXCL_LINE*/ | |
} | |
struct vm_gvnull_t *value = (struct vm_gvnull_t *)&varstack->stack[ret]; | |
value->type = VNULL; | |
value->ret = token; | |
value->rule = obj->nr; | |
node->value = ret; | |
varstack->nrbytes = size; | |
varstack->bufsize = alignedbuffer(size); | |
} | |
const char *key = (char *)node->token; | |
switch(varstack->stack[node->value]) { | |
case VINTEGER: { | |
struct vm_gvinteger_t *na = (struct vm_gvinteger_t *)&varstack->stack[node->value]; | |
memset(&vinteger, 0, sizeof(struct vm_vinteger_t)); | |
vinteger.type = VINTEGER; | |
vinteger.value = (int)na->value; | |
// sprintf((char *)&out, ".. %s %d %s = %d", __FUNCTION__, node->value, key, (int)na->value); | |
// Serial.println(out); | |
return (unsigned char *)&vinteger; | |
} break; | |
case VFLOAT: { | |
struct vm_gvfloat_t *na = (struct vm_gvfloat_t *)&varstack->stack[node->value]; | |
memset(&vfloat, 0, sizeof(struct vm_vfloat_t)); | |
vfloat.type = VFLOAT; | |
vfloat.value = na->value; | |
// sprintf((char *)&out, ".. %s %d %s = %g", __FUNCTION__, node->value, key, na->value); | |
// Serial.println(out); | |
return (unsigned char *)&vfloat; | |
} break; | |
case VNULL: { | |
struct vm_gvnull_t *na = (struct vm_gvnull_t *)&varstack->stack[node->value]; | |
memset(&vnull, 0, sizeof(struct vm_vnull_t)); | |
vnull.type = VNULL; | |
// sprintf((char *)&out, ".. %s %d %s = NULL", __FUNCTION__, node->value, key); | |
// Serial.println(out); | |
return (unsigned char *)&vnull; | |
} break; | |
case VCHAR: { | |
Serial.println("a"); | |
exit(-1); | |
} break; | |
} | |
Serial.println("b"); | |
exit(-1); | |
} | |
if(node->token[0] == '@') { | |
for(i=0;i<NUMBER_OF_TOPICS;i++) { | |
if(stricmp(topics[i], (char *)&node->token[1]) == 0) { | |
float var = atof(hp_values[i]); | |
float nr = 0; | |
// mosquitto_publish | |
if(modff(var, &nr) == 0) { | |
memset(&vinteger, 0, sizeof(struct vm_vinteger_t)); | |
vinteger.type = VINTEGER; | |
vinteger.value = (int)var; | |
// sprintf((char *)&out, "%s %s = %d", __FUNCTION__, (char *)node->token, (int)var); | |
// Serial.println(out); | |
return (unsigned char *)&vinteger; | |
} else { | |
memset(&vfloat, 0, sizeof(struct vm_vfloat_t)); | |
vfloat.type = VFLOAT; | |
vfloat.value = var; | |
// sprintf((char *)&out, "%s %s = %g", __FUNCTION__, (char *)node->token, var); | |
// Serial.println(out); | |
return (unsigned char *)&vfloat; | |
} | |
} | |
} | |
} | |
if(node->token[0] == '%') { | |
if(stricmp((char *)&node->token[1], "hour") == 0) { | |
memset(&vinteger, 0, sizeof(struct vm_vinteger_t)); | |
vinteger.type = VINTEGER; | |
vinteger.value = (int)lt.tm_hour; | |
// sprintf((char *)&out, "%s %s = %d", __FUNCTION__, (char *)node->token, (int)lt.tm_hour); | |
// Serial.println(out); | |
return (unsigned char *)&vinteger; | |
} | |
} | |
return NULL; | |
} | |
static int vm_value_del(struct rules_t *obj, uint16_t idx) { | |
struct varstack_t *varstack = (struct varstack_t *)obj->userdata; | |
int x = 0, ret = 0; | |
if(idx == varstack->nrbytes) { | |
return -1; | |
} | |
switch(varstack->stack[idx]) { | |
case VINTEGER: { | |
ret = alignedbytes(sizeof(struct vm_vinteger_t)); | |
memmove(&varstack->stack[idx], &varstack->stack[idx+ret], varstack->nrbytes-idx-ret); | |
if((varstack->stack = (unsigned char *)REALLOC(varstack->stack, alignedbuffer(varstack->nrbytes-ret))) == NULL) { | |
OUT_OF_MEMORY /*LCOV_EXCL_LINE*/ | |
} | |
varstack->nrbytes -= ret; | |
varstack->bufsize = alignedbuffer(varstack->nrbytes); | |
} break; | |
case VFLOAT: { | |
ret = alignedbytes(sizeof(struct vm_vfloat_t)); | |
memmove(&varstack->stack[idx], &varstack->stack[idx+ret], varstack->nrbytes-idx-ret); | |
if((varstack->stack = (unsigned char *)REALLOC(varstack->stack,alignedbuffer(varstack->nrbytes-ret))) == NULL) { | |
OUT_OF_MEMORY /*LCOV_EXCL_LINE*/ | |
} | |
varstack->nrbytes -= ret; | |
varstack->bufsize = alignedbuffer(varstack->nrbytes); | |
} break; | |
case VNULL: { | |
ret = alignedbytes(sizeof(struct vm_vnull_t)); | |
memmove(&varstack->stack[idx], &varstack->stack[idx+ret], varstack->nrbytes-idx-ret); | |
if((varstack->stack = (unsigned char *)REALLOC(varstack->stack, alignedbuffer(varstack->nrbytes-ret))) == NULL) { | |
OUT_OF_MEMORY /*LCOV_EXCL_LINE*/ | |
} | |
varstack->nrbytes -= ret; | |
varstack->bufsize = alignedbuffer(varstack->nrbytes); | |
} break; | |
default: { | |
return -1; | |
} break; | |
} | |
/* | |
* Values are linked back to their root node, | |
* by their absolute position in the bytecode. | |
* If a value is deleted, these positions changes, | |
* so we need to update all nodes. | |
*/ | |
for(x=idx;alignedbytes(x)<varstack->nrbytes;x++) { | |
x = alignedbytes(x); | |
switch(varstack->stack[x]) { | |
case VINTEGER: { | |
struct vm_vinteger_t *node = (struct vm_vinteger_t *)&varstack->stack[x]; | |
if(node->ret > 0) { | |
struct vm_tvar_t *tmp = (struct vm_tvar_t *)&obj->ast.buffer[node->ret]; | |
tmp->value = x; | |
} | |
x += sizeof(struct vm_vinteger_t)-1; | |
} break; | |
case VFLOAT: { | |
struct vm_vfloat_t *node = (struct vm_vfloat_t *)&varstack->stack[x]; | |
if(node->ret > 0) { | |
struct vm_tvar_t *tmp = (struct vm_tvar_t *)&obj->ast.buffer[node->ret]; | |
tmp->value = x; | |
} | |
x += sizeof(struct vm_vfloat_t)-1; | |
} break; | |
default: { | |
return -1; | |
} break; | |
} | |
} | |
return ret; | |
} | |
static void vm_value_set(struct rules_t *obj, uint16_t token, uint16_t val) { | |
struct varstack_t *varstack = NULL; | |
struct vm_tvar_t *var = (struct vm_tvar_t *)&obj->ast.buffer[token]; | |
int ret = 0, x = 0, loop = 1; | |
if(var->token[0] == '$') { | |
varstack = (struct varstack_t *)obj->userdata; | |
const char *key = (char *)var->token; | |
switch(obj->varstack.buffer[val]) { | |
case VINTEGER: { | |
struct vm_vinteger_t *na = (struct vm_vinteger_t *)&obj->varstack.buffer[val]; | |
// sprintf((char *)&out, ".. %s %d %s = %d", __FUNCTION__, val, key, (int)na->value); | |
// Serial.println(out); | |
} break; | |
case VFLOAT: { | |
struct vm_vfloat_t *na = (struct vm_vfloat_t *)&obj->varstack.buffer[val]; | |
// sprintf((char *)&out, ".. %s %d %s = %g", __FUNCTION__, val, key, na->value); | |
// Serial.println(out); | |
} break; | |
case VNULL: { | |
struct vm_vnull_t *na = (struct vm_vnull_t *)&obj->varstack.buffer[val]; | |
// sprintf((char *)&out, ".. %s %d %s = NULL", __FUNCTION__, val, key); | |
// Serial.println(out); | |
} break; | |
case VCHAR: { | |
struct vm_vchar_t *na = (struct vm_vchar_t *)&obj->varstack.buffer[val]; | |
// sprintf((char *)&out, ".. %s %d %s = %s", __FUNCTION__, val, key, na->value); | |
// Serial.println(out); | |
} break; | |
} | |
/* | |
* Remove previous value linked to | |
* the variable being set. | |
*/ | |
for(x=4;alignedbytes(x)<varstack->nrbytes && loop == 1;x++) { | |
x = alignedbytes(x); | |
switch(varstack->stack[x]) { | |
case VINTEGER: { | |
struct vm_vinteger_t *node = (struct vm_vinteger_t *)&varstack->stack[x]; | |
struct vm_tvar_t *tmp = (struct vm_tvar_t *)&obj->ast.buffer[node->ret]; | |
if(strcmp((char *)var->token, (char *)tmp->token) == 0) { | |
var->value = 0; | |
vm_value_del(obj, x); | |
loop = 0; | |
break; | |
} | |
x += sizeof(struct vm_vinteger_t)-1; | |
} break; | |
case VFLOAT: { | |
struct vm_vfloat_t *node = (struct vm_vfloat_t *)&varstack->stack[x]; | |
struct vm_tvar_t *tmp = (struct vm_tvar_t *)&obj->ast.buffer[node->ret]; | |
if(strcmp((char *)var->token, (char *)tmp->token) == 0) { | |
var->value = 0; | |
vm_value_del(obj, x); | |
loop = 0; | |
break; | |
} | |
x += sizeof(struct vm_vfloat_t)-1; | |
} break; | |
case VNULL: { | |
struct vm_vnull_t *node = (struct vm_vnull_t *)&varstack->stack[x]; | |
struct vm_tvar_t *tmp = (struct vm_tvar_t *)&obj->ast.buffer[node->ret]; | |
if(strcmp((char *)var->token, (char *)tmp->token) == 0) { | |
var->value = 0; | |
vm_value_del(obj, x); | |
loop = 0; | |
break; | |
} | |
x += sizeof(struct vm_vnull_t)-1; | |
} break; | |
default: { | |
return; | |
} break; | |
} | |
} | |
var = (struct vm_tvar_t *)&obj->ast.buffer[token]; | |
if(var->value > 0) { | |
vm_value_del(obj, var->value); | |
} | |
var = (struct vm_tvar_t *)&obj->ast.buffer[token]; | |
ret = varstack->nrbytes; | |
var->value = ret; | |
switch(obj->varstack.buffer[val]) { | |
case VINTEGER: { | |
unsigned int size = alignedbytes(varstack->nrbytes+sizeof(struct vm_vinteger_t)); | |
if((varstack->stack = (unsigned char *)REALLOC(varstack->stack, alignedbuffer(size))) == NULL) { | |
OUT_OF_MEMORY /*LCOV_EXCL_LINE*/ | |
} | |
struct vm_vinteger_t *cpy = (struct vm_vinteger_t *)&obj->varstack.buffer[val]; | |
struct vm_vinteger_t *value = (struct vm_vinteger_t *)&varstack->stack[ret]; | |
value->type = VINTEGER; | |
value->ret = token; | |
value->value = (int)cpy->value; | |
varstack->nrbytes = size; | |
varstack->bufsize = alignedbuffer(size); | |
} break; | |
case VFLOAT: { | |
unsigned int size = alignedbytes(varstack->nrbytes+sizeof(struct vm_vfloat_t)); | |
if((varstack->stack = (unsigned char *)REALLOC(varstack->stack, alignedbuffer(size))) == NULL) { | |
OUT_OF_MEMORY /*LCOV_EXCL_LINE*/ | |
} | |
struct vm_vfloat_t *cpy = (struct vm_vfloat_t *)&obj->varstack.buffer[val]; | |
struct vm_vfloat_t *value = (struct vm_vfloat_t *)&varstack->stack[ret]; | |
value->type = VFLOAT; | |
value->ret = token; | |
value->value = cpy->value; | |
varstack->nrbytes = size; | |
varstack->bufsize = alignedbuffer(size); | |
} break; | |
case VNULL: { | |
unsigned int size = alignedbytes(varstack->nrbytes+sizeof(struct vm_vnull_t)); | |
if((varstack->stack = (unsigned char *)REALLOC(varstack->stack, alignedbuffer(size))) == NULL) { | |
OUT_OF_MEMORY /*LCOV_EXCL_LINE*/ | |
} | |
struct vm_vnull_t *value = (struct vm_vnull_t *)&varstack->stack[ret]; | |
value->type = VNULL; | |
value->ret = token; | |
varstack->nrbytes = size; | |
varstack->bufsize = alignedbuffer(size); | |
} break; | |
default: { | |
return; | |
} break; | |
} | |
} else if(var->token[0] == '#') { | |
varstack = &global_varstack; | |
const char *key = (char *)var->token; | |
switch(obj->varstack.buffer[val]) { | |
case VINTEGER: { | |
struct vm_vinteger_t *na = (struct vm_vinteger_t *)&obj->varstack.buffer[val]; | |
// sprintf((char *)&out, ".. %s %d %d %s = %d", __FUNCTION__, __LINE__, val, key, (int)na->value); | |
// Serial.println(out); | |
} break; | |
case VFLOAT: { | |
struct vm_vfloat_t *na = (struct vm_vfloat_t *)&obj->varstack.buffer[val]; | |
// sprintf((char *)&out, ".. %s %d %d %s = %g", __FUNCTION__, __LINE__, val, key, na->value); | |
// Serial.println(out); | |
} break; | |
case VCHAR: { | |
struct vm_vchar_t *na = (struct vm_vchar_t *)&obj->varstack.buffer[val]; | |
// sprintf((char *)&out, ".. %s %d %d %s = %s", __FUNCTION__, __LINE__, val, key, na->value); | |
// Serial.println(out); | |
} break; | |
case VNULL: { | |
struct vm_vnull_t *na = (struct vm_vnull_t *)&obj->varstack.buffer[val]; | |
// sprintf((char *)&out, ".. %s %d %d %s = NULL", __FUNCTION__, __LINE__, val, key); | |
// Serial.println(out); | |
} break; | |
} | |
var = (struct vm_tvar_t *)&obj->ast.buffer[token]; | |
int move = 0; | |
for(x=4;alignedbytes(x)<varstack->nrbytes;x++) { | |
x = alignedbytes(x); | |
switch(varstack->stack[x]) { | |
case VINTEGER: { | |
struct vm_gvinteger_t *val = (struct vm_gvinteger_t *)&varstack->stack[x]; | |
struct vm_tvar_t *foo = (struct vm_tvar_t *)&rules[val->rule-1]->ast.buffer[val->ret]; | |
// sprintf((char *)&out, ".. %s %d %d %d %d %s = %d", __FUNCTION__, __LINE__, x, val->ret, val->rule, foo->token, val->value); | |
// Serial.println(out); | |
if(strcmp((char *)foo->token, (char *)var->token) == 0) { | |
move = 1; | |
ret = alignedbytes(sizeof(struct vm_gvinteger_t)); | |
memmove(&varstack->stack[x], &varstack->stack[x+ret], varstack->nrbytes-x-ret); | |
if((varstack->stack = (unsigned char *)REALLOC(varstack->stack, alignedbuffer(varstack->nrbytes-ret))) == NULL) { | |
OUT_OF_MEMORY /*LCOV_EXCL_LINE*/ | |
} | |
varstack->nrbytes -= ret; | |
varstack->bufsize = alignedbuffer(varstack->nrbytes); | |
} | |
} break; | |
case VFLOAT: { | |
struct vm_gvfloat_t *val = (struct vm_gvfloat_t *)&varstack->stack[x]; | |
struct vm_tvar_t *foo = (struct vm_tvar_t *)&rules[val->rule-1]->ast.buffer[val->ret]; | |
// sprintf((char *)&out, ".. %s %d %d %d %d %s = %g", __FUNCTION__, __LINE__, x, val->ret, val->rule, foo->token, val->value); | |
// Serial.println(out); | |
if(strcmp((char *)foo->token, (char *)var->token) == 0) { | |
move = 1; | |
ret = alignedbytes(sizeof(struct vm_gvfloat_t)); | |
memmove(&varstack->stack[x], &varstack->stack[x+ret], varstack->nrbytes-x-ret); | |
if((varstack->stack = (unsigned char *)REALLOC(varstack->stack, alignedbuffer(varstack->nrbytes-ret))) == NULL) { | |
OUT_OF_MEMORY /*LCOV_EXCL_LINE*/ | |
} | |
varstack->nrbytes -= ret; | |
varstack->bufsize = alignedbuffer(varstack->nrbytes); | |
} | |
} break; | |
case VNULL: { | |
struct vm_gvnull_t *val = (struct vm_gvnull_t *)&varstack->stack[x]; | |
struct vm_tvar_t *foo = (struct vm_tvar_t *)&rules[val->rule-1]->ast.buffer[val->ret]; | |
// sprintf((char *)&out, ".. %s %d %d %d %d %s = NULL", __FUNCTION__, __LINE__, x, val->ret, val->rule, foo->token); | |
// Serial.println(out); | |
if(strcmp((char *)foo->token, (char *)var->token) == 0) { | |
move = 1; | |
ret = alignedbytes(sizeof(struct vm_gvnull_t)); | |
memmove(&varstack->stack[x], &varstack->stack[x+ret], varstack->nrbytes-x-ret); | |
if((varstack->stack = (unsigned char *)REALLOC(varstack->stack, alignedbuffer(varstack->nrbytes-ret))) == NULL) { | |
OUT_OF_MEMORY /*LCOV_EXCL_LINE*/ | |
} | |
varstack->nrbytes -= ret; | |
varstack->bufsize = alignedbuffer(varstack->nrbytes); | |
} | |
} break; | |
default: { | |
return; | |
} break; | |
} | |
if(x == varstack->nrbytes) { | |
break; | |
} | |
switch(varstack->stack[x]) { | |
case VINTEGER: { | |
if(move == 1 && x < varstack->nrbytes) { | |
struct vm_gvinteger_t *node = (struct vm_gvinteger_t *)&varstack->stack[x]; | |
if(node->ret > 0) { | |
struct vm_tvar_t *tmp = (struct vm_tvar_t *)&rules[node->rule-1]->ast.buffer[node->ret]; | |
tmp->value = x; | |
} | |
} | |
x += sizeof(struct vm_gvinteger_t)-1; | |
} break; | |
case VFLOAT: { | |
if(move == 1 && x < varstack->nrbytes) { | |
struct vm_gvfloat_t *node = (struct vm_gvfloat_t *)&varstack->stack[x]; | |
if(node->ret > 0) { | |
struct vm_tvar_t *tmp = (struct vm_tvar_t *)&rules[node->rule-1]->ast.buffer[node->ret]; | |
tmp->value = x; | |
} | |
} | |
x += sizeof(struct vm_gvfloat_t)-1; | |
} break; | |
case VNULL: { | |
if(move == 1 && x < varstack->nrbytes) { | |
struct vm_gvnull_t *node = (struct vm_gvnull_t *)&varstack->stack[x]; | |
if(node->ret > 0) { | |
struct vm_tvar_t *tmp = (struct vm_tvar_t *)&rules[node->rule-1]->ast.buffer[node->ret]; | |
tmp->value = x; | |
} | |
} | |
x += sizeof(struct vm_gvnull_t)-1; | |
} break; | |
} | |
} | |
var = (struct vm_tvar_t *)&obj->ast.buffer[token]; | |
ret = varstack->nrbytes; | |
var->value = ret; | |
switch(obj->varstack.buffer[val]) { | |
case VINTEGER: { | |
unsigned int size = alignedbytes(varstack->nrbytes + sizeof(struct vm_gvinteger_t)); | |
if((varstack->stack = (unsigned char *)REALLOC(varstack->stack, alignedbuffer(size))) == NULL) { | |
OUT_OF_MEMORY /*LCOV_EXCL_LINE*/ | |
} | |
struct vm_vinteger_t *cpy = (struct vm_vinteger_t *)&obj->varstack.buffer[val]; | |
struct vm_gvinteger_t *value = (struct vm_gvinteger_t *)&varstack->stack[ret]; | |
value->type = VINTEGER; | |
value->ret = token; | |
value->value = (int)cpy->value; | |
value->rule = obj->nr; | |
// sprintf((char *)&out, ".. %s %d %d %d %d %s = %d", __FUNCTION__, __LINE__, ret, token, obj->nr, var->token, cpy->value); | |
// Serial.println(out); | |
varstack->nrbytes = size; | |
varstack->bufsize = alignedbuffer(size); | |
} break; | |
case VFLOAT: { | |
unsigned int size = alignedbytes(varstack->nrbytes + sizeof(struct vm_gvfloat_t)); | |
if((varstack->stack = (unsigned char *)REALLOC(varstack->stack, alignedbuffer(size))) == NULL) { | |
OUT_OF_MEMORY /*LCOV_EXCL_LINE*/ | |
} | |
struct vm_vfloat_t *cpy = (struct vm_vfloat_t *)&obj->varstack.buffer[val]; | |
struct vm_gvfloat_t *value = (struct vm_gvfloat_t *)&varstack->stack[ret]; | |
value->type = VFLOAT; | |
value->ret = token; | |
value->value = cpy->value; | |
value->rule = obj->nr; | |
// sprintf((char *)&out, ".. %s %d %d %d %d %s = %g", __FUNCTION__, __LINE__, ret, token, obj->nr, var->token, cpy->value); | |
// Serial.println(out); | |
varstack->nrbytes = size; | |
varstack->bufsize = alignedbuffer(size); | |
} break; | |
case VNULL: { | |
unsigned int size = alignedbytes(varstack->nrbytes + sizeof(struct vm_gvnull_t)); | |
if((varstack->stack = (unsigned char *)REALLOC(varstack->stack, alignedbuffer(size))) == NULL) { | |
OUT_OF_MEMORY /*LCOV_EXCL_LINE*/ | |
} | |
struct vm_gvnull_t *value = (struct vm_gvnull_t *)&varstack->stack[ret]; | |
value->type = VNULL; | |
value->ret = token; | |
value->rule = obj->nr; | |
// sprintf((char *)&out, ".. %s %d %d %d %d %s = NULL", __FUNCTION__, __LINE__, ret, token, obj->nr, var->token); | |
// Serial.println(out); | |
varstack->nrbytes = size; | |
varstack->bufsize = alignedbuffer(size); | |
} break; | |
default: { | |
return; | |
} break; | |
} | |
} else if(var->token[0] == '@') { | |
char *topic = NULL, *payload = NULL; | |
const char *key = (char *)var->token; | |
int len = 0; | |
switch(obj->varstack.buffer[val]) { | |
case VINTEGER: { | |
struct vm_vinteger_t *na = (struct vm_vinteger_t *)&obj->varstack.buffer[val]; | |
// sprintf((char *)&out, "%s %d %s = %d", __FUNCTION__, val, key, (int)na->value); | |
// Serial.println(out); | |
len = snprintf(NULL, 0, "%d", (int)na->value); | |
if((payload = (char *)MALLOC(len+1)) == NULL) { | |
OUT_OF_MEMORY | |
} | |
snprintf(payload, len+1, "%d", (int)na->value); | |
} break; | |
case VFLOAT: { | |
struct vm_vfloat_t *na = (struct vm_vfloat_t *)&obj->varstack.buffer[val]; | |
// sprintf((char *)&out, "%s %d %s = %g", __FUNCTION__, val, key, na->value); | |
// Serial.println(out); | |
len = snprintf(NULL, 0, "%g", (float)na->value); | |
if((payload = (char *)MALLOC(len+1)) == NULL) { | |
OUT_OF_MEMORY | |
} | |
snprintf(payload, len+1, "%g", (float)na->value); | |
} break; | |
case VCHAR: { | |
struct vm_vchar_t *na = (struct vm_vchar_t *)&obj->varstack.buffer[val]; | |
// sprintf((char *)&out, "%s %d %s = %s", __FUNCTION__, val, key, na->value); | |
// Serial.println(out); | |
len = snprintf(NULL, 0, "%s", na->value); | |
if((payload = (char *)MALLOC(len+1)) == NULL) { | |
OUT_OF_MEMORY | |
} | |
snprintf(payload, len+1, "%s", na->value); | |
} break; | |
} | |
len = snprintf(NULL, 0, "panasonic_heat_pump/commands/%s", &var->token[1]); | |
if((topic = (char *)MALLOC(len+1)) == NULL) { | |
OUT_OF_MEMORY | |
} | |
snprintf(topic, len+1, "panasonic_heat_pump/commands/%s", &var->token[1]); | |
// mosquitto_publish(mosq, NULL, topic, strlen(payload), payload, 0, 0); | |
FREE(topic); | |
FREE(payload); | |
} | |
} | |
static void vm_value_prt(struct rules_t *obj, char *out, int size) { | |
struct varstack_t *varstack = (struct varstack_t *)obj->userdata; | |
int x = 0, pos = 0; | |
for(x=4;alignedbytes(x)<varstack->nrbytes;x++) { | |
if(alignedbytes(x) < varstack->nrbytes) { | |
x = alignedbytes(x); | |
switch(varstack->stack[x]) { | |
case VINTEGER: { | |
struct vm_vinteger_t *val = (struct vm_vinteger_t *)&varstack->stack[x]; | |
switch(obj->ast.buffer[val->ret]) { | |
case TVAR: { | |
struct vm_tvar_t *node = (struct vm_tvar_t *)&obj->ast.buffer[val->ret]; | |
pos += snprintf(&out[pos], size - pos, "%s = %d\n", node->token, val->value); | |
} break; | |
default: { | |
// printf("err: %s %d %d\n", __FUNCTION__, __LINE__, obj->ast.buffer[val->ret]); | |
// exit(-1); | |
} break; | |
} | |
x += sizeof(struct vm_vinteger_t)-1; | |
} break; | |
case VFLOAT: { | |
struct vm_vfloat_t *val = (struct vm_vfloat_t *)&varstack->stack[x]; | |
switch(obj->ast.buffer[val->ret]) { | |
case TVAR: { | |
struct vm_tvar_t *node = (struct vm_tvar_t *)&obj->ast.buffer[val->ret]; | |
pos += snprintf(&out[pos], size - pos, "%s = %g\n", node->token, val->value); | |
} break; | |
default: { | |
// printf("err: %s %d\n", __FUNCTION__, __LINE__); | |
// exit(-1); | |
} break; | |
} | |
x += sizeof(struct vm_vfloat_t)-1; | |
} break; | |
case VNULL: { | |
struct vm_vnull_t *val = (struct vm_vnull_t *)&varstack->stack[x]; | |
switch(obj->ast.buffer[val->ret]) { | |
case TVAR: { | |
struct vm_tvar_t *node = (struct vm_tvar_t *)&obj->ast.buffer[val->ret]; | |
pos += snprintf(&out[pos], size - pos, "%s = NULL\n", node->token); | |
} break; | |
default: { | |
// printf("err: %s %d\n", __FUNCTION__, __LINE__); | |
// exit(-1); | |
} break; | |
} | |
x += sizeof(struct vm_vnull_t)-1; | |
} break; | |
default: { | |
return; | |
} break; | |
} | |
} | |
} | |
} | |
static void vm_global_value_prt(char *out, int size) { | |
struct varstack_t *varstack = &global_varstack; | |
int x = 0, pos = 0; | |
for(x=4;alignedbytes(x)<varstack->nrbytes;x++) { | |
x = alignedbytes(x); | |
switch(varstack->stack[x]) { | |
case VINTEGER: { | |
struct vm_gvinteger_t *val = (struct vm_gvinteger_t *)&varstack->stack[x]; | |
switch(rules[val->rule-1]->ast.buffer[val->ret]) { | |
case TVAR: { | |
struct vm_tvar_t *node = (struct vm_tvar_t *)&rules[val->rule-1]->ast.buffer[val->ret]; | |
pos += snprintf(&out[pos], size - pos, "%d %s = %d\n", x, node->token, val->value); | |
} break; | |
default: { | |
// printf("err: %s %d %d\n", __FUNCTION__, __LINE__, obj->ast.buffer[val->ret]); | |
// exit(-1); | |
} break; | |
} | |
x += sizeof(struct vm_gvinteger_t)-1; | |
} break; | |
case VFLOAT: { | |
struct vm_gvfloat_t *val = (struct vm_gvfloat_t *)&varstack->stack[x]; | |
switch(rules[val->rule-1]->ast.buffer[val->ret]) { | |
case TVAR: { | |
struct vm_tvar_t *node = (struct vm_tvar_t *)&rules[val->rule-1]->ast.buffer[val->ret]; | |
pos += snprintf(&out[pos], size - pos, "%d %s = %g\n", x, node->token, val->value); | |
} break; | |
default: { | |
// printf("err: %s %d\n", __FUNCTION__, __LINE__); | |
// exit(-1); | |
} break; | |
} | |
x += sizeof(struct vm_gvfloat_t)-1; | |
} break; | |
case VNULL: { | |
struct vm_gvnull_t *val = (struct vm_gvnull_t *)&varstack->stack[x]; | |
switch(rules[val->rule-1]->ast.buffer[val->ret]) { | |
case TVAR: { | |
struct vm_tvar_t *node = (struct vm_tvar_t *)&rules[val->rule-1]->ast.buffer[val->ret]; | |
pos += snprintf(&out[pos], size - pos, "%d %s = NULL\n", x, node->token); | |
} break; | |
default: { | |
// printf("err: %s %d\n", __FUNCTION__, __LINE__); | |
// exit(-1); | |
} break; | |
} | |
x += sizeof(struct vm_gvnull_t)-1; | |
} break; | |
default: { | |
return; | |
} break; | |
} | |
} | |
} | |
void vm_clear_values(struct rules_t *obj) { | |
int i = 0, x = 0; | |
for(i=x;alignedbytes(i)<obj->ast.nrbytes;i++) { | |
i = alignedbytes(i); | |
switch(obj->ast.buffer[i]) { | |
case TSTART: { | |
i+=sizeof(struct vm_tstart_t)-1; | |
} break; | |
case TEOF: { | |
i+=sizeof(struct vm_teof_t)-1; | |
} break; | |
case VNULL: { | |
i+=sizeof(struct vm_vnull_t)-1; | |
} break; | |
case TIF: { | |
i+=sizeof(struct vm_tif_t)-1; | |
} break; | |
case LPAREN: { | |
struct vm_lparen_t *node = (struct vm_lparen_t *)&obj->ast.buffer[i]; | |
node->value = 0; | |
i+=sizeof(struct vm_lparen_t)-1; | |
} break; | |
case TFALSE: | |
case TTRUE: { | |
struct vm_ttrue_t *node = (struct vm_ttrue_t *)&obj->ast.buffer[i]; | |
i+=sizeof(struct vm_ttrue_t)+(sizeof(node->go[0])*node->nrgo)-1; | |
} break; | |
case TFUNCTION: { | |
struct vm_tfunction_t *node = (struct vm_tfunction_t *)&obj->ast.buffer[i]; | |
node->value = 0; | |
i+=sizeof(struct vm_tfunction_t)+(sizeof(node->go[0])*node->nrgo)-1; | |
} break; | |
case TCEVENT: { | |
struct vm_tcevent_t *node = (struct vm_tcevent_t *)&obj->ast.buffer[i]; | |
i+=sizeof(struct vm_tcevent_t)+strlen((char *)node->token); | |
} break; | |
case TVAR: { | |
struct vm_tvar_t *node = (struct vm_tvar_t *)&obj->ast.buffer[i]; | |
node->value = 0; | |
i+=sizeof(struct vm_tvar_t)+strlen((char *)node->token); | |
} break; | |
case TEVENT: { | |
struct vm_tevent_t *node = (struct vm_tevent_t *)&obj->ast.buffer[i]; | |
i += sizeof(struct vm_tevent_t)+strlen((char *)node->token); | |
} break; | |
case TNUMBER: { | |
struct vm_tnumber_t *node = (struct vm_tnumber_t *)&obj->ast.buffer[i]; | |
i+=sizeof(struct vm_tnumber_t)+strlen((char *)node->token); | |
} break; | |
case VINTEGER: { | |
struct vm_vinteger_t *node = (struct vm_vinteger_t *)&obj->ast.buffer[i]; | |
i+=sizeof(struct vm_vinteger_t)-1; | |
} break; | |
case VFLOAT: { | |
struct vm_vfloat_t *node = (struct vm_vfloat_t *)&obj->ast.buffer[i]; | |
i+=sizeof(struct vm_vfloat_t)-1; | |
} break; | |
case TOPERATOR: { | |
struct vm_toperator_t *node = (struct vm_toperator_t *)&obj->ast.buffer[i]; | |
node->value = 0; | |
i+=sizeof(struct vm_toperator_t)-1; | |
} break; | |
default: { | |
} break; | |
} | |
} | |
} | |
void mqtt_callback(char *topic, byte *payload, unsigned int length) { | |
int i = 0, offset = strlen("panasonic_heat_pump/main"); | |
/* | |
* This value has been overridden so ignore. | |
*/ | |
if(strstr(topic, "panasonic_heat_pump/main/Room_Thermostat_Temp") != NULL) { | |
return; | |
} | |
if(strstr(topic, "woonkamer/temperature/temperature") != NULL) { | |
topic = "panasonic_heat_pump/main/Room_Thermostat_Temp"; | |
} | |
for(i=0;i<NUMBER_OF_TOPICS;i++) { | |
if(strstr(topic, "panasonic_heat_pump/main") != NULL) { | |
if(strcmp(topics[i], &topic[offset+1]) == 0 && length < 255) { | |
memcpy(hp_values[i], (char *)payload, length); | |
hp_values[i][length] = 0; | |
} | |
} | |
} | |
if(( | |
strstr(topic, "panasonic_heat_pump/main") != NULL || | |
strstr(topic, "woonkamer/temperature/temperature") != NULL | |
) | |
) { | |
for(i=0;i<nrrules;i++) { | |
if(get_event(rules[i]) > -1 && rules[i]->ast.buffer[get_event(rules[i])+5] == '@' && | |
strnicmp((char *)&rules[i]->ast.buffer[get_event(rules[i])+6], (char *)&topic[offset+1], strlen(&topic[offset+1])) == 0) { | |
sprintf((char *)&out, "\n\n==== %s ====\n", (char *)&rules[i]->ast.buffer[get_event(rules[i])+6]); | |
Serial.println(out); | |
sprintf((char *)&out, ">>> rule %d nrbytes: %d", i, rules[i]->ast.nrbytes); | |
Serial.println(out); | |
sprintf((char *)&out, ">>> global stack nrbytes: %d", global_varstack.nrbytes); | |
Serial.println(out); | |
rules[i]->timestamp.first = micros(); | |
rule_run(rules[i], 0); | |
rules[i]->timestamp.second = micros(); | |
sprintf((char *)&out, "rule #%d was executed in %d microseconds", rules[i]->nr, rules[i]->timestamp.second - rules[i]->timestamp.first); | |
Serial.println(out); | |
Serial.println("\n>>> local variables"); | |
vm_value_prt(rules[i], (char *)&out, 512); | |
Serial.println(out); | |
Serial.println(">>> global variables"); | |
vm_global_value_prt((char *)&out, 512); | |
Serial.println(out); | |
} | |
} | |
int x = 0; | |
for(i=0;i<nrrules;i++) { | |
x += rules[i]->ast.nrbytes; | |
} | |
sprintf((char *)&out, ">>> total rule bytes: %d", x+global_varstack.nrbytes); | |
Serial.println(out); | |
} | |
} | |
void setup() { | |
memset(&hp_values, 0, 255*NUMBER_OF_TOPICS); | |
int tmp = ESP.getFreeHeap(); | |
Serial.begin(115200); | |
Serial.print("Start: "); | |
Serial.println(tmp, DEC); | |
Serial.print("Serial: "); | |
Serial.println(ESP.getFreeHeap(), DEC); | |
WiFi.begin(ssid, password); | |
while(WiFi.status() != WL_CONNECTED) { | |
delay(500); | |
Serial.println("Connecting to WiFi.."); | |
} | |
Serial.println("Connected to the WiFi network"); | |
Serial.print("WiFI: "); | |
Serial.println(ESP.getFreeHeap(), DEC); | |
time_t t = ntpClient.getUnixTime(); | |
memset(<, 0, sizeof(struct tm)); | |
memset(&st, 0, sizeof(struct tm)); | |
localtime_r(&t, <); | |
localtime_r(&t, &st); | |
mqtt_client.setServer(mqttServer, mqttPort); | |
mqtt_client.setCallback(mqtt_callback); | |
while(!mqtt_client.connected()) { | |
Serial.println("Connecting to MQTT..."); | |
if(mqtt_client.connect("ESPHeishaDaemon", NULL, NULL)) { | |
Serial.println("connected"); | |
} else { | |
Serial.print("failed with state "); | |
Serial.print(mqtt_client.state()); | |
delay(2000); | |
} | |
} | |
Serial.print("MQTT: "); | |
Serial.println(ESP.getFreeHeap(), DEC); | |
LittleFS.begin(); | |
if(LittleFS.exists("/rules.txt")) { | |
Serial.println("Reading rules"); | |
File frules = LittleFS.open("/rules.txt", "r"); | |
int len = frules.size(); | |
char *content = (char *)malloc(len+1); | |
memset(content, 0, len+1); | |
frules.readBytes(content, len); | |
Serial.print("Rules read: "); | |
Serial.println(ESP.getFreeHeap(), DEC); | |
global_varstack.stack = NULL; | |
global_varstack.nrbytes = 4; | |
memset(&rule_options, 0, sizeof(struct rule_options_t)); | |
rule_options.is_token_cb = is_variable; | |
rule_options.is_event_cb = is_event; | |
rule_options.set_token_val_cb = vm_value_set; | |
rule_options.get_token_val_cb = vm_value_get; | |
rule_options.prt_token_val_cb = vm_value_prt; | |
rule_options.cpy_token_val_cb = vm_value_cpy; | |
rule_options.clr_token_val_cb = vm_value_clr; | |
rule_options.event_cb = event_cb; | |
struct varstack_t *varstack = (struct varstack_t *)MALLOC(sizeof(struct varstack_t)); | |
if(varstack == NULL) { | |
OUT_OF_MEMORY | |
} | |
varstack->stack = NULL; | |
varstack->nrbytes = 4; | |
varstack->bufsize = 4; | |
Serial.print("Varstack: "); | |
Serial.println(ESP.getFreeHeap(), DEC); | |
while(rule_initialize(&content, &rules, &nrrules, varstack) == 0) { | |
Serial.print("Rules read: "); | |
Serial.println(ESP.getFreeHeap(), DEC); | |
varstack = (struct varstack_t *)MALLOC(sizeof(struct varstack_t)); | |
if(varstack == NULL) { | |
OUT_OF_MEMORY | |
} | |
varstack->stack = NULL; | |
varstack->nrbytes = 4; | |
varstack->bufsize = 4; | |
} | |
FREE(varstack); | |
FREE(content); | |
int i = 0; | |
for(i=0;i<nrrules;i++) { | |
vm_clear_values(rules[i]); | |
} | |
FREE(global_varstack.stack); | |
global_varstack.stack = NULL; | |
global_varstack.nrbytes = 4; | |
/* | |
* Clear all timers | |
*/ | |
// struct itimerval it_val; | |
struct timerqueue_t *node = NULL; | |
while((node = timerqueue_pop()) != NULL) { | |
FREE(node); | |
} | |
// it_val.it_value.tv_sec = 0; | |
// it_val.it_value.tv_usec = 0; | |
// it_val.it_interval = it_val.it_value; | |
// setitimer(ITIMER_REAL, &it_val, NULL); | |
frules.close(); | |
free(content); | |
} | |
Serial.println("done"); | |
for(int i=0;i<nrrules;i++) { | |
if(get_event(rules[i]) > -1 && strcmp((char *)&rules[i]->ast.buffer[get_event(rules[i])+5], "System#Boot") == 0) { | |
sprintf((char *)&out, "\n\n==== SYSTEM#BOOT ====\n"); | |
rule_run(rules[i], 0); | |
} | |
} | |
mqtt_client.subscribe("panasonic_heat_pump/main/#"); | |
mqtt_client.subscribe("woonkamer/temperature/temperature"); | |
} | |
void loop() { | |
if (millis() > nexttime) { | |
time_t t = ntpClient.getUnixTime(); | |
memset(<, 0, sizeof(struct tm)); | |
localtime_r(&t, <); | |
Serial.println(asctime(&st)); | |
nexttime = millis() + 1000; | |
} | |
mqtt_client.loop(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment