Tasmota/lib/libesp32_lvgl/lv_binding_berry/src/lv_berry.c
2022-03-21 19:10:07 +01:00

342 lines
12 KiB
C

#include "lv_berry.h"
#include "be_mapping.h"
#include "be_exec.h"
#include "be_vm.h"
#include "be_mem.h"
#include <stdio.h>
#include "../generate/be_lv_c_mapping.h"
/*********************************************************************************************\
* Retrieve the value of `self._p`
\*********************************************************************************************/
// Get the `_p` member of instance at `index`
void * lv_get_arg(bvm *vm, int index) {
void * ret = NULL;
if (be_isinstance(vm, index)) {
be_getmember(vm, index, "_p");
ret = be_tocomptr(vm, -1);
be_pop(vm, 1); // remove _p attribute
}
return ret;
}
/*********************************************************************************************\
* Support for lv_indev and objects that don't need creator
\*********************************************************************************************/
int lv0_init(bvm *vm);
int lv0_init(bvm *vm) {
// "+_p" indicates that there must be an non NULL argument, either passed as comptr or returned by the function
// Here, there is no function, so calling the constructor without a non-null comptr argument is rejected
return be_call_c_func(vm, NULL, "=_p", NULL);
}
/*********************************************************************************************\
* Generalized tostring method, shows class and _p value
\*********************************************************************************************/
int lv_x_tostring(bvm *vm) {
lv_obj_t * obj = (lv_obj_t*) lv_get_arg(vm, 1);
const char * classname = be_classname(vm, 1);
char s[48];
snprintf(s, sizeof(s), "<instance: %s(0x%08X)>", classname, obj);
be_pushnstring(vm, s, strlen(s)); /* make escape string from buffer */
be_return(vm);
}
/*********************************************************************************************\
* Support for lv_style `init()`
*
* Either encapsulate the pointer passed as `comptr` as arg1
* Or allocate a new empty style structure in memory. In this case, it is never freed.
\*********************************************************************************************/
int lv_be_style_init(bvm *vm) {
int argc = be_top(vm);
lv_style_t * style = NULL;
if (argc > 1) {
style = (lv_style_t*) be_convert_single_elt(vm, 2, NULL, NULL);
}
if (style == NULL) {
// if no valid pointer passed, allocate a new empty style
style = (lv_style_t*) be_malloc(vm, sizeof(lv_style_t));
if (style == NULL) {
be_throw(vm, BE_MALLOC_FAIL);
}
if (style != NULL) {
lv_style_init(style);
}
}
be_pushcomptr(vm, style);
be_setmember(vm, 1, "_p");
be_return_nil(vm);
}
/*********************************************************************************************\
* Support for lv_anim `init()`
*
* Either encapsulate the pointer passed as `comptr` as arg1
* Or allocate a new empty style structure in memory. In this case, it is never freed.
\*********************************************************************************************/
int lv_be_anim_init(bvm *vm) {
int argc = be_top(vm);
lv_anim_t * anim = NULL;
if (argc > 1) {
anim = (lv_anim_t*) be_convert_single_elt(vm, 2, NULL, NULL);
}
if (anim == NULL) {
// if no valid pointer passed, allocate a new empty style
anim = (lv_anim_t*) be_malloc(vm, sizeof(lv_anim_t));
if (anim == NULL) {
be_throw(vm, BE_MALLOC_FAIL);
}
if (anim != NULL) {
lv_anim_init(anim);
}
}
be_pushcomptr(vm, anim);
be_setmember(vm, 1, "_p");
be_return_nil(vm);
}
// native closure to call `be_call_c_func`
int lv_x_call_c(bvm *vm) {
// berry_log_C("lv_x_call_c enter");
// keep parameters unchanged
be_getupval(vm, 0, 0); // if index is zero, it's the current native closure
void * func = be_tocomptr(vm, -1);
be_getupval(vm, 0, 1); // if index is zero, it's the current native closure
const char * return_type = be_tostring(vm, -1);
be_getupval(vm, 0, 2); // if index is zero, it's the current native closure
const char * arg_type = be_tostring(vm, -1);
be_pop(vm, 3); // remove 3 upvals
// berry_log_C("lv_x_call_c %p '%s' <- (%s)", func, return_type, arg_type);
return be_call_c_func(vm, func, return_type, arg_type);
}
// virtual method, arg1: instance, arg2: name of method
int lv_x_member(bvm *vm) {
int32_t argc = be_top(vm); // Get the number of arguments
if (argc == 2 && be_isinstance(vm, 1) && be_isstring(vm, 2)) {
const char * method_name = be_tostring(vm, 2); // the method we are looking for
while (be_isinstance(vm, 1)) {
const char * class_name = be_classname(vm, 1);
// berry_log_C("lv_x_member looking for method '%s' of class '%s'", method_name, class_name);
// look for class descriptor
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 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 = be_map_bin_search(method_name, methods_calls, sizeof(be_ntv_func_def_t), methods_size);
if (method_idx >= 0) {
// method found
const be_ntv_func_def_t * method = &methods_calls[method_idx];
// berry_log_C("lv_x_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, &lv_x_call_c, 3); // 3 upvals
be_pushcomptr(vm, method->args.func);
be_setupval(vm, -2, 0);
be_pop(vm, 1);
be_pushstring(vm, method->args.return_type);
be_setupval(vm, -2, 1);
be_pop(vm, 1);
be_pushstring(vm, method->args.arg_type);
be_setupval(vm, -2, 2);
be_pop(vm, 1);
// all good
be_return(vm);
}
}
// get super if any, or nil if none
be_getsuper(vm, 1);
be_moveto(vm, -1, 1);
be_pop(vm, 1);
}
// berry_log_C("lv_x_member method not found");
be_return_nil(vm);
}
be_raise(vm, "type_error", NULL);
}
// lv_color - constructor
//
// Supports either new initialization taking 24 bits RGB
// or an existing color using native enconding
//
// Arg1 - the instance of the new lv_color object created
// Arg2 - 1/ if `int` then color is 24 bits 0xRRGGBB
// 2/ if `comptr` then color is native format (probably 16 bits)
// 3/ if no Arg2, color is 0x000000 (black)
int lco_init(bvm *vm) {
int argc = be_top(vm);
lv_color_t lv_color = {}; // default value is all zeroes (black)
uint32_t color32 = 0x000000; // default to black
if (argc > 1) {
if (be_isint(vm, 2)) { // color is RGB 24 bits
lv_color = lv_color_hex(be_toint(vm, 2));
} else if (be_iscomptr(vm, 2)) {
lv_color.full = (intptr_t) be_tocomptr(vm, 2);
}
}
be_pushint(vm, lv_color_to_uint32(lv_color));
be_setmember(vm, 1, "_p");
be_return_nil(vm);
}
int lco_tostring(bvm *vm) {
lv_color_t lv_color = {};
be_getmember(vm, 1, "_p");
uint32_t ntv_color = be_toint(vm, -1);
lv_color = lv_color_from_uint32(ntv_color);
uint32_t color = lv_color_to32(lv_color) & 0xFFFFFF;
be_pop(vm, 1); // remove attribute
char s[48];
snprintf(s, sizeof(s), "lv_color(0x%06x - native:0x%04x)", color, ntv_color);
be_pushnstring(vm, s, strlen(s)); /* make escape string from buffer */
be_return(vm);
}
int lco_toint(bvm *vm) {
lv_color_t lv_color = {};
be_getmember(vm, 1, "_p");
uint32_t ntv_color = be_toint(vm, -1);
be_pushint(vm, ntv_color);
be_return(vm);
}
// function is (void) -> lv_obt_t*
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_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() )
be_pop(vm, 2); // stack = instance
be_return(vm);
}
/*********************************************************************************************\
* Support for lv_fonts
\*********************************************************************************************/
// load font by name on file-system
int lv0_load_font(bvm *vm) {
int argc = be_top(vm);
if (argc == 1 && be_isstring(vm, 1)) {
lv_font_t * font = lv_font_load(be_tostring(vm, 1));
if (font != NULL) {
be_find_global_or_module_member(vm, "lv.lv_font");
be_pushcomptr(vm, font);
be_call(vm, 1);
be_pop(vm, 1);
be_return(vm);
} else {
be_return_nil(vm);
}
}
be_raise(vm, "type_error", NULL);
}
/*********************************************************************************************\
* Get Touch Screen calibration information
\*********************************************************************************************/
lv_ts_calibration_t lv_ts_calibration = {
0, 0,
0, 0,
LV_INDEV_STATE_RELEASED
};
lv_ts_calibration_t * lv_get_ts_calibration(void) {
return &lv_ts_calibration;
}
/*********************************************************************************************\
* LVGL top level virtual members
*
* Responds to virtual constants
\*********************************************************************************************/
extern const be_ntv_func_def_t lv_func[];
extern const size_t lv_func_size;
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[];
extern const size_t be_ctypes_lvgl_classes_size;
int lv0_member(bvm *vm);
int lv0_member(bvm *vm) {
// first try the standard way
if (be_const_module_member(vm, lv0_constants, lv0_constants_size)) {
be_return(vm);
}
// try alternative members
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;
// 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 = be_map_bin_search(cl_prefixed, &lv_classes[0].name, sizeof(lv_classes[0]), lv_classes_size);
if (idx < 0) {
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
be_pushntvclass(vm, lv_classes[idx].cl);
be_return(vm);
}
// same search for ctypes
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 = 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
be_pushntvclass(vm, be_ctypes_lvgl_classes[idx].cl);
be_return(vm);
}
// search for a method with this name
idx = be_map_bin_search(needle, &lv_func[0].name, sizeof(lv_func[0]), lv_func_size);
if (idx >= 0) {
const be_ntv_func_def_t * method = &lv_func[idx];
// push native closure
be_pushntvclosure(vm, &lv_x_call_c, 3); // 3 upvals
be_pushcomptr(vm, method->args.func);
be_setupval(vm, -2, 0);
be_pop(vm, 1);
be_pushstring(vm, method->args.return_type);
be_setupval(vm, -2, 1);
be_pop(vm, 1);
be_pushstring(vm, method->args.arg_type);
be_setupval(vm, -2, 2);
be_pop(vm, 1);
// all good
be_return(vm);
}
}
be_return_nil(vm);
}