mirror of https://github.com/arendst/Tasmota.git
Berry improvements
This commit is contained in:
parent
f91ca66a69
commit
b613e1db37
|
@ -1,128 +1,111 @@
|
|||
extern const bcstring be_const_str_calldepth;
|
||||
extern const bcstring be_const_str_clock;
|
||||
extern const bcstring be_const_str_size;
|
||||
extern const bcstring be_const_str_system;
|
||||
extern const bcstring be_const_str_type;
|
||||
extern const bcstring be_const_str_if;
|
||||
extern const bcstring be_const_str_int;
|
||||
extern const bcstring be_const_str_isfile;
|
||||
extern const bcstring be_const_str_log;
|
||||
extern const bcstring be_const_str_raise;
|
||||
extern const bcstring be_const_str_concat;
|
||||
extern const bcstring be_const_str_list;
|
||||
extern const bcstring be_const_str_map;
|
||||
extern const bcstring be_const_str_for;
|
||||
extern const bcstring be_const_str_dot_p;
|
||||
extern const bcstring be_const_str_isdir;
|
||||
extern const bcstring be_const_str_mkdir;
|
||||
extern const bcstring be_const_str_remove;
|
||||
extern const bcstring be_const_str_cosh;
|
||||
extern const bcstring be_const_str_abs;
|
||||
extern const bcstring be_const_str_reverse;
|
||||
extern const bcstring be_const_str_sinh;
|
||||
extern const bcstring be_const_str_hex;
|
||||
extern const bcstring be_const_str_tostring;
|
||||
extern const bcstring be_const_str_opt_add;
|
||||
extern const bcstring be_const_str_atan;
|
||||
extern const bcstring be_const_str_real;
|
||||
extern const bcstring be_const_str_iter;
|
||||
extern const bcstring be_const_str_top;
|
||||
extern const bcstring be_const_str_except;
|
||||
extern const bcstring be_const_str_getcwd;
|
||||
extern const bcstring be_const_str_listdir;
|
||||
extern const bcstring be_const_str_log10;
|
||||
extern const bcstring be_const_str_allocated;
|
||||
extern const bcstring be_const_str_init;
|
||||
extern const bcstring be_const_str_module;
|
||||
extern const bcstring be_const_str_ceil;
|
||||
extern const bcstring be_const_str_clear;
|
||||
extern const bcstring be_const_str_collect;
|
||||
extern const bcstring be_const_str_find;
|
||||
extern const bcstring be_const_str_item;
|
||||
extern const bcstring be_const_str_format;
|
||||
extern const bcstring be_const_str_sqrt;
|
||||
extern const bcstring be_const_str_classname;
|
||||
extern const bcstring be_const_str_byte;
|
||||
extern const bcstring be_const_str_else;
|
||||
extern const bcstring be_const_str_deinit;
|
||||
extern const bcstring be_const_str_end;
|
||||
extern const bcstring be_const_str_true;
|
||||
extern const bcstring be_const_str___upper__;
|
||||
extern const bcstring be_const_str_char;
|
||||
extern const bcstring be_const_str_load;
|
||||
extern const bcstring be_const_str_resize;
|
||||
extern const bcstring be_const_str_sethook;
|
||||
extern const bcstring be_const_str_varname;
|
||||
extern const bcstring be_const_str_deg;
|
||||
extern const bcstring be_const_str_srand;
|
||||
extern const bcstring be_const_str_str;
|
||||
extern const bcstring be_const_str_range;
|
||||
extern const bcstring be_const_str_toupper;
|
||||
extern const bcstring be_const_str_;
|
||||
extern const bcstring be_const_str_copy;
|
||||
extern const bcstring be_const_str_exp;
|
||||
extern const bcstring be_const_str_time;
|
||||
extern const bcstring be_const_str_break;
|
||||
extern const bcstring be_const_str_opt_neq;
|
||||
extern const bcstring be_const_str_assert;
|
||||
extern const bcstring be_const_str_attrdump;
|
||||
extern const bcstring be_const_str_chdir;
|
||||
extern const bcstring be_const_str_isinstance;
|
||||
extern const bcstring be_const_str_continue;
|
||||
extern const bcstring be_const_str_do;
|
||||
extern const bcstring be_const_str_lower;
|
||||
extern const bcstring be_const_str_pow;
|
||||
extern const bcstring be_const_str_false;
|
||||
extern const bcstring be_const_str_count;
|
||||
extern const bcstring be_const_str_exit;
|
||||
extern const bcstring be_const_str_print;
|
||||
extern const bcstring be_const_str_def;
|
||||
extern const bcstring be_const_str_pop;
|
||||
extern const bcstring be_const_str_tolower;
|
||||
extern const bcstring be_const_str_classof;
|
||||
extern const bcstring be_const_str_cos;
|
||||
extern const bcstring be_const_str_dump;
|
||||
extern const bcstring be_const_str_join;
|
||||
extern const bcstring be_const_str_push;
|
||||
extern const bcstring be_const_str_sin;
|
||||
extern const bcstring be_const_str_return;
|
||||
extern const bcstring be_const_str_path;
|
||||
extern const bcstring be_const_str_rand;
|
||||
extern const bcstring be_const_str_class;
|
||||
extern const bcstring be_const_str_nil;
|
||||
extern const bcstring be_const_str_input;
|
||||
extern const bcstring be_const_str_floor;
|
||||
extern const bcstring be_const_str_keys;
|
||||
extern const bcstring be_const_str_number;
|
||||
extern const bcstring be_const_str_rad;
|
||||
extern const bcstring be_const_str_imin;
|
||||
extern const bcstring be_const_str_pi;
|
||||
extern const bcstring be_const_str_splitext;
|
||||
extern const bcstring be_const_str_compile;
|
||||
extern const bcstring be_const_str_setrange;
|
||||
extern const bcstring be_const_str_traceback;
|
||||
extern const bcstring be_const_str_upper;
|
||||
extern const bcstring be_const_str_var;
|
||||
extern const bcstring be_const_str_opt_eq;
|
||||
extern const bcstring be_const_str_codedump;
|
||||
extern const bcstring be_const_str_tan;
|
||||
extern const bcstring be_const_str_setitem;
|
||||
extern const bcstring be_const_str_tanh;
|
||||
extern const bcstring be_const_str_as;
|
||||
extern const bcstring be_const_str_issubclass;
|
||||
extern const bcstring be_const_str_upvname;
|
||||
extern const bcstring be_const_str_opt_connect;
|
||||
extern const bcstring be_const_str_try;
|
||||
extern const bcstring be_const_str_while;
|
||||
extern const bcstring be_const_str_import;
|
||||
extern const bcstring be_const_str___lower__;
|
||||
extern const bcstring be_const_str_open;
|
||||
extern const bcstring be_const_str_acos;
|
||||
extern const bcstring be_const_str_asin;
|
||||
extern const bcstring be_const_str_imax;
|
||||
extern const bcstring be_const_str_insert;
|
||||
extern const bcstring be_const_str_split;
|
||||
extern const bcstring be_const_str___iterator__;
|
||||
extern const bcstring be_const_str_exists;
|
||||
extern const bcstring be_const_str_super;
|
||||
extern const bcstring be_const_str_list;
|
||||
extern const bcstring be_const_str_module;
|
||||
extern const bcstring be_const_str_pop;
|
||||
extern const bcstring be_const_str_int;
|
||||
extern const bcstring be_const_str_push;
|
||||
extern const bcstring be_const_str_setrange;
|
||||
extern const bcstring be_const_str_sinh;
|
||||
extern const bcstring be_const_str_elif;
|
||||
extern const bcstring be_const_str_iter;
|
||||
extern const bcstring be_const_str_load;
|
||||
extern const bcstring be_const_str_class;
|
||||
extern const bcstring be_const_str_if;
|
||||
extern const bcstring be_const_str_opt_eq;
|
||||
extern const bcstring be_const_str_ceil;
|
||||
extern const bcstring be_const_str_floor;
|
||||
extern const bcstring be_const_str_map;
|
||||
extern const bcstring be_const_str_print;
|
||||
extern const bcstring be_const_str_else;
|
||||
extern const bcstring be_const_str_find;
|
||||
extern const bcstring be_const_str_str;
|
||||
extern const bcstring be_const_str___upper__;
|
||||
extern const bcstring be_const_str_dump;
|
||||
extern const bcstring be_const_str_atan;
|
||||
extern const bcstring be_const_str_size;
|
||||
extern const bcstring be_const_str_tolower;
|
||||
extern const bcstring be_const_str_opt_add;
|
||||
extern const bcstring be_const_str_abs;
|
||||
extern const bcstring be_const_str_lower;
|
||||
extern const bcstring be_const_str_end;
|
||||
extern const bcstring be_const_str_import;
|
||||
extern const bcstring be_const_str_classof;
|
||||
extern const bcstring be_const_str_concat;
|
||||
extern const bcstring be_const_str_byte;
|
||||
extern const bcstring be_const_str_top;
|
||||
extern const bcstring be_const_str_clear;
|
||||
extern const bcstring be_const_str_opt_connect;
|
||||
extern const bcstring be_const_str_collect;
|
||||
extern const bcstring be_const_str_init;
|
||||
extern const bcstring be_const_str_log10;
|
||||
extern const bcstring be_const_str_nil;
|
||||
extern const bcstring be_const_str_;
|
||||
extern const bcstring be_const_str_real;
|
||||
extern const bcstring be_const_str_calldepth;
|
||||
extern const bcstring be_const_str_format;
|
||||
extern const bcstring be_const_str_pi;
|
||||
extern const bcstring be_const_str_do;
|
||||
extern const bcstring be_const_str___iterator__;
|
||||
extern const bcstring be_const_str_number;
|
||||
extern const bcstring be_const_str_type;
|
||||
extern const bcstring be_const_str_dot_p;
|
||||
extern const bcstring be_const_str_traceback;
|
||||
extern const bcstring be_const_str_as;
|
||||
extern const bcstring be_const_str___lower__;
|
||||
extern const bcstring be_const_str_exp;
|
||||
extern const bcstring be_const_str_hex;
|
||||
extern const bcstring be_const_str_char;
|
||||
extern const bcstring be_const_str_split;
|
||||
extern const bcstring be_const_str_toupper;
|
||||
extern const bcstring be_const_str_deinit;
|
||||
extern const bcstring be_const_str_tan;
|
||||
extern const bcstring be_const_str_srand;
|
||||
extern const bcstring be_const_str_imin;
|
||||
extern const bcstring be_const_str_input;
|
||||
extern const bcstring be_const_str_issubclass;
|
||||
extern const bcstring be_const_str_tostring;
|
||||
extern const bcstring be_const_str_break;
|
||||
extern const bcstring be_const_str_insert;
|
||||
extern const bcstring be_const_str_var;
|
||||
extern const bcstring be_const_str_open;
|
||||
extern const bcstring be_const_str_tanh;
|
||||
extern const bcstring be_const_str_upper;
|
||||
extern const bcstring be_const_str_allocated;
|
||||
extern const bcstring be_const_str_rad;
|
||||
extern const bcstring be_const_str_attrdump;
|
||||
extern const bcstring be_const_str_copy;
|
||||
extern const bcstring be_const_str_sqrt;
|
||||
extern const bcstring be_const_str_for;
|
||||
extern const bcstring be_const_str_raise;
|
||||
extern const bcstring be_const_str_opt_neq;
|
||||
extern const bcstring be_const_str_assert;
|
||||
extern const bcstring be_const_str_item;
|
||||
extern const bcstring be_const_str_reverse;
|
||||
extern const bcstring be_const_str_sin;
|
||||
extern const bcstring be_const_str_super;
|
||||
extern const bcstring be_const_str_try;
|
||||
extern const bcstring be_const_str_range;
|
||||
extern const bcstring be_const_str_return;
|
||||
extern const bcstring be_const_str_compile;
|
||||
extern const bcstring be_const_str_false;
|
||||
extern const bcstring be_const_str_resize;
|
||||
extern const bcstring be_const_str_continue;
|
||||
extern const bcstring be_const_str_log;
|
||||
extern const bcstring be_const_str_true;
|
||||
extern const bcstring be_const_str_while;
|
||||
extern const bcstring be_const_str_pow;
|
||||
extern const bcstring be_const_str_cos;
|
||||
extern const bcstring be_const_str_count;
|
||||
extern const bcstring be_const_str_remove;
|
||||
extern const bcstring be_const_str_imax;
|
||||
extern const bcstring be_const_str_rand;
|
||||
extern const bcstring be_const_str_codedump;
|
||||
extern const bcstring be_const_str_deg;
|
||||
extern const bcstring be_const_str_keys;
|
||||
extern const bcstring be_const_str_setitem;
|
||||
extern const bcstring be_const_str_def;
|
||||
extern const bcstring be_const_str_except;
|
||||
extern const bcstring be_const_str_classname;
|
||||
extern const bcstring be_const_str_isinstance;
|
||||
extern const bcstring be_const_str_cosh;
|
||||
|
|
|
@ -1,190 +1,165 @@
|
|||
be_define_const_str(calldepth, "calldepth", 3122364302u, 0, 9, &be_const_str_clock);
|
||||
be_define_const_str(clock, "clock", 363073373u, 0, 5, &be_const_str_size);
|
||||
be_define_const_str(size, "size", 597743964u, 0, 4, &be_const_str_system);
|
||||
be_define_const_str(system, "system", 1226705564u, 0, 6, &be_const_str_type);
|
||||
be_define_const_str(type, "type", 1361572173u, 0, 4, &be_const_str_if);
|
||||
be_define_const_str(if, "if", 959999494u, 50, 2, NULL);
|
||||
be_define_const_str(int, "int", 2515107422u, 0, 3, &be_const_str_isfile);
|
||||
be_define_const_str(isfile, "isfile", 3131505107u, 0, 6, &be_const_str_log);
|
||||
be_define_const_str(log, "log", 1062293841u, 0, 3, &be_const_str_raise);
|
||||
be_define_const_str(raise, "raise", 1593437475u, 70, 5, NULL);
|
||||
be_define_const_str(concat, "concat", 4124019837u, 0, 6, &be_const_str_list);
|
||||
be_define_const_str(list, "list", 217798785u, 0, 4, &be_const_str_map);
|
||||
be_define_const_str(map, "map", 3751997361u, 0, 3, &be_const_str_for);
|
||||
be_define_const_str(for, "for", 2901640080u, 54, 3, NULL);
|
||||
be_define_const_str(dot_p, ".p", 1171526419u, 0, 2, &be_const_str_isdir);
|
||||
be_define_const_str(isdir, "isdir", 2340917412u, 0, 5, &be_const_str_mkdir);
|
||||
be_define_const_str(mkdir, "mkdir", 2883839448u, 0, 5, &be_const_str_remove);
|
||||
be_define_const_str(remove, "remove", 3683784189u, 0, 6, NULL);
|
||||
be_define_const_str(cosh, "cosh", 4099687964u, 0, 4, NULL);
|
||||
be_define_const_str(abs, "abs", 709362235u, 0, 3, &be_const_str_reverse);
|
||||
be_define_const_str(reverse, "reverse", 558918661u, 0, 7, &be_const_str_sinh);
|
||||
be_define_const_str(sinh, "sinh", 282220607u, 0, 4, NULL);
|
||||
be_define_const_str(hex, "hex", 4273249610u, 0, 3, NULL);
|
||||
be_define_const_str(tostring, "tostring", 2299708645u, 0, 8, NULL);
|
||||
be_define_const_str(opt_add, "+", 772578730u, 0, 1, &be_const_str_atan);
|
||||
be_define_const_str(atan, "atan", 108579519u, 0, 4, &be_const_str_real);
|
||||
be_define_const_str(real, "real", 3604983901u, 0, 4, NULL);
|
||||
be_define_const_str(iter, "iter", 3124256359u, 0, 4, &be_const_str_top);
|
||||
be_define_const_str(top, "top", 2802900028u, 0, 3, &be_const_str_except);
|
||||
be_define_const_str(except, "except", 950914032u, 69, 6, NULL);
|
||||
be_define_const_str(getcwd, "getcwd", 652026575u, 0, 6, &be_const_str_listdir);
|
||||
be_define_const_str(listdir, "listdir", 2005220720u, 0, 7, &be_const_str_log10);
|
||||
be_define_const_str(log10, "log10", 2346846000u, 0, 5, NULL);
|
||||
be_define_const_str(allocated, "allocated", 429986098u, 0, 9, &be_const_str_init);
|
||||
be_define_const_str(init, "init", 380752755u, 0, 4, &be_const_str_module);
|
||||
be_define_const_str(module, "module", 3617558685u, 0, 6, NULL);
|
||||
be_define_const_str(ceil, "ceil", 1659167240u, 0, 4, &be_const_str_clear);
|
||||
be_define_const_str(clear, "clear", 1550717474u, 0, 5, &be_const_str_collect);
|
||||
be_define_const_str(collect, "collect", 2399039025u, 0, 7, &be_const_str_find);
|
||||
be_define_const_str(find, "find", 3186656602u, 0, 4, &be_const_str_item);
|
||||
be_define_const_str(item, "item", 2671260646u, 0, 4, NULL);
|
||||
be_define_const_str(format, "format", 3114108242u, 0, 6, &be_const_str_sqrt);
|
||||
be_define_const_str(sqrt, "sqrt", 2112764879u, 0, 4, NULL);
|
||||
be_define_const_str(classname, "classname", 1998589948u, 0, 9, NULL);
|
||||
be_define_const_str(byte, "byte", 1683620383u, 0, 4, NULL);
|
||||
be_define_const_str(else, "else", 3183434736u, 52, 4, NULL);
|
||||
be_define_const_str(deinit, "deinit", 2345559592u, 0, 6, &be_const_str_end);
|
||||
be_define_const_str(end, "end", 1787721130u, 56, 3, &be_const_str_true);
|
||||
be_define_const_str(true, "true", 1303515621u, 61, 4, NULL);
|
||||
be_define_const_str(__upper__, "__upper__", 3612202883u, 0, 9, NULL);
|
||||
be_define_const_str(char, "char", 2823553821u, 0, 4, &be_const_str_load);
|
||||
be_define_const_str(load, "load", 3859241449u, 0, 4, &be_const_str_resize);
|
||||
be_define_const_str(resize, "resize", 3514612129u, 0, 6, &be_const_str_sethook);
|
||||
be_define_const_str(sethook, "sethook", 3963967276u, 0, 7, &be_const_str_varname);
|
||||
be_define_const_str(varname, "varname", 2273276445u, 0, 7, NULL);
|
||||
be_define_const_str(deg, "deg", 3327754271u, 0, 3, &be_const_str_srand);
|
||||
be_define_const_str(srand, "srand", 465518633u, 0, 5, &be_const_str_str);
|
||||
be_define_const_str(str, "str", 3259748752u, 0, 3, NULL);
|
||||
be_define_const_str(range, "range", 4208725202u, 0, 5, &be_const_str_toupper);
|
||||
be_define_const_str(toupper, "toupper", 3691983576u, 0, 7, NULL);
|
||||
be_define_const_str(, "", 2166136261u, 0, 0, &be_const_str_copy);
|
||||
be_define_const_str(copy, "copy", 3848464964u, 0, 4, &be_const_str_exp);
|
||||
be_define_const_str(exp, "exp", 1923516200u, 0, 3, &be_const_str_time);
|
||||
be_define_const_str(time, "time", 1564253156u, 0, 4, &be_const_str_break);
|
||||
be_define_const_str(break, "break", 3378807160u, 58, 5, NULL);
|
||||
be_define_const_str(opt_neq, "!=", 2428715011u, 0, 2, &be_const_str_assert);
|
||||
be_define_const_str(assert, "assert", 2774883451u, 0, 6, &be_const_str_attrdump);
|
||||
be_define_const_str(attrdump, "attrdump", 1521571304u, 0, 8, &be_const_str_chdir);
|
||||
be_define_const_str(chdir, "chdir", 806634853u, 0, 5, &be_const_str_isinstance);
|
||||
be_define_const_str(isinstance, "isinstance", 3669352738u, 0, 10, &be_const_str_continue);
|
||||
be_define_const_str(continue, "continue", 2977070660u, 59, 8, &be_const_str_do);
|
||||
be_define_const_str(do, "do", 1646057492u, 65, 2, NULL);
|
||||
be_define_const_str(lower, "lower", 3038577850u, 0, 5, &be_const_str_pow);
|
||||
be_define_const_str(pow, "pow", 1479764693u, 0, 3, &be_const_str_false);
|
||||
be_define_const_str(false, "false", 184981848u, 62, 5, NULL);
|
||||
be_define_const_str(count, "count", 967958004u, 0, 5, NULL);
|
||||
be_define_const_str(exit, "exit", 3454868101u, 0, 4, &be_const_str_print);
|
||||
be_define_const_str(print, "print", 372738696u, 0, 5, &be_const_str_def);
|
||||
be_define_const_str(def, "def", 3310976652u, 55, 3, NULL);
|
||||
be_define_const_str(pop, "pop", 1362321360u, 0, 3, &be_const_str_tolower);
|
||||
be_define_const_str(tolower, "tolower", 1042520049u, 0, 7, NULL);
|
||||
be_define_const_str(classof, "classof", 1796577762u, 0, 7, &be_const_str_cos);
|
||||
be_define_const_str(cos, "cos", 4220379804u, 0, 3, &be_const_str_dump);
|
||||
be_define_const_str(dump, "dump", 3663001223u, 0, 4, &be_const_str_join);
|
||||
be_define_const_str(join, "join", 3374496889u, 0, 4, &be_const_str_push);
|
||||
be_define_const_str(push, "push", 2272264157u, 0, 4, &be_const_str_sin);
|
||||
be_define_const_str(sin, "sin", 3761252941u, 0, 3, &be_const_str_return);
|
||||
be_define_const_str(return, "return", 2246981567u, 60, 6, NULL);
|
||||
be_define_const_str(path, "path", 2223459638u, 0, 4, &be_const_str_rand);
|
||||
be_define_const_str(rand, "rand", 2711325910u, 0, 4, &be_const_str_class);
|
||||
be_define_const_str(class, "class", 2872970239u, 57, 5, &be_const_str_nil);
|
||||
be_define_const_str(nil, "nil", 228849900u, 63, 3, NULL);
|
||||
be_define_const_str(input, "input", 4191711099u, 0, 5, NULL);
|
||||
be_define_const_str(floor, "floor", 3102149661u, 0, 5, &be_const_str_keys);
|
||||
be_define_const_str(keys, "keys", 4182378701u, 0, 4, &be_const_str_number);
|
||||
be_define_const_str(number, "number", 467038368u, 0, 6, &be_const_str_rad);
|
||||
be_define_const_str(rad, "rad", 1358899048u, 0, 3, NULL);
|
||||
be_define_const_str(imin, "imin", 2714127864u, 0, 4, &be_const_str_pi);
|
||||
be_define_const_str(pi, "pi", 1213090802u, 0, 2, NULL);
|
||||
be_define_const_str(splitext, "splitext", 2150391934u, 0, 8, NULL);
|
||||
be_define_const_str(compile, "compile", 1000265118u, 0, 7, &be_const_str_setrange);
|
||||
be_define_const_str(setrange, "setrange", 3794019032u, 0, 8, &be_const_str_traceback);
|
||||
be_define_const_str(traceback, "traceback", 3385188109u, 0, 9, &be_const_str_upper);
|
||||
be_define_const_str(upper, "upper", 176974407u, 0, 5, &be_const_str_var);
|
||||
be_define_const_str(var, "var", 2317739966u, 64, 3, NULL);
|
||||
be_define_const_str(opt_eq, "==", 2431966415u, 0, 2, NULL);
|
||||
be_define_const_str(codedump, "codedump", 1786337906u, 0, 8, &be_const_str_tan);
|
||||
be_define_const_str(tan, "tan", 2633446552u, 0, 3, NULL);
|
||||
be_define_const_str(setitem, "setitem", 1554834596u, 0, 7, NULL);
|
||||
be_define_const_str(tanh, "tanh", 153638352u, 0, 4, &be_const_str_as);
|
||||
be_define_const_str(as, "as", 1579491469u, 67, 2, NULL);
|
||||
be_define_const_str(issubclass, "issubclass", 4078395519u, 0, 10, &be_const_str_upvname);
|
||||
be_define_const_str(upvname, "upvname", 3848760617u, 0, 7, NULL);
|
||||
be_define_const_str(opt_connect, "..", 2748622605u, 0, 2, NULL);
|
||||
be_define_const_str(try, "try", 2887626766u, 68, 3, &be_const_str_while);
|
||||
be_define_const_str(while, "while", 231090382u, 53, 5, NULL);
|
||||
be_define_const_str(import, "import", 288002260u, 66, 6, NULL);
|
||||
be_define_const_str(__lower__, "__lower__", 123855590u, 0, 9, &be_const_str_open);
|
||||
be_define_const_str(open, "open", 3546203337u, 0, 4, NULL);
|
||||
be_define_const_str(acos, "acos", 1006755615u, 0, 4, &be_const_str_asin);
|
||||
be_define_const_str(asin, "asin", 4272848550u, 0, 4, &be_const_str_imax);
|
||||
be_define_const_str(imax, "imax", 3084515410u, 0, 4, &be_const_str_insert);
|
||||
be_define_const_str(insert, "insert", 3332609576u, 0, 6, &be_const_str_split);
|
||||
be_define_const_str(split, "split", 2276994531u, 0, 5, NULL);
|
||||
be_define_const_str(__iterator__, "__iterator__", 3884039703u, 0, 12, &be_const_str_exists);
|
||||
be_define_const_str(exists, "exists", 1002329533u, 0, 6, &be_const_str_super);
|
||||
be_define_const_str(super, "super", 4152230356u, 0, 5, &be_const_str_elif);
|
||||
be_define_const_str(asin, "asin", 4272848550u, 0, 4, &be_const_str_list);
|
||||
be_define_const_str(list, "list", 217798785u, 0, 4, &be_const_str_module);
|
||||
be_define_const_str(module, "module", 3617558685u, 0, 6, &be_const_str_pop);
|
||||
be_define_const_str(pop, "pop", 1362321360u, 0, 3, NULL);
|
||||
be_define_const_str(int, "int", 2515107422u, 0, 3, &be_const_str_push);
|
||||
be_define_const_str(push, "push", 2272264157u, 0, 4, &be_const_str_setrange);
|
||||
be_define_const_str(setrange, "setrange", 3794019032u, 0, 8, &be_const_str_sinh);
|
||||
be_define_const_str(sinh, "sinh", 282220607u, 0, 4, &be_const_str_elif);
|
||||
be_define_const_str(elif, "elif", 3232090307u, 51, 4, NULL);
|
||||
be_define_const_str(iter, "iter", 3124256359u, 0, 4, &be_const_str_load);
|
||||
be_define_const_str(load, "load", 3859241449u, 0, 4, &be_const_str_class);
|
||||
be_define_const_str(class, "class", 2872970239u, 57, 5, &be_const_str_if);
|
||||
be_define_const_str(if, "if", 959999494u, 50, 2, NULL);
|
||||
be_define_const_str(opt_eq, "==", 2431966415u, 0, 2, &be_const_str_ceil);
|
||||
be_define_const_str(ceil, "ceil", 1659167240u, 0, 4, NULL);
|
||||
be_define_const_str(floor, "floor", 3102149661u, 0, 5, &be_const_str_map);
|
||||
be_define_const_str(map, "map", 3751997361u, 0, 3, &be_const_str_print);
|
||||
be_define_const_str(print, "print", 372738696u, 0, 5, &be_const_str_else);
|
||||
be_define_const_str(else, "else", 3183434736u, 52, 4, NULL);
|
||||
be_define_const_str(find, "find", 3186656602u, 0, 4, &be_const_str_str);
|
||||
be_define_const_str(str, "str", 3259748752u, 0, 3, NULL);
|
||||
be_define_const_str(__upper__, "__upper__", 3612202883u, 0, 9, &be_const_str_dump);
|
||||
be_define_const_str(dump, "dump", 3663001223u, 0, 4, NULL);
|
||||
be_define_const_str(atan, "atan", 108579519u, 0, 4, &be_const_str_size);
|
||||
be_define_const_str(size, "size", 597743964u, 0, 4, &be_const_str_tolower);
|
||||
be_define_const_str(tolower, "tolower", 1042520049u, 0, 7, NULL);
|
||||
be_define_const_str(opt_add, "+", 772578730u, 0, 1, &be_const_str_abs);
|
||||
be_define_const_str(abs, "abs", 709362235u, 0, 3, &be_const_str_lower);
|
||||
be_define_const_str(lower, "lower", 3038577850u, 0, 5, &be_const_str_end);
|
||||
be_define_const_str(end, "end", 1787721130u, 56, 3, &be_const_str_import);
|
||||
be_define_const_str(import, "import", 288002260u, 66, 6, NULL);
|
||||
be_define_const_str(classof, "classof", 1796577762u, 0, 7, &be_const_str_concat);
|
||||
be_define_const_str(concat, "concat", 4124019837u, 0, 6, NULL);
|
||||
be_define_const_str(byte, "byte", 1683620383u, 0, 4, &be_const_str_top);
|
||||
be_define_const_str(top, "top", 2802900028u, 0, 3, NULL);
|
||||
be_define_const_str(clear, "clear", 1550717474u, 0, 5, NULL);
|
||||
be_define_const_str(opt_connect, "..", 2748622605u, 0, 2, &be_const_str_collect);
|
||||
be_define_const_str(collect, "collect", 2399039025u, 0, 7, &be_const_str_init);
|
||||
be_define_const_str(init, "init", 380752755u, 0, 4, &be_const_str_log10);
|
||||
be_define_const_str(log10, "log10", 2346846000u, 0, 5, &be_const_str_nil);
|
||||
be_define_const_str(nil, "nil", 228849900u, 63, 3, NULL);
|
||||
be_define_const_str(, "", 2166136261u, 0, 0, &be_const_str_real);
|
||||
be_define_const_str(real, "real", 3604983901u, 0, 4, NULL);
|
||||
be_define_const_str(calldepth, "calldepth", 3122364302u, 0, 9, &be_const_str_format);
|
||||
be_define_const_str(format, "format", 3114108242u, 0, 6, &be_const_str_pi);
|
||||
be_define_const_str(pi, "pi", 1213090802u, 0, 2, &be_const_str_do);
|
||||
be_define_const_str(do, "do", 1646057492u, 65, 2, NULL);
|
||||
be_define_const_str(__iterator__, "__iterator__", 3884039703u, 0, 12, &be_const_str_number);
|
||||
be_define_const_str(number, "number", 467038368u, 0, 6, &be_const_str_type);
|
||||
be_define_const_str(type, "type", 1361572173u, 0, 4, NULL);
|
||||
be_define_const_str(dot_p, ".p", 1171526419u, 0, 2, &be_const_str_traceback);
|
||||
be_define_const_str(traceback, "traceback", 3385188109u, 0, 9, &be_const_str_as);
|
||||
be_define_const_str(as, "as", 1579491469u, 67, 2, NULL);
|
||||
be_define_const_str(__lower__, "__lower__", 123855590u, 0, 9, &be_const_str_exp);
|
||||
be_define_const_str(exp, "exp", 1923516200u, 0, 3, &be_const_str_hex);
|
||||
be_define_const_str(hex, "hex", 4273249610u, 0, 3, NULL);
|
||||
be_define_const_str(char, "char", 2823553821u, 0, 4, &be_const_str_split);
|
||||
be_define_const_str(split, "split", 2276994531u, 0, 5, &be_const_str_toupper);
|
||||
be_define_const_str(toupper, "toupper", 3691983576u, 0, 7, NULL);
|
||||
be_define_const_str(deinit, "deinit", 2345559592u, 0, 6, &be_const_str_tan);
|
||||
be_define_const_str(tan, "tan", 2633446552u, 0, 3, NULL);
|
||||
be_define_const_str(srand, "srand", 465518633u, 0, 5, NULL);
|
||||
be_define_const_str(imin, "imin", 2714127864u, 0, 4, &be_const_str_input);
|
||||
be_define_const_str(input, "input", 4191711099u, 0, 5, &be_const_str_issubclass);
|
||||
be_define_const_str(issubclass, "issubclass", 4078395519u, 0, 10, NULL);
|
||||
be_define_const_str(tostring, "tostring", 2299708645u, 0, 8, &be_const_str_break);
|
||||
be_define_const_str(break, "break", 3378807160u, 58, 5, NULL);
|
||||
be_define_const_str(insert, "insert", 3332609576u, 0, 6, &be_const_str_var);
|
||||
be_define_const_str(var, "var", 2317739966u, 64, 3, NULL);
|
||||
be_define_const_str(open, "open", 3546203337u, 0, 4, &be_const_str_tanh);
|
||||
be_define_const_str(tanh, "tanh", 153638352u, 0, 4, &be_const_str_upper);
|
||||
be_define_const_str(upper, "upper", 176974407u, 0, 5, NULL);
|
||||
be_define_const_str(allocated, "allocated", 429986098u, 0, 9, &be_const_str_rad);
|
||||
be_define_const_str(rad, "rad", 1358899048u, 0, 3, NULL);
|
||||
be_define_const_str(attrdump, "attrdump", 1521571304u, 0, 8, &be_const_str_copy);
|
||||
be_define_const_str(copy, "copy", 3848464964u, 0, 4, &be_const_str_sqrt);
|
||||
be_define_const_str(sqrt, "sqrt", 2112764879u, 0, 4, NULL);
|
||||
be_define_const_str(for, "for", 2901640080u, 54, 3, &be_const_str_raise);
|
||||
be_define_const_str(raise, "raise", 1593437475u, 70, 5, NULL);
|
||||
be_define_const_str(opt_neq, "!=", 2428715011u, 0, 2, &be_const_str_assert);
|
||||
be_define_const_str(assert, "assert", 2774883451u, 0, 6, &be_const_str_item);
|
||||
be_define_const_str(item, "item", 2671260646u, 0, 4, &be_const_str_reverse);
|
||||
be_define_const_str(reverse, "reverse", 558918661u, 0, 7, &be_const_str_sin);
|
||||
be_define_const_str(sin, "sin", 3761252941u, 0, 3, &be_const_str_super);
|
||||
be_define_const_str(super, "super", 4152230356u, 0, 5, &be_const_str_try);
|
||||
be_define_const_str(try, "try", 2887626766u, 68, 3, NULL);
|
||||
be_define_const_str(range, "range", 4208725202u, 0, 5, &be_const_str_return);
|
||||
be_define_const_str(return, "return", 2246981567u, 60, 6, NULL);
|
||||
be_define_const_str(compile, "compile", 1000265118u, 0, 7, &be_const_str_false);
|
||||
be_define_const_str(false, "false", 184981848u, 62, 5, NULL);
|
||||
be_define_const_str(resize, "resize", 3514612129u, 0, 6, NULL);
|
||||
be_define_const_str(continue, "continue", 2977070660u, 59, 8, NULL);
|
||||
be_define_const_str(log, "log", 1062293841u, 0, 3, &be_const_str_true);
|
||||
be_define_const_str(true, "true", 1303515621u, 61, 4, NULL);
|
||||
be_define_const_str(while, "while", 231090382u, 53, 5, NULL);
|
||||
be_define_const_str(pow, "pow", 1479764693u, 0, 3, NULL);
|
||||
be_define_const_str(cos, "cos", 4220379804u, 0, 3, &be_const_str_count);
|
||||
be_define_const_str(count, "count", 967958004u, 0, 5, &be_const_str_remove);
|
||||
be_define_const_str(remove, "remove", 3683784189u, 0, 6, NULL);
|
||||
be_define_const_str(imax, "imax", 3084515410u, 0, 4, &be_const_str_rand);
|
||||
be_define_const_str(rand, "rand", 2711325910u, 0, 4, NULL);
|
||||
be_define_const_str(codedump, "codedump", 1786337906u, 0, 8, &be_const_str_deg);
|
||||
be_define_const_str(deg, "deg", 3327754271u, 0, 3, &be_const_str_keys);
|
||||
be_define_const_str(keys, "keys", 4182378701u, 0, 4, &be_const_str_setitem);
|
||||
be_define_const_str(setitem, "setitem", 1554834596u, 0, 7, NULL);
|
||||
be_define_const_str(def, "def", 3310976652u, 55, 3, &be_const_str_except);
|
||||
be_define_const_str(except, "except", 950914032u, 69, 6, NULL);
|
||||
be_define_const_str(classname, "classname", 1998589948u, 0, 9, &be_const_str_isinstance);
|
||||
be_define_const_str(isinstance, "isinstance", 3669352738u, 0, 10, NULL);
|
||||
be_define_const_str(cosh, "cosh", 4099687964u, 0, 4, NULL);
|
||||
|
||||
static const bstring* const m_string_table[] = {
|
||||
(const bstring *)&be_const_str_calldepth,
|
||||
(const bstring *)&be_const_str_int,
|
||||
(const bstring *)&be_const_str_concat,
|
||||
(const bstring *)&be_const_str_dot_p,
|
||||
NULL,
|
||||
(const bstring *)&be_const_str_cosh,
|
||||
(const bstring *)&be_const_str_abs,
|
||||
(const bstring *)&be_const_str_hex,
|
||||
(const bstring *)&be_const_str_tostring,
|
||||
(const bstring *)&be_const_str_opt_add,
|
||||
(const bstring *)&be_const_str_iter,
|
||||
(const bstring *)&be_const_str_getcwd,
|
||||
NULL,
|
||||
(const bstring *)&be_const_str_allocated,
|
||||
(const bstring *)&be_const_str_ceil,
|
||||
(const bstring *)&be_const_str_format,
|
||||
(const bstring *)&be_const_str_classname,
|
||||
(const bstring *)&be_const_str_byte,
|
||||
(const bstring *)&be_const_str_else,
|
||||
(const bstring *)&be_const_str_deinit,
|
||||
(const bstring *)&be_const_str___upper__,
|
||||
(const bstring *)&be_const_str_char,
|
||||
NULL,
|
||||
(const bstring *)&be_const_str_deg,
|
||||
NULL,
|
||||
(const bstring *)&be_const_str_range,
|
||||
(const bstring *)&be_const_str_,
|
||||
NULL,
|
||||
(const bstring *)&be_const_str_opt_neq,
|
||||
(const bstring *)&be_const_str_lower,
|
||||
(const bstring *)&be_const_str_count,
|
||||
(const bstring *)&be_const_str_exit,
|
||||
(const bstring *)&be_const_str_pop,
|
||||
(const bstring *)&be_const_str_classof,
|
||||
(const bstring *)&be_const_str_path,
|
||||
(const bstring *)&be_const_str_input,
|
||||
(const bstring *)&be_const_str_floor,
|
||||
(const bstring *)&be_const_str_imin,
|
||||
(const bstring *)&be_const_str_splitext,
|
||||
NULL,
|
||||
(const bstring *)&be_const_str_compile,
|
||||
(const bstring *)&be_const_str_opt_eq,
|
||||
(const bstring *)&be_const_str_codedump,
|
||||
(const bstring *)&be_const_str_setitem,
|
||||
(const bstring *)&be_const_str_tanh,
|
||||
(const bstring *)&be_const_str_issubclass,
|
||||
(const bstring *)&be_const_str_opt_connect,
|
||||
(const bstring *)&be_const_str_try,
|
||||
(const bstring *)&be_const_str_import,
|
||||
(const bstring *)&be_const_str___lower__,
|
||||
NULL,
|
||||
(const bstring *)&be_const_str_acos,
|
||||
(const bstring *)&be_const_str___iterator__
|
||||
NULL,
|
||||
(const bstring *)&be_const_str_int,
|
||||
NULL,
|
||||
(const bstring *)&be_const_str_iter,
|
||||
(const bstring *)&be_const_str_opt_eq,
|
||||
(const bstring *)&be_const_str_floor,
|
||||
(const bstring *)&be_const_str_find,
|
||||
(const bstring *)&be_const_str___upper__,
|
||||
(const bstring *)&be_const_str_atan,
|
||||
(const bstring *)&be_const_str_opt_add,
|
||||
NULL,
|
||||
(const bstring *)&be_const_str_classof,
|
||||
(const bstring *)&be_const_str_byte,
|
||||
(const bstring *)&be_const_str_clear,
|
||||
(const bstring *)&be_const_str_opt_connect,
|
||||
(const bstring *)&be_const_str_,
|
||||
(const bstring *)&be_const_str_calldepth,
|
||||
(const bstring *)&be_const_str___iterator__,
|
||||
(const bstring *)&be_const_str_dot_p,
|
||||
(const bstring *)&be_const_str___lower__,
|
||||
(const bstring *)&be_const_str_char,
|
||||
(const bstring *)&be_const_str_deinit,
|
||||
(const bstring *)&be_const_str_srand,
|
||||
(const bstring *)&be_const_str_imin,
|
||||
(const bstring *)&be_const_str_tostring,
|
||||
(const bstring *)&be_const_str_insert,
|
||||
(const bstring *)&be_const_str_open,
|
||||
(const bstring *)&be_const_str_allocated,
|
||||
(const bstring *)&be_const_str_attrdump,
|
||||
(const bstring *)&be_const_str_for,
|
||||
(const bstring *)&be_const_str_opt_neq,
|
||||
(const bstring *)&be_const_str_range,
|
||||
(const bstring *)&be_const_str_compile,
|
||||
(const bstring *)&be_const_str_resize,
|
||||
(const bstring *)&be_const_str_continue,
|
||||
(const bstring *)&be_const_str_log,
|
||||
(const bstring *)&be_const_str_while,
|
||||
(const bstring *)&be_const_str_pow,
|
||||
(const bstring *)&be_const_str_cos,
|
||||
(const bstring *)&be_const_str_imax,
|
||||
(const bstring *)&be_const_str_codedump,
|
||||
(const bstring *)&be_const_str_def,
|
||||
(const bstring *)&be_const_str_classname,
|
||||
(const bstring *)&be_const_str_cosh
|
||||
};
|
||||
|
||||
static const struct bconststrtab m_const_string_table = {
|
||||
.size = 53,
|
||||
.count = 107,
|
||||
.size = 45,
|
||||
.count = 90,
|
||||
.table = m_string_table
|
||||
};
|
||||
|
|
|
@ -1,19 +1,16 @@
|
|||
#include "be_constobj.h"
|
||||
|
||||
static be_define_const_map_slots(m_libdebug_map) {
|
||||
{ be_const_key(attrdump, -1), be_const_func(m_attrdump) },
|
||||
{ be_const_key(upvname, -1), be_const_func(m_upvname) },
|
||||
{ be_const_key(codedump, -1), be_const_func(m_codedump) },
|
||||
{ be_const_key(top, -1), be_const_func(m_top) },
|
||||
{ be_const_key(sethook, 3), be_const_func(m_sethook) },
|
||||
{ be_const_key(varname, 7), be_const_func(m_varname) },
|
||||
{ be_const_key(calldepth, -1), be_const_func(m_calldepth) },
|
||||
{ be_const_key(traceback, -1), be_const_func(m_traceback) },
|
||||
{ be_const_key(codedump, -1), be_const_func(m_codedump) },
|
||||
{ be_const_key(calldepth, -1), be_const_func(m_calldepth) },
|
||||
{ be_const_key(top, -1), be_const_func(m_top) },
|
||||
{ be_const_key(attrdump, 0), be_const_func(m_attrdump) },
|
||||
};
|
||||
|
||||
static be_define_const_map(
|
||||
m_libdebug_map,
|
||||
8
|
||||
5
|
||||
);
|
||||
|
||||
static be_define_const_module(
|
||||
|
|
|
@ -1,24 +1,2 @@
|
|||
#include "be_constobj.h"
|
||||
|
||||
static be_define_const_map_slots(m_libos_map) {
|
||||
{ be_const_key(listdir, 1), be_const_func(m_listdir) },
|
||||
{ be_const_key(mkdir, -1), be_const_func(m_mkdir) },
|
||||
{ be_const_key(chdir, -1), be_const_func(m_chdir) },
|
||||
{ be_const_key(exit, 2), be_const_func(m_exit) },
|
||||
{ be_const_key(system, -1), be_const_func(m_system) },
|
||||
{ be_const_key(remove, 3), be_const_func(m_remove) },
|
||||
{ be_const_key(path, -1), be_const_module(m_libpath) },
|
||||
{ be_const_key(getcwd, -1), be_const_func(m_getcwd) },
|
||||
};
|
||||
|
||||
static be_define_const_map(
|
||||
m_libos_map,
|
||||
8
|
||||
);
|
||||
|
||||
static be_define_const_module(
|
||||
m_libos,
|
||||
"os"
|
||||
);
|
||||
|
||||
BE_EXPORT_VARIABLE be_define_const_native_module(os, NULL);
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
#include "be_constobj.h"
|
||||
|
|
@ -1,17 +1,2 @@
|
|||
#include "be_constobj.h"
|
||||
|
||||
static be_define_const_map_slots(m_libsys_map) {
|
||||
{ be_const_key(path, -1), be_const_func(m_path) },
|
||||
};
|
||||
|
||||
static be_define_const_map(
|
||||
m_libsys_map,
|
||||
1
|
||||
);
|
||||
|
||||
static be_define_const_module(
|
||||
m_libsys,
|
||||
"sys"
|
||||
);
|
||||
|
||||
BE_EXPORT_VARIABLE be_define_const_native_module(sys, NULL);
|
||||
|
|
|
@ -1,19 +1,2 @@
|
|||
#include "be_constobj.h"
|
||||
|
||||
static be_define_const_map_slots(m_libtime_map) {
|
||||
{ be_const_key(dump, 1), be_const_func(m_dump) },
|
||||
{ be_const_key(clock, -1), be_const_func(m_clock) },
|
||||
{ be_const_key(time, 0), be_const_func(m_time) },
|
||||
};
|
||||
|
||||
static be_define_const_map(
|
||||
m_libtime_map,
|
||||
3
|
||||
);
|
||||
|
||||
static be_define_const_module(
|
||||
m_libtime,
|
||||
"time"
|
||||
);
|
||||
|
||||
BE_EXPORT_VARIABLE be_define_const_native_module(time, NULL);
|
||||
|
|
|
@ -310,7 +310,7 @@ static void free_ntvclos(bvm *vm, bgcobject *obj)
|
|||
while (count--) {
|
||||
be_free(vm, *uv++, sizeof(bupval));
|
||||
}
|
||||
be_free(vm, f, sizeof(bntvclos));
|
||||
be_free(vm, f, sizeof(bntvclos) + sizeof(bupval*) * f->nupvals);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#define BE_GCOBJECT BE_STRING
|
||||
|
||||
#define gc_object(o) cast(bgcobject*, o)
|
||||
#define gc_cast(o, t, T) ((o) && pgm_read_byte(&(o)->type) == (t) ? (T*)(o) : NULL)
|
||||
#define gc_cast(o, t, T) ((o) && (o)->type == (t) ? (T*)(o) : NULL)
|
||||
#define cast_proto(o) gc_cast(o, BE_PROTO, bproto)
|
||||
#define cast_closure(o) gc_cast(o, BE_CLOSURE, bclosure)
|
||||
#define cast_ntvclos(o) gc_cast(o, BE_NTVCLOS, bntvclos)
|
||||
|
@ -38,11 +38,11 @@ if (!gc_isconst(o)) { \
|
|||
#define gc_setwhite(o) gc_setmark((o), GC_WHITE)
|
||||
#define gc_setgray(o) gc_setmark((o), GC_GRAY)
|
||||
#define gc_setdark(o) gc_setmark((o), GC_DARK)
|
||||
#define gc_isfixed(o) ((pgm_read_byte(&(o)->marked) & GC_FIXED) != 0)
|
||||
#define gc_isfixed(o) (((o)->marked & GC_FIXED) != 0)
|
||||
#define gc_setfixed(o) ((o)->marked |= GC_FIXED)
|
||||
#define gc_clearfixed(o) ((o)->marked &= ~GC_FIXED)
|
||||
#define gc_isconst(o) ((pgm_read_byte(&(o)->marked) & GC_CONST) != 0)
|
||||
#define gc_exmark(o) ((pgm_read_byte(&(o)->marked) >> 4) & 0x0F)
|
||||
#define gc_isconst(o) (((o)->marked & GC_CONST) != 0)
|
||||
#define gc_exmark(o) (((o)->marked >> 4) & 0x0F)
|
||||
#define gc_setexmark(o, k) ((o)->marked |= (k) << 4)
|
||||
|
||||
#define be_isgctype(t) ((t) >= BE_GCOBJECT)
|
||||
|
|
|
@ -105,8 +105,7 @@ static int next(blexer *lexer)
|
|||
lr->s = s ? s : &eos;
|
||||
--lr->len;
|
||||
}
|
||||
// lexer->cursor = *lr->s++; // SH
|
||||
lexer->cursor = pgm_read_byte(lr->s++);
|
||||
lexer->cursor = *lr->s++;
|
||||
return lexer->cursor;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,37 +10,6 @@
|
|||
|
||||
#include "berry.h"
|
||||
|
||||
/* support for PROGMEM on ESP8266 and AVR */
|
||||
#ifdef _PGMSPACE_H_
|
||||
#define strncmp strncmp_PP
|
||||
#define strcmp(str1P, str2P) strncmp_PP((str1P), (str2P), SIZE_IRRELEVANT)
|
||||
#define strncasecmp strncasecmp_P
|
||||
#define strcasecmp_P(str1, str2P) strncasecmp_P((str1), (str2P), SIZE_IRRELEVANT)
|
||||
#define strlen strlen_P
|
||||
#define strchr strchr_P
|
||||
#define strcat strcat_P
|
||||
#define strncat strncat_P
|
||||
#define strcpy strcpy_P
|
||||
#define strncpy strncpy_P
|
||||
#define memcpy memcpy_P
|
||||
#define memccpy memccpy_P
|
||||
#define memmove memmove_P
|
||||
#define memcmp memcmp_P
|
||||
#define memmem memmem_P
|
||||
#define memchr memchr_P
|
||||
#define sprintf sprintf_P
|
||||
#define snprintf snprintf_P
|
||||
#endif
|
||||
|
||||
#ifndef pgm_read_byte
|
||||
#define pgm_read_byte(addr) (*(const uint8_t*)(addr))
|
||||
#endif
|
||||
|
||||
#ifndef pgm_read_word
|
||||
#define pgm_read_word(addr) (*(const uint16_t*)(addr))
|
||||
#endif
|
||||
|
||||
|
||||
/* basic types, do not change value */
|
||||
#define BE_NONE (-1) /* unknow type */
|
||||
#define BE_COMPTR (-2) /* common pointer */
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
#define FUNC_ANONYMOUS 2
|
||||
|
||||
/* get binary operator priority */
|
||||
#define binary_op_prio(op) (pgm_read_byte(&binary_op_prio_tab[cast_int(op) - OptAdd]))
|
||||
#define binary_op_prio(op) (binary_op_prio_tab[cast_int(op) - OptAdd])
|
||||
|
||||
#define scan_next_token(parser) (be_lexer_scan_next(&(parser)->lexer))
|
||||
#define next_token(parser) ((parser)->lexer.token)
|
||||
|
|
|
@ -44,9 +44,9 @@ int be_eqstr(bstring *s1, bstring *s2)
|
|||
if (s1 == s2) { /* short string or the same string */
|
||||
return 1;
|
||||
}
|
||||
slen = pgm_read_byte(&s1->slen);
|
||||
slen = s1->slen;
|
||||
/* long string */
|
||||
if (slen == 255 && slen == pgm_read_byte(&s2->slen)) {
|
||||
if (slen == 255 && slen == s2->slen) {
|
||||
blstring *ls1 = cast(blstring*, s1);
|
||||
blstring *ls2 = cast(blstring*, s2);
|
||||
return ls1->llen == ls2->llen && !strcmp(lstr(ls1), lstr(ls2));
|
||||
|
@ -88,7 +88,7 @@ static void resize(bvm *vm, int size)
|
|||
|
||||
static void free_sstring(bvm *vm, bstring *str)
|
||||
{
|
||||
be_free(vm, str, sizeof(bsstring) + pgm_read_byte(&str->slen) + 1);
|
||||
be_free(vm, str, sizeof(bsstring) + str->slen + 1);
|
||||
}
|
||||
|
||||
/* FNV-1a Hash */
|
||||
|
@ -97,8 +97,7 @@ static uint32_t str_hash(const char *str, size_t len)
|
|||
uint32_t hash = 2166136261u;
|
||||
be_assert(str || len);
|
||||
while (len--) {
|
||||
hash = (hash ^ (unsigned char)pgm_read_byte(str)) * 16777619u;
|
||||
str++;
|
||||
hash = (hash ^ (unsigned char)*str++) * 16777619u;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
@ -150,7 +149,7 @@ static bstring* find_conststr(const char *str, size_t len)
|
|||
uint32_t hash = str_hash(str, len);
|
||||
bcstring *s = (bcstring*)tab->table[hash % tab->size];
|
||||
for (; s != NULL; s = next(s)) {
|
||||
if (len == pgm_read_byte(&s->slen) && !strncmp(str, s->s, len)) {
|
||||
if (len == s->slen && !strncmp(str, s->s, len)) {
|
||||
return (bstring*)s;
|
||||
}
|
||||
}
|
||||
|
@ -166,7 +165,7 @@ static bstring* newshortstr(bvm *vm, const char *str, size_t len)
|
|||
bstring **list = vm->strtab.table + (hash & (size - 1));
|
||||
|
||||
for (s = *list; s != NULL; s = next(s)) {
|
||||
if (len == pgm_read_byte(&s->slen) && !strncmp(str, sstr(s), len)) {
|
||||
if (len == s->slen && !strncmp(str, sstr(s), len)) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
@ -253,7 +252,7 @@ uint32_t be_strhash(const bstring *s)
|
|||
return cast(bcstring*, s)->hash;
|
||||
}
|
||||
#if BE_USE_STR_HASH_CACHE
|
||||
if (pgm_read_byte(&s->slen) != 255) {
|
||||
if (s->slen != 255) {
|
||||
return cast(bsstring*, s)->hash;
|
||||
}
|
||||
#endif
|
||||
|
@ -266,7 +265,7 @@ const char* be_str2cstr(const bstring *s)
|
|||
if (gc_isconst(s)) {
|
||||
return cstr(s);
|
||||
}
|
||||
if (pgm_read_byte(&s->slen) == 255) {
|
||||
if (s->slen == 255) {
|
||||
return lstr(s);
|
||||
}
|
||||
return sstr(s);
|
||||
|
@ -277,4 +276,4 @@ void be_str_setextra(bstring *s, int extra)
|
|||
if (!gc_isconst(s)) {
|
||||
s->extra = cast(bbyte, extra);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ typedef struct {
|
|||
} bcstring;
|
||||
|
||||
#define str_len(_s) \
|
||||
(pgm_read_byte(&(_s)->slen) == 255 ? cast(blstring*, _s)->llen : pgm_read_byte(&(_s)->slen))
|
||||
((_s)->slen == 255 ? cast(blstring*, _s)->llen : (_s)->slen)
|
||||
|
||||
#define str(_s) be_str2cstr(_s)
|
||||
#define str_extra(_s) ((_s)->extra)
|
||||
|
|
|
@ -176,7 +176,7 @@ const char* be_pushvfstr(bvm *vm, const char *format, va_list arg)
|
|||
}
|
||||
pushstr(vm, format, p - format);
|
||||
concat2(vm);
|
||||
switch (pgm_read_byte(&p[1])) {
|
||||
switch (p[1]) {
|
||||
case 's': {
|
||||
const char *s = va_arg(arg, char*);
|
||||
if (s == NULL) {
|
||||
|
@ -339,8 +339,8 @@ bstring* be_strindex(bvm *vm, bstring *str, bvalue *idx)
|
|||
const char* be_splitpath(const char *path)
|
||||
{
|
||||
const char *p;
|
||||
for (p = path - 1; pgm_read_byte(path) != '\0'; ++path) {
|
||||
if (pgm_read_byte(path) == '/') {
|
||||
for (p = path - 1; *path != '\0'; ++path) {
|
||||
if (*path == '/') {
|
||||
p = path;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -122,16 +122,16 @@ static int binary_search(int value)
|
|||
const uint16_t *high = tab + array_count(tab) - 1;
|
||||
while (low <= high) {
|
||||
const uint16_t *mid = low + ((high - low) >> 1);
|
||||
if (pgm_read_word(mid) == value) {
|
||||
return pgm_read_word(&mid[1]);
|
||||
if (*mid == value) {
|
||||
return mid[1];
|
||||
}
|
||||
if (pgm_read_word(mid) < value) {
|
||||
if (*mid < value) {
|
||||
low = mid + 1;
|
||||
} else {
|
||||
high = mid - 1;
|
||||
}
|
||||
}
|
||||
return pgm_read_word(low);
|
||||
return *low;
|
||||
}
|
||||
|
||||
static int nextpow(int value)
|
||||
|
|
|
@ -20,7 +20,8 @@ be_extern_native_module(debug);
|
|||
be_extern_native_module(gc);
|
||||
|
||||
/* Tasmota specific */
|
||||
be_extern_native_module(tasmota);
|
||||
be_extern_native_module(tasmota_ntv);
|
||||
be_extern_native_module(wire);
|
||||
|
||||
/* user-defined modules declare start */
|
||||
|
||||
|
@ -55,7 +56,8 @@ BERRY_LOCAL const bntvmodule* const be_module_table[] = {
|
|||
#endif
|
||||
/* user-defined modules register start */
|
||||
|
||||
&be_native_module(tasmota),
|
||||
&be_native_module(tasmota_ntv),
|
||||
&be_native_module(wire),
|
||||
|
||||
/* user-defined modules register end */
|
||||
NULL /* do not remove */
|
||||
|
|
|
@ -13,9 +13,16 @@ extern int l_millis(bvm *vm);
|
|||
extern int l_timereached(bvm *vm);
|
||||
extern int l_yield(bvm *vm);
|
||||
|
||||
extern int l_respCmnd(bvm *vm);
|
||||
extern int l_respCmndStr(bvm *vm);
|
||||
extern int l_respCmndDone(bvm *vm);
|
||||
extern int l_respCmndError(bvm *vm);
|
||||
extern int l_respCmndFailed(bvm *vm);
|
||||
|
||||
// #if !BE_USE_PRECOMPILED_OBJECT
|
||||
#if 1 // TODO we will do pre-compiled later
|
||||
be_native_module_attr_table(tasmota) {
|
||||
|
||||
be_native_module_attr_table(tasmota_ntv) {
|
||||
be_native_module_function("getfreeheap", l_getFreeHeap),
|
||||
be_native_module_function("publish", l_publish),
|
||||
be_native_module_function("cmd", l_cmd),
|
||||
|
@ -23,9 +30,17 @@ be_native_module_attr_table(tasmota) {
|
|||
be_native_module_function("millis", l_millis),
|
||||
be_native_module_function("timereached", l_timereached),
|
||||
be_native_module_function("yield", l_yield),
|
||||
|
||||
be_native_module_function("respcmnd", l_respCmnd),
|
||||
be_native_module_function("respcmndstr", l_respCmndStr),
|
||||
be_native_module_function("respcmnd_done", l_respCmndDone),
|
||||
be_native_module_function("respcmnd_error", l_respCmndError),
|
||||
be_native_module_function("respcmnd_failed", l_respCmndFailed),
|
||||
|
||||
be_native_module_str("_operators", "=<>!|"),
|
||||
};
|
||||
|
||||
be_define_native_module(tasmota, NULL);
|
||||
be_define_native_module(tasmota_ntv, NULL);
|
||||
#else
|
||||
/* @const_object_info_begin
|
||||
module tasmota (scope: global, depend: 1) {
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/********************************************************************
|
||||
* Tasmota lib
|
||||
*
|
||||
* To use: `import wire`
|
||||
*
|
||||
* 2 wire communication - I2C
|
||||
*******************************************************************/
|
||||
#include "be_object.h"
|
||||
|
||||
extern int b_wire_begintransmission(bvm *vm);
|
||||
extern int b_wire_endtransmission(bvm *vm);
|
||||
extern int b_wire_requestfrom(bvm *vm);
|
||||
extern int b_wire_available(bvm *vm);
|
||||
extern int b_wire_write(bvm *vm);
|
||||
extern int b_wire_read(bvm *vm);
|
||||
|
||||
// #if !BE_USE_PRECOMPILED_OBJECT
|
||||
#if 1 // TODO we will do pre-compiled later
|
||||
be_native_module_attr_table(wire) {
|
||||
be_native_module_function("begintransmission", b_wire_begintransmission),
|
||||
be_native_module_function("endtransmission", b_wire_endtransmission),
|
||||
be_native_module_function("requestfrom", b_wire_requestfrom),
|
||||
be_native_module_function("available", b_wire_available),
|
||||
be_native_module_function("write", b_wire_write),
|
||||
be_native_module_function("read", b_wire_read),
|
||||
};
|
||||
|
||||
be_define_native_module(wire, NULL);
|
||||
#else
|
||||
/* @const_object_info_begin
|
||||
module tasmota (scope: global, depend: 1) {
|
||||
getfreeheap, func(l_getFreeHeap)
|
||||
}
|
||||
@const_object_info_end */
|
||||
#include "../generate/be_fixed_tasmota.h"
|
||||
#endif
|
|
@ -8,19 +8,6 @@
|
|||
#ifndef BERRY_CONF_H
|
||||
#define BERRY_CONF_H
|
||||
|
||||
#include <pgmspace.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern int strncmp_PP(const char * str1P, const char * str2P, size_t size);
|
||||
extern char * strchr_P(const char *s, int c);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
/* Macro: BE_DEBUG
|
||||
|
@ -53,12 +40,12 @@ extern "C" {
|
|||
* Use precompiled objects to avoid creating these objects at
|
||||
* runtime. Enable this macro can greatly optimize RAM usage.
|
||||
* Default: 1
|
||||
**/
|
||||
#ifdef ESP8266
|
||||
#define BE_USE_PRECOMPILED_OBJECT 0
|
||||
#else
|
||||
#define BE_USE_PRECOMPILED_OBJECT 0 // will enable later when stabilized
|
||||
#endif
|
||||
// **/
|
||||
// #ifdef ESP8266
|
||||
// #define BE_USE_PRECOMPILED_OBJECT 0
|
||||
// #else
|
||||
#define BE_USE_PRECOMPILED_OBJECT 1 // will enable later when stabilized
|
||||
// #endif
|
||||
|
||||
/* Macro: BE_DEBUG_RUNTIME_INFO
|
||||
* Set runtime error debugging information.
|
||||
|
|
|
@ -20,6 +20,26 @@ def charsinstring(s,c)
|
|||
return -1
|
||||
end
|
||||
|
||||
###
|
||||
class Tasmota
|
||||
var _op, _operators, _rules
|
||||
def init()
|
||||
self._operators = "=<>!|"
|
||||
self._op = [
|
||||
['==', /s1,s2-> str(s1) == str(s2)],
|
||||
['!==',/s1,s2-> str(s1) != str(s2)],
|
||||
['=', /f1,f2-> real(f1) == real(f2)],
|
||||
['!=', /f1,f2-> real(f1) != real(f2)],
|
||||
['>=', /f1,f2-> real(f1) >= real(f2)],
|
||||
['<=', /f1,f2-> real(f1) <= real(f2)],
|
||||
['>', /f1,f2-> real(f1) > real(f2)],
|
||||
['<', /f1,f2-> real(f1) < real(f2)],
|
||||
]
|
||||
self._rules = {}
|
||||
end
|
||||
end
|
||||
###
|
||||
|
||||
tasmota._eqstr=/s1,s2-> str(s1) == str(s2)
|
||||
tasmota._neqstr=/s1,s2-> str(s1) != str(s2)
|
||||
tasmota._eq=/f1,f2-> real(f1) == real(f2)
|
||||
|
|
|
@ -0,0 +1,323 @@
|
|||
/*
|
||||
xdrv_52_3_berry_native.ino - Berry scripting language, native fucnctions
|
||||
|
||||
Copyright (C) 2021 Stephan Hadinger, Berry language by Guan Wenliang https://github.com/Skiars/berry
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifdef USE_BERRY
|
||||
|
||||
#include <berry.h>
|
||||
#include <Wire.h>
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Native functions mapped to Berry functions
|
||||
*
|
||||
* log(msg:string [,log_level:int]) ->nil
|
||||
*
|
||||
* import tasmota
|
||||
*
|
||||
* tasmota.getfreeheap() -> int
|
||||
* tasmota.publish(topic:string, payload:string[, retain:bool]) -> nil
|
||||
* tasmota.cmd(command:string) -> string
|
||||
* tasmota.getoption(index:int) -> int
|
||||
* tasmota.millis([delay:int]) -> int
|
||||
* tasmota.timereached(timer:int) -> bool
|
||||
* tasmota.yield() -> nil
|
||||
*
|
||||
\*********************************************************************************************/
|
||||
extern "C" {
|
||||
// Berry: `tasmota.publish(topic, payload [,retain]) -> nil``
|
||||
//
|
||||
int32_t l_publish(struct bvm *vm);
|
||||
int32_t l_publish(struct bvm *vm) {
|
||||
int32_t top = be_top(vm); // Get the number of arguments
|
||||
if (top >= 2 && be_isstring(vm, 1) && be_isstring(vm, 2)) { // 2 mandatory string arguments
|
||||
if (top == 2 || (top == 3 && be_isbool(vm, 3))) { // 3rd optional argument must be bool
|
||||
const char * topic = be_tostring(vm, 1);
|
||||
const char * payload = be_tostring(vm, 2);
|
||||
bool retain = false;
|
||||
if (top == 3) {
|
||||
retain = be_tobool(vm, 3);
|
||||
}
|
||||
strlcpy(TasmotaGlobal.mqtt_data, payload, sizeof(TasmotaGlobal.mqtt_data));
|
||||
MqttPublish(topic, retain);
|
||||
be_return(vm); // Return
|
||||
}
|
||||
}
|
||||
be_return_nil(vm); // Return nil when something goes wrong
|
||||
}
|
||||
|
||||
// Berry: `tasmota.cmd(command:string) -> string`
|
||||
//
|
||||
int32_t l_cmd(struct bvm *vm);
|
||||
int32_t l_cmd(struct bvm *vm) {
|
||||
int32_t top = be_top(vm); // Get the number of arguments
|
||||
if (top == 1 && be_isstring(vm, 1)) { // only 1 argument of type string accepted
|
||||
const char * command = be_tostring(vm, 1);
|
||||
ExecuteCommand(command, SRC_BERRY);
|
||||
be_pushstring(vm, TasmotaGlobal.mqtt_data);
|
||||
be_return(vm); // Return
|
||||
}
|
||||
be_return_nil(vm); // Return nil when something goes wrong
|
||||
}
|
||||
|
||||
// Berry: tasmota.millis([delay:int]) -> int
|
||||
//
|
||||
int32_t l_millis(struct bvm *vm);
|
||||
int32_t l_millis(struct bvm *vm) {
|
||||
int32_t top = be_top(vm); // Get the number of arguments
|
||||
if (top == 0 || (top == 1 && be_isint(vm, 1))) { // only 1 argument of type string accepted
|
||||
uint32_t delay = 0;
|
||||
if (top == 1) {
|
||||
delay = be_toint(vm, 1);
|
||||
}
|
||||
uint32_t ret_millis = millis() + delay;
|
||||
be_pushint(vm, ret_millis);
|
||||
be_return(vm); // Return
|
||||
}
|
||||
be_return_nil(vm); // Return nil when something goes wrong
|
||||
}
|
||||
|
||||
// Berry: tasmota.getoption(index:int) -> int
|
||||
//
|
||||
int32_t l_getoption(struct bvm *vm);
|
||||
int32_t l_getoption(struct bvm *vm) {
|
||||
int32_t top = be_top(vm); // Get the number of arguments
|
||||
if (top == 1 && be_isint(vm, 1)) {
|
||||
uint32_t opt = GetOption(be_toint(vm, 1));
|
||||
be_pushint(vm, opt);
|
||||
be_return(vm); // Return
|
||||
}
|
||||
be_return_nil(vm); // Return nil when something goes wrong
|
||||
}
|
||||
|
||||
// Berry: tasmota.timereached(timer:int) -> bool
|
||||
//
|
||||
int32_t l_timereached(struct bvm *vm);
|
||||
int32_t l_timereached(struct bvm *vm) {
|
||||
int32_t top = be_top(vm); // Get the number of arguments
|
||||
if (top == 1 && be_isint(vm, 1)) { // only 1 argument of type string accepted
|
||||
uint32_t timer = be_toint(vm, 1);
|
||||
bool reached = TimeReached(timer);
|
||||
be_pushbool(vm, reached);
|
||||
be_return(vm); // Return
|
||||
}
|
||||
be_return_nil(vm); // Return nil when something goes wrong
|
||||
}
|
||||
|
||||
// Berry: `yield() -> nil`
|
||||
// ESP object
|
||||
int32_t l_yield(bvm *vm);
|
||||
int32_t l_yield(bvm *vm) {
|
||||
optimistic_yield(10);
|
||||
be_return(vm);
|
||||
}
|
||||
|
||||
// Berry: `save(file:string, f:closure) -> bool`
|
||||
int32_t l_save(struct bvm *vm);
|
||||
int32_t l_save(struct bvm *vm) {
|
||||
int32_t top = be_top(vm); // Get the number of arguments
|
||||
if (top ==2 && be_isstring(vm, 1) && be_isclosure(vm, 2)) { // only 1 argument of type string accepted
|
||||
const char *fname = be_tostring(vm, 1);
|
||||
int32_t ret = be_savecode(vm, fname);
|
||||
be_pushint(vm, ret);
|
||||
be_return(vm); // Return
|
||||
}
|
||||
be_return_nil(vm); // Return nil when something goes wrong
|
||||
}
|
||||
|
||||
int32_t l_respCmnd(bvm *vm);
|
||||
int32_t l_respCmnd(bvm *vm) {
|
||||
int32_t top = be_top(vm); // Get the number of arguments
|
||||
if (top == 1) {
|
||||
const char *msg = be_tostring(vm, 1);
|
||||
Response_P("%s", msg);
|
||||
}
|
||||
be_return_nil(vm); // Return nil when something goes wrong
|
||||
}
|
||||
|
||||
int32_t l_respCmndStr(bvm *vm);
|
||||
int32_t l_respCmndStr(bvm *vm) {
|
||||
int32_t top = be_top(vm); // Get the number of arguments
|
||||
if (top == 1) {
|
||||
const char *msg = be_tostring(vm, 1);
|
||||
ResponseCmndChar(msg);
|
||||
}
|
||||
be_return_nil(vm); // Return nil when something goes wrong
|
||||
}
|
||||
|
||||
int32_t l_respCmndDone(bvm *vm);
|
||||
int32_t l_respCmndDone(bvm *vm) {
|
||||
ResponseCmndDone();
|
||||
be_return_nil(vm);
|
||||
}
|
||||
|
||||
int32_t l_respCmndError(bvm *vm);
|
||||
int32_t l_respCmndError(bvm *vm) {
|
||||
ResponseCmndError();
|
||||
be_return_nil(vm);
|
||||
}
|
||||
|
||||
int32_t l_respCmndFailed(bvm *vm);
|
||||
int32_t l_respCmndFailed(bvm *vm) {
|
||||
ResponseCmndFailed();
|
||||
be_return_nil(vm);
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Native functions mapped to Berry functions
|
||||
*
|
||||
* import wire
|
||||
*
|
||||
* wire.getfreeheap() -> int
|
||||
*
|
||||
\*********************************************************************************************/
|
||||
extern "C" {
|
||||
// Berry: `begintransmission(address:int) -> nil`
|
||||
int32_t b_wire_begintransmission(struct bvm *vm);
|
||||
int32_t b_wire_begintransmission(struct bvm *vm) {
|
||||
int32_t top = be_top(vm); // Get the number of arguments
|
||||
if (top == 1 && be_isint(vm, 1)) { // only 1 argument of type string accepted
|
||||
int32_t address = be_toint(vm, 1);
|
||||
Wire.beginTransmission(address);
|
||||
be_return(vm); // Return
|
||||
}
|
||||
be_return_nil(vm); // Return nil when something goes wrong
|
||||
}
|
||||
|
||||
// Berry: `endtransmission([stop:bool]) -> nil`
|
||||
int32_t b_wire_endtransmission(struct bvm *vm);
|
||||
int32_t b_wire_endtransmission(struct bvm *vm) {
|
||||
int32_t top = be_top(vm); // Get the number of arguments
|
||||
if (top == 0 || (top == 1 && be_isbool(vm, 1))) { // only 1 argument of type string accepted
|
||||
bool stop = true;
|
||||
if (top == 1) {
|
||||
stop = be_tobool(vm, 1);
|
||||
}
|
||||
uint32_t ret = Wire.endTransmission(stop);
|
||||
be_pushint(vm, ret);
|
||||
be_return(vm); // Return
|
||||
}
|
||||
be_return_nil(vm); // Return nil when something goes wrong
|
||||
}
|
||||
|
||||
// Berry: `requestfrom(address:int, quantity:int [stop:bool = true]) -> nil`
|
||||
int32_t b_wire_requestfrom(struct bvm *vm);
|
||||
int32_t b_wire_requestfrom(struct bvm *vm) {
|
||||
int32_t top = be_top(vm); // Get the number of arguments
|
||||
if ( (top == 2 || (top == 3 && be_isbool(vm, 3)))
|
||||
&& be_isint(vm, 1) && be_isint(vm, 2) ) {
|
||||
int32_t address = be_toint(vm, 1);
|
||||
int32_t quantity = be_toint(vm, 2);
|
||||
bool stop = true;
|
||||
if (top == 3) {
|
||||
stop = be_tobool(vm, 3);
|
||||
}
|
||||
Wire.requestFrom((uint16_t)address, (uint8_t)quantity, stop);
|
||||
be_return(vm); // Return
|
||||
}
|
||||
be_return_nil(vm); // Return nil when something goes wrong
|
||||
}
|
||||
|
||||
// Berry: `available() -> bool`
|
||||
int32_t b_wire_available(struct bvm *vm);
|
||||
int32_t b_wire_available(struct bvm *vm) {
|
||||
int32_t top = be_top(vm); // Get the number of arguments
|
||||
if (top == 0) {
|
||||
size_t available = Wire.available();
|
||||
be_pushint(vm, available);
|
||||
be_return(vm); // Return
|
||||
}
|
||||
be_return_nil(vm); // Return nil when something goes wrong
|
||||
}
|
||||
|
||||
// Berry: `write(value:int | s:string) -> nil`
|
||||
int32_t b_wire_write(struct bvm *vm);
|
||||
int32_t b_wire_write(struct bvm *vm) {
|
||||
int32_t top = be_top(vm); // Get the number of arguments
|
||||
if (top == 1 && (be_isint(vm, 1) || be_isint(vm, 1))) {
|
||||
if (be_isint(vm, 1)) {
|
||||
int32_t value = be_toint(vm, 1);
|
||||
Wire.write(value);
|
||||
} else if (be_isstring(vm, 1)) {
|
||||
const char * s = be_tostring(vm, 1);
|
||||
Wire.write(s);
|
||||
} else {
|
||||
be_return_nil(vm);
|
||||
}
|
||||
be_return(vm); // Return
|
||||
}
|
||||
be_return_nil(vm); // Return nil when something goes wrong
|
||||
}
|
||||
|
||||
// Berry: `read() -> int`
|
||||
int32_t b_wire_read(struct bvm *vm);
|
||||
int32_t b_wire_read(struct bvm *vm) {
|
||||
int32_t top = be_top(vm); // Get the number of arguments
|
||||
if (top == 0) {
|
||||
int32_t value = Wire.read();
|
||||
be_pushint(vm, value);
|
||||
be_return(vm); // Return
|
||||
}
|
||||
be_return_nil(vm); // Return nil when something goes wrong
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Native functions mapped to Berry functions
|
||||
*
|
||||
* log(msg:string [,log_level:int]) ->nil
|
||||
*
|
||||
\*********************************************************************************************/
|
||||
extern "C" {
|
||||
// Berry: `log(msg:string [,log_level:int]) ->nil`
|
||||
// Logs the string at LOG_LEVEL_INFO (loglevel=2)
|
||||
int32_t l_logInfo(struct bvm *vm);
|
||||
int32_t l_logInfo(struct bvm *vm) {
|
||||
int32_t top = be_top(vm); // Get the number of arguments
|
||||
if (top >= 1 && be_isstring(vm, 1)) { // only 1 argument of type string accepted
|
||||
const char * msg = be_tostring(vm, 1);
|
||||
uint32_t log_level = LOG_LEVEL_INFO;
|
||||
if (top >= 2 && be_isint(vm, 2)) {
|
||||
log_level = be_toint(vm, 2);
|
||||
if (log_level > LOG_LEVEL_DEBUG_MORE) { log_level = LOG_LEVEL_DEBUG_MORE; }
|
||||
}
|
||||
AddLog(log_level, PSTR("%s"), msg);
|
||||
be_return(vm); // Return
|
||||
}
|
||||
be_return_nil(vm); // Return nil when something goes wrong
|
||||
}
|
||||
|
||||
// Berry: `getFreeHeap() -> int`
|
||||
// ESP object
|
||||
int32_t l_getFreeHeap(bvm *vm);
|
||||
int32_t l_getFreeHeap(bvm *vm) {
|
||||
be_pushint(vm, ESP.getFreeHeap());
|
||||
be_return(vm);
|
||||
}
|
||||
}
|
||||
|
||||
// called as a replacement to Berry `print()`
|
||||
void berry_log(const char * berry_buf);
|
||||
void berry_log(const char * berry_buf) {
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("%s"), berry_buf);
|
||||
}
|
||||
|
||||
|
||||
#endif // USE_BERRY
|
|
@ -0,0 +1,281 @@
|
|||
/*
|
||||
xdrv_52_3_berry_embedded.ino - Berry scripting language, embedded code
|
||||
|
||||
Copyright (C) 2021 Stephan Hadinger, Berry language by Guan Wenliang https://github.com/Skiars/berry
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifdef USE_BERRY
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Handlers for Berry calls and async
|
||||
*
|
||||
\*********************************************************************************************/
|
||||
|
||||
const char berry_prog[] =
|
||||
""
|
||||
//"def func(x) for i:1..x print('a') end end "
|
||||
//"def testreal() return str(1.2+1) end "
|
||||
//"def noop() log('noop before'); yield(); log('middle after'); yield(); log('noop after'); end "
|
||||
//"log(\"foobar\") "
|
||||
|
||||
// auto-import modules
|
||||
// // import alias
|
||||
"import wire "
|
||||
|
||||
// Phase 1
|
||||
// Prepare the super class that will be eventually in Flash
|
||||
"class Tasmota_ntv "
|
||||
"var _op, _operators, _rules, _timers, _cmd "
|
||||
|
||||
// Map all native functions to methods
|
||||
// Again, this will be eventually pre-compiled
|
||||
"var getfreeheap, publish, cmd, getoption, millis, timereached, yield "
|
||||
"var respcmnd, respcmndstr, respcmnd_done, respcmnd_error, respcmnd_failed "
|
||||
"def init_ntv() "
|
||||
"import tasmota_ntv "
|
||||
"self.getfreeheap = tasmota_ntv.getfreeheap "
|
||||
"self.publish = tasmota_ntv.publish "
|
||||
"self.cmd = tasmota_ntv.cmd "
|
||||
"self.getoption = tasmota_ntv.getoption "
|
||||
"self.millis = tasmota_ntv.millis "
|
||||
"self.timereached = tasmota_ntv.timereached "
|
||||
"self.yield = tasmota_ntv.yield "
|
||||
"self._operators = tasmota_ntv._operators "
|
||||
|
||||
"self.respcmnd = tasmota_ntv.respcmnd "
|
||||
"self.respcmndstr = tasmota_ntv.respcmndstr "
|
||||
"self.respcmnd_done = tasmota_ntv.respcmnd_done "
|
||||
"self.respcmnd_error = tasmota_ntv.respcmnd_error "
|
||||
"self.respcmnd_failed = tasmota_ntv.respcmnd_failed "
|
||||
"end "
|
||||
|
||||
"def init() "
|
||||
"self._op = [ "
|
||||
"['==', /s1,s2-> str(s1) == str(s2)],"
|
||||
"['!==',/s1,s2-> str(s1) != str(s2)],"
|
||||
"['=', /f1,f2-> real(f1) == real(f2)],"
|
||||
"['!=', /f1,f2-> real(f1) != real(f2)],"
|
||||
"['>=', /f1,f2-> real(f1) >= real(f2)],"
|
||||
"['<=', /f1,f2-> real(f1) <= real(f2)],"
|
||||
"['>', /f1,f2-> real(f1) > real(f2)],"
|
||||
"['<', /f1,f2-> real(f1) < real(f2)],"
|
||||
"] "
|
||||
"self._rules = {} "
|
||||
"self._timers = [] "
|
||||
"self._cmd = {} "
|
||||
"self.init_ntv() "
|
||||
"end "
|
||||
"end "
|
||||
|
||||
"class Tasmota: Tasmota_ntv "
|
||||
// add `charsinstring(s:string,c:string) -> int``
|
||||
// looks for any char in c, and return the position of the first chat
|
||||
// or -1 if not found
|
||||
"def charsinstring(s,c) "
|
||||
"for i:0..size(s)-1 "
|
||||
"for j:0..size(c)-1 "
|
||||
"if s[i] == c[j] return i end "
|
||||
"end "
|
||||
"end "
|
||||
"return -1 "
|
||||
"end "
|
||||
|
||||
// find a key in map, case insensitive, return actual key or nil if not found
|
||||
"def findkeyi(m,keyi) "
|
||||
"import string "
|
||||
"var keyu = string.toupper(keyi) "
|
||||
"if classof(m) == map "
|
||||
"for k:m.keys() "
|
||||
"if string.toupper(k)==keyu || keyi=='?' "
|
||||
"return k "
|
||||
"end "
|
||||
"end "
|
||||
"end "
|
||||
"end "
|
||||
|
||||
// Rules
|
||||
"def addrule(pat,f) self._rules[pat] = f end "
|
||||
|
||||
// # split the item when there is an operator, returns a list of (left,op,right)
|
||||
// # ex: "Dimmer>50" -> ["Dimmer",tasmota_gt,"50"]
|
||||
"def find_op(item) "
|
||||
"import string "
|
||||
"var pos = self.charsinstring(item, self._operators) "
|
||||
"if pos>=0 "
|
||||
"var op_split = string.split(item,pos) "
|
||||
// #print(op_split)
|
||||
"var op_left = op_split[0] "
|
||||
"var op_rest = op_split[1] "
|
||||
// # iterate through operators
|
||||
"for op: self._op "
|
||||
"if string.find(op_rest,op[0]) == 0 "
|
||||
"var op_func = op[1] "
|
||||
"var op_right = string.split(op_rest,size(op[0]))[1] "
|
||||
"return [op_left,op_func,op_right] "
|
||||
"end "
|
||||
"end "
|
||||
"end "
|
||||
"return [item, nil, nil] "
|
||||
"end "
|
||||
|
||||
// Rules trigger if match. return true if match, false if not
|
||||
// Note: condition is not yet managed
|
||||
"def try_rule(ev, rule, f) "
|
||||
"import string "
|
||||
"var rl_list = self.find_op(rule) "
|
||||
"var e=ev "
|
||||
"var rl=string.split(rl_list[0],'#') "
|
||||
"for it:rl "
|
||||
"found=self.findkeyi(e,it) "
|
||||
"if found == nil "
|
||||
"return false "
|
||||
"end "
|
||||
"e=e[found] "
|
||||
"end "
|
||||
// # check if condition is true
|
||||
"if rl_list[1] "
|
||||
// # did we find a function
|
||||
"if !rl_list[1](e,rl_list[2]) "
|
||||
// # condition is not met
|
||||
"return false "
|
||||
"end "
|
||||
"end "
|
||||
"f(e,ev) "
|
||||
"return true "
|
||||
"end "
|
||||
|
||||
// Run rules, i.e. check each individual rule
|
||||
// Returns true if at least one rule matched, false if none
|
||||
"def exec_rules(ev_json) "
|
||||
"import json "
|
||||
"var ev = json.load(ev_json) "
|
||||
"var ret = false "
|
||||
"if ev == nil "
|
||||
"print('BRY: ERROR, bad json: '+ev_json, 3) "
|
||||
"else "
|
||||
"for r: self._rules.keys() "
|
||||
"ret = self.try_rule(ev,r,self._rules[r]) || ret "
|
||||
"end "
|
||||
"end "
|
||||
"return ret "
|
||||
"end "
|
||||
|
||||
"def settimer(delay,f) self._timers.push([self.millis(delay),f]) end "
|
||||
|
||||
"def run_deferred() "
|
||||
"var i=0 "
|
||||
"while i<self._timers.size() "
|
||||
"if self.timereached(self._timers[i][0]) "
|
||||
"f=self._timers[i][1] "
|
||||
"self._timers.remove(i) "
|
||||
"f() "
|
||||
"else "
|
||||
"i=i+1 "
|
||||
"end "
|
||||
"end "
|
||||
"end "
|
||||
|
||||
// Delay function, internally calls yield() every 10ms to avoid WDT
|
||||
"def delay(ms) "
|
||||
"var tend = self.millis(ms) "
|
||||
"while !self.timereached(tend) "
|
||||
"self.yield() "
|
||||
"end "
|
||||
"end "
|
||||
|
||||
// Add command to list
|
||||
"def addcommand(c,f) "
|
||||
"self._cmd[c]=f "
|
||||
"end "
|
||||
|
||||
"def exec_cmd(cmd, idx, payload) "
|
||||
"import json "
|
||||
"var payload_json = json.load(payload) "
|
||||
"var cmd_found = self.findkeyi(self._cmd, cmd) "
|
||||
"if cmd_found != nil "
|
||||
"return self._cmd[cmd_found](cmd_found, idx, payload, payload_json) "
|
||||
"end "
|
||||
"end "
|
||||
|
||||
// Force gc and return allocated memory
|
||||
"def gc() "
|
||||
"import gc "
|
||||
"gc.collect() "
|
||||
"return gc.allocated() "
|
||||
"end "
|
||||
|
||||
"end "
|
||||
|
||||
// Instantiate tasmota object
|
||||
"tasmota = Tasmota() "
|
||||
|
||||
// Not sure how to run call methods from C
|
||||
"def _exec_rules(e) return tasmota.exec_rules(e) end "
|
||||
"def _run_deferred() return tasmota.run_deferred() end "
|
||||
"def _exec_cmd(cmd, idx, payload) return tasmota.exec_cmd(cmd, idx, payload) end "
|
||||
"def _gc() return tasmota.gc() end "
|
||||
|
||||
// simple wrapper to load a file
|
||||
// prefixes '/' if needed, and simpler to use than `compile()`
|
||||
"def load(f) "
|
||||
"import string "
|
||||
"try "
|
||||
// check that the file ends with '.be' of '.bec'
|
||||
"var fl = string.split(f,'.') "
|
||||
"if (size(fl) <= 1 || (fl[-1] != 'be' && fl[-1] != 'bec')) "
|
||||
"raise \"file extension is not '.be' or '.bec'\" "
|
||||
"end "
|
||||
"var native = f[size(f)-1] == 'c' "
|
||||
// add prefix if needed
|
||||
"if f[0] != '/' f = '/' + f end "
|
||||
// load - works the same for .be and .bec
|
||||
"var c = compile(f,'file') "
|
||||
// save the compiled bytecode
|
||||
"if !native "
|
||||
"save(f+'c', c) "
|
||||
"end "
|
||||
// call the compiled code
|
||||
"c() "
|
||||
"except .. as e "
|
||||
"log(string.format(\"BRY: could not load file '%s' - %s\",f,e)) "
|
||||
"end "
|
||||
"end "
|
||||
|
||||
// try to load "/autoexec.be"
|
||||
// "try compile('/autoexec.be','file')() except .. log('BRY: no /autoexec.bat file') end "
|
||||
|
||||
// Wire
|
||||
"wire.validread = def(addr, reg, size) "
|
||||
"var ret = nil "
|
||||
"for i:0..2 "
|
||||
"wire.begintransmission(addr) "
|
||||
"wire.write(reg) "
|
||||
"if wire.endtransmission(false) == 0 "
|
||||
"wire.requestfrom(addr, size) "
|
||||
"if wire.available() == size "
|
||||
"for j:0..size-1 "
|
||||
"ret = ((ret != nil ? ret : 0) << 8) + wire.read() "
|
||||
"end "
|
||||
"return ret "
|
||||
"end "
|
||||
"end "
|
||||
"end "
|
||||
"wire.endtransmission() "
|
||||
"end "
|
||||
;
|
||||
|
||||
#endif // USE_BERRY
|
|
@ -0,0 +1,354 @@
|
|||
/*
|
||||
xdrv_52_9_berry.ino - Berry scripting language
|
||||
|
||||
Copyright (C) 2021 Stephan Hadinger, Berry language by Guan Wenliang https://github.com/Skiars/berry
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifdef USE_BERRY
|
||||
|
||||
#define XDRV_52 52
|
||||
|
||||
#include <berry.h>
|
||||
|
||||
const char kBrCommands[] PROGMEM = D_PRFX_BR "|" // prefix
|
||||
D_CMND_BR_RUN "|" D_CMND_BR_RESET
|
||||
;
|
||||
|
||||
void (* const BerryCommand[])(void) PROGMEM = {
|
||||
CmndBrRun, CmndBrReset,
|
||||
};
|
||||
|
||||
class BerrySupport {
|
||||
public:
|
||||
bvm *vm = nullptr; // berry vm
|
||||
bool rules_busy = false; // are we already processing rules, avoid infinite loop
|
||||
const char *fname = nullptr; // name of berry function to call
|
||||
int32_t fret = 0;
|
||||
};
|
||||
BerrySupport berry;
|
||||
|
||||
//
|
||||
// Sanity Check for be_top()
|
||||
//
|
||||
// Checks that the Berry stack is empty, if not print a Warning and empty it
|
||||
//
|
||||
void checkBeTop(void) {
|
||||
int32_t top = be_top(berry.vm);
|
||||
if (top != 0) {
|
||||
be_pop(berry.vm, top); // TODO should not be there
|
||||
AddLog(LOG_LEVEL_ERROR, D_LOG_BERRY "Error be_top is non zero=%d", top);
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Handlers for Berry calls and async
|
||||
*
|
||||
\*********************************************************************************************/
|
||||
// // call a function (if exists) of type void -> void
|
||||
// void callBerryFunctionVoid_berry(const char * fname) {
|
||||
// berry.fret = 0;
|
||||
// callBerryFunctionVoid(berry.fname);
|
||||
// }
|
||||
|
||||
bool callBerryRule(void) {
|
||||
if (berry.rules_busy) { return false; }
|
||||
berry.rules_busy = true;
|
||||
char * json_event = TasmotaGlobal.mqtt_data;
|
||||
bool serviced = false;
|
||||
|
||||
checkBeTop();
|
||||
be_getglobal(berry.vm, "_exec_rules");
|
||||
if (!be_isnil(berry.vm, -1)) {
|
||||
|
||||
// {
|
||||
// String event_saved = TasmotaGlobal.mqtt_data;
|
||||
// // json_event = {"INA219":{"Voltage":4.494,"Current":0.020,"Power":0.089}}
|
||||
// // json_event = {"System":{"Boot":1}}
|
||||
// // json_event = {"SerialReceived":"on"} - invalid but will be expanded to {"SerialReceived":{"Data":"on"}}
|
||||
// char *p = strchr(json_event, ':');
|
||||
// if ((p != NULL) && !(strchr(++p, ':'))) { // Find second colon
|
||||
// event_saved.replace(F(":"), F(":{\"Data\":"));
|
||||
// event_saved += F("}");
|
||||
// // event_saved = {"SerialReceived":{"Data":"on"}}
|
||||
// }
|
||||
// be_pushstring(berry.vm, event_saved.c_str());
|
||||
// }
|
||||
be_pushstring(berry.vm, TasmotaGlobal.mqtt_data);
|
||||
int ret = be_pcall(berry.vm, 1);
|
||||
serviced = be_tobool(berry.vm, 1);
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_BERRY "Event (%s) serviced=%d"), TasmotaGlobal.mqtt_data, serviced);
|
||||
be_pop(berry.vm, 2); // remove function object
|
||||
} else {
|
||||
be_pop(berry.vm, 1); // remove nil object
|
||||
}
|
||||
checkBeTop();
|
||||
berry.rules_busy = false;
|
||||
|
||||
return serviced; // TODO event not handled
|
||||
}
|
||||
|
||||
bool callBerryCommand(void) {
|
||||
const char * command = nullptr;
|
||||
|
||||
checkBeTop();
|
||||
be_getglobal(berry.vm, "_exec_cmd");
|
||||
if (!be_isnil(berry.vm, -1)) {
|
||||
be_pushstring(berry.vm, XdrvMailbox.topic);
|
||||
be_pushint(berry.vm, XdrvMailbox.index);
|
||||
be_pushstring(berry.vm, XdrvMailbox.data);
|
||||
int ret = be_pcall(berry.vm, 3);
|
||||
command = be_tostring(berry.vm, 3);
|
||||
strlcpy(XdrvMailbox.topic, command, CMDSZ);
|
||||
// AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_BERRY "Command (%s) serviced=%d"), XdrvMailbox.command, serviced);
|
||||
be_pop(berry.vm, 4); // remove function object
|
||||
} else {
|
||||
be_pop(berry.vm, 1); // remove nil object
|
||||
}
|
||||
checkBeTop();
|
||||
|
||||
return command != nullptr; // TODO event not handled
|
||||
}
|
||||
|
||||
size_t callBerryGC(void) {
|
||||
size_t ram_used = 0;
|
||||
checkBeTop();
|
||||
be_getglobal(berry.vm, "_gc");
|
||||
if (!be_isnil(berry.vm, -1)) {
|
||||
int ret = be_pcall(berry.vm, 0);
|
||||
ram_used = be_toint(berry.vm, 1);
|
||||
be_pop(berry.vm, 1); // remove function object
|
||||
} else {
|
||||
be_pop(berry.vm, 1); // remove nil object
|
||||
}
|
||||
checkBeTop();
|
||||
|
||||
return ram_used;
|
||||
}
|
||||
|
||||
// void callBerryMqttData(void) {
|
||||
// AddLog(LOG_LEVEL_INFO, D_LOG_BERRY "callBerryMqttData");
|
||||
// if (nullptr == berry.vm) { return; }
|
||||
// if (XdrvMailbox.data_len < 1) {
|
||||
// return;
|
||||
// }
|
||||
// const char * topic = XdrvMailbox.topic;
|
||||
// const char * payload = XdrvMailbox.data;
|
||||
|
||||
// checkBeTop();
|
||||
// be_getglobal(berry.vm, "mqtt_data_dispatch");
|
||||
// if (!be_isnil(berry.vm, -1)) {
|
||||
// be_pushstring(berry.vm, topic);
|
||||
// be_pushstring(berry.vm, payload);
|
||||
// be_pcall(berry.vm, 0);
|
||||
// be_pop(berry.vm, 3); // remove function object
|
||||
// } else {
|
||||
// be_pop(berry.vm, 1); // remove nil object
|
||||
// }
|
||||
// checkBeTop();
|
||||
// }
|
||||
|
||||
// call a function (if exists) of type void -> void
|
||||
void callBerryFunctionVoid(const char * fname) {
|
||||
if (nullptr == berry.vm) { return; }
|
||||
checkBeTop();
|
||||
be_getglobal(berry.vm, fname);
|
||||
if (!be_isnil(berry.vm, -1)) {
|
||||
be_pcall(berry.vm, 0);
|
||||
}
|
||||
be_pop(berry.vm, 1); // remove function or nil object
|
||||
checkBeTop();
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* VM Init
|
||||
\*********************************************************************************************/
|
||||
extern "C" {
|
||||
extern size_t be_gc_memcount(bvm *vm);
|
||||
extern void be_gc_collect(bvm *vm);
|
||||
}
|
||||
void BrReset(void) {
|
||||
// clean previous VM if any
|
||||
if (berry.vm != nullptr) {
|
||||
be_vm_delete(berry.vm);
|
||||
berry.vm = nullptr;
|
||||
}
|
||||
|
||||
int32_t ret_code1, ret_code2;
|
||||
bool berry_init_ok = false;
|
||||
do {
|
||||
berry.vm = be_vm_new(); /* create a virtual machine instance */
|
||||
// AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_BERRY "Berry VM created, RAM used=%u"), be_gc_memcount(berry.vm));
|
||||
|
||||
// Register functions
|
||||
be_regfunc(berry.vm, PSTR("log"), l_logInfo);
|
||||
be_regfunc(berry.vm, PSTR("save"), l_save);
|
||||
|
||||
// AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_BERRY "Berry function registered, RAM used=%u"), be_gc_memcount(berry.vm));
|
||||
|
||||
ret_code1 = be_loadstring(berry.vm, berry_prog);
|
||||
if (ret_code1 != 0) {
|
||||
AddLog(LOG_LEVEL_ERROR, PSTR(D_LOG_BERRY "ERROR: be_loadstring [%s] %s"), be_tostring(berry.vm, -2), be_tostring(berry.vm, -1));
|
||||
be_pop(berry.vm, 2);
|
||||
break;
|
||||
}
|
||||
// AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_BERRY "Berry code loaded, RAM used=%u"), be_gc_memcount(berry.vm));
|
||||
ret_code2 = be_pcall(berry.vm, 0);
|
||||
if (ret_code1 != 0) {
|
||||
AddLog(LOG_LEVEL_ERROR, PSTR(D_LOG_BERRY "ERROR: be_pcall [%s] %s"), be_tostring(berry.vm, -2), be_tostring(berry.vm, -1));
|
||||
be_pop(berry.vm, 2);
|
||||
break;
|
||||
}
|
||||
// AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_BERRY "Berry code ran, RAM used=%u"), be_gc_memcount(berry.vm));
|
||||
be_pop(berry.vm, 1);
|
||||
|
||||
be_gc_collect(berry.vm);
|
||||
AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_BERRY "Berry initialized, RAM used=%u"), callBerryGC());
|
||||
// AddLog(LOG_LEVEL_INFO, PSTR("Delete Berry VM"));
|
||||
// be_vm_delete(vm);
|
||||
// AddLog(LOG_LEVEL_INFO, PSTR("After Berry"));
|
||||
|
||||
berry_init_ok = true;
|
||||
} while (0);
|
||||
|
||||
if (!berry_init_ok) {
|
||||
// free resources
|
||||
if (berry.vm != nullptr) {
|
||||
be_vm_delete(berry.vm);
|
||||
berry.vm = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Tasmota Commands
|
||||
\*********************************************************************************************/
|
||||
//
|
||||
// Command `BrRun`
|
||||
//
|
||||
void CmndBrRun(void) {
|
||||
int32_t ret_code;
|
||||
const char * ret_type, * ret_val;
|
||||
|
||||
if (berry.vm == nullptr) { ResponseCmndChar_P(PSTR(D_BR_NOT_STARTED)); return; }
|
||||
|
||||
char br_cmd[XdrvMailbox.data_len+12];
|
||||
// encapsulate into a function, copied from `be_repl.c` / `try_return()`
|
||||
snprintf_P(br_cmd, sizeof(br_cmd), PSTR("return (%s)"), XdrvMailbox.data);
|
||||
|
||||
checkBeTop();
|
||||
do {
|
||||
// First try with the `return ()` wrapper
|
||||
ret_code = be_loadbuffer(berry.vm, PSTR("input"), br_cmd, strlen(br_cmd));
|
||||
if (be_getexcept(berry.vm, ret_code) == BE_SYNTAX_ERROR) {
|
||||
be_pop(berry.vm, 2); // remove exception values
|
||||
// if fails, try the direct command
|
||||
ret_code = be_loadbuffer(berry.vm, PSTR("input"), XdrvMailbox.data, strlen(XdrvMailbox.data));
|
||||
}
|
||||
if (0 != ret_code) break;
|
||||
|
||||
ret_code = be_pcall(berry.vm, 0); // execute code
|
||||
} while (0);
|
||||
|
||||
if (0 == ret_code) {
|
||||
// code taken from REPL, look first at top, and if nil, look at return value
|
||||
if (be_isnil(berry.vm, 0)) {
|
||||
ret_val = be_tostring(berry.vm, -1);
|
||||
} else {
|
||||
ret_val = be_tostring(berry.vm, 0);
|
||||
}
|
||||
Response_P("{\"" D_PRFX_BR "\":\"%s\"}", ret_val); // can't use XdrvMailbox.command as it may have been overwritten by subcommand
|
||||
be_pop(berry.vm, 1);
|
||||
} else {
|
||||
Response_P(PSTR("{\"" D_PRFX_BR "\":\"[%s] %s\"}"), be_tostring(berry.vm, -2), be_tostring(berry.vm, -1));
|
||||
be_pop(berry.vm, 2);
|
||||
}
|
||||
|
||||
checkBeTop();
|
||||
}
|
||||
|
||||
//
|
||||
// Command `BrReset`
|
||||
//
|
||||
void CmndBrReset(void) {
|
||||
if (berry.vm == nullptr) { ResponseCmndChar_P(PSTR(D_BR_NOT_STARTED)); return; }
|
||||
|
||||
BrReset();
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Interface
|
||||
\*********************************************************************************************/
|
||||
bool Xdrv52(uint8_t function)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
switch (function) {
|
||||
//case FUNC_PRE_INIT:
|
||||
case FUNC_INIT:
|
||||
BrReset();
|
||||
break;
|
||||
case FUNC_EVERY_50_MSECOND:
|
||||
callBerryFunctionVoid(PSTR("_run_deferred"));
|
||||
break;
|
||||
case FUNC_EVERY_100_MSECOND:
|
||||
callBerryFunctionVoid(PSTR("every_100ms"));
|
||||
break;
|
||||
case FUNC_EVERY_SECOND:
|
||||
callBerryFunctionVoid(PSTR("every_second"));
|
||||
break;
|
||||
case FUNC_COMMAND:
|
||||
result = DecodeCommand(kBrCommands, BerryCommand);
|
||||
if (!result) {
|
||||
result = callBerryCommand();
|
||||
}
|
||||
break;
|
||||
// case FUNC_SET_POWER:
|
||||
// break;
|
||||
case FUNC_RULES_PROCESS:
|
||||
result = callBerryRule();
|
||||
break;
|
||||
#ifdef USE_WEBSERVER
|
||||
case FUNC_WEB_ADD_BUTTON:
|
||||
break;
|
||||
case FUNC_WEB_ADD_MAIN_BUTTON:
|
||||
|
||||
break;
|
||||
case FUNC_WEB_ADD_HANDLER:
|
||||
break;
|
||||
#endif // USE_WEBSERVER
|
||||
case FUNC_SAVE_BEFORE_RESTART:
|
||||
break;
|
||||
case FUNC_MQTT_DATA:
|
||||
// callBerryMqttData();
|
||||
break;
|
||||
case FUNC_WEB_SENSOR:
|
||||
break;
|
||||
|
||||
case FUNC_JSON_APPEND:
|
||||
break;
|
||||
|
||||
case FUNC_BUTTON_PRESSED:
|
||||
break;
|
||||
|
||||
case FUNC_LOOP:
|
||||
break;
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // USE_BERRY
|
|
@ -1,650 +0,0 @@
|
|||
/*
|
||||
xdrv_52_berry.ino - Berry scripting language
|
||||
|
||||
Copyright (C) 2021 Stephan Hadinger, Berry language by Guan Wenliang https://github.com/Skiars/berry
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifdef USE_BERRY
|
||||
|
||||
#define XDRV_52 52
|
||||
|
||||
#include <berry.h>
|
||||
#include <csetjmp>
|
||||
|
||||
const char kBrCommands[] PROGMEM = D_PRFX_BR "|" // prefix
|
||||
D_CMND_BR_RUN "|" D_CMND_BR_RESET
|
||||
;
|
||||
|
||||
void (* const BerryCommand[])(void) PROGMEM = {
|
||||
CmndBrRun, CmndBrReset,
|
||||
};
|
||||
|
||||
class BerrySupport {
|
||||
public:
|
||||
bvm *vm = nullptr; // berry vm
|
||||
bool rules_busy = false; // are we already processing rules, avoid infinite loop
|
||||
const char *fname = nullptr; // name of berry function to call
|
||||
int32_t fret = 0;
|
||||
};
|
||||
BerrySupport berry;
|
||||
|
||||
//
|
||||
// Sanity Check for be_top()
|
||||
//
|
||||
// Checks that the Berry stack is empty, if not print a Warning and empty it
|
||||
//
|
||||
void checkBeTop(void) {
|
||||
int32_t top = be_top(berry.vm);
|
||||
if (top != 0) {
|
||||
be_pop(berry.vm, top); // TODO should not be there
|
||||
AddLog(LOG_LEVEL_ERROR, D_LOG_BERRY "Error be_top is non zero=%d", top);
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Native functions mapped to Berry functions
|
||||
*
|
||||
* log(msg:string [,log_level:int]) ->nil
|
||||
*
|
||||
* import tasmota
|
||||
*
|
||||
* tasmota.getfreeheap() -> int
|
||||
* tasmota.publish(topic:string, payload:string[, retain:bool]) -> nil
|
||||
* tasmota.cmd(command:string) -> string
|
||||
* tasmota.getoption(index:int) -> int
|
||||
* tasmota.millis([delay:int]) -> int
|
||||
* tasmota.timereached(timer:int) -> bool
|
||||
* tasmota.yield() -> nil
|
||||
*
|
||||
\*********************************************************************************************/
|
||||
extern "C" {
|
||||
// Berry: `log(msg:string [,log_level:int]) ->nil`
|
||||
// Logs the string at LOG_LEVEL_INFO (loglevel=2)
|
||||
int32_t l_logInfo(struct bvm *vm);
|
||||
int32_t l_logInfo(struct bvm *vm) {
|
||||
int32_t top = be_top(vm); // Get the number of arguments
|
||||
if (top >= 1 && be_isstring(vm, 1)) { // only 1 argument of type string accepted
|
||||
const char * msg = be_tostring(vm, 1);
|
||||
uint32_t log_level = LOG_LEVEL_INFO;
|
||||
if (top >= 2 && be_isint(vm, 2)) {
|
||||
log_level = be_toint(vm, 2);
|
||||
if (log_level > LOG_LEVEL_DEBUG_MORE) { log_level = LOG_LEVEL_DEBUG_MORE; }
|
||||
}
|
||||
AddLog(log_level, PSTR("%s"), msg);
|
||||
be_return(vm); // Return
|
||||
}
|
||||
be_return_nil(vm); // Return nil when something goes wrong
|
||||
}
|
||||
|
||||
// Berry: `getFreeHeap() -> int`
|
||||
// ESP object
|
||||
int32_t l_getFreeHeap(bvm *vm);
|
||||
int32_t l_getFreeHeap(bvm *vm) {
|
||||
be_pushint(vm, ESP.getFreeHeap());
|
||||
be_return(vm);
|
||||
}
|
||||
|
||||
// Berry: `tasmota.publish(topic, payload [,retain]) -> nil``
|
||||
//
|
||||
int32_t l_publish(struct bvm *vm);
|
||||
int32_t l_publish(struct bvm *vm) {
|
||||
int32_t top = be_top(vm); // Get the number of arguments
|
||||
if (top >= 2 && be_isstring(vm, 1) && be_isstring(vm, 2)) { // 2 mandatory string arguments
|
||||
if (top == 2 || (top == 3 && be_isbool(vm, 3))) { // 3rd optional argument must be bool
|
||||
const char * topic = be_tostring(vm, 1);
|
||||
const char * payload = be_tostring(vm, 2);
|
||||
bool retain = false;
|
||||
if (top == 3) {
|
||||
retain = be_tobool(vm, 3);
|
||||
}
|
||||
strlcpy(TasmotaGlobal.mqtt_data, payload, sizeof(TasmotaGlobal.mqtt_data));
|
||||
MqttPublish(topic, retain);
|
||||
be_return(vm); // Return
|
||||
}
|
||||
}
|
||||
be_return_nil(vm); // Return nil when something goes wrong
|
||||
}
|
||||
|
||||
// Berry: `tasmota.cmd(command:string) -> string`
|
||||
//
|
||||
int32_t l_cmd(struct bvm *vm);
|
||||
int32_t l_cmd(struct bvm *vm) {
|
||||
int32_t top = be_top(vm); // Get the number of arguments
|
||||
if (top == 1 && be_isstring(vm, 1)) { // only 1 argument of type string accepted
|
||||
const char * command = be_tostring(vm, 1);
|
||||
ExecuteCommand(command, SRC_BERRY);
|
||||
be_pushstring(vm, TasmotaGlobal.mqtt_data);
|
||||
be_return(vm); // Return
|
||||
}
|
||||
be_return_nil(vm); // Return nil when something goes wrong
|
||||
}
|
||||
|
||||
// Berry: tasmota.millis([delay:int]) -> int
|
||||
//
|
||||
int32_t l_millis(struct bvm *vm);
|
||||
int32_t l_millis(struct bvm *vm) {
|
||||
int32_t top = be_top(vm); // Get the number of arguments
|
||||
if (top == 0 || (top == 1 && be_isint(vm, 1))) { // only 1 argument of type string accepted
|
||||
uint32_t delay = 0;
|
||||
if (top == 1) {
|
||||
delay = be_toint(vm, 1);
|
||||
}
|
||||
uint32_t ret_millis = millis() + delay;
|
||||
be_pushint(vm, ret_millis);
|
||||
be_return(vm); // Return
|
||||
}
|
||||
be_return_nil(vm); // Return nil when something goes wrong
|
||||
}
|
||||
|
||||
// Berry: tasmota.getoption(index:int) -> int
|
||||
//
|
||||
int32_t l_getoption(struct bvm *vm);
|
||||
int32_t l_getoption(struct bvm *vm) {
|
||||
int32_t top = be_top(vm); // Get the number of arguments
|
||||
if (top == 1 && be_isint(vm, 1)) {
|
||||
uint32_t opt = GetOption(be_toint(vm, 1));
|
||||
be_pushint(vm, opt);
|
||||
be_return(vm); // Return
|
||||
}
|
||||
be_return_nil(vm); // Return nil when something goes wrong
|
||||
}
|
||||
|
||||
// Berry: tasmota.timereached(timer:int) -> bool
|
||||
//
|
||||
int32_t l_timereached(struct bvm *vm);
|
||||
int32_t l_timereached(struct bvm *vm) {
|
||||
int32_t top = be_top(vm); // Get the number of arguments
|
||||
if (top == 1 && be_isint(vm, 1)) { // only 1 argument of type string accepted
|
||||
uint32_t timer = be_toint(vm, 1);
|
||||
bool reached = TimeReached(timer);
|
||||
be_pushbool(vm, reached);
|
||||
be_return(vm); // Return
|
||||
}
|
||||
be_return_nil(vm); // Return nil when something goes wrong
|
||||
}
|
||||
|
||||
// Berry: `yield() -> nil`
|
||||
// ESP object
|
||||
int32_t l_yield(bvm *vm);
|
||||
int32_t l_yield(bvm *vm) {
|
||||
optimistic_yield(10);
|
||||
be_return(vm);
|
||||
}
|
||||
|
||||
// Berry: `save(file:string, f:closure) -> bool`
|
||||
int32_t l_save(struct bvm *vm);
|
||||
int32_t l_save(struct bvm *vm) {
|
||||
int32_t top = be_top(vm); // Get the number of arguments
|
||||
if (top ==2 && be_isstring(vm, 1) && be_isclosure(vm, 2)) { // only 1 argument of type string accepted
|
||||
const char *fname = be_tostring(vm, 1);
|
||||
int32_t ret = be_savecode(vm, fname);
|
||||
be_pushint(vm, ret);
|
||||
be_return(vm); // Return
|
||||
}
|
||||
be_return_nil(vm); // Return nil when something goes wrong
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// called as a replacement to Berry `print()`
|
||||
void berry_log(const char * berry_buf);
|
||||
void berry_log(const char * berry_buf) {
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("%s"), berry_buf);
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Handlers for Berry calls and async
|
||||
*
|
||||
\*********************************************************************************************/
|
||||
// // call a function (if exists) of type void -> void
|
||||
// void callBerryFunctionVoid_berry(const char * fname) {
|
||||
// berry.fret = 0;
|
||||
// callBerryFunctionVoid(berry.fname);
|
||||
// }
|
||||
|
||||
bool callBerryRule(void) {
|
||||
if (berry.rules_busy) { return false; }
|
||||
berry.rules_busy = true;
|
||||
char * json_event = TasmotaGlobal.mqtt_data;
|
||||
bool serviced = false;
|
||||
|
||||
checkBeTop();
|
||||
be_getglobal(berry.vm, "_exec_rules");
|
||||
if (!be_isnil(berry.vm, -1)) {
|
||||
|
||||
// {
|
||||
// String event_saved = TasmotaGlobal.mqtt_data;
|
||||
// // json_event = {"INA219":{"Voltage":4.494,"Current":0.020,"Power":0.089}}
|
||||
// // json_event = {"System":{"Boot":1}}
|
||||
// // json_event = {"SerialReceived":"on"} - invalid but will be expanded to {"SerialReceived":{"Data":"on"}}
|
||||
// char *p = strchr(json_event, ':');
|
||||
// if ((p != NULL) && !(strchr(++p, ':'))) { // Find second colon
|
||||
// event_saved.replace(F(":"), F(":{\"Data\":"));
|
||||
// event_saved += F("}");
|
||||
// // event_saved = {"SerialReceived":{"Data":"on"}}
|
||||
// }
|
||||
// be_pushstring(berry.vm, event_saved.c_str());
|
||||
// }
|
||||
be_pushstring(berry.vm, TasmotaGlobal.mqtt_data);
|
||||
int ret = be_pcall(berry.vm, 1);
|
||||
serviced = be_tobool(berry.vm, 1);
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_BERRY "Event (%s) serviced=%d"), TasmotaGlobal.mqtt_data, serviced);
|
||||
be_pop(berry.vm, 2); // remove function object
|
||||
} else {
|
||||
be_pop(berry.vm, 1); // remove nil object
|
||||
}
|
||||
checkBeTop();
|
||||
berry.rules_busy = false;
|
||||
|
||||
return serviced; // TODO event not handled
|
||||
}
|
||||
|
||||
// void callBerryMqttData(void) {
|
||||
// AddLog(LOG_LEVEL_INFO, D_LOG_BERRY "callBerryMqttData");
|
||||
// if (nullptr == berry.vm) { return; }
|
||||
// if (XdrvMailbox.data_len < 1) {
|
||||
// return;
|
||||
// }
|
||||
// const char * topic = XdrvMailbox.topic;
|
||||
// const char * payload = XdrvMailbox.data;
|
||||
|
||||
// checkBeTop();
|
||||
// be_getglobal(berry.vm, "mqtt_data_dispatch");
|
||||
// if (!be_isnil(berry.vm, -1)) {
|
||||
// be_pushstring(berry.vm, topic);
|
||||
// be_pushstring(berry.vm, payload);
|
||||
// be_pcall(berry.vm, 0);
|
||||
// be_pop(berry.vm, 3); // remove function object
|
||||
// } else {
|
||||
// be_pop(berry.vm, 1); // remove nil object
|
||||
// }
|
||||
// checkBeTop();
|
||||
// }
|
||||
|
||||
// call a function (if exists) of type void -> void
|
||||
void callBerryFunctionVoid(const char * fname) {
|
||||
if (nullptr == berry.vm) { return; }
|
||||
checkBeTop();
|
||||
be_getglobal(berry.vm, fname);
|
||||
if (!be_isnil(berry.vm, -1)) {
|
||||
be_pcall(berry.vm, 0);
|
||||
}
|
||||
be_pop(berry.vm, 1); // remove function or nil object
|
||||
checkBeTop();
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Handlers for Berry calls and async
|
||||
*
|
||||
\*********************************************************************************************/
|
||||
|
||||
const char berry_prog[] PROGMEM =
|
||||
""
|
||||
//"def func(x) for i:1..x print('a') end end "
|
||||
//"def testreal() return str(1.2+1) end "
|
||||
//"def noop() log('noop before'); yield(); log('middle after'); yield(); log('noop after'); end "
|
||||
//"log(\"foobar\") "
|
||||
|
||||
// auto-import modules
|
||||
"import string "
|
||||
"import json "
|
||||
"import gc "
|
||||
"import tasmota "
|
||||
// import alias
|
||||
"import tasmota as t "
|
||||
|
||||
// add `charsinstring(s:string,c:string) -> int``
|
||||
// looks for any char in c, and return the position of the first chat
|
||||
// or -1 if not found
|
||||
"def charsinstring(s,c) "
|
||||
"for i:0..size(s)-1 "
|
||||
"for j:0..size(c)-1 "
|
||||
"if s[i] == c[j] return i end "
|
||||
"end "
|
||||
"end "
|
||||
"return -1 "
|
||||
"end "
|
||||
|
||||
// find a key in map, case insensitive, return actual key or nil if not found
|
||||
"def findkeyi(m,keyi) "
|
||||
"var keyu = string.toupper(keyi) "
|
||||
"if classof(m) == map "
|
||||
"for k:m.keys() "
|
||||
"if string.toupper(k)==keyu || keyi=='?' "
|
||||
"return k "
|
||||
"end "
|
||||
"end "
|
||||
"end "
|
||||
"end "
|
||||
|
||||
// Rules
|
||||
|
||||
"tasmota._operators='=<>!' " // operators used in rules
|
||||
// Rules comparisong functions
|
||||
"tasmota._eqstr=/s1,s2-> str(s1) == str(s2) "
|
||||
"tasmota._neqstr=/s1,s2-> str(s1) != str(s2) "
|
||||
"tasmota._eq=/f1,f2-> real(f1) == real(f2) "
|
||||
"tasmota._neq=/f1,f2-> real(f1) != real(f2) "
|
||||
"tasmota._gt=/f1,f2-> real(f1) > real(f2) "
|
||||
"tasmota._lt=/f1,f2-> real(f1) < real(f2) "
|
||||
"tasmota._ge=/f1,f2-> real(f1) >= real(f2) "
|
||||
"tasmota._le=/f1,f2-> real(f1) <= real(f2) "
|
||||
|
||||
"tasmota._op=["
|
||||
"['==',tasmota._eqstr],"
|
||||
"['!==',tasmota._neqstr],"
|
||||
"['=',tasmota._eq],"
|
||||
"['!=',tasmota._neq],"
|
||||
"['>=',tasmota._ge],"
|
||||
"['<=',tasmota._le],"
|
||||
"['>',tasmota._gt],"
|
||||
"['<',tasmota._lt],"
|
||||
"] "
|
||||
"tasmota_rules={} "
|
||||
"tasmota.rule = def(pat,f) tasmota_rules[pat] = f end "
|
||||
|
||||
// # split the item when there is an operator, returns a list of (left,op,right)
|
||||
// # ex: "Dimmer>50" -> ["Dimmer",tasmota_gt,"50"]
|
||||
"tasmota.find_op = def (item) "
|
||||
"var pos = charsinstring(item, tasmota._operators) "
|
||||
"if pos>=0 "
|
||||
"var op_split = string.split(item,pos) "
|
||||
// #print(op_split)
|
||||
"var op_left = op_split[0] "
|
||||
"var op_rest = op_split[1] "
|
||||
// # iterate through operators
|
||||
"for op:tasmota._op "
|
||||
"if string.find(op_rest,op[0]) == 0 "
|
||||
"var op_func = op[1] "
|
||||
"var op_right = string.split(op_rest,size(op[0]))[1] "
|
||||
"return [op_left,op_func,op_right] "
|
||||
"end "
|
||||
"end "
|
||||
"end "
|
||||
"return [item, nil, nil] "
|
||||
"end "
|
||||
|
||||
// Rules trigger if match. return true if match, false if not
|
||||
// Note: condition is not yet managed
|
||||
"tasmota.try_rule = def (ev, rule, f) "
|
||||
"var rl_list = tasmota.find_op(rule) "
|
||||
"var e=ev "
|
||||
"var rl=string.split(rl_list[0],'#') "
|
||||
"for it:rl "
|
||||
"found=findkeyi(e,it) "
|
||||
"if found == nil "
|
||||
"return false "
|
||||
"end "
|
||||
"e=e[found] "
|
||||
"end "
|
||||
// # check if condition is true
|
||||
"if rl_list[1] "
|
||||
// # did we find a function
|
||||
"if !rl_list[1](e,rl_list[2]) "
|
||||
// # condition is not met
|
||||
"return false "
|
||||
"end "
|
||||
"end "
|
||||
"f(e,ev) "
|
||||
"return true "
|
||||
"end "
|
||||
// Run rules, i.e. check each individual rule
|
||||
// Returns true if at least one rule matched, false if none
|
||||
"tasmota.exec_rules = def (ev_json) "
|
||||
"var ev = json.load(ev_json) "
|
||||
"var ret = false "
|
||||
"if ev == nil "
|
||||
"log('BRY: ERROR, bad json: '+ev_json, 3) "
|
||||
"end "
|
||||
"for r:tasmota_rules.keys() "
|
||||
"ret = tasmota.try_rule(ev,r,tasmota_rules[r]) || ret "
|
||||
"end "
|
||||
"return ret "
|
||||
"end "
|
||||
// Not sure how to run `tasmota.exec_rules` from C code, so alias with `_exec_rules()``
|
||||
"def _exec_rules(e) return tasmota.exec_rules(e) end "
|
||||
|
||||
// Timers
|
||||
"tasmota_timers=[] "
|
||||
"tasmota.timer = def (delay,f) tasmota_timers.push([tasmota.millis(delay),f]) end "
|
||||
|
||||
"def _run_deferred() "
|
||||
"var i=0 "
|
||||
"while i<tasmota_timers.size() "
|
||||
"if tasmota.timereached(tasmota_timers[i][0]) "
|
||||
"f=tasmota_timers[i][1] "
|
||||
"tasmota_timers.remove(i) "
|
||||
"f() "
|
||||
"else "
|
||||
"i=i+1 "
|
||||
"end "
|
||||
"end "
|
||||
"end "
|
||||
|
||||
// Delay function, internally calls yield() every 10ms to avoid WDT
|
||||
"tasmota.delay = def(ms) "
|
||||
"var tend = tasmota.millis(ms) "
|
||||
"while !tasmota.timereached(tend) "
|
||||
"tasmota.yield() "
|
||||
"end "
|
||||
"end "
|
||||
|
||||
// simple wrapper to load a file
|
||||
// prefixes '/' if needed, and simpler to use than `compile()`
|
||||
"def load(f) "
|
||||
"try "
|
||||
// check that the file ends with '.be' of '.bec'
|
||||
"var fl = string.split(f,'.') "
|
||||
"if (size(fl) <= 1 || (fl[-1] != 'be' && fl[-1] != 'bec')) "
|
||||
"raise \"file extension is not '.be' or '.bec'\" "
|
||||
"end "
|
||||
"var native = f[size(f)-1] == 'c' "
|
||||
// add prefix if needed
|
||||
"if f[0] != '/' f = '/' + f end "
|
||||
// load - works the same for .be and .bec
|
||||
"var c = compile(f,'file') "
|
||||
// save the compiled bytecode
|
||||
"if !native "
|
||||
"save(f+'c', c) "
|
||||
"end "
|
||||
// call the compiled code
|
||||
"c() "
|
||||
"except .. as e "
|
||||
"log(string.format(\"BRY: could not load file '%s' - %s\",f,e)) "
|
||||
"end "
|
||||
"end "
|
||||
|
||||
// try to load "/autoexec.be"
|
||||
// "try compile('/autoexec.be','file')() except .. log('BRY: no /autoexec.bat file') end "
|
||||
|
||||
// trigger Garbage Collector
|
||||
"gc.collect() "
|
||||
;
|
||||
|
||||
/*********************************************************************************************\
|
||||
* VM Init
|
||||
\*********************************************************************************************/
|
||||
void BrReset(void) {
|
||||
// clean previous VM if any
|
||||
if (berry.vm != nullptr) {
|
||||
be_vm_delete(berry.vm);
|
||||
berry.vm = nullptr;
|
||||
}
|
||||
|
||||
int32_t ret_code1, ret_code2;
|
||||
bool berry_init_ok = false;
|
||||
do {
|
||||
uint32_t heap_before = ESP.getFreeHeap();
|
||||
berry.vm = be_vm_new(); /* create a virtual machine instance */
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_BERRY "Berry VM created, RAM consumed=%u (Heap=%u)"), heap_before - ESP.getFreeHeap(), ESP.getFreeHeap());
|
||||
|
||||
// Register functions
|
||||
be_regfunc(berry.vm, PSTR("log"), l_logInfo);
|
||||
be_regfunc(berry.vm, PSTR("save"), l_save);
|
||||
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_BERRY "Berry function registered, RAM consumed=%u (Heap=%u)"), heap_before - ESP.getFreeHeap(), ESP.getFreeHeap());
|
||||
|
||||
ret_code1 = be_loadstring(berry.vm, berry_prog);
|
||||
if (ret_code1 != 0) {
|
||||
AddLog(LOG_LEVEL_ERROR, PSTR(D_LOG_BERRY "ERROR: be_loadstring [%s] %s"), be_tostring(berry.vm, -2), be_tostring(berry.vm, -1));
|
||||
be_pop(berry.vm, 2);
|
||||
break;
|
||||
}
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_BERRY "Berry code loaded, RAM consumed=%u (Heap=%u)"), heap_before - ESP.getFreeHeap(), ESP.getFreeHeap());
|
||||
ret_code2 = be_pcall(berry.vm, 0);
|
||||
if (ret_code1 != 0) {
|
||||
AddLog(LOG_LEVEL_ERROR, PSTR(D_LOG_BERRY "ERROR: be_pcall [%s] %s"), be_tostring(berry.vm, -2), be_tostring(berry.vm, -1));
|
||||
be_pop(berry.vm, 2);
|
||||
break;
|
||||
}
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_BERRY "Berry code ran, RAM consumed=%u (Heap=%u)"), heap_before - ESP.getFreeHeap(), ESP.getFreeHeap());
|
||||
be_pop(berry.vm, 1);
|
||||
|
||||
AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_BERRY "Berry initialized, RAM consumed=%u (Heap=%u)"), heap_before - ESP.getFreeHeap(), ESP.getFreeHeap());
|
||||
// AddLog(LOG_LEVEL_INFO, PSTR("Delete Berry VM"));
|
||||
// be_vm_delete(vm);
|
||||
// AddLog(LOG_LEVEL_INFO, PSTR("After Berry"));
|
||||
|
||||
berry_init_ok = true;
|
||||
} while (0);
|
||||
|
||||
if (!berry_init_ok) {
|
||||
// free resources
|
||||
if (berry.vm != nullptr) {
|
||||
be_vm_delete(berry.vm);
|
||||
berry.vm = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Tasmota Commands
|
||||
\*********************************************************************************************/
|
||||
//
|
||||
// Command `BrRun`
|
||||
//
|
||||
void CmndBrRun(void) {
|
||||
int32_t ret_code;
|
||||
const char * ret_type, * ret_val;
|
||||
|
||||
if (berry.vm == nullptr) { ResponseCmndChar_P(PSTR(D_BR_NOT_STARTED)); return; }
|
||||
|
||||
char br_cmd[XdrvMailbox.data_len+12];
|
||||
// encapsulate into a function, copied from `be_repl.c` / `try_return()`
|
||||
snprintf_P(br_cmd, sizeof(br_cmd), PSTR("return (%s)"), XdrvMailbox.data);
|
||||
|
||||
checkBeTop();
|
||||
do {
|
||||
// First try with the `return ()` wrapper
|
||||
ret_code = be_loadbuffer(berry.vm, PSTR("input"), br_cmd, strlen(br_cmd));
|
||||
if (be_getexcept(berry.vm, ret_code) == BE_SYNTAX_ERROR) {
|
||||
be_pop(berry.vm, 2); // remove exception values
|
||||
// if fails, try the direct command
|
||||
ret_code = be_loadbuffer(berry.vm, PSTR("input"), XdrvMailbox.data, strlen(XdrvMailbox.data));
|
||||
}
|
||||
if (0 != ret_code) break;
|
||||
|
||||
ret_code = be_pcall(berry.vm, 0); // execute code
|
||||
} while (0);
|
||||
|
||||
if (0 == ret_code) {
|
||||
// code taken from REPL, look first at top, and if nil, look at return value
|
||||
if (be_isnil(berry.vm, 0)) {
|
||||
ret_val = be_tostring(berry.vm, -1);
|
||||
} else {
|
||||
ret_val = be_tostring(berry.vm, 0);
|
||||
}
|
||||
Response_P("{\"" D_PRFX_BR "\":\"%s\"}", ret_val); // can't use XdrvMailbox.command as it may have been overwritten by subcommand
|
||||
be_pop(berry.vm, 1);
|
||||
} else {
|
||||
Response_P(PSTR("{\"" D_PRFX_BR "\":\"[%s] %s\"}"), be_tostring(berry.vm, -2), be_tostring(berry.vm, -1));
|
||||
be_pop(berry.vm, 2);
|
||||
}
|
||||
|
||||
checkBeTop();
|
||||
}
|
||||
|
||||
//
|
||||
// Command `BrReset`
|
||||
//
|
||||
void CmndBrReset(void) {
|
||||
if (berry.vm == nullptr) { ResponseCmndChar_P(PSTR(D_BR_NOT_STARTED)); return; }
|
||||
|
||||
BrReset();
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Interface
|
||||
\*********************************************************************************************/
|
||||
bool Xdrv52(uint8_t function)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
switch (function) {
|
||||
//case FUNC_PRE_INIT:
|
||||
case FUNC_INIT:
|
||||
BrReset();
|
||||
break;
|
||||
case FUNC_EVERY_50_MSECOND:
|
||||
callBerryFunctionVoid(PSTR("_run_deferred"));
|
||||
break;
|
||||
case FUNC_EVERY_100_MSECOND:
|
||||
callBerryFunctionVoid(PSTR("every_100ms"));
|
||||
break;
|
||||
case FUNC_EVERY_SECOND:
|
||||
callBerryFunctionVoid(PSTR("every_second"));
|
||||
break;
|
||||
case FUNC_COMMAND:
|
||||
result = DecodeCommand(kBrCommands, BerryCommand);
|
||||
break;
|
||||
// case FUNC_SET_POWER:
|
||||
// break;
|
||||
case FUNC_RULES_PROCESS:
|
||||
result = callBerryRule();
|
||||
break;
|
||||
#ifdef USE_WEBSERVER
|
||||
case FUNC_WEB_ADD_BUTTON:
|
||||
break;
|
||||
case FUNC_WEB_ADD_MAIN_BUTTON:
|
||||
|
||||
break;
|
||||
case FUNC_WEB_ADD_HANDLER:
|
||||
break;
|
||||
#endif // USE_WEBSERVER
|
||||
case FUNC_SAVE_BEFORE_RESTART:
|
||||
break;
|
||||
case FUNC_MQTT_DATA:
|
||||
// callBerryMqttData();
|
||||
break;
|
||||
case FUNC_WEB_SENSOR:
|
||||
break;
|
||||
|
||||
case FUNC_JSON_APPEND:
|
||||
break;
|
||||
|
||||
case FUNC_BUTTON_PRESSED:
|
||||
break;
|
||||
|
||||
case FUNC_LOOP:
|
||||
break;
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // USE_BERRY
|
Loading…
Reference in New Issue