mirror of https://github.com/arendst/Tasmota.git
Merge pull request #11208 from s-hadinger/berry_mar_2
Berry improvements
This commit is contained in:
commit
7f501578b3
|
@ -504,6 +504,9 @@ void be_gc_collect(bvm *vm)
|
||||||
if (vm->gc.status & GC_HALT) {
|
if (vm->gc.status & GC_HALT) {
|
||||||
return; /* the GC cannot run for some reason */
|
return; /* the GC cannot run for some reason */
|
||||||
}
|
}
|
||||||
|
#if BE_USE_OBSERVABILITY_HOOK
|
||||||
|
if (vm->obshook != NULL) (*vm->obshook)(vm, BE_OBS_GC_START, vm->gc.usage);
|
||||||
|
#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 */
|
||||||
premark_global(vm); /* global objects */
|
premark_global(vm); /* global objects */
|
||||||
|
@ -520,4 +523,7 @@ void be_gc_collect(bvm *vm)
|
||||||
reset_fixedlist(vm);
|
reset_fixedlist(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 (vm->obshook != NULL) (*vm->obshook)(vm, BE_OBS_GC_END, vm->gc.usage);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -398,6 +398,9 @@ BERRY_API bvm* be_vm_new(void)
|
||||||
be_globalvar_init(vm);
|
be_globalvar_init(vm);
|
||||||
be_gc_setpause(vm, 1);
|
be_gc_setpause(vm, 1);
|
||||||
be_loadlibs(vm);
|
be_loadlibs(vm);
|
||||||
|
#if BE_USE_OBSERVABILITY_HOOK
|
||||||
|
vm->obshook = NULL;
|
||||||
|
#endif
|
||||||
return vm;
|
return vm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1051,3 +1054,10 @@ void be_dofunc(bvm *vm, bvalue *v, int argc)
|
||||||
default: call_error(vm, v);
|
default: call_error(vm, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BERRY_API void be_set_obs_hook(bvm *vm, beobshook hook)
|
||||||
|
{
|
||||||
|
#if BE_USE_OBSERVABILITY_HOOK
|
||||||
|
vm->obshook = hook;
|
||||||
|
#endif
|
||||||
|
}
|
|
@ -86,6 +86,9 @@ struct bvm {
|
||||||
bmap *ntvclass; /* native class table */
|
bmap *ntvclass; /* native class table */
|
||||||
blist *registry; /* registry list */
|
blist *registry; /* registry list */
|
||||||
struct bgc gc;
|
struct bgc gc;
|
||||||
|
#if BE_USE_OBSERVABILITY_HOOK
|
||||||
|
beobshook obshook;
|
||||||
|
#endif
|
||||||
#if BE_USE_DEBUG_HOOK
|
#if BE_USE_DEBUG_HOOK
|
||||||
bvalue hook;
|
bvalue hook;
|
||||||
bbyte hookmask;
|
bbyte hookmask;
|
||||||
|
|
|
@ -273,6 +273,14 @@ typedef void(*bntvhook)(bvm *vm, bhookinfo *info);
|
||||||
#define be_assert(expr) ((void)0)
|
#define be_assert(expr) ((void)0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Observability hook */
|
||||||
|
|
||||||
|
typedef void(*beobshook)(bvm *vm, int event, ...);
|
||||||
|
enum beobshookevents {
|
||||||
|
BE_OBS_GC_START, // start of GC, arg = allocated size
|
||||||
|
BE_OBS_GC_END, // end of GC, arg = allocated size
|
||||||
|
};
|
||||||
|
|
||||||
/* FFI functions */
|
/* FFI functions */
|
||||||
#define be_writestring(s) be_writebuffer((s), strlen(s))
|
#define be_writestring(s) be_writebuffer((s), strlen(s))
|
||||||
#define be_writenewline() be_writebuffer("\n", 1)
|
#define be_writenewline() be_writebuffer("\n", 1)
|
||||||
|
@ -406,6 +414,9 @@ BERRY_API void be_regclass(bvm *vm, const char *name, const bnfuncinfo *lib);
|
||||||
BERRY_API bvm* be_vm_new(void);
|
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 */
|
||||||
|
BERRY_API void be_set_obs_hook(bvm *vm, beobshook hook);
|
||||||
|
|
||||||
/* code load APIs */
|
/* code load APIs */
|
||||||
BERRY_API int be_loadbuffer(bvm *vm,
|
BERRY_API int be_loadbuffer(bvm *vm,
|
||||||
const char *name, const char *buffer, size_t length);
|
const char *name, const char *buffer, size_t length);
|
||||||
|
|
|
@ -18,6 +18,7 @@ extern int l_respCmndStr(bvm *vm);
|
||||||
extern int l_respCmndDone(bvm *vm);
|
extern int l_respCmndDone(bvm *vm);
|
||||||
extern int l_respCmndError(bvm *vm);
|
extern int l_respCmndError(bvm *vm);
|
||||||
extern int l_respCmndFailed(bvm *vm);
|
extern int l_respCmndFailed(bvm *vm);
|
||||||
|
extern int l_resolveCmnd(bvm *vm);
|
||||||
|
|
||||||
// #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
|
||||||
|
@ -36,6 +37,7 @@ be_native_module_attr_table(tasmota_ntv) {
|
||||||
be_native_module_function("respcmnd_done", l_respCmndDone),
|
be_native_module_function("respcmnd_done", l_respCmndDone),
|
||||||
be_native_module_function("respcmnd_error", l_respCmndError),
|
be_native_module_function("respcmnd_error", l_respCmndError),
|
||||||
be_native_module_function("respcmnd_failed", l_respCmndFailed),
|
be_native_module_function("respcmnd_failed", l_respCmndFailed),
|
||||||
|
be_native_module_function("resolvecmnd", l_resolveCmnd),
|
||||||
|
|
||||||
be_native_module_str("_operators", "=<>!|"),
|
be_native_module_str("_operators", "=<>!|"),
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,6 +14,8 @@ extern int b_wire_available(bvm *vm);
|
||||||
extern int b_wire_write(bvm *vm);
|
extern int b_wire_write(bvm *vm);
|
||||||
extern int b_wire_read(bvm *vm);
|
extern int b_wire_read(bvm *vm);
|
||||||
|
|
||||||
|
extern int b_wire_validread(bvm *vm);
|
||||||
|
|
||||||
// #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
|
||||||
be_native_module_attr_table(wire) {
|
be_native_module_attr_table(wire) {
|
||||||
|
@ -23,6 +25,7 @@ be_native_module_attr_table(wire) {
|
||||||
be_native_module_function("available", b_wire_available),
|
be_native_module_function("available", b_wire_available),
|
||||||
be_native_module_function("write", b_wire_write),
|
be_native_module_function("write", b_wire_write),
|
||||||
be_native_module_function("read", b_wire_read),
|
be_native_module_function("read", b_wire_read),
|
||||||
|
be_native_module_function("validread", b_wire_validread),
|
||||||
};
|
};
|
||||||
|
|
||||||
be_define_native_module(wire, NULL);
|
be_define_native_module(wire, NULL);
|
||||||
|
|
|
@ -64,6 +64,12 @@
|
||||||
**/
|
**/
|
||||||
#define BE_DEBUG_VAR_INFO 0
|
#define BE_DEBUG_VAR_INFO 0
|
||||||
|
|
||||||
|
/* Macro: BE_USE_OBSERVABILITY_HOOK
|
||||||
|
* Use the obshook function to report low-level actions.
|
||||||
|
* Default: 0
|
||||||
|
**/
|
||||||
|
#define BE_USE_OBSERVABILITY_HOOK 1
|
||||||
|
|
||||||
/* Macro: BE_STACK_TOTAL_MAX
|
/* Macro: BE_STACK_TOTAL_MAX
|
||||||
* Set the maximum total stack size.
|
* Set the maximum total stack size.
|
||||||
* Default: 20000
|
* Default: 20000
|
||||||
|
|
|
@ -177,6 +177,17 @@ extern "C" {
|
||||||
ResponseCmndFailed();
|
ResponseCmndFailed();
|
||||||
be_return_nil(vm);
|
be_return_nil(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update XdrvMailbox.command with actual command
|
||||||
|
int32_t l_resolveCmnd(bvm *vm);
|
||||||
|
int32_t l_resolveCmnd(bvm *vm) {
|
||||||
|
int32_t top = be_top(vm); // Get the number of arguments
|
||||||
|
if (top == 1 && be_isstring(vm, 1)) {
|
||||||
|
const char *msg = be_tostring(vm, 1);
|
||||||
|
strlcpy(XdrvMailbox.command, msg, CMDSZ);
|
||||||
|
}
|
||||||
|
be_return_nil(vm); // Return nil when something goes wrong
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*********************************************************************************************\
|
/*********************************************************************************************\
|
||||||
|
@ -277,6 +288,24 @@ extern "C" {
|
||||||
be_return_nil(vm); // Return nil when something goes wrong
|
be_return_nil(vm); // Return nil when something goes wrong
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Berry: `validread(address:int, reg:int, size:int) -> int or nil`
|
||||||
|
int32_t b_wire_validread(struct bvm *vm);
|
||||||
|
int32_t b_wire_validread(struct bvm *vm) {
|
||||||
|
int32_t top = be_top(vm); // Get the number of arguments
|
||||||
|
if (top == 3 && be_isint(vm, 1) && be_isint(vm, 2) && be_isint(vm, 3)) {
|
||||||
|
uint8_t addr = be_toint(vm, 1);
|
||||||
|
uint8_t reg = be_toint(vm, 2);
|
||||||
|
uint8_t size = be_toint(vm, 3);
|
||||||
|
bool ok = I2cValidRead(addr, reg, size);
|
||||||
|
if (ok) {
|
||||||
|
be_pushint(vm, i2c_buffer);
|
||||||
|
} else {
|
||||||
|
be_pushnil(vm);
|
||||||
|
}
|
||||||
|
be_return(vm); // Return
|
||||||
|
}
|
||||||
|
be_return_nil(vm); // Return nil when something goes wrong
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*********************************************************************************************\
|
/*********************************************************************************************\
|
||||||
|
|
|
@ -44,7 +44,7 @@ const char berry_prog[] =
|
||||||
// Map all native functions to methods
|
// Map all native functions to methods
|
||||||
// Again, this will be eventually pre-compiled
|
// Again, this will be eventually pre-compiled
|
||||||
"var getfreeheap, publish, cmd, getoption, millis, timereached, yield "
|
"var getfreeheap, publish, cmd, getoption, millis, timereached, yield "
|
||||||
"var respcmnd, respcmndstr, respcmnd_done, respcmnd_error, respcmnd_failed "
|
"var respcmnd, respcmndstr, respcmnd_done, respcmnd_error, respcmnd_failed, resolvecmnd "
|
||||||
"def init_ntv() "
|
"def init_ntv() "
|
||||||
"import tasmota_ntv "
|
"import tasmota_ntv "
|
||||||
"self.getfreeheap = tasmota_ntv.getfreeheap "
|
"self.getfreeheap = tasmota_ntv.getfreeheap "
|
||||||
|
@ -61,6 +61,7 @@ const char berry_prog[] =
|
||||||
"self.respcmnd_done = tasmota_ntv.respcmnd_done "
|
"self.respcmnd_done = tasmota_ntv.respcmnd_done "
|
||||||
"self.respcmnd_error = tasmota_ntv.respcmnd_error "
|
"self.respcmnd_error = tasmota_ntv.respcmnd_error "
|
||||||
"self.respcmnd_failed = tasmota_ntv.respcmnd_failed "
|
"self.respcmnd_failed = tasmota_ntv.respcmnd_failed "
|
||||||
|
"self.resolvecmnd = tasmota_ntv.resolvecmnd "
|
||||||
"end "
|
"end "
|
||||||
|
|
||||||
"def init() "
|
"def init() "
|
||||||
|
@ -207,8 +208,11 @@ const char berry_prog[] =
|
||||||
"var payload_json = json.load(payload) "
|
"var payload_json = json.load(payload) "
|
||||||
"var cmd_found = self.findkeyi(self._cmd, cmd) "
|
"var cmd_found = self.findkeyi(self._cmd, cmd) "
|
||||||
"if cmd_found != nil "
|
"if cmd_found != nil "
|
||||||
"return self._cmd[cmd_found](cmd_found, idx, payload, payload_json) "
|
"self.resolvecmnd(cmd_found) " // set the command name in XdrvMailbox.command
|
||||||
|
"self._cmd[cmd_found](cmd_found, idx, payload, payload_json) "
|
||||||
|
"return true "
|
||||||
"end "
|
"end "
|
||||||
|
"return false "
|
||||||
"end "
|
"end "
|
||||||
|
|
||||||
// Force gc and return allocated memory
|
// Force gc and return allocated memory
|
||||||
|
@ -259,23 +263,6 @@ const char berry_prog[] =
|
||||||
// "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 "
|
||||||
|
|
||||||
// Wire
|
// 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
|
#endif // USE_BERRY
|
||||||
|
|
|
@ -102,7 +102,7 @@ bool callBerryRule(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool callBerryCommand(void) {
|
bool callBerryCommand(void) {
|
||||||
const char * command = nullptr;
|
bool serviced = false;
|
||||||
|
|
||||||
checkBeTop();
|
checkBeTop();
|
||||||
be_getglobal(berry.vm, "_exec_cmd");
|
be_getglobal(berry.vm, "_exec_cmd");
|
||||||
|
@ -111,16 +111,21 @@ bool callBerryCommand(void) {
|
||||||
be_pushint(berry.vm, XdrvMailbox.index);
|
be_pushint(berry.vm, XdrvMailbox.index);
|
||||||
be_pushstring(berry.vm, XdrvMailbox.data);
|
be_pushstring(berry.vm, XdrvMailbox.data);
|
||||||
int ret = be_pcall(berry.vm, 3);
|
int ret = be_pcall(berry.vm, 3);
|
||||||
command = be_tostring(berry.vm, 3);
|
// AddLog(LOG_LEVEL_INFO, "callBerryCommand: top=%d", be_top(berry.vm));
|
||||||
strlcpy(XdrvMailbox.topic, command, CMDSZ);
|
// AddLog(LOG_LEVEL_INFO, "callBerryCommand: type(1)=%s", be_typename(berry.vm, 1));
|
||||||
// AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_BERRY "Command (%s) serviced=%d"), XdrvMailbox.command, serviced);
|
// AddLog(LOG_LEVEL_INFO, "callBerryCommand: type(2)=%s", be_typename(berry.vm, 2));
|
||||||
|
// AddLog(LOG_LEVEL_INFO, "callBerryCommand: type(3)=%s", be_typename(berry.vm, 3));
|
||||||
|
// AddLog(LOG_LEVEL_INFO, "callBerryCommand: type(4)=%s", be_typename(berry.vm, 4));
|
||||||
|
// AddLog(LOG_LEVEL_INFO, "callBerryCommand: type(5)=%s", be_typename(berry.vm, 5));
|
||||||
|
serviced = be_tobool(berry.vm, 1); // return value is in slot 1
|
||||||
|
// AddLog(LOG_LEVEL_INFO, "callBerryCommand: serviced=%d", serviced);
|
||||||
be_pop(berry.vm, 4); // remove function object
|
be_pop(berry.vm, 4); // remove function object
|
||||||
} else {
|
} else {
|
||||||
be_pop(berry.vm, 1); // remove nil object
|
be_pop(berry.vm, 1); // remove nil object
|
||||||
}
|
}
|
||||||
checkBeTop();
|
checkBeTop();
|
||||||
|
|
||||||
return command != nullptr; // TODO event not handled
|
return serviced; // TODO event not handled
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t callBerryGC(void) {
|
size_t callBerryGC(void) {
|
||||||
|
@ -173,6 +178,35 @@ void callBerryFunctionVoid(const char * fname) {
|
||||||
checkBeTop();
|
checkBeTop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* VM Observability
|
||||||
|
\*********************************************************************************************/
|
||||||
|
void BerryObservability(bvm *vm, int32_t event...);
|
||||||
|
void BerryObservability(bvm *vm, int32_t event...) {
|
||||||
|
va_list param;
|
||||||
|
va_start(param, event);
|
||||||
|
static int32_t vm_usage = 0;
|
||||||
|
static uint32_t gc_time = 0;
|
||||||
|
|
||||||
|
switch (event) {
|
||||||
|
case BE_OBS_GC_START:
|
||||||
|
{
|
||||||
|
gc_time = millis();
|
||||||
|
vm_usage = va_arg(param, int32_t);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BE_OBS_GC_END:
|
||||||
|
{
|
||||||
|
int32_t vm_usage2 = va_arg(param, int32_t);
|
||||||
|
uint32_t gc_elapsed = millis() - gc_time;
|
||||||
|
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_BERRY "GC from %i to %i bytes (in %d ms)"), vm_usage, vm_usage2, gc_elapsed);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
va_end(param);
|
||||||
|
}
|
||||||
|
|
||||||
/*********************************************************************************************\
|
/*********************************************************************************************\
|
||||||
* VM Init
|
* VM Init
|
||||||
\*********************************************************************************************/
|
\*********************************************************************************************/
|
||||||
|
@ -191,6 +225,7 @@ void BrReset(void) {
|
||||||
bool berry_init_ok = false;
|
bool berry_init_ok = false;
|
||||||
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);
|
||||||
// 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
|
||||||
|
@ -264,12 +299,12 @@ void CmndBrRun(void) {
|
||||||
} while (0);
|
} while (0);
|
||||||
|
|
||||||
if (0 == ret_code) {
|
if (0 == ret_code) {
|
||||||
|
// AddLog(LOG_LEVEL_INFO, "run: top=%d", be_top(berry.vm));
|
||||||
|
// AddLog(LOG_LEVEL_INFO, "run: type(1)=%s", be_typename(berry.vm, 1));
|
||||||
|
// AddLog(LOG_LEVEL_INFO, "run: type(2)=%s", be_typename(berry.vm, 2));
|
||||||
|
|
||||||
// code taken from REPL, look first at top, and if nil, look at return value
|
// 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);
|
||||||
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
|
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);
|
be_pop(berry.vm, 1);
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in New Issue