Berry stabilized and methods solidified

This commit is contained in:
Stephan Hadinger 2021-03-27 19:02:22 +01:00
parent 210460f3c9
commit b06568b3c8
30 changed files with 2959 additions and 318 deletions

View File

@ -0,0 +1,17 @@
#include "be_constobj.h"
static be_define_const_map_slots(m_libsolidify_map) {
{ be_const_key(dump, -1), be_const_func(m_dump) },
};
static be_define_const_map(
m_libsolidify_map,
1
);
static be_define_const_module(
m_libsolidify,
"solidify"
);
BE_EXPORT_VARIABLE be_define_const_native_module(solidify, NULL);

View File

@ -0,0 +1,2 @@
#include "be_constobj.h"

View File

@ -35,6 +35,17 @@ static void class_init(bvm *vm, bclass *c, const bnfuncinfo *lib)
} }
++lib; ++lib;
} }
if (lib->function == (bntvfunc) BE_CLOSURE) {
/* next section is closures */
++lib;
while (lib->name) {
if (lib->function) { /* method */
bstring *s = be_newstr(vm, lib->name);
be_closure_method_bind(vm, c, s, (bclosure*) lib->function);
}
++lib;
}
}
be_map_release(vm, c->members); /* clear space */ be_map_release(vm, c->members); /* clear space */
} }
} }
@ -346,6 +357,13 @@ BERRY_API void be_pushvalue(bvm *vm, int index)
be_incrtop(vm); be_incrtop(vm);
} }
BERRY_API void be_pushclosure(bvm *vm, void *cl)
{
bvalue *reg = be_incrtop(vm);
bclosure * closure = (bclosure*) cl;
var_setclosure(reg, closure);
}
BERRY_API void be_pushntvclosure(bvm *vm, bntvfunc f, int nupvals) BERRY_API void be_pushntvclosure(bvm *vm, bntvfunc f, int nupvals)
{ {
/* to create a native closure and then push the top registor, /* to create a native closure and then push the top registor,

View File

@ -32,12 +32,14 @@ typedef struct buf_impl {
** **
** Extracted from Tasmota SBuffer lib ** Extracted from Tasmota SBuffer lib
********************************************************************/ ********************************************************************/
static inline uint8_t* buf_get_buf(buf_impl* buf) { static inline uint8_t* buf_get_buf(buf_impl* buf)
{
return &buf->buf[0]; return &buf->buf[0];
} }
// shrink or increase. If increase, fill with zeores. Cannot go beyond `size` // shrink or increase. If increase, fill with zeores. Cannot go beyond `size`
static void buf_set_len(buf_impl* buf, const size_t len) { static void buf_set_len(buf_impl* buf, const size_t len)
{
uint16_t old_len = buf->len; uint16_t old_len = buf->len;
buf->len = (len <= buf->size) ? len : buf->size; buf->len = (len <= buf->size) ? len : buf->size;
if (old_len < buf->len) { if (old_len < buf->len) {
@ -45,33 +47,41 @@ static void buf_set_len(buf_impl* buf, const size_t len) {
} }
} }
static void buf_set1(buf_impl* buf, const size_t offset, const uint8_t data)
static void buf_set1(buf_impl* buf, const size_t offset, const uint8_t data) { {
if (offset < buf->len) { if (offset < buf->len) {
buf->buf[offset] = data; buf->buf[offset] = data;
} }
} }
static size_t buf_add1(buf_impl* buf, const uint8_t data) { // append 8 bits value
static size_t buf_add1(buf_impl* buf, const uint8_t data) // append 8 bits value
{
if (buf->len < buf->size) { // do we have room for 1 byte if (buf->len < buf->size) { // do we have room for 1 byte
buf->buf[buf->len++] = data; buf->buf[buf->len++] = data;
} }
return buf->len; return buf->len;
} }
static size_t buf_add2_le(buf_impl* buf, const uint16_t data) { // append 16 bits value
static size_t buf_add2_le(buf_impl* buf, const uint16_t data) // append 16 bits value
{
if (buf->len < buf->size - 1) { // do we have room for 2 bytes if (buf->len < buf->size - 1) { // do we have room for 2 bytes
buf->buf[buf->len++] = data; buf->buf[buf->len++] = data;
buf->buf[buf->len++] = data >> 8; buf->buf[buf->len++] = data >> 8;
} }
return buf->len; return buf->len;
} }
static size_t buf_add2_be(buf_impl* buf, const uint16_t data) { // append 16 bits value
static size_t buf_add2_be(buf_impl* buf, const uint16_t data) // append 16 bits value
{
if (buf->len < buf->size - 1) { // do we have room for 2 bytes if (buf->len < buf->size - 1) { // do we have room for 2 bytes
buf->buf[buf->len++] = data >> 8; buf->buf[buf->len++] = data >> 8;
buf->buf[buf->len++] = data; buf->buf[buf->len++] = data;
} }
return buf->len; return buf->len;
} }
static size_t buf_add4_le(buf_impl* buf, const uint32_t data) { // append 32 bits value
static size_t buf_add4_le(buf_impl* buf, const uint32_t data) // append 32 bits value
{
if (buf->len < buf->size - 3) { // do we have room for 4 bytes if (buf->len < buf->size - 3) { // do we have room for 4 bytes
buf->buf[buf->len++] = data; buf->buf[buf->len++] = data;
buf->buf[buf->len++] = data >> 8; buf->buf[buf->len++] = data >> 8;
@ -80,7 +90,9 @@ static size_t buf_add4_le(buf_impl* buf, const uint32_t data) { // app
} }
return buf->len; return buf->len;
} }
size_t buf_add4_be(buf_impl* buf, const uint32_t data) { // append 32 bits value
size_t buf_add4_be(buf_impl* buf, const uint32_t data) // append 32 bits value
{
if (buf->len < buf->size - 3) { // do we have room for 4 bytes if (buf->len < buf->size - 3) { // do we have room for 4 bytes
buf->buf[buf->len++] = data >> 24; buf->buf[buf->len++] = data >> 24;
buf->buf[buf->len++] = data >> 16; buf->buf[buf->len++] = data >> 16;
@ -90,7 +102,8 @@ size_t buf_add4_be(buf_impl* buf, const uint32_t data) { // append 32
return buf->len; return buf->len;
} }
static size_t buf_add_buf(buf_impl* buf, buf_impl* buf2) { static size_t buf_add_buf(buf_impl* buf, buf_impl* buf2)
{
if (buf->len + buf2->len <= buf->size) { if (buf->len + buf2->len <= buf->size) {
for (uint32_t i = 0; i < buf2->len; i++) { for (uint32_t i = 0; i < buf2->len; i++) {
buf->buf[buf->len++] = buf2->buf[i]; buf->buf[buf->len++] = buf2->buf[i];
@ -99,32 +112,40 @@ static size_t buf_add_buf(buf_impl* buf, buf_impl* buf2) {
return buf->len; return buf->len;
} }
static uint8_t buf_get1(buf_impl* buf, int offset) { static uint8_t buf_get1(buf_impl* buf, int offset)
{
if ((offset >= 0) && (offset < buf->len)) { if ((offset >= 0) && (offset < buf->len)) {
return buf->buf[offset]; return buf->buf[offset];
} }
return 0; return 0;
} }
static uint16_t buf_get2_le(buf_impl* buf, int offset) { static uint16_t buf_get2_le(buf_impl* buf, int offset) {
if ((offset >= 0) && (offset < buf->len - 1)) { if ((offset >= 0) && (offset < buf->len - 1)) {
return buf->buf[offset] | (buf->buf[offset+1] << 8); return buf->buf[offset] | (buf->buf[offset+1] << 8);
} }
return 0; return 0;
} }
static uint16_t buf_get2_be(buf_impl* buf, int offset) {
static uint16_t buf_get2_be(buf_impl* buf, int offset)
{
if (offset < buf->len - 1) { if (offset < buf->len - 1) {
return buf->buf[offset+1] | (buf->buf[offset] << 8); return buf->buf[offset+1] | (buf->buf[offset] << 8);
} }
return 0; return 0;
} }
static uint32_t buf_get4_le(buf_impl* buf, int offset) {
static uint32_t buf_get4_le(buf_impl* buf, int offset)
{
if ((offset >= 0) && (offset < buf->len - 3)) { if ((offset >= 0) && (offset < buf->len - 3)) {
return buf->buf[offset] | (buf->buf[offset+1] << 8) | return buf->buf[offset] | (buf->buf[offset+1] << 8) |
(buf->buf[offset+2] << 16) | (buf->buf[offset+3] << 24); (buf->buf[offset+2] << 16) | (buf->buf[offset+3] << 24);
} }
return 0; return 0;
} }
static uint32_t buf_get4_be(buf_impl* buf, int offset) {
static uint32_t buf_get4_be(buf_impl* buf, int offset)
{
if (offset < buf->len - 3) { if (offset < buf->len - 3) {
return buf->buf[offset+3] | (buf->buf[offset+2] << 8) | return buf->buf[offset+3] | (buf->buf[offset+2] << 8) |
(buf->buf[offset+1] << 16) | (buf->buf[offset] << 24); (buf->buf[offset+1] << 16) | (buf->buf[offset] << 24);
@ -133,7 +154,8 @@ static uint32_t buf_get4_be(buf_impl* buf, int offset) {
} }
// nullptr accepted // nullptr accepted
static bbool buf_equals(buf_impl* buf1, buf_impl* buf2) { static bbool buf_equals(buf_impl* buf1, buf_impl* buf2)
{
if (buf1 == buf2) { return btrue; } if (buf1 == buf2) { return btrue; }
if (!buf1 || !buf2) { return bfalse; } // at least one buf is not empty if (!buf1 || !buf2) { return bfalse; } // at least one buf is not empty
// we know that both buf1 and buf2 are non-null // we know that both buf1 and buf2 are non-null
@ -145,7 +167,8 @@ static bbool buf_equals(buf_impl* buf1, buf_impl* buf2) {
return btrue; return btrue;
} }
static uint8_t asc2byte(char chr) { static uint8_t asc2byte(char chr)
{
uint8_t rVal = 0; uint8_t rVal = 0;
if (isdigit(chr)) { rVal = chr - '0'; } if (isdigit(chr)) { rVal = chr - '0'; }
else if (chr >= 'A' && chr <= 'F') { rVal = chr + 10 - 'A'; } else if (chr >= 'A' && chr <= 'F') { rVal = chr + 10 - 'A'; }
@ -153,7 +176,8 @@ static uint8_t asc2byte(char chr) {
return rVal; return rVal;
} }
// does not check if there is enough room before hand, truncated if buffer too small // does not check if there is enough room before hand, truncated if buffer too small
static void buf_add_hex(buf_impl* buf, const char *hex, size_t len) { static void buf_add_hex(buf_impl* buf, const char *hex, size_t len)
{
uint8_t val; uint8_t val;
for (; len > 1; len -= 2) { for (; len > 1; len -= 2) {
val = asc2byte(*hex++) << 4; val = asc2byte(*hex++) << 4;
@ -166,7 +190,8 @@ static void buf_add_hex(buf_impl* buf, const char *hex, size_t len) {
** Wrapping into lib ** Wrapping into lib
********************************************************************/ ********************************************************************/
// typedef int (*bntvfunc)(bvm*); /* native function pointer */ // typedef int (*bntvfunc)(bvm*); /* native function pointer */
int free_bytes_buf(bvm* vm) { int free_bytes_buf(bvm* vm)
{
int argc = be_top(vm); int argc = be_top(vm);
if (argc > 0) { if (argc > 0) {
buf_impl * buf = (buf_impl*) be_tocomptr(vm, 1); buf_impl * buf = (buf_impl*) be_tocomptr(vm, 1);
@ -285,9 +310,9 @@ static int m_tostring(bvm *vm)
size_t hex_len = len * 2 + 5 + 2 + 2 + 1; /* reserve size for `bytes("")\0` - 9 chars */ size_t hex_len = len * 2 + 5 + 2 + 2 + 1; /* reserve size for `bytes("")\0` - 9 chars */
char * hex_out = be_pushbuffer(vm, hex_len); char * hex_out = be_pushbuffer(vm, hex_len);
size_t l = strlcpy(hex_out, "bytes('", hex_len); size_t l = be_strlcpy(hex_out, "bytes('", hex_len);
l += tohex(&hex_out[l], hex_len - l, buf_get_buf(buf), buf->len); l += tohex(&hex_out[l], hex_len - l, buf_get_buf(buf), buf->len);
l += strlcpy(&hex_out[l], "')", hex_len - l); l += be_strlcpy(&hex_out[l], "')", hex_len - l);
be_pushnstring(vm, hex_out, l); /* make escape string from buffer */ be_pushnstring(vm, hex_out, l); /* make escape string from buffer */
be_remove(vm, -2); /* remove buffer */ be_remove(vm, -2); /* remove buffer */
@ -303,6 +328,7 @@ static int m_asstring(bvm *vm)
be_pushnstring(vm, (const char*) buf_get_buf(buf), buf->len); be_pushnstring(vm, (const char*) buf_get_buf(buf), buf->len);
be_return(vm); be_return(vm);
} }
static int m_fromstring(bvm *vm) static int m_fromstring(bvm *vm)
{ {
int argc = be_top(vm); int argc = be_top(vm);
@ -395,7 +421,6 @@ static int m_get(bvm *vm)
be_return_nil(vm); be_return_nil(vm);
} }
static int m_setitem(bvm *vm) static int m_setitem(bvm *vm)
{ {
int argc = be_top(vm); int argc = be_top(vm);

View File

@ -59,8 +59,10 @@ int be_class_attribute(bvm *vm, bclass *c, bstring *attr)
void be_member_bind(bvm *vm, bclass *c, bstring *name) void be_member_bind(bvm *vm, bclass *c, bstring *name)
{ {
bvalue *attr; bvalue *attr;
set_fixed(name);
check_members(vm, c); check_members(vm, c);
attr = be_map_insertstr(vm, c->members, name, NULL); attr = be_map_insertstr(vm, c->members, name, NULL);
restore_fixed(name);
attr->v.i = c->nvar++; attr->v.i = c->nvar++;
attr->type = MT_VARIABLE; attr->type = MT_VARIABLE;
} }
@ -69,8 +71,10 @@ void be_method_bind(bvm *vm, bclass *c, bstring *name, bproto *p)
{ {
bclosure *cl; bclosure *cl;
bvalue *attr; bvalue *attr;
set_fixed(name);
check_members(vm, c); check_members(vm, c);
attr = be_map_insertstr(vm, c->members, name, NULL); attr = be_map_insertstr(vm, c->members, name, NULL);
restore_fixed(name);
var_setnil(attr); var_setnil(attr);
cl = be_newclosure(vm, p->nupvals); cl = be_newclosure(vm, p->nupvals);
cl->proto = p; cl->proto = p;
@ -80,12 +84,23 @@ void be_method_bind(bvm *vm, bclass *c, bstring *name, bproto *p)
void be_prim_method_bind(bvm *vm, bclass *c, bstring *name, bntvfunc f) void be_prim_method_bind(bvm *vm, bclass *c, bstring *name, bntvfunc f)
{ {
bvalue *attr; bvalue *attr;
set_fixed(name);
check_members(vm, c); check_members(vm, c);
attr = be_map_insertstr(vm, c->members, name, NULL); attr = be_map_insertstr(vm, c->members, name, NULL);
restore_fixed(name);
attr->v.nf = f; attr->v.nf = f;
attr->type = MT_PRIMMETHOD; attr->type = MT_PRIMMETHOD;
} }
void be_closure_method_bind(bvm *vm, bclass *c, bstring *name, bclosure *cl)
{
bvalue *attr;
check_members(vm, c);
attr = be_map_insertstr(vm, c->members, name, NULL);
attr->v.gc = (bgcobject*) cl;
attr->type = MT_METHOD;
}
/* get the closure method count that need upvalues */ /* get the closure method count that need upvalues */
int be_class_closure_count(bclass *c) int be_class_closure_count(bclass *c)
{ {

View File

@ -52,6 +52,7 @@ int be_class_attribute(bvm *vm, bclass *c, bstring *attr);
void be_member_bind(bvm *vm, bclass *c, bstring *name); void be_member_bind(bvm *vm, bclass *c, bstring *name);
void be_method_bind(bvm *vm, bclass *c, bstring *name, bproto *p); void be_method_bind(bvm *vm, bclass *c, bstring *name, bproto *p);
void be_prim_method_bind(bvm *vm, bclass *c, bstring *name, bntvfunc f); void be_prim_method_bind(bvm *vm, bclass *c, bstring *name, bntvfunc f);
void be_closure_method_bind(bvm *vm, bclass *c, bstring *name, bclosure *cl);
int be_class_closure_count(bclass *c); int be_class_closure_count(bclass *c);
void be_class_upvalue_init(bvm *vm, bclass *c); void be_class_upvalue_init(bvm *vm, bclass *c);
bbool be_class_newobj(bvm *vm, bclass *c, bvalue *argv, int argc); bbool be_class_newobj(bvm *vm, bclass *c, bvalue *argv, int argc);

View File

@ -46,7 +46,7 @@ static const char* opc2str(bopcode op)
return op < array_count(opc_tab) ? opc_tab[op] : "ERROP"; return op < array_count(opc_tab) ? opc_tab[op] : "ERROP";
} }
static void print_inst(binstruction ins, int pc) void be_print_inst(binstruction ins, int pc)
{ {
char __lbuf[INST_BUF_SIZE]; char __lbuf[INST_BUF_SIZE];
bopcode op = IGET_OP(ins); bopcode op = IGET_OP(ins);
@ -145,7 +145,7 @@ void be_dumpclosure(bclosure *cl)
logfmt("; line %d\n", (++lineinfo)->linenumber); logfmt("; line %d\n", (++lineinfo)->linenumber);
} }
#endif #endif
print_inst(*code++, pc); be_print_inst(*code++, pc);
} }
} }
#endif #endif

View File

@ -21,4 +21,8 @@ void be_callhook(bvm *vm, int mask);
bbool be_debug_varname(bvm *vm, int level, int index); bbool be_debug_varname(bvm *vm, int level, int index);
bbool be_debug_upvname(bvm *vm, int level, int index); bbool be_debug_upvname(bvm *vm, int level, int index);
#if BE_USE_DEBUG_MODULE
void be_print_inst(binstruction ins, int pc);
#endif
#endif #endif

View File

@ -120,6 +120,20 @@ void be_gc_unfix(bvm *vm, bgcobject *obj)
} }
} }
bbool be_gc_fix_set(bvm *vm, bgcobject *obj, bbool fix)
{
(void)vm;
bbool was_fixed = gc_isfixed(obj);
if (!gc_isconst(obj)) {
if (fix) {
gc_setfixed(obj);
} else {
gc_clearfixed(obj);
}
}
return was_fixed;
}
static void mark_gray(bvm *vm, bgcobject *obj) static void mark_gray(bvm *vm, bgcobject *obj)
{ {
if (obj && gc_iswhite(obj) && !gc_isconst(obj)) { if (obj && gc_iswhite(obj) && !gc_isconst(obj)) {
@ -285,6 +299,9 @@ static void free_proto(bvm *vm, bgcobject *obj)
be_free(vm, proto->code, proto->codesize * sizeof(binstruction)); be_free(vm, proto->code, proto->codesize * sizeof(binstruction));
#if BE_DEBUG_RUNTIME_INFO #if BE_DEBUG_RUNTIME_INFO
be_free(vm, proto->lineinfo, proto->nlineinfo * sizeof(blineinfo)); be_free(vm, proto->lineinfo, proto->nlineinfo * sizeof(blineinfo));
#endif
#if BE_DEBUG_VAR_INFO
be_free(vm, proto->varinfo, proto->nvarinfo * sizeof(bvarinfo));
#endif #endif
be_free(vm, proto, sizeof(bproto)); be_free(vm, proto, sizeof(bproto));
} }
@ -489,9 +506,15 @@ static void reset_fixedlist(bvm *vm)
void be_gc_auto(bvm *vm) void be_gc_auto(bvm *vm)
{ {
#if BE_USE_DEBUG_GC
if (vm->gc.status & GC_PAUSE) { /* force gc each time it's possible */
be_gc_collect(vm);
}
#else
if (vm->gc.status & GC_PAUSE && vm->gc.usage > vm->gc.threshold) { if (vm->gc.status & GC_PAUSE && vm->gc.usage > vm->gc.threshold) {
be_gc_collect(vm); be_gc_collect(vm);
} }
#endif
} }
size_t be_gc_memcount(bvm *vm) size_t be_gc_memcount(bvm *vm)
@ -505,7 +528,8 @@ void be_gc_collect(bvm *vm)
return; /* the GC cannot run for some reason */ return; /* the GC cannot run for some reason */
} }
#if BE_USE_OBSERVABILITY_HOOK #if BE_USE_OBSERVABILITY_HOOK
if (vm->obshook != NULL) (*vm->obshook)(vm, BE_OBS_GC_START, vm->gc.usage); if (vm->obshook != NULL)
(*vm->obshook)(vm, BE_OBS_GC_START, vm->gc.usage);
#endif #endif
/* step 1: set root-set reference objects to unscanned */ /* step 1: set root-set reference objects to unscanned */
premark_internal(vm); /* object internal the VM */ premark_internal(vm); /* object internal the VM */
@ -524,6 +548,7 @@ void be_gc_collect(bvm *vm)
/* step 5: calculate the next GC threshold */ /* step 5: calculate the next GC threshold */
vm->gc.threshold = next_threshold(vm->gc); vm->gc.threshold = next_threshold(vm->gc);
#if BE_USE_OBSERVABILITY_HOOK #if BE_USE_OBSERVABILITY_HOOK
if (vm->obshook != NULL) (*vm->obshook)(vm, BE_OBS_GC_END, vm->gc.usage); if (vm->obshook != NULL)
(*vm->obshook)(vm, BE_OBS_GC_END, vm->gc.usage);
#endif #endif
} }

View File

@ -49,6 +49,9 @@ if (!gc_isconst(o)) { \
#define be_isgcobj(o) be_isgctype(var_type(o)) #define be_isgcobj(o) be_isgctype(var_type(o))
#define be_gcnew(v, t, s) be_newgcobj((v), (t), sizeof(s)) #define be_gcnew(v, t, s) be_newgcobj((v), (t), sizeof(s))
#define set_fixed(s) bbool _was_fixed = be_gc_fix_set(vm, cast(bgcobject*, (s)), 1)
#define restore_fixed(s) be_gc_fix_set(vm, cast(bgcobject*, (s)), _was_fixed);
/* the GC mark uses bit4:0 of the `object->marked` field, /* the GC mark uses bit4:0 of the `object->marked` field,
* so other bits can be used for special flags (ex-mark). */ * so other bits can be used for special flags (ex-mark). */
typedef enum { typedef enum {
@ -68,6 +71,7 @@ bgcobject *be_newgcobj(bvm *vm, int type, size_t size);
bgcobject* be_gc_newstr(bvm *vm, size_t size, int islong); bgcobject* be_gc_newstr(bvm *vm, size_t size, int islong);
void be_gc_fix(bvm *vm, bgcobject *obj); void be_gc_fix(bvm *vm, bgcobject *obj);
void be_gc_unfix(bvm *vm, bgcobject *obj); void be_gc_unfix(bvm *vm, bgcobject *obj);
bbool be_gc_fix_set(bvm *vm, bgcobject *obj, bbool fix);
void be_gc_collect(bvm *vm); void be_gc_collect(bvm *vm);
void be_gc_auto(bvm *vm); void be_gc_auto(bvm *vm);

View File

@ -12,9 +12,7 @@ extern void be_load_listlib(bvm *vm);
extern void be_load_maplib(bvm *vm); extern void be_load_maplib(bvm *vm);
extern void be_load_rangelib(bvm *vm); extern void be_load_rangelib(bvm *vm);
extern void be_load_filelib(bvm *vm); extern void be_load_filelib(bvm *vm);
extern void be_load_byteslib(bvm *vm);
extern void be_load_tasmota_ntvlib(bvm *vm);
extern void be_load_wirelib(bvm *vm);
void be_loadlibs(bvm *vm) void be_loadlibs(bvm *vm)
{ {
@ -26,6 +24,4 @@ void be_loadlibs(bvm *vm)
be_load_filelib(vm); be_load_filelib(vm);
be_load_byteslib(vm); be_load_byteslib(vm);
#endif #endif
be_load_tasmota_ntvlib(vm);
be_load_wirelib(vm);
} }

View File

@ -315,7 +315,10 @@ bvalue* be_map_insertstr(bvm *vm, bmap *map, bstring *key, bvalue *value)
{ {
bvalue v; bvalue v;
var_setstr(&v, key); var_setstr(&v, key);
return be_map_insert(vm, map, &v, value); set_fixed(key);
bvalue * r = be_map_insert(vm, map, &v, value);
restore_fixed(key);
return r;
} }
void be_map_removestr(bvm *vm, bmap *map, bstring *key) void be_map_removestr(bvm *vm, bmap *map, bstring *key)

View File

@ -10,6 +10,7 @@
#include "be_vm.h" #include "be_vm.h"
#include "be_gc.h" #include "be_gc.h"
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#define GC_ALLOC (1 << 2) /* GC in alloc */ #define GC_ALLOC (1 << 2) /* GC in alloc */
@ -53,6 +54,10 @@ static void* _realloc(void *ptr, size_t old_size, size_t new_size)
return malloc(new_size); return malloc(new_size);
} }
be_assert(new_size == 0); be_assert(new_size == 0);
#if BE_USE_DEBUG_GC
memset(ptr, 0xFF, old_size); /* fill the structure with invalid pointers */
#endif
free(ptr); free(ptr);
return NULL; return NULL;
} }

View File

@ -0,0 +1,232 @@
/********************************************************************
** Copyright (c) 2018-2020 Guan Wenliang
** This file is part of the Berry default interpreter.
** skiars@qq.com, https://github.com/Skiars/berry
** See Copyright Notice in the LICENSE file or at
** https://github.com/Skiars/berry/blob/master/LICENSE
********************************************************************/
#include "be_object.h"
#include "be_module.h"
#include "be_string.h"
#include "be_vector.h"
#include "be_class.h"
#include "be_debug.h"
#include "be_map.h"
#include "be_vm.h"
#include "be_decoder.h"
#include <string.h>
#include <stdio.h>
#if BE_USE_SOLIDIFY_MODULE
#ifndef INST_BUF_SIZE
#define INST_BUF_SIZE 96
#endif
#define logbuf(...) snprintf(__lbuf, sizeof(__lbuf), __VA_ARGS__)
#define logfmt(...) \
do { \
char __lbuf[INST_BUF_SIZE]; \
logbuf(__VA_ARGS__); \
be_writestring(__lbuf); \
} while (0)
/* output only valid types for ktab, or NULL */
static const char * m_type_ktab(int type)
{
switch (type){
case BE_NIL: return "BE_NIL";
case BE_INT: return "BE_INT";
case BE_REAL: return "BE_REAL";
case BE_BOOL: return "BE_BOOL";
case BE_STRING: return "BE_STRING";
default: return NULL;
}
}
static void m_solidify_closure(bvm *vm, bclosure *cl, int builtins)
{
bproto *pr = cl->proto;
const char * func_name = str(pr->name);
const char * func_source = str(pr->source);
// logfmt("// == builtin_count %i\n", builtins);
// logfmt("// type %i, ", cl->type);
// logfmt("// marked %i, ", cl->marked);
// logfmt("// nupvals %i\n", cl->nupvals);
// logfmt("// PROTO:\n");
// logfmt("// type %i, ", pr->type);
// logfmt("// marked %i, ", pr->marked);
// logfmt("// nstack %i, ", pr->nstack);
// logfmt("// argcs %i, ", pr->argc);
// // logfmt("// varg %i\n", pr->varg);
// logfmt("// gray %p\n", (void*)pr->gray);
// logfmt("// upvals %p\n", (void*)pr->upvals);
// logfmt("// proto_tab %p (%i)\n", (void*)pr->ptab, pr->nproto);
// logfmt("// name %s\n", str(pr->name));
// logfmt("// source %s\n", str(pr->source));
// logfmt("\n");
// logfmt("// ktab %p (%i)\n", (void*)pr->ktab, pr->nconst);
// for (int i = 0; i < pr->nconst; i++) {
// logfmt("// const[%i] type %i (%s) %p", i, pr->ktab[i].type, be_vtype2str(&pr->ktab[i]), pr->ktab[i].v.p);
// if (pr->ktab[i].type == BE_STRING) {
// logfmt(" = '%s'", str(pr->ktab[i].v.s));
// }
// logfmt("\n");
// }
logfmt("\n");
logfmt("/********************************************************************\n");
logfmt("** Solidified function: %s\n", func_name);
logfmt("********************************************************************/\n\n");
/* create static strings for name and source */
logfmt("be_define_local_const_str(%s_str_name, \"%s\", %i, 0, %u, 0);\n",
func_name, func_name, be_strhash(pr->name), str_len(pr->name));
logfmt("be_define_local_const_str(%s_str_source, \"%s\", %i, 0, %u, 0);\n",
func_name, func_source, be_strhash(pr->source), str_len(pr->source));
/* create static strings first */
for (int i = 0; i < pr->nconst; i++) {
if (pr->ktab[i].type == BE_STRING) {
logfmt("be_define_local_const_str(%s_str_%i, \"",
func_name, i);
be_writestring(str(pr->ktab[i].v.s));
size_t len = strlen(str(pr->ktab[i].v.s));
if (len >= 255) {
be_raise(vm, "internal_error", "Strings greater than 255 chars not supported yet");
}
logfmt("\", %i, 0, %zu, 0);\n", be_strhash(pr->ktab[i].v.s), len >= 255 ? 255 : len);
}
}
logfmt("\n");
logfmt("static const bvalue %s_ktab[%i] = {\n", func_name, pr->nconst);
for (int k = 0; k < pr->nconst; k++) {
int type = pr->ktab[k].type;
const char *type_name = m_type_ktab(type);
if (type_name == NULL) {
char error[64];
snprintf(error, sizeof(error), "Unsupported type in function constants: %i", type);
be_raise(vm, "internal_error", error);
}
if (type == BE_STRING) {
logfmt(" { { .s=be_local_const_str(%s_str_%i) }, %s},\n", func_name, k, type_name);
} else if (type == BE_INT) {
logfmt(" { { .i=%" BE_INT_FMTLEN "i }, %s},\n", pr->ktab[k].v.i, type_name);
} else if (type == BE_REAL) {
#if BE_USE_SINGLE_FLOAT
logfmt(" { { .p=(void*)0x%08X }, %s},\n", (uint32_t) pr->ktab[k].v.p, type_name);
#else
logfmt(" { { .p=(void*)0x%016llX }, %s},\n", (uint64_t) pr->ktab[k].v.p, type_name);
#endif
} else if (type == BE_BOOL) {
logfmt(" { { .b=%i }, %s},\n", pr->ktab[k].v.b, type_name);
}
}
logfmt("};\n\n");
logfmt("static const uint32_t %s_code[%i] = {\n", func_name, pr->codesize);
for (int pc = 0; pc < pr->codesize; pc++) {
uint32_t ins = pr->code[pc];
logfmt(" 0x%04X, //", ins);
be_print_inst(ins, pc);
bopcode op = IGET_OP(ins);
if (op == OP_GETGBL || op == OP_SETGBL) {
// check if the global is in built-ins
int glb = IGET_Bx(ins);
if (glb > builtins) {
// not supported
logfmt("\n===== unsupported global G%d\n", glb);
be_raise(vm, "internal_error", "Unsupported access to non-builtin global");
}
}
}
logfmt("};\n\n");
logfmt("static const bproto %s_proto = {\n", func_name);
// bcommon_header
logfmt(" NULL, // bgcobject *next\n");
logfmt(" %i, // type\n", pr->type);
logfmt(" GC_CONST, // marked\n");
//
logfmt(" %i, // nstack\n", pr->nstack);
logfmt(" %i, // nupvals\n", pr->nupvals);
logfmt(" %i, // argc\n", pr->argc);
logfmt(" %i, // varg\n", pr->varg);
if (pr->nproto > 0) {
be_raise(vm, "internal_error", "unsupported non-null proto list");
}
logfmt(" NULL, // bgcobject *gray\n");
logfmt(" NULL, // bupvaldesc *upvals\n");
logfmt(" (bvalue*) &%s_ktab, // ktab\n", func_name);
logfmt(" NULL, // bproto **ptab\n");
logfmt(" (binstruction*) &%s_code, // code\n", func_name);
logfmt(" be_local_const_str(%s_str_name), // name\n", func_name);
logfmt(" %i, // codesize\n", pr->codesize);
logfmt(" %i, // nconst\n", pr->nconst);
logfmt(" %i, // nproto\n", pr->nproto);
logfmt(" be_local_const_str(%s_str_source), // source\n", func_name);
//
logfmt("#if BE_DEBUG_RUNTIME_INFO /* debug information */\n");
logfmt(" NULL, // lineinfo\n");
logfmt(" 0, // nlineinfo\n");
logfmt("#endif\n");
logfmt("#if BE_DEBUG_VAR_INFO\n");
logfmt(" NULL, // varinfo\n");
logfmt(" 0, // nvarinfo\n");
logfmt("#endif\n");
logfmt("};\n\n");
// closure
logfmt("static const bclosure %s_closure = {\n", func_name);
// bcommon_header
logfmt(" NULL, // bgcobject *next\n");
logfmt(" %i, // type\n", cl->type);
logfmt(" GC_CONST, // marked\n");
//
logfmt(" %i, // nupvals\n", cl->nupvals);
logfmt(" NULL, // bgcobject *gray\n");
logfmt(" (bproto*) &%s_proto, // proto\n", func_name);
logfmt(" { NULL } // upvals\n");
logfmt("};\n\n");
logfmt("/*******************************************************************/\n\n");
}
#define be_builtin_count(vm) \
be_vector_count(&(vm)->gbldesc.builtin.vlist)
static int m_dump(bvm *vm)
{
if (be_top(vm) >= 1) {
bvalue *v = be_indexof(vm, 1);
if (var_isclosure(v)) {
m_solidify_closure(vm, var_toobj(v), be_builtin_count(vm));
}
}
be_return_nil(vm);
}
#if !BE_USE_PRECOMPILED_OBJECT
be_native_module_attr_table(solidify) {
be_native_module_function("dump", m_dump),
};
be_define_native_module(solidify, NULL);
#else
/* @const_object_info_begin
module solidify (scope: global, depend: BE_USE_SOLIDIFY_MODULE) {
dump, func(m_dump)
}
@const_object_info_end */
#include "../generate/be_fixed_solidify.h"
#endif
#endif /* BE_USE_SOLIFIDY_MODULE */

View File

@ -14,7 +14,7 @@
#define next(_s) cast(void*, cast(bstring*, (_s)->next)) #define next(_s) cast(void*, cast(bstring*, (_s)->next))
#define sstr(_s) cast(char*, cast(bsstring*, _s) + 1) #define sstr(_s) cast(char*, cast(bsstring*, _s) + 1)
#define lstr(_s) cast(char*, cast(blstring*, _s) + 1) #define lstr(_s) cast(char*, cast(blstring*, _s) + 1)
#define cstr(_s) (cast(bcstring*, s)->s) #define cstr(_s) (cast(bcstring*, _s)->s)
#define be_define_const_str(_name, _s, _hash, _extra, _len, _next) \ #define be_define_const_str(_name, _s, _hash, _extra, _len, _next) \
BERRY_LOCAL const bcstring be_const_str_##_name = { \ BERRY_LOCAL const bcstring be_const_str_##_name = { \
@ -45,12 +45,25 @@ int be_eqstr(bstring *s1, bstring *s2)
return 1; return 1;
} }
slen = s1->slen; slen = s1->slen;
/* discard different lengths */
if (slen != s2->slen) {
return 0;
}
/* long string */ /* long string */
if (slen == 255 && slen == s2->slen) { if (slen == 255) { /* s2->slen is also 255 */
blstring *ls1 = cast(blstring*, s1); blstring *ls1 = cast(blstring*, s1);
blstring *ls2 = cast(blstring*, s2); blstring *ls2 = cast(blstring*, s2);
return ls1->llen == ls2->llen && !strcmp(lstr(ls1), lstr(ls2)); return ls1->llen == ls2->llen && !strcmp(lstr(ls1), lstr(ls2));
} }
// TODO one is long const and the other is long string
/* const short strings */
if (gc_isconst(s1) || gc_isconst(s2)) { /* one of the two string is short const */
if (cast(bcstring*, s1)->hash && cast(bcstring*, s2)->hash) {
return 0; /* if they both have a hash, then we know they are different */
}
return !strcmp(str(s1), str(s2));
}
return 0; return 0;
} }
@ -249,7 +262,12 @@ void be_gcstrtab(bvm *vm)
uint32_t be_strhash(const bstring *s) uint32_t be_strhash(const bstring *s)
{ {
if (gc_isconst(s)) { if (gc_isconst(s)) {
return cast(bcstring*, s)->hash; bcstring* cs = cast(bcstring*, s);
if (cs->hash) { /* if hash is null we need to compute it */
return cs->hash;
} else {
return str_hash(cstr(s), str_len(s));
}
} }
#if BE_USE_STR_HASH_CACHE #if BE_USE_STR_HASH_CACHE
if (s->slen != 255) { if (s->slen != 255) {

View File

@ -336,6 +336,18 @@ bstring* be_strindex(bvm *vm, bstring *str, bvalue *idx)
return NULL; return NULL;
} }
size_t be_strlcpy(char *dst, const char *src, size_t maxlen)
{
const size_t srclen = strlen(src);
if (srclen + 1 < maxlen) {
memcpy(dst, src, srclen + 1);
} else if (maxlen != 0) {
memcpy(dst, src, maxlen - 1);
dst[maxlen-1] = '\0';
}
return srclen;
}
const char* be_splitpath(const char *path) const char* be_splitpath(const char *path)
{ {
const char *p; const char *p;

View File

@ -19,6 +19,7 @@ bstring* be_strcat(bvm *vm, bstring *s1, bstring *s2);
int be_strcmp(bstring *s1, bstring *s2); int be_strcmp(bstring *s1, bstring *s2);
bstring* be_num2str(bvm *vm, bvalue *v); bstring* be_num2str(bvm *vm, bvalue *v);
void be_val2str(bvm *vm, int index); void be_val2str(bvm *vm, int index);
size_t be_strlcpy(char *dst, const char *src, size_t size);
const char* be_splitpath(const char *path); const char* be_splitpath(const char *path);
const char* be_splitname(const char *path); const char* be_splitname(const char *path);
const char* be_pushvfstr(bvm *vm, const char *format, va_list arg); const char* be_pushvfstr(bvm *vm, const char *format, va_list arg);

View File

@ -21,6 +21,7 @@
#include "be_debug.h" #include "be_debug.h"
#include "be_libs.h" #include "be_libs.h"
#include <string.h> #include <string.h>
#include <math.h>
#define NOT_METHOD BE_NONE #define NOT_METHOD BE_NONE
@ -51,8 +52,14 @@
DEBUG_HOOK(); \ DEBUG_HOOK(); \
switch (IGET_OP(ins = *vm->ip++)) switch (IGET_OP(ins = *vm->ip++))
#define opcase(opcode) case OP_##opcode #if BE_USE_SINGLE_FLOAT
#define dispatch() goto loop #define mathfunc(func) func##f
#else
#define mathfunc(func) func
#endif
#define opcase(opcode) case OP_##opcode
#define dispatch() goto loop
#define equal_rule(op, iseq) \ #define equal_rule(op, iseq) \
bbool res; \ bbool res; \
@ -561,6 +568,8 @@ newframe: /* a new call frame */
bvalue *dst = RA(), *a = RKB(), *b = RKC(); bvalue *dst = RA(), *a = RKB(), *b = RKC();
if (var_isint(a) && var_isint(b)) { if (var_isint(a) && var_isint(b)) {
var_setint(dst, ibinop(%, a, b)); var_setint(dst, ibinop(%, a, b));
} else if (var_isnumber(a) && var_isnumber(b)) {
var_setreal(dst, mathfunc(fmod)(var_toreal(a), var_toreal(b)));
} else if (var_isinstance(a)) { } else if (var_isinstance(a)) {
ins_binop(vm, "%", ins); ins_binop(vm, "%", ins);
} else { } else {
@ -1055,8 +1064,11 @@ void be_dofunc(bvm *vm, bvalue *v, int argc)
} }
} }
BERRY_API void be_set_obs_hook(bvm *vm, beobshook hook) BERRY_API void be_set_obs_hook(bvm *vm, bobshook hook)
{ {
(void)vm; /* avoid comiler warning */
(void)hook; /* avoid comiler warning */
#if BE_USE_OBSERVABILITY_HOOK #if BE_USE_OBSERVABILITY_HOOK
vm->obshook = hook; vm->obshook = hook;
#endif #endif

View File

@ -87,7 +87,7 @@ struct bvm {
blist *registry; /* registry list */ blist *registry; /* registry list */
struct bgc gc; struct bgc gc;
#if BE_USE_OBSERVABILITY_HOOK #if BE_USE_OBSERVABILITY_HOOK
beobshook obshook; bobshook obshook;
#endif #endif
#if BE_USE_DEBUG_HOOK #if BE_USE_DEBUG_HOOK
bvalue hook; bvalue hook;

View File

@ -101,7 +101,7 @@ enum berrorcode {
#elif defined(__GNUC__) /* in GCC */ #elif defined(__GNUC__) /* in GCC */
#define BERRY_LOCAL __attribute__ ((visibility ("hidden"))) #define BERRY_LOCAL __attribute__ ((visibility ("hidden")))
#else /* other platforms */ #else /* other platforms */
#define BERRY_LOCAL #define BERRY_LOCAL static
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
@ -249,6 +249,22 @@ typedef struct bntvmodule {
} }
#endif #endif
/* support for solidified berry functions */
/* native const strings outside of global string hash */
#define be_define_local_const_str(_name, _s, _hash, _extra, _len, _next) \
BERRY_LOCAL const bcstring be_local_const_str_##_name = { \
.next = (bgcobject *)NULL, \
.type = BE_STRING, \
.marked = GC_CONST, \
.extra = 0, \
.slen = _len, \
.hash = 0, \
.s = _s \
}
#define be_local_const_str(_name) (bstring*) &be_local_const_str_##_name
/* debug hook typedefs */ /* debug hook typedefs */
#define BE_HOOK_LINE 1 #define BE_HOOK_LINE 1
#define BE_HOOK_CALL 2 #define BE_HOOK_CALL 2
@ -275,7 +291,7 @@ typedef void(*bntvhook)(bvm *vm, bhookinfo *info);
/* Observability hook */ /* Observability hook */
typedef void(*beobshook)(bvm *vm, int event, ...); typedef void(*bobshook)(bvm *vm, int event, ...);
enum beobshookevents { enum beobshookevents {
BE_OBS_GC_START, // start of GC, arg = allocated size BE_OBS_GC_START, // start of GC, arg = allocated size
BE_OBS_GC_END, // end of GC, arg = allocated size BE_OBS_GC_END, // end of GC, arg = allocated size
@ -346,6 +362,7 @@ BERRY_API void be_pushnstring(bvm *vm, const char *str, size_t n);
BERRY_API const char* be_pushfstring(bvm *vm, const char *format, ...); BERRY_API const char* be_pushfstring(bvm *vm, const char *format, ...);
BERRY_API void* be_pushbuffer(bvm *vm, size_t size); BERRY_API void* be_pushbuffer(bvm *vm, size_t size);
BERRY_API void be_pushvalue(bvm *vm, int index); BERRY_API void be_pushvalue(bvm *vm, int index);
BERRY_API void be_pushclosure(bvm *vm, void *cl);
BERRY_API void be_pushntvclosure(bvm *vm, bntvfunc f, int nupvals); BERRY_API void be_pushntvclosure(bvm *vm, bntvfunc f, int nupvals);
BERRY_API void be_pushntvfunction(bvm *vm, bntvfunc f); BERRY_API void be_pushntvfunction(bvm *vm, bntvfunc f);
BERRY_API void be_pushclass(bvm *vm, const char *name, const bnfuncinfo *lib); BERRY_API void be_pushclass(bvm *vm, const char *name, const bnfuncinfo *lib);
@ -416,7 +433,7 @@ BERRY_API bvm* be_vm_new(void);
BERRY_API void be_vm_delete(bvm *vm); BERRY_API void be_vm_delete(bvm *vm);
/* Observability hook */ /* Observability hook */
BERRY_API void be_set_obs_hook(bvm *vm, beobshook hook); BERRY_API void be_set_obs_hook(bvm *vm, bobshook hook);
/* code load APIs */ /* code load APIs */
BERRY_API int be_loadbuffer(bvm *vm, BERRY_API int be_loadbuffer(bvm *vm,
@ -431,7 +448,7 @@ BERRY_API void be_module_path_set(bvm *vm, const char *path);
/* bytes operations */ /* bytes operations */
BERRY_API void be_pushbytes(bvm *vm, const void *buf, size_t len); BERRY_API void be_pushbytes(bvm *vm, const void *buf, size_t len);
BERRY_API const void *be_tobytes(bvm *vm, int index, size_t *len); BERRY_API const void* be_tobytes(bvm *vm, int index, size_t *len);
/* registry operation */ /* registry operation */
BERRY_API int be_register(bvm *vm, int index); BERRY_API int be_register(bvm *vm, int index);

View File

@ -0,0 +1,34 @@
/********************************************************************
* Tasmota lib
*
* To use: `d = Driver()`
*
*******************************************************************/
#include "be_object.h"
// #if !BE_USE_PRECOMPILED_OBJECT
#if 1 // TODO we will do pre-compiled later
void be_load_driverlib(bvm *vm)
{
static const bnfuncinfo members[] = {
{ "every_second", NULL },
{ "every_100ms", NULL },
{ "web_add_button", NULL },
{ "web_add_main_button", NULL },
{ "save_before_restart", NULL },
{ "web_sensor", NULL },
{ "json_append", NULL },
{ "button_pressed", NULL },
{ NULL, NULL }
};
be_regclass(vm, "Driver", members);
}
#else
/* @const_object_info_begin
module tasmota (scope: global, depend: 1) {
get_free_heap, func(l_getFreeHeap)
}
@const_object_info_end */
#include "../generate/be_fixed_tasmota.h"
#endif

View File

@ -18,6 +18,7 @@ be_extern_native_module(os);
be_extern_native_module(sys); be_extern_native_module(sys);
be_extern_native_module(debug); be_extern_native_module(debug);
be_extern_native_module(gc); be_extern_native_module(gc);
be_extern_native_module(solidify);
/* Tasmota specific */ /* Tasmota specific */
// be_extern_native_module(tasmota_ntv); // be_extern_native_module(tasmota_ntv);
@ -54,6 +55,9 @@ BERRY_LOCAL const bntvmodule* const be_module_table[] = {
#endif #endif
#if BE_USE_GC_MODULE #if BE_USE_GC_MODULE
&be_native_module(gc), &be_native_module(gc),
#endif
#if BE_USE_SOLIDIFY_MODULE
&be_native_module(solidify),
#endif #endif
/* user-defined modules register start */ /* user-defined modules register start */
@ -62,3 +66,21 @@ BERRY_LOCAL const bntvmodule* const be_module_table[] = {
/* user-defined modules register end */ /* user-defined modules register end */
NULL /* do not remove */ NULL /* do not remove */
}; };
extern void be_load_tasmota_ntvlib(bvm *vm);
extern void be_load_wirelib(bvm *vm);
extern void be_load_driverlib(bvm *vm);
/* this code loads the native class definitions */
BERRY_API void be_load_custom_libs(bvm *vm)
{
(void)vm; /* prevent a compiler warning */
/* add here custom libs */
#if !BE_USE_PRECOMPILED_OBJECT
/* be_load_xxxlib(vm); */
#endif
be_load_tasmota_ntvlib(vm);
be_load_wirelib(vm);
be_load_driverlib(vm);
}

File diff suppressed because it is too large Load Diff

View File

@ -6,6 +6,8 @@
* 2 wire communication - I2C * 2 wire communication - I2C
*******************************************************************/ *******************************************************************/
#include "be_object.h" #include "be_object.h"
#include "be_string.h"
#include "be_gc.h"
extern int b_wire_init(bvm *vm); extern int b_wire_init(bvm *vm);
@ -22,6 +24,189 @@ extern int b_wire_validwrite(bvm *vm);
extern int b_wire_validread(bvm *vm); extern int b_wire_validread(bvm *vm);
extern int b_wire_detect(bvm *vm); extern int b_wire_detect(bvm *vm);
/********************************************************************
"def read_bytes(addr,reg,size) "
"self._begin_transmission(addr) "
"self._write(reg) "
"self._end_transmission(false) "
"self._request_from(addr,size) "
"var ret=bytes(size) "
"while (self._available()) "
"ret..self._read() "
"end "
"return ret "
"end "
********************************************************************/
/********************************************************************
** Solidified function: read_bytes
********************************************************************/
be_define_local_const_str(read_bytes_str_name, "read_bytes", -718234123, 0, 10, 0);
be_define_local_const_str(read_bytes_str_source, "string", 398550328, 0, 6, 0);
be_define_local_const_str(read_bytes_str_0, "_begin_transmission", -1515506120, 0, 19, 0);
be_define_local_const_str(read_bytes_str_1, "_write", -2079504471, 0, 6, 0);
be_define_local_const_str(read_bytes_str_2, "_end_transmission", -1057486896, 0, 17, 0);
be_define_local_const_str(read_bytes_str_3, "_request_from", -329818692, 0, 13, 0);
be_define_local_const_str(read_bytes_str_4, "_available", 1306196581, 0, 10, 0);
be_define_local_const_str(read_bytes_str_5, "_read", 346717030, 0, 5, 0);
static const bvalue read_bytes_ktab[6] = {
{ { .s=be_local_const_str(read_bytes_str_0) }, BE_STRING},
{ { .s=be_local_const_str(read_bytes_str_1) }, BE_STRING},
{ { .s=be_local_const_str(read_bytes_str_2) }, BE_STRING},
{ { .s=be_local_const_str(read_bytes_str_3) }, BE_STRING},
{ { .s=be_local_const_str(read_bytes_str_4) }, BE_STRING},
{ { .s=be_local_const_str(read_bytes_str_5) }, BE_STRING},
};
static const uint32_t read_bytes_code[24] = {
0x8C100100, // 0000 GETMET R4 R0 R256
0x5C180200, // 0001 MOVE R6 R1
0x7C100400, // 0002 CALL R4 2
0x8C100101, // 0003 GETMET R4 R0 R257
0x5C180400, // 0004 MOVE R6 R2
0x7C100400, // 0005 CALL R4 2
0x8C100102, // 0006 GETMET R4 R0 R258
0x50180000, // 0007 LDBOOL R6 0 0
0x7C100400, // 0008 CALL R4 2
0x8C100103, // 0009 GETMET R4 R0 R259
0x5C180200, // 000A MOVE R6 R1
0x5C1C0600, // 000B MOVE R7 R3
0x7C100600, // 000C CALL R4 3
0x60100002, // 000D GETGBL R4 G2
0x5C140600, // 000E MOVE R5 R3
0x7C100200, // 000F CALL R4 1
0x8C140104, // 0010 GETMET R5 R0 R260
0x7C140200, // 0011 CALL R5 1
0x78160003, // 0012 JMPF R5 #0017
0x8C140105, // 0013 GETMET R5 R0 R261
0x7C140200, // 0014 CALL R5 1
0x40140805, // 0015 CONNECT R5 R4 R5
0x7001FFF8, // 0016 JMP #0010
0x80040800, // 0017 RET 1 R4
};
static const bproto read_bytes_proto = {
NULL, // bgcobject *next
8, // type
GC_CONST, // marked
8, // nstack
0, // nupvals
4, // argc
0, // varg
NULL, // bgcobject *gray
NULL, // bupvaldesc *upvals
(bvalue*) &read_bytes_ktab, // ktab
NULL, // bproto **ptab
(binstruction*) &read_bytes_code, // code
be_local_const_str(read_bytes_str_name), // name
24, // codesize
6, // nconst
0, // nproto
be_local_const_str(read_bytes_str_source), // source
#if BE_DEBUG_RUNTIME_INFO /* debug information */
NULL, // lineinfo
0, // nlineinfo
#endif
#if BE_DEBUG_VAR_INFO
NULL, // varinfo
0, // nvarinfo
#endif
};
const bclosure read_bytes_closure = {
NULL, // bgcobject *next
36, // type
GC_CONST, // marked
0, // nupvals
NULL, // bgcobject *gray
(bproto*) &read_bytes_proto, // proto
{ NULL } // upvals
};
/*******************************************************************/
/********************************************************************
"def write_bytes(addr,reg,b) "
"self._begin_transmission(addr) "
"self._write(reg) "
"self._write(b) "
"self._end_transmission() "
"end "
********************************************************************/
/********************************************************************
** Solidified function: write_bytes
********************************************************************/
be_define_local_const_str(write_bytes_str_name, "write_bytes", 1227543792, 0, 11, 0);
be_define_local_const_str(write_bytes_str_source, "string", 398550328, 0, 6, 0);
be_define_local_const_str(write_bytes_str_0, "_begin_transmission", -1515506120, 0, 19, 0);
be_define_local_const_str(write_bytes_str_1, "_write", -2079504471, 0, 6, 0);
be_define_local_const_str(write_bytes_str_2, "_end_transmission", -1057486896, 0, 17, 0);
static const bvalue write_bytes_ktab[3] = {
{ { .s=be_local_const_str(write_bytes_str_0) }, BE_STRING},
{ { .s=be_local_const_str(write_bytes_str_1) }, BE_STRING},
{ { .s=be_local_const_str(write_bytes_str_2) }, BE_STRING},
};
static const uint32_t write_bytes_code[12] = {
0x8C100100, // 0000 GETMET R4 R0 R256
0x5C180200, // 0001 MOVE R6 R1
0x7C100400, // 0002 CALL R4 2
0x8C100101, // 0003 GETMET R4 R0 R257
0x5C180400, // 0004 MOVE R6 R2
0x7C100400, // 0005 CALL R4 2
0x8C100101, // 0006 GETMET R4 R0 R257
0x5C180600, // 0007 MOVE R6 R3
0x7C100400, // 0008 CALL R4 2
0x8C100102, // 0009 GETMET R4 R0 R258
0x7C100200, // 000A CALL R4 1
0x80000000, // 000B RET 0 R0
};
static const bproto write_bytes_proto = {
NULL, // bgcobject *next
8, // type
GC_CONST, // marked
7, // nstack
0, // nupvals
4, // argc
0, // varg
NULL, // bgcobject *gray
NULL, // bupvaldesc *upvals
(bvalue*) &write_bytes_ktab, // ktab
NULL, // bproto **ptab
(binstruction*) &write_bytes_code, // code
be_local_const_str(write_bytes_str_name), // name
12, // codesize
3, // nconst
0, // nproto
be_local_const_str(write_bytes_str_source), // source
#if BE_DEBUG_RUNTIME_INFO /* debug information */
NULL, // lineinfo
0, // nlineinfo
#endif
#if BE_DEBUG_VAR_INFO
NULL, // varinfo
0, // nvarinfo
#endif
};
const bclosure write_bytes_closure = {
NULL, // bgcobject *next
36, // type
GC_CONST, // marked
0, // nupvals
NULL, // bgcobject *gray
(bproto*) &write_bytes_proto, // proto
{ NULL } // upvals
};
/*******************************************************************/
// #if !BE_USE_PRECOMPILED_OBJECT // #if !BE_USE_PRECOMPILED_OBJECT
#if 1 // TODO we will do pre-compiled later #if 1 // TODO we will do pre-compiled later
void be_load_wirelib(bvm *vm) void be_load_wirelib(bvm *vm)
@ -39,10 +224,14 @@ void be_load_wirelib(bvm *vm)
{ "write", b_wire_validwrite }, { "write", b_wire_validwrite },
{ "read", b_wire_validread }, { "read", b_wire_validread },
{ "detect", b_wire_detect }, { "detect", b_wire_detect },
{ NULL, (bntvfunc) BE_CLOSURE }, /* mark section for berry closures */
{ "read_bytes", (bntvfunc) &read_bytes_closure },
{ "write_bytes", (bntvfunc) &write_bytes_closure },
{ NULL, NULL } { NULL, NULL }
}; };
be_regclass(vm, "Wire_ntv", members); be_regclass(vm, "Wire", members);
} }
#else #else
/* @const_object_info_begin /* @const_object_info_begin

View File

@ -155,6 +155,7 @@
#define BE_USE_SYS_MODULE 0 #define BE_USE_SYS_MODULE 0
#define BE_USE_DEBUG_MODULE 1 #define BE_USE_DEBUG_MODULE 1
#define BE_USE_GC_MODULE 1 #define BE_USE_GC_MODULE 1
#define BE_USE_SOLIDIFY_MODULE 1
/* Macro: BE_EXPLICIT_XXX /* Macro: BE_EXPLICIT_XXX
* If these macros are defined, the corresponding function will * If these macros are defined, the corresponding function will

122
tasmota/berry/mpu6886.be Normal file
View File

@ -0,0 +1,122 @@
#-
- Example of I2C driver written in Berry
-
- Support for MPU6886 device found in M5Stack
- Alternative to xsns_85_mpu6886.ino
-#
class MPU6886 : Driver
var enabled, wire
var gres, ares
var accel, gyro
def init()
self.enabled = false
if tasmota.i2c_enabled(58) || 1
var bus = 1
if wire1.detect(0x68)
self.wire = wire1
elif wire2.detect(0x68)
self.wire = wire2
bus = 2
end
if self.wire
var v = self.wire.read(0x68,0x75,1)
if v != 0x19 return end #- wrong device -#
self.wire.write(0x68, 0x6B, 0, 1)
tasmota.delay(10)
self.wire.write(0x68, 0x6B, 1<<7, 1) # MPU6886_PWR_MGMT_1
tasmota.delay(10)
self.wire.write(0x68, 0x6B, 1<<0, 1) # MPU6886_PWR_MGMT_1
tasmota.delay(10)
self.wire.write(0x68, 0x1C, 0x10, 1) # MPU6886_ACCEL_CONFIG - AFS_8G
tasmota.delay(1)
self.wire.write(0x68, 0x1B, 0x18, 1) # MPU6886_GYRO_CONFIG - GFS_2000DPS
tasmota.delay(1)
self.wire.write(0x68, 0x1A, 0x01, 1) # MPU6886_CONFIG
tasmota.delay(1)
self.wire.write(0x68, 0x19, 0x05, 1) # MPU6886_SMPLRT_DIV
tasmota.delay(1)
self.wire.write(0x68, 0x38, 0x00, 1) # MPU6886_INT_ENABLE
tasmota.delay(1)
self.wire.write(0x68, 0x1D, 0x00, 1) # MPU6886_ACCEL_CONFIG2
tasmota.delay(1)
self.wire.write(0x68, 0x6A, 0x00, 1) # MPU6886_USER_CTRL
tasmota.delay(1)
self.wire.write(0x68, 0x23, 0x00, 1) # MPU6886_FIFO_EN
tasmota.delay(1)
self.wire.write(0x68, 0x37, 0x22, 1) # MPU6886_INT_PIN_CFG
tasmota.delay(1)
self.wire.write(0x68, 0x38, 0x01, 1) # MPU6886_INT_ENABLE
tasmota.delay(100)
self.enabled = true
self.gres = 2000.0/32768.0
self.ares = 8.0/32678.0
print("I2C: MPU6886 detected on bus "+str(bus))
end
end
end
#- returns a list of 3 axis, float as g acceleration -#
def read_accel()
var b = self.wire.read_bytes(0x68,0x3B,6)
var a1 = b.get(0,-2)
if a1 >= 0x8000 a1 -= 0x10000 end
var a2 = b.get(2,-2)
if a2 >= 0x8000 a2 -= 0x10000 end
var a3 = b.get(4,-2)
if a3 >= 0x8000 a3 -= 0x10000 end
self.accel = [a1 * self.ares, a2 * self.ares, a3 * self.ares]
return self.accel
end
#- returns a list of 3 gyroscopes, int as dps (degree per second) -#
def read_gyro()
var b = self.wire.read_bytes(0x68,0x43,6)
var g1 = b.get(0,-2)
if g1 >= 0x8000 g1 -= 0x10000 end
var g2 = b.get(2,-2)
if g2 >= 0x8000 g2 -= 0x10000 end
var g3 = b.get(4,-2)
if g3 >= 0x8000 g3 -= 0x10000 end
self.gyro = [int(g1 * self.gres), int(g2 * self.gres), int(g3 * self.gres)]
return self.gyro
end
#- trigger a read every second -#
def every_second()
self.read_accel()
self.read_gyro()
end
#- display sensor value in the web UI -#
def web_sensor()
import string
var msg = string.format(
"{s}MPU6886 acc_x{m}%f G{e}"..
"{s}MPU6886 acc_y{m}%f G{e}"..
"{s}MPU6886 acc_z{m}%f G{e}"..
"{s}MPU6886 gyr_x{m}%i dps{e}"..
"{s}MPU6886 gyr_y{m}%i dps{e}"..
"{s}MPU6886 gyr_z{m}%i dps{e}",
self.accel[0], self.accel[1], self.accel[2], self.gyro[0], self.gyro[1], self.gyro[2])
tasmota.web_send_decimal(msg)
end
#- add sensor value to teleperiod -#
def json_append()
import string
var ax = int(self.accel[0] * 1000)
var ay = int(self.accel[1] * 1000)
var az = int(self.accel[2] * 1000)
var msg = string.format(",\"MPU6886\":{\"AX\":%i,\"AY\":%i,\"AZ\":%i,\"GX\":%i,\"GY\":%i,\"GZ\":%i}",
ax, ay, az, self.gyro[0], self.gyro[1], self.gyro[2])
tasmota.response_append(msg)
end
end
mpu = MPU6886()
tasmota.add_driver(mpu)

View File

@ -22,6 +22,8 @@
#include <berry.h> #include <berry.h>
#define BERRY_CONSOLE_CMD_DELIMITER "\x01"
typedef LList_elt<char[0]> log_elt; // store the string after the header to avoid double allocation if we had used char* typedef LList_elt<char[0]> log_elt; // store the string after the header to avoid double allocation if we had used char*
class BerryLog { class BerryLog {

View File

@ -218,6 +218,30 @@ extern "C" {
be_raise(vm, kTypeError, nullptr); be_raise(vm, kTypeError, nullptr);
} }
// Response_append
int32_t l_respAppend(bvm *vm);
int32_t l_respAppend(bvm *vm) {
int32_t top = be_top(vm); // Get the number of arguments
if (top == 2 && be_isstring(vm, 2)) {
const char *msg = be_tostring(vm, 2);
ResponseAppend_P(PSTR("%s"), msg);
be_return_nil(vm); // Return nil when something goes wrong
}
be_raise(vm, kTypeError, nullptr);
}
// web append with decimal conversion
int32_t l_webSendDecimal(bvm *vm);
int32_t l_webSendDecimal(bvm *vm) {
int32_t top = be_top(vm); // Get the number of arguments
if (top == 2 && be_isstring(vm, 2)) {
const char *msg = be_tostring(vm, 2);
WSContentSend_PD(PSTR("%s"), msg);
be_return_nil(vm); // Return nil when something goes wrong
}
be_raise(vm, kTypeError, nullptr);
}
// push the light status object on the vm stack // push the light status object on the vm stack
void push_getlight(bvm *vm, uint32_t light_num) { void push_getlight(bvm *vm, uint32_t light_num) {
bool data_present = false; // do we have relevant data bool data_present = false; // do we have relevant data
@ -501,17 +525,19 @@ extern "C" {
extern "C" { extern "C" {
// Berry: `log(msg:string [,log_level:int]) ->nil` // Berry: `log(msg:string [,log_level:int]) ->nil`
// Logs the string at LOG_LEVEL_INFO (loglevel=2) // Logs the string at LOG_LEVEL_INFO (loglevel=2)
// We allow this function to be called as a method or a direct function
// if the first argument is an instance, we remove it
int32_t l_logInfo(struct bvm *vm); int32_t l_logInfo(struct bvm *vm);
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 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 if (top >= 2 && be_isstring(vm, 2)) { // only 1 argument of type string accepted
const char * msg = be_tostring(vm, 1); const char * msg = be_tostring(vm, 2);
uint32_t log_level = LOG_LEVEL_INFO; uint32_t log_level = LOG_LEVEL_INFO;
if (top >= 2 && be_isint(vm, 2)) { if (top >= 3 && be_isint(vm, 3)) {
log_level = be_toint(vm, 2); log_level = be_toint(vm, 3);
if (log_level > LOG_LEVEL_DEBUG_MORE) { log_level = LOG_LEVEL_DEBUG_MORE; } if (log_level > LOG_LEVEL_DEBUG_MORE) { log_level = LOG_LEVEL_DEBUG_MORE; }
} }
AddLog(log_level, PSTR("%s"), msg); AddLog_P(log_level, PSTR("%s"), msg);
be_return(vm); // Return be_return(vm); // Return
} }
be_return_nil(vm); // Return nil when something goes wrong be_return_nil(vm); // Return nil when something goes wrong
@ -529,8 +555,8 @@ extern "C" {
int32_t l_save(struct bvm *vm); int32_t l_save(struct bvm *vm);
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 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 if (top == 3 && be_isstring(vm, 2) && be_isclosure(vm, 3)) { // only 1 argument of type string accepted
const char *fname = be_tostring(vm, 1); const char *fname = be_tostring(vm, 2);
int32_t ret = be_savecode(vm, fname); int32_t ret = be_savecode(vm, fname);
be_pushint(vm, ret); be_pushint(vm, ret);
be_return(vm); // Return be_return(vm); // Return
@ -542,14 +568,19 @@ extern "C" {
// called as a replacement to Berry `print()` // called as a replacement to Berry `print()`
void berry_log(const char * berry_buf); void berry_log(const char * berry_buf);
void berry_log(const char * berry_buf) { void berry_log(const char * berry_buf) {
if (berry.repl_active) { const char * pre_delimiter = nullptr; // do we need to prepend a delimiter if no REPL command
if (!berry.repl_active) {
// if no REPL in flight, we limit the number of logs
if (berry.log.log.length() == 0) {
pre_delimiter = BERRY_CONSOLE_CMD_DELIMITER;
}
if (berry.log.log.length() >= BERRY_MAX_LOGS) { if (berry.log.log.length() >= BERRY_MAX_LOGS) {
berry.log.log.remove(berry.log.log.head()); berry.log.log.remove(berry.log.log.head());
} }
} }
// AddLog(LOG_LEVEL_INFO, PSTR("[Add to log] %s"), berry_buf); // AddLog(LOG_LEVEL_INFO, PSTR("[Add to log] %s"), berry_buf);
berry.log.addString(berry_buf, nullptr, "\n"); berry.log.addString(berry_buf, pre_delimiter, "\n");
AddLog(LOG_LEVEL_INFO, PSTR("%s"), berry_buf); AddLog_P(LOG_LEVEL_INFO, PSTR("%s"), berry_buf);
} }

View File

@ -27,13 +27,8 @@
const char berry_prog[] = 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\") "
// create a 'ntv' module to allow functions to be registered in a safe namespace // create a 'ntv' module to allow functions to be registered in a safe namespace
"ntv = module('ntv') " // "ntv = module('ntv') "
// auto-import modules // auto-import modules
// // import alias // // import alias
@ -42,140 +37,141 @@ const char berry_prog[] =
// Phase 1 // Phase 1
"class Tasmota: Tasmota_ntv " "class Tasmota: Tasmota_ntv "
// for now the variables are built, need to find a way to push in Flash // for now the variables are built, need to find a way to push in Flash
"def init() " // "def init() "
"self._op = ['==', '!==', '=', '!=', '>=', '<=', '>', '<'] " // "end "
"self._opf = [ " // // add `chars_in_string(s:string,c:string) -> int``
"/s1,s2-> str(s1) == str(s2)," // // looks for any char in c, and return the position of the first char
"/s1,s2-> str(s1) != str(s2)," // // or -1 if not found
"/f1,f2-> real(f1) == real(f2)," // // inv is optional and inverses the behavior, i.e. look for chars not in the list
"/f1,f2-> real(f1) != real(f2)," // "def chars_in_string(s,c,inv) "
"/f1,f2-> real(f1) >= real(f2)," // "var inverted = inv ? true : false "
"/f1,f2-> real(f1) <= real(f2)," // "for i:0..size(s)-1 "
"/f1,f2-> real(f1) > real(f2)," // "var found = false "
"/f1,f2-> real(f1) < real(f2)," // "for j:0..size(c)-1 "
"] " // "if s[i] == c[j] found = true end "
"self._operators = \"=<>!|\" " // "end "
"end " // "if inverted != found return i end "
// add `chars_in_string(s:string,c:string) -> int`` // "end "
// looks for any char in c, and return the position of the first chat // "return -1 "
// or -1 if not found // "end "
"def chars_in_string(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 // // find a key in map, case insensitive, return actual key or nil if not found
"def find_key_i(m,keyi) " // "def find_key_i(m,keyi) "
"import string " // "import string "
"var keyu = string.toupper(keyi) " // "var keyu = string.toupper(keyi) "
"if classof(m) == map " // "if classof(m) == map "
"for k:m.keys() " // "for k:m.keys() "
"if string.toupper(k)==keyu || keyi=='?' " // "if string.toupper(k)==keyu || keyi=='?' "
"return k " // "return k "
"end " // "end "
"end " // "end "
"end " // "end "
"end " // "end "
// # split the item when there is an operator, returns a list of (left,op,right) // # split the item when there is an operator, returns a list of (left,op,right)
// # ex: "Dimmer>50" -> ["Dimmer",tasmota_gt,"50"] // // # ex: "Dimmer>50" -> ["Dimmer",tasmota_gt,"50"]
"def find_op(item) " // "def find_op(item) "
"import string " // "import string "
"var pos = self.chars_in_string(item, self._operators) " // "var op_chars = '=<>!' "
"if pos>=0 " // "var pos = self.chars_in_string(item, op_chars) "
"var op_split = string.split(item,pos) " // "if pos >= 0 "
// #print(op_split) // "var op_split = string.split(item,pos) "
"var op_left = op_split[0] " // "var op_left = op_split[0] "
"var op_rest = op_split[1] " // "var op_rest = op_split[1] "
// # iterate through operators // "pos = self.chars_in_string(op_rest, op_chars, true) "
"for i: 0..size(self._op)-1 " // "if pos >= 0 "
"var op = self._op[i] " // "var op_split2 = string.split(op_rest,pos) "
"if string.find(op_rest,op) == 0 " // "var op_middle = op_split2[0] "
"var op_func = self._opf[i] " // "var op_right = op_split2[1] "
"var op_right = string.split(op_rest,size(op))[1] " // "return [op_left,op_middle,op_right] "
"return [op_left,op_func,op_right] " // "end "
"end " // "end "
"end " // "return [item, nil, nil] "
"end " // "end "
"return [item, nil, nil] "
"end "
// Rules // // Rules
"def add_rule(pat,f) " // "def add_rule(pat,f) "
"if !self._rules " // "if !self._rules "
"self._rules={} " // "self._rules={} "
"end " // "end "
"self._rules[pat] = f " // "self._rules[pat] = f "
"end " // "end "
// Rules trigger if match. return true if match, false if not // // Rules trigger if match. return true if match, false if not
"def try_rule(ev, rule, f) " // "def try_rule(ev, rule, f) "
"import string " // "import string "
"var rl_list = self.find_op(rule) " // "var rl_list = self.find_op(rule) "
"var e=ev " // "var e=ev "
"var rl=string.split(rl_list[0],'#') " // "var rl=string.split(rl_list[0],'#') "
"for it:rl " // "for it:rl "
"found=self.find_key_i(e,it) " // "found=self.find_key_i(e,it) "
"if found == nil " // "if found == nil return false end "
"return false " // "e=e[found] "
"end " // "end "
"e=e[found] " // "var op=rl_list[1]"
"end " // "var op2=rl_list[2]"
// # check if condition is true // "if op "
"if rl_list[1] " // "if op=='==' "
// # did we find a function // "if str(e) != str(op2) return false end "
"if !rl_list[1](e,rl_list[2]) " // "elif op=='!==' "
// # condition is not met // "if str(e) == str(op2) return false end "
"return false " // "elif op=='=' "
"end " // "if real(e) != real(op2) return false end "
"end " // "elif op=='!=' "
"f(e,ev) " // "if real(e) == real(op2) return false end "
"return true " // "elif op=='>' "
"end " // "if real(e) <= real(op2) return false end "
// "elif op=='>=' "
// "if real(e) < real(op2) return false end "
// "elif op=='<' "
// "if real(e) >= real(op2) return false end "
// "elif op=='<=' "
// "if real(e) > real(op2) return false end "
// "end "
// "end "
// "f(e,ev) "
// "return true "
// "end "
// Run rules, i.e. check each individual rule // // Run rules, i.e. check each individual rule
// Returns true if at least one rule matched, false if none // // Returns true if at least one rule matched, false if none
"def exec_rules(ev_json) " // "def exec_rules(ev_json) "
"if self._rules " // "if self._rules "
"import json " // "import json "
"var ev = json.load(ev_json) " // "var ev = json.load(ev_json) "
"var ret = false " // "var ret = false "
"if ev == nil " // "if ev == nil "
"print('BRY: ERROR, bad json: '+ev_json, 3) " // "print('BRY: ERROR, bad json: '+ev_json, 3) "
"else " // "else "
"for r: self._rules.keys() " // "for r: self._rules.keys() "
"ret = self.try_rule(ev,r,self._rules[r]) || ret " // "ret = self.try_rule(ev,r,self._rules[r]) || ret "
"end " // "end "
"end " // "end "
"return ret " // "return ret "
"end " // "end "
"return false " // "return false "
"end " // "end "
"def set_timer(delay,f) " // "def set_timer(delay,f) "
"if !self._timers self._timers=[] end " // "if !self._timers self._timers=[] end "
"self._timers.push([self.millis(delay),f]) " // "self._timers.push([self.millis(delay),f]) "
"end " // "end "
// run every 50ms tick // // run every 50ms tick
"def run_deferred() " // "def run_deferred() "
"if self._timers " // "if self._timers "
"var i=0 " // "var i=0 "
"while i<self._timers.size() " // "while i<self._timers.size() "
"if self.time_reached(self._timers[i][0]) " // "if self.time_reached(self._timers[i][0]) "
"f=self._timers[i][1] " // "f=self._timers[i][1] "
"self._timers.remove(i) " // "self._timers.remove(i) "
"f() " // "f() "
"else " // "else "
"i=i+1 " // "i=i+1 "
"end " // "end "
"end " // "end "
"end " // "end "
"end " // "end "
// // Delay function, internally calls yield() every 10ms to avoid WDT // // Delay function, internally calls yield() every 10ms to avoid WDT
// "def delay(ms) " // "def delay(ms) "
@ -185,147 +181,143 @@ const char berry_prog[] =
// "end " // "end "
// "end " // "end "
// Add command to list // // Add command to list
"def add_cmd(c,f) " // "def add_cmd(c,f) "
"if !self._cmd " // "if !self._cmd "
"self._cmd={} " // "self._cmd={} "
"end " // "end "
"self._cmd[c]=f " // "self._cmd[c]=f "
"end " // "end "
"def exec_cmd(cmd, idx, payload) " // "def exec_cmd(cmd, idx, payload) "
"if self._cmd " // "if self._cmd "
"import json " // "import json "
"var payload_json = json.load(payload) " // "var payload_json = json.load(payload) "
"var cmd_found = self.find_key_i(self._cmd, cmd) " // "var cmd_found = self.find_key_i(self._cmd, cmd) "
"if cmd_found != nil " // "if cmd_found != nil "
"self.resolvecmnd(cmd_found) " // set the command name in XdrvMailbox.command // "self.resolvecmnd(cmd_found) " // set the command name in XdrvMailbox.command
"self._cmd[cmd_found](cmd_found, idx, payload, payload_json) " // "self._cmd[cmd_found](cmd_found, idx, payload, payload_json) "
"return true " // "return true "
"end " // "end "
"end " // "end "
"return false " // "return false "
"end " // "end "
// Force gc and return allocated memory // // Force gc and return allocated memory
"def gc() " // "def gc() "
"import gc " // "import gc "
"gc.collect() " // "gc.collect() "
"return gc.allocated() " // "return gc.allocated() "
"end " // // "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 "
// "try "
// "self.save(f+'c', c) "
// "except .. as e "
// "self.log(string.format('BRY: could not save compiled file %s (%s)',f+'c',e)) "
// "end "
// "end "
// // call the compiled code
// "c() "
// "self.log(string.format(\"BRY: sucessfully loaded '%s'\",f)) "
// "except .. as e "
// "raise \"io_error\",string.format(\"Could not load file '%s'\",f) "
// "end "
// // "end "
// Event from Tasmota is:
// 1. event:string -- type of event (cmd, rule, ...) // //
// 2. cmd:string -- name of the command to process // // Event from Tasmota is:
// 3. index:int -- index number // // 1. event:string -- type of event (cmd, rule, ...)
// 4. payload:string -- payload as text, analyzed as json // // 2. cmd:string -- name of the command to process
// // // 3. index:int -- index number
"def event(type, cmd, idx, payload) " // // 4. payload:string -- payload as text, analyzed as json
"if type=='cmd' return self.exec_cmd(cmd, idx, payload) " // // //
"elif type=='rule' return self.exec_rules(payload) " // "def event(type, cmd, idx, payload) "
"elif type=='mqtt_data' return nil " // not yet implemented // "if type=='cmd' return self.exec_cmd(cmd, idx, payload) "
"elif type=='gc' return self.gc() " // "elif type=='rule' return self.exec_rules(payload) "
"elif type=='every_50ms' return self.run_deferred() " // "elif type=='mqtt_data' return nil " // not yet implemented
"elif self._drivers " // "elif type=='gc' return self.gc() "
"for d:self._drivers " // "elif type=='every_50ms' return self.run_deferred() "
"try " // "elif self._drivers "
"if d.dispatch && d.dispatch(type, cmd, idx, payload) nil " // nil for `nop` // "for d:self._drivers "
"elif type=='every_second' && d.every_second return d.every_second() " // "try "
"elif type=='every_100ms' && d.every_100ms return d.every_100ms() " // "if type=='every_second' && d.every_second return d.every_second() "
"end " // "elif type=='every_100ms' && d.every_100ms return d.every_100ms() "
"except .. as e,m " // "elif type=='web_add_button' && d.web_add_button return d.web_add_button() "
"import string " // "elif type=='web_add_main_button' && d.web_add_main_button return d.web_add_main_button() "
"log(string.format('BRY: exception %s - %m',3)) " // "elif type=='save_before_restart' && d.save_before_restart return d.save_before_restart() "
"end " // "elif type=='web_sensor' && d.web_sensor return d.web_sensor() "
"end " // "elif type=='json_append' && d.json_append return d.json_append() "
"end " // "elif type=='button_pressed' && d.button_pressed return d.button_pressed() "
"end " // "end "
// "except .. as e,m "
// "import string "
// "self.log(string.format('BRY: exception %s - %m',3)) "
// "end "
// "end "
// "end "
// "end "
// //
// add driver to the queue of event dispatching // add driver to the queue of event dispatching
// //
"def add_driver(d) " // "def add_driver(d) "
"if self._drivers " // "if self._drivers "
"self._drivers.push(d) " // "self._drivers.push(d) "
"else " // "else "
"self._drivers = [d]" // "self._drivers = [d]"
"end " // "end "
"end " // "end "
"end " "end "
// Instantiate tasmota object // Instantiate tasmota object
"tasmota = Tasmota() " "tasmota = Tasmota() "
"def log(m,l) tasmota.log(m,l) end "
"def load(f) tasmota.load(f) end "
// Wire class // Wire class
"class Wire : Wire_ntv " // "class Wire : Wire_ntv "
// read bytes as `bytes()` object // // read bytes as `bytes()` object
"def read_bytes(addr,reg,size) " // "def read_bytes(addr,reg,size) "
"self._begin_transmission(addr) " // "self._begin_transmission(addr) "
"self._write(reg) " // "self._write(reg) "
"self._end_transmission(false) " // "self._end_transmission(false) "
"self._request_from(addr,size) " // "self._request_from(addr,size) "
"var ret=bytes(size) " // "var ret=bytes(size) "
"while (self._available()) " // "while (self._available()) "
"ret..self._read() " // "ret..self._read() "
"end " // "end "
"return ret " // "return ret "
"end " // "end "
// write bytes from `bytes` object // // write bytes from `bytes` object
"def write_bytes(addr,reg,b) " // "def write_bytes(addr,reg,b) "
"self._begin_transmission(addr) " // "self._begin_transmission(addr) "
"self._write(reg) " // "self._write(reg) "
"self._write(b) " // "self._write(b) "
"self._end_transmission() " // "self._end_transmission() "
"end " // "end "
"end " // "end "
"wire = Wire(0) " "wire = Wire(0) "
"wire1 = wire " "wire1 = wire "
"wire2 = Wire(1) " "wire2 = Wire(1) "
//
// Base class for Tasmota Driver
//
"class Driver "
// functions are needs to be set to trigger an event
"var dispatch " // general dispatcher, returns true if serviced
"var every_second " // called every_second
"var every_100ms " // called every 100ms
// ...
"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 "
"try "
"save(f+'c', c) "
"except .. as e "
"log(string.format('BRY: could not save compiled file %s (%s)',f+'c',e)) "
"end "
"end "
// call the compiled code
"c() "
"log(string.format(\"BRY: sucessfully loaded '%s'\",f)) "
"except .. as e "
"raise \"io_error\",string.format(\"Could not load file '%s'\",f) "
"end "
"end "
// try to load "/autoexec.be" // try to load "/autoexec.be"
// "try compile('/autoexec.be','file')() except .. log('BRY: no /autoexec.bat file') end " // "try compile('/autoexec.be','file')() except .. log('BRY: no /autoexec.bat file') end "
; ;

View File

@ -24,7 +24,9 @@
#include <berry.h> #include <berry.h>
#define BERRY_CONSOLE_CMD_DELIMITER "\x01" extern "C" {
extern void be_load_custom_libs(bvm *vm);
}
const char kBrCommands[] PROGMEM = D_PRFX_BR "|" // prefix const char kBrCommands[] PROGMEM = D_PRFX_BR "|" // prefix
D_CMND_BR_RUN "|" D_CMND_BR_RESET D_CMND_BR_RUN "|" D_CMND_BR_RESET
@ -179,8 +181,9 @@ int32_t callBerryEventDispatcher(const char *type, const char *cmd, int32_t idx,
be_pushstring(berry.vm, payload != nullptr ? payload : "{}"); // empty json be_pushstring(berry.vm, payload != nullptr ? payload : "{}"); // empty json
be_pcall(berry.vm, 5); // 5 arguments be_pcall(berry.vm, 5); // 5 arguments
be_pop(berry.vm, 5); be_pop(berry.vm, 5);
if (be_isint(berry.vm, -1)) { if (be_isint(berry.vm, -1) || be_isbool(berry.vm, -1)) {
ret = be_toint(berry.vm, -1); if (be_isint(berry.vm, -1)) { ret = be_toint(berry.vm, -1); }
if (be_isbool(berry.vm, -1)) { ret = be_tobool(berry.vm, -1); }
} }
} }
be_pop(berry.vm, 1); // remove method be_pop(berry.vm, 1); // remove method
@ -238,11 +241,12 @@ void BrReset(void) {
do { do {
berry.vm = be_vm_new(); /* create a virtual machine instance */ berry.vm = be_vm_new(); /* create a virtual machine instance */
be_set_obs_hook(berry.vm, &BerryObservability); be_set_obs_hook(berry.vm, &BerryObservability);
be_load_custom_libs(berry.vm);
// AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_BERRY "Berry VM created, RAM used=%u"), be_gc_memcount(berry.vm)); // AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_BERRY "Berry VM created, RAM used=%u"), be_gc_memcount(berry.vm));
// Register functions // Register functions
be_regfunc(berry.vm, PSTR("log"), l_logInfo); // be_regfunc(berry.vm, PSTR("log"), l_logInfo);
be_regfunc(berry.vm, PSTR("save"), l_save); // 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)); // AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_BERRY "Berry function registered, RAM used=%u"), be_gc_memcount(berry.vm));
@ -727,7 +731,7 @@ bool Xdrv52(uint8_t function)
callBerryEventDispatcher(PSTR("web_add_main_button"), nullptr, 0, nullptr); callBerryEventDispatcher(PSTR("web_add_main_button"), nullptr, 0, nullptr);
break; break;
case FUNC_WEB_ADD_HANDLER: case FUNC_WEB_ADD_HANDLER:
callBerryEventDispatcher(PSTR("web_add_handler"), nullptr, 0, nullptr); // callBerryEventDispatcher(PSTR("web_add_handler"), nullptr, 0, nullptr);
WebServer_on(PSTR("/bs"), HandleBerryConsole); WebServer_on(PSTR("/bs"), HandleBerryConsole);
break; break;
#endif // USE_WEBSERVER #endif // USE_WEBSERVER
@ -739,7 +743,7 @@ bool Xdrv52(uint8_t function)
break; break;
case FUNC_JSON_APPEND: case FUNC_JSON_APPEND:
callBerryEventDispatcher(PSTR("json_aooend"), nullptr, 0, nullptr); callBerryEventDispatcher(PSTR("json_append"), nullptr, 0, nullptr);
break; break;
case FUNC_BUTTON_PRESSED: case FUNC_BUTTON_PRESSED: