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) {
|
||||
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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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", "=<>!|"),
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue