Merge branch 'mdev' into dmx_input
This commit is contained in:
111
wled00/wled.cpp
111
wled00/wled.cpp
@@ -3,6 +3,8 @@
|
||||
#include "wled_ethernet.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
#warning WLED-MM GPL-v3. By installing WLED MM you implicitly accept the terms!
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_DISABLE_BROWNOUT_DET)
|
||||
#include "soc/soc.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
@@ -62,6 +64,22 @@
|
||||
// WLEDMM end
|
||||
|
||||
|
||||
#if INCLUDE_xTaskGetHandle && defined(ARDUINO_ARCH_ESP32) && (defined(WLED_DEBUG) || defined(WLED_DEBUG_HEAP))
|
||||
// WLEDMM stack debug tool - find async_tcp task, and queries it's free stack
|
||||
static int wledmm_get_tcp_stacksize(void) {
|
||||
static TaskHandle_t tcp_taskHandle = NULL; // to store the task handle for later calls
|
||||
char * tcp_taskname = pcTaskGetTaskName(tcp_taskHandle); // ask for name of the known task (to make sure we are still looking at the right one)
|
||||
|
||||
if ((tcp_taskHandle == NULL) || (tcp_taskname == NULL) || (strncmp(tcp_taskname, "async_tcp", 9) != 0)) {
|
||||
tcp_taskHandle = xTaskGetHandle("async_tcp"); // need to look for the task by name. FreeRTOS docs say this is very slow, so we store the result for next time
|
||||
//DEBUG_PRINT(F("async_tcp task ")); DEBUG_PRINTLN( (tcp_taskHandle != NULL) ? F("found") : F("not found"));
|
||||
}
|
||||
|
||||
if (tcp_taskHandle != NULL) return uxTaskGetStackHighWaterMark(tcp_taskHandle); // got it !!
|
||||
else return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Main WLED class implementation. Mostly initialization and connection logic
|
||||
*/
|
||||
@@ -198,7 +216,7 @@ void WLED::loop()
|
||||
#endif
|
||||
if (!offMode || strip.isOffRefreshRequired()) {
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(WLEDMM_PROTECT_SERVICE) // WLEDMM experimental
|
||||
static unsigned long lastTimeService = 0; // WLEMM needed to remove stale lock
|
||||
static unsigned long lastTimeService = 0; // WLEDMM needed to remove stale lock
|
||||
if (!suspendStripService && !doInitBusses && !loadLedmap) { // WLEDMM prevent effect drawing while strip or segments are being updated
|
||||
#endif
|
||||
strip.service();
|
||||
@@ -234,7 +252,7 @@ void WLED::loop()
|
||||
if (lastMqttReconnectAttempt > millis()) {
|
||||
rolloverMillis++;
|
||||
lastMqttReconnectAttempt = 0;
|
||||
ntpLastSyncTime = 0;
|
||||
ntpLastSyncTime = NTP_NEVER; // force new NTP query
|
||||
strip.restartRuntime();
|
||||
}
|
||||
if (millis() - lastMqttReconnectAttempt > 30000 || lastMqttReconnectAttempt == 0) { // lastMqttReconnectAttempt==0 forces immediate broadcast
|
||||
@@ -349,6 +367,10 @@ void WLED::loop()
|
||||
if (millis() - debugTime > 4999 ) { // WLEDMM: Special case for debugging heap faster
|
||||
DEBUG_PRINT(F("*** Free heap: ")); DEBUG_PRINT(heap_caps_get_free_size(0x1800));
|
||||
DEBUG_PRINT(F("\tLargest free block: ")); DEBUG_PRINT(heap_caps_get_largest_free_block(0x1800));
|
||||
DEBUG_PRINT(F(" *** \t\tArduino min free stack: ")); DEBUG_PRINT(uxTaskGetStackHighWaterMark(NULL));
|
||||
#if INCLUDE_xTaskGetHandle
|
||||
DEBUG_PRINT(F(" TCP min free stack: ")); DEBUG_PRINT(wledmm_get_tcp_stacksize());
|
||||
#endif
|
||||
DEBUG_PRINTLN(F(" ***"));
|
||||
debugTime = millis();
|
||||
}
|
||||
@@ -364,6 +386,23 @@ void WLED::loop()
|
||||
ESP.wdtFeed();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if 0 && defined(ALL_JSON_TO_PSRAM) && defined(WLED_USE_PSRAM_JSON)
|
||||
// WLEDMM experiment - JSON garbagecollect once per minute. Warning: may crash at random
|
||||
static unsigned long last_gc_time = 0;
|
||||
// try once in 60 seconds
|
||||
if ((millis() - last_gc_time) > 60000) {
|
||||
// look for a perfect moment -> make sure no strip or segments or presets activity, no configs being updated, no realtime external control
|
||||
if (!suspendStripService && !doInitBusses && !doReboot && !doCloseFile && !realtimeMode && !loadLedmap && !presetsActionPending()) {
|
||||
// make sure JSON buffer is not in use
|
||||
if ( (doSerializeConfig == false) && (jsonBufferLock == 0) && (fileDoc == nullptr)) {
|
||||
USER_PRINTLN(F("JSON gabage collection (regular)."));
|
||||
doc.garbageCollect(); // WLEDMM experimental - trigger garbage collection on JSON doc memory pool.
|
||||
// this will make any pending reference to JSON objects _invalid_
|
||||
last_gc_time = millis();
|
||||
} } }
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(WLEDMM_FASTPATH)
|
||||
@@ -416,6 +455,10 @@ void WLED::setup()
|
||||
if (!Serial) delay(2500); // WLEDMM allow CDC USB serial to initialise
|
||||
#endif
|
||||
#if ARDUINO_USB_CDC_ON_BOOT || ARDUINO_USB_MODE
|
||||
#if ARDUINO_USB_CDC_ON_BOOT && (defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6))
|
||||
// WLEDMM avoid "hung devices" when USB_CDC is enabled; see https://github.com/espressif/arduino-esp32/issues/9043
|
||||
Serial.setTxTimeoutMs(0); // potential side-effect: incomplete debug output, with missing characters whenever TX buffer is full.
|
||||
#endif
|
||||
if (!Serial) delay(2500); // WLEDMM: always allow CDC USB serial to initialise
|
||||
if (Serial) Serial.println("wait 1"); // waiting a bit longer ensures that a debug messages are shown in serial monitor
|
||||
if (!Serial) delay(2500);
|
||||
@@ -533,7 +576,7 @@ void WLED::setup()
|
||||
#endif
|
||||
DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap());
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0) // unfortunately not availeable in older framework versions
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0) // unfortunately not available in older framework versions
|
||||
DEBUG_PRINT(F("\nArduino max stack ")); DEBUG_PRINTLN(getArduinoLoopTaskStackSize());
|
||||
#endif
|
||||
DEBUG_PRINTF("%s min free stack %d\n", pcTaskGetTaskName(NULL), uxTaskGetStackHighWaterMark(NULL)); //WLEDMM
|
||||
@@ -547,12 +590,12 @@ void WLED::setup()
|
||||
pinManager.allocateMultiplePins(pins, sizeof(pins)/sizeof(managed_pin_type), PinOwner::SPI_RAM);
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
// S2: reserve GPIO 26-32 for PSRAM (may fail due to isPinOk() but that will also prevent other allocation)
|
||||
managed_pin_type pins[] = { {26, true}, {27, true}, {28, true}, {29, true}, {30, true}, {31, true}, {32, true} };
|
||||
pinManager.allocateMultiplePins(pins, sizeof(pins)/sizeof(managed_pin_type), PinOwner::SPI_RAM);
|
||||
//managed_pin_type pins[] = { {26, true}, {27, true}, {28, true}, {29, true}, {30, true}, {31, true}, {32, true} };
|
||||
//pinManager.allocateMultiplePins(pins, sizeof(pins)/sizeof(managed_pin_type), PinOwner::SPI_RAM);
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
// C3: reserve GPIO 12-17 for PSRAM (may fail due to isPinOk() but that will also prevent other allocation)
|
||||
managed_pin_type pins[] = { {12, true}, {13, true}, {14, true}, {15, true}, {16, true}, {17, true} };
|
||||
pinManager.allocateMultiplePins(pins, sizeof(pins)/sizeof(managed_pin_type), PinOwner::SPI_RAM);
|
||||
//managed_pin_type pins[] = { {12, true}, {13, true}, {14, true}, {15, true}, {16, true}, {17, true} };
|
||||
//pinManager.allocateMultiplePins(pins, sizeof(pins)/sizeof(managed_pin_type), PinOwner::SPI_RAM);
|
||||
#else
|
||||
// GPIO16/GPIO17 reserved for SPI RAM
|
||||
managed_pin_type pins[] = { {16, true}, {17, true} };
|
||||
@@ -566,11 +609,16 @@ void WLED::setup()
|
||||
#else
|
||||
DEBUG_PRINTLN(F("PSRAM not used."));
|
||||
#endif
|
||||
#endif
|
||||
#if defined(ARDUINO_ESP32_PICO)
|
||||
// special handling for PICO-D4: gpio16+17 are in use for onboard SPI FLASH (not PSRAM)
|
||||
managed_pin_type pins[] = { {16, true}, {17, true} };
|
||||
pinManager.allocateMultiplePins(pins, sizeof(pins)/sizeof(managed_pin_type), PinOwner::SPI_RAM);
|
||||
#endif
|
||||
|
||||
//DEBUG_PRINT(F("LEDs inited. heap usage ~"));
|
||||
//DEBUG_PRINTLN(heapPreAlloc - ESP.getFreeHeap());
|
||||
USER_FLUSH(); // WLEDMM flush buffer now, before anything time-critial is started.
|
||||
USER_FLUSH(); // WLEDMM flush buffer now, before anything time-critical is started.
|
||||
|
||||
pinManager.manageDebugTXPin();
|
||||
|
||||
@@ -578,6 +626,11 @@ void WLED::setup()
|
||||
pinManager.allocatePin(2, true, PinOwner::DMX);
|
||||
#endif
|
||||
|
||||
#if defined(ALL_JSON_TO_PSRAM) && defined(WLED_USE_PSRAM_JSON)
|
||||
USER_PRINTLN(F("JSON gabage collection (initial)."));
|
||||
doc.garbageCollect(); // WLEDMM experimental - this seems to move the complete doc[] into PSRAM
|
||||
#endif
|
||||
|
||||
// WLEDMM experimental: support for single neoPixel on Adafruit boards
|
||||
#if 0
|
||||
//#ifdef PIN_NEOPIXEL
|
||||
@@ -607,7 +660,7 @@ void WLED::setup()
|
||||
for (uint8_t i=1; i<WLED_MAX_BUTTONS; i++) btnPin[i] = -1;
|
||||
|
||||
bool fsinit = false;
|
||||
USER_PRINTLN(F("Mount FS"));
|
||||
USER_PRINTLN(F("Mounting FS ..."));
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
fsinit = WLED_FS.begin(true);
|
||||
#else
|
||||
@@ -616,6 +669,8 @@ void WLED::setup()
|
||||
if (!fsinit) {
|
||||
USER_PRINTLN(F("Mount FS failed!")); // WLEDMM
|
||||
errorFlag = ERR_FS_BEGIN;
|
||||
} else {
|
||||
USER_PRINTLN(F("Mount FS succeeded.")); // WLEDMM
|
||||
}
|
||||
#ifdef WLED_ADD_EEPROM_SUPPORT
|
||||
else deEEP();
|
||||
@@ -715,7 +770,20 @@ void WLED::setup()
|
||||
DEBUG_PRINT(pcTaskGetTaskName(NULL)); DEBUG_PRINT(F(" free stack ")); DEBUG_PRINTLN(uxTaskGetStackHighWaterMark(NULL));
|
||||
#endif
|
||||
|
||||
// Seed FastLED random functions with an esp random value, which already works properly at this point.
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
uint32_t seed32 = esp_random();
|
||||
seed32 ^= random(0, INT32_MAX); // WLEDMM some extra entropy (for older frameworks where esp_ramdom alone might be too predictable after startup)
|
||||
#elif defined(ARDUINO_ARCH_ESP8266)
|
||||
const uint32_t seed32 = RANDOM_REG32;
|
||||
#else
|
||||
const uint32_t seed32 = random(std::numeric_limits<long>::max());
|
||||
#endif
|
||||
random16_set_seed((uint16_t)((seed32 & 0xFFFF) ^ (seed32 >> 16)));
|
||||
|
||||
#if WLED_WATCHDOG_TIMEOUT > 0
|
||||
enableWatchdog();
|
||||
#endif
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_DISABLE_BROWNOUT_DET)
|
||||
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 1); //enable brownout detector
|
||||
@@ -967,7 +1035,7 @@ void WLED::initConnection()
|
||||
|
||||
WiFi.disconnect(true); // close old connections
|
||||
#ifdef ESP8266
|
||||
WiFi.setPhyMode(WIFI_PHY_MODE_11N);
|
||||
WiFi.setPhyMode(force802_3g ? WIFI_PHY_MODE_11G : WIFI_PHY_MODE_11N);
|
||||
#endif
|
||||
|
||||
if (staticIP[0] != 0 && staticGateway[0] != 0) {
|
||||
@@ -1138,16 +1206,19 @@ void WLED::handleConnection()
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
// reconnect WiFi to clear stale allocations if heap gets too low
|
||||
if (now - heapTime > 5000) { // WLEDMM: updated with better logic for small heap available by block, not total.
|
||||
// uint32_t heap = ESP.getFreeHeap();
|
||||
#if defined(ARDUINO_ARCH_ESP32S2)
|
||||
uint32_t heap = ESP.getFreeHeap(); // WLEDMM works better on -S2
|
||||
#else
|
||||
uint32_t heap = heap_caps_get_largest_free_block(0x1800); // WLEDMM: This is a better metric for free heap.
|
||||
#endif
|
||||
if (heap < MIN_HEAP_SIZE && lastHeap < MIN_HEAP_SIZE) {
|
||||
DEBUG_PRINT(F("Heap too low! (step 2, force reconnect): "));
|
||||
DEBUG_PRINTLN(heap);
|
||||
USER_PRINT(F("Heap too low! (step 2, force reconnect): "));
|
||||
USER_PRINTLN(heap);
|
||||
forceReconnect = true;
|
||||
strip.purgeSegments(true); // remove all but one segments from memory
|
||||
} else if (heap < MIN_HEAP_SIZE) {
|
||||
DEBUG_PRINT(F("Heap too low! (step 1, flush unread UDP): "));
|
||||
DEBUG_PRINTLN(heap);
|
||||
USER_PRINT(F("Heap too low! (step 1, flush unread UDP): "));
|
||||
USER_PRINTLN(heap);
|
||||
strip.purgeSegments();
|
||||
notifierUdp.flush();
|
||||
rgbUdp.flush();
|
||||
@@ -1275,7 +1346,15 @@ void WLED::handleStatusLED()
|
||||
if (ledStatusType) {
|
||||
if (millis() - ledStatusLastMillis >= (1000/ledStatusType)) {
|
||||
ledStatusLastMillis = millis();
|
||||
ledStatusState = !ledStatusState;
|
||||
#if 0
|
||||
// WLEDMM un-comment this to stop the blinking
|
||||
if ((ledStatusType != 2) && (ledStatusType != 4))
|
||||
ledStatusState = !ledStatusState;
|
||||
else
|
||||
ledStatusState = HIGH;
|
||||
#else
|
||||
ledStatusState = !ledStatusState;
|
||||
#endif
|
||||
#if STATUSLED>=0
|
||||
digitalWrite(STATUSLED, ledStatusState);
|
||||
#else
|
||||
|
||||
Reference in New Issue
Block a user