From 3f140b4b1018e0cb4e94916d3daf6eb03055cbb6 Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Thu, 18 Nov 2021 20:30:16 +0100 Subject: [PATCH] Berry support for neopixel (WS2812, SK6812) --- CHANGELOG.md | 2 + .../Berry/default/be_leds_animator_lib.c | 316 +++++++++ lib/libesp32/Berry/default/be_leds_lib.c | 618 ++++++++++++++++++ .../Berry/default/be_leds_matrix_lib.c | 106 +++ lib/libesp32/Berry/default/be_leds_ntv_lib.c | 77 +++ lib/libesp32/Berry/default/be_modtab.c | 10 + lib/libesp32/Berry/default/embedded/leds.be | 141 ++++ .../Berry/default/embedded/leds_animator.be | 51 ++ tasmota/berry/leds/rainbow.be | 159 +++++ tasmota/tasmota.h | 12 + tasmota/tasmota_template.h | 2 +- tasmota/xdrv_52_3_berry_leds.ino | 299 +++++++++ tasmota/xdrv_52_9_berry.ino | 6 +- 13 files changed, 1795 insertions(+), 4 deletions(-) create mode 100644 lib/libesp32/Berry/default/be_leds_animator_lib.c create mode 100644 lib/libesp32/Berry/default/be_leds_lib.c create mode 100644 lib/libesp32/Berry/default/be_leds_matrix_lib.c create mode 100644 lib/libesp32/Berry/default/be_leds_ntv_lib.c create mode 100644 lib/libesp32/Berry/default/embedded/leds.be create mode 100644 lib/libesp32/Berry/default/embedded/leds_animator.be create mode 100644 tasmota/berry/leds/rainbow.be create mode 100644 tasmota/xdrv_52_3_berry_leds.ino diff --git a/CHANGELOG.md b/CHANGELOG.md index 98b1365fd..448585921 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ All notable changes to this project will be documented in this file. - Autoconfiguration for ESP32 and variants - ESP32 fix leftover GPIO configuration after restart - ESP32 Proof of Concept Sonoff SPM with limited functionality (switching and energy monitoring) (#13447) +- Preliminary support for Tasmota Apps (.tapp extesions) +- Berry support for neopixel (WS2812, SK6812) ### Changed - ESP8266 Gratuitous ARP enabled and set to 60 seconds (#13623) diff --git a/lib/libesp32/Berry/default/be_leds_animator_lib.c b/lib/libesp32/Berry/default/be_leds_animator_lib.c new file mode 100644 index 000000000..092d354f6 --- /dev/null +++ b/lib/libesp32/Berry/default/be_leds_animator_lib.c @@ -0,0 +1,316 @@ +/******************************************************************** + * Berry class `Leds_animator` + * + *******************************************************************/ +#include "be_constobj.h" + +#ifdef USE_WS2812 + +/******************************************************************** +** Solidified function: set_bri +********************************************************************/ +be_local_closure(set_bri, /* name */ + be_nested_proto( + 2, /* 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("bri", 2112284244, 3), + }), + (be_nested_const_str("set_bri", -1505848517, 7)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 2]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x80000000, // 0001 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: clear +********************************************************************/ +be_local_closure(clear, /* name */ + be_nested_proto( + 3, /* nstack */ + 1, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_string("stop", -883741979, 4), + /* K1 */ be_nested_string("strip", -48555823, 5), + /* K2 */ be_nested_string("clear", 1550717474, 5), + }), + (be_nested_const_str("clear", 1550717474, 5)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 6]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x7C040200, // 0001 CALL R1 1 + 0x88040101, // 0002 GETMBR R1 R0 K1 + 0x8C040302, // 0003 GETMET R1 R1 K2 + 0x7C040200, // 0004 CALL R1 1 + 0x80000000, // 0005 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_bri +********************************************************************/ +be_local_closure(get_bri, /* 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("bri", 2112284244, 3), + }), + (be_nested_const_str("get_bri", 2041809895, 7)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 2]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x80040400, // 0001 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: every_50ms +********************************************************************/ +be_local_closure(every_50ms, /* name */ + be_nested_proto( + 3, /* nstack */ + 1, /* 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("running", 343848780, 7), + /* K1 */ be_nested_string("animate", -409180496, 7), + }), + (be_nested_const_str("every_50ms", -1911083288, 10)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 5]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x78060001, // 0001 JMPF R1 #0004 + 0x8C040101, // 0002 GETMET R1 R0 K1 + 0x7C040200, // 0003 CALL R1 1 + 0x80000000, // 0004 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: stop +********************************************************************/ +be_local_closure(stop, /* 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("running", 343848780, 7), + }), + (be_nested_const_str("stop", -883741979, 4)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 3]) { /* code */ + 0x50040000, // 0000 LDBOOL R1 0 0 + 0x90020001, // 0001 SETMBR R0 K0 R1 + 0x80000000, // 0002 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: remove +********************************************************************/ +be_local_closure(remove, /* 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[ 2]) { /* constants */ + /* K0 */ be_nested_string("tasmota", 424643812, 7), + /* K1 */ be_nested_string("remove_driver", 1030243768, 13), + }), + (be_nested_const_str("remove", -611183107, 6)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 5]) { /* code */ + 0xB8060000, // 0000 GETNGBL R1 K0 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0x5C0C0000, // 0002 MOVE R3 R0 + 0x7C040400, // 0003 CALL R1 2 + 0x80000000, // 0004 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: start +********************************************************************/ +be_local_closure(start, /* 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("running", 343848780, 7), + }), + (be_nested_const_str("start", 1697318111, 5)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 3]) { /* code */ + 0x50040200, // 0000 LDBOOL R1 1 0 + 0x90020001, // 0001 SETMBR R0 K0 R1 + 0x80000000, // 0002 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(init, /* name */ + be_nested_proto( + 5, /* nstack */ + 2, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 7]) { /* constants */ + /* K0 */ be_nested_string("strip", -48555823, 5), + /* K1 */ be_nested_string("bri", 2112284244, 3), + /* K2 */ be_nested_string("running", 343848780, 7), + /* K3 */ be_nested_string("pixel_count", -1855836553, 11), + /* K4 */ be_nested_string("clear", 1550717474, 5), + /* K5 */ be_nested_string("tasmota", 424643812, 7), + /* K6 */ be_nested_string("add_driver", 1654458371, 10), + }), + (be_nested_const_str("init", 380752755, 4)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[15]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x540A0031, // 0001 LDINT R2 50 + 0x90020202, // 0002 SETMBR R0 K1 R2 + 0x50080000, // 0003 LDBOOL R2 0 0 + 0x90020402, // 0004 SETMBR R0 K2 R2 + 0x8C080303, // 0005 GETMET R2 R1 K3 + 0x7C080200, // 0006 CALL R2 1 + 0x90020602, // 0007 SETMBR R0 K3 R2 + 0x8C080104, // 0008 GETMET R2 R0 K4 + 0x7C080200, // 0009 CALL R2 1 + 0xB80A0A00, // 000A GETNGBL R2 K5 + 0x8C080506, // 000B GETMET R2 R2 K6 + 0x5C100000, // 000C MOVE R4 R0 + 0x7C080400, // 000D CALL R2 2 + 0x80000000, // 000E RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: animate +********************************************************************/ +be_local_closure(animate, /* name */ + be_nested_proto( + 1, /* nstack */ + 1, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + (be_nested_const_str("animate", -409180496, 7)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 1]) { /* code */ + 0x80000000, // 0000 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Leds_animator +********************************************************************/ +be_local_class(Leds_animator, + 4, + NULL, + be_nested_map(13, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_nested_key("set_bri", -1505848517, 7, 9), be_const_closure(set_bri_closure) }, + { be_nested_key("clear", 1550717474, 5, -1), be_const_closure(clear_closure) }, + { be_nested_key("running", 343848780, 7, -1), be_const_var(3) }, + { be_nested_key("get_bri", 2041809895, 7, -1), be_const_closure(get_bri_closure) }, + { be_nested_key("every_50ms", -1911083288, 10, -1), be_const_closure(every_50ms_closure) }, + { be_nested_key("bri", 2112284244, 3, 0), be_const_var(2) }, + { be_nested_key("stop", -883741979, 4, 11), be_const_closure(stop_closure) }, + { be_nested_key("remove", -611183107, 6, 1), be_const_closure(remove_closure) }, + { be_nested_key("start", 1697318111, 5, 3), be_const_closure(start_closure) }, + { be_nested_key("strip", -48555823, 5, -1), be_const_var(0) }, + { be_nested_key("pixel_count", -1855836553, 11, -1), be_const_var(1) }, + { be_nested_key("init", 380752755, 4, -1), be_const_closure(init_closure) }, + { be_nested_key("animate", -409180496, 7, 4), be_const_closure(animate_closure) }, + })), + (be_nested_const_str("Leds_animator", 142168673, 13)) +); +/*******************************************************************/ + +void be_load_Leds_animator_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Leds_animator); + be_setglobal(vm, "Leds_animator"); + be_pop(vm, 1); +} + +#endif // USE_WS2812 diff --git a/lib/libesp32/Berry/default/be_leds_lib.c b/lib/libesp32/Berry/default/be_leds_lib.c new file mode 100644 index 000000000..7ddaa4b16 --- /dev/null +++ b/lib/libesp32/Berry/default/be_leds_lib.c @@ -0,0 +1,618 @@ +/******************************************************************** + * Berry class `Leds` + * + *******************************************************************/ +#include "be_constobj.h" + +#ifdef USE_WS2812 + +/******************************************************************** +** Solidified function: get_pixel_color +********************************************************************/ +be_local_closure(get_pixel_color, /* name */ + be_nested_proto( + 6, /* 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("call_native", 1389147405, 11), + }), + (be_nested_const_str("get_pixel_color", 337490048, 15)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 5]) { /* code */ + 0x8C080100, // 0000 GETMET R2 R0 K0 + 0x5412000A, // 0001 LDINT R4 11 + 0x5C140200, // 0002 MOVE R5 R1 + 0x7C080600, // 0003 CALL R2 3 + 0x80040400, // 0004 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: pixels_buffer +********************************************************************/ +be_local_closure(pixels_buffer, /* 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[ 1]) { /* constants */ + /* K0 */ be_nested_string("call_native", 1389147405, 11), + }), + (be_nested_const_str("pixels_buffer", 1229555807, 13)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 4]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x540E0005, // 0001 LDINT R3 6 + 0x7C040400, // 0002 CALL R1 2 + 0x80040200, // 0003 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: clear +********************************************************************/ +be_local_closure(clear, /* 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[ 3]) { /* constants */ + /* K0 */ be_nested_string("clear_to", -766965166, 8), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_string("show", -1454906820, 4), + }), + (be_nested_const_str("clear", 1550717474, 5)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 6]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x580C0001, // 0001 LDCONST R3 K1 + 0x7C040400, // 0002 CALL R1 2 + 0x8C040102, // 0003 GETMET R1 R0 K2 + 0x7C040200, // 0004 CALL R1 1 + 0x80000000, // 0005 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(init, /* name */ + be_nested_proto( + 9, /* nstack */ + 4, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[11]) { /* constants */ + /* K0 */ be_nested_string("gamma", -802614262, 5), + /* K1 */ be_nested_string("pin", 1866532500, 3), + /* K2 */ be_nested_string("WS2812", -755226078, 6), + /* K3 */ be_const_int(0), + /* K4 */ be_nested_string("valuer_error", -1727020191, 12), + /* K5 */ be_nested_string("no GPIO specified for neopixelbus", 42078528, 33), + /* K6 */ be_nested_string("ctor", 375399343, 4), + /* K7 */ be_nested_string("_p", 1594591802, 2), + /* K8 */ be_nested_string("internal_error", -1775809127, 14), + /* K9 */ be_nested_string("couldn't not initialize noepixelbus", -1758476484, 35), + /* K10 */ be_nested_string("begin", 1748273790, 5), + }), + (be_nested_const_str("init", 380752755, 4)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[31]) { /* code */ + 0x50100200, // 0000 LDBOOL R4 1 0 + 0x90020004, // 0001 SETMBR R0 K0 R4 + 0x4C100000, // 0002 LDNIL R4 + 0x1C100404, // 0003 EQ R4 R2 R4 + 0x78120008, // 0004 JMPF R4 #000E + 0x8C100501, // 0005 GETMET R4 R2 K1 + 0x88180502, // 0006 GETMBR R6 R2 K2 + 0x7C100400, // 0007 CALL R4 2 + 0x28100903, // 0008 GE R4 R4 K3 + 0x78120003, // 0009 JMPF R4 #000E + 0x8C100501, // 000A GETMET R4 R2 K1 + 0x88180502, // 000B GETMBR R6 R2 K2 + 0x7C100400, // 000C CALL R4 2 + 0x5C080800, // 000D MOVE R2 R4 + 0x4C100000, // 000E LDNIL R4 + 0x1C100404, // 000F EQ R4 R2 R4 + 0x78120000, // 0010 JMPF R4 #0012 + 0xB0060905, // 0011 RAISE 1 K4 K5 + 0x8C100106, // 0012 GETMET R4 R0 K6 + 0x5C180200, // 0013 MOVE R6 R1 + 0x5C1C0400, // 0014 MOVE R7 R2 + 0x5C200600, // 0015 MOVE R8 R3 + 0x7C100800, // 0016 CALL R4 4 + 0x88100107, // 0017 GETMBR R4 R0 K7 + 0x4C140000, // 0018 LDNIL R5 + 0x1C100805, // 0019 EQ R4 R4 R5 + 0x78120000, // 001A JMPF R4 #001C + 0xB0061109, // 001B RAISE 1 K8 K9 + 0x8C10010A, // 001C GETMET R4 R0 K10 + 0x7C100200, // 001D CALL R4 1 + 0x80000000, // 001E RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_pixel_color +********************************************************************/ +be_local_closure(set_pixel_color, /* name */ + be_nested_proto( + 12, /* nstack */ + 4, /* 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("call_native", 1389147405, 11), + /* K1 */ be_nested_string("to_gamma", 1597139862, 8), + }), + (be_nested_const_str("set_pixel_color", 1275248356, 15)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 9]) { /* code */ + 0x8C100100, // 0000 GETMET R4 R0 K0 + 0x541A0009, // 0001 LDINT R6 10 + 0x5C1C0200, // 0002 MOVE R7 R1 + 0x8C200101, // 0003 GETMET R8 R0 K1 + 0x5C280400, // 0004 MOVE R10 R2 + 0x5C2C0600, // 0005 MOVE R11 R3 + 0x7C200600, // 0006 CALL R8 3 + 0x7C100800, // 0007 CALL R4 4 + 0x80000000, // 0008 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: begin +********************************************************************/ +be_local_closure(begin, /* 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[ 2]) { /* constants */ + /* K0 */ be_nested_string("call_native", 1389147405, 11), + /* K1 */ be_const_int(1), + }), + (be_nested_const_str("begin", 1748273790, 5)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 4]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x580C0001, // 0001 LDCONST R3 K1 + 0x7C040400, // 0002 CALL R1 2 + 0x80000000, // 0003 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: to_gamma +********************************************************************/ +be_local_closure(to_gamma, /* name */ + be_nested_proto( + 12, /* nstack */ + 3, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 7]) { /* constants */ + /* K0 */ be_nested_string("tasmota", 424643812, 7), + /* K1 */ be_nested_string("scale_uint", -1204156202, 10), + /* K2 */ be_const_int(0), + /* K3 */ be_const_int(16711680), + /* K4 */ be_nested_string("gamma", -802614262, 5), + /* K5 */ be_nested_string("light", -493019601, 5), + /* K6 */ be_nested_string("gamma8", -492123466, 6), + }), + (be_nested_const_str("to_gamma", 1597139862, 8)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[67]) { /* code */ + 0x4C0C0000, // 0000 LDNIL R3 + 0x200C0403, // 0001 NE R3 R2 R3 + 0x780E0001, // 0002 JMPF R3 #0005 + 0x5C0C0400, // 0003 MOVE R3 R2 + 0x70020000, // 0004 JMP #0006 + 0x540E0063, // 0005 LDINT R3 100 + 0x5C080600, // 0006 MOVE R2 R3 + 0xB80E0000, // 0007 GETNGBL R3 K0 + 0x8C0C0701, // 0008 GETMET R3 R3 K1 + 0x5C140400, // 0009 MOVE R5 R2 + 0x58180002, // 000A LDCONST R6 K2 + 0x541E0063, // 000B LDINT R7 100 + 0x58200002, // 000C LDCONST R8 K2 + 0x2C240303, // 000D AND R9 R1 K3 + 0x542A000F, // 000E LDINT R10 16 + 0x3C24120A, // 000F SHR R9 R9 R10 + 0x7C0C0C00, // 0010 CALL R3 6 + 0xB8120000, // 0011 GETNGBL R4 K0 + 0x8C100901, // 0012 GETMET R4 R4 K1 + 0x5C180400, // 0013 MOVE R6 R2 + 0x581C0002, // 0014 LDCONST R7 K2 + 0x54220063, // 0015 LDINT R8 100 + 0x58240002, // 0016 LDCONST R9 K2 + 0x542AFEFF, // 0017 LDINT R10 65280 + 0x2C28020A, // 0018 AND R10 R1 R10 + 0x542E0007, // 0019 LDINT R11 8 + 0x3C28140B, // 001A SHR R10 R10 R11 + 0x7C100C00, // 001B CALL R4 6 + 0xB8160000, // 001C GETNGBL R5 K0 + 0x8C140B01, // 001D GETMET R5 R5 K1 + 0x5C1C0400, // 001E MOVE R7 R2 + 0x58200002, // 001F LDCONST R8 K2 + 0x54260063, // 0020 LDINT R9 100 + 0x58280002, // 0021 LDCONST R10 K2 + 0x542E00FE, // 0022 LDINT R11 255 + 0x2C2C020B, // 0023 AND R11 R1 R11 + 0x7C140C00, // 0024 CALL R5 6 + 0x88180104, // 0025 GETMBR R6 R0 K4 + 0x781A0013, // 0026 JMPF R6 #003B + 0xB81A0A00, // 0027 GETNGBL R6 K5 + 0x8C180D06, // 0028 GETMET R6 R6 K6 + 0x5C200600, // 0029 MOVE R8 R3 + 0x7C180400, // 002A CALL R6 2 + 0x541E000F, // 002B LDINT R7 16 + 0x38180C07, // 002C SHL R6 R6 R7 + 0xB81E0A00, // 002D GETNGBL R7 K5 + 0x8C1C0F06, // 002E GETMET R7 R7 K6 + 0x5C240800, // 002F MOVE R9 R4 + 0x7C1C0400, // 0030 CALL R7 2 + 0x54220007, // 0031 LDINT R8 8 + 0x381C0E08, // 0032 SHL R7 R7 R8 + 0x30180C07, // 0033 OR R6 R6 R7 + 0xB81E0A00, // 0034 GETNGBL R7 K5 + 0x8C1C0F06, // 0035 GETMET R7 R7 K6 + 0x5C240A00, // 0036 MOVE R9 R5 + 0x7C1C0400, // 0037 CALL R7 2 + 0x30180C07, // 0038 OR R6 R6 R7 + 0x80040C00, // 0039 RET 1 R6 + 0x70020006, // 003A JMP #0042 + 0x541A000F, // 003B LDINT R6 16 + 0x38180606, // 003C SHL R6 R3 R6 + 0x541E0007, // 003D LDINT R7 8 + 0x381C0807, // 003E SHL R7 R4 R7 + 0x30180C07, // 003F OR R6 R6 R7 + 0x30180C05, // 0040 OR R6 R6 R5 + 0x80040C00, // 0041 RET 1 R6 + 0x80000000, // 0042 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: pixel_count +********************************************************************/ +be_local_closure(pixel_count, /* 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[ 1]) { /* constants */ + /* K0 */ be_nested_string("call_native", 1389147405, 11), + }), + (be_nested_const_str("pixel_count", -1855836553, 11)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 4]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x540E0007, // 0001 LDINT R3 8 + 0x7C040400, // 0002 CALL R1 2 + 0x80040200, // 0003 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: can_show +********************************************************************/ +be_local_closure(can_show, /* 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[ 2]) { /* constants */ + /* K0 */ be_nested_string("call_native", 1389147405, 11), + /* K1 */ be_const_int(3), + }), + (be_nested_const_str("can_show", 960091187, 8)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 4]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x580C0001, // 0001 LDCONST R3 K1 + 0x7C040400, // 0002 CALL R1 2 + 0x80040200, // 0003 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: pixel_size +********************************************************************/ +be_local_closure(pixel_size, /* 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[ 1]) { /* constants */ + /* K0 */ be_nested_string("call_native", 1389147405, 11), + }), + (be_nested_const_str("pixel_size", -2085831511, 10)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 4]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x540E0006, // 0001 LDINT R3 7 + 0x7C040400, // 0002 CALL R1 2 + 0x80040200, // 0003 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: dirty +********************************************************************/ +be_local_closure(dirty, /* 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[ 1]) { /* constants */ + /* K0 */ be_nested_string("call_native", 1389147405, 11), + }), + (be_nested_const_str("dirty", -1627386213, 5)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 4]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x540E0004, // 0001 LDINT R3 5 + 0x7C040400, // 0002 CALL R1 2 + 0x80000000, // 0003 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: show +********************************************************************/ +be_local_closure(show, /* 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[ 2]) { /* constants */ + /* K0 */ be_nested_string("call_native", 1389147405, 11), + /* K1 */ be_const_int(2), + }), + (be_nested_const_str("show", -1454906820, 4)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 4]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x580C0001, // 0001 LDCONST R3 K1 + 0x7C040400, // 0002 CALL R1 2 + 0x80000000, // 0003 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: clear_to +********************************************************************/ +be_local_closure(clear_to, /* name */ + be_nested_proto( + 10, /* nstack */ + 3, /* 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("call_native", 1389147405, 11), + /* K1 */ be_nested_string("to_gamma", 1597139862, 8), + }), + (be_nested_const_str("clear_to", -766965166, 8)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 8]) { /* code */ + 0x8C0C0100, // 0000 GETMET R3 R0 K0 + 0x54160008, // 0001 LDINT R5 9 + 0x8C180101, // 0002 GETMET R6 R0 K1 + 0x5C200200, // 0003 MOVE R8 R1 + 0x5C240400, // 0004 MOVE R9 R2 + 0x7C180600, // 0005 CALL R6 3 + 0x7C0C0600, // 0006 CALL R3 3 + 0x80000000, // 0007 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: is_dirty +********************************************************************/ +be_local_closure(is_dirty, /* 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[ 1]) { /* constants */ + /* K0 */ be_nested_string("call_native", 1389147405, 11), + }), + (be_nested_const_str("is_dirty", 418034110, 8)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 4]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x540E0003, // 0001 LDINT R3 4 + 0x7C040400, // 0002 CALL R1 2 + 0x80040200, // 0003 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: ctor +********************************************************************/ +be_local_closure(ctor, /* name */ + be_nested_proto( + 10, /* nstack */ + 4, /* 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("call_native", 1389147405, 11), + /* K1 */ be_const_int(0), + }), + (be_nested_const_str("ctor", 375399343, 4)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[16]) { /* code */ + 0x4C100000, // 0000 LDNIL R4 + 0x1C100604, // 0001 EQ R4 R3 R4 + 0x78120005, // 0002 JMPF R4 #0009 + 0x8C100100, // 0003 GETMET R4 R0 K0 + 0x58180001, // 0004 LDCONST R6 K1 + 0x5C1C0200, // 0005 MOVE R7 R1 + 0x5C200400, // 0006 MOVE R8 R2 + 0x7C100800, // 0007 CALL R4 4 + 0x70020005, // 0008 JMP #000F + 0x8C100100, // 0009 GETMET R4 R0 K0 + 0x58180001, // 000A LDCONST R6 K1 + 0x5C1C0200, // 000B MOVE R7 R1 + 0x5C200400, // 000C MOVE R8 R2 + 0x5C240600, // 000D MOVE R9 R3 + 0x7C100A00, // 000E CALL R4 5 + 0x80000000, // 000F RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Leds +********************************************************************/ +extern const bclass be_class_Leds_ntv; +be_local_class(Leds, + 1, + &be_class_Leds_ntv, + be_nested_map(16, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_nested_key("get_pixel_color", 337490048, 15, -1), be_const_closure(get_pixel_color_closure) }, + { be_nested_key("pixels_buffer", 1229555807, 13, -1), be_const_closure(pixels_buffer_closure) }, + { be_nested_key("clear", 1550717474, 5, 13), be_const_closure(clear_closure) }, + { be_nested_key("init", 380752755, 4, 8), be_const_closure(init_closure) }, + { be_nested_key("set_pixel_color", 1275248356, 15, -1), be_const_closure(set_pixel_color_closure) }, + { be_nested_key("begin", 1748273790, 5, -1), be_const_closure(begin_closure) }, + { be_nested_key("to_gamma", 1597139862, 8, -1), be_const_closure(to_gamma_closure) }, + { be_nested_key("pixel_count", -1855836553, 11, -1), be_const_closure(pixel_count_closure) }, + { be_nested_key("can_show", 960091187, 8, -1), be_const_closure(can_show_closure) }, + { be_nested_key("pixel_size", -2085831511, 10, -1), be_const_closure(pixel_size_closure) }, + { be_nested_key("gamma", -802614262, 5, -1), be_const_var(0) }, + { be_nested_key("dirty", -1627386213, 5, -1), be_const_closure(dirty_closure) }, + { be_nested_key("show", -1454906820, 4, -1), be_const_closure(show_closure) }, + { be_nested_key("clear_to", -766965166, 8, -1), be_const_closure(clear_to_closure) }, + { be_nested_key("is_dirty", 418034110, 8, 5), be_const_closure(is_dirty_closure) }, + { be_nested_key("ctor", 375399343, 4, 1), be_const_closure(ctor_closure) }, + })), + (be_nested_const_str("Leds", -1585722021, 4)) +); +/*******************************************************************/ + +void be_load_Leds_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Leds); + be_setglobal(vm, "Leds"); + be_pop(vm, 1); +} + +#endif // USE_WS2812 diff --git a/lib/libesp32/Berry/default/be_leds_matrix_lib.c b/lib/libesp32/Berry/default/be_leds_matrix_lib.c new file mode 100644 index 000000000..b6d83bb18 --- /dev/null +++ b/lib/libesp32/Berry/default/be_leds_matrix_lib.c @@ -0,0 +1,106 @@ +/******************************************************************** + * Berry class `Leds_matrix` + * + *******************************************************************/ +#include "be_constobj.h" + +#ifdef USE_WS2812 + +/******************************************************************** +** Solidified function: set_matrix_pixel_color +********************************************************************/ +be_local_closure(set_matrix_pixel_color, /* name */ + be_nested_proto( + 10, /* nstack */ + 5, /* 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("set_pixel_color", 1275248356, 15), + /* K1 */ be_nested_string("w", -234078410, 1), + }), + (be_nested_const_str("set_matrix_pixel_color", 1197149462, 22)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 8]) { /* code */ + 0x8C140100, // 0000 GETMET R5 R0 K0 + 0x881C0101, // 0001 GETMBR R7 R0 K1 + 0x081C0207, // 0002 MUL R7 R1 R7 + 0x001C0E02, // 0003 ADD R7 R7 R2 + 0x5C200600, // 0004 MOVE R8 R3 + 0x5C240800, // 0005 MOVE R9 R4 + 0x7C140800, // 0006 CALL R5 4 + 0x80000000, // 0007 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(init, /* name */ + be_nested_proto( + 10, /* nstack */ + 5, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_string("w", -234078410, 1), + /* K1 */ be_nested_string("h", -317966505, 1), + /* K2 */ be_nested_string("init", 380752755, 4), + }), + (be_nested_const_str("init", 380752755, 4)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[11]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x90020202, // 0001 SETMBR R0 K1 R2 + 0x60140003, // 0002 GETGBL R5 G3 + 0x5C180000, // 0003 MOVE R6 R0 + 0x7C140200, // 0004 CALL R5 1 + 0x8C140B02, // 0005 GETMET R5 R5 K2 + 0x081C0202, // 0006 MUL R7 R1 R2 + 0x5C200600, // 0007 MOVE R8 R3 + 0x5C240800, // 0008 MOVE R9 R4 + 0x7C140800, // 0009 CALL R5 4 + 0x80000000, // 000A RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Leds_matrix +********************************************************************/ +extern const bclass be_class_Leds; +be_local_class(Leds_matrix, + 2, + &be_class_Leds, + be_nested_map(4, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_nested_key("h", -317966505, 1, -1), be_const_var(0) }, + { be_nested_key("w", -234078410, 1, -1), be_const_var(1) }, + { be_nested_key("set_matrix_pixel_color", 1197149462, 22, 1), be_const_closure(set_matrix_pixel_color_closure) }, + { be_nested_key("init", 380752755, 4, 0), be_const_closure(init_closure) }, + })), + (be_nested_const_str("Leds_matrix", -1450073227, 11)) +); +/*******************************************************************/ + +void be_load_Leds_matrix_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Leds_matrix); + be_setglobal(vm, "Leds_matrix"); + be_pop(vm, 1); +} + + +#endif // USE_WS2812 diff --git a/lib/libesp32/Berry/default/be_leds_ntv_lib.c b/lib/libesp32/Berry/default/be_leds_ntv_lib.c new file mode 100644 index 000000000..8d09f952b --- /dev/null +++ b/lib/libesp32/Berry/default/be_leds_ntv_lib.c @@ -0,0 +1,77 @@ +/******************************************************************** + * Berry class `neopixelbus_ntv` + * + *******************************************************************/ +/* + +class Leds_ntv + var _p # pointer to internal object of type `NeoPixelBus(uint16_t countPixels, uint8_t pin)` + var _t # type of led strip + static WS2812_GRB = 1 + static WS2812_GRBW = 2 + static SK6812_GRB = 3 + static SK6812_GRBW = 4 + + # skeleton for native call + def call_native() end +end + +*/ +#include "be_constobj.h" + +#ifdef USE_WS2812 + +extern int be_neopixelbus_call_native(bvm *vm); + +/******************************************************************** +** Solidified function: call_native +********************************************************************/ +be_local_closure(call_native, /* name */ + be_nested_proto( + 1, /* nstack */ + 1, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + (be_nested_const_str("call_native", 1389147405, 11)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 1]) { /* code */ + 0x80000000, // 0000 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Leds_ntv +********************************************************************/ +be_local_class(Leds_ntv, + 2, + NULL, + be_nested_map(7, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_nested_key("WS2812_GRB", 1736405692, 10, 3), be_const_int(1) }, + { be_nested_key("WS2812_GRBW", -660477967, 11, -1), be_const_int(2) }, + { be_nested_key("call_native", 1389147405, 11, 1), be_const_func(be_neopixelbus_call_native) }, + { be_nested_key("_t", 1527481326, 2, -1), be_const_var(1) }, + { be_nested_key("SK6812_GRBW", 81157857, 11, -1), be_const_int(4) }, + { be_nested_key("SK6812_GRB", 1159411308, 10, -1), be_const_int(3) }, + { be_nested_key("_p", 1594591802, 2, 5), be_const_var(0) }, + })), + (be_nested_const_str("Leds_ntv", -292677248, 8)) +); +/*******************************************************************/ + +void be_load_Leds_ntv_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Leds_ntv); + be_setglobal(vm, "Leds_ntv"); + be_pop(vm, 1); +} + +// be_const_func(be_neopixelbus_call_native) +#endif // USE_WS2812 diff --git a/lib/libesp32/Berry/default/be_modtab.c b/lib/libesp32/Berry/default/be_modtab.c index 7e1a1bad9..df2b93843 100644 --- a/lib/libesp32/Berry/default/be_modtab.c +++ b/lib/libesp32/Berry/default/be_modtab.c @@ -132,6 +132,10 @@ extern void be_load_AXP192_class(bvm *vm); extern void be_load_md5_lib(bvm *vm); extern void be_load_webclient_lib(bvm *vm); extern void be_load_crypto_lib(bvm *vm); +extern void be_load_Leds_ntv_class(bvm *vm); +extern void be_load_Leds_class(bvm *vm); +extern void be_load_Leds_matrix_class(bvm *vm); +extern void be_load_Leds_animator_class(bvm *vm); extern void be_load_ctypes_lib(bvm *vm); extern void be_load_ctypes_energy_definitions_lib(bvm *vm); @@ -186,6 +190,12 @@ BERRY_API void be_load_custom_libs(bvm *vm) #if defined(USE_ONEWIRE) || defined(USE_DS18x20) be_load_onewirelib(vm); #endif +#ifdef USE_WS2812 + be_load_Leds_ntv_class(vm); + be_load_Leds_class(vm); + be_load_Leds_matrix_class(vm); + be_load_Leds_animator_class(vm); +#endif // USE_WS2812 #ifdef USE_I2S_AUDIO_BERRY be_load_driver_audio_lib(vm); #endif diff --git a/lib/libesp32/Berry/default/embedded/leds.be b/lib/libesp32/Berry/default/embedded/leds.be new file mode 100644 index 000000000..aed675125 --- /dev/null +++ b/lib/libesp32/Berry/default/embedded/leds.be @@ -0,0 +1,141 @@ +# class Leds +# +# for adressable leds like NoePixel + + +# Native commands +# 00 : ctor (leds:int, gpio:int) -> void +# 01 : begin void -> void +# 02 : show void -> void +# 03 : CanShow void -> bool +# 04 : IsDirty void -> bool +# 05 : Dirty void -> void +# 06 : Pixels void -> bytes() (mapped to the buffer) +# 07 : PixelSize void -> int +# 08 : PixelCount void -> int +# 09 : ClearTo (color:??) -> void +# 10 : SetPixelColor (idx:int, color:??) -> void +# 11 : GetPixelColor (idx:int) -> color:?? +# 20 : RotateLeft (rot:int [, first:int, last:int]) -> void +# 21 : RotateRight (rot:int [, first:int, last:int]) -> void +# 22 : ShiftLeft (rot:int [, first:int, last:int]) -> void +# 23 : ShiftRight (rot:int [, first:int, last:int]) -> void + + +class Leds : Leds_ntv + var gamma # if true, apply gamma (true is default) + # leds:int = number of leds of the strip + # gpio:int (optional) = GPIO for NeoPixel. If not specified, takes the WS2812 gpio + # type:int (optional) = Type of LED, defaults to WS2812 RGB + # rmt:int (optional) = RMT hardware channel to use, leave default unless you have a good reason + def init(leds, gpio, type, rmt) # rmt is optional + self.gamma = true # gamma is enabled by default, it should be disabled explicitly if needed + + if gpio == nil && gpio.pin(gpio.WS2812) >= 0 + gpio = gpio.pin(gpio.WS2812) + end + + # if no GPIO, abort + if gpio == nil + raise "valuer_error", "no GPIO specified for neopixelbus" + end + + # initialize the structure + self.ctor(leds, gpio, type, rmt) + + if self._p == nil raise "internal_error", "couldn't not initialize noepixelbus" end + + # call begin + self.begin() + + end + + def clear() + self.clear_to(0x000000) + self.show() + end + + def ctor(leds, gpio, rmt) + if rmt == nil + self.call_native(0, leds, gpio) + else + self.call_native(0, leds, gpio, rmt) + end + end + def begin() + self.call_native(1) + end + def show() + self.call_native(2) + end + def can_show() + return self.call_native(3) + end + def is_dirty() + return self.call_native(4) + end + def dirty() + self.call_native(5) + end + def pixels_buffer() + return self.call_native(6) + end + def pixel_size() + return self.call_native(7) + end + def pixel_count() + return self.call_native(8) + end + def clear_to(col, bri) + self.call_native(9, self.to_gamma(col, bri)) + end + def set_pixel_color(idx, col, bri) + self.call_native(10, idx, self.to_gamma(col, bri)) + end + def get_pixel_color(idx) + return self.call_native(11, idx) + end + # def rotate_left(rot, first, last) + # self.call_native(20, rot, first, last) + # end + # def rotate_right(rot, first, last) + # self.call_native(21, rot, first, last) + # end + # def shift_left(rot, first, last) + # self.call_native(22, rot, first, last) + # end + # def shift_right(rot, first, last) + # self.call_native(22, rot, first, last) + # end + + # apply gamma and bri + def to_gamma(rgbw, bri) + bri = (bri != nil) ? bri : 100 + var r = tasmota.scale_uint(bri, 0, 100, 0, (rgbw & 0xFF0000) >> 16) + var g = tasmota.scale_uint(bri, 0, 100, 0, (rgbw & 0x00FF00) >> 8) + var b = tasmota.scale_uint(bri, 0, 100, 0, (rgbw & 0x0000FF)) + if self.gamma + return light.gamma8(r) << 16 | + light.gamma8(g) << 8 | + light.gamma8(b) + else + return r << 16 | + g << 8 | + b + end + end +end + +class Leds_matrix : Leds + var h, w + + def init(w, h, gpio, rmt) + self.w = w + self.h = h + super(self).init(w * h, gpio, rmt) + end + + def set_matrix_pixel_color(x, y, col, bri) + self.set_pixel_color(x * self.w + y, col, bri) + end +end diff --git a/lib/libesp32/Berry/default/embedded/leds_animator.be b/lib/libesp32/Berry/default/embedded/leds_animator.be new file mode 100644 index 000000000..c57fd87bf --- /dev/null +++ b/lib/libesp32/Berry/default/embedded/leds_animator.be @@ -0,0 +1,51 @@ +# class Leds_animator + +class Leds_animator + var strip # neopixelbus object + var pixel_count # number of pixels in the strip + var bri # brightness of the animation, 0..100, default 50 + var running # is the animation running + + def init(strip) + self.strip = strip + self.bri = 50 # percentage of brightness 0..100 + self.running = false + self.pixel_count = strip.pixel_count() + # + self.clear() # clear all leds first + # + tasmota.add_driver(self) + end + + def clear() + self.stop() + self.strip.clear() + end + def start() + self.running = true + end + def stop() + self.running = false + end + + def set_bri(bri) + self.bri = bri + end + def get_bri(bri) + return self.bri + end + + def every_50ms() + if self.running + self.animate() + end + end + + def animate() + # placeholder - do nothing by default + end + + def remove() + tasmota.remove_driver(self) + end +end diff --git a/tasmota/berry/leds/rainbow.be b/tasmota/berry/leds/rainbow.be new file mode 100644 index 000000000..eebd485a3 --- /dev/null +++ b/tasmota/berry/leds/rainbow.be @@ -0,0 +1,159 @@ +# simple Rainbow animator + +#- +# Ex: if WS2812 configured to WS2812 - channel 2 + +var strip = neopixelbus(25, gpio.pin(gpio.WS2812, 1)) +rainbow = Rainbow(strip) +rainbow.start() + +-# + +# https://stackoverflow.com/questions/34187171/fast-integer-square-root-approximation +def fast_sqrt_int(val) + var a, b + + if val < 2 return val end + + a = 1255 # starting point is relatively unimportant + + b = val / a; a = (a+b) /2; + b = val / a; a = (a+b) /2; + b = val / a; a = (a+b) /2; + b = val / a; a = (a+b) /2; + b = val / a; a = (a+b) /2; + b = val / a; a = (a+b) /2; + if (val < 20000) + b = val / a; a = (a+b) /2; + b = val / a; a = (a+b) /2; + end + + return a +end + +class Rainbow : Leds_animator + var cur_offset # current offset in the palette + static palette = [ 0xFF0000, #- red -# + 0xFFA500, #- orange -# + 0xFFFF00, #- yellow -# + 0x008800, #- green -# + 0x0000FF, #- blue -# + 0x4B0082, #- indigo -# + 0xEE82EE, #- violet -# + ] + + def init(strip) + super(self).init(strip) + self.cur_offset = 0 + end + + def animate() + var i = 0 + # move instance variables to registers to avoid GETMBR inside the loop + var cur_offset = self.cur_offset + var modulus = size(self.palette) + var palette = self.palette + var strip = self.strip + var bri = self.bri + var set_pixel_color = strip.set_pixel_color + + while i < self.pixel_count # doing a loop rather than a `for` prevents from allocating a new object + var col = palette[(cur_offset + i) % modulus] + set_pixel_color(strip, i, col, bri) # simulate the method call without GETMET + i += 1 + end + strip.show() + # advance to next color + self.cur_offset = (self.cur_offset + 1) % modulus + end + +end + +class Rainbow_Matrix : Leds_animator + var cur_offset # current offset in the palette + static palette = [ 0xFF0000, #- red -# + 0xFFA500, #- orange -# + 0xFFFF00, #- yellow -# + 0x008800, #- green -# + 0x0000FF, #- blue -# + 0x4B0082, #- indigo -# + 0xEE82EE, #- violet -# + ] + + def init(strip) + super(self).init(strip) + self.cur_offset = 0 + end + + def animate() + # move instance variables to registers to avoid GETMBR inside the loop + var cur_offset = self.cur_offset + var modulus = size(self.palette) + var palette = self.palette + var strip = self.strip + var bri = self.bri + var set_matrix_pixel_color = strip.set_matrix_pixel_color + var h = self.strip.h + var w = self.strip.w + + var y = 0 + while y < h + var x = 0 + while x < w + var col = palette[(cur_offset + y) % modulus] + set_matrix_pixel_color(strip, x, y, col, bri) # simulate the method call without GETMET + x += 1 + end + y += 1 + end + strip.show() + # advance to next color + self.cur_offset = (self.cur_offset + 1) % modulus + end + +end + + +class Round : Leds_animator + var cur_val + var min_val, max_val + var incr_val + + def init(strip) + super(self).init(strip) + self.cur_val = 5 << 8 + self.min_val = 2 << 8 + self.max_val = 6 << 8 + self.incr_val = 50 + end + + def animate() + # move instance variables to registers to avoid GETMBR inside the loop + var strip = self.strip + var bri = self.bri + var set_matrix_pixel_color = strip.set_matrix_pixel_color + var h = self.strip.h + var w = self.strip.w + var ch = h / 2 + var cw = w / 2 + + var y = 0 + while y < h + var x = 0 + while x < w + var col = 0xFF0000 # red + var dist = fast_sqrt_int( ((y - ch)*(y - ch) + (x - cw)*(x - cw)) << 16) + var rel_bri = tasmota.scale_uint(dist, 0, self.cur_val, bri, 0) + set_matrix_pixel_color(strip, x, y, col, rel_bri) # simulate the method call without GETMET + x += 1 + end + y += 1 + end + strip.show() + # + self.cur_val += self.incr_val + if self.cur_val > self.max_val self.cur_val = self.max_val self.incr_val = -self.incr_val end + if self.cur_val < self.min_val self.cur_val = self.min_val self.incr_val = -self.incr_val end + end + +end diff --git a/tasmota/tasmota.h b/tasmota/tasmota.h index 92803ca87..f6a2b113d 100644 --- a/tasmota/tasmota.h +++ b/tasmota/tasmota.h @@ -83,10 +83,22 @@ const uint16_t VL53L0X_MAX_SENSORS = 8; // Max number of VL53L0X sensors const uint8_t MAX_I2C = 2; // Max number of I2C controllers (ESP32 = 2) const uint8_t MAX_SPI = 2; // Max number of Hardware SPI controllers (ESP32 = 2) const uint8_t MAX_I2S = 2; // Max number of Hardware I2S controllers (ESP32 = 2) + +#if CONFIG_IDF_TARGET_ESP32 +const uint8_t MAX_RMT = 8; // Max number or RMT channels (ESP32 only) +#elif CONFIG_IDF_TARGET_ESP32S2 +const uint8_t MAX_RMT = 4; // Max number or RMT channels (ESP32S2 only) +#elif CONFIG_IDF_TARGET_ESP32C3 +const uint8_t MAX_RMT = 2; // Max number or RMT channels (ESP32C3 only) +#else +const uint8_t MAX_RMT = 0; // Max number or RMT channels (0 if unknown) +#endif + #else const uint8_t MAX_I2C = 0; // Max number of I2C controllers (ESP8266 = 0, no choice) const uint8_t MAX_SPI = 0; // Max number of Hardware SPI controllers (ESP8266 = 0, no choice) const uint8_t MAX_I2S = 0; // Max number of Hardware I2S controllers (ESP8266 = 0, no choice) +const uint8_t MAX_RMT = 0; // No RMT channel on ESP8266 #endif // Changes to the following MAX_ defines need to be in line with enum SettingsTextIndex diff --git a/tasmota/tasmota_template.h b/tasmota/tasmota_template.h index 4f9b41b4b..bbbce4d01 100644 --- a/tasmota/tasmota_template.h +++ b/tasmota/tasmota_template.h @@ -569,7 +569,7 @@ const uint16_t kGpioNiceList[] PROGMEM = { AGPIO(GPIO_P9813_CLK), // P9813 CLOCK AGPIO(GPIO_P9813_DAT), // P9813 DATA #else - AGPIO(GPIO_WS2812), // WS2812 Led string + AGPIO(GPIO_WS2812) + MAX_RMT,// WS2812 Led string, using RMT on ESP32 #endif // NEO_HW_P9813 #endif #ifdef USE_ARILUX_RF diff --git a/tasmota/xdrv_52_3_berry_leds.ino b/tasmota/xdrv_52_3_berry_leds.ino new file mode 100644 index 000000000..5e7d95b77 --- /dev/null +++ b/tasmota/xdrv_52_3_berry_leds.ino @@ -0,0 +1,299 @@ +/* + xdrv_52_3_berry_leds.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 . +*/ + + +#ifdef USE_BERRY + +#include + +#ifdef USE_WS2812 + +#include + +enum { + ws2812_grb = 1, + ws2812_grbw = 2, + sk6812_grb = 3, + sk6812_grbw = 4, + + neopixel_type_end +}; + +typedef NeoPixelBus neopixel_ws2812_grb_t; +typedef NeoPixelBus neopixel_ws2812_grbw_t; +typedef NeoPixelBus neopixel_sk6812_grb_t; +typedef NeoPixelBus neopixel_sk6812_grbw_t; + + +/*********************************************************************************************\ + * Native functions mapped to Berry functions + * + * import unishox + * + * +\*********************************************************************************************/ +extern "C" { + + // # Native commands + // # 00 : ctor + // # 01 : begin void -> void + // # 02 : show void -> void + // # 03 : CanShow void -> bool + // # 04 : IsDirty void -> bool + // # 05 : Dirty void -> void + // # 06 : Pixels void -> bytes() (mapped to the buffer) + // # 07 : PixelSize void -> int + // # 08 : PixelCount void -> int + // # 09 : ClearTo (color:??) -> void + // # 10 : SetPixelColor (idx:int, color:??) -> void + // # 11 : GetPixelColor (idx:int) -> color:?? + // # 20 : RotateLeft (rot:int [, first:int, last:int]) -> void + // # 21 : RotateRight (rot:int [, first:int, last:int]) -> void + // # 22 : ShiftLeft (rot:int [, first:int, last:int]) -> void + // # 23 : ShiftRight (rot:int [, first:int, last:int]) -> void + + void * be_get_neopixelbus(bvm *vm) { + be_getmember(vm, 1, "_p"); + void * strip = (void*) be_tocomptr(vm, -1); + be_pop(vm, 1); + if (strip == nullptr) { + be_raise(vm, "internal_error", "neopixelbus object not initialized"); + } + return strip; + } + int32_t be_get_leds_type(bvm *vm) { + be_getmember(vm, 1, "_t"); + int32_t type = be_toint(vm, -1); + be_pop(vm, 1); + if (type <= 0 || type >= neopixel_type_end) { + be_raise(vm, "internal_error", "invalid leds type"); + } + return type; + } + + int be_neopixelbus_call_native(bvm *vm); + int be_neopixelbus_call_native(bvm *vm) { + int32_t argc = be_top(vm); // Get the number of arguments + if (argc >= 2 && be_isint(vm, 2)) { + int32_t cmd = be_toint(vm, 2); + + if (0 == cmd) { // 00 : ctor (leds:int, gpio:int) -> void + if (!(argc >= 4 && be_isint(vm, 3) && be_isint(vm, 4))) { + be_raise(vm, "value_error", "bad arguments for neopixelbus:ctor"); + } + int32_t leds = be_toint(vm, 3); + int32_t gpio = be_toint(vm, 4); + int32_t rmt = 0; + int32_t neopixel_type = ws2812_grb; + if (argc >= 5 && !(be_isnil(vm, 5))) { + neopixel_type = be_toint(vm, 5); + } + if (neopixel_type < 1) { neopixel_type = 1; } + if (neopixel_type >= neopixel_type_end) { neopixel_type = neopixel_type_end - 1; } + + // store type in attribute `_t` + be_pushint(vm, neopixel_type); + be_setmember(vm, 1, "_t"); + be_pop(vm, 1); + + if (PinUsed(GPIO_WS2812)) { + rmt = 1; // if WS2812 is already configured by Tasmota UI, we switch to RMT1 + } + if (argc >= 6 && !(be_isnil(vm, 6))) { + rmt = be_toint(vm, 6); // if arg5, then RMT channel is specified + } + if (rmt < 0) { rmt = 0; } + if (rmt >= MAX_RMT) { rmt = MAX_RMT - 1; } + void * strip = nullptr; + switch (neopixel_type) { + case ws2812_grb: strip = new neopixel_ws2812_grb_t(leds, gpio, (NeoBusChannel) rmt); + break; + case ws2812_grbw: strip = new neopixel_ws2812_grbw_t(leds, gpio, (NeoBusChannel) rmt); + break; + case sk6812_grb: strip = new neopixel_sk6812_grb_t(leds, gpio, (NeoBusChannel) rmt); + break; + case sk6812_grbw: strip = new neopixel_sk6812_grbw_t(leds, gpio, (NeoBusChannel) rmt); + break; + } + be_pushcomptr(vm, (void*) strip); + be_setmember(vm, 1, "_p"); + be_pop(vm, 1); + be_pushnil(vm); + } else { + // all other commands need a valid neopixelbus pointer + int32_t leds_type = be_get_leds_type(vm); + const void * s = be_get_neopixelbus(vm); // raises an exception if pointer is invalid + // initialize all possible variants + neopixel_ws2812_grb_t * s_ws2812_grb = (leds_type == ws2812_grb) ? (neopixel_ws2812_grb_t*) s : nullptr; + neopixel_ws2812_grbw_t * s_ws2812_grbw = (leds_type == ws2812_grbw) ? (neopixel_ws2812_grbw_t*) s : nullptr; + neopixel_sk6812_grb_t * s_sk6812_grb = (leds_type == sk6812_grb) ? (neopixel_sk6812_grb_t*) s : nullptr; + neopixel_sk6812_grbw_t * s_sk6812_grbw = (leds_type == sk6812_grbw) ? (neopixel_sk6812_grbw_t*) s : nullptr; + + be_pushnil(vm); // push a default `nil` return value + + switch (cmd) { + case 1: // # 01 : begin void -> void + if (s_ws2812_grb) s_ws2812_grb->Begin(); + if (s_ws2812_grbw) s_ws2812_grbw->Begin(); + if (s_sk6812_grb) s_sk6812_grb->Begin(); + if (s_sk6812_grbw) s_sk6812_grbw->Begin(); + break; + case 2: // # 02 : show void -> void + if (s_ws2812_grb) s_ws2812_grb->Show(); + if (s_ws2812_grbw) s_ws2812_grbw->Show(); + if (s_sk6812_grb) s_sk6812_grb->Show(); + if (s_sk6812_grbw) s_sk6812_grbw->Show(); + break; + case 3: // # 03 : CanShow void -> bool + if (s_ws2812_grb) be_pushbool(vm, s_ws2812_grb->CanShow()); + if (s_ws2812_grbw) be_pushbool(vm, s_ws2812_grbw->CanShow()); + if (s_sk6812_grb) be_pushbool(vm, s_sk6812_grb->CanShow()); + if (s_sk6812_grbw) be_pushbool(vm, s_sk6812_grbw->CanShow()); + break; + case 4: // # 04 : IsDirty void -> bool + if (s_ws2812_grb) be_pushbool(vm, s_ws2812_grb->IsDirty()); + if (s_ws2812_grbw) be_pushbool(vm, s_ws2812_grbw->IsDirty()); + if (s_sk6812_grb) be_pushbool(vm, s_sk6812_grb->IsDirty()); + if (s_sk6812_grbw) be_pushbool(vm, s_sk6812_grbw->IsDirty()); + break; + case 5: // # 05 : Dirty void -> void + if (s_ws2812_grb) s_ws2812_grb->Dirty(); + if (s_ws2812_grbw) s_ws2812_grbw->Dirty(); + if (s_sk6812_grb) s_sk6812_grb->Dirty(); + if (s_sk6812_grbw) s_sk6812_grbw->Dirty(); + break; + case 6: // # 06 : Pixels void -> bytes() (mapped to the buffer) + { + size_t pixels_bytes; + if (s_ws2812_grb) pixels_bytes = s_ws2812_grb->PixelsSize(); + if (s_ws2812_grbw) pixels_bytes = s_ws2812_grbw->PixelsSize(); + if (s_sk6812_grb) pixels_bytes = s_sk6812_grb->PixelsSize(); + if (s_sk6812_grbw) pixels_bytes = s_sk6812_grbw->PixelsSize(); + + uint8_t * pixels; + if (s_ws2812_grb) pixels = s_ws2812_grb->Pixels(); + if (s_ws2812_grbw) pixels = s_ws2812_grbw->Pixels(); + if (s_sk6812_grb) pixels = s_sk6812_grb->Pixels(); + if (s_sk6812_grbw) pixels = s_sk6812_grbw->Pixels(); + + be_getbuiltin(vm, "bytes"); + be_pushcomptr(vm, pixels); + be_pushint(vm, pixels_bytes); + be_call(vm, 2); + be_pop(vm, 2); + } + break; + case 7: // # 07 : PixelSize void -> int + if (s_ws2812_grb) be_pushint(vm, s_ws2812_grb->PixelSize()); + if (s_ws2812_grbw) be_pushint(vm, s_ws2812_grbw->PixelSize()); + if (s_sk6812_grb) be_pushint(vm, s_sk6812_grb->PixelSize()); + if (s_sk6812_grbw) be_pushint(vm, s_sk6812_grbw->PixelSize()); + break; + case 8: // # 08 : PixelCount void -> int + if (s_ws2812_grb) be_pushint(vm, s_ws2812_grb->PixelCount()); + if (s_ws2812_grbw) be_pushint(vm, s_ws2812_grbw->PixelCount()); + if (s_sk6812_grb) be_pushint(vm, s_sk6812_grb->PixelCount()); + if (s_sk6812_grbw) be_pushint(vm, s_sk6812_grbw->PixelCount()); + break; + case 9: // # 09 : ClearTo (color:??) -> void + { + uint32_t rgbw = be_toint(vm, 3); + uint8_t w = (rgbw & 0xFF000000) >> 24; + uint8_t r = (rgbw & 0xFF0000) >> 16; + uint8_t g = (rgbw & 0xFF00) >> 8; + uint8_t b = (rgbw & 0xFF); + if (s_ws2812_grb) s_ws2812_grb->ClearTo(RgbColor(r, g, b)); + if (s_ws2812_grbw) s_ws2812_grbw->ClearTo(RgbwColor(r, g, b, 0)); + if (s_sk6812_grb) s_sk6812_grb->ClearTo(RgbColor(r, g, b)); + if (s_sk6812_grbw) s_sk6812_grbw->ClearTo(RgbwColor(r, g, b, 0)); + } + break; + case 10: // # 10 : SetPixelColor (idx:int, color:??) -> void + { + int32_t idx = be_toint(vm, 3); + uint32_t rgbw = be_toint(vm, 4); + uint8_t w = (rgbw & 0xFF000000) >> 24; + uint8_t r = (rgbw & 0xFF0000) >> 16; + uint8_t g = (rgbw & 0xFF00) >> 8; + uint8_t b = (rgbw & 0xFF); + if (s_ws2812_grb) s_ws2812_grb->SetPixelColor(idx, RgbColor(r, g, b)); + if (s_ws2812_grbw) s_ws2812_grbw->SetPixelColor(idx, RgbwColor(r, g, b, 0)); + if (s_sk6812_grb) s_sk6812_grb->SetPixelColor(idx, RgbColor(r, g, b)); + if (s_sk6812_grbw) s_sk6812_grbw->SetPixelColor(idx, RgbwColor(r, g, b, 0)); + } + break; + case 11: // # 11 : GetPixelColor (idx:int) -> color:?? + { + int32_t idx = be_toint(vm, 3); + RgbColor rgb; + + if (s_ws2812_grb) { + RgbColor rgb = s_ws2812_grb->GetPixelColor(idx); + be_pushint(vm, (rgb.R << 16) | (rgb.G << 8) | rgb.B); + } + if (s_ws2812_grbw) { + RgbwColor rgbw = s_ws2812_grbw->GetPixelColor(idx); + be_pushint(vm, (rgbw.W << 24) | (rgb.R << 16) | (rgb.G << 8) | rgb.B); + } + if (s_sk6812_grb) { + RgbColor rgb = s_sk6812_grb->GetPixelColor(idx); + be_pushint(vm, (rgb.R << 16) | (rgb.G << 8) | rgb.B); + } + if (s_sk6812_grbw) { + RgbwColor rgbw = s_sk6812_grbw->GetPixelColor(idx); + be_pushint(vm, (rgbw.W << 24) | (rgb.R << 16) | (rgb.G << 8) | rgb.B); + } + } + break; + // case 20: // # 20 : RotateLeft (rot:int [, first:int, last:int]) -> void + // case 21: // # 21 : RotateRight (rot:int [, first:int, last:int]) -> void + // case 22: // # 22 : ShiftLeft (rot:int [, first:int, last:int]) -> void + // case 23: // # 23 : ShiftRight (rot:int [, first:int, last:int]) -> void + // { + // int32_t rot = be_toint(vm, 3); + // int32_t first = -1; + // int32_t last = -1; + // if (argc >= 5) { + // first = be_toint(vm, 4); + // last = be_toint(vm, 5); + // } + // if (20 == cmd) { + // if (first >= 0) { strip->RotateLeft(rot, first, last); } else { strip->RotateLeft(rot); }; + // } else if (21 == cmd) { + // if (first >= 0) { strip->RotateRight(rot, first, last); } else { strip->RotateRight(rot); }; + // } else if (22 == cmd) { + // if (first >= 0) { strip->ShiftLeft(rot, first, last); } else { strip->ShiftLeft(rot); }; + // } else if (23 == cmd) { + // if (first >= 0) { strip->ShiftRight(rot, first, last); } else { strip->ShiftRight(rot); }; + // } + // } + // break; + default: + break; + } + } + be_return(vm); + } + be_raise(vm, kTypeError, nullptr); + } + +} + +#endif // USE_WS2812 +#endif // USE_BERRY diff --git a/tasmota/xdrv_52_9_berry.ino b/tasmota/xdrv_52_9_berry.ino index 84a7b962a..c2ed977be 100644 --- a/tasmota/xdrv_52_9_berry.ino +++ b/tasmota/xdrv_52_9_berry.ino @@ -780,9 +780,6 @@ bool Xdrv52(uint8_t function) case FUNC_MQTT_DATA: result = callBerryEventDispatcher(PSTR("mqtt_data"), XdrvMailbox.topic, 0, XdrvMailbox.data, XdrvMailbox.data_len); break; - case FUNC_EVERY_50_MSECOND: - callBerryEventDispatcher(PSTR("every_50ms"), nullptr, 0, nullptr); - break; case FUNC_COMMAND: result = DecodeCommand(kBrCommands, BerryCommand); if (!result) { @@ -791,6 +788,9 @@ bool Xdrv52(uint8_t function) break; // Module specific events + case FUNC_EVERY_50_MSECOND: + callBerryEventDispatcher(PSTR("every_50ms"), nullptr, 0, nullptr); + break; case FUNC_EVERY_100_MSECOND: callBerryEventDispatcher(PSTR("every_100ms"), nullptr, 0, nullptr); break;