mirror of https://github.com/arendst/Tasmota.git
Berry revamped ``energy`` module to expose all C variables to Berry (read/write)
This commit is contained in:
parent
7c71c3bdd8
commit
509daa24dc
|
@ -22,6 +22,7 @@ All notable changes to this project will be documented in this file.
|
|||
- Minimum PWM Frequency lowered to 2Hz on ESP32 (#13123)
|
||||
- Use Tasmota Arduino Core32 1.0.7.4 for ESP32 builds (#13154)
|
||||
- Shrinked Webcam build, uses now `USE_TASMOTA_DISCOVERY` (#13148)
|
||||
- Berry revamped ``energy`` module to expose all C variables to Berry (read/write)
|
||||
|
||||
### Fixed
|
||||
- OpenTherm invalid JSON (#13028)
|
||||
|
|
|
@ -51,6 +51,10 @@ enum {
|
|||
ctypes_be_u16 = -2,
|
||||
ctypes_be_u8 = -1,
|
||||
|
||||
// floating point
|
||||
ctypes_float = 5,
|
||||
ctypes_double = 10,
|
||||
|
||||
ctypes_bf = 0, //bif-field
|
||||
};
|
||||
|
||||
|
@ -88,13 +92,23 @@ typedef struct be_ctypes_classes_t {
|
|||
//
|
||||
// If no arg: allocate a bytes() structure of the right size, filled with zeroes
|
||||
// Arg1 is instance self
|
||||
// If arg 2 is int (and not null): copy the data to the bytes structure
|
||||
// If arg 2 is int or comptr (and not null): create a mapped bytes buffer to read/write at a specific location (can be copied if need a snapshot)
|
||||
int be_ctypes_init(bvm *vm) {
|
||||
int argc = be_top(vm);
|
||||
void * src_data = NULL;
|
||||
if (argc > 1 && (be_isint(vm, 2) || be_iscomptr(vm,2))) {
|
||||
if (argc > 1 && (be_isint(vm, 2) || be_iscomptr(vm, 2))) {
|
||||
if (be_iscomptr(vm, 2)) {
|
||||
src_data = be_tocomptr(vm, 2);
|
||||
} else {
|
||||
src_data = (void*) be_toint(vm, 2);
|
||||
}
|
||||
}
|
||||
|
||||
// look for class definition
|
||||
be_getmember(vm, 1, "_def"); // static class comptr
|
||||
const be_ctypes_structure_t *definitions;
|
||||
definitions = (const be_ctypes_structure_t *) be_tocomptr(vm, -1);
|
||||
be_pop(vm, 1);
|
||||
|
||||
// call super(self, bytes)
|
||||
be_getglobal(vm, "super"); // push super function
|
||||
|
@ -107,34 +121,13 @@ int be_ctypes_init(bvm *vm) {
|
|||
// call bytes.init(self)
|
||||
be_getmember(vm, -1, "init");
|
||||
be_pushvalue(vm, -2);
|
||||
be_call(vm, 1);
|
||||
be_pop(vm, 3);
|
||||
// berry_log_C("be_ctypes_init> init called");
|
||||
if (src_data) { be_pushcomptr(vm, src_data); } // if mapped, push address
|
||||
be_pushint(vm, definitions ? -definitions->size_bytes : 0); // negative size signals a fixed size
|
||||
be_call(vm, src_data ? 3 : 2); // call with 2 or 3 arguments depending on provided address
|
||||
be_pop(vm, src_data ? 4 : 3);
|
||||
// super(self, bytes) still on top of stack
|
||||
|
||||
// look for class definition
|
||||
be_getmember(vm, 1, "_def"); // static class comptr
|
||||
const be_ctypes_structure_t *definitions;
|
||||
definitions = (const be_ctypes_structure_t *) be_tocomptr(vm, -1);
|
||||
if (definitions) {
|
||||
// call self.resize(definitions->size_bytes)
|
||||
be_getmember(vm, 1, "resize");
|
||||
be_pushvalue(vm, 1);
|
||||
be_pushint(vm, definitions->size_bytes);
|
||||
be_call(vm, 2);
|
||||
be_pop(vm, 3);
|
||||
|
||||
// if src_data then copy source data to the new structure
|
||||
if (src_data) {
|
||||
// call self._buffer()
|
||||
be_getmember(vm, 1, "_buffer");
|
||||
be_pushvalue(vm, 1);
|
||||
be_call(vm, 1); // call with 1 parameter
|
||||
void * dst_data = be_tocomptr(vm, -2);
|
||||
be_pop(vm, 2);
|
||||
// copy data
|
||||
memmove(dst_data, src_data, definitions->size_bytes);
|
||||
}
|
||||
}
|
||||
be_pop(vm, 1);
|
||||
|
||||
be_return(vm);
|
||||
}
|
||||
|
@ -146,9 +139,35 @@ int be_ctypes_copy(bvm *vm) {
|
|||
size_t len;
|
||||
const void * src = be_tobytes(vm, 1, &len);
|
||||
be_classof(vm, 1);
|
||||
be_pushint(vm, (int32_t) src); // skip first 4 bytes
|
||||
be_call(vm, 1);
|
||||
// stack: 1/self + class_object
|
||||
be_call(vm, 0); // call empty constructor to build empty resizable copy
|
||||
// stack: 1/ self + new_empty_instance
|
||||
|
||||
// source object (self)
|
||||
be_getmember(vm, 1, ".p");
|
||||
const void* src_buf = be_tocomptr(vm, -1);
|
||||
be_pop(vm, 1);
|
||||
|
||||
be_getmember(vm, 1, ".len");
|
||||
int32_t src_len = be_toint(vm, -1);
|
||||
be_pop(vm, 1);
|
||||
|
||||
// dest object
|
||||
be_getmember(vm, -1, ".p");
|
||||
const void* dst_buf = be_tocomptr(vm, -1);
|
||||
be_pop(vm, 1);
|
||||
|
||||
be_getmember(vm, -1, ".len");
|
||||
int32_t dst_len = be_toint(vm, -1);
|
||||
be_pop(vm, 1);
|
||||
|
||||
if (src_len != dst_len) {
|
||||
be_raisef(vm, "internal_error", "new object has wrong size %i (should be %i)", dst_len, src_len);
|
||||
}
|
||||
|
||||
// copy bytes
|
||||
memmove((void*)dst_buf, src_buf, src_len);
|
||||
|
||||
be_return(vm);
|
||||
}
|
||||
|
||||
|
@ -180,6 +199,20 @@ int be_ctypes_member(bvm *vm) {
|
|||
be_call(vm, 3);
|
||||
be_pop(vm, 3);
|
||||
// int result at top of stack
|
||||
} else if (ctypes_float == member->type) {
|
||||
// Note: double not supported (no need identified)
|
||||
// get raw int32_t
|
||||
be_getmember(vm, 1, "geti"); // self.get or self.geti
|
||||
be_pushvalue(vm, 1); // push self
|
||||
be_pushint(vm, member->offset_bytes);
|
||||
be_pushint(vm, 4); // size is 4 bytes
|
||||
be_call(vm, 3);
|
||||
be_pop(vm, 3);
|
||||
// get int and convert to float
|
||||
int32_t val = be_toint(vm, -1);
|
||||
be_pop(vm, 1);
|
||||
float *fval = (float*) &val; // type wizardry
|
||||
be_pushreal(vm, *fval);
|
||||
} else {
|
||||
// general int support
|
||||
int size = member->type; // eventually 1/2/4, positive if little endian, negative if big endian
|
||||
|
@ -272,6 +305,19 @@ int be_ctypes_setmember(bvm *vm) {
|
|||
be_call(vm, 4);
|
||||
be_pop(vm, 5);
|
||||
be_return_nil(vm);
|
||||
} else if (ctypes_float == member->type) {
|
||||
// Note: double not supported (no need identified)
|
||||
float val = be_toreal(vm, 3);
|
||||
int32_t *ival = (int32_t*) &val;
|
||||
// set
|
||||
be_getmember(vm, 1, "seti");
|
||||
be_pushvalue(vm, 1); // push self
|
||||
be_pushint(vm, member->offset_bytes);
|
||||
be_pushint(vm, *ival);
|
||||
be_pushint(vm, 4); // size is 4 bytes
|
||||
be_call(vm, 4);
|
||||
be_pop(vm, 5);
|
||||
be_return_nil(vm);
|
||||
} else {
|
||||
// general int support
|
||||
int size = member->type; // eventually 1/2/4, positive if little endian, negative if big endian
|
||||
|
@ -300,6 +346,38 @@ int be_ctypes_setmember(bvm *vm) {
|
|||
}
|
||||
}
|
||||
|
||||
//
|
||||
// tomap, create a map instance containing all values decoded
|
||||
//
|
||||
int be_ctypes_tomap(bvm *vm) {
|
||||
// don't need argc
|
||||
be_getmember(vm, 1, "_def");
|
||||
const be_ctypes_structure_t *definitions;
|
||||
definitions = (const be_ctypes_structure_t *) be_tocomptr(vm, -1);
|
||||
be_pop(vm, 1);
|
||||
|
||||
// create empty map
|
||||
be_newobject(vm, "map");
|
||||
|
||||
for (uint32_t i = 0; i < definitions->size_elt; i++) {
|
||||
const be_ctypes_structure_item_t * item = &definitions->items[i];
|
||||
|
||||
be_pushstring(vm, item->name); // stack: map - key
|
||||
|
||||
be_getmember(vm, 1, "member");
|
||||
be_pushvalue(vm, 1);
|
||||
be_pushstring(vm, item->name);
|
||||
be_call(vm, 2);
|
||||
be_pop(vm, 2); // stack: map - key - value
|
||||
|
||||
be_data_insert(vm, -3);
|
||||
be_pop(vm, 2); // stack: map
|
||||
}
|
||||
|
||||
be_pop(vm, 1); // remove map struct, to leave map instance
|
||||
be_return(vm);
|
||||
}
|
||||
|
||||
BE_EXPORT_VARIABLE extern const bclass be_class_bytes;
|
||||
|
||||
#include "../generate/be_fixed_be_class_ctypes.h"
|
||||
|
@ -317,5 +395,7 @@ class be_class_ctypes (scope: global, name: ctypes_bytes, super: be_class_bytes)
|
|||
init, func(be_ctypes_init)
|
||||
member, func(be_ctypes_member)
|
||||
setmember, func(be_ctypes_setmember)
|
||||
|
||||
tomap, func(be_ctypes_tomap)
|
||||
}
|
||||
@const_object_info_end */
|
||||
|
|
|
@ -0,0 +1,162 @@
|
|||
/********************************************************************
|
||||
* Tasmota LVGL ctypes mapping
|
||||
*******************************************************************/
|
||||
#include "be_constobj.h"
|
||||
|
||||
#ifdef USE_ENERGY_SENSOR
|
||||
|
||||
/********************************************************************
|
||||
* Generated code, don't edit
|
||||
*******************************************************************/
|
||||
|
||||
enum {
|
||||
ctypes_i32 = 14,
|
||||
ctypes_i16 = 12,
|
||||
ctypes_i8 = 11,
|
||||
ctypes_u32 = 4,
|
||||
ctypes_u16 = 2,
|
||||
ctypes_u8 = 1,
|
||||
|
||||
// big endian
|
||||
ctypes_be_i32 = -14,
|
||||
ctypes_be_i16 = -12,
|
||||
ctypes_be_i8 = -11,
|
||||
ctypes_be_u32 = -4,
|
||||
ctypes_be_u16 = -2,
|
||||
ctypes_be_u8 = -1,
|
||||
|
||||
ctypes_bf = 0, //bif-field
|
||||
};
|
||||
|
||||
typedef struct be_ctypes_structure_item_t {
|
||||
const char * name;
|
||||
uint16_t offset_bytes;
|
||||
uint8_t offset_bits : 3;
|
||||
uint8_t len_bits : 5;
|
||||
int8_t type : 5;
|
||||
uint8_t mapping : 3;
|
||||
} be_ctypes_structure_item_t;
|
||||
|
||||
typedef struct be_ctypes_structure_t {
|
||||
uint16_t size_bytes; /* size in bytes */
|
||||
uint16_t size_elt; /* number of elements */
|
||||
const char **instance_mapping; /* array of instance class names for automatic instanciation of class */
|
||||
const be_ctypes_structure_item_t * items;
|
||||
} be_ctypes_structure_t;
|
||||
|
||||
typedef struct be_ctypes_class_t {
|
||||
const char * name;
|
||||
const be_ctypes_structure_t * definitions;
|
||||
} be_ctypes_class_t;
|
||||
|
||||
typedef struct be_ctypes_classes_t {
|
||||
uint16_t size;
|
||||
const char **instance_mapping; /* array of instance class names for automatic instanciation of class */
|
||||
const be_ctypes_class_t * classes;
|
||||
} be_ctypes_classes_t;
|
||||
|
||||
BE_EXPORT_VARIABLE extern const bclass be_class_ctypes;
|
||||
|
||||
static void ctypes_register_class(bvm *vm, const bclass * ctypes_class, const be_ctypes_structure_t * definitions) {
|
||||
be_pushntvclass(vm, ctypes_class);
|
||||
be_setglobal(vm, str(ctypes_class->name));
|
||||
be_pop(vm, 1);
|
||||
}
|
||||
|
||||
static const char * be_ctypes_instance_mappings[]; /* forward definition */
|
||||
|
||||
// Define a sub-class of ctypes with only one member which points to the ctypes defintion
|
||||
#define be_define_ctypes_class(_c_name, _def, _super, _name) \
|
||||
be_local_class(_c_name, \
|
||||
0, \
|
||||
_super, \
|
||||
be_nested_map(1, \
|
||||
( (struct bmapnode*) &(const bmapnode[]) { \
|
||||
{ be_nested_key("_def", 1985022181, 4, -1), be_const_comptr(_def) },\
|
||||
})), \
|
||||
(be_nested_const_str(_name, 0, sizeof(_name)-1)) \
|
||||
)
|
||||
|
||||
/********************************************************************/
|
||||
|
||||
const be_ctypes_structure_t be_energy_struct = {
|
||||
146, /* size in bytes */
|
||||
62, /* number of elements */
|
||||
be_ctypes_instance_mappings,
|
||||
(const be_ctypes_structure_item_t[62]) {
|
||||
{ "active_power", 24, 0, 0, 5, 0 },
|
||||
{ "active_power_2", 28, 0, 0, 5, 0 },
|
||||
{ "active_power_3", 32, 0, 0, 5, 0 },
|
||||
{ "command_code", 113, 0, 0, 1, 0 },
|
||||
{ "current", 12, 0, 0, 5, 0 },
|
||||
{ "current_2", 16, 0, 0, 5, 0 },
|
||||
{ "current_3", 20, 0, 0, 5, 0 },
|
||||
{ "current_available", 118, 5, 1, 0, 0 },
|
||||
{ "daily", 88, 0, 0, 5, 0 },
|
||||
{ "data_valid", 114, 0, 0, 1, 0 },
|
||||
{ "data_valid_2", 115, 0, 0, 1, 0 },
|
||||
{ "data_valid_3", 116, 0, 0, 1, 0 },
|
||||
{ "export_active", 72, 0, 0, 5, 0 },
|
||||
{ "export_active_2", 76, 0, 0, 5, 0 },
|
||||
{ "export_active_3", 80, 0, 0, 5, 0 },
|
||||
{ "fifth_second", 112, 0, 0, 1, 0 },
|
||||
{ "frequency", 60, 0, 0, 5, 0 },
|
||||
{ "frequency_2", 64, 0, 0, 5, 0 },
|
||||
{ "frequency_3", 68, 0, 0, 5, 0 },
|
||||
{ "frequency_common", 118, 1, 1, 0, 0 },
|
||||
{ "max_current_flag", 138, 5, 1, 0, 0 },
|
||||
{ "max_energy_state", 145, 0, 0, 1, 0 },
|
||||
{ "max_power_flag", 138, 1, 1, 0, 0 },
|
||||
{ "max_voltage_flag", 138, 3, 1, 0, 0 },
|
||||
{ "min_current_flag", 138, 4, 1, 0, 0 },
|
||||
{ "min_power_flag", 138, 0, 1, 0, 0 },
|
||||
{ "min_voltage_flag", 138, 2, 1, 0, 0 },
|
||||
{ "mplh_counter", 140, 0, 0, 2, 0 },
|
||||
{ "mplr_counter", 144, 0, 0, 1, 0 },
|
||||
{ "mplw_counter", 142, 0, 0, 2, 0 },
|
||||
{ "period", 108, 0, 0, 4, 0 },
|
||||
{ "phase_count", 117, 0, 0, 1, 0 },
|
||||
{ "power_factor", 48, 0, 0, 5, 0 },
|
||||
{ "power_factor_2", 52, 0, 0, 5, 0 },
|
||||
{ "power_factor_3", 56, 0, 0, 5, 0 },
|
||||
{ "power_history_0", 119, 0, 0, 2, 0 },
|
||||
{ "power_history_0_2", 121, 0, 0, 2, 0 },
|
||||
{ "power_history_0_3", 123, 0, 0, 2, 0 },
|
||||
{ "power_history_1", 125, 0, 0, 2, 0 },
|
||||
{ "power_history_1_2", 127, 0, 0, 2, 0 },
|
||||
{ "power_history_1_3", 129, 0, 0, 2, 0 },
|
||||
{ "power_history_2", 131, 0, 0, 2, 0 },
|
||||
{ "power_history_2_2", 133, 0, 0, 2, 0 },
|
||||
{ "power_history_2_3", 135, 0, 0, 2, 0 },
|
||||
{ "power_on", 118, 7, 1, 0, 0 },
|
||||
{ "power_steady_counter", 137, 0, 0, 1, 0 },
|
||||
{ "reactive_power", 36, 0, 0, 5, 0 },
|
||||
{ "reactive_power_2", 40, 0, 0, 5, 0 },
|
||||
{ "reactive_power_3", 44, 0, 0, 5, 0 },
|
||||
{ "start_energy", 84, 0, 0, 5, 0 },
|
||||
{ "today_delta_kwh", 96, 0, 0, 4, 0 },
|
||||
{ "today_kwh", 104, 0, 0, 4, 0 },
|
||||
{ "today_offset_init_kwh", 118, 3, 1, 0, 0 },
|
||||
{ "today_offset_kwh", 100, 0, 0, 4, 0 },
|
||||
{ "total", 92, 0, 0, 5, 0 },
|
||||
{ "type_dc", 118, 6, 1, 0, 0 },
|
||||
{ "use_overtemp", 118, 2, 1, 0, 0 },
|
||||
{ "voltage", 0, 0, 0, 5, 0 },
|
||||
{ "voltage_2", 4, 0, 0, 5, 0 },
|
||||
{ "voltage_3", 8, 0, 0, 5, 0 },
|
||||
{ "voltage_available", 118, 4, 1, 0, 0 },
|
||||
{ "voltage_common", 118, 0, 1, 0, 0 },
|
||||
}};
|
||||
|
||||
static const char * be_ctypes_instance_mappings[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static be_define_ctypes_class(energy_struct, &be_energy_struct, &be_class_ctypes, "energy_struct");
|
||||
|
||||
void be_load_ctypes_energy_definitions_lib(bvm *vm) {
|
||||
ctypes_register_class(vm, &be_class_energy_struct, &be_energy_struct);
|
||||
}
|
||||
/********************************************************************/
|
||||
|
||||
#endif // USE_ENERGY_SENSOR
|
|
@ -9,11 +9,157 @@
|
|||
|
||||
#ifdef USE_ENERGY_SENSOR
|
||||
|
||||
extern int b_nrg_read(bvm *vm);
|
||||
extern struct ENERGY Energy;
|
||||
/*
|
||||
|
||||
def init(m)
|
||||
import global
|
||||
global._energy = energy_struct(m._ptr)
|
||||
end
|
||||
|
||||
def read()
|
||||
return _energy.tomap()
|
||||
end
|
||||
|
||||
def member(k)
|
||||
return _energy.(k)
|
||||
end
|
||||
|
||||
def setmember(k, v)
|
||||
_energy.(k) = v
|
||||
end
|
||||
|
||||
import solidify
|
||||
solidify.dump(m.init)
|
||||
*/
|
||||
|
||||
/********************************************************************
|
||||
** Solidified function: init
|
||||
********************************************************************/
|
||||
be_local_closure(init, /* name */
|
||||
be_nested_proto(
|
||||
4, /* nstack */
|
||||
1, /* argc */
|
||||
0, /* varg */
|
||||
0, /* has upvals */
|
||||
NULL, /* no upvals */
|
||||
0, /* has sup protos */
|
||||
NULL, /* no sub protos */
|
||||
1, /* has constants */
|
||||
( &(const bvalue[ 4]) { /* constants */
|
||||
/* K0 */ be_nested_string("global", 503252654, 6),
|
||||
/* K1 */ be_nested_string("_energy", 535372070, 7),
|
||||
/* K2 */ be_nested_string("energy_struct", 1655792843, 13),
|
||||
/* K3 */ be_nested_string("_ptr", 306235816, 4),
|
||||
}),
|
||||
(be_nested_const_str("<anonymous>", 1160973142, 11)),
|
||||
(be_nested_const_str("input", -103256197, 5)),
|
||||
( &(const binstruction[ 6]) { /* code */
|
||||
0xA4060000, // 0000 IMPORT R1 K0
|
||||
0xB80A0400, // 0001 GETNGBL R2 K2
|
||||
0x880C0103, // 0002 GETMBR R3 R0 K3
|
||||
0x7C080200, // 0003 CALL R2 1
|
||||
0x90060202, // 0004 SETMBR R1 K1 R2
|
||||
0x80000000, // 0005 RET 0
|
||||
})
|
||||
)
|
||||
);
|
||||
/*******************************************************************/
|
||||
|
||||
|
||||
/********************************************************************
|
||||
** Solidified function: read
|
||||
********************************************************************/
|
||||
be_local_closure(read, /* name */
|
||||
be_nested_proto(
|
||||
2, /* nstack */
|
||||
0, /* argc */
|
||||
0, /* varg */
|
||||
0, /* has upvals */
|
||||
NULL, /* no upvals */
|
||||
0, /* has sup protos */
|
||||
NULL, /* no sub protos */
|
||||
1, /* has constants */
|
||||
( &(const bvalue[ 2]) { /* constants */
|
||||
/* K0 */ be_nested_string("_energy", 535372070, 7),
|
||||
/* K1 */ be_nested_string("tomap", 612167626, 5),
|
||||
}),
|
||||
(be_nested_const_str("<anonymous>", 1160973142, 11)),
|
||||
(be_nested_const_str("input", -103256197, 5)),
|
||||
( &(const binstruction[ 4]) { /* code */
|
||||
0xB8020000, // 0000 GETNGBL R0 K0
|
||||
0x8C000101, // 0001 GETMET R0 R0 K1
|
||||
0x7C000200, // 0002 CALL R0 1
|
||||
0x80040000, // 0003 RET 1 R0
|
||||
})
|
||||
)
|
||||
);
|
||||
/*******************************************************************/
|
||||
|
||||
/********************************************************************
|
||||
** Solidified function: member
|
||||
********************************************************************/
|
||||
be_local_closure(member, /* name */
|
||||
be_nested_proto(
|
||||
2, /* nstack */
|
||||
1, /* argc */
|
||||
0, /* varg */
|
||||
0, /* has upvals */
|
||||
NULL, /* no upvals */
|
||||
0, /* has sup protos */
|
||||
NULL, /* no sub protos */
|
||||
1, /* has constants */
|
||||
( &(const bvalue[ 1]) { /* constants */
|
||||
/* K0 */ be_nested_string("_energy", 535372070, 7),
|
||||
}),
|
||||
(be_nested_const_str("member", 719708611, 6)),
|
||||
(be_nested_const_str("input", -103256197, 5)),
|
||||
( &(const binstruction[ 3]) { /* code */
|
||||
0xB8060000, // 0000 GETNGBL R1 K0
|
||||
0x88040200, // 0001 GETMBR R1 R1 R0
|
||||
0x80040200, // 0002 RET 1 R1
|
||||
})
|
||||
)
|
||||
);
|
||||
/*******************************************************************/
|
||||
|
||||
|
||||
/********************************************************************
|
||||
** Solidified function: setmember
|
||||
********************************************************************/
|
||||
be_local_closure(setmember, /* name */
|
||||
be_nested_proto(
|
||||
3, /* nstack */
|
||||
2, /* argc */
|
||||
0, /* varg */
|
||||
0, /* has upvals */
|
||||
NULL, /* no upvals */
|
||||
0, /* has sup protos */
|
||||
NULL, /* no sub protos */
|
||||
1, /* has constants */
|
||||
( &(const bvalue[ 1]) { /* constants */
|
||||
/* K0 */ be_nested_string("_energy", 535372070, 7),
|
||||
}),
|
||||
(be_nested_const_str("setmember", 1432909441, 9)),
|
||||
(be_nested_const_str("input", -103256197, 5)),
|
||||
( &(const binstruction[ 3]) { /* code */
|
||||
0xB80A0000, // 0000 GETNGBL R2 K0
|
||||
0x90080001, // 0001 SETMBR R2 R0 R1
|
||||
0x80000000, // 0002 RET 0
|
||||
})
|
||||
)
|
||||
);
|
||||
/*******************************************************************/
|
||||
|
||||
|
||||
/* @const_object_info_begin
|
||||
module energy (scope: global) {
|
||||
read, func(b_nrg_read)
|
||||
_ptr, comptr(&Energy)
|
||||
init, closure(init_closure)
|
||||
|
||||
read, closure(read_closure)
|
||||
member, closure(member_closure)
|
||||
setmember, closure(setmember_closure)
|
||||
}
|
||||
@const_object_info_end */
|
||||
#include "../generate/be_fixed_energy.h"
|
||||
|
|
|
@ -59,13 +59,13 @@ typedef struct be_ctypes_classes_t {
|
|||
|
||||
BE_EXPORT_VARIABLE extern const bclass be_class_ctypes;
|
||||
|
||||
void ctypes_register_class(bvm *vm, const bclass * ctypes_class, const be_ctypes_structure_t * definitions) {
|
||||
static void ctypes_register_class(bvm *vm, const bclass * ctypes_class, const be_ctypes_structure_t * definitions) {
|
||||
be_pushntvclass(vm, ctypes_class);
|
||||
be_setglobal(vm, str(ctypes_class->name));
|
||||
be_pop(vm, 1);
|
||||
}
|
||||
|
||||
const char * be_ctypes_instance_mappings[]; /* forward definition */
|
||||
static const char * be_ctypes_instance_mappings[]; /* forward definition */
|
||||
|
||||
// Define a sub-class of ctypes with only one member which points to the ctypes defintion
|
||||
#define be_define_ctypes_class(_c_name, _def, _super, _name) \
|
||||
|
@ -410,7 +410,7 @@ const be_ctypes_structure_t be_lv_draw_mask_saved = {
|
|||
{ "param", 0, 0, 0, 4, 0 },
|
||||
}};
|
||||
|
||||
const char * be_ctypes_instance_mappings[] = {
|
||||
static const char * be_ctypes_instance_mappings[] = {
|
||||
"lv_color",
|
||||
NULL
|
||||
};
|
||||
|
@ -435,7 +435,7 @@ static be_define_ctypes_class(lv_draw_rect_dsc, &be_lv_draw_rect_dsc, &be_class_
|
|||
static be_define_ctypes_class(lv_point, &be_lv_point, &be_class_ctypes, "lv_point");
|
||||
static be_define_ctypes_class(lv_sqrt_res, &be_lv_sqrt_res, &be_class_ctypes, "lv_sqrt_res");
|
||||
|
||||
void be_load_ctypes_definitions_lib(bvm *vm) {
|
||||
void be_load_ctypes_lvgl_definitions_lib(bvm *vm) {
|
||||
ctypes_register_class(vm, &be_class_lv_area, &be_lv_area);
|
||||
ctypes_register_class(vm, &be_class_lv_draw_img_dsc, &be_lv_draw_img_dsc);
|
||||
ctypes_register_class(vm, &be_class_lv_draw_label_dsc, &be_lv_draw_label_dsc);
|
||||
|
|
|
@ -115,6 +115,7 @@ extern void be_load_webclient_lib(bvm *vm);
|
|||
extern void be_load_crypto_lib(bvm *vm);
|
||||
|
||||
extern void be_load_ctypes_lib(bvm *vm);
|
||||
extern void be_load_ctypes_energy_definitions_lib(bvm *vm);
|
||||
|
||||
#ifdef USE_I2S_AUDIO_BERRY
|
||||
extern void be_load_driver_audio_lib(bvm *vm);
|
||||
|
@ -126,7 +127,7 @@ extern void be_load_lvgl_font_lib(bvm *vm);
|
|||
extern void be_load_lv_all_lib(bvm *vm);
|
||||
extern void be_load_lvgl_cb_lib(bvm *vm);
|
||||
extern void be_load_lvgl_cb_all_lib(bvm *vm);
|
||||
extern void be_load_ctypes_definitions_lib(bvm *vm);
|
||||
extern void be_load_ctypes_lvgl_definitions_lib(bvm *vm);
|
||||
// custom widgets
|
||||
extern void be_load_lv_signal_bars_class(bvm *vm);
|
||||
extern void be_load_lv_wifi_bars_class(bvm *vm);
|
||||
|
@ -160,6 +161,9 @@ BERRY_API void be_load_custom_libs(bvm *vm)
|
|||
be_load_driver_i2c_lib(vm);
|
||||
be_load_AXP192_class(vm);
|
||||
#endif // USE_I2C
|
||||
#ifdef USE_ENERGY_SENSOR
|
||||
be_load_ctypes_energy_definitions_lib(vm);
|
||||
#endif // USE_ENERGY_SENSOR
|
||||
#ifdef USE_WEBCLIENT
|
||||
be_load_webclient_lib(vm);
|
||||
#endif // USE_WEBCLIENT
|
||||
|
@ -177,7 +181,7 @@ BERRY_API void be_load_custom_libs(bvm *vm)
|
|||
be_load_lv_all_lib(vm);
|
||||
be_load_lvgl_cb_lib(vm);
|
||||
be_load_lvgl_cb_all_lib(vm);
|
||||
be_load_ctypes_definitions_lib(vm);
|
||||
be_load_ctypes_lvgl_definitions_lib(vm);
|
||||
// custom widgets
|
||||
be_load_lv_signal_bars_class(vm);
|
||||
be_load_lv_wifi_bars_class(vm);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,16 +1,17 @@
|
|||
#include "be_constobj.h"
|
||||
|
||||
static be_define_const_map_slots(be_class_ctypes_map) {
|
||||
{ be_const_key(init, -1), be_const_func(be_ctypes_init) },
|
||||
{ be_const_key(setmember, 2), be_const_func(be_ctypes_setmember) },
|
||||
{ be_const_key(_def, 3), be_const_nil() },
|
||||
{ be_const_key(member, -1), be_const_func(be_ctypes_member) },
|
||||
{ be_const_key(_def, 5), be_const_nil() },
|
||||
{ be_const_key(setmember, 0), be_const_func(be_ctypes_setmember) },
|
||||
{ be_const_key(copy, -1), be_const_func(be_ctypes_copy) },
|
||||
{ be_const_key(init, -1), be_const_func(be_ctypes_init) },
|
||||
{ be_const_key(tomap, -1), be_const_func(be_ctypes_tomap) },
|
||||
{ be_const_key(member, -1), be_const_func(be_ctypes_member) },
|
||||
};
|
||||
|
||||
static be_define_const_map(
|
||||
be_class_ctypes_map,
|
||||
5
|
||||
6
|
||||
);
|
||||
|
||||
BE_EXPORT_VARIABLE be_define_const_class(
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
#include "be_constobj.h"
|
||||
|
||||
static be_define_const_map_slots(m_libenergy_map) {
|
||||
{ be_const_key(read, -1), be_const_func(b_nrg_read) },
|
||||
{ be_const_key(init, -1), be_const_closure(init_closure) },
|
||||
{ be_const_key(_ptr, 3), be_const_comptr(&Energy) },
|
||||
{ be_const_key(setmember, -1), be_const_closure(setmember_closure) },
|
||||
{ be_const_key(member, 2), be_const_closure(member_closure) },
|
||||
{ be_const_key(read, -1), be_const_closure(read_closure) },
|
||||
};
|
||||
|
||||
static be_define_const_map(
|
||||
m_libenergy_map,
|
||||
1
|
||||
5
|
||||
);
|
||||
|
||||
static be_define_const_module(
|
||||
|
|
|
@ -255,9 +255,11 @@ static void cache_module(bvm *vm, bstring *name)
|
|||
/* Try to run '()' function of module. Module is already loaded. */
|
||||
static void module_init(bvm *vm) {
|
||||
if (be_getmember(vm, -1, "init")) {
|
||||
/* found, call it with no parameter */
|
||||
be_call(vm, 0);
|
||||
/* found, call it with current module as parameter */
|
||||
be_pushvalue(vm, -2);
|
||||
be_call(vm, 1);
|
||||
/* we don't care about the result */
|
||||
be_pop(vm, 1);
|
||||
}
|
||||
be_pop(vm, 1);
|
||||
}
|
||||
|
@ -339,7 +341,7 @@ bbool be_module_setmember(bvm *vm, bmodule *module, bstring *attr, bvalue *src)
|
|||
} else {
|
||||
/* if not writable, try 'setmember' */
|
||||
int type = be_module_attr(vm, module, str_literal(vm, "setmember"), vm->top);
|
||||
if (type == BE_FUNCTION) {
|
||||
if (basetype(type) == BE_FUNCTION) {
|
||||
bvalue *top = vm->top;
|
||||
// top[0] already has 'member'
|
||||
var_setstr(&top[1], attr); /* attribute name */
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
runcolor = nil
|
||||
|
||||
def runcolor()
|
||||
var pwr = energy.read().find('activepower',0)
|
||||
print(pwr)
|
||||
var pwr = energy.active_power
|
||||
#print(pwr)
|
||||
var red = tasmota.scale_uint(int(pwr), 0, 2500, 0, 255)
|
||||
var green = 255 - red
|
||||
var channels = [red, green, 0]
|
||||
|
|
|
@ -40,6 +40,10 @@ ctypes.be_u32 = -4
|
|||
ctypes.be_u16 = -2
|
||||
ctypes.be_u8 = -1
|
||||
|
||||
# floating point
|
||||
ctypes.float = 5
|
||||
ctypes.double = 10
|
||||
|
||||
ctypes.bf_x = 0 # generic bitfield
|
||||
# bitfields (always unsigned)
|
||||
ctypes.bf_0 = 100 # serves as base
|
||||
|
@ -211,13 +215,13 @@ ctypes.print_types = def ()
|
|||
print()
|
||||
print("BE_EXPORT_VARIABLE extern const bclass be_class_ctypes;")
|
||||
print()
|
||||
print("void ctypes_register_class(bvm *vm, const bclass * ctypes_class, const be_ctypes_structure_t * definitions) {")
|
||||
print("static void ctypes_register_class(bvm *vm, const bclass * ctypes_class, const be_ctypes_structure_t * definitions) {")
|
||||
print(" be_pushntvclass(vm, ctypes_class);")
|
||||
print(" be_setglobal(vm, str(ctypes_class->name));")
|
||||
print(" be_pop(vm, 1);")
|
||||
print("}")
|
||||
print()
|
||||
print("const char * be_ctypes_instance_mappings[]; /* forward definition */")
|
||||
print("static const char * be_ctypes_instance_mappings[]; /* forward definition */")
|
||||
print()
|
||||
|
||||
print("// Define a sub-class of ctypes with only one member which points to the ctypes defintion")
|
||||
|
@ -239,12 +243,12 @@ end
|
|||
global_classes = [] # track the list of all classes and
|
||||
global_mappings = [] # mapping to Berry classes, ex: lv_color
|
||||
|
||||
ctypes.print_classes = def ()
|
||||
ctypes.print_classes = def (module_name)
|
||||
# print mappings
|
||||
if size(global_mappings) > 7
|
||||
raise "internal_error", "too many mappings, 7 max"
|
||||
end
|
||||
print("const char * be_ctypes_instance_mappings[] = {")
|
||||
print("static const char * be_ctypes_instance_mappings[] = {")
|
||||
for n:global_mappings.iter()
|
||||
print(string.format(" \"%s\",", n))
|
||||
end
|
||||
|
@ -259,7 +263,7 @@ ctypes.print_classes = def ()
|
|||
end
|
||||
|
||||
print()
|
||||
print("void be_load_ctypes_definitions_lib(bvm *vm) {")
|
||||
print(string.format("void be_load_ctypes_%s_definitions_lib(bvm *vm) {", module_name))
|
||||
for elt:global_classes
|
||||
print(string.format(" ctypes_register_class(vm, &be_class_%s, &be_%s);", elt, elt))
|
||||
end
|
||||
|
@ -366,6 +370,9 @@ class structure
|
|||
if type_obj > ctypes.bf_0
|
||||
# bit field
|
||||
self.get_bitfield_closure(name, type_obj - ctypes.bf_0, mapping_idx)
|
||||
elif (type_obj == ctypes.float) || (type_obj == ctypes.double)
|
||||
# multi-bytes
|
||||
self.get_float_closure(name, type_obj, mapping_idx)
|
||||
else
|
||||
# multi-bytes
|
||||
self.get_int_closure(name, type_obj, mapping_idx)
|
||||
|
@ -438,6 +445,26 @@ class structure
|
|||
self.cur_offset += size_in_bytes # next offset
|
||||
end
|
||||
|
||||
def get_float_closure(name, type, instance_mapping) # can be 1/2/4
|
||||
#- abs size -#
|
||||
var size_in_bytes = (type == ctypes.float) ? 4 : 8
|
||||
|
||||
self.align(size_in_bytes) # force alignment
|
||||
var offset = self.cur_offset # prepare variable for capture in closure
|
||||
|
||||
self.mapping[name] = [offset, 0, 0, type, instance_mapping]
|
||||
|
||||
#- add closures -#
|
||||
# TODO no closure yet, anyways need to rethink closures, they are too heavy
|
||||
# if signed
|
||||
# self.get_closures[name] = def (b, p) return b.geti(offset + p, size_in_bytes_le_be) end
|
||||
# else
|
||||
# self.get_closures[name] = def (b, p) return b.get(offset + p, size_in_bytes_le_be) end
|
||||
# end
|
||||
# self.set_closures[name] = def (b, p, v) return b.set(offset+ p, v, size_in_bytes_le_be) end
|
||||
|
||||
self.cur_offset += size_in_bytes # next offset
|
||||
end
|
||||
|
||||
def get_bitfield_closure(name, size_in_bits, instance_mapping) # can be 1..32
|
||||
var cur_offset = self.cur_offset # prepare variable for capture in closure
|
||||
|
|
|
@ -0,0 +1,157 @@
|
|||
#
|
||||
# ctype buidings for Tasmota Energy driver
|
||||
#
|
||||
# To generate C bindings, do:
|
||||
# > compile("energy_ctypes.be","file")()
|
||||
#
|
||||
# and copy/paste output in C format
|
||||
#
|
||||
import ctypes
|
||||
|
||||
ctypes.print_types()
|
||||
|
||||
float = ctypes.float
|
||||
uint8 = ctypes.u8
|
||||
uint16 = ctypes.u16
|
||||
uint32 = ctypes.u32
|
||||
int32 = ctypes.i32
|
||||
bool = ctypes.bf_1
|
||||
|
||||
energy_struct = [
|
||||
[float, "voltage"],
|
||||
[float, "voltage_2"],
|
||||
[float, "voltage_3"],
|
||||
[float, "current"],
|
||||
[float, "current_2"],
|
||||
[float, "current_3"],
|
||||
[float, "active_power"],
|
||||
[float, "active_power_2"],
|
||||
[float, "active_power_3"],
|
||||
[float, "reactive_power"],
|
||||
[float, "reactive_power_2"],
|
||||
[float, "reactive_power_3"],
|
||||
[float, "power_factor"],
|
||||
[float, "power_factor_2"],
|
||||
[float, "power_factor_3"],
|
||||
[float, "frequency"],
|
||||
[float, "frequency_2"],
|
||||
[float, "frequency_3"],
|
||||
# relocate SDM630_IMPORT and SDM72_IMPEXP
|
||||
[float, "export_active"],
|
||||
[float, "export_active_2"],
|
||||
[float, "export_active_3"],
|
||||
|
||||
[float, "start_energy"],
|
||||
[float, "daily"],
|
||||
[float, "total"],
|
||||
|
||||
[uint32, "today_delta_kwh"],
|
||||
[uint32, "today_offset_kwh"],
|
||||
[uint32, "today_kwh"],
|
||||
[uint32, "period"],
|
||||
|
||||
[uint8, "fifth_second"],
|
||||
[uint8, "command_code"],
|
||||
[uint8, "data_valid"],
|
||||
[uint8, "data_valid_2"],
|
||||
[uint8, "data_valid_3"],
|
||||
|
||||
[uint8, "phase_count"],
|
||||
|
||||
[bool, "voltage_common"],
|
||||
[bool, "frequency_common"],
|
||||
[bool, "use_overtemp"],
|
||||
[bool, "today_offset_init_kwh"],
|
||||
|
||||
[bool, "voltage_available"],
|
||||
[bool, "current_available"],
|
||||
|
||||
[bool, "type_dc"],
|
||||
[bool, "power_on"],
|
||||
# #ifdef USE_ENERGY_MARGIN_DETECTION
|
||||
[uint16, "power_history_0"],
|
||||
[uint16, "power_history_0_2"],
|
||||
[uint16, "power_history_0_3"],
|
||||
[uint16, "power_history_1"],
|
||||
[uint16, "power_history_1_2"],
|
||||
[uint16, "power_history_1_3"],
|
||||
[uint16, "power_history_2"],
|
||||
[uint16, "power_history_2_2"],
|
||||
[uint16, "power_history_2_3"],
|
||||
|
||||
[uint8, "power_steady_counter"],
|
||||
|
||||
[bool, "min_power_flag"],
|
||||
[bool, "max_power_flag"],
|
||||
[bool, "min_voltage_flag"],
|
||||
[bool, "max_voltage_flag"],
|
||||
[bool, "min_current_flag"],
|
||||
[bool, "max_current_flag"],
|
||||
|
||||
# #ifdef USE_ENERGY_POWER_LIMIT
|
||||
[uint16, "mplh_counter"],
|
||||
[uint16, "mplw_counter"],
|
||||
[uint8, "mplr_counter"],
|
||||
[uint8, "max_energy_state"],
|
||||
]
|
||||
energy_struct = ctypes.structure(energy_struct, "energy_struct")
|
||||
|
||||
# struct ENERGY {
|
||||
# float voltage[ENERGY_MAX_PHASES]; // 123.1 V
|
||||
# float current[ENERGY_MAX_PHASES]; // 123.123 A
|
||||
# float active_power[ENERGY_MAX_PHASES]; // 123.1 W
|
||||
# float apparent_power[ENERGY_MAX_PHASES]; // 123.1 VA
|
||||
# float reactive_power[ENERGY_MAX_PHASES]; // 123.1 VAr
|
||||
# float power_factor[ENERGY_MAX_PHASES]; // 0.12
|
||||
# float frequency[ENERGY_MAX_PHASES]; // 123.1 Hz
|
||||
# #if defined(SDM630_IMPORT) || defined(SDM72_IMPEXP)
|
||||
# float import_active[ENERGY_MAX_PHASES]; // 123.123 kWh
|
||||
# #endif // SDM630_IMPORT || SDM72_IMPEXP
|
||||
# float export_active[ENERGY_MAX_PHASES]; // 123.123 kWh
|
||||
|
||||
# float start_energy; // 12345.12345 kWh total previous
|
||||
# float daily; // 123.123 kWh
|
||||
# float total; // 12345.12345 kWh total energy
|
||||
|
||||
# unsigned long kWhtoday_delta; // 1212312345 Wh 10^-5 (deca micro Watt hours) - Overflows to Energy.kWhtoday (HLW and CSE only)
|
||||
# unsigned long kWhtoday_offset; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = Energy.daily
|
||||
# unsigned long kWhtoday; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = Energy.daily
|
||||
# unsigned long period; // 12312312 Wh * 10^-2 (deca milli Watt hours) - 5764 = 0.05764 kWh = 0.058 kWh = Energy.daily
|
||||
|
||||
# uint8_t fifth_second;
|
||||
# uint8_t command_code;
|
||||
# uint8_t data_valid[ENERGY_MAX_PHASES];
|
||||
|
||||
# uint8_t phase_count; // Number of phases active
|
||||
# bool voltage_common; // Use single voltage
|
||||
# bool frequency_common; // Use single frequency
|
||||
# bool use_overtemp; // Use global temperature as overtemp trigger on internal energy monitor hardware
|
||||
# bool kWhtoday_offset_init;
|
||||
|
||||
# bool voltage_available; // Enable if voltage is measured
|
||||
# bool current_available; // Enable if current is measured
|
||||
|
||||
# bool type_dc;
|
||||
# bool power_on;
|
||||
|
||||
# #ifdef USE_ENERGY_MARGIN_DETECTION
|
||||
# uint16_t power_history[ENERGY_MAX_PHASES][3];
|
||||
# uint8_t power_steady_counter; // Allow for power on stabilization
|
||||
# bool min_power_flag;
|
||||
# bool max_power_flag;
|
||||
# bool min_voltage_flag;
|
||||
# bool max_voltage_flag;
|
||||
# bool min_current_flag;
|
||||
# bool max_current_flag;
|
||||
|
||||
# #ifdef USE_ENERGY_POWER_LIMIT
|
||||
# uint16_t mplh_counter;
|
||||
# uint16_t mplw_counter;
|
||||
# uint8_t mplr_counter;
|
||||
# uint8_t max_energy_state;
|
||||
# #endif // USE_ENERGY_POWER_LIMIT
|
||||
# #endif // USE_ENERGY_MARGIN_DETECTION
|
||||
# } Energy;
|
||||
|
||||
#
|
||||
ctypes.print_classes("energy")
|
|
@ -276,7 +276,7 @@ lv_draw_mask_saved = [
|
|||
lv_draw_mask_saved = ctypes.structure(lv_draw_mask_saved, "lv_draw_mask_saved")
|
||||
|
||||
#
|
||||
ctypes.print_classes()
|
||||
ctypes.print_classes("lvgl")
|
||||
|
||||
# Ex:
|
||||
# bb = ctypes.buffer(test_t, bytes("0101020203030404FFFFFEFEFCFC8080"))
|
||||
|
|
|
@ -1,69 +0,0 @@
|
|||
/*
|
||||
xdrv_52_3_berry_native.ino - Berry scripting language, native fucnctions
|
||||
|
||||
Copyright (C) 2021 Stephan Hadinger, Berry language by Guan Wenliang https://github.com/Skiars/berry
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifdef USE_BERRY
|
||||
|
||||
#ifdef USE_ENERGY_SENSOR
|
||||
|
||||
#include <berry.h>
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Native functions mapped to Berry functions
|
||||
*
|
||||
* import power
|
||||
*
|
||||
* power.read() -> map
|
||||
*
|
||||
\*********************************************************************************************/
|
||||
extern "C" {
|
||||
// Berry: `begintransmission(address:int) -> nil`
|
||||
int32_t b_nrg_read(struct bvm *vm);
|
||||
int32_t b_nrg_read(struct bvm *vm) {
|
||||
be_newobject(vm, "map");
|
||||
map_insert_float(vm, "total", Energy.total);
|
||||
// Energy.phase_count
|
||||
map_insert_float(vm, "power", Energy.active_power[0]);
|
||||
map_insert_float(vm, "yesterday", (float)Settings->energy_kWhyesterday / 100000);
|
||||
map_insert_float(vm, "today", Energy.daily);
|
||||
map_insert_float(vm, "activepower", Energy.active_power[0]);
|
||||
map_insert_float(vm, "apparentpower", Energy.active_power[0]);
|
||||
map_insert_float(vm, "reactivepower", Energy.reactive_power[0]);
|
||||
// map_insert_float(vm, "powerfactor", );
|
||||
map_insert_float(vm, "frequency", Energy.frequency[0]);
|
||||
map_insert_float(vm, "voltage", Energy.voltage[0]);
|
||||
map_insert_float(vm, "current", Energy.current[0]);
|
||||
|
||||
be_pop(vm, 1);
|
||||
be_return(vm); // Return
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
//
|
||||
int32_t b_wire_energymissing(struct bvm *vm);
|
||||
int32_t b_wire_energymissing(struct bvm *vm) {
|
||||
be_raise(vm, "feature_error", "Energy sensor is not enabled, use '#define USE_ENERGY_SENSOR'");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // USE_ENERGY_SENSOR
|
||||
#endif // USE_BERRY
|
Loading…
Reference in New Issue