mirror of https://github.com/arendst/Tasmota.git
Merge pull request #11255 from s-hadinger/berry_mar_7
Berry improvements
This commit is contained in:
commit
419b40b1c0
|
@ -976,6 +976,7 @@ BERRY_API int be_pcall(bvm *vm, int argc)
|
|||
return be_protectedcall(vm, f, argc);
|
||||
}
|
||||
|
||||
__attribute__((noreturn))
|
||||
BERRY_API void be_raise(bvm *vm, const char *except, const char *msg)
|
||||
{
|
||||
be_pushstring(vm, except);
|
||||
|
@ -987,6 +988,9 @@ BERRY_API void be_raise(bvm *vm, const char *except, const char *msg)
|
|||
be_pop(vm, 2);
|
||||
be_save_stacktrace(vm);
|
||||
be_throw(vm, BE_EXCEPTION);
|
||||
#ifdef __GNUC__
|
||||
__builtin_unreachable();
|
||||
#endif
|
||||
}
|
||||
|
||||
BERRY_API void be_stop_iteration(bvm *vm)
|
||||
|
|
|
@ -401,6 +401,7 @@ BERRY_API int be_pcall(bvm *vm, int argc);
|
|||
BERRY_API void be_exit(bvm *vm, int status);
|
||||
|
||||
/* exception APIs */
|
||||
__attribute__((noreturn))
|
||||
BERRY_API void be_raise(bvm *vm, const char *except, const char *msg);
|
||||
BERRY_API int be_getexcept(bvm *vm, int code);
|
||||
BERRY_API void be_dumpvalue(bvm *vm, int index);
|
||||
|
|
|
@ -12,6 +12,7 @@ extern int l_getoption(bvm *vm);
|
|||
extern int l_millis(bvm *vm);
|
||||
extern int l_timereached(bvm *vm);
|
||||
extern int l_yield(bvm *vm);
|
||||
extern int l_delay(bvm *vm);
|
||||
|
||||
extern int l_respCmnd(bvm *vm);
|
||||
extern int l_respCmndStr(bvm *vm);
|
||||
|
@ -20,6 +21,8 @@ extern int l_respCmndError(bvm *vm);
|
|||
extern int l_respCmndFailed(bvm *vm);
|
||||
extern int l_resolveCmnd(bvm *vm);
|
||||
|
||||
extern int l_getlight(bvm *vm);
|
||||
|
||||
// #if !BE_USE_PRECOMPILED_OBJECT
|
||||
#if 1 // TODO we will do pre-compiled later
|
||||
|
||||
|
@ -31,6 +34,7 @@ be_native_module_attr_table(tasmota_ntv) {
|
|||
be_native_module_function("millis", l_millis),
|
||||
be_native_module_function("timereached", l_timereached),
|
||||
be_native_module_function("yield", l_yield),
|
||||
be_native_module_function("delay", l_delay),
|
||||
|
||||
be_native_module_function("respcmnd", l_respCmnd),
|
||||
be_native_module_function("respcmndstr", l_respCmndStr),
|
||||
|
@ -39,6 +43,8 @@ be_native_module_attr_table(tasmota_ntv) {
|
|||
be_native_module_function("respcmnd_failed", l_respCmndFailed),
|
||||
be_native_module_function("resolvecmnd", l_resolveCmnd),
|
||||
|
||||
be_native_module_function("getlight", l_getlight),
|
||||
|
||||
be_native_module_str("_operators", "=<>!|"),
|
||||
};
|
||||
|
||||
|
|
|
@ -14,18 +14,23 @@ extern int b_wire_available(bvm *vm);
|
|||
extern int b_wire_write(bvm *vm);
|
||||
extern int b_wire_read(bvm *vm);
|
||||
|
||||
extern int b_wire_scan(bvm *vm);
|
||||
|
||||
extern int b_wire_validwrite(bvm *vm);
|
||||
extern int b_wire_validread(bvm *vm);
|
||||
|
||||
// #if !BE_USE_PRECOMPILED_OBJECT
|
||||
#if 1 // TODO we will do pre-compiled later
|
||||
be_native_module_attr_table(wire) {
|
||||
be_native_module_function("begintransmission", b_wire_begintransmission),
|
||||
be_native_module_function("endtransmission", b_wire_endtransmission),
|
||||
be_native_module_function("requestfrom", b_wire_requestfrom),
|
||||
be_native_module_function("available", b_wire_available),
|
||||
be_native_module_function("write", b_wire_write),
|
||||
be_native_module_function("read", b_wire_read),
|
||||
be_native_module_function("validread", b_wire_validread),
|
||||
be_native_module_function("_begintransmission", b_wire_begintransmission),
|
||||
be_native_module_function("_endtransmission", b_wire_endtransmission),
|
||||
be_native_module_function("_requestfrom", b_wire_requestfrom),
|
||||
be_native_module_function("_available", b_wire_available),
|
||||
be_native_module_function("_write", b_wire_write),
|
||||
be_native_module_function("_read", b_wire_read),
|
||||
be_native_module_function("scan", b_wire_scan),
|
||||
be_native_module_function("write", b_wire_validwrite),
|
||||
be_native_module_function("read", b_wire_validread),
|
||||
};
|
||||
|
||||
be_define_native_module(wire, NULL);
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <berry.h>
|
||||
#include <Wire.h>
|
||||
|
||||
const char kTypeError[] PROGMEM = "type_error";
|
||||
/*********************************************************************************************\
|
||||
* Native functions mapped to Berry functions
|
||||
*
|
||||
|
@ -58,7 +59,7 @@ extern "C" {
|
|||
be_return(vm); // Return
|
||||
}
|
||||
}
|
||||
be_return_nil(vm); // Return nil when something goes wrong
|
||||
be_raise(vm, kTypeError, nullptr);
|
||||
}
|
||||
|
||||
// Berry: `tasmota.cmd(command:string) -> string`
|
||||
|
@ -72,7 +73,7 @@ extern "C" {
|
|||
be_pushstring(vm, TasmotaGlobal.mqtt_data);
|
||||
be_return(vm); // Return
|
||||
}
|
||||
be_return_nil(vm); // Return nil when something goes wrong
|
||||
be_raise(vm, kTypeError, nullptr);
|
||||
}
|
||||
|
||||
// Berry: tasmota.millis([delay:int]) -> int
|
||||
|
@ -89,7 +90,7 @@ extern "C" {
|
|||
be_pushint(vm, ret_millis);
|
||||
be_return(vm); // Return
|
||||
}
|
||||
be_return_nil(vm); // Return nil when something goes wrong
|
||||
be_raise(vm, kTypeError, nullptr);
|
||||
}
|
||||
|
||||
// Berry: tasmota.getoption(index:int) -> int
|
||||
|
@ -102,7 +103,7 @@ extern "C" {
|
|||
be_pushint(vm, opt);
|
||||
be_return(vm); // Return
|
||||
}
|
||||
be_return_nil(vm); // Return nil when something goes wrong
|
||||
be_raise(vm, kTypeError, nullptr);
|
||||
}
|
||||
|
||||
// Berry: tasmota.timereached(timer:int) -> bool
|
||||
|
@ -116,7 +117,20 @@ extern "C" {
|
|||
be_pushbool(vm, reached);
|
||||
be_return(vm); // Return
|
||||
}
|
||||
be_return_nil(vm); // Return nil when something goes wrong
|
||||
be_raise(vm, kTypeError, nullptr);
|
||||
}
|
||||
|
||||
// Berry: tasmota.delay(timer:int) -> nil
|
||||
//
|
||||
int32_t l_delay(struct bvm *vm);
|
||||
int32_t l_delay(struct bvm *vm) {
|
||||
int32_t top = be_top(vm); // Get the number of arguments
|
||||
if (top == 1 && be_isint(vm, 1)) { // only 1 argument of type string accepted
|
||||
uint32_t timer = be_toint(vm, 1);
|
||||
delay(timer);
|
||||
be_return_nil(vm); // Return
|
||||
}
|
||||
be_raise(vm, kTypeError, nullptr);
|
||||
}
|
||||
|
||||
// Berry: `yield() -> nil`
|
||||
|
@ -137,7 +151,7 @@ extern "C" {
|
|||
be_pushint(vm, ret);
|
||||
be_return(vm); // Return
|
||||
}
|
||||
be_return_nil(vm); // Return nil when something goes wrong
|
||||
be_raise(vm, kTypeError, nullptr);
|
||||
}
|
||||
|
||||
int32_t l_respCmnd(bvm *vm);
|
||||
|
@ -146,8 +160,9 @@ extern "C" {
|
|||
if (top == 1) {
|
||||
const char *msg = be_tostring(vm, 1);
|
||||
Response_P("%s", msg);
|
||||
be_return_nil(vm); // Return nil when something goes wrong
|
||||
}
|
||||
be_return_nil(vm); // Return nil when something goes wrong
|
||||
be_raise(vm, kTypeError, nullptr);
|
||||
}
|
||||
|
||||
int32_t l_respCmndStr(bvm *vm);
|
||||
|
@ -156,8 +171,9 @@ extern "C" {
|
|||
if (top == 1) {
|
||||
const char *msg = be_tostring(vm, 1);
|
||||
ResponseCmndChar(msg);
|
||||
be_return_nil(vm); // Return nil when something goes wrong
|
||||
}
|
||||
be_return_nil(vm); // Return nil when something goes wrong
|
||||
be_raise(vm, kTypeError, nullptr);
|
||||
}
|
||||
|
||||
int32_t l_respCmndDone(bvm *vm);
|
||||
|
@ -185,9 +201,139 @@ extern "C" {
|
|||
if (top == 1 && be_isstring(vm, 1)) {
|
||||
const char *msg = be_tostring(vm, 1);
|
||||
strlcpy(XdrvMailbox.command, msg, CMDSZ);
|
||||
be_return_nil(vm); // Return nil when something goes wrong
|
||||
}
|
||||
be_return_nil(vm); // Return nil when something goes wrong
|
||||
be_raise(vm, kTypeError, nullptr);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
// get light
|
||||
int32_t l_getlight(bvm *vm);
|
||||
int32_t l_getlight(bvm *vm) {
|
||||
int32_t top = be_top(vm); // Get the number of arguments
|
||||
if (top == 0 || (top == 1 && be_isint(vm, 1))) {
|
||||
int32_t light_num = 0;
|
||||
if (top > 0) {
|
||||
light_num = be_toint(vm, 1);
|
||||
}
|
||||
bool data_present = false; // do we have relevant data
|
||||
be_newobject(vm, "map");
|
||||
// check if the light exist
|
||||
// TasmotaGlobal.devices_present
|
||||
// Light.device
|
||||
// Light.subtype
|
||||
// Light.pwm_multi_channels
|
||||
// light_controller.isCTRGBLinked()
|
||||
|
||||
if (Light.device > 0) {
|
||||
// we have a light
|
||||
|
||||
uint8_t channels[LST_MAX];
|
||||
uint8_t channelsb[LST_MAX];
|
||||
char rgbcw[12] = {0};
|
||||
char rgbcwb[12] = {0};
|
||||
light_state.getChannelsRaw(channels);
|
||||
light_state.getChannels(channelsb);
|
||||
|
||||
// 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());
|
||||
|
||||
if (!Light.pwm_multi_channels) {
|
||||
uint32_t subtype = Light.subtype; // virtual sub-type, for SO37 128
|
||||
uint32_t chanidx = 0; // channel offset, for SO37 128
|
||||
|
||||
|
||||
if (light_controller.isCTRGBLinked() && (light_num == 0)) {
|
||||
data_present = true; // valid combination
|
||||
}
|
||||
if (!light_controller.isCTRGBLinked()) {
|
||||
if (light_num == 0) {
|
||||
data_present = true; // valid combination
|
||||
if (subtype > LST_RGB) { subtype = LST_RGB; } // limit to RGB
|
||||
}
|
||||
if ((light_num == 1) && subtype > LST_RGB) {
|
||||
data_present = true; // valid combination
|
||||
subtype = subtype - LST_RGB;
|
||||
chanidx = 3; // skip first 3 channels
|
||||
}
|
||||
}
|
||||
|
||||
if (data_present) {
|
||||
// see ResponseLightState()
|
||||
map_insert_bool(vm, "power", (bool)(Light.power & 1));
|
||||
map_insert_int(vm, "bri", light_state.getBri());
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
if ((LST_COLDWARM == subtype) || (LST_RGBW <= subtype)) {
|
||||
map_insert_int(vm, "ct", light_state.getCT());
|
||||
}
|
||||
if (subtype > LST_NONE) {
|
||||
for (uint32_t i=0; i < subtype; i++) {
|
||||
snprintf_P(rgbcw, sizeof(rgbcw), PSTR("%s%02X"), rgbcw, channels[i+chanidx]);
|
||||
snprintf_P(rgbcwb, sizeof(rgbcwb), PSTR("%s%02X"), rgbcwb, channelsb[i+chanidx]);
|
||||
}
|
||||
map_insert_str(vm, "channels", rgbcw);
|
||||
map_insert_str(vm, "channelsb", rgbcwb);
|
||||
// map_insert_bool(vm, "gamma", Settings.light_correction);
|
||||
}
|
||||
}
|
||||
} 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]);
|
||||
snprintf_P(rgbcw, sizeof(rgbcw), PSTR("%02X"), channels[light_num]);
|
||||
snprintf_P(rgbcwb, sizeof(rgbcwb), PSTR("%02X"), channelsb[light_num]);
|
||||
map_insert_str(vm, "channels", rgbcw);
|
||||
map_insert_str(vm, "channelsb", rgbcwb);
|
||||
}
|
||||
}
|
||||
|
||||
be_pop(vm, 1);
|
||||
if (data_present) {
|
||||
be_return(vm); // Return
|
||||
} else {
|
||||
be_return_nil(vm); // no data, return nil instead of empty map
|
||||
}
|
||||
} else {
|
||||
be_return_nil(vm);
|
||||
}
|
||||
}
|
||||
be_raise(vm, kTypeError, nullptr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
|
@ -208,7 +354,7 @@ extern "C" {
|
|||
Wire.beginTransmission(address);
|
||||
be_return(vm); // Return
|
||||
}
|
||||
be_return_nil(vm); // Return nil when something goes wrong
|
||||
be_raise(vm, kTypeError, nullptr);
|
||||
}
|
||||
|
||||
// Berry: `endtransmission([stop:bool]) -> nil`
|
||||
|
@ -224,7 +370,7 @@ extern "C" {
|
|||
be_pushint(vm, ret);
|
||||
be_return(vm); // Return
|
||||
}
|
||||
be_return_nil(vm); // Return nil when something goes wrong
|
||||
be_raise(vm, kTypeError, nullptr);
|
||||
}
|
||||
|
||||
// Berry: `requestfrom(address:int, quantity:int [stop:bool = true]) -> nil`
|
||||
|
@ -242,7 +388,7 @@ extern "C" {
|
|||
Wire.requestFrom((uint16_t)address, (uint8_t)quantity, stop);
|
||||
be_return(vm); // Return
|
||||
}
|
||||
be_return_nil(vm); // Return nil when something goes wrong
|
||||
be_raise(vm, kTypeError, nullptr);
|
||||
}
|
||||
|
||||
// Berry: `available() -> bool`
|
||||
|
@ -254,14 +400,14 @@ extern "C" {
|
|||
be_pushint(vm, available);
|
||||
be_return(vm); // Return
|
||||
}
|
||||
be_return_nil(vm); // Return nil when something goes wrong
|
||||
be_raise(vm, kTypeError, nullptr);
|
||||
}
|
||||
|
||||
// Berry: `write(value:int | s:string) -> nil`
|
||||
int32_t b_wire_write(struct bvm *vm);
|
||||
int32_t b_wire_write(struct bvm *vm) {
|
||||
int32_t top = be_top(vm); // Get the number of arguments
|
||||
if (top == 1 && (be_isint(vm, 1) || be_isint(vm, 1))) {
|
||||
if (top == 1 && (be_isint(vm, 1) || be_isstring(vm, 1))) {
|
||||
if (be_isint(vm, 1)) {
|
||||
int32_t value = be_toint(vm, 1);
|
||||
Wire.write(value);
|
||||
|
@ -273,7 +419,7 @@ extern "C" {
|
|||
}
|
||||
be_return(vm); // Return
|
||||
}
|
||||
be_return_nil(vm); // Return nil when something goes wrong
|
||||
be_raise(vm, kTypeError, nullptr);
|
||||
}
|
||||
|
||||
// Berry: `read() -> int`
|
||||
|
@ -285,7 +431,43 @@ extern "C" {
|
|||
be_pushint(vm, value);
|
||||
be_return(vm); // Return
|
||||
}
|
||||
be_return_nil(vm); // Return nil when something goes wrong
|
||||
be_raise(vm, kTypeError, nullptr);
|
||||
}
|
||||
|
||||
int32_t b_wire_scan(struct bvm *vm);
|
||||
int32_t b_wire_scan(struct bvm *vm) {
|
||||
int32_t top = be_top(vm); // Get the number of arguments
|
||||
if (top == 0) {
|
||||
be_newobject(vm, "list");
|
||||
for (uint8_t address = 1; address <= 127; address++) {
|
||||
Wire.beginTransmission(address);
|
||||
int32_t error = Wire.endTransmission();
|
||||
if (0 == error) {
|
||||
be_pushint(vm, address);
|
||||
be_data_push(vm, -2);
|
||||
be_pop(vm, 1);
|
||||
}
|
||||
}
|
||||
be_pop(vm, 1);
|
||||
be_return(vm); // Return
|
||||
}
|
||||
be_raise(vm, kTypeError, nullptr);
|
||||
}
|
||||
|
||||
// Berry: `validwrite(address:int, reg:int, val:int, size:int) -> bool or nil`
|
||||
int32_t b_wire_validwrite(struct bvm *vm);
|
||||
int32_t b_wire_validwrite(struct bvm *vm) {
|
||||
int32_t top = be_top(vm); // Get the number of arguments
|
||||
if (top == 4 && be_isint(vm, 1) && be_isint(vm, 2) && be_isint(vm, 3) && be_isint(vm, 4)) {
|
||||
uint8_t addr = be_toint(vm, 1);
|
||||
uint8_t reg = be_toint(vm, 2);
|
||||
uint8_t val = be_toint(vm, 3);
|
||||
uint8_t size = be_toint(vm, 4);
|
||||
bool ok = I2cWrite(addr, reg, val, size);
|
||||
be_pushbool(vm, ok);
|
||||
be_return(vm); // Return
|
||||
}
|
||||
be_raise(vm, kTypeError, nullptr);
|
||||
}
|
||||
|
||||
// Berry: `validread(address:int, reg:int, size:int) -> int or nil`
|
||||
|
@ -304,7 +486,7 @@ extern "C" {
|
|||
}
|
||||
be_return(vm); // Return
|
||||
}
|
||||
be_return_nil(vm); // Return nil when something goes wrong
|
||||
be_raise(vm, kTypeError, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@ const char berry_prog[] =
|
|||
// Again, this will be eventually pre-compiled
|
||||
"var getfreeheap, publish, cmd, getoption, millis, timereached, yield "
|
||||
"var respcmnd, respcmndstr, respcmnd_done, respcmnd_error, respcmnd_failed, resolvecmnd "
|
||||
"var getlight "
|
||||
"def init_ntv() "
|
||||
"import tasmota_ntv "
|
||||
"self.getfreeheap = tasmota_ntv.getfreeheap "
|
||||
|
@ -62,6 +63,8 @@ const char berry_prog[] =
|
|||
"self.respcmnd_error = tasmota_ntv.respcmnd_error "
|
||||
"self.respcmnd_failed = tasmota_ntv.respcmnd_failed "
|
||||
"self.resolvecmnd = tasmota_ntv.resolvecmnd "
|
||||
|
||||
"self.getlight = tasmota_ntv.getlight "
|
||||
"end "
|
||||
|
||||
"def init() "
|
||||
|
|
|
@ -304,11 +304,15 @@ void CmndBrRun(void) {
|
|||
// AddLog(LOG_LEVEL_INFO, "run: type(2)=%s", be_typename(berry.vm, 2));
|
||||
|
||||
// code taken from REPL, look first at top, and if nil, look at return value
|
||||
ret_val = be_tostring(berry.vm, 1);
|
||||
Response_P("{\"" D_PRFX_BR "\":\"%s\"}", ret_val); // can't use XdrvMailbox.command as it may have been overwritten by subcommand
|
||||
if (!be_isnil(berry.vm, 1)) {
|
||||
ret_val = be_tostring(berry.vm, 1);
|
||||
} else {
|
||||
ret_val = be_tostring(berry.vm, 2);
|
||||
}
|
||||
Response_P("{\"" D_PRFX_BR "\":\"%s\"}", EscapeJSONString(ret_val).c_str()); // can't use XdrvMailbox.command as it may have been overwritten by subcommand
|
||||
be_pop(berry.vm, 1);
|
||||
} else {
|
||||
Response_P(PSTR("{\"" D_PRFX_BR "\":\"[%s] %s\"}"), be_tostring(berry.vm, -2), be_tostring(berry.vm, -1));
|
||||
Response_P(PSTR("{\"" D_PRFX_BR "\":\"[%s] %s\"}"), EscapeJSONString(be_tostring(berry.vm, -2)).c_str(), EscapeJSONString(be_tostring(berry.vm, -1)).c_str());
|
||||
be_pop(berry.vm, 2);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue