Merge pull request #11208 from s-hadinger/berry_mar_2

Berry improvements
This commit is contained in:
s-hadinger 2021-03-03 08:43:57 +01:00 committed by GitHub
commit 7f501578b3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 121 additions and 29 deletions

View File

@ -504,6 +504,9 @@ void be_gc_collect(bvm *vm)
if (vm->gc.status & GC_HALT) {
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 */
premark_internal(vm); /* object internal the VM */
premark_global(vm); /* global objects */
@ -520,4 +523,7 @@ void be_gc_collect(bvm *vm)
reset_fixedlist(vm);
/* step 5: calculate the next GC threshold */
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
}

View File

@ -398,6 +398,9 @@ BERRY_API bvm* be_vm_new(void)
be_globalvar_init(vm);
be_gc_setpause(vm, 1);
be_loadlibs(vm);
#if BE_USE_OBSERVABILITY_HOOK
vm->obshook = NULL;
#endif
return vm;
}
@ -1051,3 +1054,10 @@ void be_dofunc(bvm *vm, bvalue *v, int argc)
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
}

View File

@ -86,6 +86,9 @@ struct bvm {
bmap *ntvclass; /* native class table */
blist *registry; /* registry list */
struct bgc gc;
#if BE_USE_OBSERVABILITY_HOOK
beobshook obshook;
#endif
#if BE_USE_DEBUG_HOOK
bvalue hook;
bbyte hookmask;

View File

@ -273,6 +273,14 @@ typedef void(*bntvhook)(bvm *vm, bhookinfo *info);
#define be_assert(expr) ((void)0)
#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 */
#define be_writestring(s) be_writebuffer((s), strlen(s))
#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 void be_vm_delete(bvm *vm);
/* Observability hook */
BERRY_API void be_set_obs_hook(bvm *vm, beobshook hook);
/* code load APIs */
BERRY_API int be_loadbuffer(bvm *vm,
const char *name, const char *buffer, size_t length);

View File

@ -18,6 +18,7 @@ extern int l_respCmndStr(bvm *vm);
extern int l_respCmndDone(bvm *vm);
extern int l_respCmndError(bvm *vm);
extern int l_respCmndFailed(bvm *vm);
extern int l_resolveCmnd(bvm *vm);
// #if !BE_USE_PRECOMPILED_OBJECT
#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_error", l_respCmndError),
be_native_module_function("respcmnd_failed", l_respCmndFailed),
be_native_module_function("resolvecmnd", l_resolveCmnd),
be_native_module_str("_operators", "=<>!|"),
};

View File

@ -14,6 +14,8 @@ extern int b_wire_available(bvm *vm);
extern int b_wire_write(bvm *vm);
extern int b_wire_read(bvm *vm);
extern int b_wire_validread(bvm *vm);
// #if !BE_USE_PRECOMPILED_OBJECT
#if 1 // TODO we will do pre-compiled later
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("write", b_wire_write),
be_native_module_function("read", b_wire_read),
be_native_module_function("validread", b_wire_validread),
};
be_define_native_module(wire, NULL);

View File

@ -64,6 +64,12 @@
**/
#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
* Set the maximum total stack size.
* Default: 20000

View File

@ -177,6 +177,17 @@ extern "C" {
ResponseCmndFailed();
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
}
// 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
}
}
/*********************************************************************************************\

View File

@ -44,7 +44,7 @@ const char berry_prog[] =
// 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 "
"var respcmnd, respcmndstr, respcmnd_done, respcmnd_error, respcmnd_failed, resolvecmnd "
"def init_ntv() "
"import tasmota_ntv "
"self.getfreeheap = tasmota_ntv.getfreeheap "
@ -61,6 +61,7 @@ const char berry_prog[] =
"self.respcmnd_done = tasmota_ntv.respcmnd_done "
"self.respcmnd_error = tasmota_ntv.respcmnd_error "
"self.respcmnd_failed = tasmota_ntv.respcmnd_failed "
"self.resolvecmnd = tasmota_ntv.resolvecmnd "
"end "
"def init() "
@ -207,8 +208,11 @@ const char berry_prog[] =
"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) "
"self.resolvecmnd(cmd_found) " // set the command name in XdrvMailbox.command
"self._cmd[cmd_found](cmd_found, idx, payload, payload_json) "
"return true "
"end "
"return false "
"end "
// 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 "
// 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

View File

@ -102,7 +102,7 @@ bool callBerryRule(void) {
}
bool callBerryCommand(void) {
const char * command = nullptr;
bool serviced = false;
checkBeTop();
be_getglobal(berry.vm, "_exec_cmd");
@ -111,16 +111,21 @@ bool callBerryCommand(void) {
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);
// AddLog(LOG_LEVEL_INFO, "callBerryCommand: top=%d", be_top(berry.vm));
// AddLog(LOG_LEVEL_INFO, "callBerryCommand: type(1)=%s", be_typename(berry.vm, 1));
// 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
} else {
be_pop(berry.vm, 1); // remove nil object
}
checkBeTop();
return command != nullptr; // TODO event not handled
return serviced; // TODO event not handled
}
size_t callBerryGC(void) {
@ -173,6 +178,35 @@ void callBerryFunctionVoid(const char * fname) {
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
\*********************************************************************************************/
@ -191,6 +225,7 @@ void BrReset(void) {
bool berry_init_ok = false;
do {
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));
// Register functions
@ -264,12 +299,12 @@ void CmndBrRun(void) {
} while (0);
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
if (be_isnil(berry.vm, 0)) {
ret_val = be_tostring(berry.vm, -1);
} else {
ret_val = be_tostring(berry.vm, 0);
}
ret_val = be_tostring(berry.vm, 1);
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 {