diff --git a/CHANGELOG.md b/CHANGELOG.md index e5d9a8633..6ca69c83c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -893,6 +893,7 @@ All notable changes to this project will be documented in this file. ### Changed - Triple-mode TLS via configuration in a single firmware (TLS AWS IoT, Letsencrypt and No-TLS) +- Berry C mapping moved to a separate ``berry_mapping`` library ### Fixed - ESP32 PWM range diff --git a/lib/libesp32/berry/default/be_lvgl_ctypes_definitions.c b/lib/libesp32/berry/default/be_lvgl_ctypes_definitions.c index bb1ffb65c..74797a760 100644 --- a/lib/libesp32/berry/default/be_lvgl_ctypes_definitions.c +++ b/lib/libesp32/berry/default/be_lvgl_ctypes_definitions.c @@ -6,7 +6,7 @@ #ifdef USE_LVGL #include "lvgl.h" -#include "be_lvgl.h" +#include "be_mapping.h" /******************************************************************** * Generated code, don't edit diff --git a/lib/libesp32/berry/default/be_lvgl_glob_lib.c b/lib/libesp32/berry/default/be_lvgl_glob_lib.c index 06827fc0e..49848e1dc 100644 --- a/lib/libesp32/berry/default/be_lvgl_glob_lib.c +++ b/lib/libesp32/berry/default/be_lvgl_glob_lib.c @@ -249,7 +249,7 @@ be_local_closure(LVGL_glob_register_obj, /* name */ be_local_closure(LVGL_glob_gen_cb, /* name */ be_nested_proto( 8, /* nstack */ - 5, /* argc */ + 4, /* argc */ 0, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ @@ -281,56 +281,57 @@ be_local_closure(LVGL_glob_gen_cb, /* name */ ), }), 1, /* has constants */ - ( &(const bvalue[ 8]) { /* constants */ - /* K0 */ be_nested_str(lv_event_cb), - /* K1 */ be_nested_str(cb_event_closure), - /* K2 */ be_nested_str(event_cb), - /* K3 */ be_nested_str(tasmota), + ( &(const bvalue[ 9]) { /* constants */ + /* K0 */ be_nested_str(cb), + /* K1 */ be_nested_str(lv_event_cb), + /* K2 */ be_nested_str(cb_event_closure), + /* K3 */ be_nested_str(event_cb), /* K4 */ be_nested_str(gen_cb), /* K5 */ be_nested_str(register_obj), - /* K6 */ be_nested_str(null_cb), - /* K7 */ be_nested_str(cb_do_nothing), + /* K6 */ be_nested_str(_p), + /* K7 */ be_nested_str(null_cb), + /* K8 */ be_nested_str(cb_do_nothing), }), &be_const_str_gen_cb, &be_const_str_solidified, ( &(const binstruction[41]) { /* code */ - 0x1C140300, // 0000 EQ R5 R1 K0 - 0x78160018, // 0001 JMPF R5 #001B - 0x88140101, // 0002 GETMBR R5 R0 K1 - 0x4C180000, // 0003 LDNIL R6 - 0x1C140A06, // 0004 EQ R5 R5 R6 - 0x78160002, // 0005 JMPF R5 #0009 - 0x60140013, // 0006 GETGBL R5 G19 - 0x7C140000, // 0007 CALL R5 0 - 0x90020205, // 0008 SETMBR R0 K1 R5 - 0x88140102, // 0009 GETMBR R5 R0 K2 - 0x4C180000, // 000A LDNIL R6 - 0x1C140A06, // 000B EQ R5 R5 R6 - 0x78160004, // 000C JMPF R5 #0012 - 0xB8160600, // 000D GETNGBL R5 K3 - 0x8C140B04, // 000E GETMET R5 R5 K4 + 0xA4120000, // 0000 IMPORT R4 K0 + 0x1C140701, // 0001 EQ R5 R3 K1 + 0x78160018, // 0002 JMPF R5 #001C + 0x88140102, // 0003 GETMBR R5 R0 K2 + 0x4C180000, // 0004 LDNIL R6 + 0x1C140A06, // 0005 EQ R5 R5 R6 + 0x78160002, // 0006 JMPF R5 #000A + 0x60140013, // 0007 GETGBL R5 G19 + 0x7C140000, // 0008 CALL R5 0 + 0x90020405, // 0009 SETMBR R0 K2 R5 + 0x88140103, // 000A GETMBR R5 R0 K3 + 0x4C180000, // 000B LDNIL R6 + 0x1C140A06, // 000C EQ R5 R5 R6 + 0x78160003, // 000D JMPF R5 #0012 + 0x8C140904, // 000E GETMET R5 R4 K4 0x841C0000, // 000F CLOSURE R7 P0 0x7C140400, // 0010 CALL R5 2 - 0x90020405, // 0011 SETMBR R0 K2 R5 + 0x90020605, // 0011 SETMBR R0 K3 R5 0x8C140105, // 0012 GETMET R5 R0 K5 - 0x5C1C0600, // 0013 MOVE R7 R3 + 0x5C1C0400, // 0013 MOVE R7 R2 0x7C140400, // 0014 CALL R5 2 - 0x88140101, // 0015 GETMBR R5 R0 K1 - 0x98140802, // 0016 SETIDX R5 R4 R2 - 0x88140102, // 0017 GETMBR R5 R0 K2 - 0xA0000000, // 0018 CLOSE R0 - 0x80040A00, // 0019 RET 1 R5 - 0x7002000B, // 001A JMP #0027 - 0x88140106, // 001B GETMBR R5 R0 K6 - 0x4C180000, // 001C LDNIL R6 - 0x1C140A06, // 001D EQ R5 R5 R6 - 0x78160004, // 001E JMPF R5 #0024 - 0xB8160600, // 001F GETNGBL R5 K3 - 0x8C140B04, // 0020 GETMET R5 R5 K4 - 0x881C0107, // 0021 GETMBR R7 R0 K7 + 0x88140506, // 0015 GETMBR R5 R2 K6 + 0x88180102, // 0016 GETMBR R6 R0 K2 + 0x98180A01, // 0017 SETIDX R6 R5 R1 + 0x88140103, // 0018 GETMBR R5 R0 K3 + 0xA0000000, // 0019 CLOSE R0 + 0x80040A00, // 001A RET 1 R5 + 0x7002000A, // 001B JMP #0027 + 0x88140107, // 001C GETMBR R5 R0 K7 + 0x4C180000, // 001D LDNIL R6 + 0x1C140A06, // 001E EQ R5 R5 R6 + 0x78160003, // 001F JMPF R5 #0024 + 0x8C140904, // 0020 GETMET R5 R4 K4 + 0x881C0108, // 0021 GETMBR R7 R0 K8 0x7C140400, // 0022 CALL R5 2 - 0x90020C05, // 0023 SETMBR R0 K6 R5 - 0x88140106, // 0024 GETMBR R5 R0 K6 + 0x90020E05, // 0023 SETMBR R0 K7 R5 + 0x88140107, // 0024 GETMBR R5 R0 K7 0xA0000000, // 0025 CLOSE R0 0x80040A00, // 0026 RET 1 R5 0xA0000000, // 0027 CLOSE R0 diff --git a/lib/libesp32/berry/default/be_lvgl_module.c b/lib/libesp32/berry/default/be_lvgl_module.c index 890efd2ff..bb9b86e3e 100644 --- a/lib/libesp32/berry/default/be_lvgl_module.c +++ b/lib/libesp32/berry/default/be_lvgl_module.c @@ -9,7 +9,7 @@ #ifdef USE_LVGL #include "lvgl.h" -#include "be_lvgl.h" +#include "be_mapping.h" #include "lv_theme_openhasp.h" extern int lv0_member(bvm *vm); // resolve virtual members @@ -34,7 +34,7 @@ static int lv_get_ver_res(void) { } /* `lv` methods */ -const lvbe_call_c_t lv_func[] = { +const be_ntv_func_def_t lv_func[] = { { "clamp_height", (void*) &lv_clamp_height, "i", "iiii" }, { "clamp_width", (void*) &lv_clamp_width, "i", "iiii" }, @@ -111,12 +111,7 @@ const size_t lv_func_size = sizeof(lv_func) / sizeof(lv_func[0]); -typedef struct be_constint_t { - const char * name; - int32_t value; -} be_constint_t; - -const be_constint_t lv0_constants[] = { +const be_const_member_t lv0_constants[] = { { "ALIGN_BOTTOM_LEFT", LV_ALIGN_BOTTOM_LEFT }, { "ALIGN_BOTTOM_MID", LV_ALIGN_BOTTOM_MID }, diff --git a/lib/libesp32/berry/default/embedded/lvgl_glob.be b/lib/libesp32/berry/default/embedded/lvgl_glob.be index 04250ff54..17a62bf31 100644 --- a/lib/libesp32/berry/default/embedded/lvgl_glob.be +++ b/lib/libesp32/berry/default/embedded/lvgl_glob.be @@ -44,20 +44,21 @@ class LVGL_glob f(obj, event) end - def gen_cb(name, f, obj, ptr) - #print('>> gen_cb', name, obj, ptr) + def gen_cb(f, obj, name) + import cb + # print('>> gen_cb', f, name, obj) # record the object, whatever the callback if name == "lv_event_cb" if self.cb_event_closure == nil self.cb_event_closure = {} end - if self.event_cb == nil self.event_cb = tasmota.gen_cb(/ event_ptr -> self.lvgl_event_dispatch(event_ptr)) end # encapsulate 'self' in closure + if self.event_cb == nil self.event_cb = cb.gen_cb(/ event_ptr -> self.lvgl_event_dispatch(event_ptr)) end # encapsulate 'self' in closure self.register_obj(obj) - self.cb_event_closure[ptr] = f + self.cb_event_closure[obj._p] = f return self.event_cb # elif name == "" else - if self.null_cb == nil self.null_cb = tasmota.gen_cb(self.cb_do_nothing) end + if self.null_cb == nil self.null_cb = cb.gen_cb(self.cb_do_nothing) end return self.null_cb end end diff --git a/lib/libesp32/berry/include/be_lvgl.h b/lib/libesp32/berry/include/be_lvgl.h deleted file mode 100644 index 52b5edc2d..000000000 --- a/lib/libesp32/berry/include/be_lvgl.h +++ /dev/null @@ -1,40 +0,0 @@ -/******************************************************************** - * Tasmota LVGL Headers - *******************************************************************/ -#ifndef __BE_LVGL_H__ -#define __BE_LVGL_H__ - -#include "be_constobj.h" - -#ifdef USE_LVGL - -#include "lvgl.h" - -#ifdef __cplusplus -extern "C" { -#endif - // table of functions per class - typedef struct lvbe_call_c_t { - const char * name; - void * func; - const char * return_type; - const char * arg_type; - } lvbe_call_c_t; - - // list of classes and function tables - typedef struct lvbe_call_c_classes_t { - const char * name; - const bclass * cl; - const lvbe_call_c_t * func_table; - size_t size; - } lvbe_call_c_classes_t; - extern const lvbe_call_c_classes_t lv_classes[]; - extern const size_t lv_classes_size; - -#ifdef __cplusplus -} -#endif - -#endif // USE_LVGL - -#endif // __BE_LVGL_H__ \ No newline at end of file diff --git a/lib/libesp32/berry_mapping/src/be_class_wrapper.c b/lib/libesp32/berry_mapping/src/be_class_wrapper.c new file mode 100644 index 000000000..5f71e7da1 --- /dev/null +++ b/lib/libesp32/berry_mapping/src/be_class_wrapper.c @@ -0,0 +1,406 @@ +/*********************************************************************************************\ + * Class wrappers for native objects + * + * These class are simple wrappers (containers) for a pointer of an external object. + * The pointer is stored interanlly by the class. + * + * The constructor of this class must accept the first argument to be `comptr`, + * in such case, the constructor must store the pointer. + * The class is not supposed to free the object at `deinit` time. +\*********************************************************************************************/ + +#include "be_mapping.h" +#include "be_exec.h" +#include + +/*********************************************************************************************\ + * Create an object of `class_name` given an external poinrt `ptr`. + * + * Instanciates the class and calls `init()` with `ptr` wrapped in `comptr` as single arg. + * Both arguments but nost bu NULL. + * + * On return, the created instance is top of stack. +\*********************************************************************************************/ +void be_create_class_wrapper(bvm *vm, const char * class_name, void * ptr) { + if (ptr == NULL) { + be_throw(vm, BE_MALLOC_FAIL); + } + + be_getglobal(vm, class_name); // stack = class + be_call(vm, 0); // instanciate, stack = instance + be_getmember(vm, -1, "init"); // stack = instance, init_func + be_pushvalue(vm, -2); // stack = instance, init_func, instance + be_pushcomptr(vm, ptr); // stack = instance, init_func, instance, ptr + be_call(vm, 2); // stack = instance, ret, instance, ptr + be_pop(vm, 3); // stack = instance +} + + +/*********************************************************************************************\ + * Find an object by global or composite name. + * + * I.e. `lv.lv_object` will check for a global called `lv` and a member `lv_object` + * + * Only supports one level of depth, meaning a class within a module. + * Does not check the type of the object found. + * + * Arguments: + * `name`: can be NULL, in such case considers the member as not found + * + * Case 1: (no dot in name) `lv_wifi_bars` will look for a global variable `lv_wifi_bars` + * Case 2: (dot in name) `lvgl.lv_obj` will get global `lvgl` and look for `lv_obj` within this module + * + * Returns the number of elements pushed on the stack: 1 for module, 2 for instance method, 0 if not found +\*********************************************************************************************/ +int be_find_global_or_module_member(bvm *vm, const char * name) { + char *saveptr; + + if (name == NULL) { + be_pushnil(vm); + return 0; + } + char name_buf[strlen(name)+1]; + strcpy(name_buf, name); + + char * prefix = strtok_r(name_buf, ".", &saveptr); + char * suffix = strtok_r(NULL, ".", &saveptr); + if (suffix) { + if (be_getglobal(vm, prefix)) { + if (be_getmember(vm, -1, suffix)) { + if (be_isinstance(vm, -2)) { // instance, so we need to push method + instance + be_pushvalue(vm, -2); + be_remove(vm, -3); + return 2; + } else { // not instane, so keep only the top object + be_remove(vm, -2); + return 1; + } + } else { + be_pop(vm, 2); + return 0; + } + } + be_pop(vm, 1); // remove nil + return 0; + } else { // no suffix, get the global object + if (be_getglobal(vm, prefix)) { + return 1; + } + be_pop(vm, 1); + return 0; + } +} + + +/*********************************************************************************************\ + * Automatically parse Berry stack and call the C function accordingly + * + * This function takes the n incoming arguments and pushes them as arguments + * on the stack for the C function: + * - be_int -> int32_t + * - be_bool -> int32_t with value 0/1 + * - be_string -> const char * + * - be_instance -> gets the member "_p" and pushes as void* + * + * This works because C silently ignores any unwanted arguments. + * There is a strong requirements that all ints and pointers are 32 bits. + * Float is not supported but could be added. Double cannot be supported because they are 64 bits + * + * Optional argument: + * - return_type: the C function return value is int32_t and is converted to the + * relevant Berry object depending on this char: + * '' (default): nil, no value + * 'i' be_int + * 'b' be_bool + * 's' be_str + * + * - arg_type: optionally check the types of input arguments, or throw an error + * string of argument types, '+' marks optional arguments + * '.' don't care + * 'i' be_int + * 'b' be_bool + * 's' be_string + * 'c' C callback + * '-' ignore and don't send to C function + * 'lv_obj' be_instance of type or subtype + * '^lv_event_cb' callback of a named class - will call `_lvgl.gen_cb(arg_type, closure, self)` and expects a callback address in return + * + * Ex: "oii+s" takes 3 mandatory arguments (obj_instance, int, int) and an optional fourth one [,string] +\*********************************************************************************************/ +// general form of lv_obj_t* function, up to 4 parameters +// We can only send 32 bits arguments (no 64 bits nor double) and we expect pointers to be 32 bits + +// read a single value at stack position idx, convert to int. +// if object instance, get `_p` member and convert it recursively +intptr_t be_convert_single_elt(bvm *vm, int idx, const char * arg_type, const char * gen_cb) { + // berry_log_C("be_convert_single_elt(idx=%i, argtype='%s', gen_cb=%p", idx, arg_type, gen_cb); + int ret = 0; + char provided_type = 0; + idx = be_absindex(vm, idx); // make sure we have an absolute index + + // berry_log_C(">> 0 idx=%i arg_type=%s", idx, arg_type ? arg_type : "NULL"); + if (arg_type == NULL) { arg_type = "."; } // if no type provided, replace with wildchar + size_t arg_type_len = strlen(arg_type); + + // handle callbacks first, since a wrong parameter will always yield to a crash + if (arg_type_len > 1 && arg_type[0] == '^') { // it is a callback + arg_type++; // skip first character + if (be_isclosure(vm, idx)) { + ret = be_find_global_or_module_member(vm, gen_cb); + if (ret) { + be_remove(vm, -3); // stack contains method + instance + be_pushvalue(vm, idx); + be_pushvalue(vm, 1); + be_pushstring(vm, arg_type); + be_call(vm, 2 + ret); + const void * func = be_tocomptr(vm, -(3 + ret)); + be_pop(vm, 3 + ret); + + // berry_log_C("func=%p", func); + return (int32_t) func; + } else { + be_raisef(vm, "type_error", "Can't find callback generator: %s", gen_cb); + } + } else { + be_raise(vm, "type_error", "Closure expected for callback type"); + } + } + + // first convert the value to int32 + if (be_isint(vm, idx)) { ret = be_toint(vm, idx); provided_type = 'i'; } + else if (be_isbool(vm, idx)) { ret = be_tobool(vm, idx); provided_type = 'b'; } + else if (be_isstring(vm, idx)) { ret = (intptr_t) be_tostring(vm, idx); provided_type = 's'; } + else if (be_iscomptr(vm, idx)) { ret = (intptr_t) be_tocomptr(vm, idx); provided_type = 'c'; } + else if (be_isnil(vm, idx)) { ret = 0; provided_type = 'c'; } + + // check if simple type was a match + if (provided_type) { + bbool type_ok = bfalse; + type_ok = (arg_type[0] == '.'); // any type is accepted + type_ok = type_ok || (arg_type[0] == provided_type); // or type is a match + type_ok = type_ok || (ret == 0 && arg_type_len != 1); // or NULL is accepted for an instance + + if (!type_ok) { + be_raisef(vm, "type_error", "Unexpected argument type '%c', expected '%s'", provided_type, arg_type); + } + // berry_log_C("be_convert_single_elt provided type=%i", ret); + return ret; + } + + // berry_log_C("be_convert_single_elt non simple type"); + // non-simple type + if (be_isinstance(vm, idx)) { + // check if the instance is a subclass of `bytes()`` + be_getbuiltin(vm, "bytes"); + if (be_isderived(vm, idx)) { + be_pop(vm, 1); + be_getmember(vm, idx, "_buffer"); + be_pushvalue(vm, idx); + be_call(vm, 1); + int32_t ret = (int32_t) be_tocomptr(vm, -2); + be_pop(vm, 2); + return ret; + } else { + be_pop(vm, 1); + // we accept either `_p` or `.p` attribute to retrieve a pointer + if (!be_getmember(vm, idx, "_p")) { + be_pop(vm, 1); // remove `nil` + be_getmember(vm, idx, ".p"); + } + int32_t ret = be_convert_single_elt(vm, -1, NULL, NULL); // recurse + be_pop(vm, 1); + + if (arg_type_len > 1) { + // Check type + be_classof(vm, idx); + int class_found = be_find_global_or_module_member(vm, arg_type); + // Stack: class_of_idx, class_of_target (or nil) + if (class_found) { + if (!be_isderived(vm, -2)) { + be_raisef(vm, "type_error", "Unexpected class type '%s', expected '%s'", be_classname(vm, idx), arg_type); + } + } else { + be_raisef(vm, "value_error", "Unable to find class '%s' (%d)", arg_type, arg_type_len); + } + be_pop(vm, 2); + } else if (arg_type[0] != '.') { + be_raisef(vm, "value_error", "Unexpected instance type '%s', expected '%s'", be_classname(vm, idx), arg_type); + } + + return ret; + } + } else { + be_raisef(vm, "value_error", "Unexpected '%s'", be_typename(vm, idx)); + } + + return ret; +} + +/*********************************************************************************************\ + * Calling any LVGL function with auto-mapping + * +\*********************************************************************************************/ + +// check input parameters, and create callbacks if needed +// change values in place +// +// Format: +// - either a lowercase character encoding for a simple type +// - 'b': bool +// - 'i': int (int32_t) +// - 's': string (const char *) +// +// - a class name surroungded by parenthesis +// - '(lv_button)' -> lv_button class or derived +// - '[lv_event_cb]' -> callback type, still prefixed with '^' to mark that it is cb +// +void be_check_arg_type(bvm *vm, int arg_start, int argc, const char * arg_type, intptr_t p[8]) { + bbool arg_type_check = (arg_type != NULL); // is type checking activated + int32_t arg_idx = 0; // position in arg_type string + char type_short_name[32]; + + uint32_t p_idx = 0; // index in p[], is incremented with each parameter except '-' + for (uint32_t i = 0; i < argc; i++) { + type_short_name[0] = 0; // clear string + // extract individual type + if (NULL != arg_type) { + switch (arg_type[arg_idx]) { + case '-': + arg_idx++; + continue; // ignore current parameter and advance + case '.': + case 'a'...'z': + type_short_name[0] = arg_type[arg_idx]; + type_short_name[1] = 0; + arg_idx++; + break; + case '(': + case '^': + { + uint32_t prefix = 0; + if (arg_type[arg_idx] == '^') { + type_short_name[0] = '^'; + type_short_name[1] = 0; + prefix = 1; + } + uint32_t offset = 0; + arg_idx++; + while (arg_type[arg_idx + offset] != ')' && arg_type[arg_idx + offset] != '^' && arg_type[arg_idx + offset] != 0 && offset+prefix+1 < sizeof(type_short_name)) { + type_short_name[offset+prefix] = arg_type[arg_idx + offset]; + type_short_name[offset+prefix+1] = 0; + offset++; + } + if (arg_type[arg_idx + offset] == 0) { + arg_type = NULL; // no more parameters, stop iterations + } + arg_idx += offset + 1; + } + break; + case 0: + arg_type = NULL; // stop iterations + break; + } + } + // AddLog(LOG_LEVEL_INFO, ">> be_call_c_func arg %i, type %s", i, arg_type_check ? type_short_name : ""); + p[p_idx++] = be_convert_single_elt(vm, i + arg_start, arg_type_check ? type_short_name : NULL, "_lvgl.gen_cb"); + } + + // check if we are missing arguments + if (arg_type != NULL && arg_type[arg_idx] != 0) { + be_raisef(vm, "value_error", "Missing arguments, remaining type '%s'", &arg_type[arg_idx]); + } +} + +// +// Internal function +// +// Called for constructors, i.e. C function mapped to Berry `init()` +// +// Pre-conditions: +// The instance must be at stack position `1` (default when calling `init()`) +// +// Arguments: +// vm: point to Berry vm (as usual) +// ptr: the C pointer for internal data (can be NULL), will be stored in an instance variable +// name: name of instance variable to store the pointer as `comptr`. +// If NULL, this function does nothing +// the name can be prefixed with `+`, if so first char is ignored. +// Ex: `+_p` stores in instance variable `_p` +static void be_set_ctor_ptr(bvm *vm, void * ptr, const char *name) { + if (name == NULL) return; // do nothing if no name of attribute + if (name[0] == '+') { name++; } // skip prefix '^' if any + if (strlen(name) == 0) return; // do nothing if name is empty + + be_pushcomptr(vm, ptr); + if (be_setmember(vm, 1, name)) { + be_pop(vm, 1); + } else { + be_raisef(vm, "attribute_error", "Missing member '%s' in ctor", name); + } +} + +/*********************************************************************************************\ + * Call a C function with auto-mapping + * + * Arguments: + * vm: pointer to Berry vm (as ususal) + * func: pointer to C function + * return_type: how to convert the result into a Berry type + * arg_type: string describing the optional and mandatory parameters + * + * Note: the C function mapping supports max 8 arguments and does not directly support + * pointers to values (although it is possible to mimick with classes) +\*********************************************************************************************/ +int be_call_c_func(bvm *vm, void * func, const char * return_type, const char * arg_type) { + intptr_t p[8] = {0,0,0,0,0,0,0,0}; + int argc = be_top(vm); // Get the number of arguments + + // the following describe the active payload for the C function (start and count) + // this is because the `init()` constructor first arg is not passed to the C function + int arg_start = 1; // start with standard values + int arg_count = argc; + + // check if we call a constructor, in this case we store the return type into the new object + // check if we call a constructor with a comptr as first arg + if (return_type && return_type[0] == '+') { + if (argc > 1 && be_iscomptr(vm, 2)) { + void * obj = be_tocomptr(vm, 2); + be_set_ctor_ptr(vm, obj, return_type); + be_return_nil(vm); + } else { + // we need to discard the first arg + arg_start++; + arg_count--; + } + } + + fn_any_callable f = (fn_any_callable) func; + be_check_arg_type(vm, arg_start, arg_count, arg_type, p); + intptr_t ret = (*f)(p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); + // berry_log_C("be_call_c_func '%s' -> '%s': (%i,%i,%i,%i,%i,%i) -> %i", return_type, arg_type, p[0], p[1], p[2], p[3], p[4], p[5], ret); + + if ((return_type == NULL) || (strlen(return_type) == 0)) { be_return_nil(vm); } // does not return + else if (return_type[0] == '+') { + void * obj = (void*) ret; + be_set_ctor_ptr(vm, obj, return_type); + be_return_nil(vm); + } + else if (strlen(return_type) == 1) { + switch (return_type[0]) { + case '.': // fallback next + case 'i': be_pushint(vm, ret); break; + case 'b': be_pushbool(vm, ret); break; + case 's': be_pushstring(vm, (const char*) ret); break; + case 'c': be_pushint(vm, ret); break; // TODO missing 'c' general callback type + default: be_raise(vm, "internal_error", "Unsupported return type"); break; + } + be_return(vm); + } else { // class name + be_find_global_or_module_member(vm, return_type); + be_pushcomptr(vm, (void*) ret); // stack = class, ptr + be_pushcomptr(vm, (void*) -1); // stack = class, ptr, -1 + be_call(vm, 2); // instanciate with 2 arguments, stack = instance, -1, ptr + be_pop(vm, 2); // stack = instance + be_return(vm); + } +} diff --git a/lib/libesp32/berry_mapping/src/be_const_members.c b/lib/libesp32/berry_mapping/src/be_const_members.c new file mode 100644 index 000000000..7a1a796df --- /dev/null +++ b/lib/libesp32/berry_mapping/src/be_const_members.c @@ -0,0 +1,64 @@ +/*********************************************************************************************\ + * Add const virtual members to classes and modules from C static tables + * + * This allows to creates hundreds of constant members (integers, strings...) + * stored in a C array instead of explicit berry members. + * + * It has the following advantages: + * - consumes much less flash memory, especially with hundreds of members + * - allows C preprocessor to compute the value at compile time (instead of pure numerical numbers) + * - allows to compute pointer addresses to C structures + * + * Takes a pointer to be_const_member_t array and size + * Returns true if a match was found. In such case the result is on Berry stack + * + * Encoding depend on prefix (which is skipped when matching names): + * 1. `COLOR_WHITE` int value + * 3. `$SYMBOL_OK"` string pointer + * 4. `&seg7_font` comptr +\*********************************************************************************************/ + +#include "be_mapping.h" +#include "be_exec.h" +#include +/*********************************************************************************************\ + * Takes a pointer to be_const_member_t array and size + * Returns true if a match was found. In such case the result is on Berry stack + * + * Can be called directly by `member()` function, takes the name of the member from + * berry stack at position 1. + * + * Encoding depend on prefix (which is skipped when matching names): + * 1. `COLOR_WHITE` int value + * 3. `$SYMBOL_OK"` string pointer + * 4. `&seg7_font` comptr + * + * The array must be lexically sorted, but the sort function must ignore the prefix `$` or `&` +\*********************************************************************************************/ +bbool be_const_member(bvm *vm, const be_const_member_t * definitions, size_t def_len) { + int32_t argc = be_top(vm); // Get the number of arguments + if (argc == 1 && be_isstring(vm, 1)) { + const char * needle = be_tostring(vm, 1); + int32_t idx; + + idx = be_map_bin_search(needle, &definitions[0].name, sizeof(definitions[0]), def_len); + if (idx >= 0) { + // we did have a match + const char * key = definitions[idx].name; + switch (key[0]) { + // switch depending on the first char of the key, indicating the type + case '$': // string + be_pushstring(vm, (const char*) definitions[idx].value); + break; + case '&': // native function + be_pushntvfunction(vm, (bntvfunc) definitions[idx].value); + break; + default: // int + be_pushint(vm, definitions[idx].value); + break; + } + return btrue; + } + } + return bfalse; +} \ No newline at end of file diff --git a/lib/libesp32/berry_mapping/src/be_mapping.h b/lib/libesp32/berry_mapping/src/be_mapping.h index 850cd08c0..108db129b 100644 --- a/lib/libesp32/berry_mapping/src/be_mapping.h +++ b/lib/libesp32/berry_mapping/src/be_mapping.h @@ -3,8 +3,64 @@ #ifndef __BE_MAPPING__ #define __BE_MAPPING__ -// include this header to force compilation fo this module +#ifdef __cplusplus +extern "C" { +#endif +#include "berry.h" + +// include this header to force compilation fo this module #define BE_MAX_CB 20 // max number of callbacks, each callback requires a distinct address +/*********************************************************************************************\ + * Support for Berry int constants + * as virtual members + \*********************************************************************************************/ + +typedef intptr_t (*fn_any_callable)(intptr_t p0, intptr_t p1, intptr_t p2, intptr_t p3, + intptr_t p4, intptr_t p5, intptr_t p6, intptr_t p7); + +typedef struct be_const_member_t { + const char * name; + int value; +} be_const_member_t; + +// table of functions per class +typedef struct be_ntv_func_def_t { + const char * name; + void * func; + const char * return_type; + const char * arg_type; +} be_ntv_func_def_t; + +struct bclass; +// list of classes and function tables +typedef struct be_ntv_class_def_t { + const char * name; + const struct bclass * cl; + const be_ntv_func_def_t * func_table; + size_t size; +} be_ntv_class_def_t; + +void be_raisef(bvm *vm, const char *except, const char *msg, ...); + +extern void be_map_insert_int(bvm *vm, const char *key, bint value); +extern void be_map_insert_bool(bvm *vm, const char *key, bbool value); +extern void be_map_insert_real(bvm *vm, const char *key, breal value); +extern void be_map_insert_str(bvm *vm, const char *key, const char *value); +extern void be_map_insert_list_uint8(bvm *vm, const char *key, const uint8_t *value, size_t size); + +extern int be_map_bin_search(const char * needle, const void * table, size_t elt_size, size_t total_elements); + +extern void be_create_class_wrapper(bvm *vm, const char * class_name, void * ptr); +extern int be_find_global_or_module_member(bvm *vm, const char * cl_name); + +extern bbool be_const_member(bvm *vm, const be_const_member_t * definitions, size_t def_len); +extern intptr_t be_convert_single_elt(bvm *vm, int idx, const char * arg_type, const char * gen_cb); +extern void be_check_arg_type(bvm *vm, int arg_start, int argc, const char * arg_type, intptr_t p[8]);; +extern int be_call_c_func(bvm *vm, void * func, const char * return_type, const char * arg_type); + +#ifdef __cplusplus +} +#endif #endif // __BE_MAPPING__ diff --git a/lib/libesp32/berry_mapping/src/be_mapping_utils.c b/lib/libesp32/berry_mapping/src/be_mapping_utils.c new file mode 100644 index 000000000..e3a2cc6e2 --- /dev/null +++ b/lib/libesp32/berry_mapping/src/be_mapping_utils.c @@ -0,0 +1,97 @@ +#include "be_mapping.h" +#include +#include + +/*********************************************************************************************\ + * Helper functions to create a map with single line calls +\*********************************************************************************************/ +/* Insert an int to a key */ +void be_map_insert_int(bvm *vm, const char *key, bint value) +{ + be_pushstring(vm, key); + be_pushint(vm, value); + be_data_insert(vm, -3); + be_pop(vm, 2); +} +/* Insert an bbool to a key */ +void be_map_insert_bool(bvm *vm, const char *key, bbool value) +{ + be_pushstring(vm, key); + be_pushbool(vm, value); + be_data_insert(vm, -3); + be_pop(vm, 2); +} +/* Insert an real to a key */ +/* if value == NAN, ignore */ +void be_map_insert_real(bvm *vm, const char *key, breal value) +{ + if (!isnan(value)) { + be_pushstring(vm, key); + be_pushreal(vm, value); + be_data_insert(vm, -3); + be_pop(vm, 2); + } +} +/* Insert an C string to a key */ +void be_map_insert_str(bvm *vm, const char *key, const char *value) +{ + be_pushstring(vm, key); + be_pushstring(vm, value); + be_data_insert(vm, -3); + be_pop(vm, 2); +} +/* Insert list of bytes as individual integers to a key */ +void be_map_insert_list_uint8(bvm *vm, const char *key, const uint8_t *value, size_t size) +{ + be_pushstring(vm, key); + + be_newobject(vm, "list"); + for (uint32_t i=0; i < size; i++) { + be_pushint(vm, value[i]); + be_data_push(vm, -2); + be_pop(vm, 1); + } + be_pop(vm, 1); // now list is on top + + be_data_insert(vm, -3); // insert into map, key/value + be_pop(vm, 2); // pop both key and value +} + +/*********************************************************************************************\ + * Binary search for dynamic attributes + * + * Names need to be sorted +\*********************************************************************************************/ +// binary search within an array of sorted strings +// the first 4 bytes are a pointer to a string +// returns 0..total_elements-1 or -1 if not found +// +// This version skips the first character of the string if it's not a letter, +// the first character is used to indicate the type of the value associated to the key +int be_map_bin_search(const char * needle, const void * table, size_t elt_size, size_t total_elements) { + int low = 0; + int high = total_elements - 1; + int mid = (low + high) / 2; + // start a dissect + while (low <= high) { + const char * elt = *(const char **) ( ((uint8_t*)table) + mid * elt_size ); + char first_char = elt[0]; + if ( !(first_char >= 'a' && first_char <='z') && !(first_char >= 'A' && first_char <='Z') ) { + elt++; // skip first char + } + int comp = strcmp(needle, elt); + if (comp < 0) { + high = mid - 1; + } else if (comp > 0) { + low = mid + 1; + } else { + break; + } + mid = (low + high) / 2; + } + if (low <= high) { + return mid; + } else { + return -1; + } +} \ No newline at end of file diff --git a/lib/libesp32/berry_mapping/src/be_raisef.c b/lib/libesp32/berry_mapping/src/be_raisef.c new file mode 100644 index 000000000..6d8451bab --- /dev/null +++ b/lib/libesp32/berry_mapping/src/be_raisef.c @@ -0,0 +1,22 @@ +/*********************************************************************************************\ + * Extended version of be_raise() +\*********************************************************************************************/ + +#include "be_mapping.h" +#include "be_exec.h" +#include +#include +#include + +// variant of be_raise with string format +void be_raisef(bvm *vm, const char *except, const char *msg, ...) { + // To save stack space support logging for max text length of 128 characters + char log_data[128]; + + va_list arg; + va_start(arg, msg); + uint32_t len = vsnprintf(log_data, sizeof(log_data)-3, msg, arg); + va_end(arg); + if (len+3 > sizeof(log_data)) { strcat(log_data, "..."); } // Actual data is more + be_raise(vm, except, log_data); +} diff --git a/tasmota/berry/include/be_gpio_defines.h b/tasmota/berry/include/be_gpio_defines.h index 73f37825e..e40219dc4 100644 --- a/tasmota/berry/include/be_gpio_defines.h +++ b/tasmota/berry/include/be_gpio_defines.h @@ -2,7 +2,7 @@ * Generated code, don't edit *******************************************************************/ -const be_constint_t lv_gpio_constants[] = { +const be_const_member_t lv_gpio_constants[] = { { "A4988_DIR", (int32_t) GPIO_A4988_DIR }, { "A4988_ENA", (int32_t) GPIO_A4988_ENA }, diff --git a/tasmota/lvgl_berry/be_lv_c_mapping.h b/tasmota/lvgl_berry/be_lv_c_mapping.h index 553238373..dd654f5f3 100644 --- a/tasmota/lvgl_berry/be_lv_c_mapping.h +++ b/tasmota/lvgl_berry/be_lv_c_mapping.h @@ -8,9 +8,10 @@ extern "C" { #endif #include "be_ctypes.h" +#include "be_mapping.h" /* `lv_style` methods */ -const lvbe_call_c_t lv_style_func[] = { +const be_ntv_func_def_t lv_style_func[] = { { "set_align", (void*) &lv_style_set_align, "", "(lv.lv_style)i" }, { "set_anim_speed", (void*) &lv_style_set_anim_speed, "", "(lv.lv_style)i" }, { "set_anim_time", (void*) &lv_style_set_anim_time, "", "(lv.lv_style)i" }, @@ -103,20 +104,20 @@ const lvbe_call_c_t lv_style_func[] = { }; /* `lv_font` methods */ -const lvbe_call_c_t lv_font_func[] = { +const be_ntv_func_def_t lv_font_func[] = { }; /* `lv_color` methods */ -const lvbe_call_c_t lv_color_func[] = { +const be_ntv_func_def_t lv_color_func[] = { }; /* `lv_theme` methods */ -const lvbe_call_c_t lv_theme_func[] = { +const be_ntv_func_def_t lv_theme_func[] = { }; /* `lv_img` methods */ #ifdef BE_LV_WIDGET_IMG -const lvbe_call_c_t lv_img_func[] = { +const be_ntv_func_def_t lv_img_func[] = { { "get_angle", (void*) &lv_img_get_angle, "i", "(lv.lv_obj)" }, { "get_antialias", (void*) &lv_img_get_antialias, "b", "(lv.lv_obj)" }, { "get_offset_x", (void*) &lv_img_get_offset_x, "i", "(lv.lv_obj)" }, @@ -136,7 +137,7 @@ const lvbe_call_c_t lv_img_func[] = { #endif // BE_LV_WIDGET_IMG /* `lv_disp` methods */ -const lvbe_call_c_t lv_disp_func[] = { +const be_ntv_func_def_t lv_disp_func[] = { { "clean_dcache", (void*) &lv_disp_clean_dcache, "", "(lv.lv_disp)" }, { "dpx", (void*) &lv_disp_dpx, "i", "(lv.lv_disp)i" }, { "get_inactive_time", (void*) &lv_disp_get_inactive_time, "i", "(lv.lv_disp)" }, @@ -154,7 +155,7 @@ const lvbe_call_c_t lv_disp_func[] = { }; /* `lv_obj` methods */ -const lvbe_call_c_t lv_obj_func[] = { +const be_ntv_func_def_t lv_obj_func[] = { { "add_event_cb", (void*) &lv_obj_add_event_cb, "i", "(lv.lv_obj)^lv_event_cb^i." }, { "add_flag", (void*) &lv_obj_add_flag, "", "(lv.lv_obj)i" }, { "add_state", (void*) &lv_obj_add_state, "", "(lv.lv_obj)i" }, @@ -458,7 +459,7 @@ const lvbe_call_c_t lv_obj_func[] = { }; /* `lv_group` methods */ -const lvbe_call_c_t lv_group_func[] = { +const be_ntv_func_def_t lv_group_func[] = { { "add_obj", (void*) &lv_group_add_obj, "", "(lv.lv_group)(lv.lv_obj)" }, { "del", (void*) &lv_group_del, "", "(lv.lv_group)" }, { "focus_freeze", (void*) &lv_group_focus_freeze, "", "(lv.lv_group)b" }, @@ -481,7 +482,7 @@ const lvbe_call_c_t lv_group_func[] = { }; /* `lv_indev` methods */ -const lvbe_call_c_t lv_indev_func[] = { +const be_ntv_func_def_t lv_indev_func[] = { { "enable", (void*) &lv_indev_enable, "", "(lv.lv_indev)b" }, { "get_gesture_dir", (void*) &lv_indev_get_gesture_dir, "i", "(lv.lv_indev)" }, { "get_key", (void*) &lv_indev_get_key, "i", "(lv.lv_indev)" }, @@ -501,7 +502,7 @@ const lvbe_call_c_t lv_indev_func[] = { /* `lv_chart` methods */ #ifdef BE_LV_WIDGET_CHART -const lvbe_call_c_t lv_chart_func[] = { +const be_ntv_func_def_t lv_chart_func[] = { { "get_cursor_point", (void*) &lv_chart_get_cursor_point, "i", "(lv.lv_obj)(lv.lv_chart_cursor)" }, { "get_point_count", (void*) &lv_chart_get_point_count, "i", "(lv.lv_obj)" }, { "get_point_pos_by_id", (void*) &lv_chart_get_point_pos_by_id, "", "(lv.lv_obj)(lv.lv_chart_series)i(lv.lv_point)" }, @@ -537,7 +538,7 @@ const lvbe_call_c_t lv_chart_func[] = { /* `lv_colorwheel` methods */ #ifdef BE_LV_WIDGET_COLORWHEEL -const lvbe_call_c_t lv_colorwheel_func[] = { +const be_ntv_func_def_t lv_colorwheel_func[] = { { "get_color_mode", (void*) &lv_colorwheel_get_color_mode, "i", "(lv.lv_obj)" }, { "get_color_mode_fixed", (void*) &lv_colorwheel_get_color_mode_fixed, "b", "(lv.lv_obj)" }, { "get_hsv", (void*) &lv_colorwheel_get_hsv, "i", "(lv.lv_obj)" }, @@ -551,14 +552,14 @@ const lvbe_call_c_t lv_colorwheel_func[] = { /* `lv_imgbtn` methods */ #ifdef BE_LV_WIDGET_IMGBTN -const lvbe_call_c_t lv_imgbtn_func[] = { +const be_ntv_func_def_t lv_imgbtn_func[] = { { "set_src", (void*) &lv_imgbtn_set_src, "", "(lv.lv_obj)(lv.lv_imgbtn_state)..." }, }; #endif // BE_LV_WIDGET_IMGBTN /* `lv_led` methods */ #ifdef BE_LV_WIDGET_LED -const lvbe_call_c_t lv_led_func[] = { +const be_ntv_func_def_t lv_led_func[] = { { "get_brightness", (void*) &lv_led_get_brightness, "i", "(lv.lv_obj)" }, { "off", (void*) &lv_led_off, "", "(lv.lv_obj)" }, { "on", (void*) &lv_led_on, "", "(lv.lv_obj)" }, @@ -570,7 +571,7 @@ const lvbe_call_c_t lv_led_func[] = { /* `lv_meter` methods */ #ifdef BE_LV_WIDGET_METER -const lvbe_call_c_t lv_meter_func[] = { +const be_ntv_func_def_t lv_meter_func[] = { { "add_arc", (void*) &lv_meter_add_arc, "lv.lv_meter_indicator", "(lv.lv_obj)(lv.lv_meter_scale)i(lv.lv_color)i" }, { "add_needle_img", (void*) &lv_meter_add_needle_img, "lv.lv_meter_indicator", "(lv.lv_obj)(lv.lv_meter_scale).ii" }, { "add_needle_line", (void*) &lv_meter_add_needle_line, "lv.lv_meter_indicator", "(lv.lv_obj)(lv.lv_meter_scale)i(lv.lv_color)i" }, @@ -587,7 +588,7 @@ const lvbe_call_c_t lv_meter_func[] = { /* `lv_msgbox` methods */ #ifdef BE_LV_WIDGET_MSGBOX -const lvbe_call_c_t lv_msgbox_func[] = { +const be_ntv_func_def_t lv_msgbox_func[] = { { "close", (void*) &lv_msgbox_close, "", "(lv.lv_obj)" }, { "get_active_btn_text", (void*) &lv_msgbox_get_active_btn_text, "s", "(lv.lv_obj)" }, { "get_btns", (void*) &lv_msgbox_get_btns, "lv.lv_obj", "(lv.lv_obj)" }, @@ -599,7 +600,7 @@ const lvbe_call_c_t lv_msgbox_func[] = { /* `lv_spinbox` methods */ #ifdef BE_LV_WIDGET_SPINBOX -const lvbe_call_c_t lv_spinbox_func[] = { +const be_ntv_func_def_t lv_spinbox_func[] = { { "decrement", (void*) &lv_spinbox_decrement, "", "(lv.lv_obj)" }, { "get_rollover", (void*) &lv_spinbox_get_rollover, "b", "(lv.lv_obj)" }, { "get_step", (void*) &lv_spinbox_get_step, "i", "(lv.lv_obj)" }, @@ -617,13 +618,13 @@ const lvbe_call_c_t lv_spinbox_func[] = { /* `lv_spinner` methods */ #ifdef BE_LV_WIDGET_SPINNER -const lvbe_call_c_t lv_spinner_func[] = { +const be_ntv_func_def_t lv_spinner_func[] = { }; #endif // BE_LV_WIDGET_SPINNER /* `lv_arc` methods */ #ifdef BE_LV_WIDGET_ARC -const lvbe_call_c_t lv_arc_func[] = { +const be_ntv_func_def_t lv_arc_func[] = { { "get_angle_end", (void*) &lv_arc_get_angle_end, "i", "(lv.lv_obj)" }, { "get_angle_start", (void*) &lv_arc_get_angle_start, "i", "(lv.lv_obj)" }, { "get_bg_angle_end", (void*) &lv_arc_get_bg_angle_end, "i", "(lv.lv_obj)" }, @@ -648,7 +649,7 @@ const lvbe_call_c_t lv_arc_func[] = { /* `lv_bar` methods */ #ifdef BE_LV_WIDGET_BAR -const lvbe_call_c_t lv_bar_func[] = { +const be_ntv_func_def_t lv_bar_func[] = { { "get_max_value", (void*) &lv_bar_get_max_value, "i", "(lv.lv_obj)" }, { "get_min_value", (void*) &lv_bar_get_min_value, "i", "(lv.lv_obj)" }, { "get_mode", (void*) &lv_bar_get_mode, "i", "(lv.lv_obj)" }, @@ -663,13 +664,13 @@ const lvbe_call_c_t lv_bar_func[] = { /* `lv_btn` methods */ #ifdef BE_LV_WIDGET_BTN -const lvbe_call_c_t lv_btn_func[] = { +const be_ntv_func_def_t lv_btn_func[] = { }; #endif // BE_LV_WIDGET_BTN /* `lv_btnmatrix` methods */ #ifdef BE_LV_WIDGET_BTNMATRIX -const lvbe_call_c_t lv_btnmatrix_func[] = { +const be_ntv_func_def_t lv_btnmatrix_func[] = { { "clear_btn_ctrl", (void*) &lv_btnmatrix_clear_btn_ctrl, "", "(lv.lv_obj)i(lv.lv_btnmatrix_ctrl)" }, { "clear_btn_ctrl_all", (void*) &lv_btnmatrix_clear_btn_ctrl_all, "", "(lv.lv_obj)(lv.lv_btnmatrix_ctrl)" }, { "get_btn_text", (void*) &lv_btnmatrix_get_btn_text, "s", "(lv.lv_obj)i" }, @@ -688,7 +689,7 @@ const lvbe_call_c_t lv_btnmatrix_func[] = { /* `lv_canvas` methods */ #ifdef BE_LV_WIDGET_CANVAS -const lvbe_call_c_t lv_canvas_func[] = { +const be_ntv_func_def_t lv_canvas_func[] = { { "blur_hor", (void*) &lv_canvas_blur_hor, "", "(lv.lv_obj)(lv.lv_area)i" }, { "blur_ver", (void*) &lv_canvas_blur_ver, "", "(lv.lv_obj)(lv.lv_area)i" }, { "copy_buf", (void*) &lv_canvas_copy_buf, "", "(lv.lv_obj).iiii" }, @@ -709,7 +710,7 @@ const lvbe_call_c_t lv_canvas_func[] = { /* `lv_checkbox` methods */ #ifdef BE_LV_WIDGET_CHECKBOX -const lvbe_call_c_t lv_checkbox_func[] = { +const be_ntv_func_def_t lv_checkbox_func[] = { { "get_text", (void*) &lv_checkbox_get_text, "s", "(lv.lv_obj)" }, { "set_text", (void*) &lv_checkbox_set_text, "", "(lv.lv_obj)s" }, { "set_text_static", (void*) &lv_checkbox_set_text_static, "", "(lv.lv_obj)s" }, @@ -718,7 +719,7 @@ const lvbe_call_c_t lv_checkbox_func[] = { /* `lv_dropdown` methods */ #ifdef BE_LV_WIDGET_DROPDOWN -const lvbe_call_c_t lv_dropdown_func[] = { +const be_ntv_func_def_t lv_dropdown_func[] = { { "add_option", (void*) &lv_dropdown_add_option, "", "(lv.lv_obj)si" }, { "clear_options", (void*) &lv_dropdown_clear_options, "", "(lv.lv_obj)" }, { "close", (void*) &lv_dropdown_close, "", "(lv.lv_obj)" }, @@ -744,7 +745,7 @@ const lvbe_call_c_t lv_dropdown_func[] = { /* `lv_label` methods */ #ifdef BE_LV_WIDGET_LABEL -const lvbe_call_c_t lv_label_func[] = { +const be_ntv_func_def_t lv_label_func[] = { { "cut_text", (void*) &lv_label_cut_text, "", "(lv.lv_obj)ii" }, { "get_letter_on", (void*) &lv_label_get_letter_on, "i", "(lv.lv_obj)(lv.lv_point)" }, { "get_letter_pos", (void*) &lv_label_get_letter_pos, "", "(lv.lv_obj)i(lv.lv_point)" }, @@ -767,7 +768,7 @@ const lvbe_call_c_t lv_label_func[] = { /* `lv_line` methods */ #ifdef BE_LV_WIDGET_LINE -const lvbe_call_c_t lv_line_func[] = { +const be_ntv_func_def_t lv_line_func[] = { { "get_y_invert", (void*) &lv_line_get_y_invert, "b", "(lv.lv_obj)" }, { "set_points", (void*) &lv_line_set_points, "", "(lv.lv_obj)ii" }, { "set_y_invert", (void*) &lv_line_set_y_invert, "", "(lv.lv_obj)b" }, @@ -776,7 +777,7 @@ const lvbe_call_c_t lv_line_func[] = { /* `lv_roller` methods */ #ifdef BE_LV_WIDGET_ROLLER -const lvbe_call_c_t lv_roller_func[] = { +const be_ntv_func_def_t lv_roller_func[] = { { "get_option_cnt", (void*) &lv_roller_get_option_cnt, "i", "(lv.lv_obj)" }, { "get_options", (void*) &lv_roller_get_options, "s", "(lv.lv_obj)" }, { "get_selected", (void*) &lv_roller_get_selected, "i", "(lv.lv_obj)" }, @@ -789,7 +790,7 @@ const lvbe_call_c_t lv_roller_func[] = { /* `lv_slider` methods */ #ifdef BE_LV_WIDGET_SLIDER -const lvbe_call_c_t lv_slider_func[] = { +const be_ntv_func_def_t lv_slider_func[] = { { "get_left_value", (void*) &lv_slider_get_left_value, "i", "(lv.lv_obj)" }, { "get_max_value", (void*) &lv_slider_get_max_value, "i", "(lv.lv_obj)" }, { "get_min_value", (void*) &lv_slider_get_min_value, "i", "(lv.lv_obj)" }, @@ -805,13 +806,13 @@ const lvbe_call_c_t lv_slider_func[] = { /* `lv_switch` methods */ #ifdef BE_LV_WIDGET_SWITCH -const lvbe_call_c_t lv_switch_func[] = { +const be_ntv_func_def_t lv_switch_func[] = { }; #endif // BE_LV_WIDGET_SWITCH /* `lv_table` methods */ #ifdef BE_LV_WIDGET_TABLE -const lvbe_call_c_t lv_table_func[] = { +const be_ntv_func_def_t lv_table_func[] = { { "add_cell_ctrl", (void*) &lv_table_add_cell_ctrl, "", "(lv.lv_obj)ii(lv.lv_table_cell_ctrl)" }, { "clear_cell_ctrl", (void*) &lv_table_clear_cell_ctrl, "", "(lv.lv_obj)ii(lv.lv_table_cell_ctrl)" }, { "get_cell_value", (void*) &lv_table_get_cell_value, "s", "(lv.lv_obj)ii" }, @@ -830,7 +831,7 @@ const lvbe_call_c_t lv_table_func[] = { /* `lv_textarea` methods */ #ifdef BE_LV_WIDGET_TEXTAREA -const lvbe_call_c_t lv_textarea_func[] = { +const be_ntv_func_def_t lv_textarea_func[] = { { "add_char", (void*) &lv_textarea_add_char, "", "(lv.lv_obj)i" }, { "add_text", (void*) &lv_textarea_add_text, "", "(lv.lv_obj)s" }, { "clear_selection", (void*) &lv_textarea_clear_selection, "", "(lv.lv_obj)" }, @@ -901,7 +902,7 @@ extern const bclass be_class_lv_theme; // map of clases -const lvbe_call_c_classes_t lv_classes[] = { +const be_ntv_class_def_t lv_classes[] = { #ifdef BE_LV_WIDGET_ARC { "lv_arc", &be_class_lv_arc, lv_arc_func, sizeof(lv_arc_func) / sizeof(lv_arc_func[0]) }, #endif // BE_LV_WIDGET_ARC @@ -988,106 +989,106 @@ const size_t lv_classes_size = sizeof(lv_classes) / sizeof(lv_classes[0]); /* `lv_theme` methods */ /* `lv_img` methods */ #ifdef BE_LV_WIDGET_IMG - int be_ntv_lv_img_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_img_create, "+", "(lv.lv_obj)"); } + int be_ntv_lv_img_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_img_create, "+_p", "(lv.lv_obj)"); } #endif // BE_LV_WIDGET_IMG /* `lv_disp` methods */ /* `lv_obj` methods */ - int be_ntv_lv_obj_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_obj_create, "+", "(lv.lv_obj)"); } + int be_ntv_lv_obj_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_obj_create, "+_p", "(lv.lv_obj)"); } /* `lv_group` methods */ - int be_ntv_lv_group_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_group_create, "+", ""); } + int be_ntv_lv_group_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_group_create, "+_p", ""); } /* `lv_indev` methods */ /* `lv_chart` methods */ #ifdef BE_LV_WIDGET_CHART - int be_ntv_lv_chart_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_chart_create, "+", "(lv.lv_obj)"); } + int be_ntv_lv_chart_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_chart_create, "+_p", "(lv.lv_obj)"); } #endif // BE_LV_WIDGET_CHART /* `lv_colorwheel` methods */ #ifdef BE_LV_WIDGET_COLORWHEEL - int be_ntv_lv_colorwheel_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_colorwheel_create, "+", "(lv.lv_obj)b"); } + int be_ntv_lv_colorwheel_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_colorwheel_create, "+_p", "(lv.lv_obj)b"); } #endif // BE_LV_WIDGET_COLORWHEEL /* `lv_imgbtn` methods */ #ifdef BE_LV_WIDGET_IMGBTN - int be_ntv_lv_imgbtn_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_imgbtn_create, "+", "(lv.lv_obj)"); } + int be_ntv_lv_imgbtn_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_imgbtn_create, "+_p", "(lv.lv_obj)"); } #endif // BE_LV_WIDGET_IMGBTN /* `lv_led` methods */ #ifdef BE_LV_WIDGET_LED - int be_ntv_lv_led_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_led_create, "+", "(lv.lv_obj)"); } + int be_ntv_lv_led_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_led_create, "+_p", "(lv.lv_obj)"); } #endif // BE_LV_WIDGET_LED /* `lv_meter` methods */ #ifdef BE_LV_WIDGET_METER - int be_ntv_lv_meter_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_meter_create, "+", "(lv.lv_obj)"); } + int be_ntv_lv_meter_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_meter_create, "+_p", "(lv.lv_obj)"); } #endif // BE_LV_WIDGET_METER /* `lv_msgbox` methods */ #ifdef BE_LV_WIDGET_MSGBOX - int be_ntv_lv_msgbox_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_msgbox_create, "+", "(lv.lv_obj)sssb"); } + int be_ntv_lv_msgbox_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_msgbox_create, "+_p", "(lv.lv_obj)sssb"); } #endif // BE_LV_WIDGET_MSGBOX /* `lv_spinbox` methods */ #ifdef BE_LV_WIDGET_SPINBOX - int be_ntv_lv_spinbox_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_spinbox_create, "+", "(lv.lv_obj)"); } + int be_ntv_lv_spinbox_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_spinbox_create, "+_p", "(lv.lv_obj)"); } #endif // BE_LV_WIDGET_SPINBOX /* `lv_spinner` methods */ #ifdef BE_LV_WIDGET_SPINNER - int be_ntv_lv_spinner_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_spinner_create, "+", "(lv.lv_obj)ii"); } + int be_ntv_lv_spinner_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_spinner_create, "+_p", "(lv.lv_obj)ii"); } #endif // BE_LV_WIDGET_SPINNER /* `lv_arc` methods */ #ifdef BE_LV_WIDGET_ARC - int be_ntv_lv_arc_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_arc_create, "+", "(lv.lv_obj)"); } + int be_ntv_lv_arc_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_arc_create, "+_p", "(lv.lv_obj)"); } #endif // BE_LV_WIDGET_ARC /* `lv_bar` methods */ #ifdef BE_LV_WIDGET_BAR - int be_ntv_lv_bar_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_bar_create, "+", "(lv.lv_obj)"); } + int be_ntv_lv_bar_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_bar_create, "+_p", "(lv.lv_obj)"); } #endif // BE_LV_WIDGET_BAR /* `lv_btn` methods */ #ifdef BE_LV_WIDGET_BTN - int be_ntv_lv_btn_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_btn_create, "+", "(lv.lv_obj)"); } + int be_ntv_lv_btn_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_btn_create, "+_p", "(lv.lv_obj)"); } #endif // BE_LV_WIDGET_BTN /* `lv_btnmatrix` methods */ #ifdef BE_LV_WIDGET_BTNMATRIX - int be_ntv_lv_btnmatrix_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_btnmatrix_create, "+", "(lv.lv_obj)"); } + int be_ntv_lv_btnmatrix_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_btnmatrix_create, "+_p", "(lv.lv_obj)"); } #endif // BE_LV_WIDGET_BTNMATRIX /* `lv_canvas` methods */ #ifdef BE_LV_WIDGET_CANVAS - int be_ntv_lv_canvas_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_canvas_create, "+", "(lv.lv_obj)"); } + int be_ntv_lv_canvas_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_canvas_create, "+_p", "(lv.lv_obj)"); } #endif // BE_LV_WIDGET_CANVAS /* `lv_checkbox` methods */ #ifdef BE_LV_WIDGET_CHECKBOX - int be_ntv_lv_checkbox_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_checkbox_create, "+", "(lv.lv_obj)"); } + int be_ntv_lv_checkbox_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_checkbox_create, "+_p", "(lv.lv_obj)"); } #endif // BE_LV_WIDGET_CHECKBOX /* `lv_dropdown` methods */ #ifdef BE_LV_WIDGET_DROPDOWN - int be_ntv_lv_dropdown_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_dropdown_create, "+", "(lv.lv_obj)"); } + int be_ntv_lv_dropdown_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_dropdown_create, "+_p", "(lv.lv_obj)"); } #endif // BE_LV_WIDGET_DROPDOWN /* `lv_label` methods */ #ifdef BE_LV_WIDGET_LABEL - int be_ntv_lv_label_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_label_create, "+", "(lv.lv_obj)"); } + int be_ntv_lv_label_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_label_create, "+_p", "(lv.lv_obj)"); } #endif // BE_LV_WIDGET_LABEL /* `lv_line` methods */ #ifdef BE_LV_WIDGET_LINE - int be_ntv_lv_line_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_line_create, "+", "(lv.lv_obj)"); } + int be_ntv_lv_line_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_line_create, "+_p", "(lv.lv_obj)"); } #endif // BE_LV_WIDGET_LINE /* `lv_roller` methods */ #ifdef BE_LV_WIDGET_ROLLER - int be_ntv_lv_roller_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_roller_create, "+", "(lv.lv_obj)"); } + int be_ntv_lv_roller_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_roller_create, "+_p", "(lv.lv_obj)"); } #endif // BE_LV_WIDGET_ROLLER /* `lv_slider` methods */ #ifdef BE_LV_WIDGET_SLIDER - int be_ntv_lv_slider_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_slider_create, "+", "(lv.lv_obj)"); } + int be_ntv_lv_slider_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_slider_create, "+_p", "(lv.lv_obj)"); } #endif // BE_LV_WIDGET_SLIDER /* `lv_switch` methods */ #ifdef BE_LV_WIDGET_SWITCH - int be_ntv_lv_switch_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_switch_create, "+", "(lv.lv_obj)"); } + int be_ntv_lv_switch_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_switch_create, "+_p", "(lv.lv_obj)"); } #endif // BE_LV_WIDGET_SWITCH /* `lv_table` methods */ #ifdef BE_LV_WIDGET_TABLE - int be_ntv_lv_table_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_table_create, "+", "(lv.lv_obj)"); } + int be_ntv_lv_table_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_table_create, "+_p", "(lv.lv_obj)"); } #endif // BE_LV_WIDGET_TABLE /* `lv_textarea` methods */ #ifdef BE_LV_WIDGET_TEXTAREA - int be_ntv_lv_textarea_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_textarea_create, "+", "(lv.lv_obj)"); } + int be_ntv_lv_textarea_init(bvm *vm) { return be_call_c_func(vm, (void*) &lv_textarea_create, "+_p", "(lv.lv_obj)"); } #endif // BE_LV_WIDGET_TEXTAREA // create font either empty or from parameter on stack -int lvbe_font_create(bvm *vm) { return be_call_c_func(vm, NULL, "+lv_font", ""); } -int lvbe_theme_create(bvm *vm) { return be_call_c_func(vm, NULL, "+lv_theme", ""); } +int lvbe_font_create(bvm *vm) { return be_call_c_func(vm, NULL, "+_p", ""); } +int lvbe_theme_create(bvm *vm) { return be_call_c_func(vm, NULL, "+_p", ""); } #ifdef __cplusplus diff --git a/tasmota/xdrv_52_1_berry_native.ino b/tasmota/xdrv_52_1_berry_native.ino index 2bf1f152e..4481320d7 100644 --- a/tasmota/xdrv_52_1_berry_native.ino +++ b/tasmota/xdrv_52_1_berry_native.ino @@ -26,19 +26,6 @@ const char kTypeError[] PROGMEM = "type_error"; const char kInternalError[] PROGMEM = "intenal_error"; -extern "C" { - - /*********************************************************************************************\ - * Support for Berry int constants - * as virtual members - \*********************************************************************************************/ - typedef struct be_constint_t { - const char * name; - int32_t value; - } be_constint_t; - -} - /*********************************************************************************************\ * LVGL top level virtual members * @@ -76,65 +63,6 @@ extern "C" { return v; } - // variant of be_raise with string format - [[ noreturn ]] void be_raisef(bvm *vm, const char *except, const char *msg, ...) { - // To save stack space support logging for max text length of 128 characters - char log_data[128]; - - va_list arg; - va_start(arg, msg); - uint32_t len = ext_vsnprintf_P(log_data, sizeof(log_data)-3, msg, arg); - va_end(arg); - if (len+3 > sizeof(log_data)) { strcat(log_data, "..."); } // Actual data is more - be_raise(vm, except, log_data); - } - - static void map_insert_int(bvm *vm, const char *key, int value) - { - be_pushstring(vm, key); - be_pushint(vm, value); - be_data_insert(vm, -3); - be_pop(vm, 2); - } - static void map_insert_bool(bvm *vm, const char *key, bool value) - { - be_pushstring(vm, key); - be_pushbool(vm, value); - be_data_insert(vm, -3); - be_pop(vm, 2); - } - // if value == NAN, ignore - static void map_insert_float(bvm *vm, const char *key, float value) - { - if (!isnan(value)) { - be_pushstring(vm, key); - be_pushreal(vm, value); - be_data_insert(vm, -3); - be_pop(vm, 2); - } - } - static void map_insert_str(bvm *vm, const char *key, const char *value) - { - be_pushstring(vm, key); - be_pushstring(vm, value); - be_data_insert(vm, -3); - be_pop(vm, 2); - } - static void map_insert_list_uint8(bvm *vm, const char *key, const uint8_t *value, size_t size) - { - be_pushstring(vm, key); - - be_newobject(vm, "list"); - for (uint32_t i=0; i < size; i++) { - be_pushint(vm, value[i]); - be_data_push(vm, -2); - be_pop(vm, 1); - } - be_pop(vm, 1); // now list is on top - - be_data_insert(vm, -3); // insert into map, key/value - be_pop(vm, 2); // pop both key and value - } int32_t member_find(bvm *vm, const char *key, int32_t default_value) { int32_t ret = default_value; if (be_getmember(vm, -1, key)) { @@ -171,283 +99,6 @@ extern "C" { be_call(vm, 2); // call wirn 2 parameters (implicit instance and key) be_pop(vm, 2); // pop 2 arguments and return value } - - // create an object from the pointer and a class name - // on return, instance is pushed on the stack - void lv_create_object(bvm *vm, const char * class_name, void * ptr); - void lv_create_object(bvm *vm, const char * class_name, void * ptr) { - if (ptr == nullptr) { - be_throw(vm, BE_MALLOC_FAIL); - } - - be_getglobal(vm, class_name); // stack = class - be_call(vm, 0); // instanciate, stack = instance - be_getmember(vm, -1, "init"); // stack = instance, init_func - be_pushvalue(vm, -2); // stack = instance, init_func, instance - be_pushcomptr(vm, ptr); // stack = instance, init_func, instance, ptr - be_call(vm, 2); // stack = instance, ret, instance, ptr - be_pop(vm, 3); // stack = instance - } - - extern void berry_log_C(const char * berry_buf, ...); - // Create a class given a global name or a name within a module - // Case 1: (no dot in name) `lv_wifi_bars` will look for a global variable `lv_wifi_bars` - // Case 2: (dot in name) `lvgl.lv_obj` will import `lvgl` and look for `lv_obj` within this module - // returns true if successful and result is top of stack, or false if not found and `nil` is at top of stack - bbool be_find_class(bvm *vm, const char * cl_name); - bbool be_find_class(bvm *vm, const char * cl_name) { - char *saveptr; - bbool ret = false; - - if (cl_name == NULL) { - be_pushnil(vm); - return ret; - } - // berry_log_C(">> be_find_class %s", cl_name); - char cl_name_buf[strlen(cl_name)+1]; - strcpy(cl_name_buf, cl_name); - - char * prefix = strtok_r(cl_name_buf, ".", &saveptr); - char * suffix = strtok_r(NULL, ".", &saveptr); - if (suffix) { - // berry_log_C(">> be_find_class %s - %s", prefix, suffix); - be_getmodule(vm, prefix); - ret = be_getmember(vm, -1, suffix); - // berry_log_C(">> be_find_class ret=%i", ret); - be_remove(vm, -2); - } else { - ret = be_getglobal(vm, prefix); - } - return ret; - } -} - -/*********************************************************************************************\ - * Binary search for dynamic attributes - * - * Names need to be sorted -\*********************************************************************************************/ -// binary search within an array of sorted strings -// the first 4 bytes are a pointer to a string -// returns 0..total_elements-1 or -1 if not found -// -// This version skips the first character of the string if it's not a letter, -// the first character is used to indicate the type of the value associated to the key -extern "C" { - int32_t bin_search(const char * needle, const void * table, size_t elt_size, size_t total_elements); - int32_t bin_search(const char * needle, const void * table, size_t elt_size, size_t total_elements) { - int32_t low = 0; - int32_t high = total_elements - 1; - int32_t mid = (low + high) / 2; - // start a dissect - while (low <= high) { - const char * elt = *(const char **) ( ((uint8_t*)table) + mid * elt_size ); - char first_char = elt[0]; - if ( !(first_char >= 'a' && first_char <='z') && !(first_char >= 'A' && first_char <='Z') ) { - elt++; // skip first char - } - int32_t comp = strcmp(needle, elt); - if (comp < 0) { - high = mid - 1; - } else if (comp > 0) { - low = mid + 1; - } else { - break; - } - mid = (low + high) / 2; - } - if (low <= high) { - return mid; - } else { - return -1; - } - } -} - -/*********************************************************************************************\ - * Generalized callbacks - * - * Warning, the following expect all parameters to be 32 bits wide -\*********************************************************************************************/ - -/*********************************************************************************************\ - * Automatically parse Berry stack and call the C function accordingly - * - * This function takes the n incoming arguments and pushes them as arguments - * on the stack for the C function: - * - be_int -> int32_t - * - be_bool -> int32_t with value 0/1 - * - be_string -> const char * - * - be_instance -> gets the member "_p" and pushes as void* - * - * This works because C silently ignores any unwanted arguments. - * There is a strong requirements that all ints and pointers are 32 bits. - * Float is not supported but could be added. Double cannot be supported because they are 64 bits - * - * Optional argument: - * - return_type: the C function return value is int32_t and is converted to the - * relevant Berry object depending on this char: - * '' (default): nil, no value - * 'i' be_int - * 'b' be_bool - * 's' be_str - * - * - arg_type: optionally check the types of input arguments, or throw an error - * string of argument types, '+' marks optional arguments - * '.' don't care - * 'i' be_int - * 'b' be_bool - * 's' be_string - * 'c' C callback - * 'lv_obj' be_instance of type or subtype - * '^lv_event_cb' callback of a named class - will call `_lvgl.gen_cb(arg_type, closure, self, lv native pointer)` and expects a callback address in return - * - * Ex: "oii+s" takes 3 mandatory arguments (obj_instance, int, int) and an optional fourth one [,string] -\*********************************************************************************************/ -// general form of lv_obj_t* function, up to 4 parameters -// We can only send 32 bits arguments (no 64 bits nor double) and we expect pointers to be 32 bits - -#define LVBE_LVGL_GLOB "_lvgl" -#define LVBE_LVGL_CB_GEN "gen_cb" - -// read a single value at stack position idx, convert to int. -// if object instance, get `_p` member and convert it recursively -int32_t be_convert_single_elt(bvm *vm, int32_t idx, const char * arg_type = nullptr, void * lv_obj_cb = nullptr) { - int32_t ret = 0; - char provided_type = 0; - idx = be_absindex(vm, idx); // make sure we have an absolute index - - // berry_log_C(">> 0 idx=%i arg_type=%s", idx, arg_type ? arg_type : "NULL"); - if (arg_type == nullptr) { arg_type = "."; } // if no type provided, replace with wildchar - size_t arg_type_len = strlen(arg_type); - - // handle callbacks first, since a wrong parameter will always yield to a crash - if (arg_type_len > 1 && arg_type[0] == '^') { // it is a callback - arg_type++; // skip first character - if (be_isclosure(vm, idx)) { - be_getglobal(vm, LVBE_LVGL_GLOB); - be_getmethod(vm, -1, LVBE_LVGL_CB_GEN); - be_pushvalue(vm, -2); - be_remove(vm, -3); // stack contains method + instance - be_pushstring(vm, arg_type); - be_pushvalue(vm, idx); - be_pushvalue(vm, 1); - be_pushcomptr(vm, lv_obj_cb); - be_call(vm, 5); - const void * func = be_tocomptr(vm, -6); - be_pop(vm, 6); - - // berry_log_C("func=%p", func); - return (int32_t) func; - } else { - be_raise(vm, kTypeError, "Closure expected for callback type"); - } - } - - // first convert the value to int32 - if (be_isint(vm, idx)) { ret = be_toint(vm, idx); provided_type = 'i'; } - else if (be_isbool(vm, idx)) { ret = be_tobool(vm, idx); provided_type = 'b'; } - else if (be_isstring(vm, idx)) { ret = (int32_t) be_tostring(vm, idx); provided_type = 's'; } - else if (be_iscomptr(vm, idx)) { ret = (int32_t) be_tocomptr(vm, idx); provided_type = 'c'; } - - // check if simple type was a match - if (provided_type) { - bool type_ok = false; - type_ok = (arg_type[0] == '.'); // any type is accepted - type_ok = type_ok || (arg_type[0] == provided_type); // or type is a match - type_ok = type_ok || (ret == 0 && arg_type_len != 1); // or NULL is accepted for an instance - - if (!type_ok) { - berry_log_C("Unexpected argument type '%c', expected '%s'", provided_type, arg_type); - } - return ret; - } - - // non-simple type - if (be_isinstance(vm, idx)) { - // check if the instance is a subclass of `bytes()`` - be_getbuiltin(vm, "bytes"); // add "list" class - if (be_isderived(vm, idx)) { - be_pop(vm, 1); - be_getmember(vm, idx, "_buffer"); - be_pushvalue(vm, idx); - be_call(vm, 1); - int32_t ret = (int32_t) be_tocomptr(vm, -2); - be_pop(vm, 2); - return ret; - } else { - be_pop(vm, 1); - be_getmember(vm, idx, "_p"); - int32_t ret = be_convert_single_elt(vm, -1, nullptr); // recurse - be_pop(vm, 1); - - if (arg_type_len > 1) { - // Check type - be_classof(vm, idx); - bool class_found = be_find_class(vm, arg_type); - // Stack: class_of_idx, class_of_target (or nil) - if (class_found) { - if (!be_isderived(vm, -2)) { - berry_log_C("Unexpected class type '%s', expected '%s'", be_classname(vm, idx), arg_type); - } - } else { - berry_log_C("Unable to find class '%s' (%d)", arg_type, arg_type_len); - } - be_pop(vm, 2); - } else if (arg_type[0] != '.') { - berry_log_C("Unexpected instance type '%s', expected '%s'", be_classname(vm, idx), arg_type); - } - - return ret; - } - } else { - be_raise(vm, kTypeError, nullptr); - } - - return ret; -} - -extern "C" { - - /*********************************************************************************************\ - * Generalized virtual members for modules - * - * Takes a pointer to be_constint_t array and size - * Returns true if a match was found. In such case the result is on Berry stack - * - * Encoding depend on prefix (which is skipped when matching names): - * 1. `COLOR_WHITE` int value - * 3. `$SYMBOL_OK"` string pointer - * 4. `&seg7_font` comptr - \*********************************************************************************************/ - bool be_module_member(bvm *vm, const be_constint_t * definitions, size_t def_len); - bool be_module_member(bvm *vm, const be_constint_t * definitions, size_t def_len) { - int32_t argc = be_top(vm); // Get the number of arguments - if (argc == 1 && be_isstring(vm, 1)) { - const char * needle = be_tostring(vm, 1); - int32_t idx; - - idx = bin_search(needle, &definitions[0].name, sizeof(definitions[0]), def_len); - if (idx >= 0) { - // we did have a match - const char * key = definitions[idx].name; - switch (key[0]) { - // switch depending on the first char of the key, indicating the type - case '$': // string - be_pushstring(vm, (const char*) definitions[idx].value); - break; - case '&': // native function - be_pushntvfunction(vm, (bntvfunc) definitions[idx].value); - break; - default: // int - be_pushint(vm, definitions[idx].value); - break; - } - return true; - } - } - return false; - } } /*********************************************************************************************\ @@ -459,7 +110,6 @@ void BrTimeoutStart(void) { if (0 == berry.timeout) { berry.timeout = 1; // rare case when value accidentally computes to zero } - } void BrTimeoutYield(void) { diff --git a/tasmota/xdrv_52_3_berry_gpio.ino b/tasmota/xdrv_52_3_berry_gpio.ino index f694b6444..63f29c258 100644 --- a/tasmota/xdrv_52_3_berry_gpio.ino +++ b/tasmota/xdrv_52_3_berry_gpio.ino @@ -39,7 +39,7 @@ extern "C" { // virtual member int gp_member(bvm *vm); int gp_member(bvm *vm) { - if (be_module_member(vm, lv_gpio_constants, lv_gpio_constants_size)) { + if (be_const_member(vm, lv_gpio_constants, lv_gpio_constants_size)) { be_return(vm); } else { be_return_nil(vm); diff --git a/tasmota/xdrv_52_3_berry_light.ino b/tasmota/xdrv_52_3_berry_light.ino index 19aa3cfb6..89ba735e3 100644 --- a/tasmota/xdrv_52_3_berry_light.ino +++ b/tasmota/xdrv_52_3_berry_light.ino @@ -50,11 +50,11 @@ extern "C" { light_controller.calcLevels(channels); uint8_t bri = light_state.getBri(); - // map_insert_int(vm, "_devices_present", TasmotaGlobal.devices_present); - // map_insert_int(vm, "_light_device", Light.device); - // map_insert_int(vm, "_light_subtype", Light.subtype); - // map_insert_int(vm, "_light_multi", Light.pwm_multi_channels); - // map_insert_int(vm, "_light_linked", light_controller.isCTRGBLinked()); + // be_map_insert_int(vm, "_devices_present", TasmotaGlobal.devices_present); + // be_map_insert_int(vm, "_light_device", Light.device); + // be_map_insert_int(vm, "_light_subtype", Light.subtype); + // be_map_insert_int(vm, "_light_multi", Light.pwm_multi_channels); + // be_map_insert_int(vm, "_light_linked", light_controller.isCTRGBLinked()); if (!Light.pwm_multi_channels) { uint32_t subtype = Light.subtype; // virtual sub-type, for SO37 128 @@ -64,7 +64,7 @@ extern "C" { if (light_controller.isCTRGBLinked() && (light_num == 0)) { data_present = true; // valid combination if (subtype >= LST_RGBW) { - map_insert_str(vm, "colormode", (light_state.getColorMode() & LCM_RGB ? "rgb" : "ct")); + be_map_insert_str(vm, "colormode", (light_state.getColorMode() & LCM_RGB ? "rgb" : "ct")); } } if (!light_controller.isCTRGBLinked()) { @@ -83,33 +83,33 @@ extern "C" { if (data_present) { // see ResponseLightState() - map_insert_bool(vm, "power", bitRead(TasmotaGlobal.power, light_num + Light.device - 1)); - map_insert_int(vm, "bri", bri); + be_map_insert_bool(vm, "power", bitRead(TasmotaGlobal.power, light_num + Light.device - 1)); + be_map_insert_int(vm, "bri", bri); if (subtype >= LST_RGB) { uint16_t hue; uint8_t sat, bri; light_state.getHSB(&hue, &sat, &bri); - map_insert_int(vm, "hue", hue); - map_insert_int(vm, "sat", sat); + be_map_insert_int(vm, "hue", hue); + be_map_insert_int(vm, "sat", sat); } if ((LST_COLDWARM == subtype) || (LST_RGBW <= subtype)) { - map_insert_int(vm, "ct", light_state.getCT()); + be_map_insert_int(vm, "ct", light_state.getCT()); } if (subtype >= LST_RGB) { snprintf(s_rgb, sizeof(s_rgb), PSTR("%02X%02X%02X"), channels[0], channels[1], channels[2]); - map_insert_str(vm, "rgb", s_rgb); + be_map_insert_str(vm, "rgb", s_rgb); } if (subtype > LST_NONE) { - map_insert_list_uint8(vm, "channels", &channels[chanidx], subtype); + be_map_insert_list_uint8(vm, "channels", &channels[chanidx], subtype); } } } else { // Light.pwm_multi_channels if ((light_num >= 0) && (light_num < LST_MAX)) { data_present = true; - map_insert_bool(vm, "power", Light.power & (1 << light_num)); - map_insert_int(vm, "bri", Light.current_color[light_num]); - map_insert_list_uint8(vm, "channels", &channels[light_num], 1); + be_map_insert_bool(vm, "power", Light.power & (1 << light_num)); + be_map_insert_int(vm, "bri", Light.current_color[light_num]); + be_map_insert_list_uint8(vm, "channels", &channels[light_num], 1); } } diff --git a/tasmota/xdrv_52_3_berry_lvgl.ino b/tasmota/xdrv_52_3_berry_lvgl.ino index f0cba617a..f86ed7db7 100644 --- a/tasmota/xdrv_52_3_berry_lvgl.ino +++ b/tasmota/xdrv_52_3_berry_lvgl.ino @@ -23,7 +23,7 @@ #include #include "lvgl.h" -#include "be_lvgl.h" +#include "be_mapping.h" #include "be_ctypes.h" #include "Adafruit_LvGL_Glue.h" @@ -35,6 +35,8 @@ // Berry easy logging extern "C" { extern void berry_log_C(const char * berry_buf, ...); + extern const be_ntv_class_def_t lv_classes[]; + extern const size_t lv_classes_size; } extern Adafruit_LvGL_Glue * glue; @@ -99,80 +101,6 @@ LVBE_globals lvbe; extern void start_lvgl(const char * uconfig); extern void lv_ex_get_started_1(void); -/*********************************************************************************************\ - * Calling any LVGL function with auto-mapping - * -\*********************************************************************************************/ - -// check input parameters, and create callbacks if needed -// change values in place -// -// Format: -// - either a lowercase character encoding for a simple type -// - 'b': bool -// - 'i': int (int32_t) -// - 's': string (const char *) -// -// - a class name surroungded by parenthesis -// - '(lv_button)' -> lv_button class or derived -// - '[lv_event_cb]' -> callback type, still prefixed with '^' to mark that it is cb -// -void be_check_arg_type(bvm *vm, int32_t arg_start, int32_t argc, const char * arg_type, int32_t p[8]); -void be_check_arg_type(bvm *vm, int32_t arg_start, int32_t argc, const char * arg_type, int32_t p[8]) { - bool arg_type_check = (arg_type != nullptr); // is type checking activated - int32_t arg_idx = 0; // position in arg_type string - char type_short_name[32]; - - for (uint32_t i = 0; i < argc; i++) { - type_short_name[0] = 0; // clear string - // extract individual type - if (nullptr != arg_type) { - switch (arg_type[arg_idx]) { - case '.': - case 'a'...'z': - type_short_name[0] = arg_type[arg_idx]; - type_short_name[1] = 0; - arg_idx++; - break; - case '(': - case '^': - { - uint32_t prefix = 0; - if (arg_type[arg_idx] == '^') { - type_short_name[0] = '^'; - type_short_name[1] = 0; - prefix = 1; - } - uint32_t offset = 0; - arg_idx++; - while (arg_type[arg_idx + offset] != ')' && arg_type[arg_idx + offset] != '^' && arg_type[arg_idx + offset] != 0 && offset+prefix+1 < sizeof(type_short_name)) { - type_short_name[offset+prefix] = arg_type[arg_idx + offset]; - type_short_name[offset+prefix+1] = 0; - offset++; - } - if (arg_type[arg_idx + offset] == 0) { - arg_type = nullptr; // no more parameters, stop iterations - } - arg_idx += offset + 1; - } - break; - case 0: - arg_type = nullptr; // stop iterations - break; - } - } - // AddLog(LOG_LEVEL_INFO, ">> be_call_c_func arg %i, type %s", i, arg_type_check ? type_short_name : ""); - p[i] = be_convert_single_elt(vm, i + arg_start, arg_type_check ? type_short_name : nullptr, (void*) p[0]); - } - - // check if we are missing arguments - if (arg_type != nullptr && arg_type[arg_idx] != 0) { - berry_log_C("Missing arguments, remaining type '%s'", &arg_type[arg_idx]); - } -} - -typedef int32_t (*fn_any_callable)(int32_t p0, int32_t p1, int32_t p2, int32_t p3, - int32_t p4, int32_t p5, int32_t p6, int32_t p7); extern "C" { void lv_init_set_member(bvm *vm, int index, void * ptr); @@ -205,15 +133,15 @@ extern "C" { // berry_log_C("lvx_member looking for method '%s' of class '%s'", method_name, class_name); // look for class descriptor - int32_t class_idx = bin_search(class_name, &lv_classes[0].name, sizeof(lv_classes[0]), lv_classes_size); + int32_t class_idx = be_map_bin_search(class_name, &lv_classes[0].name, sizeof(lv_classes[0]), lv_classes_size); if (class_idx >= 0) { - const lvbe_call_c_t * methods_calls = lv_classes[class_idx].func_table; + const be_ntv_func_def_t * methods_calls = lv_classes[class_idx].func_table; size_t methods_size = lv_classes[class_idx].size; - int32_t method_idx = bin_search(method_name, methods_calls, sizeof(lvbe_call_c_t), methods_size); + int32_t method_idx = be_map_bin_search(method_name, methods_calls, sizeof(be_ntv_func_def_t), methods_size); if (method_idx >= 0) { // method found - const lvbe_call_c_t * method = &methods_calls[method_idx]; + const be_ntv_func_def_t * method = &methods_calls[method_idx]; // berry_log_C("lvx_member method found func=%p return_type=%s arg_type=%s", method->func, method->return_type, method->arg_type); // push native closure be_pushntvclosure(vm, &lvx_call_c, 3); // 3 upvals @@ -245,63 +173,6 @@ extern "C" { } be_raise(vm, kTypeError, nullptr); } - - int be_call_c_func(bvm *vm, void * func, const char * return_type, const char * arg_type) { - // AddLog(LOG_LEVEL_INFO, ">> be_call_c_func, func=%p, return_type=%s, arg_type=%s", func, return_type ? return_type : "", arg_type ? arg_type : ""); - int32_t p[8] = {0,0,0,0,0,0,0,0}; - int32_t argc = be_top(vm); // Get the number of arguments - - // the following describe the active payload for the C function (start and count) - // this is because the `init()` constructor first arg is not passed to the C function - int32_t arg_start = 1; // start with standard values - int32_t arg_count = argc; - - // check if we call a constructor, in this case we store the return type into the new object - // check if we call a constructor with a comptr as first arg - if (return_type && return_type[0] == '+') { - if (argc > 1 && be_iscomptr(vm, 2)) { - lv_obj_t * obj = (lv_obj_t*) be_tocomptr(vm, 2); - lv_init_set_member(vm, 1, obj); - be_return_nil(vm); - } else { - // we need to discard the first arg - arg_start++; - arg_count--; - } - } - - fn_any_callable f = (fn_any_callable) func; - // AddLog(LOG_LEVEL_INFO, ">> before be_check_arg_type argc=%i - %i", arg_count, arg_start); - be_check_arg_type(vm, arg_start, arg_count, arg_type, p); - // AddLog(LOG_LEVEL_INFO, ">> be_call_c_func(%p) - %p,%p,%p,%p,%p - %s", f, p[0], p[1], p[2], p[3], p[4], return_type ? return_type : "NULL"); - int32_t ret = (*f)(p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); - // AddLog(LOG_LEVEL_INFO, ">> be_call_c_func, ret = %p", ret); - if ((return_type == nullptr) || (strlen(return_type) == 0)) { be_return_nil(vm); } // does not return - else if (return_type[0] == '+') { - lv_obj_t * obj = (lv_obj_t*) ret; - lv_init_set_member(vm, 1, obj); - be_return_nil(vm); - } - else if (strlen(return_type) == 1) { - switch (return_type[0]) { - case '.': // fallback next - case 'i': be_pushint(vm, ret); break; - case 'b': be_pushbool(vm, ret); break; - case 's': be_pushstring(vm, (const char*) ret); break; - case 'c': be_pushint(vm, ret); break; // TODO missing 'c' general callback type - default: be_raise(vm, "internal_error", "Unsupported return type"); break; - } - be_return(vm); - } else { // class name - // AddLog(LOG_LEVEL_INFO, ">> be_call_c_func, create_obj ret=%i return_type=%s", ret, return_type); - be_find_class(vm, return_type); - be_pushcomptr(vm, (void*) ret); // stack = class, ptr - be_pushcomptr(vm, (void*) -1); // stack = class, ptr, -1 - be_call(vm, 2); // instanciate with 2 arguments, stack = instance, -1, ptr - be_pop(vm, 2); // stack = instance - be_return(vm); - } - } } /*********************************************************************************************\ @@ -396,7 +267,7 @@ extern "C" { typedef lv_obj_t* (*fn_lvobj__void)(void); // f() -> newly created lv_obj() int lv0_lvobj__void_call(bvm *vm, fn_lvobj__void func) { lv_obj_t * obj = (*func)(); - be_find_class(vm, "lv.lv_obj"); + be_find_global_or_module_member(vm, "lv.lv_obj"); be_pushcomptr(vm, (void*) -1); // stack = class, -1 be_pushcomptr(vm, (void*) obj); // stack = class, -1, ptr be_call(vm, 2); // instanciate, stack = instance (don't call init() ) @@ -413,7 +284,7 @@ extern "C" { if (argc == 1 && be_isstring(vm, 1)) { lv_font_t * font = lv_font_load(be_tostring(vm, 1)); if (font != nullptr) { - be_find_class(vm, "lv.lv_font"); + be_find_global_or_module_member(vm, "lv.lv_font"); be_pushcomptr(vm, font); be_call(vm, 1); be_pop(vm, 1); @@ -441,7 +312,7 @@ extern "C" { lv_font_t * font = info.font; if (font != nullptr) { - be_find_class(vm, "lv.lv_font"); + be_find_global_or_module_member(vm, "lv.lv_font"); be_pushcomptr(vm, font); be_call(vm, 1); be_pop(vm, 1); @@ -637,7 +508,7 @@ extern "C" { be_raisef(vm, "value_error", "unknown font size '%s-%i'", name, size); } - be_find_class(vm, "lv.lv_font"); + be_find_global_or_module_member(vm, "lv.lv_font"); be_pushcomptr(vm, (void*)font_entry->font); be_call(vm, 1); be_pop(vm, 1); @@ -674,10 +545,10 @@ extern "C" { * Responds to virtual constants \*********************************************************************************************/ - extern const lvbe_call_c_t lv_func[]; + extern const be_ntv_func_def_t lv_func[]; extern const size_t lv_func_size; - extern const be_constint_t lv0_constants[]; + extern const be_const_member_t lv0_constants[]; extern const size_t lv0_constants_size; extern const be_ctypes_class_by_name_t be_ctypes_lvgl_classes[]; @@ -686,7 +557,7 @@ extern "C" { int lv0_member(bvm *vm); int lv0_member(bvm *vm) { // first try the standard way - if (be_module_member(vm, lv0_constants, lv0_constants_size)) { + if (be_const_member(vm, lv0_constants, lv0_constants_size)) { be_return(vm); } // try alternative members @@ -698,9 +569,9 @@ extern "C" { // search for a class with this name char cl_prefixed[32]; snprintf(cl_prefixed, sizeof(cl_prefixed), "lv_%s", needle); // we try both actual name and prefixed with `lv_` so both `lv.obj` and `lv.lv_obj` work - idx = bin_search(cl_prefixed, &lv_classes[0].name, sizeof(lv_classes[0]), lv_classes_size); + idx = be_map_bin_search(cl_prefixed, &lv_classes[0].name, sizeof(lv_classes[0]), lv_classes_size); if (idx < 0) { - idx = bin_search(needle, &lv_classes[0].name, sizeof(lv_classes[0]), lv_classes_size); + idx = be_map_bin_search(needle, &lv_classes[0].name, sizeof(lv_classes[0]), lv_classes_size); } if (idx >= 0) { // we did have a match @@ -708,9 +579,9 @@ extern "C" { be_return(vm); } // same search for ctypes - idx = bin_search(cl_prefixed, &be_ctypes_lvgl_classes[0].name, sizeof(be_ctypes_lvgl_classes[0]), be_ctypes_lvgl_classes_size); + idx = be_map_bin_search(cl_prefixed, &be_ctypes_lvgl_classes[0].name, sizeof(be_ctypes_lvgl_classes[0]), be_ctypes_lvgl_classes_size); if (idx < 0) { - idx = bin_search(needle, &be_ctypes_lvgl_classes[0].name, sizeof(be_ctypes_lvgl_classes[0]), be_ctypes_lvgl_classes_size); + idx = be_map_bin_search(needle, &be_ctypes_lvgl_classes[0].name, sizeof(be_ctypes_lvgl_classes[0]), be_ctypes_lvgl_classes_size); } if (idx >= 0) { // we did have a match @@ -719,9 +590,9 @@ extern "C" { } // search for a method with this name - idx = bin_search(needle, &lv_func[0].name, sizeof(lv_func[0]), lv_func_size); + idx = be_map_bin_search(needle, &lv_func[0].name, sizeof(lv_func[0]), lv_func_size); if (idx >= 0) { - const lvbe_call_c_t * method = &lv_func[idx]; + const be_ntv_func_def_t * method = &lv_func[idx]; // push native closure be_pushntvclosure(vm, &lvx_call_c, 3); // 3 upvals @@ -803,7 +674,7 @@ extern "C" { lv_indev_t * indev = lv_indev_drv_register(&lvbe.indev_drv); lvbe.indev_list.addHead(indev); // keep track of indevs - be_find_class(vm, "lv.lv_indev"); + be_find_global_or_module_member(vm, "lv.lv_indev"); be_pushint(vm, (int32_t) indev); be_call(vm, 1); be_pop(vm, 1); @@ -859,7 +730,7 @@ extern "C" { void * obj = nullptr; int argc = be_top(vm); if (argc > 1) { - obj = (void*) be_convert_single_elt(vm, 2); + obj = (void*) be_convert_single_elt(vm, 2, NULL, NULL); } lv_init_set_member(vm, 1, obj); be_return_nil(vm); @@ -885,7 +756,7 @@ extern "C" { lv_style_t * style = nullptr; if (argc > 1) { - style = (lv_style_t*) be_convert_single_elt(vm, 2); + style = (lv_style_t*) be_convert_single_elt(vm, 2, NULL, NULL); } if (style == nullptr) { style = (lv_style_t*) be_malloc(vm, sizeof(lv_style_t)); diff --git a/tasmota/xdrv_52_3_berry_tasmota.ino b/tasmota/xdrv_52_3_berry_tasmota.ino index a9d0ad734..fdff25f1e 100644 --- a/tasmota/xdrv_52_3_berry_tasmota.ino +++ b/tasmota/xdrv_52_3_berry_tasmota.ino @@ -181,10 +181,10 @@ extern "C" { int32_t top = be_top(vm); // Get the number of arguments if (top == 1) { // no argument (instance only) be_newobject(vm, "map"); - map_insert_int(vm, "utc", Rtc.utc_time); - map_insert_int(vm, "local", Rtc.local_time); - map_insert_int(vm, "restart", Rtc.restart_time); - map_insert_int(vm, "timezone", Rtc.time_timezone); + be_map_insert_int(vm, "utc", Rtc.utc_time); + be_map_insert_int(vm, "local", Rtc.local_time); + be_map_insert_int(vm, "restart", Rtc.restart_time); + be_map_insert_int(vm, "timezone", Rtc.time_timezone); be_pop(vm, 1); be_return(vm); } @@ -198,14 +198,14 @@ extern "C" { int32_t top = be_top(vm); // Get the number of arguments if (top == 1) { // no argument (instance only) be_newobject(vm, "map"); - map_insert_int(vm, "flash", ESP.getFlashChipSize() / 1024); - map_insert_int(vm, "program", ESP_getSketchSize() / 1024); - map_insert_int(vm, "program_free", ESP.getFreeSketchSpace() / 1024); - map_insert_int(vm, "heap_free", ESP_getFreeHeap() / 1024); - map_insert_int(vm, "frag", ESP_getHeapFragmentation()); + be_map_insert_int(vm, "flash", ESP.getFlashChipSize() / 1024); + be_map_insert_int(vm, "program", ESP_getSketchSize() / 1024); + be_map_insert_int(vm, "program_free", ESP.getFreeSketchSpace() / 1024); + be_map_insert_int(vm, "heap_free", ESP_getFreeHeap() / 1024); + be_map_insert_int(vm, "frag", ESP_getHeapFragmentation()); if (UsePSRAM()) { - map_insert_int(vm, "psram", ESP.getPsramSize() / 1024); - map_insert_int(vm, "psram_free", ESP.getFreePsram() / 1024); + be_map_insert_int(vm, "psram", ESP.getPsramSize() / 1024); + be_map_insert_int(vm, "psram_free", ESP.getFreePsram() / 1024); } be_pop(vm, 1); be_return(vm); @@ -222,17 +222,17 @@ extern "C" { be_newobject(vm, "map"); if (Settings->flag4.network_wifi) { int32_t rssi = WiFi.RSSI(); - map_insert_int(vm, "rssi", rssi); - map_insert_int(vm, "quality", WifiGetRssiAsQuality(rssi)); + be_map_insert_int(vm, "rssi", rssi); + be_map_insert_int(vm, "quality", WifiGetRssiAsQuality(rssi)); #if LWIP_IPV6 String ipv6_addr = WifiGetIPv6(); if (ipv6_addr != "") { - map_insert_str(vm, "ip6", ipv6_addr.c_str()); + be_map_insert_str(vm, "ip6", ipv6_addr.c_str()); } #endif if (static_cast(WiFi.localIP()) != 0) { - map_insert_str(vm, "mac", WiFi.macAddress().c_str()); - map_insert_str(vm, "ip", WiFi.localIP().toString().c_str()); + be_map_insert_str(vm, "mac", WiFi.macAddress().c_str()); + be_map_insert_str(vm, "ip", WiFi.localIP().toString().c_str()); } } be_pop(vm, 1); @@ -250,8 +250,8 @@ extern "C" { be_newobject(vm, "map"); #ifdef USE_ETHERNET if (static_cast(EthernetLocalIP()) != 0) { - map_insert_str(vm, "mac", EthernetMacAddress().c_str()); - map_insert_str(vm, "ip", EthernetLocalIP().toString().c_str()); + be_map_insert_str(vm, "mac", EthernetMacAddress().c_str()); + be_map_insert_str(vm, "ip", EthernetLocalIP().toString().c_str()); } #endif be_pop(vm, 1); @@ -262,14 +262,14 @@ extern "C" { static void l_push_time(bvm *vm, struct tm *t, const char *unparsed) { be_newobject(vm, "map"); - map_insert_int(vm, "year", t->tm_year + 1900); - map_insert_int(vm, "month", t->tm_mon + 1); - map_insert_int(vm, "day", t->tm_mday); - map_insert_int(vm, "hour", t->tm_hour); - map_insert_int(vm, "min", t->tm_min); - map_insert_int(vm, "sec", t->tm_sec); - map_insert_int(vm, "weekday", t->tm_wday); - if (unparsed) map_insert_str(vm, "unparsed", unparsed); + be_map_insert_int(vm, "year", t->tm_year + 1900); + be_map_insert_int(vm, "month", t->tm_mon + 1); + be_map_insert_int(vm, "day", t->tm_mday); + be_map_insert_int(vm, "hour", t->tm_hour); + be_map_insert_int(vm, "min", t->tm_min); + be_map_insert_int(vm, "sec", t->tm_sec); + be_map_insert_int(vm, "weekday", t->tm_wday); + if (unparsed) be_map_insert_str(vm, "unparsed", unparsed); be_pop(vm, 1); } @@ -332,27 +332,14 @@ extern "C" { // ESP object int32_t l_yield(bvm *vm); int32_t l_yield(bvm *vm) { - BrTimeoutYield(); // reset timeout - be_return_nil(vm); + return be_call_c_func(vm, (void*) &BrTimeoutYield, NULL, "-"); } // Berry: tasmota.scale_uint(int * 5) -> int // int32_t l_scaleuint(struct bvm *vm); int32_t l_scaleuint(struct bvm *vm) { - int32_t top = be_top(vm); // Get the number of arguments - if (top == 6 && be_isint(vm, 2) && be_isint(vm, 3) && be_isint(vm, 4) && be_isint(vm, 5) && be_isint(vm, 6)) { // only 1 argument of type string accepted - int32_t v = be_toint(vm, 2); - int32_t from1 = be_toint(vm, 3); - int32_t from2 = be_toint(vm, 4); - int32_t to1 = be_toint(vm, 5); - int32_t to2 = be_toint(vm, 6); - - int32_t ret = changeUIntScale(v, from1, from2, to1, to2); - be_pushint(vm, ret); - be_return(vm); - } - be_raise(vm, kTypeError, nullptr); + return be_call_c_func(vm, (void*) &changeUIntScale, "i", "-iiiii"); } int32_t l_respCmnd(bvm *vm); @@ -379,20 +366,17 @@ extern "C" { int32_t l_respCmndDone(bvm *vm); int32_t l_respCmndDone(bvm *vm) { - ResponseCmndDone(); - be_return_nil(vm); + return be_call_c_func(vm, (void*) &ResponseCmndDone, NULL, "-"); } int32_t l_respCmndError(bvm *vm); int32_t l_respCmndError(bvm *vm) { - ResponseCmndError(); - be_return_nil(vm); + return be_call_c_func(vm, (void*) &ResponseCmndError, NULL, "-"); } int32_t l_respCmndFailed(bvm *vm); int32_t l_respCmndFailed(bvm *vm) { - ResponseCmndFailed(); - be_return_nil(vm); + return be_call_c_func(vm, (void*) &ResponseCmndFailed, NULL, "-"); } // update XdrvMailbox.command with actual command diff --git a/tasmota/xdrv_52_3_berry_webclient.ino b/tasmota/xdrv_52_3_berry_webclient.ino index 5c1700ebf..625c54622 100644 --- a/tasmota/xdrv_52_3_berry_webclient.ino +++ b/tasmota/xdrv_52_3_berry_webclient.ino @@ -57,7 +57,7 @@ String wc_UrlEncode(const String& text) { /*********************************************************************************************\ * Int constants *********************************************************************************************/ -// const be_constint_t webserver_constants[] = { +// const be_const_member_t webserver_constants[] = { // { "BUTTON_CONFIGURATION", BUTTON_CONFIGURATION }, // { "BUTTON_INFORMATION", BUTTON_INFORMATION }, // { "BUTTON_MAIN", BUTTON_MAIN }, diff --git a/tasmota/xdrv_52_3_berry_webserver.ino b/tasmota/xdrv_52_3_berry_webserver.ino index 2faa223ba..00f260d5a 100644 --- a/tasmota/xdrv_52_3_berry_webserver.ino +++ b/tasmota/xdrv_52_3_berry_webserver.ino @@ -27,7 +27,7 @@ /*********************************************************************************************\ * Int constants *********************************************************************************************/ -const be_constint_t webserver_constants[] = { +const be_const_member_t webserver_constants[] = { { "BUTTON_CONFIGURATION", BUTTON_CONFIGURATION }, { "BUTTON_INFORMATION", BUTTON_INFORMATION }, { "BUTTON_MAIN", BUTTON_MAIN }, @@ -51,7 +51,7 @@ extern "C" { if (argc == 1 && be_isstring(vm, 1)) { const char * needle = be_tostring(vm, 1); - int32_t constant_idx = bin_search(needle, &webserver_constants[0].name, sizeof(webserver_constants[0]), ARRAY_SIZE(webserver_constants)); + int32_t constant_idx = be_map_bin_search(needle, &webserver_constants[0].name, sizeof(webserver_constants[0]), ARRAY_SIZE(webserver_constants)); if (constant_idx >= 0) { // we did have a match, low == high diff --git a/tools/lv_berry/convert.py b/tools/lv_berry/convert.py index a814af381..86a4b86d4 100644 --- a/tools/lv_berry/convert.py +++ b/tools/lv_berry/convert.py @@ -320,13 +320,14 @@ extern "C" { #endif #include "be_ctypes.h" +#include "be_mapping.h" """) for subtype, flv in lv.items(): print(f"/* `lv_{subtype}` methods */") if subtype in lv_widgets: print(f"#ifdef BE_LV_WIDGET_{subtype.upper()}") - print(f"const lvbe_call_c_t lv_{subtype}_func[] = {{") + print(f"const be_ntv_func_def_t lv_{subtype}_func[] = {{") func_out = {} # used to sort output for f in flv: @@ -361,7 +362,7 @@ print() # print the global map of classes print(f""" // map of clases -const lvbe_call_c_classes_t lv_classes[] = {{""") +const be_ntv_class_def_t lv_classes[] = {{""") for subtype in sorted(lv): # for subtype, flv in lv.items(): @@ -391,7 +392,7 @@ for subtype, flv in lv.items(): if len(c_ret_type) > 1: c_ret_type = "lv." + c_ret_type if c_func_name.endswith("_create"): - c_ret_type = "+" # constructor, init method does not return any value + c_ret_type = "+_p" # constructor, init method does not return any value if subtype in lv_widgets: print(f"#ifdef BE_LV_WIDGET_{subtype.upper()}") print(f" int be_ntv_lv_{subtype}_init(bvm *vm) {{ return be_call_c_func(vm, (void*) &{orig_func_name}, \"{c_ret_type}\", { c_argc if c_argc else 'nullptr'}); }}") @@ -401,8 +402,8 @@ for subtype, flv in lv.items(): print(""" // create font either empty or from parameter on stack -int lvbe_font_create(bvm *vm) { return be_call_c_func(vm, NULL, "+lv_font", ""); } -int lvbe_theme_create(bvm *vm) { return be_call_c_func(vm, NULL, "+lv_theme", ""); } +int lvbe_font_create(bvm *vm) { return be_call_c_func(vm, NULL, "+_p", ""); } +int lvbe_theme_create(bvm *vm) { return be_call_c_func(vm, NULL, "+_p", ""); } """) print() @@ -660,7 +661,7 @@ print("""/******************************************************************** #ifdef USE_LVGL #include "lvgl.h" -#include "be_lvgl.h" +#include "be_mapping.h" #include "lv_theme_openhasp.h" extern int lv0_member(bvm *vm); // resolve virtual members @@ -685,7 +686,7 @@ static int lv_get_ver_res(void) { } /* `lv` methods */ -const lvbe_call_c_t lv_func[] = { +const be_ntv_func_def_t lv_func[] = { """) func_out = {} # used to sort output @@ -728,12 +729,7 @@ const size_t lv_func_size = sizeof(lv_func) / sizeof(lv_func[0]); print(""" -typedef struct be_constint_t { - const char * name; - int32_t value; -} be_constint_t; - -const be_constint_t lv0_constants[] = { +const be_const_member_t lv0_constants[] = { """) lv_module2 = {} diff --git a/tools/lv_gpio/gpio_convert.py b/tools/lv_gpio/gpio_convert.py index dfa3d78f0..6232fd287 100644 --- a/tools/lv_gpio/gpio_convert.py +++ b/tools/lv_gpio/gpio_convert.py @@ -56,7 +56,7 @@ print(" * Generated code, don't edit") print(" *******************************************************************/") print(""" -const be_constint_t lv_gpio_constants[] = { +const be_const_member_t lv_gpio_constants[] = { """) lv_module2 = {}