diff --git a/CHANGELOG.md b/CHANGELOG.md
index e66fc9fa0..35534baa8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,12 +11,14 @@ All notable changes to this project will be documented in this file.
- ESP32 Hybrid compile take custom boards settings in account (#22542)
### Breaking Changed
+- ArtNet on ESP32 switches from GRB to RGB encoding
### Changed
- ESP32 max number of supported switches/buttons/relays from 28 to 32
- ESP32 max number of interlocks from 14 to 16
- ESP32 Platform from 2024.11.30 to 2024.11.31, Framework (Arduino Core) from v3.1.0.241030 to v3.1.0.241117 and IDF to 5.3.1.241024 (#22504)
- Prevent active BLE operations with unencrypted MI-format beacons (#22453)
+- Replace NeoPixelBus with TasmotaLED on ESP32x
### Fixed
- ESP32 upgrade by file upload response based on file size (#22500)
diff --git a/lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32RmtMethod_idf5.h b/lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32RmtMethod_idf5.h
index a86b05330..d26aece56 100644
--- a/lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32RmtMethod_idf5.h
+++ b/lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32RmtMethod_idf5.h
@@ -69,7 +69,7 @@ typedef struct {
rmt_symbol_word_t reset_code;
} rmt_led_strip_encoder_t;
-static size_t rmt_encode_led_strip(rmt_encoder_t *encoder, rmt_channel_handle_t channel, const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state)
+static IRAM_ATTR size_t rmt_encode_led_strip(rmt_encoder_t *encoder, rmt_channel_handle_t channel, const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state)
{
rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base);
rmt_encoder_handle_t bytes_encoder = led_encoder->bytes_encoder;
diff --git a/lib/lib_basic/TasmotaLED/library.json b/lib/lib_basic/TasmotaLED/library.json
new file mode 100644
index 000000000..8ee6079f5
--- /dev/null
+++ b/lib/lib_basic/TasmotaLED/library.json
@@ -0,0 +1,17 @@
+{
+ "name": "TasmotaLED",
+ "version": "0.1",
+ "keywords": [
+ "ws2816", "sk6812", "leds"
+ ],
+ "description": "Lightweight implementation for adressable leds.",
+ "repository":
+ {
+ "type": "git",
+ "url": "https://github.com/arendst/Tasmota/lib/lib_basic/TasmotaLED"
+ },
+ "frameworks": "arduino",
+ "platforms": [
+ "espressif32"
+ ]
+}
diff --git a/lib/lib_basic/TasmotaLED/src/TasmotaLED.cpp b/lib/lib_basic/TasmotaLED/src/TasmotaLED.cpp
new file mode 100644
index 000000000..d323c20ab
--- /dev/null
+++ b/lib/lib_basic/TasmotaLED/src/TasmotaLED.cpp
@@ -0,0 +1,237 @@
+/*
+ TasmotaLED.cpp - Lightweight implementation for adressable leds.
+
+ Copyright (C) 2024 Stephan Hadinger
+
+ This library 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 .
+*/
+
+#include
+#ifdef ESP32
+
+#include "TasmotaLEDPusher.h"
+#include "TasmotaLED.h"
+
+// DRAM_ATTR to force in IRAM because we use this in show loop
+static const DRAM_ATTR uint8_t TASMOTALED_CHANNEL_ORDERS[6][3] = {
+ {1, 0, 2}, // GRB (0)
+ {2, 0, 1}, // GBR (1)
+ {0, 1, 2}, // RGB (2)
+ {0, 2, 1}, // RBG (3)
+ {2, 1, 0}, // BRG (4)
+ {1, 2, 0} // BGR (5)
+};
+
+static const TasmotaLED_Timing TasmotaLED_Timings[] = {
+ // WS2812
+ // RmtBit0 0x00228010 RmtBit1 0x00128020 RmtReset 0x800207D0
+ {
+ .T0H = 400,
+ .T0L = 850,
+ .T1H = 800,
+ .T1L = 450,
+ .Reset = 80000 // it is 50000 for WS2812, but for compatibility with SK6812, we raise to 80000
+ },
+ // SK6812
+ // RmtBit0 0x0024800C RmtBit1 0x00188018 RmtReset 0x80020C80
+ {
+ .T0H = 300,
+ .T0L = 900,
+ .T1H = 600,
+ .T1L = 600,
+ .Reset = 80000
+ },
+};
+
+// enable AddLog
+extern void AddLog(uint32_t loglevel, PGM_P formatP, ...);
+enum LoggingLevels {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE};
+
+
+TasmotaLED::TasmotaLED(uint16_t type, uint16_t num_leds) :
+ _type(type),
+ _pixel_order((type >> 4) & 0x07),
+ _w_before(type & 0x08),
+ _timing((type >> 8) & 0xFF),
+ _started(false),
+ _dirty(true),
+ _raw_format(false),
+ _pixel_count(num_leds),
+ _buf_work(nullptr),
+ _buf_show(nullptr),
+ _pixel_matrix(&TASMOTALED_CHANNEL_ORDERS[0]),
+ _pusher(nullptr)
+{
+ if (_timing > (TasmotaLed_TimingEnd >> 8)) {
+ _timing = 0;
+ }
+ switch (_type & 0x0F) {
+ // case TasmotaLed_1_W:
+ // _pixel_size = 1;
+ // break;
+ case TasmotaLed_4_WRGB:
+ _pixel_size = 4;
+ break;
+ case TasmotaLed_3_RGB:
+ default: // fallback
+ _pixel_size = 3;
+ break;
+ }
+
+ _pixel_matrix = &TASMOTALED_CHANNEL_ORDERS[_pixel_order];
+
+ _buf_work = new uint8_t[_pixel_count * _pixel_size];
+ memset(_buf_work, 0, _pixel_count * _pixel_size);
+ _buf_show = new uint8_t[_pixel_count * _pixel_size];
+ memset(_buf_show, 0, _pixel_count * _pixel_size);
+ // AddLog(LOG_LEVEL_DEBUG, "LED: type=0x%04X pixel_order=0x%02X _timing=%i ", _type, _pixel_order, _timing);
+}
+
+TasmotaLED::~TasmotaLED() {
+ if (_pusher) {
+ delete _pusher;
+ _pusher = nullptr;
+ }
+ delete _buf_work;
+ _buf_work = nullptr;
+ delete _buf_show;
+ _buf_show = nullptr;
+}
+
+// Color is passed as 0xWWRRGGBB and copied as WWRRGGBB in _buf_work
+void TasmotaLED::ClearTo(uint32_t wrgb, int32_t first, int32_t last) {
+ // adjust first and last to be in range of 0 to _pixel_count-1
+ if (first <0) { first += _pixel_count; }
+ if (last <0) { last += _pixel_count; }
+ if (first < 0) { first = 0; }
+ if (last >= _pixel_count) { last = _pixel_count - 1; }
+ if (first > last) { return; }
+ // adjust to pixel format
+ uint8_t b0 = (wrgb >> 24) & 0xFF;
+ uint8_t b1 = (wrgb >> 16) & 0xFF;
+ uint8_t b2 = (wrgb >> 8) & 0xFF;
+ uint8_t b3 = (wrgb ) & 0xFF;
+
+ if ((b0 | b1 | b2 | b3) == 0) {
+ // special version for clearing to black
+ memset(_buf_work + first * _pixel_size, 0, (last - first + 1) * _pixel_size);
+ } else {
+ // fill sub-buffer with RRGGBB or WWRRGGBB (or raw)
+ uint8_t *buf = _buf_work + first * _pixel_size;
+ for (uint32_t i = first; i <= last; i++) {
+ if (_pixel_size == 4) { *buf++ = b0;}
+ *buf++ = b1;
+ *buf++ = b2;
+ *buf++ = b3;
+ }
+ }
+}
+
+void TasmotaLED::Show(void) {
+ if (_pusher) {
+ _dirty = false; // we don't use the _dirty attribute and always show
+
+ // copy the input buffer to the work buffer in format to be understood by LED strip
+ if (_raw_format) {
+ memmove(_buf_show, _buf_work, _pixel_count * _pixel_size); // copy buffer in next buffer so we start with the current content
+ } else {
+ uint8_t *buf_from = _buf_work;
+ uint8_t *buf_to = _buf_show;
+ if (_pixel_size == 3) {
+ // copying with swapping 512 pixels (1536 bytes) takes 124 microseconds to copy, so it's negligeable
+ for (uint32_t i = 0; i < _pixel_count; i++) {
+ buf_to[(*_pixel_matrix)[0]] = buf_from[0]; // R
+ buf_to[(*_pixel_matrix)[1]] = buf_from[1]; // G
+ buf_to[(*_pixel_matrix)[2]] = buf_from[2]; // B
+ buf_to += 3;
+ buf_from += 3;
+ }
+ } else if (_pixel_size == 4) {
+ for (uint32_t i = 0; i < _pixel_count; i++) {
+ if (_w_before) { *buf_to++ = buf_from[3]; }
+ buf_to[(*_pixel_matrix)[0]] = buf_from[0]; // R
+ buf_to[(*_pixel_matrix)[1]] = buf_from[1]; // G
+ buf_to[(*_pixel_matrix)[2]] = buf_from[2]; // B
+ if (!_w_before) { *buf_to++ = buf_from[3]; }
+ buf_to += 3; // one increment already happened
+ buf_from += 4;
+ }
+ }
+ }
+ _pusher->Push(_buf_show); // push to leds
+ }
+}
+
+void TasmotaLED::SetPixelColor(int32_t index, uint32_t wrgb) {
+ if (index < 0) { index += _pixel_count; }
+ if ((index >= 0) && (index < _pixel_count)) {
+ uint8_t *buf = _buf_work + index * _pixel_size;
+ uint8_t b0 = (wrgb >> 24) & 0xFF;
+ uint8_t b1 = (wrgb >> 16) & 0xFF;
+ uint8_t b2 = (wrgb >> 8) & 0xFF;
+ uint8_t b3 = (wrgb ) & 0xFF;
+
+ if (_pixel_size == 4) { *buf++ = b0;}
+ *buf++ = b1;
+ *buf++ = b2;
+ *buf++ = b3;
+ _dirty = true;
+ }
+}
+
+uint32_t TasmotaLED::GetPixelColor(int32_t index) {
+ if (index < 0) { index += _pixel_count; }
+ if ((index >= 0) && (index < _pixel_count)) {
+ uint8_t *buf = _buf_work + index * _pixel_size;
+ uint32_t wrgb = 0;
+ if (_pixel_size == 4) { wrgb = (*buf++) << 24; }
+ wrgb |= (*buf++) << 16;
+ wrgb |= (*buf++) << 8;
+ wrgb |= (*buf++);
+ return wrgb;
+ } else {
+ return 0;
+ }
+}
+
+void TasmotaLED::SetPusher(TasmotaLEDPusher *pusher) {
+ if (_pusher) {
+ delete _pusher;
+ }
+ _pusher = pusher;
+ _started = false;
+}
+
+bool TasmotaLED::Begin(void) {
+ if (_pusher) {
+ if (_started) {
+ return true;
+ } else {
+ const TasmotaLED_Timing * timing = &TasmotaLED_Timings[_timing];
+ // AddLog(LOG_LEVEL_DEBUG, "LED: T0H=%i T0L=%i T1H=%i T1L=%i Reset=%i", timing.T0H, timing.T0L, timing.T1H, timing.T1L, timing.Reset);
+ return _pusher->Begin(_pixel_count, _pixel_size, timing);
+ }
+ } else {
+ return false;
+ }
+}
+
+bool TasmotaLED::CanShow(void) const {
+ if (_pusher) {
+ return _pusher->CanShow();
+ }
+ return false;
+}
+
+#endif // ESP32
diff --git a/lib/lib_basic/TasmotaLED/src/TasmotaLED.h b/lib/lib_basic/TasmotaLED/src/TasmotaLED.h
new file mode 100644
index 000000000..ac1b78c1e
--- /dev/null
+++ b/lib/lib_basic/TasmotaLED/src/TasmotaLED.h
@@ -0,0 +1,129 @@
+/*
+ TasmotaLED.h - Lightweight implementation for adressable leds.
+
+ Copyright (C) 2024 Stephan Hadinger
+
+ This library 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 .
+*/
+
+#ifndef __TASMOTALED_H__
+#define __TASMOTALED_H__
+
+enum TasmotaLEDTypesEncoding : uint16_t {
+ // bits 0..3 encode for number of bytes per pixel
+ TasmotaLed_1_W = 0x0, // 1 byte per pixel (not used yet)
+ TasmotaLed_3_RGB = 0x1, // 3 bytes per pixel
+ TasmotaLed_4_WRGB = 0x2, // 4 bytes per pixel
+ // bits 4..6 encode for pixel order
+ TasmotaLed_GRB = 0b000 << 4,
+ TasmotaLed_GBR = 0b001 << 4,
+ TasmotaLed_RGB = 0b010 << 4,
+ TasmotaLed_RBG = 0b011 << 4,
+ TasmotaLed_BRG = 0b100 << 4,
+ TasmotaLed_BGR = 0b101 << 4,
+ // bit 7 sets the position for W channel
+ TasmotaLed_xxxW = 0b0 << 7, // W channel after color
+ TasmotaLed_Wxxx = 0b1 << 7, // W channel before color
+ // bits 8..15 encode for timing specifics
+ TasmotaLed_WS2812 = 0 << 8,
+ TasmotaLed_SK6812 = 1 << 8,
+ TasmotaLed_TimingEnd = 2 << 8,
+};
+
+enum TasmotaLEDHardware : uint32_t {
+ // low-order bits are reserved for channels numbers and hardware flags - currenlty not useds
+ // bits 16..23
+ TasmotaLed_HW_Default = 0x0 << 16,
+ TasmotaLed_RMT = 1 << 16,
+ TasmotaLed_SPI = 2 << 16,
+ TasmotaLed_I2S = 3 << 16,
+ TasmotaLed_HW_None = 0xFF << 16, // indicates that the specified HW is not supported
+};
+
+// Below is the encoding for full strips
+// We need to keep backwards compatibility so:
+// 0 = WS2812 (GRB)
+// 1 = SK6812 with White (GRBW)
+enum TasmotaLEDTypes : uint16_t {
+ ws2812_grb = TasmotaLed_3_RGB | TasmotaLed_GRB | TasmotaLed_WS2812, // 1 for backwards compatibility
+ sk6812_grbw = TasmotaLed_4_WRGB | TasmotaLed_GRB | TasmotaLed_xxxW | TasmotaLed_SK6812, // 2 for backwards compatibility
+ sk6812_grb = TasmotaLed_3_RGB | TasmotaLed_GRB | TasmotaLed_SK6812,
+};
+
+#ifdef __cplusplus
+
+/*******************************************************************************************\
+ * class TasmotaLED
+ *
+ * This class is a lightweight replacement for NeoPixelBus library with a smaller
+ * implementation focusing only on pushing a buffer to the leds.
+ *
+ * It supports:
+ * - RMT and I2S hardware support
+ * Possible enhancements could be considered with SPI and Serial
+ * - Led size of 3 bytes (GRB) and 4 bytes (GRBW)
+ * APIs take 0xRRGGBB or 0xRRGGBBWW as input
+ * but Internal buffers use GGRRBB and GGRRBBWW
+ * - Led type of WS2812 and SK6812
+ * - There is no buffer swapping, the working buffer is copied to an internal
+ * buffer just before display, so you can keep a reference to the buffer
+ * and modify it without having to worry about the display
+ * - buffer is cleared at start
+ * - "Dirty" is kept for API compatibility with NeoPixelBus but is glbally ignored
+ * so any call to `Show()` pushes the pixels even if they haven't changed.
+ * Control for dirty pixels should be done by the caller if required.
+ * - We tried to keep as close as possible to NeoPixelBus method names to ease transition
+\*******************************************************************************************/
+class TasmotaLEDPusher; // forward definition
+class TasmotaLED {
+public:
+ TasmotaLED(uint16_t type, uint16_t num_leds);
+ ~TasmotaLED();
+
+ bool Begin(void);
+ void SetPusher(TasmotaLEDPusher *pusher); // needs to be called before `Begin()`, sets the hardware implementation
+ void Show(void); // pushes the pixels to the LED strip
+ inline void SetRawFormat(bool raw_format) { _raw_format = raw_format; }
+
+ void ClearTo(uint32_t rgbw, int32_t first = 0, int32_t last = -1);
+ void SetPixelColor(int32_t index, uint32_t wrgb);
+ uint32_t GetPixelColor(int32_t index);
+
+ uint8_t GetType(void) const { return _type; }
+ uint16_t PixelCount(void) const { return _pixel_count; }
+ uint8_t PixelSize(void) const { return _pixel_size; }
+ inline uint8_t * Pixels(void) const { return _buf_work; }
+ inline bool IsDirty(void) const { return _dirty; }
+ inline void Dirty(void) { _dirty = true; }
+
+ bool CanShow(void) const;
+
+protected:
+ uint16_t _type; // the composite type
+ uint8_t _pixel_order; // permutation between RGB and position of W
+ bool _w_before; // true if W channel comes first (4 channels only)
+ uint8_t _timing; // timing code for strip, 0=WS2812, 1=SK6812...
+ bool _started; // true if the hardware implementation is configured
+ bool _dirty; // for NeoPixelBus compatibility, but ignored by `Push()`
+ bool _raw_format; // if true, copy raw to leds, if false, convert from RGB to GRB or LED format
+ uint16_t _pixel_count; // how many pixels in the strip
+ uint8_t _pixel_size; // how many bytes per pixels, only 3 and 4 are supported
+ uint8_t *_buf_work; // buffer used to draw into, can be modified directly by the caller
+ uint8_t *_buf_show; // copy of the buffer used to push to leds, private to this class
+ const uint8_t (*_pixel_matrix)[3]; // pointer to the pixer_order_matrix
+ TasmotaLEDPusher *_pusher; // pixels pusher implementation based on hardware (RMT, I2S...)
+};
+
+#endif // __cplusplus
+#endif // __TASMOTALED_H__
diff --git a/lib/lib_basic/TasmotaLED/src/TasmotaLEDPusher.cpp b/lib/lib_basic/TasmotaLED/src/TasmotaLEDPusher.cpp
new file mode 100644
index 000000000..d765703e5
--- /dev/null
+++ b/lib/lib_basic/TasmotaLED/src/TasmotaLEDPusher.cpp
@@ -0,0 +1,97 @@
+/*
+ TasmotaLEDPusher.cpp - Implementation to push Leds via hardware acceleration
+
+ Copyright (C) 2024 Stephan Hadinger
+
+ This library 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 ESP32
+
+#include "TasmotaLEDPusher.h"
+#include "TasmotaLED.h"
+
+//**************************************************************************************************************
+// enable AddLog support within a C++ library
+extern void AddLog(uint32_t loglevel, PGM_P formatP, ...);
+enum LoggingLevels {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE};
+//**************************************************************************************************************
+
+
+// convert to the appropriate hardware acceleration based on capacities of the SOC
+uint32_t TasmotaLEDPusher::ResolveHardware(uint32_t hw) {
+uint32_t hw_orig = hw;
+ // Step 1. discard any unsupported hardware, and replace with TasmotaLed_HW_Default
+ uint32_t hw_type = hw & 0xFF0000; // discard bits 0..15
+#if !TASMOTALED_HARDWARE_RMT
+ if (hw_type == TasmotaLed_RMT) {
+ hw = TasmotaLed_HW_None;
+ }
+#endif // TASMOTALED_HARDWARE_RMT
+#if !TASMOTALED_HARDWARE_SPI
+ if (hw_type == TasmotaLed_SPI) {
+ hw = TasmotaLed_HW_None;
+ }
+#endif // TASMOTALED_HARDWARE_SPI
+#if !TASMOTALED_HARDWARE_I2S
+ if (hw_type == TasmotaLed_I2S) {
+ hw = TasmotaLed_HW_None;
+ }
+#endif // TASMOTALED_HARDWARE_I2S
+
+ // Step 2. If TasmotaLed_HW_Default, find a suitable scheme, RMT preferred
+#if TASMOTALED_HARDWARE_RMT
+ if ((hw & 0xFF0000) == TasmotaLed_HW_Default) {
+ hw = TasmotaLed_RMT;
+ }
+#endif // TASMOTALED_HARDWARE_RMT
+#if TASMOTALED_HARDWARE_I2S
+ if ((hw & 0xFF0000) == TasmotaLed_HW_Default) {
+ hw = TasmotaLed_I2S;
+ }
+#endif // TASMOTALED_HARDWARE_I2S
+#if TASMOTALED_HARDWARE_SPI
+ if ((hw & 0xFF0000) == TasmotaLed_HW_Default) {
+ hw = TasmotaLed_SPI;
+ }
+#endif // TASMOTALED_HARDWARE_SPI
+ return hw;
+}
+
+
+TasmotaLEDPusher * TasmotaLEDPusher::Create(uint32_t hw, int8_t gpio) {
+ TasmotaLEDPusher * pusher = nullptr;
+
+ hw = TasmotaLEDPusher::ResolveHardware(hw);
+
+ switch (hw & 0XFF0000) {
+#if TASMOTALED_HARDWARE_RMT
+ case TasmotaLed_RMT:
+ pusher = new TasmotaLEDPusherRMT(gpio);
+ AddLog(LOG_LEVEL_DEBUG, "LED: RMT gpio %i", gpio);
+ break;
+#endif // TASMOTALED_HARDWARE_RMT
+#if TASMOTALED_HARDWARE_SPI
+ case TasmotaLed_SPI:
+ pusher = new TasmotaLEDPusherSPI(gpio);
+ AddLog(LOG_LEVEL_DEBUG, "LED: SPI gpio %i", gpio);
+ break;
+#endif // TASMOTALED_HARDWARE_SPI
+ default:
+ break;
+ }
+ return pusher;
+}
+
+#endif // ESP32
diff --git a/lib/lib_basic/TasmotaLED/src/TasmotaLEDPusher.h b/lib/lib_basic/TasmotaLED/src/TasmotaLEDPusher.h
new file mode 100644
index 000000000..2b8eb4896
--- /dev/null
+++ b/lib/lib_basic/TasmotaLED/src/TasmotaLEDPusher.h
@@ -0,0 +1,161 @@
+/*
+ TasmotaLEDPusher.h - Abstract class for Leds pusher (RMT, SPI, I2S...)
+
+ Copyright (C) 2024 Stephan Hadinger
+
+ This library 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 .
+*/
+
+#ifndef __TASMOTALEDPUSHER_H__
+#define __TASMOTALEDPUSHER_H__
+
+#include
+
+// Below are flags to enable of disable each hardware support: RMT, I2S, SPI
+// By default, only enable RMT support, and SPI is used as fallback if no protocol works
+//
+// Use de defines below:
+// #define TASMOTALED_HARDWARE_RMT 0/1
+// #define TASMOTALED_HARDWARE_I2S 0/1
+// #define TASMOTALED_HARDWARE_SPI 0/1
+//
+#ifndef TASMOTALED_HARDWARE_RMT
+ #define TASMOTALED_HARDWARE_RMT 1
+#endif
+
+#ifndef TASMOTALED_HARDWARE_I2S
+ #define TASMOTALED_HARDWARE_I2S 0
+#endif
+
+#ifndef TASMOTALED_HARDWARE_SPI
+ #define TASMOTALED_HARDWARE_SPI 0
+#endif
+
+// Disable any hardware if not supported by the SOC
+#if TASMOTALED_HARDWARE_RMT && !defined(SOC_RMT_SUPPORTED)
+ #undef TASMOTALED_HARDWARE_RMT
+ #define TASMOTALED_HARDWARE_RMT 0
+#endif
+
+#if TASMOTALED_HARDWARE_I2S && !defined(SOC_I2S_SUPPORTED)
+ #undef TASMOTALED_HARDWARE_I2S
+ #define TASMOTALED_HARDWARE_I2S 0
+#endif
+
+#if TASMOTALED_HARDWARE_SPI && !defined(SOC_GPSPI_SUPPORTED)
+ #undef TASMOTALED_HARDWARE_SPI
+ #define TASMOTALED_HARDWARE_SPI 0
+#endif
+
+// if no protocol is defined, use SPI as fallback
+#if !TASMOTALED_HARDWARE_RMT && !TASMOTALED_HARDWARE_I2S && !TASMOTALED_HARDWARE_SPI
+ #undef TASMOTALED_HARDWARE_SPI
+ #define TASMOTALED_HARDWARE_SPI 1
+#endif
+
+// Timing structure for LEDS - in nanoseconds
+// It is passed by TasmotaLed to the pushers
+typedef struct TasmotaLED_Timing {
+ uint16_t T0H, T0L, T1H, T1L;
+ uint32_t Reset;
+} TasmotaLED_Timing;
+
+/*******************************************************************************************\
+ * class TasmotaLEDPusher
+ *
+ * This is an virtual abstract class for Leds pusher (RMT, SPI, I2S...)
+ *
+ * Below are interfaces for current implementations
+\*******************************************************************************************/
+class TasmotaLEDPusher {
+public:
+ TasmotaLEDPusher() : _pixel_count(0), _pixel_size(0), _led_timing(nullptr) {};
+ virtual ~TasmotaLEDPusher() {};
+
+ virtual bool Begin(uint16_t pixel_count, uint16_t pixel_size, const TasmotaLED_Timing * led_timing) {
+ _pixel_count = pixel_count;
+ _pixel_size = pixel_size;
+ _led_timing = led_timing;
+ return true;
+ }
+ virtual bool Push(uint8_t *buf) = 0;
+ virtual bool CanShow(void) = 0;
+
+ static uint32_t ResolveHardware(uint32_t hw); // convert to the appropriate hardware acceleration based on capacities of the SOC
+ static TasmotaLEDPusher * Create(uint32_t hw, int8_t gpio); // create instance for the provided type, or nullptr if failed
+
+protected:
+ uint16_t _pixel_count;
+ uint16_t _pixel_size;
+ const TasmotaLED_Timing * _led_timing;
+};
+
+/*******************************************************************************************\
+ * class TasmotaLEDPusherRMT
+ *
+ * Implementation based on RMT driver
+\*******************************************************************************************/
+#if TASMOTALED_HARDWARE_RMT
+#include "driver/rmt_tx.h"
+class TasmotaLEDPusherRMT : public TasmotaLEDPusher {
+public:
+ TasmotaLEDPusherRMT(int8_t pin) : _pin(pin) {};
+ ~TasmotaLEDPusherRMT();
+
+ bool Begin(uint16_t pixel_count, uint16_t pixel_size, const TasmotaLED_Timing * led_timing) override;
+
+ bool Push(uint8_t *buf) override;
+ bool CanShow(void) override;
+protected:
+ int8_t _pin;
+ rmt_transmit_config_t _tx_config = {};
+ rmt_channel_handle_t _channel = nullptr;;
+ rmt_encoder_handle_t _led_encoder = nullptr;
+};
+#endif // TASMOTALED_HARDWARE_RMT
+
+/*******************************************************************************************\
+ * class TasmotaLEDPusherSPI
+ *
+ * Implementation based on SPI driver, mandatory for C2
+\*******************************************************************************************/
+#if TASMOTALED_HARDWARE_SPI
+#include
+
+typedef struct led_strip_spi_obj_t {
+ uint8_t * pixel_buf;
+ uint16_t strip_len;
+ uint8_t bytes_per_pixel;
+ spi_host_device_t spi_host;
+ spi_device_handle_t spi_device;
+ spi_transaction_t tx_conf; // transaction in process if any
+} led_strip_spi_obj;
+
+class TasmotaLEDPusherSPI : public TasmotaLEDPusher {
+public:
+ TasmotaLEDPusherSPI(int8_t pin) : _pin(pin), _spi_strip({}) {};
+ ~TasmotaLEDPusherSPI();
+
+ bool Begin(uint16_t pixel_count, uint16_t pixel_size, const TasmotaLED_Timing * led_timing) override;
+
+ bool Push(uint8_t *buf) override;
+ bool CanShow(void) override;
+
+protected:
+ int8_t _pin;
+ struct led_strip_spi_obj_t _spi_strip;
+};
+#endif // TASMOTALED_HARDWARE_SPI
+
+#endif // __TASMOTALEDPUSHER_H__
diff --git a/lib/lib_basic/TasmotaLED/src/TasmotaLEDPusherRMT.cpp b/lib/lib_basic/TasmotaLED/src/TasmotaLEDPusherRMT.cpp
new file mode 100644
index 000000000..747985008
--- /dev/null
+++ b/lib/lib_basic/TasmotaLED/src/TasmotaLEDPusherRMT.cpp
@@ -0,0 +1,240 @@
+/*
+ TasmotaLEDPusherRMT.cpp - Implementation to push Leds via RMT channel
+
+ Copyright (C) 2024 Stephan Hadinger
+
+ This library 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 ESP32
+
+#include "TasmotaLEDPusher.h"
+#include "TasmotaLED.h"
+
+#if TASMOTALED_HARDWARE_RMT
+#include
+#include
+
+//**************************************************************************************************************
+// enable AddLog support within a C++ library
+extern void AddLog(uint32_t loglevel, PGM_P formatP, ...);
+enum LoggingLevels {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE};
+//**************************************************************************************************************
+
+/*******************************************************************************************\
+ * Implementation for TasmotaLEDPusherRMT
+ *
+ * Code mostly copied from Tasmota patch to NeoPixelBus applied to support esp-idf 5.x
+ * itself inspired from esp-idf example for RMT encoder from
+ * https://github.com/espressif/esp-idf/tree/v5.3.1/examples/peripherals/rmt/ir_nec_transceiver
+\*******************************************************************************************/
+#define RMT_LED_STRIP_RESOLUTION_HZ 40000000 // 40MHz resolution, steps of 25 nanoseconds
+
+// structure used to pass arguments to `rmt_new_led_strip_encoder`
+// currently only the encoder resolution in Hz
+typedef struct {
+ uint32_t resolution; /*!< Encoder resolution, in Hz */
+} led_strip_encoder_config_t;
+
+// structure used to store all the necessary information for the RMT encoder
+typedef struct {
+ rmt_encoder_t base;
+ rmt_encoder_t *bytes_encoder;
+ rmt_encoder_t *copy_encoder;
+ int32_t state;
+ rmt_symbol_word_t reset_code;
+} rmt_led_strip_encoder_t;
+
+static IRAM_ATTR size_t rmt_encode_led_strip(rmt_encoder_t *encoder, rmt_channel_handle_t channel, const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state)
+{
+ rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base);
+ rmt_encoder_handle_t bytes_encoder = led_encoder->bytes_encoder;
+ rmt_encoder_handle_t copy_encoder = led_encoder->copy_encoder;
+ rmt_encode_state_t session_state = RMT_ENCODING_RESET;
+ rmt_encode_state_t state = RMT_ENCODING_RESET;
+ size_t encoded_symbols = 0;
+ switch (led_encoder->state) {
+ case 0: // send RGB data
+ encoded_symbols += bytes_encoder->encode(bytes_encoder, channel, primary_data, data_size, &session_state);
+ if (session_state & RMT_ENCODING_COMPLETE) {
+ led_encoder->state = 1; // switch to next state when current encoding session finished
+ }
+ if (session_state & RMT_ENCODING_MEM_FULL) {
+ state = static_cast(static_cast(state) | static_cast(RMT_ENCODING_MEM_FULL));
+ goto out; // yield if there's no free space for encoding artifacts
+ }
+ // fall-through
+ case 1: // send reset code
+ encoded_symbols += copy_encoder->encode(copy_encoder, channel, &led_encoder->reset_code, sizeof(led_encoder->reset_code), &session_state);
+ if (session_state & RMT_ENCODING_COMPLETE) {
+ led_encoder->state = RMT_ENCODING_RESET; // back to the initial encoding session
+ state = static_cast(static_cast(state) | static_cast(RMT_ENCODING_COMPLETE));
+ }
+ if (session_state & RMT_ENCODING_MEM_FULL) {
+ state = static_cast(static_cast(state) | static_cast(RMT_ENCODING_MEM_FULL));
+ goto out; // yield if there's no free space for encoding artifacts
+ }
+ }
+out:
+ *ret_state = state;
+ return encoded_symbols;
+}
+
+static esp_err_t rmt_del_led_strip_encoder(rmt_encoder_t *encoder) {
+ rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base);
+ rmt_del_encoder(led_encoder->bytes_encoder);
+ rmt_del_encoder(led_encoder->copy_encoder);
+ delete led_encoder;
+ return ESP_OK;
+}
+
+static esp_err_t rmt_led_strip_encoder_reset(rmt_encoder_t *encoder) {
+ rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base);
+ rmt_encoder_reset(led_encoder->bytes_encoder);
+ rmt_encoder_reset(led_encoder->copy_encoder);
+ led_encoder->state = RMT_ENCODING_RESET;
+ return ESP_OK;
+}
+
+static esp_err_t rmt_new_led_strip_encoder(const led_strip_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder, rmt_symbol_word_t bit0, rmt_symbol_word_t bit1, rmt_symbol_word_t reset_code) {
+ static const char* TAG = "TASMOTA_RMT";
+ esp_err_t ret = ESP_OK;
+ rmt_led_strip_encoder_t *led_encoder = NULL;
+ rmt_bytes_encoder_config_t bytes_encoder_config;
+ rmt_copy_encoder_config_t copy_encoder_config = {};
+
+ ESP_GOTO_ON_FALSE(config && ret_encoder, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
+ led_encoder = new rmt_led_strip_encoder_t();
+ ESP_GOTO_ON_FALSE(led_encoder, ESP_ERR_NO_MEM, err, TAG, "no mem for led strip encoder");
+ led_encoder->base.encode = rmt_encode_led_strip;
+ led_encoder->base.del = rmt_del_led_strip_encoder;
+ led_encoder->base.reset = rmt_led_strip_encoder_reset;
+ led_encoder->reset_code = reset_code;
+
+ bytes_encoder_config.bit0 = bit0;
+ bytes_encoder_config.bit1 = bit1;
+ bytes_encoder_config.flags.msb_first = 1; // WS2812 transfer bit order: G7...G0R7...R0B7...B0 - TODO: more checks
+
+ ESP_GOTO_ON_ERROR(rmt_new_bytes_encoder(&bytes_encoder_config, &led_encoder->bytes_encoder), err, TAG, "create bytes encoder failed");
+ ESP_GOTO_ON_ERROR(rmt_new_copy_encoder(©_encoder_config, &led_encoder->copy_encoder), err, TAG, "create copy encoder failed");
+
+ *ret_encoder = &led_encoder->base;
+ return ret;
+err:
+ AddLog(LOG_LEVEL_INFO, "RMT: could not init led encoder");
+ if (led_encoder) {
+ if (led_encoder->bytes_encoder) { rmt_del_encoder(led_encoder->bytes_encoder); }
+ if (led_encoder->copy_encoder) { rmt_del_encoder(led_encoder->copy_encoder); }
+ delete led_encoder;
+ }
+ return ret;
+}
+
+TasmotaLEDPusherRMT::~TasmotaLEDPusherRMT() {
+ if (_channel) {
+ rmt_tx_wait_all_done(_channel, 10000 / portTICK_PERIOD_MS);
+ rmt_del_channel(_channel);
+ _channel = nullptr;
+ }
+
+ if (_pin >= 0) {
+ gpio_matrix_out(_pin, 0x100, false, false);
+ pinMode(_pin, INPUT);
+ _pin = -1;
+ }
+}
+
+bool TasmotaLEDPusherRMT::Begin(uint16_t pixel_count, uint16_t pixel_size, const TasmotaLED_Timing * led_timing) {
+ TasmotaLEDPusher::Begin(pixel_count, pixel_size, led_timing);
+
+ esp_err_t ret = ESP_OK;
+ rmt_tx_channel_config_t config = {};
+ config.clk_src = RMT_CLK_SRC_DEFAULT;
+ config.gpio_num = static_cast(_pin);
+ config.mem_block_symbols = 192; // memory block size, 64 * 4 = 256 Bytes
+ config.resolution_hz = RMT_LED_STRIP_RESOLUTION_HZ; // 40 MHz tick resolution, i.e., 1 tick = 0.025 µs or 25 ns
+ config.trans_queue_depth = 4; // set the number of transactions that can pend in the background
+ config.flags.invert_out = false; // do not invert output signal
+ config.flags.with_dma = false; // do not need DMA backend
+
+ ret = rmt_new_tx_channel(&config, &_channel);
+ if (ret != ESP_OK) {
+ AddLog(LOG_LEVEL_INFO, "RMT: cannot initialize Gpio %i err=%i", _pin, ret);
+ return false;
+ }
+ led_strip_encoder_config_t encoder_config = {
+ .resolution = RMT_LED_STRIP_RESOLUTION_HZ,
+ };
+
+ _tx_config.loop_count = 0; // no loop
+
+ rmt_symbol_word_t RmtBit0 = {
+ .duration0 = (uint16_t) (led_timing->T0H * (RMT_LED_STRIP_RESOLUTION_HZ / 1000000) / 1000),
+ .level0 = 1,
+ .duration1 = (uint16_t) (led_timing->T0L * (RMT_LED_STRIP_RESOLUTION_HZ / 1000000) / 1000),
+ .level1 = 0,
+ };
+ rmt_symbol_word_t RmtBit1 = {
+ .duration0 = (uint16_t) (led_timing->T1H * (RMT_LED_STRIP_RESOLUTION_HZ / 1000000) / 1000),
+ .level0 = 1,
+ .duration1 = (uint16_t) (led_timing->T1L * (RMT_LED_STRIP_RESOLUTION_HZ / 1000000) / 1000),
+ .level1 = 0,
+ };
+ rmt_symbol_word_t RmtReset = {
+ .duration0 = (uint16_t) (led_timing->Reset * (RMT_LED_STRIP_RESOLUTION_HZ / 1000000) / 1000),
+ .level0 = 0,
+ .duration1 = 50 * (RMT_LED_STRIP_RESOLUTION_HZ / 1000000) / 1000,
+ .level1 = 1,
+ };
+ // AddLog(LOG_LEVEL_INFO, "RMT: RmtBit0 0x%08X RmtBit1 0x%08X RmtReset 0x%08X", RmtBit0.val, RmtBit1.val, RmtReset.val);
+ ret = rmt_new_led_strip_encoder(&encoder_config, &_led_encoder, RmtBit0, RmtBit1, RmtReset);
+ if (ret != ESP_OK) {
+ // AddLog(LOG_LEVEL_INFO, "RMT: cannot initialize led strip encoder err=%i", ret);
+ return false;
+ }
+ ret = rmt_enable(_channel);
+ if (ret != ESP_OK) {
+ // AddLog(LOG_LEVEL_INFO, "RMT: cannot enable channel err=%i", ret);
+ return false;
+ }
+ return true;
+}
+
+bool TasmotaLEDPusherRMT::CanShow(void) {
+ if (_channel) {
+ return (ESP_OK == rmt_tx_wait_all_done(_channel, 0));
+ } else {
+ return false;
+ }
+}
+
+bool TasmotaLEDPusherRMT::Push(uint8_t *buf) {
+
+ // wait for not actively sending data
+ // this will time out at 1 second, an arbitrarily long period of time
+ // and do nothing if this happens
+ esp_err_t ret = rmt_tx_wait_all_done(_channel, 1000 / portTICK_PERIOD_MS);
+ if (ESP_OK == ret) {
+ // now start the RMT transmit with the editing buffer before we swap
+ ret = rmt_transmit(_channel, _led_encoder, buf, _pixel_count * _pixel_size, &_tx_config);
+ if (ESP_OK != ret) {
+ AddLog(LOG_LEVEL_DEBUG, "RMT: cannot transmit err=%i", ret);
+ return false;
+ }
+ }
+ return true;
+}
+
+#endif // TASMOTALED_HARDWARE_RMT
+#endif // ESP32
diff --git a/lib/lib_basic/TasmotaLED/src/TasmotaLEDPusherSPI.cpp b/lib/lib_basic/TasmotaLED/src/TasmotaLEDPusherSPI.cpp
new file mode 100644
index 000000000..72ea342ef
--- /dev/null
+++ b/lib/lib_basic/TasmotaLED/src/TasmotaLEDPusherSPI.cpp
@@ -0,0 +1,191 @@
+/*
+ TasmotaLEDPusherRMT.cpp - Implementation to push Leds via SPI channel
+
+ Copyright (C) 2024 Stephan Hadinger
+
+ This library 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 ESP32
+
+#include "TasmotaLEDPusher.h"
+#include "TasmotaLED.h"
+
+#if TASMOTALED_HARDWARE_SPI
+#include
+
+//**************************************************************************************************************
+// enable AddLog support within a C++ library
+extern void AddLog(uint32_t loglevel, PGM_P formatP, ...);
+enum LoggingLevels {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE};
+//**************************************************************************************************************
+
+/*******************************************************************************************\
+ * Implementation for TasmotaLEDPusherSPI
+ *
+\*******************************************************************************************/
+
+#define LED_STRIP_SPI_DEFAULT_RESOLUTION (25 * 100 * 1000) // 2.5MHz resolution
+#define LED_STRIP_SPI_DEFAULT_TRANS_QUEUE_SIZE 4
+
+#define SPI_BYTES_PER_COLOR_BYTE 3
+#define SPI_BITS_PER_COLOR_BYTE (SPI_BYTES_PER_COLOR_BYTE * 8)
+
+static void __led_strip_spi_bit(uint8_t data, uint8_t *buf)
+{
+ // Each color of 1 bit is represented by 3 bits of SPI, low_level:100 ,high_level:110
+ // So a color byte occupies 3 bytes of SPI.
+ buf[0] = (data & BIT(5) ? BIT(1) | BIT(0) : BIT(1)) | (data & BIT(6) ? BIT(4) | BIT(3) : BIT(4)) | (data & BIT(7) ? BIT(7) | BIT(6) : BIT(7));
+ buf[1] = (BIT(0)) | (data & BIT(3) ? BIT(3) | BIT(2) : BIT(3)) | (data & BIT(4) ? BIT(6) | BIT(5) : BIT(6));
+ buf[2] = (data & BIT(0) ? BIT(2) | BIT(1) : BIT(2)) | (data & BIT(1) ? BIT(5) | BIT(4) : BIT(5)) | (data & BIT(2) ? BIT(7) : 0x00);
+}
+
+esp_err_t led_strip_spi_refresh(led_strip_spi_obj * spi_strip)
+{
+ spi_strip->tx_conf.length = spi_strip->strip_len * spi_strip->bytes_per_pixel * SPI_BITS_PER_COLOR_BYTE;
+ spi_strip->tx_conf.tx_buffer = spi_strip->pixel_buf;
+ spi_strip->tx_conf.rx_buffer = NULL;
+ spi_device_transmit(spi_strip->spi_device, &spi_strip->tx_conf);
+ return ESP_OK;
+}
+
+void led_strip_transmit_buffer(led_strip_spi_obj * spi_strip, uint8_t * buffer_rgbw) {
+ // Timing for 512 pixels (extreme test)
+ // Copying to buffer: 418 us
+ // sending pixels: 16.2 ms
+ uint8_t * buf = buffer_rgbw;
+ uint8_t * pix_buf = spi_strip->pixel_buf;
+ for (int i = 0; i < spi_strip->strip_len; i++) {
+ // LED_PIXEL_FORMAT_GRB takes 72bits(9bytes)
+ __led_strip_spi_bit(*buf++, pix_buf); pix_buf += SPI_BYTES_PER_COLOR_BYTE;
+ __led_strip_spi_bit(*buf++, pix_buf); pix_buf += SPI_BYTES_PER_COLOR_BYTE;
+ __led_strip_spi_bit(*buf++, pix_buf); pix_buf += SPI_BYTES_PER_COLOR_BYTE;
+ if (spi_strip->bytes_per_pixel > 3) {
+ __led_strip_spi_bit(*buf++, pix_buf); pix_buf += SPI_BYTES_PER_COLOR_BYTE;
+ }
+ }
+ /* Refresh the strip to send data */
+ led_strip_spi_refresh(spi_strip);
+}
+
+
+TasmotaLEDPusherSPI::~TasmotaLEDPusherSPI() {
+ if (_spi_strip.spi_device) {
+ spi_bus_remove_device(_spi_strip.spi_device);
+ }
+ if (_spi_strip.spi_host) {
+ spi_bus_free(_spi_strip.spi_host);
+ }
+
+ if (_pin >= 0) {
+ gpio_matrix_out(_pin, 0x100, false, false);
+ pinMode(_pin, INPUT);
+ _pin = -1;
+ }
+}
+
+bool TasmotaLEDPusherSPI::Begin(uint16_t pixel_count, uint16_t pixel_size, const TasmotaLED_Timing * led_timing) {
+ TasmotaLEDPusher::Begin(pixel_count, pixel_size, led_timing);
+ _spi_strip.bytes_per_pixel = _pixel_size;
+ _spi_strip.strip_len = _pixel_count;
+
+ esp_err_t err = ESP_OK;
+ uint32_t mem_caps = MALLOC_CAP_DEFAULT;
+ // spi_clock_source_t clk_src = SPI_CLK_SRC_DEFAULT;
+ spi_bus_config_t spi_bus_cfg;
+ spi_device_interface_config_t spi_dev_cfg;
+ spi_host_device_t spi_host = SPI2_HOST;
+ bool with_dma = true; /// TODO: pass value or compute based on pixelcount
+ int clock_resolution_khz = 0;
+
+ if (with_dma) { // TODO
+ // DMA buffer must be placed in internal SRAM
+ mem_caps |= MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA;
+ }
+ _spi_strip.pixel_buf = (uint8_t *)heap_caps_calloc(1, _pixel_count * _pixel_size * SPI_BYTES_PER_COLOR_BYTE, mem_caps);
+ if (_spi_strip.pixel_buf == nullptr) {
+ AddLog(LOG_LEVEL_INFO, PSTR("LED: Error no mem for spi strip"));
+ goto err;
+ }
+
+ spi_bus_cfg = {
+ .mosi_io_num = _pin,
+ //Only use MOSI to generate the signal, set -1 when other pins are not used.
+ .miso_io_num = -1,
+ .sclk_io_num = -1,
+ .quadwp_io_num = -1,
+ .quadhd_io_num = -1,
+ .max_transfer_sz = _pixel_count * _pixel_size * SPI_BYTES_PER_COLOR_BYTE,
+ };
+ err = spi_bus_initialize(spi_host, &spi_bus_cfg, with_dma ? SPI_DMA_CH_AUTO : SPI_DMA_DISABLED);
+ if (err != ESP_OK) {
+ AddLog(LOG_LEVEL_INFO, PSTR("LED: Error create SPI bus failed"));
+ goto err;
+ }
+ _spi_strip.spi_host = spi_host; // confirmed working, so keep it's value to free it later
+
+ spi_dev_cfg = {
+ .command_bits = 0,
+ .address_bits = 0,
+ .dummy_bits = 0,
+ .mode = 0,
+ //set -1 when CS is not used
+ .clock_source = SPI_CLK_SRC_DEFAULT, // clk_src,
+ .clock_speed_hz = LED_STRIP_SPI_DEFAULT_RESOLUTION,
+ .spics_io_num = -1,
+ .queue_size = LED_STRIP_SPI_DEFAULT_TRANS_QUEUE_SIZE,
+ };
+ err = spi_bus_add_device(_spi_strip.spi_host, &spi_dev_cfg, &_spi_strip.spi_device);
+ if (err != ESP_OK) {
+ // AddLog(LOG_LEVEL_INFO, "LED: Error failed to add spi device");
+ goto err;
+ }
+
+ spi_device_get_actual_freq(_spi_strip.spi_device, &clock_resolution_khz);
+ if (err != ESP_OK) {
+ // AddLog(LOG_LEVEL_INFO, "LED: Error failed to get spi frequency");
+ goto err;
+ }
+ // TODO: ideally we should decide the SPI_BYTES_PER_COLOR_BYTE by the real clock resolution
+ // But now, let's fixed the resolution, the downside is, we don't support a clock source whose frequency is not multiple of LED_STRIP_SPI_DEFAULT_RESOLUTION
+ if (clock_resolution_khz != LED_STRIP_SPI_DEFAULT_RESOLUTION / 1000) {
+ // AddLog(LOG_LEVEL_INFO, "LED: Error unsupported clock resolution: %dKHz", clock_resolution_khz);
+ goto err;
+ }
+
+ return true;
+err:
+ if (_spi_strip.spi_device) {
+ spi_bus_remove_device(_spi_strip.spi_device);
+ }
+ if (_spi_strip.spi_host) {
+ spi_bus_free(_spi_strip.spi_host);
+ }
+ return false;
+}
+
+bool TasmotaLEDPusherSPI::CanShow(void) {
+ return true; // TODO
+}
+
+bool TasmotaLEDPusherSPI::Push(uint8_t *buf) {
+
+ if (CanShow()) {
+ led_strip_transmit_buffer(&_spi_strip, buf);
+ }
+ return true;
+}
+
+#endif // TASMOTALED_HARDWARE_SPI
+#endif // ESP32
diff --git a/lib/libesp32/berry/default/be_modtab.c b/lib/libesp32/berry/default/be_modtab.c
index e4f60edcc..f948b7d04 100644
--- a/lib/libesp32/berry/default/be_modtab.c
+++ b/lib/libesp32/berry/default/be_modtab.c
@@ -152,7 +152,7 @@ BERRY_LOCAL const bntvmodule_t* const be_module_table[] = {
&be_native_module(unishox),
#endif // USE_UNISHOX_COMPRESSION
-#ifdef USE_WS2812
+#if defined(USE_WS2812) && !defined(USE_WS2812_FORCE_NEOPIXELBUS)
&be_native_module(animate),
#endif // USE_WS2812
@@ -293,7 +293,7 @@ BERRY_LOCAL bclass_array be_class_table = {
#ifdef USE_BERRY_TCPSERVER
&be_native_class(tcpserver),
#endif // USE_BERRY_TCPSERVER
-#ifdef USE_WS2812
+#if defined(USE_WS2812) && !defined(USE_WS2812_FORCE_NEOPIXELBUS)
&be_native_class(Leds_ntv),
&be_native_class(Leds),
#endif // USE_WS2812
diff --git a/lib/libesp32/berry_animate/src/be_berry_leds_frame.cpp b/lib/libesp32/berry_animate/src/be_berry_leds_frame.cpp
index 70917593f..65ab158cc 100644
--- a/lib/libesp32/berry_animate/src/be_berry_leds_frame.cpp
+++ b/lib/libesp32/berry_animate/src/be_berry_leds_frame.cpp
@@ -45,10 +45,10 @@ extern "C" {
uint32_t g2 = (color_b >> 8) & 0xFF;
uint32_t b2 = (color_b ) & 0xFF;
uint32_t a2 = (color_b >> 24) & 0xFF;
- uint32_t r3 = changeUIntScale(alpha, 0, 255, r2, r);
- uint32_t g3 = changeUIntScale(alpha, 0, 255, g2, g);
- uint32_t b3 = changeUIntScale(alpha, 0, 255, b2, b);
- uint32_t a3 = changeUIntScale(alpha, 0, 255, a2, a);
+ uint8_t r3 = changeUIntScale(alpha, 0, 255, r2, r);
+ uint8_t g3 = changeUIntScale(alpha, 0, 255, g2, g);
+ uint8_t b3 = changeUIntScale(alpha, 0, 255, b2, b);
+ uint8_t a3 = changeUIntScale(alpha, 0, 255, a2, a);
uint32_t rgb = (a3 << 24) | (r3 << 16) | (g3 << 8) | b3;
be_pushint(vm, rgb);
be_return(vm);
@@ -97,9 +97,9 @@ extern "C" {
uint32_t fore_g = (fore_argb >> 8) & 0xFF;
uint32_t back_b = (back_argb ) & 0xFF;
uint32_t fore_b = (fore_argb ) & 0xFF;
- uint32_t dest_r_new = changeUIntScale(fore_alpha, 0, 255, fore_r, back_r);
- uint32_t dest_g_new = changeUIntScale(fore_alpha, 0, 255, fore_g, back_g);
- uint32_t dest_b_new = changeUIntScale(fore_alpha, 0, 255, fore_b, back_b);
+ uint8_t dest_r_new = changeUIntScale(fore_alpha, 0, 255, fore_r, back_r);
+ uint8_t dest_g_new = changeUIntScale(fore_alpha, 0, 255, fore_g, back_g);
+ uint8_t dest_b_new = changeUIntScale(fore_alpha, 0, 255, fore_b, back_b);
dest_rgb_new = (dest_r_new << 16) | (dest_g_new << 8) | dest_b_new;
}
dest[i] = dest_rgb_new;
@@ -135,7 +135,7 @@ extern "C" {
// Leds_frame.paste_pixels(neopixel:bytes(), led_buffer:bytes(), bri:int 0..100, gamma:bool)
//
- // Copy from ARGB buffer to GRB
+ // Copy from ARGB buffer to RGB
int32_t be_leds_paste_pixels(bvm *vm);
int32_t be_leds_paste_pixels(bvm *vm) {
int32_t top = be_top(vm); // Get the number of arguments
@@ -162,8 +162,8 @@ extern "C" {
uint32_t src_r = (src_argb >> 16) & 0xFF;
uint32_t src_g = (src_argb >> 8) & 0xFF;
uint32_t src_b = (src_argb ) & 0xFF;
- dest_buf[i * 3 + 0] = src_g;
- dest_buf[i * 3 + 1] = src_r;
+ dest_buf[i * 3 + 0] = src_r;
+ dest_buf[i * 3 + 1] = src_g;
dest_buf[i * 3 + 2] = src_b;
}
}
diff --git a/lib/libesp32/berry_tasmota/src/be_leds_ntv_lib.c b/lib/libesp32/berry_tasmota/src/be_leds_ntv_lib.c
index 26ff0b69b..11b2712f6 100644
--- a/lib/libesp32/berry_tasmota/src/be_leds_ntv_lib.c
+++ b/lib/libesp32/berry_tasmota/src/be_leds_ntv_lib.c
@@ -7,7 +7,9 @@
#ifdef USE_WS2812
-extern int be_neopixelbus_call_native(bvm *vm);
+#include "TasmotaLED.h"
+
+extern int be_tasmotaled_call_native(bvm *vm);
extern int be_leds_blend_color(bvm *vm);
extern int be_leds_apply_bri_gamma(bvm *vm);
@@ -16,10 +18,15 @@ class be_class_Leds_ntv (scope: global, name: Leds_ntv, strings: weak) {
_p, var
_t, var
- WS2812_GRB, int(1)
- SK6812_GRBW, int(2)
+ WS2812_GRB, int(ws2812_grb)
+ SK6812_GRBW, int(sk6812_grbw)
+ SK6812_GRB, int(sk6812_grb)
- call_native, func(be_neopixelbus_call_native)
+ RMT, int(TasmotaLed_RMT)
+ SPI, int(TasmotaLed_SPI)
+ I2S, int(TasmotaLed_I2S)
+
+ call_native, func(be_tasmotaled_call_native)
blend_color, static_func(be_leds_blend_color)
apply_bri_gamma, static_func(be_leds_apply_bri_gamma)
diff --git a/lib/libesp32/berry_tasmota/src/embedded/leds.be b/lib/libesp32/berry_tasmota/src/embedded/leds.be
index 019a64e3b..7a124fc50 100644
--- a/lib/libesp32/berry_tasmota/src/embedded/leds.be
+++ b/lib/libesp32/berry_tasmota/src/embedded/leds.be
@@ -31,8 +31,8 @@ class Leds : Leds_ntv
# leds:int = number of leds of the strip
# gpio:int (optional) = GPIO for NeoPixel. If not specified, takes the WS2812 gpio
# typ: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_phy, typ, rmt) # rmt is optional
+ # hardware:int (optional) = hardware support (Leds.RMT, Leds.SPI)
+ def init(leds, gpio_phy, typ, hardware)
import gpio
self.gamma = true # gamma is enabled by default, it should be disabled explicitly if needed
if (gpio_phy == nil) || (gpio_phy == gpio.pin(gpio.WS2812, 0))
@@ -47,7 +47,7 @@ class Leds : Leds_ntv
self.bri = 127 # 50% brightness by default
# initialize the structure
- self.ctor(self.leds, gpio_phy, typ, rmt)
+ self.ctor(self.leds, gpio_phy, typ, hardware)
end
if self._p == nil raise "internal_error", "couldn't not initialize noepixelbus" end
@@ -56,44 +56,6 @@ class Leds : Leds_ntv
self.begin()
end
- # assign RMT
- static def assign_rmt(gpio_phy)
- gpio_phy = int(gpio_phy)
- if gpio_phy < 0 raise "value_error", "invalid GPIO number" end
-
- import global
- var rmt
- # if "_rmt" is not initialized, set to an array of GPIO of size MAX_RMT
- if !global.contains("_rmt")
- rmt = []
- global._rmt = rmt
- for i:0..gpio.MAX_RMT-1
- rmt.push(-1)
- end
- # if default WS2812 is set, assign RMT0
- if gpio.pin_used(gpio.WS2812, 0)
- rmt[0] = gpio.pin(gpio.WS2812, 0)
- end
- end
-
- rmt = global._rmt
- # find an already assigned slot or try to assign a new one
- var i = 0
- var first_free = -1
- while i < gpio.MAX_RMT
- var elt = rmt[i]
- if elt == gpio_phy return i end # already assigned
- if elt < 0 && first_free < 0 first_free = i end # found a free slot
- i += 1
- end
- if first_free >= 0
- rmt[first_free] = gpio_phy
- return first_free
- end
- # no more slot
- raise "internal_error", "no more RMT channel available"
- end
-
def clear()
self.clear_to(0x000000)
self.show()
@@ -109,17 +71,14 @@ class Leds : Leds_ntv
return self.bri
end
- def ctor(leds, gpio_phy, typ, rmt)
+ def ctor(leds, gpio_phy, typ, hardware)
if gpio_phy == nil
self.call_native(0) # native driver
else
if typ == nil
typ = self.WS2812_GRB
end
- if rmt == nil
- rmt = self.assign_rmt(gpio_phy)
- end
- self.call_native(0, leds, gpio_phy, typ, rmt)
+ self.call_native(0, leds, gpio_phy, typ, hardware)
end
end
def begin()
@@ -155,9 +114,13 @@ class Leds : Leds_ntv
def pixel_offset()
return 0
end
- def clear_to(col, bri)
+ def clear_to(col, bri, index, len)
if (bri == nil) bri = self.bri end
- self.call_native(9, self.to_gamma(col, bri))
+ if index != nil && len != nil
+ self.call_native(9, self.to_gamma(col, bri), index, len)
+ else
+ self.call_native(9, self.to_gamma(col, bri))
+ end
end
def set_pixel_color(idx, col, bri)
if (bri == nil) bri = self.bri end
@@ -403,15 +366,15 @@ anim()
#-
-var s = Leds_matrix(5, 5, gpio.pin(gpio.WS2812, 1))
+var s = Leds(25, gpio.pin(gpio.WS2812, 1)).create_matrix(5, 5)
s.set_alternate(true)
-s.clear_to(0x300000)
+s.clear_to(0x400000)
s.show()
x = 0
y = 0
def anim()
- s.clear_to(0x300000)
+ s.clear_to(0x400000)
s.set_matrix_pixel_color(x, y, 0x004000)
s.show()
y = (y + 1) % 5
diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_leds.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_leds.h
index 683e7e756..5a493db0e 100644
--- a/lib/libesp32/berry_tasmota/src/solidify/solidified_leds.h
+++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_leds.h
@@ -3,471 +3,9 @@
* Generated code, don't edit *
\********************************************************************/
#include "be_constobj.h"
-extern const bclass be_class_Leds_segment;
extern const bclass be_class_Leds;
extern const bclass be_class_Leds_matrix;
-// compact class 'Leds_segment' ktab size: 16, total: 34 (saved 144 bytes)
-static const bvalue be_ktab_class_Leds_segment[16] = {
- /* K0 */ be_nested_str(offset),
- /* K1 */ be_nested_str(bri),
- /* K2 */ be_nested_str(strip),
- /* K3 */ be_nested_str(call_native),
- /* K4 */ be_nested_str(to_gamma),
- /* K5 */ be_nested_str(leds),
- /* K6 */ be_nested_str(dirty),
- /* K7 */ be_nested_str(can_show),
- /* K8 */ be_nested_str(set_pixel_color),
- /* K9 */ be_nested_str(is_dirty),
- /* K10 */ be_nested_str(clear_to),
- /* K11 */ be_const_int(0),
- /* K12 */ be_nested_str(show),
- /* K13 */ be_nested_str(get_pixel_color),
- /* K14 */ be_nested_str(offseta),
- /* K15 */ be_nested_str(pixel_size),
-};
-
-
extern const bclass be_class_Leds_segment;
-
-/********************************************************************
-** Solidified function: pixel_offset
-********************************************************************/
-be_local_closure(class_Leds_segment_pixel_offset, /* name */
- be_nested_proto(
- 2, /* nstack */
- 1, /* argc */
- 10, /* varg */
- 0, /* has upvals */
- NULL, /* no upvals */
- 0, /* has sup protos */
- NULL, /* no sub protos */
- 1, /* has constants */
- &be_ktab_class_Leds_segment, /* shared constants */
- &be_const_str_pixel_offset,
- &be_const_str_solidified,
- ( &(const binstruction[ 2]) { /* code */
- 0x88040100, // 0000 GETMBR R1 R0 K0
- 0x80040200, // 0001 RET 1 R1
- })
- )
-);
-/*******************************************************************/
-
-
-/********************************************************************
-** Solidified function: clear_to
-********************************************************************/
-be_local_closure(class_Leds_segment_clear_to, /* name */
- be_nested_proto(
- 10, /* nstack */
- 3, /* argc */
- 10, /* varg */
- 0, /* has upvals */
- NULL, /* no upvals */
- 0, /* has sup protos */
- NULL, /* no sub protos */
- 1, /* has constants */
- &be_ktab_class_Leds_segment, /* shared constants */
- &be_const_str_clear_to,
- &be_const_str_solidified,
- ( &(const binstruction[16]) { /* code */
- 0x4C0C0000, // 0000 LDNIL R3
- 0x1C0C0403, // 0001 EQ R3 R2 R3
- 0x780E0000, // 0002 JMPF R3 #0004
- 0x88080101, // 0003 GETMBR R2 R0 K1
- 0x880C0102, // 0004 GETMBR R3 R0 K2
- 0x8C0C0703, // 0005 GETMET R3 R3 K3
- 0x54160008, // 0006 LDINT R5 9
- 0x88180102, // 0007 GETMBR R6 R0 K2
- 0x8C180D04, // 0008 GETMET R6 R6 K4
- 0x5C200200, // 0009 MOVE R8 R1
- 0x5C240400, // 000A MOVE R9 R2
- 0x7C180600, // 000B CALL R6 3
- 0x881C0100, // 000C GETMBR R7 R0 K0
- 0x88200105, // 000D GETMBR R8 R0 K5
- 0x7C0C0A00, // 000E CALL R3 5
- 0x80000000, // 000F RET 0
- })
- )
-);
-/*******************************************************************/
-
-
-/********************************************************************
-** Solidified function: pixel_count
-********************************************************************/
-be_local_closure(class_Leds_segment_pixel_count, /* name */
- be_nested_proto(
- 2, /* nstack */
- 1, /* argc */
- 10, /* varg */
- 0, /* has upvals */
- NULL, /* no upvals */
- 0, /* has sup protos */
- NULL, /* no sub protos */
- 1, /* has constants */
- &be_ktab_class_Leds_segment, /* shared constants */
- &be_const_str_pixel_count,
- &be_const_str_solidified,
- ( &(const binstruction[ 2]) { /* code */
- 0x88040105, // 0000 GETMBR R1 R0 K5
- 0x80040200, // 0001 RET 1 R1
- })
- )
-);
-/*******************************************************************/
-
-
-/********************************************************************
-** Solidified function: pixels_buffer
-********************************************************************/
-be_local_closure(class_Leds_segment_pixels_buffer, /* name */
- be_nested_proto(
- 2, /* nstack */
- 1, /* argc */
- 10, /* varg */
- 0, /* has upvals */
- NULL, /* no upvals */
- 0, /* has sup protos */
- NULL, /* no sub protos */
- 1, /* has constants */
- &be_ktab_class_Leds_segment, /* shared constants */
- &be_const_str_pixels_buffer,
- &be_const_str_solidified,
- ( &(const binstruction[ 2]) { /* code */
- 0x4C040000, // 0000 LDNIL R1
- 0x80040200, // 0001 RET 1 R1
- })
- )
-);
-/*******************************************************************/
-
-
-/********************************************************************
-** Solidified function: dirty
-********************************************************************/
-be_local_closure(class_Leds_segment_dirty, /* name */
- be_nested_proto(
- 3, /* nstack */
- 1, /* argc */
- 10, /* varg */
- 0, /* has upvals */
- NULL, /* no upvals */
- 0, /* has sup protos */
- NULL, /* no sub protos */
- 1, /* has constants */
- &be_ktab_class_Leds_segment, /* shared constants */
- &be_const_str_dirty,
- &be_const_str_solidified,
- ( &(const binstruction[ 4]) { /* code */
- 0x88040102, // 0000 GETMBR R1 R0 K2
- 0x8C040306, // 0001 GETMET R1 R1 K6
- 0x7C040200, // 0002 CALL R1 1
- 0x80000000, // 0003 RET 0
- })
- )
-);
-/*******************************************************************/
-
-
-/********************************************************************
-** Solidified function: can_show
-********************************************************************/
-be_local_closure(class_Leds_segment_can_show, /* name */
- be_nested_proto(
- 3, /* nstack */
- 1, /* argc */
- 10, /* varg */
- 0, /* has upvals */
- NULL, /* no upvals */
- 0, /* has sup protos */
- NULL, /* no sub protos */
- 1, /* has constants */
- &be_ktab_class_Leds_segment, /* shared constants */
- &be_const_str_can_show,
- &be_const_str_solidified,
- ( &(const binstruction[ 4]) { /* code */
- 0x88040102, // 0000 GETMBR R1 R0 K2
- 0x8C040307, // 0001 GETMET R1 R1 K7
- 0x7C040200, // 0002 CALL R1 1
- 0x80040200, // 0003 RET 1 R1
- })
- )
-);
-/*******************************************************************/
-
-
-/********************************************************************
-** Solidified function: set_pixel_color
-********************************************************************/
-be_local_closure(class_Leds_segment_set_pixel_color, /* name */
- be_nested_proto(
- 9, /* nstack */
- 4, /* argc */
- 10, /* varg */
- 0, /* has upvals */
- NULL, /* no upvals */
- 0, /* has sup protos */
- NULL, /* no sub protos */
- 1, /* has constants */
- &be_ktab_class_Leds_segment, /* shared constants */
- &be_const_str_set_pixel_color,
- &be_const_str_solidified,
- ( &(const binstruction[12]) { /* code */
- 0x4C100000, // 0000 LDNIL R4
- 0x1C100604, // 0001 EQ R4 R3 R4
- 0x78120000, // 0002 JMPF R4 #0004
- 0x880C0101, // 0003 GETMBR R3 R0 K1
- 0x88100102, // 0004 GETMBR R4 R0 K2
- 0x8C100908, // 0005 GETMET R4 R4 K8
- 0x88180100, // 0006 GETMBR R6 R0 K0
- 0x00180206, // 0007 ADD R6 R1 R6
- 0x5C1C0400, // 0008 MOVE R7 R2
- 0x5C200600, // 0009 MOVE R8 R3
- 0x7C100800, // 000A CALL R4 4
- 0x80000000, // 000B RET 0
- })
- )
-);
-/*******************************************************************/
-
-
-/********************************************************************
-** Solidified function: is_dirty
-********************************************************************/
-be_local_closure(class_Leds_segment_is_dirty, /* name */
- be_nested_proto(
- 3, /* nstack */
- 1, /* argc */
- 10, /* varg */
- 0, /* has upvals */
- NULL, /* no upvals */
- 0, /* has sup protos */
- NULL, /* no sub protos */
- 1, /* has constants */
- &be_ktab_class_Leds_segment, /* shared constants */
- &be_const_str_is_dirty,
- &be_const_str_solidified,
- ( &(const binstruction[ 4]) { /* code */
- 0x88040102, // 0000 GETMBR R1 R0 K2
- 0x8C040309, // 0001 GETMET R1 R1 K9
- 0x7C040200, // 0002 CALL R1 1
- 0x80040200, // 0003 RET 1 R1
- })
- )
-);
-/*******************************************************************/
-
-
-/********************************************************************
-** Solidified function: clear
-********************************************************************/
-be_local_closure(class_Leds_segment_clear, /* name */
- be_nested_proto(
- 4, /* nstack */
- 1, /* argc */
- 10, /* varg */
- 0, /* has upvals */
- NULL, /* no upvals */
- 0, /* has sup protos */
- NULL, /* no sub protos */
- 1, /* has constants */
- &be_ktab_class_Leds_segment, /* shared constants */
- &be_const_str_clear,
- &be_const_str_solidified,
- ( &(const binstruction[ 6]) { /* code */
- 0x8C04010A, // 0000 GETMET R1 R0 K10
- 0x580C000B, // 0001 LDCONST R3 K11
- 0x7C040400, // 0002 CALL R1 2
- 0x8C04010C, // 0003 GETMET R1 R0 K12
- 0x7C040200, // 0004 CALL R1 1
- 0x80000000, // 0005 RET 0
- })
- )
-);
-/*******************************************************************/
-
-
-/********************************************************************
-** Solidified function: begin
-********************************************************************/
-be_local_closure(class_Leds_segment_begin, /* name */
- be_nested_proto(
- 1, /* nstack */
- 1, /* argc */
- 10, /* varg */
- 0, /* has upvals */
- NULL, /* no upvals */
- 0, /* has sup protos */
- NULL, /* no sub protos */
- 1, /* has constants */
- &be_ktab_class_Leds_segment, /* shared constants */
- &be_const_str_begin,
- &be_const_str_solidified,
- ( &(const binstruction[ 1]) { /* code */
- 0x80000000, // 0000 RET 0
- })
- )
-);
-/*******************************************************************/
-
-
-/********************************************************************
-** Solidified function: get_pixel_color
-********************************************************************/
-be_local_closure(class_Leds_segment_get_pixel_color, /* name */
- be_nested_proto(
- 5, /* nstack */
- 2, /* argc */
- 10, /* varg */
- 0, /* has upvals */
- NULL, /* no upvals */
- 0, /* has sup protos */
- NULL, /* no sub protos */
- 1, /* has constants */
- &be_ktab_class_Leds_segment, /* shared constants */
- &be_const_str_get_pixel_color,
- &be_const_str_solidified,
- ( &(const binstruction[ 6]) { /* code */
- 0x88080102, // 0000 GETMBR R2 R0 K2
- 0x8C08050D, // 0001 GETMET R2 R2 K13
- 0x8810010E, // 0002 GETMBR R4 R0 K14
- 0x00100204, // 0003 ADD R4 R1 R4
- 0x7C080400, // 0004 CALL R2 2
- 0x80040400, // 0005 RET 1 R2
- })
- )
-);
-/*******************************************************************/
-
-
-/********************************************************************
-** Solidified function: pixel_size
-********************************************************************/
-be_local_closure(class_Leds_segment_pixel_size, /* name */
- be_nested_proto(
- 3, /* nstack */
- 1, /* argc */
- 10, /* varg */
- 0, /* has upvals */
- NULL, /* no upvals */
- 0, /* has sup protos */
- NULL, /* no sub protos */
- 1, /* has constants */
- &be_ktab_class_Leds_segment, /* shared constants */
- &be_const_str_pixel_size,
- &be_const_str_solidified,
- ( &(const binstruction[ 4]) { /* code */
- 0x88040102, // 0000 GETMBR R1 R0 K2
- 0x8C04030F, // 0001 GETMET R1 R1 K15
- 0x7C040200, // 0002 CALL R1 1
- 0x80040200, // 0003 RET 1 R1
- })
- )
-);
-/*******************************************************************/
-
-
-/********************************************************************
-** Solidified function: init
-********************************************************************/
-be_local_closure(class_Leds_segment_init, /* name */
- be_nested_proto(
- 6, /* nstack */
- 4, /* argc */
- 10, /* varg */
- 0, /* has upvals */
- NULL, /* no upvals */
- 0, /* has sup protos */
- NULL, /* no sub protos */
- 1, /* has constants */
- &be_ktab_class_Leds_segment, /* shared constants */
- &be_const_str_init,
- &be_const_str_solidified,
- ( &(const binstruction[10]) { /* code */
- 0x90020401, // 0000 SETMBR R0 K2 R1
- 0x60100009, // 0001 GETGBL R4 G9
- 0x5C140400, // 0002 MOVE R5 R2
- 0x7C100200, // 0003 CALL R4 1
- 0x90020004, // 0004 SETMBR R0 K0 R4
- 0x60100009, // 0005 GETGBL R4 G9
- 0x5C140600, // 0006 MOVE R5 R3
- 0x7C100200, // 0007 CALL R4 1
- 0x90020A04, // 0008 SETMBR R0 K5 R4
- 0x80000000, // 0009 RET 0
- })
- )
-);
-/*******************************************************************/
-
-
-/********************************************************************
-** Solidified function: show
-********************************************************************/
-be_local_closure(class_Leds_segment_show, /* name */
- be_nested_proto(
- 4, /* nstack */
- 2, /* argc */
- 10, /* varg */
- 0, /* has upvals */
- NULL, /* no upvals */
- 0, /* has sup protos */
- NULL, /* no sub protos */
- 1, /* has constants */
- &be_ktab_class_Leds_segment, /* shared constants */
- &be_const_str_show,
- &be_const_str_solidified,
- ( &(const binstruction[16]) { /* code */
- 0x60080017, // 0000 GETGBL R2 G23
- 0x5C0C0200, // 0001 MOVE R3 R1
- 0x7C080200, // 0002 CALL R2 1
- 0x740A0007, // 0003 JMPT R2 #000C
- 0x88080100, // 0004 GETMBR R2 R0 K0
- 0x1C08050B, // 0005 EQ R2 R2 K11
- 0x780A0007, // 0006 JMPF R2 #000F
- 0x88080105, // 0007 GETMBR R2 R0 K5
- 0x880C0102, // 0008 GETMBR R3 R0 K2
- 0x880C0705, // 0009 GETMBR R3 R3 K5
- 0x1C080403, // 000A EQ R2 R2 R3
- 0x780A0002, // 000B JMPF R2 #000F
- 0x88080102, // 000C GETMBR R2 R0 K2
- 0x8C08050C, // 000D GETMET R2 R2 K12
- 0x7C080200, // 000E CALL R2 1
- 0x80000000, // 000F RET 0
- })
- )
-);
-/*******************************************************************/
-
-
-/********************************************************************
-** Solidified class: Leds_segment
-********************************************************************/
-be_local_class(Leds_segment,
- 3,
- NULL,
- be_nested_map(17,
- ( (struct bmapnode*) &(const bmapnode[]) {
- { be_const_key(pixel_offset, 9), be_const_closure(class_Leds_segment_pixel_offset_closure) },
- { be_const_key(clear_to, -1), be_const_closure(class_Leds_segment_clear_to_closure) },
- { be_const_key(show, -1), be_const_closure(class_Leds_segment_show_closure) },
- { be_const_key(pixels_buffer, 10), be_const_closure(class_Leds_segment_pixels_buffer_closure) },
- { be_const_key(offset, -1), be_const_var(1) },
- { be_const_key(dirty, -1), be_const_closure(class_Leds_segment_dirty_closure) },
- { be_const_key(can_show, -1), be_const_closure(class_Leds_segment_can_show_closure) },
- { be_const_key(set_pixel_color, 6), be_const_closure(class_Leds_segment_set_pixel_color_closure) },
- { be_const_key(get_pixel_color, -1), be_const_closure(class_Leds_segment_get_pixel_color_closure) },
- { be_const_key(pixel_count, -1), be_const_closure(class_Leds_segment_pixel_count_closure) },
- { be_const_key(strip, 7), be_const_var(0) },
- { be_const_key(leds, -1), be_const_var(2) },
- { be_const_key(begin, -1), be_const_closure(class_Leds_segment_begin_closure) },
- { be_const_key(is_dirty, 8), be_const_closure(class_Leds_segment_is_dirty_closure) },
- { be_const_key(pixel_size, -1), be_const_closure(class_Leds_segment_pixel_size_closure) },
- { be_const_key(init, -1), be_const_closure(class_Leds_segment_init_closure) },
- { be_const_key(clear, 2), be_const_closure(class_Leds_segment_clear_closure) },
- })),
- (bstring*) &be_const_str_Leds_segment
-);
// compact class 'Leds_matrix' ktab size: 24, total: 62 (saved 304 bytes)
static const bvalue be_ktab_class_Leds_matrix[24] = {
/* K0 */ be_nested_str(strip),
@@ -1111,140 +649,35 @@ be_local_class(Leds_matrix,
})),
(bstring*) &be_const_str_Leds_matrix
);
-// compact class 'Leds' ktab size: 43, total: 83 (saved 320 bytes)
-static const bvalue be_ktab_class_Leds[43] = {
- /* K0 */ be_nested_str(leds),
- /* K1 */ be_const_int(0),
- /* K2 */ be_nested_str(value_error),
- /* K3 */ be_nested_str(out_X20of_X20range),
- /* K4 */ be_const_class(be_class_Leds_segment),
- /* K5 */ be_nested_str(bri),
- /* K6 */ be_nested_str(call_native),
- /* K7 */ be_const_int(1),
- /* K8 */ be_nested_str(clear_to),
- /* K9 */ be_nested_str(show),
- /* K10 */ be_nested_str(gpio),
- /* K11 */ be_nested_str(gamma),
- /* K12 */ be_nested_str(pin),
- /* K13 */ be_nested_str(WS2812),
- /* K14 */ be_nested_str(ctor),
- /* K15 */ be_nested_str(pixel_count),
- /* K16 */ be_nested_str(light),
- /* K17 */ be_nested_str(get),
- /* K18 */ be_nested_str(_p),
- /* K19 */ be_nested_str(internal_error),
- /* K20 */ be_nested_str(couldn_X27t_X20not_X20initialize_X20noepixelbus),
- /* K21 */ be_nested_str(begin),
- /* K22 */ be_nested_str(apply_bri_gamma),
- /* K23 */ be_const_int(2),
- /* K24 */ be_const_class(be_class_Leds),
- /* K25 */ be_nested_str(Leds),
- /* K26 */ be_nested_str(create_matrix),
- /* K27 */ be_nested_str(to_gamma),
- /* K28 */ be_const_class(be_class_Leds_matrix),
- /* K29 */ be_const_int(3),
- /* K30 */ be_nested_str(invalid_X20GPIO_X20number),
- /* K31 */ be_nested_str(global),
- /* K32 */ be_nested_str(contains),
- /* K33 */ be_nested_str(_rmt),
- /* K34 */ be_nested_str(MAX_RMT),
- /* K35 */ be_nested_str(push),
- /* K36 */ be_nested_str(stop_iteration),
- /* K37 */ be_nested_str(pin_used),
- /* K38 */ be_nested_str(no_X20more_X20RMT_X20channel_X20available),
- /* K39 */ be_nested_str(WS2812_GRB),
- /* K40 */ be_nested_str(assign_rmt),
- /* K41 */ be_nested_str(pixel_size),
- /* K42 */ be_nested_str(_change_buffer),
+// compact class 'Leds_segment' ktab size: 16, total: 34 (saved 144 bytes)
+static const bvalue be_ktab_class_Leds_segment[16] = {
+ /* K0 */ be_nested_str(offset),
+ /* K1 */ be_nested_str(bri),
+ /* K2 */ be_nested_str(strip),
+ /* K3 */ be_nested_str(call_native),
+ /* K4 */ be_nested_str(to_gamma),
+ /* K5 */ be_nested_str(leds),
+ /* K6 */ be_nested_str(dirty),
+ /* K7 */ be_nested_str(can_show),
+ /* K8 */ be_nested_str(set_pixel_color),
+ /* K9 */ be_nested_str(is_dirty),
+ /* K10 */ be_nested_str(clear_to),
+ /* K11 */ be_const_int(0),
+ /* K12 */ be_nested_str(show),
+ /* K13 */ be_nested_str(get_pixel_color),
+ /* K14 */ be_nested_str(offseta),
+ /* K15 */ be_nested_str(pixel_size),
};
-extern const bclass be_class_Leds;
+extern const bclass be_class_Leds_segment;
/********************************************************************
-** Solidified function: create_segment
+** Solidified function: pixel_offset
********************************************************************/
-be_local_closure(class_Leds_create_segment, /* name */
+be_local_closure(class_Leds_segment_pixel_offset, /* name */
be_nested_proto(
- 8, /* nstack */
- 3, /* argc */
- 10, /* varg */
- 0, /* has upvals */
- NULL, /* no upvals */
- 0, /* has sup protos */
- NULL, /* no sub protos */
- 1, /* has constants */
- &be_ktab_class_Leds, /* shared constants */
- &be_const_str_create_segment,
- &be_const_str_solidified,
- ( &(const binstruction[23]) { /* code */
- 0x600C0009, // 0000 GETGBL R3 G9
- 0x5C100200, // 0001 MOVE R4 R1
- 0x7C0C0200, // 0002 CALL R3 1
- 0x60100009, // 0003 GETGBL R4 G9
- 0x5C140400, // 0004 MOVE R5 R2
- 0x7C100200, // 0005 CALL R4 1
- 0x000C0604, // 0006 ADD R3 R3 R4
- 0x88100100, // 0007 GETMBR R4 R0 K0
- 0x240C0604, // 0008 GT R3 R3 R4
- 0x740E0003, // 0009 JMPT R3 #000E
- 0x140C0301, // 000A LT R3 R1 K1
- 0x740E0001, // 000B JMPT R3 #000E
- 0x140C0501, // 000C LT R3 R2 K1
- 0x780E0000, // 000D JMPF R3 #000F
- 0xB0060503, // 000E RAISE 1 K2 K3
- 0x580C0004, // 000F LDCONST R3 K4
- 0xB4000004, // 0010 CLASS K4
- 0x5C100600, // 0011 MOVE R4 R3
- 0x5C140000, // 0012 MOVE R5 R0
- 0x5C180200, // 0013 MOVE R6 R1
- 0x5C1C0400, // 0014 MOVE R7 R2
- 0x7C100600, // 0015 CALL R4 3
- 0x80040800, // 0016 RET 1 R4
- })
- )
-);
-/*******************************************************************/
-
-
-/********************************************************************
-** Solidified function: set_bri
-********************************************************************/
-be_local_closure(class_Leds_set_bri, /* name */
- be_nested_proto(
- 3, /* nstack */
- 2, /* argc */
- 10, /* varg */
- 0, /* has upvals */
- NULL, /* no upvals */
- 0, /* has sup protos */
- NULL, /* no sub protos */
- 1, /* has constants */
- &be_ktab_class_Leds, /* shared constants */
- &be_const_str_set_bri,
- &be_const_str_solidified,
- ( &(const binstruction[ 9]) { /* code */
- 0x14080301, // 0000 LT R2 R1 K1
- 0x780A0000, // 0001 JMPF R2 #0003
- 0x58040001, // 0002 LDCONST R1 K1
- 0x540A00FE, // 0003 LDINT R2 255
- 0x24080202, // 0004 GT R2 R1 R2
- 0x780A0000, // 0005 JMPF R2 #0007
- 0x540600FE, // 0006 LDINT R1 255
- 0x90020A01, // 0007 SETMBR R0 K5 R1
- 0x80000000, // 0008 RET 0
- })
- )
-);
-/*******************************************************************/
-
-
-/********************************************************************
-** Solidified function: begin
-********************************************************************/
-be_local_closure(class_Leds_begin, /* name */
- be_nested_proto(
- 4, /* nstack */
+ 2, /* nstack */
1, /* argc */
10, /* varg */
0, /* has upvals */
@@ -1252,14 +685,12 @@ be_local_closure(class_Leds_begin, /* name */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
- &be_ktab_class_Leds, /* shared constants */
- &be_const_str_begin,
+ &be_ktab_class_Leds_segment, /* shared constants */
+ &be_const_str_pixel_offset,
&be_const_str_solidified,
- ( &(const binstruction[ 4]) { /* code */
- 0x8C040106, // 0000 GETMET R1 R0 K6
- 0x580C0007, // 0001 LDCONST R3 K7
- 0x7C040400, // 0002 CALL R1 2
- 0x80000000, // 0003 RET 0
+ ( &(const binstruction[ 2]) { /* code */
+ 0x88040100, // 0000 GETMBR R1 R0 K0
+ 0x80040200, // 0001 RET 1 R1
})
)
);
@@ -1267,106 +698,11 @@ be_local_closure(class_Leds_begin, /* name */
/********************************************************************
-** Solidified function: clear
+** Solidified function: clear_to
********************************************************************/
-be_local_closure(class_Leds_clear, /* name */
+be_local_closure(class_Leds_segment_clear_to, /* name */
be_nested_proto(
- 4, /* nstack */
- 1, /* argc */
- 10, /* varg */
- 0, /* has upvals */
- NULL, /* no upvals */
- 0, /* has sup protos */
- NULL, /* no sub protos */
- 1, /* has constants */
- &be_ktab_class_Leds, /* shared constants */
- &be_const_str_clear,
- &be_const_str_solidified,
- ( &(const binstruction[ 6]) { /* code */
- 0x8C040108, // 0000 GETMET R1 R0 K8
- 0x580C0001, // 0001 LDCONST R3 K1
- 0x7C040400, // 0002 CALL R1 2
- 0x8C040109, // 0003 GETMET R1 R0 K9
- 0x7C040200, // 0004 CALL R1 1
- 0x80000000, // 0005 RET 0
- })
- )
-);
-/*******************************************************************/
-
-
-/********************************************************************
-** Solidified function: init
-********************************************************************/
-be_local_closure(class_Leds_init, /* name */
- be_nested_proto(
- 12, /* nstack */
- 5, /* argc */
- 10, /* varg */
- 0, /* has upvals */
- NULL, /* no upvals */
- 0, /* has sup protos */
- NULL, /* no sub protos */
- 1, /* has constants */
- &be_ktab_class_Leds, /* shared constants */
- &be_const_str_init,
- &be_const_str_solidified,
- ( &(const binstruction[43]) { /* code */
- 0xA4161400, // 0000 IMPORT R5 K10
- 0x50180200, // 0001 LDBOOL R6 1 0
- 0x90021606, // 0002 SETMBR R0 K11 R6
- 0x4C180000, // 0003 LDNIL R6
- 0x1C180406, // 0004 EQ R6 R2 R6
- 0x741A0005, // 0005 JMPT R6 #000C
- 0x8C180B0C, // 0006 GETMET R6 R5 K12
- 0x88200B0D, // 0007 GETMBR R8 R5 K13
- 0x58240001, // 0008 LDCONST R9 K1
- 0x7C180600, // 0009 CALL R6 3
- 0x1C180406, // 000A EQ R6 R2 R6
- 0x781A000A, // 000B JMPF R6 #0017
- 0x8C18010E, // 000C GETMET R6 R0 K14
- 0x7C180200, // 000D CALL R6 1
- 0x8C18010F, // 000E GETMET R6 R0 K15
- 0x7C180200, // 000F CALL R6 1
- 0x90020006, // 0010 SETMBR R0 K0 R6
- 0xA41A2000, // 0011 IMPORT R6 K16
- 0x8C1C0D11, // 0012 GETMET R7 R6 K17
- 0x7C1C0200, // 0013 CALL R7 1
- 0x941C0F05, // 0014 GETIDX R7 R7 K5
- 0x90020A07, // 0015 SETMBR R0 K5 R7
- 0x7002000B, // 0016 JMP #0023
- 0x60180009, // 0017 GETGBL R6 G9
- 0x5C1C0200, // 0018 MOVE R7 R1
- 0x7C180200, // 0019 CALL R6 1
- 0x90020006, // 001A SETMBR R0 K0 R6
- 0x541A007E, // 001B LDINT R6 127
- 0x90020A06, // 001C SETMBR R0 K5 R6
- 0x8C18010E, // 001D GETMET R6 R0 K14
- 0x88200100, // 001E GETMBR R8 R0 K0
- 0x5C240400, // 001F MOVE R9 R2
- 0x5C280600, // 0020 MOVE R10 R3
- 0x5C2C0800, // 0021 MOVE R11 R4
- 0x7C180A00, // 0022 CALL R6 5
- 0x88180112, // 0023 GETMBR R6 R0 K18
- 0x4C1C0000, // 0024 LDNIL R7
- 0x1C180C07, // 0025 EQ R6 R6 R7
- 0x781A0000, // 0026 JMPF R6 #0028
- 0xB0062714, // 0027 RAISE 1 K19 K20
- 0x8C180115, // 0028 GETMET R6 R0 K21
- 0x7C180200, // 0029 CALL R6 1
- 0x80000000, // 002A RET 0
- })
- )
-);
-/*******************************************************************/
-
-
-/********************************************************************
-** Solidified function: to_gamma
-********************************************************************/
-be_local_closure(class_Leds_to_gamma, /* name */
- be_nested_proto(
- 8, /* nstack */
+ 10, /* nstack */
3, /* argc */
10, /* varg */
0, /* has upvals */
@@ -1374,47 +710,26 @@ be_local_closure(class_Leds_to_gamma, /* name */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
- &be_ktab_class_Leds, /* shared constants */
- &be_const_str_to_gamma,
+ &be_ktab_class_Leds_segment, /* shared constants */
+ &be_const_str_clear_to,
&be_const_str_solidified,
- ( &(const binstruction[10]) { /* code */
+ ( &(const binstruction[16]) { /* code */
0x4C0C0000, // 0000 LDNIL R3
0x1C0C0403, // 0001 EQ R3 R2 R3
0x780E0000, // 0002 JMPF R3 #0004
- 0x88080105, // 0003 GETMBR R2 R0 K5
- 0x8C0C0116, // 0004 GETMET R3 R0 K22
- 0x5C140200, // 0005 MOVE R5 R1
- 0x5C180400, // 0006 MOVE R6 R2
- 0x881C010B, // 0007 GETMBR R7 R0 K11
- 0x7C0C0800, // 0008 CALL R3 4
- 0x80040600, // 0009 RET 1 R3
- })
- )
-);
-/*******************************************************************/
-
-
-/********************************************************************
-** Solidified function: show
-********************************************************************/
-be_local_closure(class_Leds_show, /* name */
- be_nested_proto(
- 4, /* nstack */
- 1, /* argc */
- 10, /* varg */
- 0, /* has upvals */
- NULL, /* no upvals */
- 0, /* has sup protos */
- NULL, /* no sub protos */
- 1, /* has constants */
- &be_ktab_class_Leds, /* shared constants */
- &be_const_str_show,
- &be_const_str_solidified,
- ( &(const binstruction[ 4]) { /* code */
- 0x8C040106, // 0000 GETMET R1 R0 K6
- 0x580C0017, // 0001 LDCONST R3 K23
- 0x7C040400, // 0002 CALL R1 2
- 0x80000000, // 0003 RET 0
+ 0x88080101, // 0003 GETMBR R2 R0 K1
+ 0x880C0102, // 0004 GETMBR R3 R0 K2
+ 0x8C0C0703, // 0005 GETMET R3 R3 K3
+ 0x54160008, // 0006 LDINT R5 9
+ 0x88180102, // 0007 GETMBR R6 R0 K2
+ 0x8C180D04, // 0008 GETMET R6 R6 K4
+ 0x5C200200, // 0009 MOVE R8 R1
+ 0x5C240400, // 000A MOVE R9 R2
+ 0x7C180600, // 000B CALL R6 3
+ 0x881C0100, // 000C GETMBR R7 R0 K0
+ 0x88200105, // 000D GETMBR R8 R0 K5
+ 0x7C0C0A00, // 000E CALL R3 5
+ 0x80000000, // 000F RET 0
})
)
);
@@ -1424,7 +739,422 @@ be_local_closure(class_Leds_show, /* name */
/********************************************************************
** Solidified function: pixel_count
********************************************************************/
-be_local_closure(class_Leds_pixel_count, /* name */
+be_local_closure(class_Leds_segment_pixel_count, /* name */
+ be_nested_proto(
+ 2, /* nstack */
+ 1, /* argc */
+ 10, /* varg */
+ 0, /* has upvals */
+ NULL, /* no upvals */
+ 0, /* has sup protos */
+ NULL, /* no sub protos */
+ 1, /* has constants */
+ &be_ktab_class_Leds_segment, /* shared constants */
+ &be_const_str_pixel_count,
+ &be_const_str_solidified,
+ ( &(const binstruction[ 2]) { /* code */
+ 0x88040105, // 0000 GETMBR R1 R0 K5
+ 0x80040200, // 0001 RET 1 R1
+ })
+ )
+);
+/*******************************************************************/
+
+
+/********************************************************************
+** Solidified function: pixels_buffer
+********************************************************************/
+be_local_closure(class_Leds_segment_pixels_buffer, /* name */
+ be_nested_proto(
+ 2, /* nstack */
+ 1, /* argc */
+ 10, /* varg */
+ 0, /* has upvals */
+ NULL, /* no upvals */
+ 0, /* has sup protos */
+ NULL, /* no sub protos */
+ 1, /* has constants */
+ &be_ktab_class_Leds_segment, /* shared constants */
+ &be_const_str_pixels_buffer,
+ &be_const_str_solidified,
+ ( &(const binstruction[ 2]) { /* code */
+ 0x4C040000, // 0000 LDNIL R1
+ 0x80040200, // 0001 RET 1 R1
+ })
+ )
+);
+/*******************************************************************/
+
+
+/********************************************************************
+** Solidified function: dirty
+********************************************************************/
+be_local_closure(class_Leds_segment_dirty, /* name */
+ be_nested_proto(
+ 3, /* nstack */
+ 1, /* argc */
+ 10, /* varg */
+ 0, /* has upvals */
+ NULL, /* no upvals */
+ 0, /* has sup protos */
+ NULL, /* no sub protos */
+ 1, /* has constants */
+ &be_ktab_class_Leds_segment, /* shared constants */
+ &be_const_str_dirty,
+ &be_const_str_solidified,
+ ( &(const binstruction[ 4]) { /* code */
+ 0x88040102, // 0000 GETMBR R1 R0 K2
+ 0x8C040306, // 0001 GETMET R1 R1 K6
+ 0x7C040200, // 0002 CALL R1 1
+ 0x80000000, // 0003 RET 0
+ })
+ )
+);
+/*******************************************************************/
+
+
+/********************************************************************
+** Solidified function: can_show
+********************************************************************/
+be_local_closure(class_Leds_segment_can_show, /* name */
+ be_nested_proto(
+ 3, /* nstack */
+ 1, /* argc */
+ 10, /* varg */
+ 0, /* has upvals */
+ NULL, /* no upvals */
+ 0, /* has sup protos */
+ NULL, /* no sub protos */
+ 1, /* has constants */
+ &be_ktab_class_Leds_segment, /* shared constants */
+ &be_const_str_can_show,
+ &be_const_str_solidified,
+ ( &(const binstruction[ 4]) { /* code */
+ 0x88040102, // 0000 GETMBR R1 R0 K2
+ 0x8C040307, // 0001 GETMET R1 R1 K7
+ 0x7C040200, // 0002 CALL R1 1
+ 0x80040200, // 0003 RET 1 R1
+ })
+ )
+);
+/*******************************************************************/
+
+
+/********************************************************************
+** Solidified function: set_pixel_color
+********************************************************************/
+be_local_closure(class_Leds_segment_set_pixel_color, /* name */
+ be_nested_proto(
+ 9, /* nstack */
+ 4, /* argc */
+ 10, /* varg */
+ 0, /* has upvals */
+ NULL, /* no upvals */
+ 0, /* has sup protos */
+ NULL, /* no sub protos */
+ 1, /* has constants */
+ &be_ktab_class_Leds_segment, /* shared constants */
+ &be_const_str_set_pixel_color,
+ &be_const_str_solidified,
+ ( &(const binstruction[12]) { /* code */
+ 0x4C100000, // 0000 LDNIL R4
+ 0x1C100604, // 0001 EQ R4 R3 R4
+ 0x78120000, // 0002 JMPF R4 #0004
+ 0x880C0101, // 0003 GETMBR R3 R0 K1
+ 0x88100102, // 0004 GETMBR R4 R0 K2
+ 0x8C100908, // 0005 GETMET R4 R4 K8
+ 0x88180100, // 0006 GETMBR R6 R0 K0
+ 0x00180206, // 0007 ADD R6 R1 R6
+ 0x5C1C0400, // 0008 MOVE R7 R2
+ 0x5C200600, // 0009 MOVE R8 R3
+ 0x7C100800, // 000A CALL R4 4
+ 0x80000000, // 000B RET 0
+ })
+ )
+);
+/*******************************************************************/
+
+
+/********************************************************************
+** Solidified function: is_dirty
+********************************************************************/
+be_local_closure(class_Leds_segment_is_dirty, /* name */
+ be_nested_proto(
+ 3, /* nstack */
+ 1, /* argc */
+ 10, /* varg */
+ 0, /* has upvals */
+ NULL, /* no upvals */
+ 0, /* has sup protos */
+ NULL, /* no sub protos */
+ 1, /* has constants */
+ &be_ktab_class_Leds_segment, /* shared constants */
+ &be_const_str_is_dirty,
+ &be_const_str_solidified,
+ ( &(const binstruction[ 4]) { /* code */
+ 0x88040102, // 0000 GETMBR R1 R0 K2
+ 0x8C040309, // 0001 GETMET R1 R1 K9
+ 0x7C040200, // 0002 CALL R1 1
+ 0x80040200, // 0003 RET 1 R1
+ })
+ )
+);
+/*******************************************************************/
+
+
+/********************************************************************
+** Solidified function: clear
+********************************************************************/
+be_local_closure(class_Leds_segment_clear, /* name */
+ be_nested_proto(
+ 4, /* nstack */
+ 1, /* argc */
+ 10, /* varg */
+ 0, /* has upvals */
+ NULL, /* no upvals */
+ 0, /* has sup protos */
+ NULL, /* no sub protos */
+ 1, /* has constants */
+ &be_ktab_class_Leds_segment, /* shared constants */
+ &be_const_str_clear,
+ &be_const_str_solidified,
+ ( &(const binstruction[ 6]) { /* code */
+ 0x8C04010A, // 0000 GETMET R1 R0 K10
+ 0x580C000B, // 0001 LDCONST R3 K11
+ 0x7C040400, // 0002 CALL R1 2
+ 0x8C04010C, // 0003 GETMET R1 R0 K12
+ 0x7C040200, // 0004 CALL R1 1
+ 0x80000000, // 0005 RET 0
+ })
+ )
+);
+/*******************************************************************/
+
+
+/********************************************************************
+** Solidified function: begin
+********************************************************************/
+be_local_closure(class_Leds_segment_begin, /* name */
+ be_nested_proto(
+ 1, /* nstack */
+ 1, /* argc */
+ 10, /* varg */
+ 0, /* has upvals */
+ NULL, /* no upvals */
+ 0, /* has sup protos */
+ NULL, /* no sub protos */
+ 1, /* has constants */
+ &be_ktab_class_Leds_segment, /* shared constants */
+ &be_const_str_begin,
+ &be_const_str_solidified,
+ ( &(const binstruction[ 1]) { /* code */
+ 0x80000000, // 0000 RET 0
+ })
+ )
+);
+/*******************************************************************/
+
+
+/********************************************************************
+** Solidified function: get_pixel_color
+********************************************************************/
+be_local_closure(class_Leds_segment_get_pixel_color, /* name */
+ be_nested_proto(
+ 5, /* nstack */
+ 2, /* argc */
+ 10, /* varg */
+ 0, /* has upvals */
+ NULL, /* no upvals */
+ 0, /* has sup protos */
+ NULL, /* no sub protos */
+ 1, /* has constants */
+ &be_ktab_class_Leds_segment, /* shared constants */
+ &be_const_str_get_pixel_color,
+ &be_const_str_solidified,
+ ( &(const binstruction[ 6]) { /* code */
+ 0x88080102, // 0000 GETMBR R2 R0 K2
+ 0x8C08050D, // 0001 GETMET R2 R2 K13
+ 0x8810010E, // 0002 GETMBR R4 R0 K14
+ 0x00100204, // 0003 ADD R4 R1 R4
+ 0x7C080400, // 0004 CALL R2 2
+ 0x80040400, // 0005 RET 1 R2
+ })
+ )
+);
+/*******************************************************************/
+
+
+/********************************************************************
+** Solidified function: pixel_size
+********************************************************************/
+be_local_closure(class_Leds_segment_pixel_size, /* name */
+ be_nested_proto(
+ 3, /* nstack */
+ 1, /* argc */
+ 10, /* varg */
+ 0, /* has upvals */
+ NULL, /* no upvals */
+ 0, /* has sup protos */
+ NULL, /* no sub protos */
+ 1, /* has constants */
+ &be_ktab_class_Leds_segment, /* shared constants */
+ &be_const_str_pixel_size,
+ &be_const_str_solidified,
+ ( &(const binstruction[ 4]) { /* code */
+ 0x88040102, // 0000 GETMBR R1 R0 K2
+ 0x8C04030F, // 0001 GETMET R1 R1 K15
+ 0x7C040200, // 0002 CALL R1 1
+ 0x80040200, // 0003 RET 1 R1
+ })
+ )
+);
+/*******************************************************************/
+
+
+/********************************************************************
+** Solidified function: init
+********************************************************************/
+be_local_closure(class_Leds_segment_init, /* name */
+ be_nested_proto(
+ 6, /* nstack */
+ 4, /* argc */
+ 10, /* varg */
+ 0, /* has upvals */
+ NULL, /* no upvals */
+ 0, /* has sup protos */
+ NULL, /* no sub protos */
+ 1, /* has constants */
+ &be_ktab_class_Leds_segment, /* shared constants */
+ &be_const_str_init,
+ &be_const_str_solidified,
+ ( &(const binstruction[10]) { /* code */
+ 0x90020401, // 0000 SETMBR R0 K2 R1
+ 0x60100009, // 0001 GETGBL R4 G9
+ 0x5C140400, // 0002 MOVE R5 R2
+ 0x7C100200, // 0003 CALL R4 1
+ 0x90020004, // 0004 SETMBR R0 K0 R4
+ 0x60100009, // 0005 GETGBL R4 G9
+ 0x5C140600, // 0006 MOVE R5 R3
+ 0x7C100200, // 0007 CALL R4 1
+ 0x90020A04, // 0008 SETMBR R0 K5 R4
+ 0x80000000, // 0009 RET 0
+ })
+ )
+);
+/*******************************************************************/
+
+
+/********************************************************************
+** Solidified function: show
+********************************************************************/
+be_local_closure(class_Leds_segment_show, /* name */
+ be_nested_proto(
+ 4, /* nstack */
+ 2, /* argc */
+ 10, /* varg */
+ 0, /* has upvals */
+ NULL, /* no upvals */
+ 0, /* has sup protos */
+ NULL, /* no sub protos */
+ 1, /* has constants */
+ &be_ktab_class_Leds_segment, /* shared constants */
+ &be_const_str_show,
+ &be_const_str_solidified,
+ ( &(const binstruction[16]) { /* code */
+ 0x60080017, // 0000 GETGBL R2 G23
+ 0x5C0C0200, // 0001 MOVE R3 R1
+ 0x7C080200, // 0002 CALL R2 1
+ 0x740A0007, // 0003 JMPT R2 #000C
+ 0x88080100, // 0004 GETMBR R2 R0 K0
+ 0x1C08050B, // 0005 EQ R2 R2 K11
+ 0x780A0007, // 0006 JMPF R2 #000F
+ 0x88080105, // 0007 GETMBR R2 R0 K5
+ 0x880C0102, // 0008 GETMBR R3 R0 K2
+ 0x880C0705, // 0009 GETMBR R3 R3 K5
+ 0x1C080403, // 000A EQ R2 R2 R3
+ 0x780A0002, // 000B JMPF R2 #000F
+ 0x88080102, // 000C GETMBR R2 R0 K2
+ 0x8C08050C, // 000D GETMET R2 R2 K12
+ 0x7C080200, // 000E CALL R2 1
+ 0x80000000, // 000F RET 0
+ })
+ )
+);
+/*******************************************************************/
+
+
+/********************************************************************
+** Solidified class: Leds_segment
+********************************************************************/
+be_local_class(Leds_segment,
+ 3,
+ NULL,
+ be_nested_map(17,
+ ( (struct bmapnode*) &(const bmapnode[]) {
+ { be_const_key(pixel_offset, 9), be_const_closure(class_Leds_segment_pixel_offset_closure) },
+ { be_const_key(clear_to, -1), be_const_closure(class_Leds_segment_clear_to_closure) },
+ { be_const_key(show, -1), be_const_closure(class_Leds_segment_show_closure) },
+ { be_const_key(pixels_buffer, 10), be_const_closure(class_Leds_segment_pixels_buffer_closure) },
+ { be_const_key(offset, -1), be_const_var(1) },
+ { be_const_key(dirty, -1), be_const_closure(class_Leds_segment_dirty_closure) },
+ { be_const_key(can_show, -1), be_const_closure(class_Leds_segment_can_show_closure) },
+ { be_const_key(set_pixel_color, 6), be_const_closure(class_Leds_segment_set_pixel_color_closure) },
+ { be_const_key(get_pixel_color, -1), be_const_closure(class_Leds_segment_get_pixel_color_closure) },
+ { be_const_key(pixel_count, -1), be_const_closure(class_Leds_segment_pixel_count_closure) },
+ { be_const_key(strip, 7), be_const_var(0) },
+ { be_const_key(leds, -1), be_const_var(2) },
+ { be_const_key(begin, -1), be_const_closure(class_Leds_segment_begin_closure) },
+ { be_const_key(is_dirty, 8), be_const_closure(class_Leds_segment_is_dirty_closure) },
+ { be_const_key(pixel_size, -1), be_const_closure(class_Leds_segment_pixel_size_closure) },
+ { be_const_key(init, -1), be_const_closure(class_Leds_segment_init_closure) },
+ { be_const_key(clear, 2), be_const_closure(class_Leds_segment_clear_closure) },
+ })),
+ (bstring*) &be_const_str_Leds_segment
+);
+// compact class 'Leds' ktab size: 33, total: 65 (saved 256 bytes)
+static const bvalue be_ktab_class_Leds[33] = {
+ /* K0 */ be_nested_str(call_native),
+ /* K1 */ be_nested_str(bri),
+ /* K2 */ be_const_class(be_class_Leds),
+ /* K3 */ be_nested_str(Leds),
+ /* K4 */ be_nested_str(create_matrix),
+ /* K5 */ be_const_int(0),
+ /* K6 */ be_const_int(3),
+ /* K7 */ be_nested_str(gamma),
+ /* K8 */ be_const_int(2),
+ /* K9 */ be_nested_str(WS2812_GRB),
+ /* K10 */ be_nested_str(leds),
+ /* K11 */ be_nested_str(value_error),
+ /* K12 */ be_nested_str(out_X20of_X20range),
+ /* K13 */ be_const_class(be_class_Leds_matrix),
+ /* K14 */ be_nested_str(to_gamma),
+ /* K15 */ be_const_class(be_class_Leds_segment),
+ /* K16 */ be_nested_str(gpio),
+ /* K17 */ be_nested_str(pin),
+ /* K18 */ be_nested_str(WS2812),
+ /* K19 */ be_nested_str(ctor),
+ /* K20 */ be_nested_str(pixel_count),
+ /* K21 */ be_nested_str(light),
+ /* K22 */ be_nested_str(get),
+ /* K23 */ be_nested_str(_p),
+ /* K24 */ be_nested_str(internal_error),
+ /* K25 */ be_nested_str(couldn_X27t_X20not_X20initialize_X20noepixelbus),
+ /* K26 */ be_nested_str(begin),
+ /* K27 */ be_nested_str(clear_to),
+ /* K28 */ be_nested_str(show),
+ /* K29 */ be_const_int(1),
+ /* K30 */ be_nested_str(apply_bri_gamma),
+ /* K31 */ be_nested_str(pixel_size),
+ /* K32 */ be_nested_str(_change_buffer),
+};
+
+
+extern const bclass be_class_Leds;
+
+/********************************************************************
+** Solidified function: is_dirty
+********************************************************************/
+be_local_closure(class_Leds_is_dirty, /* name */
be_nested_proto(
4, /* nstack */
1, /* argc */
@@ -1435,11 +1165,11 @@ be_local_closure(class_Leds_pixel_count, /* name */
NULL, /* no sub protos */
1, /* has constants */
&be_ktab_class_Leds, /* shared constants */
- &be_const_str_pixel_count,
+ &be_const_str_is_dirty,
&be_const_str_solidified,
( &(const binstruction[ 4]) { /* code */
- 0x8C040106, // 0000 GETMET R1 R0 K6
- 0x540E0007, // 0001 LDINT R3 8
+ 0x8C040100, // 0000 GETMET R1 R0 K0
+ 0x540E0003, // 0001 LDINT R3 4
0x7C040400, // 0002 CALL R1 2
0x80040200, // 0003 RET 1 R1
})
@@ -1465,7 +1195,7 @@ be_local_closure(class_Leds_get_bri, /* name */
&be_const_str_get_bri,
&be_const_str_solidified,
( &(const binstruction[ 2]) { /* code */
- 0x88040105, // 0000 GETMBR R1 R0 K5
+ 0x88040101, // 0000 GETMBR R1 R0 K1
0x80040200, // 0001 RET 1 R1
})
)
@@ -1473,6 +1203,100 @@ be_local_closure(class_Leds_get_bri, /* name */
/*******************************************************************/
+/********************************************************************
+** Solidified function: matrix
+********************************************************************/
+be_local_closure(class_Leds_matrix, /* name */
+ be_nested_proto(
+ 11, /* nstack */
+ 4, /* argc */
+ 12, /* varg */
+ 0, /* has upvals */
+ NULL, /* no upvals */
+ 0, /* has sup protos */
+ NULL, /* no sub protos */
+ 1, /* has constants */
+ &be_ktab_class_Leds, /* shared constants */
+ &be_const_str_matrix,
+ &be_const_str_solidified,
+ ( &(const binstruction[12]) { /* code */
+ 0x58100002, // 0000 LDCONST R4 K2
+ 0xB8160600, // 0001 GETNGBL R5 K3
+ 0x08180001, // 0002 MUL R6 R0 R1
+ 0x5C1C0400, // 0003 MOVE R7 R2
+ 0x5C200600, // 0004 MOVE R8 R3
+ 0x7C140600, // 0005 CALL R5 3
+ 0x8C180B04, // 0006 GETMET R6 R5 K4
+ 0x5C200000, // 0007 MOVE R8 R0
+ 0x5C240200, // 0008 MOVE R9 R1
+ 0x58280005, // 0009 LDCONST R10 K5
+ 0x7C180800, // 000A CALL R6 4
+ 0x80040C00, // 000B RET 1 R6
+ })
+ )
+);
+/*******************************************************************/
+
+
+/********************************************************************
+** Solidified function: can_show
+********************************************************************/
+be_local_closure(class_Leds_can_show, /* name */
+ be_nested_proto(
+ 4, /* nstack */
+ 1, /* argc */
+ 10, /* varg */
+ 0, /* has upvals */
+ NULL, /* no upvals */
+ 0, /* has sup protos */
+ NULL, /* no sub protos */
+ 1, /* has constants */
+ &be_ktab_class_Leds, /* shared constants */
+ &be_const_str_can_show,
+ &be_const_str_solidified,
+ ( &(const binstruction[ 4]) { /* code */
+ 0x8C040100, // 0000 GETMET R1 R0 K0
+ 0x580C0006, // 0001 LDCONST R3 K6
+ 0x7C040400, // 0002 CALL R1 2
+ 0x80040200, // 0003 RET 1 R1
+ })
+ )
+);
+/*******************************************************************/
+
+
+/********************************************************************
+** Solidified function: set_bri
+********************************************************************/
+be_local_closure(class_Leds_set_bri, /* name */
+ be_nested_proto(
+ 3, /* nstack */
+ 2, /* argc */
+ 10, /* varg */
+ 0, /* has upvals */
+ NULL, /* no upvals */
+ 0, /* has sup protos */
+ NULL, /* no sub protos */
+ 1, /* has constants */
+ &be_ktab_class_Leds, /* shared constants */
+ &be_const_str_set_bri,
+ &be_const_str_solidified,
+ ( &(const binstruction[ 9]) { /* code */
+ 0x14080305, // 0000 LT R2 R1 K5
+ 0x780A0000, // 0001 JMPF R2 #0003
+ 0x58040005, // 0002 LDCONST R1 K5
+ 0x540A00FE, // 0003 LDINT R2 255
+ 0x24080202, // 0004 GT R2 R1 R2
+ 0x780A0000, // 0005 JMPF R2 #0007
+ 0x540600FE, // 0006 LDINT R1 255
+ 0x90020201, // 0007 SETMBR R0 K1 R1
+ 0x80000000, // 0008 RET 0
+ })
+ )
+);
+/*******************************************************************/
+
+
/********************************************************************
** Solidified function: set_gamma
********************************************************************/
@@ -1493,7 +1317,7 @@ be_local_closure(class_Leds_set_gamma, /* name */
0x60080017, // 0000 GETGBL R2 G23
0x5C0C0200, // 0001 MOVE R3 R1
0x7C080200, // 0002 CALL R2 1
- 0x90021602, // 0003 SETMBR R0 K11 R2
+ 0x90020E02, // 0003 SETMBR R0 K7 R2
0x80000000, // 0004 RET 0
})
)
@@ -1502,37 +1326,9 @@ be_local_closure(class_Leds_set_gamma, /* name */
/********************************************************************
-** Solidified function: get_pixel_color
+** Solidified function: show
********************************************************************/
-be_local_closure(class_Leds_get_pixel_color, /* name */
- be_nested_proto(
- 6, /* nstack */
- 2, /* argc */
- 10, /* varg */
- 0, /* has upvals */
- NULL, /* no upvals */
- 0, /* has sup protos */
- NULL, /* no sub protos */
- 1, /* has constants */
- &be_ktab_class_Leds, /* shared constants */
- &be_const_str_get_pixel_color,
- &be_const_str_solidified,
- ( &(const binstruction[ 5]) { /* code */
- 0x8C080106, // 0000 GETMET R2 R0 K6
- 0x5412000A, // 0001 LDINT R4 11
- 0x5C140200, // 0002 MOVE R5 R1
- 0x7C080600, // 0003 CALL R2 3
- 0x80040400, // 0004 RET 1 R2
- })
- )
-);
-/*******************************************************************/
-
-
-/********************************************************************
-** Solidified function: dirty
-********************************************************************/
-be_local_closure(class_Leds_dirty, /* name */
+be_local_closure(class_Leds_show, /* name */
be_nested_proto(
4, /* nstack */
1, /* argc */
@@ -1543,11 +1339,11 @@ be_local_closure(class_Leds_dirty, /* name */
NULL, /* no sub protos */
1, /* has constants */
&be_ktab_class_Leds, /* shared constants */
- &be_const_str_dirty,
+ &be_const_str_show,
&be_const_str_solidified,
( &(const binstruction[ 4]) { /* code */
- 0x8C040106, // 0000 GETMET R1 R0 K6
- 0x540E0004, // 0001 LDINT R3 5
+ 0x8C040100, // 0000 GETMET R1 R0 K0
+ 0x580C0008, // 0001 LDCONST R3 K8
0x7C040400, // 0002 CALL R1 2
0x80000000, // 0003 RET 0
})
@@ -1557,106 +1353,12 @@ be_local_closure(class_Leds_dirty, /* name */
/********************************************************************
-** Solidified function: matrix
+** Solidified function: ctor
********************************************************************/
-be_local_closure(class_Leds_matrix, /* name */
- be_nested_proto(
- 11, /* nstack */
- 4, /* argc */
- 12, /* varg */
- 0, /* has upvals */
- NULL, /* no upvals */
- 0, /* has sup protos */
- NULL, /* no sub protos */
- 1, /* has constants */
- &be_ktab_class_Leds, /* shared constants */
- &be_const_str_matrix,
- &be_const_str_solidified,
- ( &(const binstruction[12]) { /* code */
- 0x58100018, // 0000 LDCONST R4 K24
- 0xB8163200, // 0001 GETNGBL R5 K25
- 0x08180001, // 0002 MUL R6 R0 R1
- 0x5C1C0400, // 0003 MOVE R7 R2
- 0x5C200600, // 0004 MOVE R8 R3
- 0x7C140600, // 0005 CALL R5 3
- 0x8C180B1A, // 0006 GETMET R6 R5 K26
- 0x5C200000, // 0007 MOVE R8 R0
- 0x5C240200, // 0008 MOVE R9 R1
- 0x58280001, // 0009 LDCONST R10 K1
- 0x7C180800, // 000A CALL R6 4
- 0x80040C00, // 000B RET 1 R6
- })
- )
-);
-/*******************************************************************/
-
-
-/********************************************************************
-** Solidified function: pixel_offset
-********************************************************************/
-be_local_closure(class_Leds_pixel_offset, /* name */
- be_nested_proto(
- 1, /* nstack */
- 1, /* argc */
- 10, /* varg */
- 0, /* has upvals */
- NULL, /* no upvals */
- 0, /* has sup protos */
- NULL, /* no sub protos */
- 1, /* has constants */
- &be_ktab_class_Leds, /* shared constants */
- &be_const_str_pixel_offset,
- &be_const_str_solidified,
- ( &(const binstruction[ 1]) { /* code */
- 0x80060200, // 0000 RET 1 K1
- })
- )
-);
-/*******************************************************************/
-
-
-/********************************************************************
-** Solidified function: clear_to
-********************************************************************/
-be_local_closure(class_Leds_clear_to, /* name */
- be_nested_proto(
- 10, /* nstack */
- 3, /* argc */
- 10, /* varg */
- 0, /* has upvals */
- NULL, /* no upvals */
- 0, /* has sup protos */
- NULL, /* no sub protos */
- 1, /* has constants */
- &be_ktab_class_Leds, /* shared constants */
- &be_const_str_clear_to,
- &be_const_str_solidified,
- ( &(const binstruction[12]) { /* code */
- 0x4C0C0000, // 0000 LDNIL R3
- 0x1C0C0403, // 0001 EQ R3 R2 R3
- 0x780E0000, // 0002 JMPF R3 #0004
- 0x88080105, // 0003 GETMBR R2 R0 K5
- 0x8C0C0106, // 0004 GETMET R3 R0 K6
- 0x54160008, // 0005 LDINT R5 9
- 0x8C18011B, // 0006 GETMET R6 R0 K27
- 0x5C200200, // 0007 MOVE R8 R1
- 0x5C240400, // 0008 MOVE R9 R2
- 0x7C180600, // 0009 CALL R6 3
- 0x7C0C0600, // 000A CALL R3 3
- 0x80000000, // 000B RET 0
- })
- )
-);
-/*******************************************************************/
-
-
-/********************************************************************
-** Solidified function: set_pixel_color
-********************************************************************/
-be_local_closure(class_Leds_set_pixel_color, /* name */
+be_local_closure(class_Leds_ctor, /* name */
be_nested_proto(
12, /* nstack */
- 4, /* argc */
+ 5, /* argc */
10, /* varg */
0, /* has upvals */
NULL, /* no upvals */
@@ -1664,22 +1366,28 @@ be_local_closure(class_Leds_set_pixel_color, /* name */
NULL, /* no sub protos */
1, /* has constants */
&be_ktab_class_Leds, /* shared constants */
- &be_const_str_set_pixel_color,
+ &be_const_str_ctor,
&be_const_str_solidified,
- ( &(const binstruction[13]) { /* code */
- 0x4C100000, // 0000 LDNIL R4
- 0x1C100604, // 0001 EQ R4 R3 R4
- 0x78120000, // 0002 JMPF R4 #0004
- 0x880C0105, // 0003 GETMBR R3 R0 K5
- 0x8C100106, // 0004 GETMET R4 R0 K6
- 0x541A0009, // 0005 LDINT R6 10
- 0x5C1C0200, // 0006 MOVE R7 R1
- 0x8C20011B, // 0007 GETMET R8 R0 K27
- 0x5C280400, // 0008 MOVE R10 R2
- 0x5C2C0600, // 0009 MOVE R11 R3
- 0x7C200600, // 000A CALL R8 3
- 0x7C100800, // 000B CALL R4 4
- 0x80000000, // 000C RET 0
+ ( &(const binstruction[19]) { /* code */
+ 0x4C140000, // 0000 LDNIL R5
+ 0x1C140405, // 0001 EQ R5 R2 R5
+ 0x78160003, // 0002 JMPF R5 #0007
+ 0x8C140100, // 0003 GETMET R5 R0 K0
+ 0x581C0005, // 0004 LDCONST R7 K5
+ 0x7C140400, // 0005 CALL R5 2
+ 0x7002000A, // 0006 JMP #0012
+ 0x4C140000, // 0007 LDNIL R5
+ 0x1C140605, // 0008 EQ R5 R3 R5
+ 0x78160000, // 0009 JMPF R5 #000B
+ 0x880C0109, // 000A GETMBR R3 R0 K9
+ 0x8C140100, // 000B GETMET R5 R0 K0
+ 0x581C0005, // 000C LDCONST R7 K5
+ 0x5C200200, // 000D MOVE R8 R1
+ 0x5C240400, // 000E MOVE R9 R2
+ 0x5C280600, // 000F MOVE R10 R3
+ 0x5C2C0800, // 0010 MOVE R11 R4
+ 0x7C140C00, // 0011 CALL R5 6
+ 0x80000000, // 0012 RET 0
})
)
);
@@ -1703,7 +1411,7 @@ be_local_closure(class_Leds_pixel_size, /* name */
&be_const_str_pixel_size,
&be_const_str_solidified,
( &(const binstruction[ 4]) { /* code */
- 0x8C040106, // 0000 GETMET R1 R0 K6
+ 0x8C040100, // 0000 GETMET R1 R0 K0
0x540E0006, // 0001 LDINT R3 7
0x7C040400, // 0002 CALL R1 2
0x80040200, // 0003 RET 1 R1
@@ -1713,6 +1421,110 @@ be_local_closure(class_Leds_pixel_size, /* name */
/*******************************************************************/
+/********************************************************************
+** Solidified function: dirty
+********************************************************************/
+be_local_closure(class_Leds_dirty, /* name */
+ be_nested_proto(
+ 4, /* nstack */
+ 1, /* argc */
+ 10, /* varg */
+ 0, /* has upvals */
+ NULL, /* no upvals */
+ 0, /* has sup protos */
+ NULL, /* no sub protos */
+ 1, /* has constants */
+ &be_ktab_class_Leds, /* shared constants */
+ &be_const_str_dirty,
+ &be_const_str_solidified,
+ ( &(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: pixel_offset
+********************************************************************/
+be_local_closure(class_Leds_pixel_offset, /* name */
+ be_nested_proto(
+ 1, /* nstack */
+ 1, /* argc */
+ 10, /* varg */
+ 0, /* has upvals */
+ NULL, /* no upvals */
+ 0, /* has sup protos */
+ NULL, /* no sub protos */
+ 1, /* has constants */
+ &be_ktab_class_Leds, /* shared constants */
+ &be_const_str_pixel_offset,
+ &be_const_str_solidified,
+ ( &(const binstruction[ 1]) { /* code */
+ 0x80060A00, // 0000 RET 1 K5
+ })
+ )
+);
+/*******************************************************************/
+
+
+/********************************************************************
+** Solidified function: get_pixel_color
+********************************************************************/
+be_local_closure(class_Leds_get_pixel_color, /* name */
+ be_nested_proto(
+ 6, /* nstack */
+ 2, /* argc */
+ 10, /* varg */
+ 0, /* has upvals */
+ NULL, /* no upvals */
+ 0, /* has sup protos */
+ NULL, /* no sub protos */
+ 1, /* has constants */
+ &be_ktab_class_Leds, /* shared constants */
+ &be_const_str_get_pixel_color,
+ &be_const_str_solidified,
+ ( &(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: get_gamma
+********************************************************************/
+be_local_closure(class_Leds_get_gamma, /* name */
+ be_nested_proto(
+ 2, /* nstack */
+ 1, /* argc */
+ 10, /* varg */
+ 0, /* has upvals */
+ NULL, /* no upvals */
+ 0, /* has sup protos */
+ NULL, /* no sub protos */
+ 1, /* has constants */
+ &be_ktab_class_Leds, /* shared constants */
+ &be_const_str_get_gamma,
+ &be_const_str_solidified,
+ ( &(const binstruction[ 2]) { /* code */
+ 0x88040107, // 0000 GETMBR R1 R0 K7
+ 0x80040200, // 0001 RET 1 R1
+ })
+ )
+);
+/*******************************************************************/
+
+
/********************************************************************
** Solidified function: create_matrix
********************************************************************/
@@ -1745,21 +1557,21 @@ be_local_closure(class_Leds_create_matrix, /* name */
0x4C100000, // 000C LDNIL R4
0x1C100604, // 000D EQ R4 R3 R4
0x78120000, // 000E JMPF R4 #0010
- 0x580C0001, // 000F LDCONST R3 K1
+ 0x580C0005, // 000F LDCONST R3 K5
0x08100202, // 0010 MUL R4 R1 R2
0x00100803, // 0011 ADD R4 R4 R3
- 0x88140100, // 0012 GETMBR R5 R0 K0
+ 0x8814010A, // 0012 GETMBR R5 R0 K10
0x24100805, // 0013 GT R4 R4 R5
0x74120005, // 0014 JMPT R4 #001B
- 0x14100501, // 0015 LT R4 R2 K1
+ 0x14100505, // 0015 LT R4 R2 K5
0x74120003, // 0016 JMPT R4 #001B
- 0x14100301, // 0017 LT R4 R1 K1
+ 0x14100305, // 0017 LT R4 R1 K5
0x74120001, // 0018 JMPT R4 #001B
- 0x14100701, // 0019 LT R4 R3 K1
+ 0x14100705, // 0019 LT R4 R3 K5
0x78120000, // 001A JMPF R4 #001C
- 0xB0060503, // 001B RAISE 1 K2 K3
- 0x5810001C, // 001C LDCONST R4 K28
- 0xB400001C, // 001D CLASS K28
+ 0xB006170C, // 001B RAISE 1 K11 K12
+ 0x5810000D, // 001C LDCONST R4 K13
+ 0xB400000D, // 001D CLASS K13
0x5C140800, // 001E MOVE R5 R4
0x5C180000, // 001F MOVE R6 R0
0x5C1C0200, // 0020 MOVE R7 R1
@@ -1774,183 +1586,9 @@ be_local_closure(class_Leds_create_matrix, /* name */
/********************************************************************
-** Solidified function: get_gamma
+** Solidified function: clear_to
********************************************************************/
-be_local_closure(class_Leds_get_gamma, /* name */
- be_nested_proto(
- 2, /* nstack */
- 1, /* argc */
- 10, /* varg */
- 0, /* has upvals */
- NULL, /* no upvals */
- 0, /* has sup protos */
- NULL, /* no sub protos */
- 1, /* has constants */
- &be_ktab_class_Leds, /* shared constants */
- &be_const_str_get_gamma,
- &be_const_str_solidified,
- ( &(const binstruction[ 2]) { /* code */
- 0x8804010B, // 0000 GETMBR R1 R0 K11
- 0x80040200, // 0001 RET 1 R1
- })
- )
-);
-/*******************************************************************/
-
-
-/********************************************************************
-** Solidified function: is_dirty
-********************************************************************/
-be_local_closure(class_Leds_is_dirty, /* name */
- be_nested_proto(
- 4, /* nstack */
- 1, /* argc */
- 10, /* varg */
- 0, /* has upvals */
- NULL, /* no upvals */
- 0, /* has sup protos */
- NULL, /* no sub protos */
- 1, /* has constants */
- &be_ktab_class_Leds, /* shared constants */
- &be_const_str_is_dirty,
- &be_const_str_solidified,
- ( &(const binstruction[ 4]) { /* code */
- 0x8C040106, // 0000 GETMET R1 R0 K6
- 0x540E0003, // 0001 LDINT R3 4
- 0x7C040400, // 0002 CALL R1 2
- 0x80040200, // 0003 RET 1 R1
- })
- )
-);
-/*******************************************************************/
-
-
-/********************************************************************
-** Solidified function: can_show
-********************************************************************/
-be_local_closure(class_Leds_can_show, /* name */
- be_nested_proto(
- 4, /* nstack */
- 1, /* argc */
- 10, /* varg */
- 0, /* has upvals */
- NULL, /* no upvals */
- 0, /* has sup protos */
- NULL, /* no sub protos */
- 1, /* has constants */
- &be_ktab_class_Leds, /* shared constants */
- &be_const_str_can_show,
- &be_const_str_solidified,
- ( &(const binstruction[ 4]) { /* code */
- 0x8C040106, // 0000 GETMET R1 R0 K6
- 0x580C001D, // 0001 LDCONST R3 K29
- 0x7C040400, // 0002 CALL R1 2
- 0x80040200, // 0003 RET 1 R1
- })
- )
-);
-/*******************************************************************/
-
-
-/********************************************************************
-** Solidified function: assign_rmt
-********************************************************************/
-be_local_closure(class_Leds_assign_rmt, /* name */
- be_nested_proto(
- 9, /* nstack */
- 1, /* argc */
- 12, /* varg */
- 0, /* has upvals */
- NULL, /* no upvals */
- 0, /* has sup protos */
- NULL, /* no sub protos */
- 1, /* has constants */
- &be_ktab_class_Leds, /* shared constants */
- &be_const_str_assign_rmt,
- &be_const_str_solidified,
- ( &(const binstruction[72]) { /* code */
- 0x58040018, // 0000 LDCONST R1 K24
- 0x60080009, // 0001 GETGBL R2 G9
- 0x5C0C0000, // 0002 MOVE R3 R0
- 0x7C080200, // 0003 CALL R2 1
- 0x5C000400, // 0004 MOVE R0 R2
- 0x14080101, // 0005 LT R2 R0 K1
- 0x780A0000, // 0006 JMPF R2 #0008
- 0xB006051E, // 0007 RAISE 1 K2 K30
- 0xA40A3E00, // 0008 IMPORT R2 K31
- 0x4C0C0000, // 0009 LDNIL R3
- 0x8C100520, // 000A GETMET R4 R2 K32
- 0x58180021, // 000B LDCONST R6 K33
- 0x7C100400, // 000C CALL R4 2
- 0x74120021, // 000D JMPT R4 #0030
- 0x60100012, // 000E GETGBL R4 G18
- 0x7C100000, // 000F CALL R4 0
- 0x5C0C0800, // 0010 MOVE R3 R4
- 0x900A4203, // 0011 SETMBR R2 K33 R3
- 0x60100010, // 0012 GETGBL R4 G16
- 0xB8161400, // 0013 GETNGBL R5 K10
- 0x88140B22, // 0014 GETMBR R5 R5 K34
- 0x04140B07, // 0015 SUB R5 R5 K7
- 0x40160205, // 0016 CONNECT R5 K1 R5
- 0x7C100200, // 0017 CALL R4 1
- 0xA8020005, // 0018 EXBLK 0 #001F
- 0x5C140800, // 0019 MOVE R5 R4
- 0x7C140000, // 001A CALL R5 0
- 0x8C180723, // 001B GETMET R6 R3 K35
- 0x5421FFFE, // 001C LDINT R8 -1
- 0x7C180400, // 001D CALL R6 2
- 0x7001FFF9, // 001E JMP #0019
- 0x58100024, // 001F LDCONST R4 K36
- 0xAC100200, // 0020 CATCH R4 1 0
- 0xB0080000, // 0021 RAISE 2 R0 R0
- 0xB8121400, // 0022 GETNGBL R4 K10
- 0x8C100925, // 0023 GETMET R4 R4 K37
- 0xB81A1400, // 0024 GETNGBL R6 K10
- 0x88180D0D, // 0025 GETMBR R6 R6 K13
- 0x581C0001, // 0026 LDCONST R7 K1
- 0x7C100600, // 0027 CALL R4 3
- 0x78120006, // 0028 JMPF R4 #0030
- 0xB8121400, // 0029 GETNGBL R4 K10
- 0x8C10090C, // 002A GETMET R4 R4 K12
- 0xB81A1400, // 002B GETNGBL R6 K10
- 0x88180D0D, // 002C GETMBR R6 R6 K13
- 0x581C0001, // 002D LDCONST R7 K1
- 0x7C100600, // 002E CALL R4 3
- 0x980E0204, // 002F SETIDX R3 K1 R4
- 0x880C0521, // 0030 GETMBR R3 R2 K33
- 0x58100001, // 0031 LDCONST R4 K1
- 0x5415FFFE, // 0032 LDINT R5 -1
- 0xB81A1400, // 0033 GETNGBL R6 K10
- 0x88180D22, // 0034 GETMBR R6 R6 K34
- 0x14180806, // 0035 LT R6 R4 R6
- 0x781A000A, // 0036 JMPF R6 #0042
- 0x94180604, // 0037 GETIDX R6 R3 R4
- 0x1C1C0C00, // 0038 EQ R7 R6 R0
- 0x781E0000, // 0039 JMPF R7 #003B
- 0x80040800, // 003A RET 1 R4
- 0x141C0D01, // 003B LT R7 R6 K1
- 0x781E0002, // 003C JMPF R7 #0040
- 0x141C0B01, // 003D LT R7 R5 K1
- 0x781E0000, // 003E JMPF R7 #0040
- 0x5C140800, // 003F MOVE R5 R4
- 0x00100907, // 0040 ADD R4 R4 K7
- 0x7001FFF0, // 0041 JMP #0033
- 0x28180B01, // 0042 GE R6 R5 K1
- 0x781A0001, // 0043 JMPF R6 #0046
- 0x980C0A00, // 0044 SETIDX R3 R5 R0
- 0x80040A00, // 0045 RET 1 R5
- 0xB0062726, // 0046 RAISE 1 K19 K38
- 0x80000000, // 0047 RET 0
- })
- )
-);
-/*******************************************************************/
-
-
-/********************************************************************
-** Solidified function: ctor
-********************************************************************/
-be_local_closure(class_Leds_ctor, /* name */
+be_local_closure(class_Leds_clear_to, /* name */
be_nested_proto(
12, /* nstack */
5, /* argc */
@@ -1961,35 +1599,301 @@ be_local_closure(class_Leds_ctor, /* name */
NULL, /* no sub protos */
1, /* has constants */
&be_ktab_class_Leds, /* shared constants */
- &be_const_str_ctor,
+ &be_const_str_clear_to,
&be_const_str_solidified,
- ( &(const binstruction[26]) { /* code */
+ ( &(const binstruction[28]) { /* code */
0x4C140000, // 0000 LDNIL R5
0x1C140405, // 0001 EQ R5 R2 R5
- 0x78160003, // 0002 JMPF R5 #0007
- 0x8C140106, // 0003 GETMET R5 R0 K6
- 0x581C0001, // 0004 LDCONST R7 K1
- 0x7C140400, // 0005 CALL R5 2
- 0x70020011, // 0006 JMP #0019
+ 0x78160000, // 0002 JMPF R5 #0004
+ 0x88080101, // 0003 GETMBR R2 R0 K1
+ 0x4C140000, // 0004 LDNIL R5
+ 0x20140605, // 0005 NE R5 R3 R5
+ 0x7816000C, // 0006 JMPF R5 #0014
0x4C140000, // 0007 LDNIL R5
- 0x1C140605, // 0008 EQ R5 R3 R5
- 0x78160000, // 0009 JMPF R5 #000B
- 0x880C0127, // 000A GETMBR R3 R0 K39
- 0x4C140000, // 000B LDNIL R5
- 0x1C140805, // 000C EQ R5 R4 R5
- 0x78160003, // 000D JMPF R5 #0012
- 0x8C140128, // 000E GETMET R5 R0 K40
- 0x5C1C0400, // 000F MOVE R7 R2
- 0x7C140400, // 0010 CALL R5 2
- 0x5C100A00, // 0011 MOVE R4 R5
- 0x8C140106, // 0012 GETMET R5 R0 K6
- 0x581C0001, // 0013 LDCONST R7 K1
- 0x5C200200, // 0014 MOVE R8 R1
- 0x5C240400, // 0015 MOVE R9 R2
- 0x5C280600, // 0016 MOVE R10 R3
- 0x5C2C0800, // 0017 MOVE R11 R4
- 0x7C140C00, // 0018 CALL R5 6
- 0x80000000, // 0019 RET 0
+ 0x20140805, // 0008 NE R5 R4 R5
+ 0x78160009, // 0009 JMPF R5 #0014
+ 0x8C140100, // 000A GETMET R5 R0 K0
+ 0x541E0008, // 000B LDINT R7 9
+ 0x8C20010E, // 000C GETMET R8 R0 K14
+ 0x5C280200, // 000D MOVE R10 R1
+ 0x5C2C0400, // 000E MOVE R11 R2
+ 0x7C200600, // 000F CALL R8 3
+ 0x5C240600, // 0010 MOVE R9 R3
+ 0x5C280800, // 0011 MOVE R10 R4
+ 0x7C140A00, // 0012 CALL R5 5
+ 0x70020006, // 0013 JMP #001B
+ 0x8C140100, // 0014 GETMET R5 R0 K0
+ 0x541E0008, // 0015 LDINT R7 9
+ 0x8C20010E, // 0016 GETMET R8 R0 K14
+ 0x5C280200, // 0017 MOVE R10 R1
+ 0x5C2C0400, // 0018 MOVE R11 R2
+ 0x7C200600, // 0019 CALL R8 3
+ 0x7C140600, // 001A CALL R5 3
+ 0x80000000, // 001B RET 0
+ })
+ )
+);
+/*******************************************************************/
+
+
+/********************************************************************
+** Solidified function: create_segment
+********************************************************************/
+be_local_closure(class_Leds_create_segment, /* name */
+ be_nested_proto(
+ 8, /* nstack */
+ 3, /* argc */
+ 10, /* varg */
+ 0, /* has upvals */
+ NULL, /* no upvals */
+ 0, /* has sup protos */
+ NULL, /* no sub protos */
+ 1, /* has constants */
+ &be_ktab_class_Leds, /* shared constants */
+ &be_const_str_create_segment,
+ &be_const_str_solidified,
+ ( &(const binstruction[23]) { /* code */
+ 0x600C0009, // 0000 GETGBL R3 G9
+ 0x5C100200, // 0001 MOVE R4 R1
+ 0x7C0C0200, // 0002 CALL R3 1
+ 0x60100009, // 0003 GETGBL R4 G9
+ 0x5C140400, // 0004 MOVE R5 R2
+ 0x7C100200, // 0005 CALL R4 1
+ 0x000C0604, // 0006 ADD R3 R3 R4
+ 0x8810010A, // 0007 GETMBR R4 R0 K10
+ 0x240C0604, // 0008 GT R3 R3 R4
+ 0x740E0003, // 0009 JMPT R3 #000E
+ 0x140C0305, // 000A LT R3 R1 K5
+ 0x740E0001, // 000B JMPT R3 #000E
+ 0x140C0505, // 000C LT R3 R2 K5
+ 0x780E0000, // 000D JMPF R3 #000F
+ 0xB006170C, // 000E RAISE 1 K11 K12
+ 0x580C000F, // 000F LDCONST R3 K15
+ 0xB400000F, // 0010 CLASS K15
+ 0x5C100600, // 0011 MOVE R4 R3
+ 0x5C140000, // 0012 MOVE R5 R0
+ 0x5C180200, // 0013 MOVE R6 R1
+ 0x5C1C0400, // 0014 MOVE R7 R2
+ 0x7C100600, // 0015 CALL R4 3
+ 0x80040800, // 0016 RET 1 R4
+ })
+ )
+);
+/*******************************************************************/
+
+
+/********************************************************************
+** Solidified function: set_pixel_color
+********************************************************************/
+be_local_closure(class_Leds_set_pixel_color, /* name */
+ be_nested_proto(
+ 12, /* nstack */
+ 4, /* argc */
+ 10, /* varg */
+ 0, /* has upvals */
+ NULL, /* no upvals */
+ 0, /* has sup protos */
+ NULL, /* no sub protos */
+ 1, /* has constants */
+ &be_ktab_class_Leds, /* shared constants */
+ &be_const_str_set_pixel_color,
+ &be_const_str_solidified,
+ ( &(const binstruction[13]) { /* code */
+ 0x4C100000, // 0000 LDNIL R4
+ 0x1C100604, // 0001 EQ R4 R3 R4
+ 0x78120000, // 0002 JMPF R4 #0004
+ 0x880C0101, // 0003 GETMBR R3 R0 K1
+ 0x8C100100, // 0004 GETMET R4 R0 K0
+ 0x541A0009, // 0005 LDINT R6 10
+ 0x5C1C0200, // 0006 MOVE R7 R1
+ 0x8C20010E, // 0007 GETMET R8 R0 K14
+ 0x5C280400, // 0008 MOVE R10 R2
+ 0x5C2C0600, // 0009 MOVE R11 R3
+ 0x7C200600, // 000A CALL R8 3
+ 0x7C100800, // 000B CALL R4 4
+ 0x80000000, // 000C RET 0
+ })
+ )
+);
+/*******************************************************************/
+
+
+/********************************************************************
+** Solidified function: init
+********************************************************************/
+be_local_closure(class_Leds_init, /* name */
+ be_nested_proto(
+ 12, /* nstack */
+ 5, /* argc */
+ 10, /* varg */
+ 0, /* has upvals */
+ NULL, /* no upvals */
+ 0, /* has sup protos */
+ NULL, /* no sub protos */
+ 1, /* has constants */
+ &be_ktab_class_Leds, /* shared constants */
+ &be_const_str_init,
+ &be_const_str_solidified,
+ ( &(const binstruction[43]) { /* code */
+ 0xA4162000, // 0000 IMPORT R5 K16
+ 0x50180200, // 0001 LDBOOL R6 1 0
+ 0x90020E06, // 0002 SETMBR R0 K7 R6
+ 0x4C180000, // 0003 LDNIL R6
+ 0x1C180406, // 0004 EQ R6 R2 R6
+ 0x741A0005, // 0005 JMPT R6 #000C
+ 0x8C180B11, // 0006 GETMET R6 R5 K17
+ 0x88200B12, // 0007 GETMBR R8 R5 K18
+ 0x58240005, // 0008 LDCONST R9 K5
+ 0x7C180600, // 0009 CALL R6 3
+ 0x1C180406, // 000A EQ R6 R2 R6
+ 0x781A000A, // 000B JMPF R6 #0017
+ 0x8C180113, // 000C GETMET R6 R0 K19
+ 0x7C180200, // 000D CALL R6 1
+ 0x8C180114, // 000E GETMET R6 R0 K20
+ 0x7C180200, // 000F CALL R6 1
+ 0x90021406, // 0010 SETMBR R0 K10 R6
+ 0xA41A2A00, // 0011 IMPORT R6 K21
+ 0x8C1C0D16, // 0012 GETMET R7 R6 K22
+ 0x7C1C0200, // 0013 CALL R7 1
+ 0x941C0F01, // 0014 GETIDX R7 R7 K1
+ 0x90020207, // 0015 SETMBR R0 K1 R7
+ 0x7002000B, // 0016 JMP #0023
+ 0x60180009, // 0017 GETGBL R6 G9
+ 0x5C1C0200, // 0018 MOVE R7 R1
+ 0x7C180200, // 0019 CALL R6 1
+ 0x90021406, // 001A SETMBR R0 K10 R6
+ 0x541A007E, // 001B LDINT R6 127
+ 0x90020206, // 001C SETMBR R0 K1 R6
+ 0x8C180113, // 001D GETMET R6 R0 K19
+ 0x8820010A, // 001E GETMBR R8 R0 K10
+ 0x5C240400, // 001F MOVE R9 R2
+ 0x5C280600, // 0020 MOVE R10 R3
+ 0x5C2C0800, // 0021 MOVE R11 R4
+ 0x7C180A00, // 0022 CALL R6 5
+ 0x88180117, // 0023 GETMBR R6 R0 K23
+ 0x4C1C0000, // 0024 LDNIL R7
+ 0x1C180C07, // 0025 EQ R6 R6 R7
+ 0x781A0000, // 0026 JMPF R6 #0028
+ 0xB0063119, // 0027 RAISE 1 K24 K25
+ 0x8C18011A, // 0028 GETMET R6 R0 K26
+ 0x7C180200, // 0029 CALL R6 1
+ 0x80000000, // 002A RET 0
+ })
+ )
+);
+/*******************************************************************/
+
+
+/********************************************************************
+** Solidified function: clear
+********************************************************************/
+be_local_closure(class_Leds_clear, /* name */
+ be_nested_proto(
+ 4, /* nstack */
+ 1, /* argc */
+ 10, /* varg */
+ 0, /* has upvals */
+ NULL, /* no upvals */
+ 0, /* has sup protos */
+ NULL, /* no sub protos */
+ 1, /* has constants */
+ &be_ktab_class_Leds, /* shared constants */
+ &be_const_str_clear,
+ &be_const_str_solidified,
+ ( &(const binstruction[ 6]) { /* code */
+ 0x8C04011B, // 0000 GETMET R1 R0 K27
+ 0x580C0005, // 0001 LDCONST R3 K5
+ 0x7C040400, // 0002 CALL R1 2
+ 0x8C04011C, // 0003 GETMET R1 R0 K28
+ 0x7C040200, // 0004 CALL R1 1
+ 0x80000000, // 0005 RET 0
+ })
+ )
+);
+/*******************************************************************/
+
+
+/********************************************************************
+** Solidified function: begin
+********************************************************************/
+be_local_closure(class_Leds_begin, /* name */
+ be_nested_proto(
+ 4, /* nstack */
+ 1, /* argc */
+ 10, /* varg */
+ 0, /* has upvals */
+ NULL, /* no upvals */
+ 0, /* has sup protos */
+ NULL, /* no sub protos */
+ 1, /* has constants */
+ &be_ktab_class_Leds, /* shared constants */
+ &be_const_str_begin,
+ &be_const_str_solidified,
+ ( &(const binstruction[ 4]) { /* code */
+ 0x8C040100, // 0000 GETMET R1 R0 K0
+ 0x580C001D, // 0001 LDCONST R3 K29
+ 0x7C040400, // 0002 CALL R1 2
+ 0x80000000, // 0003 RET 0
+ })
+ )
+);
+/*******************************************************************/
+
+
+/********************************************************************
+** Solidified function: pixel_count
+********************************************************************/
+be_local_closure(class_Leds_pixel_count, /* name */
+ be_nested_proto(
+ 4, /* nstack */
+ 1, /* argc */
+ 10, /* varg */
+ 0, /* has upvals */
+ NULL, /* no upvals */
+ 0, /* has sup protos */
+ NULL, /* no sub protos */
+ 1, /* has constants */
+ &be_ktab_class_Leds, /* shared constants */
+ &be_const_str_pixel_count,
+ &be_const_str_solidified,
+ ( &(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: to_gamma
+********************************************************************/
+be_local_closure(class_Leds_to_gamma, /* name */
+ be_nested_proto(
+ 8, /* nstack */
+ 3, /* argc */
+ 10, /* varg */
+ 0, /* has upvals */
+ NULL, /* no upvals */
+ 0, /* has sup protos */
+ NULL, /* no sub protos */
+ 1, /* has constants */
+ &be_ktab_class_Leds, /* shared constants */
+ &be_const_str_to_gamma,
+ &be_const_str_solidified,
+ ( &(const binstruction[10]) { /* code */
+ 0x4C0C0000, // 0000 LDNIL R3
+ 0x1C0C0403, // 0001 EQ R3 R2 R3
+ 0x780E0000, // 0002 JMPF R3 #0004
+ 0x88080101, // 0003 GETMBR R2 R0 K1
+ 0x8C0C011E, // 0004 GETMET R3 R0 K30
+ 0x5C140200, // 0005 MOVE R5 R1
+ 0x5C180400, // 0006 MOVE R6 R2
+ 0x881C0107, // 0007 GETMBR R7 R0 K7
+ 0x7C0C0800, // 0008 CALL R3 4
+ 0x80040600, // 0009 RET 1 R3
})
)
);
@@ -2013,7 +1917,7 @@ be_local_closure(class_Leds_pixels_buffer, /* name */
&be_const_str_pixels_buffer,
&be_const_str_solidified,
( &(const binstruction[21]) { /* code */
- 0x8C080106, // 0000 GETMET R2 R0 K6
+ 0x8C080100, // 0000 GETMET R2 R0 K0
0x54120005, // 0001 LDINT R4 6
0x7C080400, // 0002 CALL R2 2
0x4C0C0000, // 0003 LDNIL R3
@@ -2021,15 +1925,15 @@ be_local_closure(class_Leds_pixels_buffer, /* name */
0x780E0009, // 0005 JMPF R3 #0010
0x600C0015, // 0006 GETGBL R3 G21
0x5C100400, // 0007 MOVE R4 R2
- 0x8C140129, // 0008 GETMET R5 R0 K41
+ 0x8C14011F, // 0008 GETMET R5 R0 K31
0x7C140200, // 0009 CALL R5 1
- 0x8C18010F, // 000A GETMET R6 R0 K15
+ 0x8C180114, // 000A GETMET R6 R0 K20
0x7C180200, // 000B CALL R6 1
0x08140A06, // 000C MUL R5 R5 R6
0x7C0C0400, // 000D CALL R3 2
0x80040600, // 000E RET 1 R3
0x70020003, // 000F JMP #0014
- 0x8C0C032A, // 0010 GETMET R3 R1 K42
+ 0x8C0C0320, // 0010 GETMET R3 R1 K32
0x5C140400, // 0011 MOVE R5 R2
0x7C0C0400, // 0012 CALL R3 2
0x80040200, // 0013 RET 1 R1
@@ -2047,35 +1951,34 @@ extern const bclass be_class_Leds_ntv;
be_local_class(Leds,
3,
&be_class_Leds_ntv,
- be_nested_map(27,
+ be_nested_map(26,
( (struct bmapnode*) &(const bmapnode[]) {
- { be_const_key(leds, -1), be_const_var(1) },
- { be_const_key(create_segment, 25), be_const_closure(class_Leds_create_segment_closure) },
- { be_const_key(clear, -1), be_const_closure(class_Leds_clear_closure) },
- { be_const_key(begin, -1), be_const_closure(class_Leds_begin_closure) },
- { be_const_key(ctor, 7), be_const_closure(class_Leds_ctor_closure) },
- { be_const_key(assign_rmt, 12), be_const_static_closure(class_Leds_assign_rmt_closure) },
- { be_const_key(to_gamma, 8), be_const_closure(class_Leds_to_gamma_closure) },
- { be_const_key(dirty, -1), be_const_closure(class_Leds_dirty_closure) },
- { be_const_key(matrix, -1), be_const_static_closure(class_Leds_matrix_closure) },
- { be_const_key(pixel_offset, 2), be_const_closure(class_Leds_pixel_offset_closure) },
- { be_const_key(set_gamma, 4), be_const_closure(class_Leds_set_gamma_closure) },
- { be_const_key(get_pixel_color, -1), be_const_closure(class_Leds_get_pixel_color_closure) },
- { be_const_key(pixel_size, -1), be_const_closure(class_Leds_pixel_size_closure) },
- { be_const_key(create_matrix, -1), be_const_closure(class_Leds_create_matrix_closure) },
- { be_const_key(set_bri, 9), be_const_closure(class_Leds_set_bri_closure) },
- { be_const_key(clear_to, -1), be_const_closure(class_Leds_clear_to_closure) },
- { be_const_key(set_pixel_color, -1), be_const_closure(class_Leds_set_pixel_color_closure) },
- { be_const_key(gamma, -1), be_const_var(0) },
- { be_const_key(pixel_count, 17), be_const_closure(class_Leds_pixel_count_closure) },
- { be_const_key(get_bri, 13), be_const_closure(class_Leds_get_bri_closure) },
- { be_const_key(get_gamma, -1), be_const_closure(class_Leds_get_gamma_closure) },
- { be_const_key(bri, -1), be_const_var(2) },
{ be_const_key(is_dirty, -1), be_const_closure(class_Leds_is_dirty_closure) },
- { be_const_key(can_show, -1), be_const_closure(class_Leds_can_show_closure) },
- { be_const_key(init, 5), be_const_closure(class_Leds_init_closure) },
- { be_const_key(show, -1), be_const_closure(class_Leds_show_closure) },
{ be_const_key(pixels_buffer, -1), be_const_closure(class_Leds_pixels_buffer_closure) },
+ { be_const_key(to_gamma, -1), be_const_closure(class_Leds_to_gamma_closure) },
+ { be_const_key(can_show, -1), be_const_closure(class_Leds_can_show_closure) },
+ { be_const_key(pixel_offset, -1), be_const_closure(class_Leds_pixel_offset_closure) },
+ { be_const_key(set_bri, 24), be_const_closure(class_Leds_set_bri_closure) },
+ { be_const_key(show, 2), be_const_closure(class_Leds_show_closure) },
+ { be_const_key(ctor, -1), be_const_closure(class_Leds_ctor_closure) },
+ { be_const_key(begin, 22), be_const_closure(class_Leds_begin_closure) },
+ { be_const_key(leds, -1), be_const_var(1) },
+ { be_const_key(set_pixel_color, -1), be_const_closure(class_Leds_set_pixel_color_closure) },
+ { be_const_key(dirty, 4), be_const_closure(class_Leds_dirty_closure) },
+ { be_const_key(get_pixel_color, -1), be_const_closure(class_Leds_get_pixel_color_closure) },
+ { be_const_key(get_gamma, -1), be_const_closure(class_Leds_get_gamma_closure) },
+ { be_const_key(gamma, -1), be_const_var(0) },
+ { be_const_key(create_matrix, -1), be_const_closure(class_Leds_create_matrix_closure) },
+ { be_const_key(matrix, 8), be_const_static_closure(class_Leds_matrix_closure) },
+ { be_const_key(create_segment, -1), be_const_closure(class_Leds_create_segment_closure) },
+ { be_const_key(bri, 10), be_const_var(2) },
+ { be_const_key(init, -1), be_const_closure(class_Leds_init_closure) },
+ { be_const_key(clear, -1), be_const_closure(class_Leds_clear_closure) },
+ { be_const_key(get_bri, 9), be_const_closure(class_Leds_get_bri_closure) },
+ { be_const_key(clear_to, -1), be_const_closure(class_Leds_clear_to_closure) },
+ { be_const_key(pixel_count, -1), be_const_closure(class_Leds_pixel_count_closure) },
+ { be_const_key(set_gamma, -1), be_const_closure(class_Leds_set_gamma_closure) },
+ { be_const_key(pixel_size, 1), be_const_closure(class_Leds_pixel_size_closure) },
})),
(bstring*) &be_const_str_Leds
);
diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h
index 5af1f9aaa..b2873e8df 100644
--- a/tasmota/my_user_config.h
+++ b/tasmota/my_user_config.h
@@ -562,14 +562,7 @@
// #define MAGICSWITCH_MASKING_WINDOW_LEN 5 // Overridable masking window (in number of 50ms loops)
// -- Optional light modules ----------------------
-#define USE_LIGHT // Add support for light control
-#define USE_WS2812 // WS2812 Led string using library NeoPixelBus (+5k code, +1k mem, 232 iram) - Disable by //
-// #define USE_WS2812_DMA // ESP8266 only, DMA supports only GPIO03 (= Serial RXD) (+1k mem). When USE_WS2812_DMA is enabled expect Exceptions on Pow
- #define USE_WS2812_RMT 0 // ESP32 only, hardware RMT support (default). Specify the RMT channel 0..7. This should be preferred to software bit bang.
-// #define USE_WS2812_I2S 0 // ESP32 only, hardware I2S support. Specify the I2S channel 0..2. This is exclusive from RMT. By default, prefer RMT support
-// #define USE_WS2812_INVERTED // Use inverted data signal
- #define USE_WS2812_HARDWARE NEO_HW_WS2812 // Hardware type (NEO_HW_WS2812, NEO_HW_WS2812X, NEO_HW_WS2813, NEO_HW_SK6812, NEO_HW_LC8812, NEO_HW_APA106, NEO_HW_P9813)
- #define USE_WS2812_CTYPE NEO_GRB // Color type (NEO_RGB, NEO_GRB, NEO_BRG, NEO_RBG, NEO_RGBW, NEO_GRBW)
+#define USE_LIGHT // Add support for light control
#define USE_MY92X1 // Add support for MY92X1 RGBCW led controller as used in Sonoff B1, Ailight and Lohas
#define USE_SM16716 // Add support for SM16716 RGB LED controller (+0k7 code)
#define USE_SM2135 // Add support for SM2135 RGBCW led control as used in Action LSC (+0k6 code)
@@ -583,6 +576,18 @@
#define USE_DGR_LIGHT_SEQUENCE // Add support for device group light sequencing (requires USE_DEVICE_GROUPS) (+0k2 code)
//#define USE_LSC_MCSL // Add support for GPE Multi color smart light as sold by Action in the Netherlands (+1k1 code)
+// -- Optional adressable leds ----------------------
+#define USE_WS2812 // WS2812 Led string using library NeoPixelBus (+5k code, +1k mem, 232 iram) - Disable by //
+// -------- below is for ESP8266 only
+// #define USE_WS2812_DMA // ESP8266 only, DMA supports only GPIO03 (= Serial RXD) (+1k mem). When USE_WS2812_DMA is enabled expect Exceptions on Pow
+ #define USE_WS2812_RMT 0 // ESP32 only, hardware RMT support (default). Specify the RMT channel 0..7. This should be preferred to software bit bang.
+// #define USE_WS2812_I2S 0 // ESP32 only, hardware I2S support. Specify the I2S channel 0..2. This is exclusive from RMT. By default, prefer RMT support
+// #define USE_WS2812_INVERTED // Use inverted data signal
+ #define USE_WS2812_HARDWARE NEO_HW_WS2812 // Hardware type (NEO_HW_WS2812, NEO_HW_WS2812X, NEO_HW_WS2813, NEO_HW_SK6812, NEO_HW_LC8812, NEO_HW_APA106, NEO_HW_P9813)
+ #define USE_WS2812_CTYPE NEO_GRB // Color type (NEO_RGB, NEO_GRB, NEO_BRG, NEO_RBG, NEO_RGBW, NEO_GRBW)
+// -------- below if for ESP32x only -- ESP32 uses a lightweight library instead of NeoPixelBus
+ // #define USE_WS2812_FORCE_NEOPIXELBUS // this option forces to use NeoPixelBus (like ESP866), which disables Berry support and limits features -- DO NOT USE unless you have a good reason
+
// #define USE_LIGHT_ARTNET // Add support for DMX/ArtNet via UDP on port 6454 (+3.5k code)
#define USE_LIGHT_ARTNET_MCAST 239,255,25,54 // Multicast address used to listen: 239.255.25.54
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_04_light_artnet.ino b/tasmota/tasmota_xdrv_driver/xdrv_04_light_artnet.ino
index d0d3b61ff..142044766 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_04_light_artnet.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_04_light_artnet.ino
@@ -386,7 +386,7 @@ bool ArtNetStart(void) {
Settings->light_rotation = 0;
Ws2812InitStrip();
} else {
- Ws2812Clear();
+ Ws2812Clear(true);
}
}
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_leds.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_leds.ino
index 0984cb14b..a06890b09 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_leds.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_leds.ino
@@ -24,22 +24,8 @@
#ifdef USE_WS2812
-#include
-
-enum {
- ws2812_grb = 1,
- sk6812_grbw = 2,
-
- neopixel_type_end
-};
-
-#ifdef CONFIG_IDF_TARGET_ESP32C2
-typedef NeoPixelBus neopixel_ws2812_grb_t;
-typedef NeoPixelBus neopixel_sk6812_grbw_t;
-#else
-typedef NeoPixelBus neopixel_ws2812_grb_t;
-typedef NeoPixelBus neopixel_sk6812_grbw_t;
-#endif
+#include "TasmotaLED.h"
+#include "TasmotaLEDPusher.h"
/*********************************************************************************************\
* Functions from Tasmota WS2812 driver
@@ -86,12 +72,12 @@ extern "C" {
// # 22 : ShiftLeft (rot:int [, first:int, last:int]) -> void
// # 23 : ShiftRight (rot:int [, first:int, last:int]) -> void
- void * be_get_neopixelbus(bvm *vm) {
+ void * be_get_tasmotaled(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");
+ be_raise(vm, "internal_error", "tasmotaled object not initialized");
}
return strip;
}
@@ -99,70 +85,65 @@ extern "C" {
be_getmember(vm, 1, "_t");
int32_t type = be_toint(vm, -1);
be_pop(vm, 1);
- if (type < 0 || type >= neopixel_type_end) {
+ if (type < 0) {
be_raise(vm, "internal_error", "invalid leds type");
}
return type;
}
- int be_neopixelbus_call_native(bvm *vm);
- int be_neopixelbus_call_native(bvm *vm) {
+ int be_tasmotaled_call_native(bvm *vm);
+ int be_tasmotaled_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 != 2) && !(argc >= 6 && be_isint(vm, 3) && be_isint(vm, 4) && be_isint(vm, 5) && be_isint(vm, 6))) {
- be_raise(vm, "value_error", "bad arguments for neopixelbus:ctor");
+ if ((argc != 2) && !(argc >= 5 && be_isint(vm, 3) && be_isint(vm, 4) && be_isint(vm, 5))) {
+ be_raise(vm, "value_error", "bad arguments for tasmotaled:ctor");
}
int32_t leds = -1;
int32_t gpio = -1;
- int32_t neopixel_type = 0;
- int32_t rmt = 0;
- void * strip = nullptr;
+ int32_t led_type = 0;
+ int32_t hardware = 0;
+ if (argc >= 6 && be_isint(vm, 6)) {
+ hardware = be_toint(vm, 6) & 0xFF0000; // remove the low 16 bits to avoid any interference with legacy parameter for RMT channels
+ }
+ TasmotaLED * strip = nullptr;
if (argc > 2) {
leds = be_toint(vm, 3);
gpio = be_toint(vm, 4);
- neopixel_type = be_toint(vm, 5);
- rmt = be_toint(vm, 6);
+ led_type = be_toint(vm, 5);
}
if (-1 == gpio) {
// if GPIO is '-1'
- neopixel_type = 0;
- Ws2812InitStrip(); // ensure the NeoPixelbus object is initialized, because Berry code runs before the driver is initialized
- strip = Ws2812GetStrip();
+ led_type = 0;
+ Ws2812InitStrip(); // ensure the tasmotaled object is initialized, because Berry code runs before the driver is initialized
+ // strip = Ws2812GetStrip(); TODO
} else {
- // allocate a new RMT
- if (neopixel_type < 1) { neopixel_type = 1; }
- if (neopixel_type >= neopixel_type_end) { neopixel_type = neopixel_type_end - 1; }
- if (rmt < 0) { rmt = 0; }
- if (rmt >= MAX_RMT) { rmt = MAX_RMT - 1; }
-
- switch (neopixel_type) {
- case ws2812_grb: strip = new neopixel_ws2812_grb_t(leds, gpio, (NeoBusChannel) rmt);
- break;
- case sk6812_grbw: strip = new neopixel_sk6812_grbw_t(leds, gpio, (NeoBusChannel) rmt);
- break;
+ if (led_type < 1) { led_type = 1; }
+ TasmotaLEDPusher * pusher = TasmotaLEDPusher::Create(hardware, gpio);
+ if (pusher == nullptr) {
+ be_raise(vm, "value_error", "LED interface not supported");
}
+ strip = new TasmotaLED(led_type, leds);
+ strip->SetPusher(pusher);
}
+ // AddLog(LOG_LEVEL_DEBUG, "LED: leds %i gpio %i type %i", leds, gpio, led_type);
// store type in attribute `_t`
- be_pushint(vm, neopixel_type);
+ be_pushint(vm, led_type);
be_setmember(vm, 1, "_t");
be_pop(vm, 1);
- be_pushcomptr(vm, (void*) strip);
+ be_pushcomptr(vm, (void*) strip); // if native driver, it is NULL
be_setmember(vm, 1, "_p");
be_pop(vm, 1);
be_pushnil(vm);
} else {
- // all other commands need a valid neopixelbus pointer
+ // all other commands need a valid tasmotaled 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_sk6812_grbw_t * s_sk6812_grbw = (leds_type == sk6812_grbw) ? (neopixel_sk6812_grbw_t*) s : nullptr;
+ TasmotaLED * strip = (TasmotaLED*) be_get_tasmotaled(vm); // raises an exception if pointer is invalid
// detect native driver
bool native = (leds_type == 0);
@@ -171,8 +152,7 @@ extern "C" {
switch (cmd) {
case 1: // # 01 : begin void -> void
if (native) Ws2812Begin();
- if (s_ws2812_grb) s_ws2812_grb->Begin();
- if (s_sk6812_grbw) s_sk6812_grbw->Begin();
+ else if (strip) strip->Begin();
break;
case 2: // # 02 : show void -> void
{
@@ -195,49 +175,50 @@ extern "C" {
}
}
uint32_t pixels_size; // number of bytes to push
- if (native) { Ws2812Show(); pixels_size = Ws2812PixelsSize(); }
- if (s_ws2812_grb) { s_ws2812_grb->Show(); pixels_size = s_ws2812_grb->PixelsSize(); }
- if (s_sk6812_grbw) { s_sk6812_grbw->Show(); pixels_size = s_sk6812_grbw->PixelsSize(); }
+ bool update_completed = false;
+ if (native) {
+ Ws2812Show();
+ pixels_size = Ws2812PixelsSize();
+ update_completed =Ws2812CanShow();
+ }
+ else if (strip) {
+ strip->Show();
+ pixels_size = strip->PixelCount() * strip->PixelSize();
+ update_completed = strip->CanShow();
+ }
// Wait for RMT/I2S to complete fixes distortion due to analogRead
// 1ms is needed for 96 bytes
- SystemBusyDelay((pixels_size + 95) / 96);
+ if (!update_completed) {
+ SystemBusyDelay((pixels_size + 95) / 96);
+ }
}
break;
case 3: // # 03 : CanShow void -> bool
if (native) be_pushbool(vm, Ws2812CanShow());
- if (s_ws2812_grb) be_pushbool(vm, s_ws2812_grb->CanShow());
- if (s_sk6812_grbw) be_pushbool(vm, s_sk6812_grbw->CanShow());
+ else if (strip) be_pushbool(vm, strip->CanShow());
break;
case 4: // # 04 : IsDirty void -> bool
if (native) be_pushbool(vm, Ws2812IsDirty());
- if (s_ws2812_grb) be_pushbool(vm, s_ws2812_grb->IsDirty());
- if (s_sk6812_grbw) be_pushbool(vm, s_sk6812_grbw->IsDirty());
+ else if (strip) be_pushbool(vm, strip->IsDirty());
break;
case 5: // # 05 : Dirty void -> void
if (native) Ws2812Dirty();
- if (s_ws2812_grb) s_ws2812_grb->Dirty();
- if (s_sk6812_grbw) s_sk6812_grbw->Dirty();
+ else if (strip) strip->Dirty();
break;
case 6: // # 06 : Pixels void -> bytes() (mapped to the buffer)
{
- uint8_t * pixels;
- if (native) pixels = Ws2812Pixels();
- if (s_ws2812_grb) pixels = s_ws2812_grb->Pixels();
- if (s_sk6812_grbw) pixels = s_sk6812_grbw->Pixels();
-
- be_pushcomptr(vm, pixels);
+ if (native) be_pushcomptr(vm, Ws2812Pixels());
+ else if (strip) be_pushcomptr(vm, strip->Pixels());
}
break;
case 7: // # 07 : PixelSize void -> int
if (native) be_pushint(vm, Ws2812PixelSize());
- if (s_ws2812_grb) be_pushint(vm, s_ws2812_grb->PixelSize());
- if (s_sk6812_grbw) be_pushint(vm, s_sk6812_grbw->PixelSize());
+ else if (strip) be_pushint(vm, strip->PixelSize());
break;
case 8: // # 08 : PixelCount void -> int
if (native) be_pushint(vm, Ws2812PixelCount());
- if (s_ws2812_grb) be_pushint(vm, s_ws2812_grb->PixelCount());
- if (s_sk6812_grbw) be_pushint(vm, s_sk6812_grbw->PixelCount());
+ else if (strip) be_pushint(vm, strip->PixelCount());
break;
case 9: // # 09 : ClearTo (color:??) -> void
{
@@ -253,42 +234,35 @@ extern "C" {
if (len < 0) { len = 0; }
if (native) Ws2812ClearTo(r, g, b, w, from, from + len - 1);
- if (s_ws2812_grb) s_ws2812_grb->ClearTo(RgbColor(r, g, b), from, from + len - 1);
- if (s_sk6812_grbw) s_sk6812_grbw->ClearTo(RgbwColor(r, g, b, w), from, from + len - 1);
+ else if (strip) strip->ClearTo(rgbw, from, from + len - 1);
} else {
if (native) Ws2812ClearTo(r, g, b, w, -1, -1);
- if (s_ws2812_grb) s_ws2812_grb->ClearTo(RgbColor(r, g, b));
- if (s_sk6812_grbw) s_sk6812_grbw->ClearTo(RgbwColor(r, g, b, w));
+ else if (strip) strip->ClearTo(rgbw);
}
}
break;
- case 10: // # 10 : SetPixelColor (idx:int, color:??) -> void
+ case 10: // # 10 : SetPixelColor (idx:int, color:int wrgb) -> void
{
int32_t idx = be_toint(vm, 3);
- uint32_t rgbw = be_toint(vm, 4);
- uint8_t w = (rgbw >> 24) & 0xFF;
- uint8_t r = (rgbw >> 16) & 0xFF;
- uint8_t g = (rgbw >> 8) & 0xFF;
- uint8_t b = (rgbw ) & 0xFF;
- if (native) Ws2812SetPixelColor(idx, r, g, b, w);
- if (s_ws2812_grb) s_ws2812_grb->SetPixelColor(idx, RgbColor(r, g, b));
- if (s_sk6812_grbw) s_sk6812_grbw->SetPixelColor(idx, RgbwColor(r, g, b, w));
+ uint32_t wrgb = be_toint(vm, 4);
+ if (native) {
+ uint8_t w = (wrgb >> 24) & 0xFF;
+ uint8_t r = (wrgb >> 16) & 0xFF;
+ uint8_t g = (wrgb >> 8) & 0xFF;
+ uint8_t b = (wrgb ) & 0xFF;
+ Ws2812SetPixelColor(idx, r, g, b, w);
+ } else if (strip) {
+ strip->SetPixelColor(idx, wrgb);
+ }
}
break;
- case 11: // # 11 : GetPixelColor (idx:int) -> color:??
+ case 11: // # 11 : GetPixelColor (idx:int) -> color:int wrgb
{
int32_t idx = be_toint(vm, 3);
-
if (native) {
be_pushint(vm, Ws2812GetPixelColor(idx));
- }
- if (s_ws2812_grb) {
- RgbColor rgb = s_ws2812_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) | (rgbw.R << 16) | (rgbw.G << 8) | rgbw.B);
+ } else if (strip) {
+ be_pushint(vm, strip->GetPixelColor(idx));
}
}
break;
diff --git a/tasmota/tasmota_xlgt_light/xlgt_01_ws2812.ino b/tasmota/tasmota_xlgt_light/xlgt_01_ws2812.ino
index b05d15e8a..9be3d3117 100644
--- a/tasmota/tasmota_xlgt_light/xlgt_01_ws2812.ino
+++ b/tasmota/tasmota_xlgt_light/xlgt_01_ws2812.ino
@@ -17,6 +17,7 @@
along with this program. If not, see .
*/
+#if defined(ESP8266) || defined(USE_WS2812_FORCE_NEOPIXELBUS)
#ifdef USE_LIGHT
#ifdef USE_WS2812
@@ -553,11 +554,14 @@ void Ws2812DDP(void)
}
#endif // USE_NETWORK_LIGHT_SCHEMES
-void Ws2812Clear(void)
+void Ws2812Clear(bool display = true);
+void Ws2812Clear(bool display)
{
strip->ClearTo(0);
- Ws2812LibStripShow();
- Ws2812.show_next = 1;
+ if (display) {
+ Ws2812LibStripShow();
+ Ws2812.show_next = 1;
+ }
}
void Ws2812SetColor(uint32_t led, uint8_t red, uint8_t green, uint8_t blue, uint8_t white)
@@ -965,3 +969,4 @@ bool Xlgt01(uint32_t function)
#endif // USE_WS2812
#endif // USE_LIGHT
+#endif // defined(ESP8266) || defined(USE_WS2812_FORCE_NEOPIXELBUS)
diff --git a/tasmota/tasmota_xlgt_light/xlgt_01_ws2812_esp32.ino b/tasmota/tasmota_xlgt_light/xlgt_01_ws2812_esp32.ino
new file mode 100644
index 000000000..5ff5d94dd
--- /dev/null
+++ b/tasmota/tasmota_xlgt_light/xlgt_01_ws2812_esp32.ino
@@ -0,0 +1,899 @@
+/*
+ xlgt_01_ws2812.ino - led string support for Tasmota
+
+ Copyright (C) 2021 Theo Arends
+
+ 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 ESP32
+#ifdef USE_LIGHT
+#if defined(USE_WS2812) && !defined(USE_WS2812_FORCE_NEOPIXELBUS)
+
+/*********************************************************************************************\
+ * WS2812 RGB / RGBW Leds using NeopixelBus library
+ *
+ * light_scheme WS2812 3+ Colors 1+2 Colors Effect
+ * ------------ ------ --------- ---------- -----------------
+ * 0 (5) yes no no Clock
+ * 1 (6) yes no no Incandescent
+ * 2 (7) yes no no RGB
+ * 3 (8) yes no no Christmas
+ * 4 (9) yes no no Hanukkah
+ * 5 (10) yes no no Kwanzaa
+ * 6 (11) yes no no Rainbow
+ * 7 (12) yes no no Fire
+ * 8 (13) yes no no Stairs
+ * 9 (14) yes no no Clear (= Berry)
+ * 10 (15) yes no no Optional DDP
+\*********************************************************************************************/
+
+#define XLGT_01 1
+
+const uint8_t WS2812_SCHEMES = 10; // Number of WS2812 schemes
+
+const char kWs2812Commands[] PROGMEM = "|" // No prefix
+ D_CMND_LED "|" D_CMND_PIXELS "|" D_CMND_ROTATION "|" D_CMND_WIDTH "|" D_CMND_STEPPIXELS ;
+
+void (* const Ws2812Command[])(void) PROGMEM = {
+ &CmndLed, &CmndPixels, &CmndRotation, &CmndWidth, &CmndStepPixels };
+
+#include
+
+const uint16_t kLedType = 0;
+// select the right pixel size
+#if (USE_WS2812_CTYPE > NEO_3LED)
+ const uint16_t kTasLed_PixelSize = TasmotaLed_4_WRGB;
+#else
+ const uint16_t kTasLed_PixelSize = TasmotaLed_3_RGB;
+#endif
+
+// select the right pixel order
+#if (USE_WS2812_CTYPE == NEO_GRB)
+ const uint16_t kTasLed_PixelOrder = TasmotaLed_GRB;
+#elif (USE_WS2812_CTYPE == NEO_BRG)
+ const uint16_t kTasLed_PixelOrder = TasmotaLed_BRG;
+#elif (USE_WS2812_CTYPE == NEO_RBG)
+ const uint16_t kTasLed_PixelOrder = TasmotaLed_RBG;
+ #elif (USE_WS2812_CTYPE == NEO_RGBW)
+ const uint16_t kTasLed_PixelOrder = TasmotaLed_RGB;
+#elif (USE_WS2812_CTYPE == NEO_GRBW)
+ const uint16_t kTasLed_PixelOrder = TasmotaLed_GRB;
+#else
+ const uint16_t kTasLed_PixelOrder = TasmotaLed_RGB;
+#endif
+
+// all leds have always W at the end
+const uint16_t kTasLed_PixelWhite = TasmotaLed_xxxW;
+
+// We drop support for NEO_HW_P9813, as it is too hard to support with hardwarre
+#if (USE_WS2812_HARDWARE == NEO_HW_P9813)
+ #error "P9813 is not supported by this library"
+#endif // USE_WS2812_CTYPE
+
+// select timing
+#if (USE_WS2812_HARDWARE == NEO_HW_WS2812X)
+ const uint16_t kTasLed_Timing = TasmotaLed_WS2812;
+#elif (USE_WS2812_HARDWARE == NEO_HW_SK6812)
+ const uint16_t kTasLed_Timing = TasmotaLed_SK6812;
+#elif (USE_WS2812_HARDWARE == NEO_HW_APA106)
+ #error "APA106 is not supported by this library"
+#else // USE_WS2812_HARDWARE
+ const uint16_t kTasLed_Timing = TasmotaLed_WS2812;
+#endif // USE_WS2812_HARDWARE
+
+const uint16_t kTasLed_Type = kTasLed_PixelSize | kTasLed_PixelOrder | kTasLed_PixelWhite | kTasLed_Timing;
+
+// select hardware acceleration - bitbanging is not supported on ESP32 due to interference of interrupts
+#if CONFIG_IDF_TARGET_ESP32C2
+ const uint32_t kTasLed_Hardware = TasmotaLed_I2S; // I2S
+#else // all other ESP32 variants
+ #if defined(USE_WS2812_DMA)
+ const uint32_t kTasLed_Hardware = TasmotaLed_RMT; // default DMA to RMT
+ #elif defined(USE_WS2812_RMT)
+ const uint32_t kTasLed_Hardware = TasmotaLed_RMT; // default DMA to RMT
+ #elif defined(USE_WS2812_I2S)
+ const uint32_t kTasLed_Hardware = TasmotaLed_I2S; // I2S
+ #else
+ const uint32_t kTasLed_Hardware = TasmotaLed_RMT; // default DMA to RMT
+ #endif
+#endif
+
+#if (USE_WS2812_HARDWARE == NEO_HW_P9813)
+ #error "P9813 is not supported by this library"
+#endif
+
+
+/*******************************************************************************************\
+ * Support for TasmotaLED
+ *
+ * From here we have defined:
+ * kTasLed_Type: encodes pixel size, pixel order, pixel white, timing
+ * kTasLed_Hardware: encodes the harware support to push to Leds: RMT, SPI, I2S
+ *******************************************************************************************/
+TasmotaLED *strip = nullptr;
+
+typedef union LedColor {
+ uint32_t C; // encoded as 0xWWRRGGBB
+ struct {
+ uint8_t B, G, R, W; // WRGB in little endian
+ };
+} LedColor;
+
+struct ColorScheme {
+ const LedColor* colors;
+ uint8_t count;
+};
+
+const LedColor kIncandescent[2] = { 0xFF8C14, 0x000000 };
+const LedColor kRgb[3] = { 0xFF0000, 0x00FF00, 0x0000FF };
+const LedColor kChristmas[2] = { 0xFF0000, 0x00FF00 };
+const LedColor kHanukkah[2] = { 0x0000FF, 0xFFFFFF };
+const LedColor kwanzaa[3] = { 0xFF0000, 0x000000, 0x00FF00 };
+const LedColor kRainbow[7] = { 0xFF0000, 0xFF8000, 0xFFFF00, 0x00FF00, 0x0000FF, 0x8000FF, 0xFF00FF };
+const LedColor kFire[3] = { 0xFF0000, 0xFF6600, 0xFFC000 };
+const LedColor kStairs[2] = { 0x000000, 0xFFFFFF0 };
+
+const ColorScheme kSchemes[WS2812_SCHEMES -2] = { // Skip clock and clear scheme
+ kIncandescent, 2,
+ kRgb, 3,
+ kChristmas, 2,
+ kHanukkah, 2,
+ kwanzaa, 3,
+ kRainbow, 7,
+ kFire, 3,
+ kStairs, 2
+};
+
+const uint8_t kWidth[5] = {
+ 1, // Small
+ 2, // Medium
+ 4, // Large
+ 8, // Largest
+ 255 // All
+};
+const uint8_t kWsRepeat[5] = {
+ 8, // Small
+ 6, // Medium
+ 4, // Large
+ 2, // Largest
+ 1 // All
+};
+
+struct WS2812 {
+ uint8_t show_next = 1;
+ uint8_t scheme_offset = 0;
+ bool suspend_update = false;
+} Ws2812;
+
+/********************************************************************************************/
+
+// For some reason map fails to compile so renamed to wsmap
+long wsmap(long x, long in_min, long in_max, long out_min, long out_max) {
+ return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
+}
+
+void Ws2812LibStripShow(void) {
+ strip->Show();
+
+#if defined(USE_WS2812_DMA) || defined(USE_WS2812_RMT) || defined(USE_WS2812_I2S)
+ // Wait for DMA/RMT/I2S to complete fixes distortion due to analogRead
+// delay((Settings->light_pixels >> 6) +1); // 256 / 64 = 4 +1 = 5
+ SystemBusyDelay( (Settings->light_pixels + 31) >> 5); // (256 + 32) / 32 = 8
+#endif
+}
+
+void Ws2812StripShow(void)
+{
+ LedColor c;
+
+ if (Settings->light_correction) {
+ for (uint32_t i = 0; i < Settings->light_pixels; i++) {
+ c.C = strip->GetPixelColor(i);
+ c.R = ledGamma(c.R);
+ c.G = ledGamma(c.G);
+ c.B = ledGamma(c.B);
+#if (USE_WS2812_CTYPE > NEO_3LED)
+ c.W = ledGamma(c.W);
+#endif
+ strip->SetPixelColor(i, c.C);
+ }
+ }
+ Ws2812LibStripShow();
+}
+
+int mod(int a, int b)
+{
+ int ret = a % b;
+ if (ret < 0) ret += b;
+ return ret;
+}
+
+void Ws2812UpdatePixelColor(int position, LedColor hand_color, float offset);
+void Ws2812UpdatePixelColor(int position, LedColor hand_color, float offset)
+{
+ LedColor color;
+
+ uint32_t mod_position = mod(position, (int)Settings->light_pixels);
+
+ color.C = strip->GetPixelColor(mod_position);
+ float dimmer = 100 / (float)Settings->light_dimmer;
+ color.R = tmin(color.R + ((hand_color.R / dimmer) * offset), 255);
+ color.G = tmin(color.G + ((hand_color.G / dimmer) * offset), 255);
+ color.B = tmin(color.B + ((hand_color.B / dimmer) * offset), 255);
+ strip->SetPixelColor(mod_position, color.C);
+}
+
+void Ws2812UpdateHand(int position, uint32_t index)
+{
+ uint32_t width = Settings->light_width;
+ if (index < WS_MARKER) { width = Settings->ws_width[index]; }
+ if (!width) { return; } // Skip
+
+ position = (position + Settings->light_rotation) % Settings->light_pixels;
+
+ if (Settings->flag.ws_clock_reverse) { // SetOption16 - Switch between clockwise or counter-clockwise
+ position = Settings->light_pixels -position;
+ }
+ LedColor hand_color = {0};
+ hand_color.R = Settings->ws_color[index][WS_RED];
+ hand_color.G = Settings->ws_color[index][WS_GREEN];
+ hand_color.B = Settings->ws_color[index][WS_BLUE];
+
+ Ws2812UpdatePixelColor(position, hand_color, 1);
+
+ uint32_t range = ((width -1) / 2) +1;
+ for (uint32_t h = 1; h < range; h++) {
+ float offset = (float)(range - h) / (float)range;
+ Ws2812UpdatePixelColor(position -h, hand_color, offset);
+ Ws2812UpdatePixelColor(position +h, hand_color, offset);
+ }
+}
+
+void Ws2812Clock(void)
+{
+ strip->ClearTo(0); // Reset strip
+ int clksize = 60000 / (int)Settings->light_pixels;
+
+ Ws2812UpdateHand((RtcTime.second * 1000) / clksize, WS_SECOND);
+ Ws2812UpdateHand((RtcTime.minute * 1000) / clksize, WS_MINUTE);
+ Ws2812UpdateHand((((RtcTime.hour % 12) * 5000) + ((RtcTime.minute * 1000) / 12 )) / clksize, WS_HOUR);
+ if (Settings->ws_color[WS_MARKER][WS_RED] + Settings->ws_color[WS_MARKER][WS_GREEN] + Settings->ws_color[WS_MARKER][WS_BLUE]) {
+ for (uint32_t i = 0; i < 12; i++) {
+ Ws2812UpdateHand((i * 5000) / clksize, WS_MARKER);
+ }
+ }
+
+ Ws2812StripShow();
+}
+
+void Ws2812GradientColor(uint32_t schemenr, LedColor* mColor, uint32_t range, uint32_t gradRange, uint32_t i);
+void Ws2812GradientColor(uint32_t schemenr, LedColor* mColor, uint32_t range, uint32_t gradRange, uint32_t i)
+{
+/*
+ * Compute the color of a pixel at position i using a gradient of the color scheme.
+ * This function is used internally by the gradient function.
+ */
+ ColorScheme scheme = kSchemes[schemenr];
+ uint32_t curRange = i / range;
+ uint32_t rangeIndex = i % range;
+ uint32_t colorIndex = rangeIndex / gradRange;
+ uint32_t start = colorIndex;
+ uint32_t end = colorIndex +1;
+ if (curRange % 2 != 0) {
+ start = (scheme.count -1) - start;
+ end = (scheme.count -1) - end;
+ }
+ float dimmer = 100 / (float)Settings->light_dimmer;
+ float fmyRed = (float)wsmap(rangeIndex % gradRange, 0, gradRange, scheme.colors[start].R, scheme.colors[end].R) / dimmer;
+ float fmyGrn = (float)wsmap(rangeIndex % gradRange, 0, gradRange, scheme.colors[start].G, scheme.colors[end].G) / dimmer;
+ float fmyBlu = (float)wsmap(rangeIndex % gradRange, 0, gradRange, scheme.colors[start].B, scheme.colors[end].B) / dimmer;
+ mColor->R = (uint8_t)fmyRed;
+ mColor->G = (uint8_t)fmyGrn;
+ mColor->B = (uint8_t)fmyBlu;
+}
+
+void Ws2812Gradient(uint32_t schemenr)
+{
+/*
+ * This routine courtesy Tony DiCola (Adafruit)
+ * Display a gradient of colors for the current color scheme.
+ * Repeat is the number of repetitions of the gradient (pick a multiple of 2 for smooth looping of the gradient).
+ */
+ LedColor c;
+
+ ColorScheme scheme = kSchemes[schemenr];
+ if (scheme.count < 2) { return; }
+
+ uint32_t repeat = kWsRepeat[Settings->light_width]; // number of scheme.count per ledcount
+ uint32_t range = (uint32_t)ceil((float)Settings->light_pixels / (float)repeat);
+ uint32_t gradRange = (uint32_t)ceil((float)range / (float)(scheme.count - 1));
+ uint32_t speed = ((Settings->light_speed * 2) -1) * (STATES / 10);
+ uint32_t offset = speed > 0 ? Light.strip_timer_counter / speed : 0;
+
+ LedColor oldColor, currentColor;
+ Ws2812GradientColor(schemenr, &oldColor, range, gradRange, offset);
+ currentColor = oldColor;
+ speed = speed ? speed : 1; // should never happen, just avoid div0
+ for (uint32_t i = 0; i < Settings->light_pixels; i++) {
+ if (kWsRepeat[Settings->light_width] > 1) {
+ Ws2812GradientColor(schemenr, ¤tColor, range, gradRange, i + offset + 1);
+ }
+ // Blend old and current color based on time for smooth movement.
+ c.R = wsmap(Light.strip_timer_counter % speed, 0, speed, oldColor.R, currentColor.R);
+ c.G = wsmap(Light.strip_timer_counter % speed, 0, speed, oldColor.G, currentColor.G);
+ c.B = wsmap(Light.strip_timer_counter % speed, 0, speed, oldColor.B, currentColor.B);
+ strip->SetPixelColor(i, c.C);
+ oldColor = currentColor;
+ }
+ Ws2812StripShow();
+}
+
+void Ws2812Bars(uint32_t schemenr)
+{
+/*
+ * This routine courtesy Tony DiCola (Adafruit)
+ * Display solid bars of color for the current color scheme.
+ * Width is the width of each bar in pixels/lights.
+ */
+ LedColor c;
+
+ ColorScheme scheme = kSchemes[schemenr];
+
+ uint32_t maxSize = Settings->light_pixels / scheme.count;
+ if (kWidth[Settings->light_width] > maxSize) { maxSize = 0; }
+
+ uint32_t speed = ((Settings->light_speed * 2) -1) * (STATES / 10);
+ uint32_t offset = (speed > 0) ? Light.strip_timer_counter / speed : 0;
+
+ LedColor mcolor[scheme.count];
+ memcpy(mcolor, scheme.colors, sizeof(mcolor));
+ float dimmer = 100 / (float)Settings->light_dimmer;
+ for (uint32_t i = 0; i < scheme.count; i++) {
+ float fmyRed = (float)mcolor[i].R / dimmer;
+ float fmyGrn = (float)mcolor[i].G / dimmer;
+ float fmyBlu = (float)mcolor[i].B / dimmer;
+ mcolor[i].R = (uint8_t)fmyRed;
+ mcolor[i].G = (uint8_t)fmyGrn;
+ mcolor[i].B = (uint8_t)fmyBlu;
+ }
+ uint32_t colorIndex = offset % scheme.count;
+ for (uint32_t i = 0; i < Settings->light_pixels; i++) {
+ if (maxSize) { colorIndex = ((i + offset) % (scheme.count * kWidth[Settings->light_width])) / kWidth[Settings->light_width]; }
+ c.R = mcolor[colorIndex].R;
+ c.G = mcolor[colorIndex].G;
+ c.B = mcolor[colorIndex].B;
+ strip->SetPixelColor(i, c.C);
+ }
+ Ws2812StripShow();
+}
+
+void Ws2812Steps(uint32_t schemenr) {
+ LedColor c;
+
+ ColorScheme scheme = kSchemes[schemenr];
+ // apply main color if current sheme == kStairs
+ if (scheme.colors == kStairs) {
+ // we patch the colors
+ static LedColor colors_stairs[2] = {
+ { 0x000000 },
+ { .B = Settings->light_color[2], .G = Settings->light_color[1], .R = Settings->light_color[0] }
+ };
+ scheme.colors = colors_stairs;
+ }
+
+ uint8_t scheme_count = scheme.count;
+ if (Settings->light_fade) {
+ scheme_count = Settings->ws_width[WS_HOUR]; // Width4
+ }
+ if (scheme_count < 2) {
+ scheme_count = 2;
+ }
+
+ LedColor mcolor[scheme_count];
+
+ uint8_t color_start = 0;
+ uint8_t color_end = 1;
+ if (Settings->light_rotation & 0x01) {
+ color_start = 1;
+ color_end = 0;
+ }
+
+ if (Settings->light_fade) {
+ // generate gradient (width = Width4)
+ for (uint32_t i = 1; i < scheme_count - 1; i++) {
+ mcolor[i].R = (uint8_t) wsmap(i, 0, scheme_count, scheme.colors[color_start].R, scheme.colors[color_end].R);
+ mcolor[i].G = (uint8_t) wsmap(i, 0, scheme_count, scheme.colors[color_start].G, scheme.colors[color_end].G);
+ mcolor[i].B = (uint8_t) wsmap(i, 0, scheme_count, scheme.colors[color_start].B, scheme.colors[color_end].B);
+ }
+ } else {
+ memcpy(mcolor, scheme.colors, sizeof(mcolor));
+ }
+ // Repair first & last color in gradient; apply scheme rotation if fade==0
+ mcolor[0].R = scheme.colors[color_start].R;
+ mcolor[0].G = scheme.colors[color_start].G;
+ mcolor[0].B = scheme.colors[color_start].B;
+ mcolor[scheme_count-1].R = scheme.colors[color_end].R;
+ mcolor[scheme_count-1].G = scheme.colors[color_end].G;
+ mcolor[scheme_count-1].B = scheme.colors[color_end].B;
+
+ // Adjust to dimmer value
+ float dimmer = 100 / (float)Settings->light_dimmer;
+ for (uint32_t i = 0; i < scheme_count; i++) {
+ float fmyRed = (float)mcolor[i].R / dimmer;
+ float fmyGrn = (float)mcolor[i].G / dimmer;
+ float fmyBlu = (float)mcolor[i].B / dimmer;
+ mcolor[i].R = (uint8_t)fmyRed;
+ mcolor[i].G = (uint8_t)fmyGrn;
+ mcolor[i].B = (uint8_t)fmyBlu;
+ }
+
+ uint32_t speed = Settings->light_speed;
+ int32_t current_position = Light.strip_timer_counter / speed;
+
+ //all pixels are shown already | rotation change will not change current state
+ if (current_position > Settings->light_pixels / Settings->light_step_pixels + scheme_count ) {
+ return;
+ }
+
+ int32_t colorIndex;
+ int32_t step_nr;
+
+ for (uint32_t i = 0; i < Settings->light_pixels; i++) {
+ step_nr = i / Settings->light_step_pixels;
+ colorIndex = current_position - step_nr;
+ if (colorIndex < 0) { colorIndex = 0; }
+ if (colorIndex > scheme_count - 1) { colorIndex = scheme_count - 1; }
+ c.R = mcolor[colorIndex].R;
+ c.G = mcolor[colorIndex].G;
+ c.B = mcolor[colorIndex].B;
+ // Adjust the scheme rotation
+ if (Settings->light_rotation & 0x02) {
+ strip->SetPixelColor(Settings->light_pixels - i - 1, c.C);
+ } else {
+ strip->SetPixelColor(i, c.C);
+ }
+ }
+ Ws2812StripShow();
+}
+
+#ifdef USE_NETWORK_LIGHT_SCHEMES
+void Ws2812DDP(void)
+{
+ LedColor c = {0};
+
+ // Can't be trying to initialize UDP too early.
+ if (TasmotaGlobal.restart_flag || TasmotaGlobal.global_state.network_down) return;
+
+ // Start DDP listener, if fail, just set last ddp_color
+ if (!ddp_udp_up) {
+ if (!ddp_udp.begin(4048)) return;
+ ddp_udp_up = 1;
+ AddLog(LOG_LEVEL_DEBUG_MORE, "DDP: UDP Listener Started: WS2812 Scheme");
+ }
+
+ // Get the DDP payload over UDP
+ std::vector payload;
+ while (uint16_t packet_size = ddp_udp.parsePacket()) {
+ payload.resize(packet_size);
+ if (!ddp_udp.read(&payload[0], payload.size())) {
+ continue;
+ }
+ }
+
+ // No verification checks performed against packet besides length
+ if (payload.size() > (9+3*Settings->light_pixels)) {
+ for (uint32_t i = 0; i < Settings->light_pixels; i++) {
+ c.R = payload[10+3*i];
+ c.G = payload[11+3*i];
+ c.B = payload[12+3*i];
+ strip->SetPixelColor(i, c.C);
+ }
+ Ws2812StripShow();
+ }
+}
+#endif // USE_NETWORK_LIGHT_SCHEMES
+
+void Ws2812Clear(bool display = true);
+void Ws2812Clear(bool display)
+{
+ strip->ClearTo(0);
+ if (display) {
+ Ws2812LibStripShow();
+ Ws2812.show_next = 1;
+ }
+}
+
+void Ws2812SetColor(uint32_t led, uint8_t red, uint8_t green, uint8_t blue, uint8_t white)
+{
+ LedColor lcolor = {0};
+
+ lcolor.R = red;
+ lcolor.G = green;
+ lcolor.B = blue;
+ if (led) {
+ strip->SetPixelColor(led -1, lcolor.C); // Led 1 is strip Led 0 -> substract offset 1
+ } else {
+// strip->ClearTo(lcolor); // Set WS2812_MAX_LEDS pixels
+ for (uint32_t i = 0; i < Settings->light_pixels; i++) {
+ strip->SetPixelColor(i, lcolor.C);
+ }
+ }
+
+ if (!Ws2812.suspend_update) {
+ Ws2812LibStripShow();
+ Ws2812.show_next = 1;
+ }
+}
+
+char* Ws2812GetColor(uint32_t led, char* scolor)
+{
+ uint8_t sl_ledcolor[4];
+
+ LedColor lcolor;
+ lcolor.C = strip->GetPixelColor(led -1);
+ sl_ledcolor[0] = lcolor.R;
+ sl_ledcolor[1] = lcolor.G;
+ sl_ledcolor[2] = lcolor.B;
+ sl_ledcolor[3] = lcolor.W;
+ scolor[0] = '\0';
+ for (uint32_t i = 0; i < Light.subtype; i++) {
+ if (Settings->flag.decimal_text) { // SetOption17 - Switch between decimal or hexadecimal output (0 = hexadecimal, 1 = decimal)
+ snprintf_P(scolor, 25, PSTR("%s%s%d"), scolor, (i > 0) ? "," : "", sl_ledcolor[i]);
+ } else {
+ snprintf_P(scolor, 25, PSTR("%s%02X"), scolor, sl_ledcolor[i]);
+ }
+ }
+ return scolor;
+}
+
+/*********************************************************************************************\
+ * Public - used by scripter only
+\*********************************************************************************************/
+
+void Ws2812ForceSuspend (void)
+{
+ Ws2812.suspend_update = true;
+}
+
+void Ws2812ForceUpdate (void)
+{
+ Ws2812.suspend_update = false;
+ Ws2812LibStripShow();
+ Ws2812.show_next = 1;
+}
+
+/********************************************************************************************/
+
+bool Ws2812SetChannels(void)
+{
+ uint8_t *cur_col = (uint8_t*)XdrvMailbox.data;
+
+ Ws2812SetColor(0, cur_col[0], cur_col[1], cur_col[2], cur_col[3]);
+
+ return true;
+}
+
+void Ws2812ShowScheme(void)
+{
+ uint32_t scheme = Settings->light_scheme - Ws2812.scheme_offset;
+
+#ifdef USE_NETWORK_LIGHT_SCHEMES
+ if ((scheme != 10) && (ddp_udp_up)) {
+ ddp_udp.stop();
+ ddp_udp_up = 0;
+ AddLog(LOG_LEVEL_DEBUG_MORE, "DDP: UDP Stopped: WS2812 Scheme not DDP");
+ }
+#endif
+ switch (scheme) {
+ case 0: // Clock
+ if ((1 == TasmotaGlobal.state_250mS) || (Ws2812.show_next)) {
+ Ws2812Clock();
+ Ws2812.show_next = 0;
+ }
+ break;
+ case 9: // Clear
+ if (Settings->light_scheme != Light.last_scheme) {
+ Ws2812Clear();
+ }
+ break;
+#ifdef USE_NETWORK_LIGHT_SCHEMES
+ case 10:
+ Ws2812DDP();
+ break;
+#endif // USE_NETWORK_LIGHT_SCHEMES
+ default:
+ if(Settings->light_step_pixels > 0){
+ Ws2812Steps(scheme -1);
+ } else {
+ if (1 == Settings->light_fade) {
+ Ws2812Gradient(scheme -1);
+ } else {
+ Ws2812Bars(scheme -1);
+ }
+ }
+ Ws2812.show_next = 1;
+ break;
+ }
+}
+
+bool Ws2812InitStrip(void)
+{
+ if (strip != nullptr) {
+ return true;
+ }
+
+ if (PinUsed(GPIO_WS2812)) { // RGB led
+ int32_t gpio = Pin(GPIO_WS2812);
+ TasmotaLEDPusher * pusher = TasmotaLEDPusher::Create(kTasLed_Hardware, gpio);
+ if (pusher == nullptr) {
+ AddLog(LOG_LEVEL_ERROR, "LED: No hardware supported");
+ return false;
+ }
+ strip = new TasmotaLED(kTasLed_Type, Settings->light_pixels);
+ strip->SetPusher(pusher);
+ strip->Begin();
+
+ Ws2812Clear();
+ return true;
+ }
+ return false;
+}
+
+void Ws2812ModuleSelected(void)
+{
+ if (Ws2812InitStrip()) {
+ Ws2812.scheme_offset = Light.max_scheme +1;
+ Light.max_scheme += WS2812_SCHEMES;
+
+#ifdef USE_NETWORK_LIGHT_SCHEMES
+ Light.max_scheme++;
+#endif
+
+#if (USE_WS2812_CTYPE > NEO_3LED)
+ TasmotaGlobal.light_type = LT_RGBW;
+#else
+ TasmotaGlobal.light_type = LT_RGB;
+#endif
+ TasmotaGlobal.light_driver = XLGT_01;
+ }
+}
+
+#ifdef ESP32
+#ifdef USE_BERRY
+/********************************************************************************************/
+// Callbacks for Berry driver
+//
+// Since we dont' want to export all the template stuff, we need to encapsulate the calls
+// in plain functions
+//
+void *Ws2812GetStrip(void) {
+ return strip;
+}
+
+void Ws2812Begin(void) {
+ if (strip) { strip->Begin(); }
+}
+
+void Ws2812Show(void) {
+ if (strip) { strip->Show(); }
+}
+
+uint32_t Ws2812PixelsSize(void) {
+ if (strip) { return strip->PixelCount(); }
+ return 0;
+}
+
+bool Ws2812CanShow(void) {
+ if (strip) { return strip->CanShow(); }
+ return false;
+}
+
+bool Ws2812IsDirty(void) {
+ if (strip) { return strip->IsDirty(); }
+ return false;
+}
+
+void Ws2812Dirty(void) {
+ if (strip) { strip->Dirty(); }
+}
+
+uint8_t * Ws2812Pixels(void) {
+ if (strip) { return strip->Pixels(); }
+ return nullptr;
+}
+
+size_t Ws2812PixelSize(void) {
+ if (strip) { return strip->PixelSize(); }
+ return 0;
+}
+
+size_t Ws2812PixelCount(void) {
+ if (strip) { return strip->PixelCount(); }
+ return 0;
+}
+
+void Ws2812ClearTo(uint8_t r, uint8_t g, uint8_t b, uint8_t w, int32_t from, int32_t to) {
+ LedColor lcolor;
+ lcolor.W = w;
+ lcolor.R = r;
+ lcolor.G = g;
+ lcolor.B = b;
+ if (strip) {
+ if (from < 0) {
+ strip->ClearTo(lcolor.C);
+ } else {
+ strip->ClearTo(lcolor.C, from, to);
+ }
+ }
+}
+
+void Ws2812SetPixelColor(uint32_t idx, uint8_t r, uint8_t g, uint8_t b, uint8_t w)
+{
+ LedColor lcolor;
+ lcolor.W = w;
+ lcolor.R = r;
+ lcolor.G = g;
+ lcolor.B = b;
+ if (strip) {
+ strip->SetPixelColor(idx, lcolor.C);
+ }
+}
+
+uint32_t Ws2812GetPixelColor(uint32_t idx) {
+ LedColor lcolor;
+ if (strip) {
+ lcolor.C = strip->GetPixelColor(idx);
+ return lcolor.C; // already encoded as WWRRGGBB
+ // return (lcolor.W << 24) | (lcolor.R << 16) | (lcolor.G << 8) | lcolor.B;
+ }
+ return 0;
+}
+
+#endif // ESP32
+#endif // USE_BERRY
+
+/********************************************************************************************/
+
+void CmndLed(void)
+{
+ if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= Settings->light_pixels)) {
+ if (XdrvMailbox.data_len > 0) {
+ char *p;
+ uint16_t idx = XdrvMailbox.index;
+ Ws2812ForceSuspend();
+ for (char *color = strtok_r(XdrvMailbox.data, " ", &p); color; color = strtok_r(nullptr, " ", &p)) {
+ if (LightColorEntry(color, strlen(color))) {
+ Ws2812SetColor(idx, Light.entry_color[0], Light.entry_color[1], Light.entry_color[2], Light.entry_color[3]);
+ idx++;
+ if (idx > Settings->light_pixels) { break; }
+ } else {
+ break;
+ }
+ }
+ Ws2812ForceUpdate();
+ }
+ char scolor[LIGHT_COLOR_SIZE];
+ ResponseCmndIdxChar(Ws2812GetColor(XdrvMailbox.index, scolor));
+ }
+}
+
+void CmndPixels(void)
+{
+ if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= WS2812_MAX_LEDS)) {
+/*
+ Settings->light_pixels = XdrvMailbox.payload;
+ Settings->light_rotation = 0;
+ Ws2812ReinitStrip(); -- does not work with latest NeoPixelBus driver
+ Light.update = true;
+*/
+ Ws2812Clear(); // Clear all known pixels
+ Settings->light_pixels = XdrvMailbox.payload;
+ Settings->light_rotation = 0;
+ TasmotaGlobal.restart_flag = 2; // reboot instead
+ }
+ ResponseCmndNumber(Settings->light_pixels);
+}
+
+void CmndStepPixels(void)
+{
+ if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 255)) {
+ Settings->light_step_pixels = (XdrvMailbox.payload > WS2812_MAX_LEDS) ? WS2812_MAX_LEDS : XdrvMailbox.payload;
+ // Ws2812ReinitStrip(); -- not sure it's actually needed
+ Light.update = true;
+ }
+ ResponseCmndNumber(Settings->light_step_pixels);
+}
+
+
+void CmndRotation(void)
+{
+ if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < Settings->light_pixels)) {
+ Settings->light_rotation = XdrvMailbox.payload;
+ }
+ ResponseCmndNumber(Settings->light_rotation);
+}
+
+void CmndWidth(void)
+{
+ if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 4)) {
+ if (1 == XdrvMailbox.index) {
+ if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 4)) {
+ Settings->light_width = XdrvMailbox.payload;
+ }
+ ResponseCmndNumber(Settings->light_width);
+ } else {
+ if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 32)) {
+ Settings->ws_width[XdrvMailbox.index -2] = XdrvMailbox.payload;
+ }
+ ResponseCmndIdxNumber(Settings->ws_width[XdrvMailbox.index -2]);
+ }
+ }
+}
+
+/*********************************************************************************************\
+ * Internal calls for ArtNet
+\*********************************************************************************************/
+// check is the Neopixel strip is configured
+bool Ws2812StripConfigured(void) {
+ return strip != nullptr;
+}
+size_t Ws2812StripGetPixelSize(void) {
+ return strip->PixelSize();
+}
+// return true if strip was dirty and an actual refresh was triggered
+bool Ws2812StripRefresh(void) {
+ if (strip->IsDirty()) {
+ Ws2812LibStripShow();
+ return true;
+ } else {
+ return false;
+ }
+}
+void Ws2812CopyPixels(const uint8_t *buf, size_t len, size_t offset_in_matrix) {
+ uint8_t *pixels = strip->Pixels();
+ memmove(&pixels[offset_in_matrix], buf, len);
+ strip->Dirty();
+}
+
+
+
+/*********************************************************************************************\
+ * Interface
+\*********************************************************************************************/
+
+bool Xlgt01(uint32_t function)
+{
+ bool result = false;
+
+ switch (function) {
+ case FUNC_SET_CHANNELS:
+ result = Ws2812SetChannels();
+ break;
+ case FUNC_SET_SCHEME:
+ Ws2812ShowScheme();
+ break;
+ case FUNC_COMMAND:
+ result = DecodeCommand(kWs2812Commands, Ws2812Command);
+ break;
+ case FUNC_MODULE_INIT:
+ Ws2812ModuleSelected();
+ break;
+ }
+ return result;
+}
+
+#endif // USE_WS2812
+#endif // USE_LIGHT
+#endif // ESP32
\ No newline at end of file