Dependents:   WeatherStation

Revision:
0:684b6fdf080c
Child:
1:f8c5afc27878
diff -r 000000000000 -r 684b6fdf080c ILinterpreter.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ILinterpreter.cpp	Sun Jun 26 12:02:32 2011 +0000
@@ -0,0 +1,420 @@
+/** @file
+ * @brief Instruction List interpreter
+ */
+
+#include "mbed.h"
+#include "ILinterpreter.h"
+
+#undef DEBUG
+
+struct MNE_str {
+    eMNEMONIC mne;
+    char str[5];
+};
+
+#define IL_MNE_NUM 22
+const struct MNE_str mne_str[IL_MNE_NUM] = {
+    {MNE_DEF, "DEF"},
+    {MNE_LD, "LD"}, {MNE_LDI, "LDI"}, {MNE_LDP, "LDP"}, {MNE_LDF, "LDF"},
+    {MNE_OR, "OR"}, {MNE_ORI, "ORI"}, {MNE_ORP, "ORP"}, {MNE_ORF, "ORF"},
+    {MNE_AND, "AND"}, {MNE_ANI, "ANI"}, {MNE_ANDP, "ANDP"}, {MNE_ANDF, "ANDF"},
+    {MNE_ORB, "ORB"}, {MNE_ANB, "ANB"}, {MNE_INV, "INV"},
+    {MNE_MPS, "MPS"}, {MNE_MRD, "MRD"}, {MNE_MPP, "MPP"},
+    {MNE_OUT, "OUT"}, {MNE_SET, "SET"}, {MNE_RST, "RST"},
+};
+
+struct EXP_str {
+    eEXPRESSION exp;
+    char str[3];
+};
+
+#define IL_EXP_NUM 10
+const struct EXP_str exp_str[IL_EXP_NUM] = {
+    {EXP_EQ, "=="}, {EXP_EQ, "="}, {EXP_NE, "!="}, {EXP_NE, "<>"},
+    {EXP_LT, "<="}, {EXP_LE, "<"}, {EXP_GT, ">"}, {EXP_GE, ">="},
+    {EXP_MOD, "%"}, {EXP_NMOD, "!%"},
+};
+
+
+ILinterpreter::ILinterpreter () : stack(IL_STACK) {
+    il_count = 0;
+    memset(&inout, 0, sizeof(inout));
+    inout.sec = time(NULL) + (60 * 60 * 9);
+    inout_old = inout;
+    cb_input = NULL;
+    cb_output = NULL;
+}
+
+// input relay, expression
+int ILinterpreter::input (tInOut *io, int i, int old) {
+    int keynum;
+    float value, check;
+    struct tm *tim;
+
+    tim = localtime(&io->sec);
+    keynum = il[i].keynum;
+    // right value
+    check = il[i].value;
+
+    // left value
+    value = 0;
+    switch (il[i].key) {
+
+    case 'y':
+        value = tim->tm_year + 1900;
+        break;
+    case 'm':
+        value = tim->tm_mon;
+        break;
+    case 'd':
+        value = tim->tm_mday;
+        break;
+    case 'h':
+        value = tim->tm_hour;
+        break;
+    case 'i':
+        value = tim->tm_min;
+        break;
+    case 's':
+        value = tim->tm_sec;
+        break;
+
+    case '0':
+        value = 0;
+        break;
+    case '1':
+        value = 1;
+        break;
+
+    case 'M': // RELAY
+        if (keynum >= IL_RELAY_NUM) break;
+        value = io->relay[keynum];
+        break;
+
+    case 'T': // Timer
+        if (keynum >= IL_TIMER_NUM) break;
+        if (il[i].expression == EXP_NULL) {
+            value = io->timer_flg[keynum] && io->timer_cnt[keynum] >= io->timer_set[keynum];
+        } else {
+            value = io->timer_cnt[keynum];
+        }
+        break;
+
+    case 'C': // Counter
+        if (keynum >= IL_COUNTER_NUM) break;
+        if (il[i].expression == EXP_NULL) {
+             value = io->count_cnt[keynum] >= io->count_set[keynum];
+        } else {
+             value = io->count_cnt[keynum];
+        }
+        break;
+
+    default: // order input
+        if (cb_input) {
+            value = (*cb_input)(il[i].key, keynum, il[i].expression, old);
+        }
+        break;
+    }
+
+    // expression
+    switch (il[i].expression) {
+    case EXP_EQ:
+        return value == check;
+    case EXP_NE:
+        return value != check;
+    case EXP_LE:
+        return value <= check;
+    case EXP_LT:
+        return value < check;
+    case EXP_GE:
+        return value >= check;
+    case EXP_GT:
+        return value > check;
+    case EXP_MOD:
+        return (int)value % (int)check;
+    case EXP_NMOD:
+        return ! ((int)value % (int)check);
+    }
+
+    return value != 0;
+}
+
+// output relay
+void ILinterpreter::output (int i, int reg, eMNEMONIC mne) {
+    int keynum;
+
+    keynum = il[i].keynum;
+#ifdef DEBUG
+    printf("output [%c%d] reg=%d sr=%d\r\n", il[i].key, keynum, reg, mne);
+#endif
+
+    switch (il[i].key) {
+    case 'M': // relay
+        if (keynum >= IL_RELAY_NUM) break;
+        if (mne == MNE_OUT) {
+            inout.relay[keynum] = reg;
+        } else
+        if (mne == MNE_SET && reg) {
+            inout.relay[keynum] = 1;
+        } else
+        if (mne == MNE_RST && reg) {
+            inout.relay[keynum] = 0;
+        }
+        break;
+
+    case 'T': // Timer
+        if (keynum >= IL_TIMER_NUM) break;
+        if (mne == MNE_OUT) {
+            if (! inout.timer_flg[keynum]) {
+                // set timer
+                inout.timer_cnt[keynum] = 0;
+            }
+            inout.timer_flg[keynum] = reg;
+        } else
+        if (mne == MNE_RST && reg) {
+            inout.timer_cnt[keynum] = 0;
+        }
+        break;
+
+    case 'C': // Counter
+        if (keynum >= IL_COUNTER_NUM) break;
+        if (mne == MNE_OUT && reg) {
+            if (inout.count_rev[keynum]) {
+                inout.count_cnt[keynum] --;
+            } else {
+                inout.count_cnt[keynum] ++;
+            }
+        } else
+        if (mne == MNE_RST && reg) {
+            inout.count_cnt[keynum] = 0;
+        }
+    case 'R': // Counter (reverse)
+        if (keynum >= IL_COUNTER_NUM) break;
+        if (mne == MNE_OUT) {
+            inout.count_rev[keynum] = reg;
+        }
+        break;
+
+    default: // order output
+        if (cb_output) {
+            (*cb_output)(il[i].key, keynum, reg, mne);
+        }
+        break;
+    }
+}
+
+// execute IL
+int ILinterpreter::exec () {
+    int i, j, reg = -1;
+    tInOut inout_tmp;
+
+    if (! il_count) return 0;
+
+    stack.clear();
+    inout.sec = time(NULL);
+    inout_tmp = inout;
+
+    // mnemonic decode
+    for(i = 0; i < il_count; i ++) {
+        switch (il[i].mnemonic) {
+        case MNE_LD:
+            stack.push(reg);
+            reg = input(&inout, i);
+            break;
+        case MNE_LDI:
+            stack.push(reg);
+            reg = ! input(&inout, i);
+            break;
+        case MNE_LDP:
+            stack.push(reg);
+            reg = input(&inout, i) && ! input(&inout_old, i, 1);
+            break;
+        case MNE_LDF:
+            stack.push(reg);
+            reg = ! input(&inout, i) && input(&inout_old, i, 1);
+            break;
+
+        case MNE_AND:
+            reg = reg && input(&inout, i);
+            break;
+        case MNE_ANI:
+            reg = reg && ! input(&inout, i);
+            break;
+        case MNE_ANDP:
+            reg = reg && (input(&inout, i) && ! input(&inout_old, i), 1);
+            break;
+        case MNE_ANDF:
+            reg = reg && (! input(&inout, i) && input(&inout_old, i), 1);
+            break;
+
+        case MNE_OR:
+            reg = reg || input(&inout, i);
+            break;
+        case MNE_ORI:
+            reg = reg || ! input(&inout, i);
+            break;
+        case MNE_ORP:
+            reg = reg || (input(&inout, i) && ! input(&inout_old, i), 1);
+            break;
+        case MNE_ORF:
+            reg = reg || (! input(&inout, i) && input(&inout_old, i), 1);
+            break;
+
+        case MNE_ANB:
+            if (stack.pop(&j) || j == -1) return -1;
+            reg = reg && j;
+            break;
+        case MNE_ORB:
+            if (stack.pop(&j) || j == -1) return -1;
+            reg = reg || j;
+            break;
+
+        case MNE_INV:
+            reg = ! reg;
+            break;
+
+        case MNE_MPS:
+            if (stack.push(reg)) return -1;
+            break;
+        case MNE_MRD:
+            if (stack.read(&reg) || reg == -1) return -1;
+            break;
+        case MNE_MPP:
+            if (stack.pop(&reg) || reg == -1) return -1;
+            break;
+
+        case MNE_OUT:
+        case MNE_SET:
+        case MNE_RST:
+            output(i, reg, il[i].mnemonic);
+            break;
+        }
+    }
+
+    inout_old = inout_tmp;
+
+#ifdef DEBUG
+    printf("timer0=%d(%d) timer1=%d(%d)\r\n", inout.timer_cnt[0], inout.timer_set[0], inout.timer_cnt[1], inout.timer_set[1]);
+#endif
+    return 0;
+}
+
+// set callback function
+void ILinterpreter::attach (struct tInOut **io, float (*pf_i)(char, int, eEXPRESSION, int), void (*pf_o)(char, int, int, eMNEMONIC)) {
+    cb_input = pf_i;
+    cb_output = pf_o;
+    *io = &inout;
+}
+
+// timer 10Hz
+void ILinterpreter::pool () {
+    int i;
+
+    if (! il_count) return;
+
+    // timer
+    for (i = 0; i < IL_TIMER_NUM; i ++) {
+        if (inout.timer_flg[i] && inout.timer_cnt[i] < inout.timer_set[i]) {
+            inout.timer_cnt[i] ++;
+        }
+    }
+}
+
+// load sub
+void ILinterpreter::load_exp (int i, char *buf) {
+    int j, len;
+    char *tmp;
+
+    // MNEMONIC "KEY""num"==value
+    il[i].key = buf[0];
+    il[i].keynum = strtol(&buf[1], &tmp, 10);
+    il[i].expression = EXP_NULL;
+    il[i].value = 0;
+
+    if (tmp) {
+        // expression
+        for (j = 0; j < IL_EXP_NUM; j ++) {
+            len = strlen(exp_str[j].str);
+            if (strncmp(tmp, exp_str[j].str, len) == 0 && tmp[len] >= '0' && tmp[len] <= '9') {
+                // MNEMONIC KEYnum"==""value"
+                il[i].expression = exp_str[j].exp;
+                il[i].value = atof(&tmp[len]);
+                break;
+            }
+        }
+    }
+}
+
+// load IL file
+int ILinterpreter::load (char *file) {
+    FILE *fp;
+    char c;
+    int i, j, len;
+    char buf[20];
+
+    il_count = 0;
+
+    fp = fopen(file, "r");
+    if (fp == NULL) return -1;
+
+    i = 0;
+    for (;;) {
+        if (il_count >= IL_NUM) break;
+        c = fgetc(fp);
+        if (feof(fp)) break;
+
+        if (c != '\r' && c != '\n' && i < 40 - 1) {
+            // load
+            buf[i] = c;
+            i ++;
+            continue;
+        }
+        buf[i] = 0;
+        
+        if (i == 0 || buf[0] == '#' || buf[0] == ';') {
+            // comment
+            i = 0;
+            continue;
+        }
+
+        // mnemonic
+        for (j = 0; j < IL_MNE_NUM; j ++) {
+            len = strlen(mne_str[j].str);
+            if (strncmp(buf, mne_str[j].str, len) == 0 && (buf[len] == ' ' || buf[len] == 0)) {
+                // "MNEMONIC" KEYnum==value
+                il[il_count].mnemonic = mne_str[j].mne;
+                load_exp(il_count, &buf[len + 1]);
+                il_count ++;
+                break;
+            }
+        }
+        if (strncmp(buf, "END", 3) == 0) break;
+        if (j == IL_MNE_NUM) return -1;
+
+        i = 0;
+    }
+
+    // init
+    for (i = 0; i < il_count; i ++) {
+      if (il[i].mnemonic == MNE_DEF) {
+        switch (il[i].key) {
+        case 't': // Timer
+            inout.timer_set[il[i].keynum] = (int)il[i].value * 10;
+            break;
+
+        case 'c': // Counter
+            inout.count_set[il[i].keynum] = (int)il[i].value;
+            break;
+        }
+      }
+    }
+
+    fclose(fp);
+
+#ifdef DEBUG
+    for (i = 0; i < il_count; i ++) {
+        printf("M=%d [%c%d] E=%d V=%f\r\n", il[i].mnemonic, il[i].key, il[i].keynum, il[i].expression, il[i].value);
+    }
+#endif
+    return 0;
+}