Berry C mapping moved to a separate ``berry_mapping`` library

This commit is contained in:
Stephan Hadinger 2021-12-17 19:41:36 +01:00
parent 394ae49613
commit 26a7fad65b
22 changed files with 843 additions and 738 deletions

View File

@ -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

View File

@ -6,7 +6,7 @@
#ifdef USE_LVGL
#include "lvgl.h"
#include "be_lvgl.h"
#include "be_mapping.h"
/********************************************************************
* Generated code, don't edit

View File

@ -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

View File

@ -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 },

View File

@ -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 == "<other_cb>"
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

View File

@ -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__

View File

@ -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 <string.h>
/*********************************************************************************************\
* 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 : "<null>");
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);
}
}

View File

@ -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 <string.h>
/*********************************************************************************************\
* 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;
}

View File

@ -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__

View File

@ -0,0 +1,97 @@
#include "be_mapping.h"
#include <string.h>
#include <math.h>
/*********************************************************************************************\
* 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;
}
}

View File

@ -0,0 +1,22 @@
/*********************************************************************************************\
* Extended version of be_raise()
\*********************************************************************************************/
#include "be_mapping.h"
#include "be_exec.h"
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
// 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);
}

View File

@ -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 },

View File

@ -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

View File

@ -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) {

View File

@ -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);

View File

@ -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);
}
}

View File

@ -23,7 +23,7 @@
#include <berry.h>
#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 : "<null>");
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));

View File

@ -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<uint32_t>(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<uint32_t>(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

View File

@ -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 },

View File

@ -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

View File

@ -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 = {}

View File

@ -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 = {}