diff --git a/CHANGELOG.md b/CHANGELOG.md index 416aec25f..e5e40273c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ All notable changes to this project will be documented in this file. - Command `SetOption162 1` to disable adding export energy to energy today (#22578) - ESP32 support for WPA2/3 Enterprise conditional in core v3.1.0.241206 (#22600) - Support for Sonoff POWCT Energy Export Active (#22596) +- Improved auto-selection of LED hardware support (RMT, SPI) (#22618) ### Breaking Changed - ESP32 ArtNet switches from GRB to RGB encoding (#22556) diff --git a/lib/lib_basic/TasmotaLED/src/TasmotaLED.h b/lib/lib_basic/TasmotaLED/src/TasmotaLED.h index ac1b78c1e..dd2fb8dc9 100644 --- a/lib/lib_basic/TasmotaLED/src/TasmotaLED.h +++ b/lib/lib_basic/TasmotaLED/src/TasmotaLED.h @@ -44,10 +44,10 @@ enum TasmotaLEDTypesEncoding : uint16_t { 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_Default = 0x000000, + TasmotaLed_RMT = (1 << 0) << 16, + TasmotaLed_SPI = (1 << 1) << 16, + TasmotaLed_I2S = (1 << 2) << 16, TasmotaLed_HW_None = 0xFF << 16, // indicates that the specified HW is not supported }; diff --git a/lib/lib_basic/TasmotaLED/src/TasmotaLEDPusher.cpp b/lib/lib_basic/TasmotaLED/src/TasmotaLEDPusher.cpp index d765703e5..19280a7dd 100644 --- a/lib/lib_basic/TasmotaLED/src/TasmotaLEDPusher.cpp +++ b/lib/lib_basic/TasmotaLED/src/TasmotaLEDPusher.cpp @@ -30,40 +30,33 @@ enum LoggingLevels {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_D // convert to the appropriate hardware acceleration based on capacities of the SOC -uint32_t TasmotaLEDPusher::ResolveHardware(uint32_t hw) { -uint32_t hw_orig = hw; +uint32_t TasmotaLEDPusher::ResolveHardware(uint32_t hw_input) { // Step 1. discard any unsupported hardware, and replace with TasmotaLed_HW_Default - uint32_t hw_type = hw & 0xFF0000; // discard bits 0..15 + uint32_t hw = hw_input & 0xFF0000; // discard bits 0..15 #if !TASMOTALED_HARDWARE_RMT - if (hw_type == TasmotaLed_RMT) { - hw = TasmotaLed_HW_None; - } + hw &= ~TasmotaLed_RMT; // remove RMT flag if not supported by hardware #endif // TASMOTALED_HARDWARE_RMT #if !TASMOTALED_HARDWARE_SPI - if (hw_type == TasmotaLed_SPI) { - hw = TasmotaLed_HW_None; - } + hw &= ~TasmotaLed_SPI; // remove SPI flag if not supported by hardware #endif // TASMOTALED_HARDWARE_SPI #if !TASMOTALED_HARDWARE_I2S - if (hw_type == TasmotaLed_I2S) { - hw = TasmotaLed_HW_None; - } + hw &= ~TasmotaLed_I2S; // remove I2S flag if not supported by hardware #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; + if (hw == TasmotaLed_HW_Default) { + hw |= TasmotaLed_RMT; } #endif // TASMOTALED_HARDWARE_RMT #if TASMOTALED_HARDWARE_I2S - if ((hw & 0xFF0000) == TasmotaLed_HW_Default) { - hw = TasmotaLed_I2S; + if (hw == TasmotaLed_HW_Default) { + hw |= TasmotaLed_I2S; } #endif // TASMOTALED_HARDWARE_I2S #if TASMOTALED_HARDWARE_SPI - if ((hw & 0xFF0000) == TasmotaLed_HW_Default) { - hw = TasmotaLed_SPI; + if (hw == TasmotaLed_HW_Default) { + hw |= TasmotaLed_SPI; } #endif // TASMOTALED_HARDWARE_SPI return hw; @@ -75,22 +68,30 @@ TasmotaLEDPusher * TasmotaLEDPusher::Create(uint32_t hw, int8_t gpio) { hw = TasmotaLEDPusher::ResolveHardware(hw); - switch (hw & 0XFF0000) { #if TASMOTALED_HARDWARE_RMT - case TasmotaLed_RMT: - pusher = new TasmotaLEDPusherRMT(gpio); + if (pusher == nullptr && (hw & TasmotaLed_RMT)) { + pusher = new TasmotaLEDPusherRMT(gpio); + if (pusher->Initialized()) { AddLog(LOG_LEVEL_DEBUG, "LED: RMT gpio %i", gpio); - break; + } else { + AddLog(LOG_LEVEL_INFO, "LED: Error create %s bus failed %i err=%i", "RMT", gpio, pusher->Error()); + delete pusher; + pusher = nullptr; + } + } #endif // TASMOTALED_HARDWARE_RMT #if TASMOTALED_HARDWARE_SPI - case TasmotaLed_SPI: - pusher = new TasmotaLEDPusherSPI(gpio); + if (pusher == nullptr && (hw & TasmotaLed_SPI)) { + pusher = new TasmotaLEDPusherSPI(gpio); + if (pusher->Initialized()) { AddLog(LOG_LEVEL_DEBUG, "LED: SPI gpio %i", gpio); - break; -#endif // TASMOTALED_HARDWARE_SPI - default: - break; + } else { + AddLog(LOG_LEVEL_INFO, "LED: Error create %s bus failed %i err=%i", "SPI", gpio, pusher->Error()); + delete pusher; + pusher = nullptr; + } } +#endif // TASMOTALED_HARDWARE_SPI return pusher; } diff --git a/lib/lib_basic/TasmotaLED/src/TasmotaLEDPusher.h b/lib/lib_basic/TasmotaLED/src/TasmotaLEDPusher.h index 2b8eb4896..89b402997 100644 --- a/lib/lib_basic/TasmotaLED/src/TasmotaLEDPusher.h +++ b/lib/lib_basic/TasmotaLED/src/TasmotaLEDPusher.h @@ -80,9 +80,11 @@ typedef struct TasmotaLED_Timing { \*******************************************************************************************/ class TasmotaLEDPusher { public: - TasmotaLEDPusher() : _pixel_count(0), _pixel_size(0), _led_timing(nullptr) {}; + TasmotaLEDPusher() : _initialized(false), _err(ESP_OK), _pixel_count(0), _pixel_size(0), _led_timing(nullptr) {}; virtual ~TasmotaLEDPusher() {}; + bool Initialized(void) const { return _initialized; } + esp_err_t Error(void) const { return _err; } virtual bool Begin(uint16_t pixel_count, uint16_t pixel_size, const TasmotaLED_Timing * led_timing) { _pixel_count = pixel_count; _pixel_size = pixel_size; @@ -96,6 +98,8 @@ public: static TasmotaLEDPusher * Create(uint32_t hw, int8_t gpio); // create instance for the provided type, or nullptr if failed protected: + bool _initialized; // did the hardware got correctly initialized + esp_err_t _err; uint16_t _pixel_count; uint16_t _pixel_size; const TasmotaLED_Timing * _led_timing; @@ -110,7 +114,7 @@ protected: #include "driver/rmt_tx.h" class TasmotaLEDPusherRMT : public TasmotaLEDPusher { public: - TasmotaLEDPusherRMT(int8_t pin) : _pin(pin) {}; + TasmotaLEDPusherRMT(int8_t pin); ~TasmotaLEDPusherRMT(); bool Begin(uint16_t pixel_count, uint16_t pixel_size, const TasmotaLED_Timing * led_timing) override; @@ -144,7 +148,7 @@ typedef struct led_strip_spi_obj_t { class TasmotaLEDPusherSPI : public TasmotaLEDPusher { public: - TasmotaLEDPusherSPI(int8_t pin) : _pin(pin), _spi_strip({}) {}; + TasmotaLEDPusherSPI(int8_t pin); ~TasmotaLEDPusherSPI(); bool Begin(uint16_t pixel_count, uint16_t pixel_size, const TasmotaLED_Timing * led_timing) override; @@ -154,7 +158,8 @@ public: protected: int8_t _pin; - struct led_strip_spi_obj_t _spi_strip; + struct led_strip_spi_obj_t _spi_strip = {};; + const bool _with_dma = true; }; #endif // TASMOTALED_HARDWARE_SPI diff --git a/lib/lib_basic/TasmotaLED/src/TasmotaLEDPusherRMT.cpp b/lib/lib_basic/TasmotaLED/src/TasmotaLEDPusherRMT.cpp index 747985008..d6ca12197 100644 --- a/lib/lib_basic/TasmotaLED/src/TasmotaLEDPusherRMT.cpp +++ b/lib/lib_basic/TasmotaLED/src/TasmotaLEDPusherRMT.cpp @@ -155,9 +155,7 @@ TasmotaLEDPusherRMT::~TasmotaLEDPusherRMT() { } } -bool TasmotaLEDPusherRMT::Begin(uint16_t pixel_count, uint16_t pixel_size, const TasmotaLED_Timing * led_timing) { - TasmotaLEDPusher::Begin(pixel_count, pixel_size, led_timing); - +TasmotaLEDPusherRMT::TasmotaLEDPusherRMT(int8_t pin) : _pin(pin) { esp_err_t ret = ESP_OK; rmt_tx_channel_config_t config = {}; config.clk_src = RMT_CLK_SRC_DEFAULT; @@ -168,11 +166,15 @@ bool TasmotaLEDPusherRMT::Begin(uint16_t pixel_count, uint16_t pixel_size, const 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; + _err = rmt_new_tx_channel(&config, &_channel); + if (_err == ESP_OK) { + _initialized = true; } +} + +bool TasmotaLEDPusherRMT::Begin(uint16_t pixel_count, uint16_t pixel_size, const TasmotaLED_Timing * led_timing) { + if (!_initialized) { return false; } + TasmotaLEDPusher::Begin(pixel_count, pixel_size, led_timing); led_strip_encoder_config_t encoder_config = { .resolution = RMT_LED_STRIP_RESOLUTION_HZ, }; @@ -198,13 +200,13 @@ bool TasmotaLEDPusherRMT::Begin(uint16_t pixel_count, uint16_t pixel_size, const .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) { + _err = rmt_new_led_strip_encoder(&encoder_config, &_led_encoder, RmtBit0, RmtBit1, RmtReset); + if (_err != 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) { + _err = rmt_enable(_channel); + if (_err != ESP_OK) { // AddLog(LOG_LEVEL_INFO, "RMT: cannot enable channel err=%i", ret); return false; } @@ -212,7 +214,7 @@ bool TasmotaLEDPusherRMT::Begin(uint16_t pixel_count, uint16_t pixel_size, const } bool TasmotaLEDPusherRMT::CanShow(void) { - if (_channel) { + if (_channel && _initialized) { return (ESP_OK == rmt_tx_wait_all_done(_channel, 0)); } else { return false; @@ -220,6 +222,7 @@ bool TasmotaLEDPusherRMT::CanShow(void) { } bool TasmotaLEDPusherRMT::Push(uint8_t *buf) { + if (!_initialized) { return false; } // wait for not actively sending data // this will time out at 1 second, an arbitrarily long period of time diff --git a/lib/lib_basic/TasmotaLED/src/TasmotaLEDPusherSPI.cpp b/lib/lib_basic/TasmotaLED/src/TasmotaLEDPusherSPI.cpp index 72ea342ef..74366ebb8 100644 --- a/lib/lib_basic/TasmotaLED/src/TasmotaLEDPusherSPI.cpp +++ b/lib/lib_basic/TasmotaLED/src/TasmotaLEDPusherSPI.cpp @@ -95,31 +95,9 @@ TasmotaLEDPusherSPI::~TasmotaLEDPusherSPI() { } } -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; +TasmotaLEDPusherSPI::TasmotaLEDPusherSPI(int8_t pin) : _pin(pin) { 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 = { + spi_bus_config_t 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, @@ -128,32 +106,55 @@ bool TasmotaLEDPusherSPI::Begin(uint16_t pixel_count, uint16_t pixel_size, const .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")); + _err = spi_bus_initialize(spi_host, &spi_bus_cfg, _with_dma ? SPI_DMA_CH_AUTO : SPI_DMA_DISABLED); + if (_err == ESP_OK) { + _spi_strip.spi_host = spi_host; // confirmed working, so keep it's value to free it later + _initialized = true; + } +} + +bool TasmotaLEDPusherSPI::Begin(uint16_t pixel_count, uint16_t pixel_size, const TasmotaLED_Timing * led_timing) { + if (!_initialized) { + return false; + } + TasmotaLEDPusher::Begin(pixel_count, pixel_size, led_timing); + _spi_strip.bytes_per_pixel = _pixel_size; + _spi_strip.strip_len = _pixel_count; + + uint32_t mem_caps = MALLOC_CAP_DEFAULT; + // spi_clock_source_t clk_src = SPI_CLK_SRC_DEFAULT; + spi_device_interface_config_t spi_dev_cfg; + 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_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, + .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) { + _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) { + _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; } @@ -163,7 +164,6 @@ bool TasmotaLEDPusherSPI::Begin(uint16_t pixel_count, uint16_t pixel_size, const // AddLog(LOG_LEVEL_INFO, "LED: Error unsupported clock resolution: %dKHz", clock_resolution_khz); goto err; } - return true; err: if (_spi_strip.spi_device) { @@ -172,15 +172,16 @@ err: if (_spi_strip.spi_host) { spi_bus_free(_spi_strip.spi_host); } + _initialized = false; return false; } bool TasmotaLEDPusherSPI::CanShow(void) { - return true; // TODO + return _initialized; // TODO } bool TasmotaLEDPusherSPI::Push(uint8_t *buf) { - + if (!_initialized) { return false; } if (CanShow()) { led_strip_transmit_buffer(&_spi_strip, buf); } diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_UI.be b/lib/libesp32/berry_matter/src/embedded/Matter_UI.be index 7117500d2..551ddffeb 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_UI.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_UI.be @@ -82,7 +82,7 @@ class Matter_UI # webserver.content_send("
") webserver.content_send("") + webserver.content_send(" Matter") end #- ---------------------------------------------------------------------- -# diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_UI.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_UI.h index 687052637..eb9a0bee3 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_UI.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_UI.h @@ -191,7 +191,7 @@ static const bvalue be_ktab_class_Matter_UI[232] = { /* K182 */ be_nested_str_weak(_X3C_X2Ftable_X3E_X3Chr_X3E), /* K183 */ be_nested_str_weak(_X3Cp_X3E_X3Cform_X20id_X3Dac_X20action_X3D_X27matterc_X27_X20style_X3D_X27display_X3A_X20block_X3B_X27_X20method_X3D_X27get_X27_X3E_X3Cbutton_X3E), /* K184 */ be_nested_str_weak(_LOGO), - /* K185 */ be_nested_str_weak(_X20Configure_X20Matter_X3C_X2Fbutton_X3E_X3C_X2Fform_X3E_X3C_X2Fp_X3E), + /* K185 */ be_nested_str_weak(_X20Matter_X3C_X2Fbutton_X3E_X3C_X2Fform_X3E_X3C_X2Fp_X3E), /* K186 */ be_nested_str_weak(get_plugin_class_displayname), /* K187 */ be_nested_str_weak(Matter_X20Advanced_X20Configuration), /* K188 */ be_nested_str_weak(show_passcode_form), diff --git a/tasmota/tasmota_support/support.ino b/tasmota/tasmota_support/support.ino index 4dc5fdff2..7d34b6c51 100755 --- a/tasmota/tasmota_support/support.ino +++ b/tasmota/tasmota_support/support.ino @@ -1148,6 +1148,8 @@ int GetCommandCode(char* destination, size_t destination_size, const char* needl bool DecodeCommand(const char* haystack, void (* const MyCommand[])(void), const uint8_t *synonyms = nullptr); bool DecodeCommand(const char* haystack, void (* const MyCommand[])(void), const uint8_t *synonyms) { + SHOW_FREE_MEM(PSTR("DecodeCommand")); + GetTextIndexed(XdrvMailbox.command, CMDSZ, 0, haystack); // Get prefix if available int prefix_length = strlen(XdrvMailbox.command); if (prefix_length) { @@ -2680,9 +2682,7 @@ void AddLogData(uint32_t loglevel, const char* log_data, const char* log_data_pa } snprintf_P(TasmotaGlobal.log_buffer, LOG_BUFFER_SIZE, PSTR("%s%c%c%s%s%s%s\1"), TasmotaGlobal.log_buffer, TasmotaGlobal.log_buffer_pointer++, '0'+loglevel, mxtime, log_data, log_data_payload, log_data_retained); - if (too_long) { - free(too_long); - } + if (too_long) { free(too_long); } TasmotaGlobal.log_buffer_pointer &= 0xFF; if (!TasmotaGlobal.log_buffer_pointer) { TasmotaGlobal.log_buffer_pointer++; // Index 0 is not allowed as it is the end of char string diff --git a/tasmota/tasmota_xdrv_driver/xdrv_02_9_mqtt.ino b/tasmota/tasmota_xdrv_driver/xdrv_02_9_mqtt.ino index 0e19c0c0e..3d2d998e8 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_02_9_mqtt.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_02_9_mqtt.ino @@ -702,15 +702,14 @@ void MqttPublishLoggingAsync(bool refresh) { void MqttPublishPayload(const char* topic, const char* payload, uint32_t binary_length, bool retained) { // Publish