diff --git a/docs/esp32-p4-eth-network-compat.md b/docs/esp32-p4-eth-network-compat.md new file mode 100644 index 0000000000..fa3fdce3d6 --- /dev/null +++ b/docs/esp32-p4-eth-network-compat.md @@ -0,0 +1,39 @@ +# ESP32-P4 Ethernet network helper compatibility + +This branch keeps WLED's network helper on the unique symbol `WLEDNetwork` while preserving existing WLED source call sites that use `Network`. + +## What changed + +WLED previously had its own helper object named `Network`. The ESP32 Arduino 3.x / ESP-IDF 5 stack also provides a global `Network` object for its `NetworkManager`, which creates a name collision when building the ESP32-P4/V5 stack. + +To avoid that collision while minimizing churn in the branch: + +- WLED's helper class/object are named `WLEDNetworkClass` and `WLEDNetwork`. +- `Network.h` maps legacy WLED helper calls with `#define Network WLEDNetwork` after including the framework WiFi/Ethernet headers. +- `Network.cpp` defines the `WLEDNetwork` object rather than a WLED-owned object named `Network`. +- The shared `DNSlookup` state used by `BusNetwork::resolveHostname()` is declared/defined so the current `bus_manager.cpp` code has a valid object to use. + +## Consequences and tradeoffs + +This is intended to keep both relevant ESP32 build stacks viable: + +- the older/current WLED ESP32 stack where WLED code historically used `Network`, and +- the ESP32-P4/V5 stack where Arduino-ESP32 provides its own global `Network` object. + +The compatibility macro keeps the diff small because most WLED call sites can remain as `Network.isConnected()`, `Network.localIP()`, etc. Those calls are redirected to WLED's `WLEDNetwork` helper after `Network.h` is included. + +The main downside is that `Network` becomes a preprocessor alias in translation units that include WLED's `Network.h`. Code in those translation units that intentionally needs Arduino-ESP32's own `NetworkManager Network` after including WLED's helper header may need to include/use it before this header or locally `#undef Network`. This branch does not currently add such a use case. + +The helper object name exposed by WLED is now `WLEDNetwork`. Any external code or usermod that directly declared or linked against WLED's old `NetworkClass Network` symbol, instead of using normal WLED headers and call sites, may need adjustment. + +No runtime behavior change is intended for Wi-Fi, Ethernet, Art-Net, DDP, Improv, JSON info, or Espalexa. The change is primarily a build/link compatibility fix for the network helper name collision. + +## Test note + +ETH and DDP tested only. + +PlatformIO build validation should still be run for at least: + +- `esp32dev_V4` +- `esp32dev` +- `esp32p4_32MB` diff --git a/platformio.ini b/platformio.ini index 9515f26cb0..1536442d43 100644 --- a/platformio.ini +++ b/platformio.ini @@ -32,6 +32,7 @@ default_envs = nodemcuv2 esp32s3dev_8MB_qspi esp32s3dev_8MB_none esp32s3_4M_qspi + esp32p4_32MB usermods src_dir = ./wled00 @@ -383,6 +384,55 @@ board_build.partitions = ${esp32.large_partitions} ;; default partioning for 8 upload_speed = 921600 monitor_filters = esp32_exception_decoder +[esp32p4] +;; generic definitions for ESP32-P4 boards. Uses pioarduino for IDF 5.5 based P4 support. +platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.37/platform-espressif32.zip +platform_packages = +build_unflags = ${common.build_unflags} + -D WLED_ENABLE_DMX_INPUT ;; esp_dmx is excluded for ESP32-P4 + -D WLED_ENABLE_DMX ;; DMX serial output needs ESP32-P4-specific adaptation +build_flags = -g + -DARDUINO_ARCH_ESP32 + -DARDUINO_ARCH_ESP32P4 + -DCONFIG_IDF_TARGET_ESP32P4=1 + -D CONFIG_ASYNC_TCP_USE_WDT=0 + -D CONFIG_ASYNC_TCP_STACK_SIZE=8192 + -D WLED_ENABLE_GIF + -DCO + -DARDUINO_USB_MODE=1 + -D WLED_DISABLE_INFRARED + -D WLED_DISABLE_ESPNOW + -D WLED_DISABLE_MQTT + -D WLED_USE_SHARED_RMT + -D ESP32_ARDUINO_NO_RGB_BUILTIN +lib_deps = + esp32async/AsyncTCP @ 3.4.10 + bitbank2/AnimatedGIF@^1.4.7 + https://github.com/Aircoookie/GifDecoder.git#bc3af189b6b1e06946569f6b4287f0b79a860f8e + NeoPixelBus = git+https://github.com/Makuna/NeoPixelBus#76afe832f74b0738a3fa1bba0caf389ade9e7693 + crankyoldgit/IRremoteESP8266 @ 2.9.0 + ESPAsyncWebServerWLED = git+https://github.com/Aircoookie/ESPAsyncWebServer#ac44e32abf2a69ae650412fb6bc193c59ccac38a + marvinroger/AsyncMqttClient @ 0.9.0 + https://github.com/blazoncek/QuickESPNow.git#optional-debug +lib_ignore = + NeoESP32RmtHI + IRremoteESP8266 + QuickEspNow + esp_dmx + +[env:esp32p4_32MB] +;; (experimental) ESP32-P4 with 32 MB flash and PSRAM +extends = esp32p4 +board = esp32-p4-evboard +board_build.flash_mode = qio +board_build.partitions = tools/WLED_ESP32_32MB.csv +build_unflags = ${esp32p4.build_unflags} +build_flags = ${common.build_flags} ${esp32p4.build_flags} + -D WLED_RELEASE_NAME=\"ESP32-P4_32MB\" + -DBOARD_HAS_PSRAM +upload_speed = 460800 +monitor_filters = esp32_exception_decoder + # ------------------------------------------------------------------------------ # WLED BUILDS diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 05f10493a1..8e6c015321 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -452,8 +452,12 @@ BusPwm::BusPwm(const BusConfig &bc) pinMode(_pins[i], OUTPUT); #else unsigned channel = _ledcStart + i; + #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) ledcSetup(channel, _frequency, _depth - (dithering*4)); // with dithering _frequency doesn't really matter as resolution is 8 bit ledcAttachPin(_pins[i], channel); + #else + ledcAttachChannel(_pins[i], _frequency, _depth - (dithering*4), channel); + #endif // LEDC timer reset credit @dedehai uint8_t group = (channel / 8), timer = ((channel / 2) % 4); // same fromula as in ledcSetup() ledc_timer_rst((ledc_mode_t)group, (ledc_timer_t)timer); // reset timer so all timers are almost in sync (for phase shift) @@ -585,10 +589,15 @@ void BusPwm::show() { unsigned ch = channel%8; // group channel // directly write to LEDC struct as there is no HAL exposed function for dithering // duty has 20 bit resolution with 4 fractional bits (24 bits in total) + #if defined(CONFIG_IDF_TARGET_ESP32P4) + // TODO: find out if / how dithering support can be implemented on P4 + ledc_set_duty_and_update((ledc_mode_t)gr, (ledc_channel_t)ch, duty >> bitShift, hPoint >> bitShift); + #else LEDC.channel_group[gr].channel[ch].duty.duty = duty << ((!dithering)*4); // lowest 4 bits are used for dithering, shift by 4 bits if not using dithering LEDC.channel_group[gr].channel[ch].hpoint.hpoint = hPoint >> bitShift; // hPoint is at _depth resolution (needs shifting if dithering) ledc_update_duty((ledc_mode_t)gr, (ledc_channel_t)ch); #endif + #endif if (!_reversed) hPoint += duty; hPoint += deadTime; // offset to cascade the signals @@ -623,7 +632,11 @@ void BusPwm::deallocatePins() { #ifdef ESP8266 digitalWrite(_pins[i], LOW); //turn off PWM interrupt #else + #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) if (_ledcStart < WLED_MAX_ANALOG_CHANNELS) ledcDetachPin(_pins[i]); + #else + if (_ledcStart < WLED_MAX_ANALOG_CHANNELS) ledcDetach(_pins[i]); + #endif #endif } #ifdef ARDUINO_ARCH_ESP32 @@ -1285,6 +1298,10 @@ void BusManager::removeAll() { // since I2S outputs are known only during config of buses, lets just assume RMT is used for digital buses // unused RMT channels should have no effect void BusManager::esp32RMTInvertIdle() { +#if defined(CONFIG_IDF_TARGET_ESP32P4) + // ESP32-P4 uses shared RMT method - idle level inversion not supported + return; +#else bool idle_out; unsigned rmt = 0; unsigned u = 0; @@ -1302,6 +1319,7 @@ void BusManager::esp32RMTInvertIdle() { rmt_set_idle_level(ch, idle_out, lvl); u++; } +#endif } #endif diff --git a/wled00/bus_wrapper.h b/wled00/bus_wrapper.h index 15b5b0a3e1..5755f66ea5 100644 --- a/wled00/bus_wrapper.h +++ b/wled00/bus_wrapper.h @@ -4,6 +4,7 @@ //#define NPB_CONF_4STEP_CADENCE #include "NeoPixelBus.h" +#include "wled_boards.h" //Hardware SPI Pins #define P_8266_HS_MOSI 13 @@ -204,6 +205,8 @@ /*** ESP32 Neopixel methods ***/ #ifdef ARDUINO_ARCH_ESP32 +#include + // C3: I2S0 and I2S1 methods not supported (has one I2S bus) // S2: I2S0 methods supported (single & parallel), I2S1 methods not supported (has one I2S bus) // S3: I2S0 methods not supported, I2S1 supports LCD parallel methods (has two I2S buses) @@ -231,7 +234,29 @@ typedef NeoEsp32I2s0Apa106Method X1Apa106Method; typedef NeoEsp32I2s0Ws2805Method X1Ws2805Method; typedef NeoEsp32I2s0Tm1914Method X1Tm1914Method; -#elif !defined(CONFIG_IDF_TARGET_ESP32C3) +#elif defined(CONFIG_IDF_TARGET_ESP32P4) + // P4 has no I2S LED driver in NeoPixelBus; keep dormant I2S switch arms compileable. + // AI: below section was generated by an AI + typedef XWs2812xMethod X1Ws2812xMethod; + typedef XSk6812Method X1Sk6812Method; + typedef X400KbpsMethod X1400KbpsMethod; + typedef X800KbpsMethod X1800KbpsMethod; + typedef XTm1814Method X1Tm1814Method; + typedef XTm1829Method X1Tm1829Method; + typedef XApa106Method X1Apa106Method; + typedef XWs2805Method X1Ws2805Method; + typedef XTm1914Method X1Tm1914Method; + typedef XWs2812xMethod X8Ws2812xMethod; + typedef XSk6812Method X8Sk6812Method; + typedef X400KbpsMethod X8400KbpsMethod; + typedef X800KbpsMethod X8800KbpsMethod; + typedef XTm1814Method X8Tm1814Method; + typedef XTm1829Method X8Tm1829Method; + typedef XApa106Method X8Apa106Method; + typedef XWs2805Method X8Ws2805Method; + typedef XTm1914Method X8Tm1914Method; + // AI: end +#elif defined(WLED_HAS_PARALLEL_I2S) // regular ESP32 will use I2S1 typedef NeoEsp32I2s1Ws2812xMethod X1Ws2812xMethod; typedef NeoEsp32I2s1Sk6812Method X1Sk6812Method; @@ -245,7 +270,9 @@ #endif // RMT driver selection -#if !defined(WLED_USE_SHARED_RMT) && !defined(__riscv) +#if ESP_ARDUINO_VERSION_MAJOR >= 3 +#define NeoEsp32RmtMethod(x) NeoEsp32RmtX ## x ## Method +#elif !defined(WLED_USE_SHARED_RMT) && !defined(__riscv) #include #define NeoEsp32RmtMethod(x) NeoEsp32RmtHIN ## x ## Method #else @@ -1345,10 +1372,15 @@ class PolyBus { #else //ESP32 // dynamic channel allocation based on driver preference // determine which driver to use based on preference and availability. First I2S bus locks the I2S type, all subsequent I2S buses are assigned the same type (hardware restriction) + #ifdef WLED_HAS_PARALLEL_I2S + constexpr bool canUseI2S = true; + #else + constexpr bool canUseI2S = false; + #endif uint8_t offset = 0; // 0 = RMT, 1 = I2S/LCD if (driverPreference == 0 && _rmtChannelsAssigned < WLED_MAX_RMT_CHANNELS) { _rmtChannelsAssigned++; - } else if (_i2sChannelsAssigned < WLED_MAX_I2S_CHANNELS) { + } else if (canUseI2S && _i2sChannelsAssigned < WLED_MAX_I2S_CHANNELS) { offset = 1; // I2S requested or RMT full _i2sChannelsAssigned++; } else { diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index 2e458e7da9..ae67dfcd74 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -135,6 +135,9 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { #ifdef WLED_USE_ETHERNET JsonObject ethernet = doc[F("eth")]; CJSON(ethernetType, ethernet["type"]); + #if defined(WLED_ETHERNET_ONLY_BUILD) && defined(WLED_ETH_DEFAULT) + if (ethernetType == WLED_ETH_NONE) ethernetType = WLED_ETH_DEFAULT; + #endif // NOTE: Ethernet configuration takes priority over other use of pins initEthernet(); #endif @@ -922,18 +925,8 @@ void serializeConfig(JsonObject root) { if (ethernetBoards[ethernetType].eth_power>=0) pins.add(ethernetBoards[ethernetType].eth_power); if (ethernetBoards[ethernetType].eth_mdc>=0) pins.add(ethernetBoards[ethernetType].eth_mdc); if (ethernetBoards[ethernetType].eth_mdio>=0) pins.add(ethernetBoards[ethernetType].eth_mdio); - switch (ethernetBoards[ethernetType].eth_clk_mode) { - case ETH_CLOCK_GPIO0_IN: - case ETH_CLOCK_GPIO0_OUT: - pins.add(0); - break; - case ETH_CLOCK_GPIO16_OUT: - pins.add(16); - break; - case ETH_CLOCK_GPIO17_OUT: - pins.add(17); - break; - } + managed_pin_type clockPin = ethernetClockPin(ethernetBoards[ethernetType]); + if (clockPin.pin >= 0) pins.add(clockPin.pin); } #endif diff --git a/wled00/const.h b/wled00/const.h index 1055942cb1..ac516aeaca 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -10,7 +10,6 @@ constexpr size_t FASTLED_PALETTE_COUNT = 7; // 6-12 = sizeof(fastledPalettes) constexpr size_t GRADIENT_PALETTE_COUNT = 59; // 13-72 = sizeof(gGradientPalettes) / sizeof(gGradientPalettes[0]); constexpr size_t DYNAMIC_PALETTE_COUNT = 6; // 0- 5 = dynamic palettes (0=default(virtual),1=random,2=primary,3=primary+secondary,4=primary+secondary+tertiary,5=primary+secondary(+tertiary if not black) constexpr size_t FIXED_PALETTE_COUNT = DYNAMIC_PALETTE_COUNT + FASTLED_PALETTE_COUNT + GRADIENT_PALETTE_COUNT; // total number of fixed palettes - // Palette ID space layout (palette IDs are uint8_t, 0-255): // 0 .. FIXED_PALETTE_COUNT-1 : fixed built-in palettes // 72 .. WLED_CUSTOM_PALETTE_ID_BASE(200) : user custom palettes (index 0 = ID 200, growing downward) @@ -73,8 +72,14 @@ constexpr size_t WLED_MAX_USERMOD_PALETTES = WLED_USERMOD_PALETTE_ID_BASE - #if !defined(LEDC_CHANNEL_MAX) || !defined(LEDC_SPEED_MODE_MAX) #include "driver/ledc.h" // needed for analog/LEDC channel counts #endif - #define WLED_MAX_ANALOG_CHANNELS (LEDC_CHANNEL_MAX*LEDC_SPEED_MODE_MAX) - #if defined(CONFIG_IDF_TARGET_ESP32C3) // 2 RMT, 6 LEDC, only has 1 I2S but NPB does not support it ATM + + // define -> constexpr to avoid preprocessor errors and enum arithmetic warnings from newer compilers + #ifdef WLED_MAX_ANALOG_CHANNELS + #undef WLED_MAX_ANALOG_CHANNELS // avoid clash between macro name and constexpr constant + #endif + constexpr size_t WLED_MAX_ANALOG_CHANNELS = static_cast(LEDC_CHANNEL_MAX) * static_cast(LEDC_SPEED_MODE_MAX); + + #if defined(CONFIG_IDF_TARGET_ESP32C3) #define WLED_MAX_RMT_CHANNELS 2 // ESP32-C3 has 2 RMT output channels #define WLED_MAX_I2S_CHANNELS 0 // I2S not supported by NPB //#define WLED_MAX_ANALOG_CHANNELS 6 @@ -89,6 +94,10 @@ constexpr size_t WLED_MAX_USERMOD_PALETTES = WLED_USERMOD_PALETTE_ID_BASE - #define WLED_MAX_I2S_CHANNELS 8 // uses LCD parallel output not I2S //#define WLED_MAX_ANALOG_CHANNELS 8 #define WLED_PLATFORM_ID 3 // used in UI to distinguish ESP type in UI, needs a proper fix! + #elif defined(CONFIG_IDF_TARGET_ESP32P4) + #define WLED_MAX_RMT_CHANNELS 2 // ESP32-P4 uses the shared RMT driver + #define WLED_MAX_I2S_CHANNELS 0 // I2S LED output is not supported by NeoPixelBus on P4 + #define WLED_PLATFORM_ID 42 // used in UI to distinguish ESP type in UI #else #define WLED_MAX_RMT_CHANNELS 8 // ESP32 has 8 RMT output channels #define WLED_MAX_I2S_CHANNELS 8 // I2S parallel output supported by NPB @@ -96,14 +105,19 @@ constexpr size_t WLED_MAX_USERMOD_PALETTES = WLED_USERMOD_PALETTE_ID_BASE - #define WLED_PLATFORM_ID 4 // used in UI to distinguish ESP type in UI, needs a proper fix! #endif #define WLED_MAX_TIMERS 64 // maximum number of timers - #define WLED_MAX_DIGITAL_CHANNELS (WLED_MAX_RMT_CHANNELS + WLED_MAX_I2S_CHANNELS) + #ifndef WLED_MAX_DIGITAL_CHANNELS + #define WLED_MAX_DIGITAL_CHANNELS (WLED_MAX_RMT_CHANNELS + WLED_MAX_I2S_CHANNELS) + #else + #warning "buildenv overrides WLED_MAX_DIGITAL_CHANNELS - please check that the value is correct" + #endif #endif // WLED_MAX_BUSSES was used to define the size of busses[] array which is no longer needed // instead it will help determine max number of buses that can be defined at compile time #ifdef WLED_MAX_BUSSES #undef WLED_MAX_BUSSES #endif -#define WLED_MAX_BUSSES (WLED_MAX_DIGITAL_CHANNELS+WLED_MAX_ANALOG_CHANNELS) +// define -> constexpr to align with definition of WLED_MAX_ANALOG_CHANNELS +constexpr size_t WLED_MAX_BUSSES = WLED_MAX_DIGITAL_CHANNELS + WLED_MAX_ANALOG_CHANNELS; static_assert(WLED_MAX_BUSSES <= 32, "WLED_MAX_BUSSES exceeds hard limit"); // Maximum number of pins per output. 5 for RGBCCT analog LEDs. @@ -395,7 +409,7 @@ static_assert(WLED_MAX_BUSSES <= 32, "WLED_MAX_BUSSES exceeds hard limit"); #define BTN_TYPE_TOUCH_SWITCH 9 //Ethernet board types -#define WLED_NUM_ETH_TYPES 16 +#define WLED_NUM_ETH_TYPES 17 #define WLED_ETH_NONE 0 @@ -414,7 +428,7 @@ static_assert(WLED_MAX_BUSSES <= 32, "WLED_MAX_BUSSES exceeds hard limit"); #define WLED_ETH_GLEDOPTO 13 #define WLED_ETH_QUINLED_V4_UNOQUAD 14 #define WLED_ETH_QUINLED_V4_OCTA 15 - +#define WLED_ETH_ESP32P4_ETH 16 //Hue error codes #define HUE_ERROR_INACTIVE 0 @@ -537,7 +551,7 @@ static_assert(WLED_MAX_BUSSES <= 32, "WLED_MAX_BUSSES exceeds hard limit"); #elif defined(CONFIG_IDF_TARGET_ESP32S2) #define MAX_LEDS 2048 //due to memory constraints S2 #else - #define MAX_LEDS 16384 + #define MAX_LEDS 16384 // classic esp32, S3 and P4 can take more #endif #endif @@ -552,7 +566,7 @@ static_assert(WLED_MAX_BUSSES <= 32, "WLED_MAX_BUSSES exceeds hard limit"); #else #define MAX_LED_MEMORY (48*1024) // with PSRAM there is more wiggle room as buffers get moved to PSRAM when needed (prioritize functionality over speed) #endif - #elif defined(CONFIG_IDF_TARGET_ESP32S3) + #elif defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32P4) #define MAX_LED_MEMORY (192*1024) // S3 has ~330k of free heap after boot #elif defined(CONFIG_IDF_TARGET_ESP32C3) #define MAX_LED_MEMORY (100*1024) // C3 has ~240k of free heap after boot, even with 8000 LEDs configured (2D) there is 30k of contiguous heap left @@ -670,7 +684,7 @@ static_assert(WLED_MAX_BUSSES <= 32, "WLED_MAX_BUSSES exceeds hard limit"); #endif // Defaults pins, type and counts to configure LED output -#if defined(ESP8266) || defined(CONFIG_IDF_TARGET_ESP32C3) +#if defined(ESP8266) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32P4) #ifdef WLED_ENABLE_DMX #define DEFAULT_LED_PIN 1 #warning "Compiling with DMX. The default LED pin has been changed to pin 1." diff --git a/wled00/data/settings_wifi.htm b/wled00/data/settings_wifi.htm index e187f887fb..7ea8f5ab27 100644 --- a/wled00/data/settings_wifi.htm +++ b/wled00/data/settings_wifi.htm @@ -240,6 +240,7 @@

Ethernet Type

+ diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 6201a19192..1c03353521 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -3,6 +3,13 @@ #define WLED_FCN_DECLARE_H #include +// dummy macro for 8266 +#ifndef ARDUINO_ARCH_ESP32 +#ifndef ESP_IDF_VERSION_VAL +#define ESP_IDF_VERSION_VAL(n1,n2,n3) 500 +#endif +#endif + #include "colors.h" /* @@ -25,7 +32,9 @@ bool isButtonPressed(uint8_t b=0); void handleButton(); void handleOnOff(bool forceOff = false); void handleIO(); +#ifdef SOC_TOUCH_VERSION_2 // ESP32 S2 and S3 have a function to check touch state but need to attach an interrupt to do so void IRAM_ATTR touchButtonISR(); +#endif //cfg.cpp bool backupConfig(); @@ -451,8 +460,12 @@ uint8_t extractModeSlider(uint8_t mode, uint8_t slider, char *dest, uint8_t maxL int16_t extractModeDefaults(uint8_t mode, const char *segVar); void checkSettingsPIN(const char *pin); uint16_t crc16(const unsigned char* data_p, size_t length); + +#if !defined(ARDUINO_ARCH_ESP32) || (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(6, 0, 0)) // ToDO: verify that this works correctly in V5 String computeSHA1(const String& input); String getDeviceId(); +#endif + uint16_t beat88(uint16_t beats_per_minute_88, uint32_t timebase = 0); uint16_t beat16(uint16_t beats_per_minute, uint32_t timebase = 0); uint8_t beat8(uint16_t beats_per_minute, uint32_t timebase = 0); @@ -524,10 +537,10 @@ inline size_t getFreeHeapSize() { return ESP.getFreeHeap(); } // returns free he inline size_t getContiguousFreeHeap() { return ESP.getMaxFreeBlockSize(); } // returns largest contiguous free block #endif #define BFRALLOC_NOBYTEACCESS (1 << 0) // ESP32 has 32bit accessible DRAM (usually ~50kB free) that must not be byte-accessed -#define BFRALLOC_PREFER_DRAM (1 << 1) // prefer DRAM over PSRAM (can still use PSRAM for larger allocations if DRAM is starting to run low) -#define BFRALLOC_ENFORCE_DRAM (1 << 2) // use DRAM only, no PSRAM allowed -#define BFRALLOC_PREFER_PSRAM (1 << 3) // prefer PSRAM over DRAM (can still use DRAM if there is loads of free DRAM to optimize speed) -#define BFRALLOC_ENFORCE_PSRAM (1 << 4) // use PSRAM if available, falls back to DRAM if PSRAM fails +#define BFRALLOC_PREFER_DRAM (1 << 1) // prefer DRAM over PSRAM +#define BFRALLOC_ENFORCE_DRAM (1 << 2) // use DRAM only, no PSRAM +#define BFRALLOC_PREFER_PSRAM (1 << 3) // prefer PSRAM over DRAM +#define BFRALLOC_ENFORCE_PSRAM (1 << 4) // use PSRAM if available, otherwise uses DRAM #define BFRALLOC_CLEAR (1 << 5) // clear allocated buffer after allocation void *allocate_buffer(size_t size, uint32_t type); diff --git a/wled00/json.cpp b/wled00/json.cpp index b4388d27ef..ec25fa8f45 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -1116,6 +1116,9 @@ void serializePins(JsonObject root) #elif defined(CONFIG_IDF_TARGET_ESP32) // ESP32 classic if (gpio == 0) caps |= PIN_CAP_BOOT; // pull low to enter bootloader mode if (gpio == 2 || gpio == 12) caps |= PIN_CAP_BOOTSTRAP; // note: if GPIO12 must be low at boot, (high=1.8V flash mode), GPIO 2 must be low or floating to enter bootloader mode + #elif defined(CONFIG_IDF_TARGET_ESP32P4) + if (gpio == 35) caps |= PIN_CAP_BOOT; // pull low to enter bootloader mode + if (gpio == 36) caps |= PIN_CAP_BOOTSTRAP; // must be high when GPIO35 is low for download mode #endif #else // ESP8266: GPIO 0-16 + GPIO17=A0 diff --git a/wled00/mbedtls_sha1_shim.cpp b/wled00/mbedtls_sha1_shim.cpp new file mode 100644 index 0000000000..d5e8ce856e --- /dev/null +++ b/wled00/mbedtls_sha1_shim.cpp @@ -0,0 +1,51 @@ +#include "wled.h" +#ifdef ESP32 +// IDF 5.5+ has SHA1 built in, skip shim +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0) && ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 5, 0) +#include "mbedtls/sha1.h" +#include "SHA1Builder.h" + +// Wrapper functions to map mbedtls SHA1 calls to Arduino SHA1Builder +// This is needed because ESP-IDF 5.x disables SHA1 in mbedtls by default + +struct mbedtls_sha1_context_wrapper { + SHA1Builder builder; +}; + +extern "C" { + +void mbedtls_sha1_init(mbedtls_sha1_context *ctx) { + // Allocate wrapper + auto* wrapper = new mbedtls_sha1_context_wrapper(); + *(void**)ctx = wrapper; +} + +int mbedtls_sha1_starts(mbedtls_sha1_context *ctx) { + auto* wrapper = *(mbedtls_sha1_context_wrapper**)ctx; + wrapper->builder.begin(); + return 0; +} + +int mbedtls_sha1_update(mbedtls_sha1_context *ctx, const unsigned char *input, size_t ilen) { + auto* wrapper = *(mbedtls_sha1_context_wrapper**)ctx; + wrapper->builder.add((const uint8_t*)input, ilen); + return 0; +} + +int mbedtls_sha1_finish(mbedtls_sha1_context *ctx, unsigned char output[20]) { + auto* wrapper = *(mbedtls_sha1_context_wrapper**)ctx; + wrapper->builder.calculate(); + wrapper->builder.getBytes(output); + return 0; +} + +void mbedtls_sha1_free(mbedtls_sha1_context *ctx) { + auto* wrapper = *(mbedtls_sha1_context_wrapper**)ctx; + delete wrapper; +} + +} // extern "C" + +#endif + +#endif diff --git a/wled00/network.cpp b/wled00/network.cpp index 606fa65d9e..cf48ce1499 100644 --- a/wled00/network.cpp +++ b/wled00/network.cpp @@ -4,16 +4,40 @@ #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) -// The following six pins are neither configurable nor -// can they be re-assigned through IOMUX / GPIO matrix. -// See https://docs.espressif.com/projects/esp-idf/en/latest/esp32/hw-reference/esp32/get-started-ethernet-kit-v1.1.html#ip101gri-phy-interface +#if defined(CONFIG_IDF_TARGET_ESP32P4) +#define WLED_ETH_CLOCK_EXT_IN EMAC_CLK_EXT_IN +#define WLED_ETH_CLOCK_OUT EMAC_CLK_OUT +#define WLED_ETH_CLOCK_GPIO0_IN WLED_ETH_CLOCK_EXT_IN +#define WLED_ETH_CLOCK_GPIO0_OUT WLED_ETH_CLOCK_OUT +#define WLED_ETH_CLOCK_GPIO16_OUT WLED_ETH_CLOCK_OUT +#define WLED_ETH_CLOCK_GPIO17_OUT WLED_ETH_CLOCK_OUT +#else +#define WLED_ETH_CLOCK_EXT_IN ETH_CLOCK_GPIO0_IN +#define WLED_ETH_CLOCK_OUT ETH_CLOCK_GPIO0_OUT +#define WLED_ETH_CLOCK_GPIO0_IN ETH_CLOCK_GPIO0_IN +#define WLED_ETH_CLOCK_GPIO0_OUT ETH_CLOCK_GPIO0_OUT +#define WLED_ETH_CLOCK_GPIO16_OUT ETH_CLOCK_GPIO16_OUT +#define WLED_ETH_CLOCK_GPIO17_OUT ETH_CLOCK_GPIO17_OUT +#endif + +// The following six pins are neither configurable nor can they be re-assigned. const managed_pin_type esp32_nonconfigurable_ethernet_pins[WLED_ETH_RSVD_PINS_COUNT] = { +#if defined(CONFIG_IDF_TARGET_ESP32P4) + { ETH_RMII_TX_EN, true }, // RMII EMAC TX EN == When high, clocks the data on TXD0 and TXD1 to transmitter + { ETH_RMII_TX0, true }, // RMII EMAC TXD0 == First bit of transmitted data + { ETH_RMII_TX1, true }, // RMII EMAC TXD1 == Second bit of transmitted data + { ETH_RMII_RX0, false }, // RMII EMAC RXD0 == First bit of received data + { ETH_RMII_RX1_EN, false }, // RMII EMAC RXD1 == Second bit of received data + { ETH_RMII_CRS_DV, false }, // RMII EMAC CRS_DV == Carrier Sense and RX Data Valid +#else + // See https://docs.espressif.com/projects/esp-idf/en/latest/esp32/hw-reference/esp32/get-started-ethernet-kit-v1.1.html#ip101gri-phy-interface { 21, true }, // RMII EMAC TX EN == When high, clocks the data on TXD0 and TXD1 to transmitter { 19, true }, // RMII EMAC TXD0 == First bit of transmitted data { 22, true }, // RMII EMAC TXD1 == Second bit of transmitted data { 25, false }, // RMII EMAC RXD0 == First bit of received data { 26, false }, // RMII EMAC RXD1 == Second bit of received data { 27, true }, // RMII EMAC CRS_DV == Carrier Sense and RX Data Valid +#endif }; const ethernet_settings ethernetBoards[] = { @@ -32,7 +56,7 @@ const ethernet_settings ethernetBoards[] = { 23, // eth_mdc, 18, // eth_mdio, ETH_PHY_LAN8720, // eth_type, - ETH_CLOCK_GPIO0_IN // eth_clk_mode + WLED_ETH_CLOCK_GPIO0_IN // eth_clk_mode }, // ESP32-POE @@ -42,7 +66,7 @@ const ethernet_settings ethernetBoards[] = { 23, // eth_mdc, 18, // eth_mdio, ETH_PHY_LAN8720, // eth_type, - ETH_CLOCK_GPIO17_OUT // eth_clk_mode + WLED_ETH_CLOCK_GPIO17_OUT // eth_clk_mode }, // WESP32 @@ -52,7 +76,7 @@ const ethernet_settings ethernetBoards[] = { 16, // eth_mdc, 17, // eth_mdio, ETH_PHY_LAN8720, // eth_type, - ETH_CLOCK_GPIO0_IN // eth_clk_mode + WLED_ETH_CLOCK_GPIO0_IN // eth_clk_mode }, // QuinLed-ESP32-Ethernet @@ -62,7 +86,7 @@ const ethernet_settings ethernetBoards[] = { 23, // eth_mdc, 18, // eth_mdio, ETH_PHY_LAN8720, // eth_type, - ETH_CLOCK_GPIO17_OUT // eth_clk_mode + WLED_ETH_CLOCK_GPIO17_OUT // eth_clk_mode }, // TwilightLord-ESP32 Ethernet Shield @@ -72,7 +96,7 @@ const ethernet_settings ethernetBoards[] = { 23, // eth_mdc, 18, // eth_mdio, ETH_PHY_LAN8720, // eth_type, - ETH_CLOCK_GPIO17_OUT // eth_clk_mode + WLED_ETH_CLOCK_GPIO17_OUT // eth_clk_mode }, // ESP3DEUXQuattro @@ -82,17 +106,17 @@ const ethernet_settings ethernetBoards[] = { 23, // eth_mdc, 18, // eth_mdio, ETH_PHY_LAN8720, // eth_type, - ETH_CLOCK_GPIO17_OUT // eth_clk_mode + WLED_ETH_CLOCK_GPIO17_OUT // eth_clk_mode }, // ESP32-ETHERNET-KIT-VE { - 1, // eth_address, + 0, // eth_address, 5, // eth_power, 23, // eth_mdc, 18, // eth_mdio, ETH_PHY_IP101, // eth_type, - ETH_CLOCK_GPIO0_IN // eth_clk_mode + WLED_ETH_CLOCK_GPIO0_IN // eth_clk_mode }, // QuinLed-Dig-Octa Brainboard-32-8L and LilyGO-T-ETH-POE @@ -102,7 +126,7 @@ const ethernet_settings ethernetBoards[] = { 23, // eth_mdc, 18, // eth_mdio, ETH_PHY_LAN8720, // eth_type, - ETH_CLOCK_GPIO17_OUT // eth_clk_mode + WLED_ETH_CLOCK_GPIO17_OUT // eth_clk_mode }, // ABC! WLED Controller V43 + Ethernet Shield & compatible @@ -112,7 +136,7 @@ const ethernet_settings ethernetBoards[] = { 23, // eth_mdc, 33, // eth_mdio, ETH_PHY_LAN8720, // eth_type, - ETH_CLOCK_GPIO17_OUT // eth_clk_mode + WLED_ETH_CLOCK_GPIO17_OUT // eth_clk_mode }, // Serg74-ESP32 Ethernet Shield @@ -122,7 +146,7 @@ const ethernet_settings ethernetBoards[] = { 23, // eth_mdc, 18, // eth_mdio, ETH_PHY_LAN8720, // eth_type, - ETH_CLOCK_GPIO17_OUT // eth_clk_mode + WLED_ETH_CLOCK_GPIO17_OUT // eth_clk_mode }, // ESP32-POE-WROVER @@ -132,7 +156,7 @@ const ethernet_settings ethernetBoards[] = { 23, // eth_mdc, 18, // eth_mdio, ETH_PHY_LAN8720, // eth_type, - ETH_CLOCK_GPIO0_OUT // eth_clk_mode + WLED_ETH_CLOCK_GPIO0_OUT // eth_clk_mode }, // LILYGO T-POE Pro @@ -143,19 +167,19 @@ const ethernet_settings ethernetBoards[] = { 23, // eth_mdc, 18, // eth_mdio, ETH_PHY_LAN8720, // eth_type, - ETH_CLOCK_GPIO0_OUT // eth_clk_mode + WLED_ETH_CLOCK_GPIO0_OUT // eth_clk_mode }, // Gledopto Series With Ethernet { - 1, // eth_address, - 5, // eth_power, - 23, // eth_mdc, - 33, // eth_mdio, + 1, // eth_address, + 5, // eth_power, + 23, // eth_mdc, + 33, // eth_mdio, ETH_PHY_LAN8720, // eth_type, - ETH_CLOCK_GPIO0_IN // eth_clk_mode + WLED_ETH_CLOCK_GPIO0_IN // eth_clk_mode }, - + // WLED_ETH_QUINLED_V4 (14) - QuinLED Dig-Uno/Quad v4 { 0, // eth_address @@ -163,9 +187,9 @@ const ethernet_settings ethernetBoards[] = { 7, // eth_mdc 8, // eth_mdio ETH_PHY_LAN8720, // eth_type - ETH_CLOCK_GPIO0_IN // eth_clk_mode + WLED_ETH_CLOCK_GPIO0_IN // eth_clk_mode }, - + // WLED_ETH_QUINLED_OCTA_V4 (15) - QuinLED Dig-Octa 32-8L v4 { 0, // eth_address @@ -173,7 +197,17 @@ const ethernet_settings ethernetBoards[] = { 23, // eth_mdc 18, // eth_mdio ETH_PHY_LAN8720, // eth_type - ETH_CLOCK_GPIO0_IN // eth_clk_mode + WLED_ETH_CLOCK_GPIO0_IN // eth_clk_mode + }, + + // Waveshare ESP32-P4-ETH / ESP32-P4-POE-ETH + { + 1, // eth_address, + 51, // eth_power, + 31, // eth_mdc, + 52, // eth_mdio, + ETH_PHY_IP101, // eth_type, + WLED_ETH_CLOCK_EXT_IN // eth_clk_mode }, }; @@ -183,6 +217,21 @@ static_assert((sizeof(ethernetBoards)/sizeof(ethernetBoards[0])) == WLED_NUM_ETH static_assert(((WLED_ETH_DEFAULT) >= WLED_ETH_NONE) && ((WLED_ETH_DEFAULT) < WLED_NUM_ETH_TYPES), "WLED_ETH_DEFAULT is out of range."); #endif +managed_pin_type ethernetClockPin(const ethernet_settings& settings) +{ +#if defined(CONFIG_IDF_TARGET_ESP32P4) + if (settings.eth_clk_mode == WLED_ETH_CLOCK_EXT_IN) return { ETH_RMII_CLK, false }; + if (settings.eth_clk_mode == WLED_ETH_CLOCK_OUT) return { ETH_RMII_CLK, true }; +#else + if (settings.eth_clk_mode == WLED_ETH_CLOCK_GPIO0_IN) return { 0, false }; + if (settings.eth_clk_mode == WLED_ETH_CLOCK_GPIO0_OUT) return { 0, true }; + if (settings.eth_clk_mode == WLED_ETH_CLOCK_GPIO16_OUT) return { 16, true }; + if (settings.eth_clk_mode == WLED_ETH_CLOCK_GPIO17_OUT) return { 17, true }; +#endif + + return { -1, false }; +} + bool initEthernet() { static bool successfullyConfiguredEthernet = false; @@ -217,19 +266,8 @@ bool initEthernet() { ((int8_t)0xFE), false }, // [9] = replaced with eth_clk_mode, mandatory }; // update the clock pin.... - if (es.eth_clk_mode == ETH_CLOCK_GPIO0_IN) { - pinsToAllocate[9].pin = 0; - pinsToAllocate[9].isOutput = false; - } else if (es.eth_clk_mode == ETH_CLOCK_GPIO0_OUT) { - pinsToAllocate[9].pin = 0; - pinsToAllocate[9].isOutput = true; - } else if (es.eth_clk_mode == ETH_CLOCK_GPIO16_OUT) { - pinsToAllocate[9].pin = 16; - pinsToAllocate[9].isOutput = true; - } else if (es.eth_clk_mode == ETH_CLOCK_GPIO17_OUT) { - pinsToAllocate[9].pin = 17; - pinsToAllocate[9].isOutput = true; - } else { + pinsToAllocate[9] = ethernetClockPin(es); + if (pinsToAllocate[9].pin < 0) { DEBUG_PRINTF_P(PSTR("initE: Failing due to invalid eth_clk_mode (%d)\n"), es.eth_clk_mode); return false; } @@ -257,6 +295,16 @@ bool initEthernet() } #endif +#if defined(ESP_IDF_VERSION) && (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)) + if (!ETH.begin( // parameter order in V5 has changed + (eth_phy_type_t) es.eth_type, + (int32_t) es.eth_address, + (int) es.eth_mdc, + (int) es.eth_mdio, + (int) es.eth_power, + (eth_clock_mode_t) es.eth_clk_mode + )) { +#else if (!ETH.begin( (uint8_t) es.eth_address, (int) es.eth_power, @@ -265,6 +313,7 @@ bool initEthernet() (eth_phy_type_t) es.eth_type, (eth_clock_mode_t) es.eth_clk_mode )) { +#endif DEBUG_PRINTLN(F("initE: ETH.begin() failed")); // de-allocate the allocated pins for (managed_pin_type mpt : pinsToAllocate) { @@ -274,7 +323,7 @@ bool initEthernet() } // https://github.com/wled/WLED/issues/5247 - if (multiWiFi[0].staticIP != (uint32_t)0x00000000 && multiWiFi[0].staticGW != (uint32_t)0x00000000) { + if (multiWiFi[0].staticIP != IPAddress((uint32_t)0) && multiWiFi[0].staticGW != IPAddress((uint32_t)0)) { ETH.config(multiWiFi[0].staticIP, multiWiFi[0].staticGW, multiWiFi[0].staticSN, dnsAddress); } else { ETH.config(INADDR_NONE, INADDR_NONE, INADDR_NONE); @@ -339,7 +388,7 @@ int findWiFi(bool doScan) { } else if (status >= 0) { // status contains number of found networks (including duplicate SSIDs with different BSSID) DEBUG_PRINTF_P(PSTR("WiFi: Found %d SSIDs. @ %lus\n"), status, millis()/1000); int rssi = -9999; - int selected = selectedWiFi; + size_t selected = (static_cast(selectedWiFi) < multiWiFi.size()) ? static_cast(selectedWiFi) : 0; // ensure valid starting index for (int o = 0; o < status; o++) { DEBUG_PRINTF_P(PSTR(" SSID: %s (BSSID: %s) RSSI: %ddB\n"), WiFi.SSID(o).c_str(), WiFi.BSSIDstr(o).c_str(), WiFi.RSSI(o)); for (unsigned n = 0; n < multiWiFi.size(); n++) @@ -384,6 +433,7 @@ bool isWiFiConfigured() { #define ARDUINO_EVENT_ETH_START SYSTEM_EVENT_ETH_START #define ARDUINO_EVENT_ETH_CONNECTED SYSTEM_EVENT_ETH_CONNECTED #define ARDUINO_EVENT_ETH_DISCONNECTED SYSTEM_EVENT_ETH_DISCONNECTED + #define ARDUINO_EVENT_ETH_GOT_IP SYSTEM_EVENT_ETH_GOT_IP #endif #if defined(ARDUINO_ARCH_ESP32) && defined(LWIP_IPV6) @@ -430,12 +480,12 @@ void WiFiEvent(WiFiEvent_t event) DEBUG_PRINTF_P(PSTR("WiFi-E: AP Client Connected (%d) @ %lus.\n"), (int)apClients, millis()/1000); break; case ARDUINO_EVENT_WIFI_STA_GOT_IP: - DEBUG_PRINT(F("WiFi-E: IP address: ")); DEBUG_PRINTLN(Network.localIP()); + DEBUG_PRINT(F("WiFi-E: IP address: ")); DEBUG_PRINTLN(WLEDNetwork.localIP()); + wasConnected = true; break; case ARDUINO_EVENT_WIFI_STA_CONNECTED: // followed by IDLE and SCAN_DONE DEBUG_PRINTF_P(PSTR("WiFi-E: Connected! @ %lus\n"), millis()/1000); - wasConnected = true; break; case ARDUINO_EVENT_WIFI_STA_DISCONNECTED: if (wasConnected && interfacesInited) { @@ -448,26 +498,10 @@ void WiFiEvent(WiFiEvent_t event) } break; #ifdef ARDUINO_ARCH_ESP32 - case ARDUINO_EVENT_WIFI_READY: - DEBUG_PRINTLN(F("WiFi-E: driver ready.")); - break; case ARDUINO_EVENT_WIFI_SCAN_DONE: // also triggered when connected to selected SSID DEBUG_PRINTLN(F("WiFi-E: SSID scan completed.")); break; - case ARDUINO_EVENT_WIFI_STA_START: - DEBUG_PRINTLN(F("WiFi-E: STA Started")); - break; - case ARDUINO_EVENT_WIFI_STA_STOP: - DEBUG_PRINTLN(F("WiFi-E: STA Stopped")); - break; - case ARDUINO_EVENT_WIFI_STA_AUTHMODE_CHANGE: - DEBUG_PRINTLN(F("WiFi-E: STA authentication mode change.")); - break; - case ARDUINO_EVENT_WIFI_STA_LOST_IP: - DEBUG_PRINTLN(F("WiFi-E: IP address lost.")); - break; - case ARDUINO_EVENT_WIFI_AP_START: DEBUG_PRINTLN(F("WiFi-E: AP Started")); break; @@ -481,15 +515,21 @@ void WiFiEvent(WiFiEvent_t event) case ARDUINO_EVENT_ETH_CONNECTED: { DEBUG_PRINTLN(F("ETH-E: Connected")); +#ifndef WLED_ETHERNET_ONLY_BUILD if (!apActive) { WiFi.disconnect(true); // disable WiFi entirely } +#endif char hostname[64] = {'\0'}; // any "hostname" within a Fully Qualified Domain Name (FQDN) must not exceed 63 characters getWLEDhostname(hostname, sizeof(hostname), true); // create DNS name based on mDNS name if set, or fall back to standard WLED server name ETH.setHostname(hostname); showWelcomePage = false; break; } + case ARDUINO_EVENT_ETH_GOT_IP: + DEBUG_PRINT(F("ETH-E: IP address: ")); DEBUG_PRINTLN(WLEDNetwork.localIP()); + wasConnected = true; + break; case ARDUINO_EVENT_ETH_DISCONNECTED: DEBUG_PRINTLN(F("ETH-E: Disconnected")); // This doesn't really affect ethernet per se, @@ -497,8 +537,13 @@ void WiFiEvent(WiFiEvent_t event) // may be necessary to reconnect the WiFi when // ethernet disconnects, as a way to provide // alternative access to the device. +#ifndef WLED_ETHERNET_ONLY_BUILD if (interfacesInited && WiFi.scanComplete() >= 0) findWiFi(true); // reinit WiFi scan forceReconnect = true; +#else + interfacesInited = false; + wasConnected = false; +#endif break; #endif #endif @@ -507,4 +552,3 @@ void WiFiEvent(WiFiEvent_t event) break; } } - diff --git a/wled00/pin_manager.cpp b/wled00/pin_manager.cpp index 84eaaec1fc..4762d4d1fc 100644 --- a/wled00/pin_manager.cpp +++ b/wled00/pin_manager.cpp @@ -100,15 +100,17 @@ bool PinManager::allocateMultiplePins(const managed_pin_type * mptArray, byte ar // as this can greatly simplify configuration arrays continue; } - // allow any GPIO for Ethernet (compile time assigned) - if (!(isPinOk(gpio, mptArray[i].isOutput) || tag==PinOwner::Ethernet)) { + const bool pinOk = isPinOk(gpio, mptArray[i].isOutput); + const bool ethernetReservedPin = (tag == PinOwner::Ethernet && gpio < WLED_NUM_PINS && !pinOk); + // allow reserved GPIOs for Ethernet (compile time assigned) + if (!(pinOk || ethernetReservedPin)) { DEBUG_PRINTF_P(PSTR("PIN ALLOC: FAIL Invalid pin attempted to be allocated: GPIO %d as %s\n."), gpio, mptArray[i].isOutput ? PSTR("output"): PSTR("input")); shouldFail = true; } if ((tag==PinOwner::HW_I2C || tag==PinOwner::HW_SPI) && isPinAllocated(gpio, tag)) { // allow multiple "allocations" of HW I2C & SPI bus pins continue; - } else if (isPinAllocated(gpio)) { + } else if (ethernetReservedPin ? ownerTag[gpio] != PinOwner::None : isPinAllocated(gpio)) { DEBUG_PRINTF_P(PSTR("PIN ALLOC: FAIL GPIO %d already allocated by 0x%02X.\n"), gpio, static_cast(ownerTag[gpio])); shouldFail = true; } @@ -232,6 +234,26 @@ bool PinManager::isPinOk(byte gpio, bool output) if (gpio > 21 && gpio < 33) return false; // 22 to 32: not connected + SPI FLASH // JTAG: GPIO39-42 are usually used for inline debugging // GPIO46 is input only and pulled down + #elif defined(CONFIG_IDF_TARGET_ESP32P4) + // based on P4 port by troyhacks https://github.com/troyhacks/WLED/tree/P4_experimental + // strapping pins: 34,35,36,37,38 + // Hide all pins not available on connector except pins we need to assign to things later, like I2S + // TODO: this list is over-protective - clean up later. + if ( gpio == 9) return false; // I2S Sound Output Pin + if (gpio > 13 && gpio < 20) return false; // ESP-Hosted WiFi pins + #if ARDUINO_USB_CDC_ON_BOOT == 1 || ARDUINO_USB_DFU_ON_BOOT == 1 + if (gpio > 23 && gpio < 26) return false; // USB Pins + #endif + if (gpio > 27 && gpio < 32) return false; // Ethernet pins + if (gpio > 33 && gpio < 36) return false; // Ethernet pins - boot button is on 35 and works... but messes with Ethernet if enabled in WLED + if (gpio > 38 && gpio < 45) return false; // SD1 Pins + if (gpio > 48 && gpio < 53) return false; // Ethernet pins & others + if ( gpio == 54) return false; // C6 WiFi EN pin + // + // 24-25 is is USB, but so is 26-27 but they're exposed on the header and work OK for pin outout. + // 45 is SD power but it's NC without hacking the board. + // 53 is for PA enable but it's exposed on header and works for WLED pin output. Best to not use it but left available. + // 54 is "C6 EN pin" so I guess we shouldn't touch it. #else if ((strncmp_P(PSTR("ESP32-U4WDH"), ESP.getChipModel(), 11) == 0) || // this is the correct identifier, but.... @@ -253,7 +275,7 @@ bool PinManager::isPinOk(byte gpio, bool output) } else { return !psramFound(); // PSRAM pins on modules with in-package PSRAM } - } + } #endif if (output) return digitalPinCanOutput(gpio); else return true; @@ -369,11 +391,20 @@ bool PinManager::isAnalogPin(byte gpio) { #elif CONFIG_IDF_TARGET_ESP32S3 // ESP32-S3: ADC1 channels 0-9 (GPIO 1-10) int adc_channel = digitalPinToAnalogChannel(gpio); - if (adc_channel >= 0 && adc_channel <= 9) return true; + if (adc_channel >= 0 && adc_channel <= 9) return true; // ADC-1 + // ESP32-S3: ADC2 channels 0-9 + if ((adc_channel >= SOC_ADC_CHANNEL_NUM(0)) && ((adc_channel - SOC_ADC_CHANNEL_NUM(0)) < SOC_ADC_CHANNEL_NUM(1))) return true; // ADC-2 #elif CONFIG_IDF_TARGET_ESP32C3 // ESP32-C3: ADC1 channels 0-4 (GPIO 0-4) int adc_channel = digitalPinToAnalogChannel(gpio); if (adc_channel >= 0 && adc_channel <= 4) return true; + #else // P4 - use generic SOC capability macros + int adc_channel = digitalPinToAnalogChannel(gpio); + if ((adc_channel < 0) || (adc_channel >= (SOC_ADC_PERIPH_NUM * SOC_ADC_MAX_CHANNEL_NUM))) return false; // out of range + if (adc_channel < SOC_ADC_CHANNEL_NUM(0)) return true; // ADC-1 + #if SOC_ADC_PERIPH_NUM > 1 + if ((adc_channel >= SOC_ADC_CHANNEL_NUM(0)) && ((adc_channel - SOC_ADC_CHANNEL_NUM(0)) < SOC_ADC_CHANNEL_NUM(1))) return true; // ADC-2 + #endif #endif #endif return false; // not an analog pin if it doesn't have ADC capability, ESP8266 has only one ADC pin (A0) which is handled separately in button.cpp, so return false for all pins here diff --git a/wled00/src/dependencies/network/Network.cpp b/wled00/src/dependencies/network/Network.cpp index dbc2707887..d56d4606a7 100644 --- a/wled00/src/dependencies/network/Network.cpp +++ b/wled00/src/dependencies/network/Network.cpp @@ -1,6 +1,10 @@ #include "Network.h" -IPAddress NetworkClass::localIP() +#ifdef ARDUINO_ARCH_ESP32 +std::shared_ptr DNSlookup; +#endif + +IPAddress WLEDNetworkClass::localIP() { IPAddress localIP; #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) @@ -17,7 +21,7 @@ IPAddress NetworkClass::localIP() return INADDR_NONE; } -IPAddress NetworkClass::subnetMask() +IPAddress WLEDNetworkClass::subnetMask() { #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) if (ETH.localIP()[0] != 0) { @@ -30,7 +34,7 @@ IPAddress NetworkClass::subnetMask() return IPAddress(255, 255, 255, 0); } -IPAddress NetworkClass::gatewayIP() +IPAddress WLEDNetworkClass::gatewayIP() { #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) if (ETH.localIP()[0] != 0) { @@ -43,7 +47,7 @@ IPAddress NetworkClass::gatewayIP() return INADDR_NONE; } -void NetworkClass::localMAC(uint8_t* MAC) +void WLEDNetworkClass::localMAC(uint8_t* MAC) { #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) // ETH.macAddress(MAC); // Does not work because of missing ETHClass:: in ETH.ccp @@ -71,12 +75,12 @@ void NetworkClass::localMAC(uint8_t* MAC) return; } -bool NetworkClass::isConnected() +bool WLEDNetworkClass::isConnected() { return (WiFi.localIP()[0] != 0 && WiFi.status() == WL_CONNECTED) || isEthernet(); } -bool NetworkClass::isEthernet() +bool WLEDNetworkClass::isEthernet() { #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) return (ETH.localIP()[0] != 0) && ETH.linkUp(); @@ -84,4 +88,4 @@ bool NetworkClass::isEthernet() return false; } -NetworkClass Network; \ No newline at end of file +WLEDNetworkClass WLEDNetwork; diff --git a/wled00/src/dependencies/network/Network.h b/wled00/src/dependencies/network/Network.h index 9201d514ea..a709abb218 100644 --- a/wled00/src/dependencies/network/Network.h +++ b/wled00/src/dependencies/network/Network.h @@ -3,12 +3,18 @@ #else // ESP32 #include #include + #include #endif #ifndef Network_h #define Network_h -class NetworkClass +#ifdef ARDUINO_ARCH_ESP32 +class AsyncDNS; +extern std::shared_ptr DNSlookup; +#endif + +class WLEDNetworkClass { public: IPAddress localIP(); @@ -19,6 +25,12 @@ class NetworkClass bool isEthernet(); }; -extern NetworkClass Network; +extern WLEDNetworkClass WLEDNetwork; -#endif \ No newline at end of file +// WLED historically used a helper named Network. arduino-esp32 3.x also +// provides a global NetworkManager named Network, so keep WLED's helper on a +// unique symbol and map existing WLED call sites to it after framework headers +// above have been included. +#define Network WLEDNetwork + +#endif diff --git a/wled00/util.cpp b/wled00/util.cpp index 179310e117..d66e23ebe3 100644 --- a/wled00/util.cpp +++ b/wled00/util.cpp @@ -14,6 +14,11 @@ #endif #include "mbedtls/sha1.h" // for SHA1 on ESP32 #include "esp_efuse.h" +#include "esp_chip_info.h" +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) + #include "SHA1Builder.h" + #include // V5 requirement +#endif #endif @@ -763,17 +768,17 @@ int32_t hw_random(int32_t lowerlimit, int32_t upperlimit) { // PSRAM compile time checks to provide info for misconfigured env #if defined(BOARD_HAS_PSRAM) - #if defined(IDF_TARGET_ESP32C3) || defined(ESP8266) +#if defined(CONFIG_IDF_TARGET_ESP32C3) || defined(ESP8266) #error "ESP32-C3 and ESP8266 with PSRAM is not supported, please remove BOARD_HAS_PSRAM definition" #else - #if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32S3) // PSRAM fix only needed for classic esp32 + #if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_IDF_TARGET_ESP32) // PSRAM fix only needed for classic esp32 // BOARD_HAS_PSRAM also means that compiler flag "-mfix-esp32-psram-cache-issue" has to be used for old "rev.1" esp32 #warning "BOARD_HAS_PSRAM defined, make sure to use -mfix-esp32-psram-cache-issue to prevent issues on rev.1 ESP32 boards \ see https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-guides/external-ram.html#esp32-rev-v1-0" #endif #endif #else - #if !defined(IDF_TARGET_ESP32C3) && !defined(ESP8266) + #if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(ESP8266) #pragma message("BOARD_HAS_PSRAM not defined, not using PSRAM.") #endif #endif @@ -830,7 +835,7 @@ static void *validateFreeHeap(void *buffer) { void *d_malloc(size_t size) { void *buffer = nullptr; - #if defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) + #if defined(WLED_HAVE_RTC_MEMORY_HEAP) // the newer ESP32 variants have byte-accessible fast RTC memory that can be used as heap, access speed is on-par with DRAM // the system does prefer normal DRAM until full, since free RTC memory is ~7.5k only, its below the minimum heap threshold and needs to be allocated explicitly // use RTC RAM for small allocations or if DRAM is running low to improve fragmentation @@ -920,7 +925,7 @@ void *allocate_buffer(size_t size, uint32_t type) { buffer = p_malloc(size); // prefer PSRAM } else if (type & BFRALLOC_ENFORCE_PSRAM) - buffer = p_malloc(size); // use PSRAM if available, fall back to DRAM if not (safeguard for boards without PSRAM #5629) + buffer = heap_caps_malloc(size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); // use PSRAM only, otherwise return nullptr buffer = validateFreeHeap(buffer); #endif if (buffer && (type & BFRALLOC_CLEAR)) @@ -1268,6 +1273,8 @@ uint8_t perlin8(uint16_t x, uint16_t y, uint16_t z) { return (((perlin3D_raw((uint32_t)x << 8, (uint32_t)y << 8, (uint32_t)z << 8, true) * 2015) >> 10) + 33168) >> 8; //scale to 16 bit, offset, then scale to 8bit } +#if !defined(ARDUINO_ARCH_ESP32) || (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(6, 0, 0)) // ToDO: validate behaviour in V5 + // Platform-agnostic SHA1 computation from String input String computeSHA1(const String& input) { #ifdef ESP8266 @@ -1277,11 +1284,19 @@ String computeSHA1(const String& input) { unsigned char shaResult[20]; // SHA1 produces 20 bytes mbedtls_sha1_context ctx; +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) mbedtls_sha1_init(&ctx); mbedtls_sha1_starts_ret(&ctx); mbedtls_sha1_update_ret(&ctx, (const unsigned char*)input.c_str(), input.length()); mbedtls_sha1_finish_ret(&ctx, shaResult); mbedtls_sha1_free(&ctx); +#else + mbedtls_sha1_init(&ctx); + mbedtls_sha1_starts(&ctx); + mbedtls_sha1_update(&ctx, (const unsigned char*)input.c_str(), input.length()); + mbedtls_sha1_finish(&ctx, shaResult); + mbedtls_sha1_free(&ctx); +#endif // Convert to hexadecimal string char hexString[41]; @@ -1295,9 +1310,12 @@ String computeSHA1(const String& input) { } #ifdef ESP32 +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) +#include "esp_adc_cal.h" // deprecated API +//#include "esp_adc/adc_cali.h" // new API +//#include "esp_adc/adc_cali_scheme.h" // new API +#else #include "esp_adc_cal.h" -#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4,4,7) // backwards compatibility patch - #define ADC_ATTEN_DB_12 ADC_ATTEN_DB_11 #endif String generateDeviceFingerprint() { uint32_t fp[2] = {0, 0}; // create 64 bit fingerprint @@ -1305,10 +1323,16 @@ String generateDeviceFingerprint() { esp_chip_info(&chip_info); esp_efuse_mac_get_default((uint8_t*)fp); fp[1] ^= ESP.getFlashChipSize(); +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) fp[0] ^= chip_info.full_revision | (chip_info.model << 16); - // mix in ADC calibration data: +#else + fp[0] ^= chip_info.revision | (chip_info.model << 16); +#endif + +#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 + // mix in ADC calibration data - legacy adc calibration API is not supported on new MCUs (-C6, -C61, -P4) esp_adc_cal_characteristics_t ch; - #if SOC_ADC_MAX_BITWIDTH == 13 // S2 has 13 bit ADC + #if (SOC_ADC_MAX_BITWIDTH == 13) || (CONFIG_SOC_ADC_RTC_MAX_BITWIDTH == 13) // S2 has 13 bit ADC constexpr auto myBIT_WIDTH = ADC_WIDTH_BIT_13; #else constexpr auto myBIT_WIDTH = ADC_WIDTH_BIT_12; @@ -1326,6 +1350,11 @@ String generateDeviceFingerprint() { fp[1] ^= ch.high_curve[i]; } } +#else + // some extra salt, instead of ADC calibration + fp[0] ^= chip_info.features | chip_info.cores << 16; + fp[1] ^= ESP.getFlashSourceFrequencyMHz() | ESP.getFlashClockDivider() << 8 ; +#endif char fp_string[17]; // 16 hex chars + null terminator sprintf(fp_string, "%08X%08X", fp[1], fp[0]); return String(fp_string); @@ -1363,4 +1392,4 @@ String getDeviceId() { return cachedDeviceId; } - +#endif // V5/V6 workaround diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 24b385cb33..6261864922 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -1,6 +1,13 @@ #define WLED_DEFINE_GLOBAL_VARS //only in one source file, wled.cpp! #include "wled.h" #include "wled_ethernet.h" +#ifdef ARDUINO_ARCH_ESP32 +#include "esp_efuse.h" +#include "esp_chip_info.h" +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) +#include "esp_mac.h" +#endif +#endif #include "ota_update.h" #ifdef WLED_ENABLE_AOTA #define NO_OTA_PORT @@ -12,6 +19,10 @@ #include "soc/rtc_cntl_reg.h" #endif +#if defined(CONFIG_IDF_TARGET_ESP32P4) +#include "WiFi.h" // WiFi library for network connectivity +#include "ESP_HostedOTA.h" // ESP-Hosted OTA update functionality +#endif extern "C" void usePWMFixedNMI(); /* @@ -47,7 +58,11 @@ void WLED::loop() unsigned long loopMillis = millis(); size_t loopDelay = loopMillis - lastRun; if (lastRun == 0) loopDelay=0; // startup - don't have valid data from last run. - if (loopDelay > 2) DEBUG_PRINTF_P(PSTR("Loop delayed more than %ums.\n"), loopDelay); + #if defined(ESP8266) || (SOC_CPU_CORES_NUM < 2) + if (loopDelay > 4) DEBUG_PRINTF_P(PSTR("Loop delayed more than %ums.\n"), loopDelay); // be a bit more relaxed on single-core MCUs + #else + if (loopDelay > 2) DEBUG_PRINTF_P(PSTR("Loop delayed more than %ums.\n"), loopDelay); + #endif static unsigned long maxLoopMillis = 0; static size_t avgLoopMillis = 0; static unsigned long maxUsermodMillis = 0; @@ -110,7 +125,7 @@ void WLED::loop() { if (apActive) dnsServer.processNextRequest(); #ifdef WLED_ENABLE_AOTA - if (Network.isConnected() && aOtaEnabled && !otaLock && correctPIN) ArduinoOTA.handle(); + if (WLEDNetwork.isConnected() && aOtaEnabled && !otaLock && correctPIN) ArduinoOTA.handle(); #endif handleNightlight(); yield(); @@ -178,7 +193,7 @@ void WLED::loop() // calling getContiguousFreeHeap() during led update causes glitches on C3 // this can (probably) be removed once RMT driver for C3 is fixed unsigned t0 = millis(); - while (strip.isUpdating() && (millis() - t0 < 150)) delay(1); // be nice, but not too nice. Waits up to 150ms + while (strip.isUpdating() && (millis() - t0 < 15)) delay(1); // be nice, but not too nice. Waits up to 15ms #endif uint32_t heap = getContiguousFreeHeap(); // ESP32 family needs ~10k of contiguous free heap for UI to work properly #endif @@ -281,11 +296,12 @@ void WLED::loop() DEBUG_PRINTF_P(PSTR("PSRAM: Free: %7u bytes | Largest block: %6u bytes\n"), psram_free, psram_largest); #endif #if defined(CONFIG_IDF_TARGET_ESP32) - // 32-bit DRAM (not byte accessible, only available on ESP32) + // 32-bit DRAM aka IRAM (not byte accessible, only available on ESP32) size_t dram32_free = heap_caps_get_free_size(MALLOC_CAP_32BIT | MALLOC_CAP_INTERNAL) - dram_free; // returns all 32bit DRAM, subtract 8bit DRAM //size_t dram32_largest = heap_caps_get_largest_free_block(MALLOC_CAP_32BIT | MALLOC_CAP_INTERNAL); // returns largest DRAM block -> not useful DEBUG_PRINTF_P(PSTR("DRAM 32-bit: Free: %7u bytes | Largest block: N/A\n"), dram32_free); - #else + #endif + #if defined(WLED_HAVE_RTC_MEMORY_HEAP) // Fast RTC Memory (not available on ESP32) size_t rtcram_free = heap_caps_get_free_size(MALLOC_CAP_RTCRAM); size_t rtcram_largest = heap_caps_get_largest_free_block(MALLOC_CAP_RTCRAM); @@ -312,7 +328,7 @@ void WLED::loop() lastWifiState = WiFi.status(); DEBUG_PRINTF_P(PSTR("State time: %lu\n"), wifiStateChangedTime); DEBUG_PRINTF_P(PSTR("NTP last sync: %lu\n"), ntpLastSyncTime); - DEBUG_PRINTF_P(PSTR("Client IP: %u.%u.%u.%u\n"), Network.localIP()[0], Network.localIP()[1], Network.localIP()[2], Network.localIP()[3]); + DEBUG_PRINTF_P(PSTR("Client IP: %u.%u.%u.%u\n"), WLEDNetwork.localIP()[0], WLEDNetwork.localIP()[1], WLEDNetwork.localIP()[2], WLEDNetwork.localIP()[3]); if (loops > 0) { // avoid division by zero DEBUG_PRINTF_P(PSTR("Loops/sec: %u\n"), loops / 30); DEBUG_PRINTF_P(PSTR("Loop time[ms]: %u/%lu\n"), avgLoopMillis/loops, maxLoopMillis); @@ -369,10 +385,8 @@ void WLED::setup() #endif #ifdef ARDUINO_ARCH_ESP32 - gpio_pulldown_en((gpio_num_t)hardwareRX); delay(1); // suppress noise in case RX pin is floating (at low noise energy) - see issue #3128 - // note: can not use pinMode(): it routes GPIO through the GPIO matrix and detaches UART0 RX + pinMode(hardwareRX, INPUT_PULLDOWN); delay(1); // suppress noise in case RX pin is floating (at low noise energy) - see issue #3128 #endif - #ifdef WLED_BOOTUPDELAY delay(WLED_BOOTUPDELAY); // delay to let voltage stabilize, helps with boot issues on some setups #endif @@ -381,7 +395,7 @@ void WLED::setup() Serial.setTimeout(50); // this causes troubles on new MCUs that have a "virtual" USB Serial (HWCDC) #else #endif - #if defined(WLED_DEBUG) && defined(ARDUINO_ARCH_ESP32) && (defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || ARDUINO_USB_CDC_ON_BOOT) + #if defined(WLED_DEBUG) && defined(ARDUINO_ARCH_ESP32) && ARDUINO_USB_CDC_ON_BOOT delay(2500); // allow CDC USB serial to initialise #endif #if !defined(WLED_DEBUG) && defined(ARDUINO_ARCH_ESP32) && !defined(WLED_DEBUG_HOST) && ARDUINO_USB_CDC_ON_BOOT @@ -391,13 +405,13 @@ void WLED::setup() DEBUG_PRINTF_P(PSTR("---WLED %s %u INIT---\n"), versionString, VERSION); DEBUG_PRINTLN(); #ifdef ARDUINO_ARCH_ESP32 - DEBUG_PRINTF_P(PSTR("esp32 %s\n"), ESP.getSdkVersion()); + DEBUG_PRINTF_P(PSTR("esp-idf %s\n"), ESP.getSdkVersion()); #if defined(ESP_ARDUINO_VERSION) DEBUG_PRINTF_P(PSTR("arduino-esp32 v%d.%d.%d\n"), int(ESP_ARDUINO_VERSION_MAJOR), int(ESP_ARDUINO_VERSION_MINOR), int(ESP_ARDUINO_VERSION_PATCH)); // available since v2.0.0 #else DEBUG_PRINTLN(F("arduino-esp32 v1.0.x\n")); // we can't say in more detail. #endif - DEBUG_PRINTF_P(PSTR("CPU: %s rev.%d, %d core(s), %d MHz.\n"), ESP.getChipModel(), (int)ESP.getChipRevision(), ESP.getChipCores(), ESP.getCpuFreqMHz()); + DEBUG_PRINTF_P(PSTR("\nCPU: %s rev.%d, %d core(s), %d MHz.\n"), ESP.getChipModel(), (int)ESP.getChipRevision(), ESP.getChipCores(), ESP.getCpuFreqMHz()); DEBUG_PRINTF_P(PSTR("FLASH: %d MB, Mode %d "), (ESP.getFlashChipSize()/1024)/1024, (int)ESP.getFlashChipMode()); #ifdef WLED_DEBUG switch (ESP.getFlashChipMode()) { @@ -421,7 +435,7 @@ void WLED::setup() DEBUG_PRINTF_P(PSTR("esp8266 @ %u MHz.\nCore: %s\n"), ESP.getCpuFreqMHz(), ESP.getCoreVersion()); DEBUG_PRINTF_P(PSTR("FLASH: %u MB\n"), (ESP.getFlashChipSize()/1024)/1024); #endif - DEBUG_PRINTF_P(PSTR("heap %u\n"), getFreeHeapSize()); + DEBUG_PRINTF_P(PSTR("\nheap %u\n"), getFreeHeapSize()); #if defined(BOARD_HAS_PSRAM) // if JSON buffer allocation fails requestJsonBufferLock() will always return false preventing crashes @@ -434,7 +448,7 @@ void WLED::setup() } #endif -#if defined(ARDUINO_ARCH_ESP32) +#if defined(ARDUINO_ARCH_ESP32) && !defined(WLED_ETHERNET_ONLY_BUILD) DEBUG_PRINTF_P(PSTR("TX power: %d/%d\n"), WiFi.getTxPower(), txPower); #endif @@ -468,13 +482,42 @@ void WLED::setup() updateFSInfo(); // generate module IDs must be done before AP setup +#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_ETHERNET_ONLY_BUILD) + { + uint8_t mac[6] = {0}; + esp_read_mac(mac, ESP_MAC_ETH); + char buf[13]; + sprintf(buf, "%02x%02x%02x%02x%02x%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + escapedMac = buf; + } +#else escapedMac = WiFi.macAddress(); escapedMac.replace(":", ""); escapedMac.toLowerCase(); +#ifdef ARDUINO_ARCH_ESP32 + // WiFi.macAddress() may return all zeros if the WiFi netif is not yet created. + // Fall back to reading the base MAC directly from eFuse. + if (escapedMac == "000000000000") { + uint8_t mac[6] = {0}; + #if defined(CONFIG_IDF_TARGET_ESP32P4) // P4 does not have on-chip WIFI, use ethernet MAC + esp_read_mac(mac, ESP_MAC_ETH); + #else + esp_read_mac(mac, ESP_MAC_WIFI_STA); + #endif + char buf[13]; + sprintf(buf, "%02x%02x%02x%02x%02x%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + escapedMac = buf; + } +#endif +#endif WLED_SET_AP_SSID(); // otherwise it is empty on first boot until config is saved multiWiFi.push_back(WiFiConfig(CLIENT_SSID,CLIENT_PASS)); // initialise vector with default WiFi +#ifdef WLED_ETHERNET_ONLY_BUILD + WiFi.onEvent(WiFiEvent); +#endif + if(!verifyConfig()) { if(!restoreConfig()) { resetConfig(); @@ -503,12 +546,7 @@ void WLED::setup() if (needsCfgSave) serializeConfigToFS(); // usermods required new parameters; need to wait for strip to be initialised #4752 - if (bootPreset > 0) { - handlePresets(); // handle boot preset - handlePlaylist(); // handle playlist if preset queued one - handlePresets(); // handle presets again to give a chance for anything queued by the boot preset or playlist - } - +#ifndef WLED_ETHERNET_ONLY_BUILD if (strcmp(multiWiFi[0].clientSSID, DEFAULT_CLIENT_SSID) == 0 && !configBackupExists()) showWelcomePage = true; @@ -522,9 +560,19 @@ void WLED::setup() #else WiFi.persistent(false); // on ESP8266 using NVM for wifi config has no benefit of faster connection #endif + WiFi.onEvent(WiFiEvent); WiFi.mode(WIFI_STA); // enable scanning + +#if defined(ARDUINO_ARCH_ESP32) && (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 2)) + // WiFi.setBandMode(WIFI_BAND_MODE_AUTO) can also be used without SOC_WIFI_SUPPORT_5G + if (!WiFi.setBandMode(WIFI_BAND_MODE_AUTO)) { // WIFI_BAND_MODE_AUTO = 5GHz+2.4GHz; WIFI_BAND_MODE_5G_ONLY, WIFI_BAND_MODE_2G_ONLY + DEBUG_PRINTLN(F("setup(): Wifi band configuration failed!\n")); + } +#endif + findWiFi(true); // start scanning for available WiFi-s +#endif // all GPIOs are allocated at this point serialCanRX = !PinManager::isPinAllocated(hardwareRX); // Serial RX pin (GPIO 3 on ESP32 and ESP8266) @@ -590,7 +638,9 @@ void WLED::setup() #endif #if defined(ARDUINO_ARCH_ESP32) && defined(LWIP_IPV6) +#if ESP_IDF_VERSION_MAJOR < 5 // ToDO: clarify if esp-idf v5.x still needs this patch installIPv6RABlocker(); // Work around unsolicited RA overwriting IPv4 DNS servers +#endif #endif #if WLED_WATCHDOG_TIMEOUT > 0 @@ -645,6 +695,10 @@ void WLED::beginStrip() void WLED::initAP(bool resetAP) { +#ifdef WLED_ETHERNET_ONLY_BUILD + return; +#endif + if (apBehavior == AP_BEHAVIOR_BUTTON_ONLY && !resetAP) return; @@ -654,10 +708,19 @@ void WLED::initAP(bool resetAP) } DEBUG_PRINT(F("Opening access point ")); DEBUG_PRINTLN(apSSID); + + #ifdef ARDUINO_ARCH_ESP32 + // reset band mode to "auto" before starting AP + #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 2) + if (!WiFi.setBandMode(WIFI_BAND_MODE_AUTO)) { + DEBUG_PRINTLN(F("initAP(): Wifi band configuration failed!\n")); + } + #endif + #endif + WiFi.softAPConfig(IPAddress(4, 3, 2, 1), IPAddress(4, 3, 2, 1), IPAddress(255, 255, 255, 0)); WiFi.softAP(apSSID, apPass, apChannel, apHide); #ifdef ARDUINO_ARCH_ESP32 - DEBUG_PRINT(F("access point maxTxPower set to ")); DEBUG_PRINTLN(txPower); WiFi.setTxPower(wifi_power_t(txPower)); #endif @@ -690,6 +753,12 @@ void WLED::initConnection() ws.onEvent(wsEvent); #endif +#ifdef WLED_ETHERNET_ONLY_BUILD + initEthernet(); + lastReconnectAttempt = millis(); + return; +#endif + #ifndef WLED_DISABLE_ESPNOW if (statusESPNow == ESP_NOW_STATE_ON) { DEBUG_PRINTLN(F("ESP-NOW stopping.")); @@ -698,7 +767,6 @@ void WLED::initConnection() } #endif - DEBUG_PRINTLN(F("WiFi disconnect.")); WiFi.disconnect(true); // close old connections delay(5); // wait for hardware to be ready #ifdef ESP8266 @@ -711,17 +779,22 @@ void WLED::initConnection() #ifdef ARDUINO_ARCH_ESP32 // Reset mode to NULL to force a full STA mode transition, so that WiFi.mode(WIFI_STA) below actually applies the hostname (and TX power, etc.). // This is required on reconnects when mode is already WIFI_STA. - DEBUG_PRINTLN(F("WiFi mode_null: driver teardown / re-init.")); WiFi.mode(WIFI_MODE_NULL); apActive = false; // the AP is physically torn down by WIFI_MODE_NULL delay(5); // give the WiFi stack time to complete the mode transition WiFi.setHostname(hostname); #endif - if (multiWiFi[selectedWiFi].staticIP != 0U && multiWiFi[selectedWiFi].staticGW != 0U) { - WiFi.config(multiWiFi[selectedWiFi].staticIP, multiWiFi[selectedWiFi].staticGW, multiWiFi[selectedWiFi].staticSN, dnsAddress); - } else { + if (multiWiFi.empty()) { // guard: handle empty WiFi list safely WiFi.config(IPAddress((uint32_t)0), IPAddress((uint32_t)0), IPAddress((uint32_t)0)); + } else { + if (selectedWiFi >= multiWiFi.size()) selectedWiFi = 0; // guard: ensure valid index + if (multiWiFi[selectedWiFi].staticIP != IPAddress((uint32_t)0) && + multiWiFi[selectedWiFi].staticGW != IPAddress((uint32_t)0)) { // guard: compare as IPAddress to avoid pointer overload + WiFi.config(multiWiFi[selectedWiFi].staticIP, multiWiFi[selectedWiFi].staticGW, multiWiFi[selectedWiFi].staticSN, dnsAddress); + } else { + WiFi.config(IPAddress((uint32_t)0), IPAddress((uint32_t)0), IPAddress((uint32_t)0)); + } } lastReconnectAttempt = millis(); @@ -737,12 +810,17 @@ void WLED::initConnection() DEBUG_PRINTLN(F("Access point disabled (init).")); WiFi.softAPdisconnect(true); WiFi.mode(WIFI_STA); + #if defined(SOC_WIFI_SUPPORT_5G) && (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 2)) + if (!WiFi.setBandMode((wifi_band_mode_t)wifiBandMode)) { + DEBUG_PRINTLN(F("initConnection(): WiFi band configuration failed!")); + } + #endif } } if (WLED_WIFI_CONFIGURED) { showWelcomePage = false; - + DEBUG_PRINTF_P(PSTR("Connecting to %s...\n"), multiWiFi[selectedWiFi].clientSSID); #ifdef WLED_ENABLE_WPA_ENTERPRISE @@ -795,12 +873,9 @@ void WLED::initConnection() #endif // WLED_ENABLE_WPA_ENTERPRISE #ifdef ARDUINO_ARCH_ESP32 - DEBUG_PRINT(F("WiFi maxTxPower set to ")); DEBUG_PRINT(txPower); - DEBUG_PRINT(F("; WiFi sleep ")); DEBUG_PRINTLN(noWifiSleep ? F("disabled."):F("enabled.")); WiFi.setTxPower(wifi_power_t(txPower)); WiFi.setSleep(!noWifiSleep); #else // ESP8266 accepts a hostname set after WiFi interface initialization - DEBUG_PRINT(F("WiFi sleep ")); DEBUG_PRINTLN(noWifiSleep ? F("disabled."):F("enabled.")); wifi_set_sleep_type((noWifiSleep) ? NONE_SLEEP_T : MODEM_SLEEP_T); WiFi.hostname(hostname); #endif @@ -831,7 +906,7 @@ void WLED::initInterfaces() DEBUG_PRINTLN(F("Init STA interfaces")); #ifndef WLED_DISABLE_HUESYNC - IPAddress ipAddress = Network.localIP(); + IPAddress ipAddress = WLEDNetwork.localIP(); if (hueIP[0] == 0) { hueIP[0] = ipAddress[0]; hueIP[1] = ipAddress[1]; @@ -888,6 +963,34 @@ void WLED::handleConnection() #ifdef WLED_DEBUG const unsigned long nowS = now/1000; #endif + +#ifdef WLED_ETHERNET_ONLY_BUILD + if (lastReconnectAttempt == 0 || forceReconnect) { + DEBUG_PRINTF_P(PSTR("Ethernet-only connect or forced reconnect (@ %lus).\n"), nowS); + initEthernet(); + lastReconnectAttempt = now; + forceReconnect = false; + } + + if (WLEDNetwork.isConnected()) { + if (!interfacesInited) { + DEBUG_PRINTLN(); + DEBUG_PRINT(F("Connected! IP address: ")); + DEBUG_PRINTLN(WLEDNetwork.localIP()); + initInterfaces(); + userConnected(); + UsermodManager::connected(); + lastMqttReconnectAttempt = 0; + } + wasConnected = true; + } else if (interfacesInited || wasConnected) { + DEBUG_PRINTLN(F("Ethernet disconnected!")); + interfacesInited = false; + wasConnected = false; + } + return; +#endif + const bool wifiConfigured = WLED_WIFI_CONFIGURED; // ignore connection handling if WiFi is configured and scan still running @@ -917,7 +1020,7 @@ void WLED::handleConnection() if (stac != stacO) { stacO = stac; DEBUG_PRINTF_P(PSTR("Connected AP clients: %d\n"), (int)stac); - if (!Network.isConnected() && wifiConfigured) { // trying to connect, but not connected + if (!WLEDNetwork.isConnected() && wifiConfigured) { // trying to connect, but not connected if (stac) WiFi.disconnect(); // disable search so that AP can work else @@ -926,7 +1029,7 @@ void WLED::handleConnection() } } - if (!Network.isConnected()) { + if (!WLEDNetwork.isConnected()) { if (interfacesInited) { if (scanDone && multiWiFi.size() > 1) { DEBUG_PRINTLN(F("WiFi scan initiated on disconnect.")); @@ -970,10 +1073,37 @@ void WLED::handleConnection() } else if (!interfacesInited) { //newly connected DEBUG_PRINTLN(); DEBUG_PRINT(F("Connected! IP address: ")); - DEBUG_PRINTLN(Network.localIP()); + DEBUG_PRINTLN(WLEDNetwork.localIP()); + #ifdef ARDUINO_ARCH_ESP32 esp_wifi_set_storage(WIFI_STORAGE_RAM); // disable further updates of NVM credentials to prevent wear on flash (same as WiFi.persistent(false) but updates immediately, arduino wifi deficiency workaround) #endif + + DEBUG_PRINT(F("Channel: ")); DEBUG_PRINT(WiFi.channel()); + #if defined(ARDUINO_ARCH_ESP32) && SOC_WIFI_SUPPORT_5G + auto wifiBand = WiFi.getBand(); + DEBUG_PRINT(wifiBand == WIFI_BAND_2G ? F(" (2.4GHz)") : (wifiBand == WIFI_BAND_5G ? F(" (5GHz)"): F(" (other)"))); + #else + DEBUG_PRINT(F(" (2.4GHz)")); + #endif + DEBUG_PRINTLN(); + + #if defined(CONFIG_IDF_TARGET_ESP32P4) && !defined(WLED_ETHERNET_ONLY_BUILD) + // directly after connection, attempt to update the ESP-Hosted Wi-Fi co-processor firmware + if (!apActive && !improvActive) { + // This function will: + // - Check if ESP-Hosted is initialized + // - Verify if an update is available + // - Download and install the firmware update if needed + if (updateEspHostedSlave()) { + // Restart the host ESP32 after successful update + // This is currently required to properly activate the new firmware on the ESP-Hosted co-processor + // ESP.restart(); + doReboot = true; // schedule reboot + } + } + #endif + if (improvActive) { if (improvError == 3) sendImprovStateResponse(0x00, true); sendImprovStateResponse(0x04); @@ -995,7 +1125,7 @@ void WLED::handleConnection() } // If status LED pin is allocated for other uses, does nothing -// else blink at 1Hz when Network.isConnected() is false (no WiFi, ?? no Ethernet ??) +// else blink at 1Hz when WLEDNetwork.isConnected() is false (no WiFi, ?? no Ethernet ??) // else blink at 2Hz when MQTT is enabled but not connected // else turn the status LED off #if defined(STATUSLED) @@ -1009,7 +1139,7 @@ void WLED::handleStatusLED() } #endif - if (Network.isConnected()) { + if (WLEDNetwork.isConnected()) { c = RGBW32(0,255,0,0); ledStatusType = 2; } else if (WLED_MQTT_CONNECTED) { diff --git a/wled00/wled.h b/wled00/wled.h index eb2df1875e..6374745ef4 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -75,6 +75,18 @@ // Library inclusions. #include + +// buildenv sanity check +#if !defined(ESP32) && !defined(ESP8266) +#error neither ESP32 nor ESP8266 defined. Please fix your build environment. +#endif +#if defined(ESP8266) && (defined(ARDUINO_ARCH_ESP32) || defined(ESP32)) +#error both ESP8266 and ESP32/ARDUINO_ARCH_ESP32 defined. Please fix your build environment. +#endif +#if (defined(ARDUINO_ARCH_ESP32) && !defined(ESP32)) || (defined(ESP32) && !defined(ARDUINO_ARCH_ESP32)) +#error either ESP32 or ARDUINO_ARCH_ESP32 not defined. Please fix your build environment. +#endif + #ifdef ESP8266 #include #ifdef WLED_ENABLE_WPA_ENTERPRISE @@ -124,6 +136,8 @@ #include "my_config.h" #endif +#include "wled_boards.h" // pull in board-specific capability defines + #include #include #include @@ -142,7 +156,9 @@ #endif #ifdef WLED_ENABLE_DMX - #if defined(ESP8266) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S2) + #if defined(CONFIG_IDF_TARGET_ESP32P4) + #error "DMX output is not supported on ESP32-P4 (esp_dmx library excluded)" + #elif defined(ESP8266) || defined(CONFIG_IDF_TARGET_ESP32C3)|| defined(CONFIG_IDF_TARGET_ESP32S2) #include "src/dependencies/dmx/ESPDMX.h" #else //ESP32 #include "src/dependencies/dmx/SparkFunDMX.h" @@ -315,7 +331,9 @@ WLED_GLOBAL bool rlyOpenDrain _INIT(RLYODRAIN); #define IRTYPE 0 #endif -#if defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S2) || (defined(RX) && defined(TX)) +// RX and TX: use "default" pins for 8266 and classic esp32 +// except when arduino-esp32 has explicitly defined RX and TX (some arduino variants don't define RX and TX) +#if defined(ARDUINO_ARCH_ESP32) && (!defined(CONFIG_IDF_TARGET_ESP32) || (defined(RX) && defined(TX))) // use RX/TX as set by the framework - these boards do _not_ have RX=3 and TX=1 constexpr uint8_t hardwareRX = RX; constexpr uint8_t hardwareTX = TX; @@ -375,8 +393,8 @@ WLED_GLOBAL bool noWifiSleep _INIT(false); #endif WLED_GLOBAL bool force802_3g _INIT(false); #endif // WLED_SAVE_RAM -#ifdef ARDUINO_ARCH_ESP32 - #if defined(LOLIN_WIFI_FIX) && (defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3)) +#if defined(ARDUINO_ARCH_ESP32) + #if defined(LOLIN_WIFI_FIX) // extend this fix to all esp32 boards WLED_GLOBAL uint8_t txPower _INIT(WIFI_POWER_8_5dBm); #else WLED_GLOBAL uint8_t txPower _INIT(WIFI_POWER_19_5dBm); @@ -384,6 +402,10 @@ WLED_GLOBAL uint8_t txPower _INIT(WIFI_POWER_19_5dBm); #endif #define WLED_WIFI_CONFIGURED isWiFiConfigured() +#if defined(WLED_USE_ETHERNET) && defined(WLED_ETHERNET_ONLY) + #define WLED_ETHERNET_ONLY_BUILD +#endif + #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) #ifdef WLED_ETH_DEFAULT // default ethernet board type if specified WLED_GLOBAL int ethernetType _INIT(WLED_ETH_DEFAULT); // ethernet board type @@ -454,7 +476,9 @@ WLED_GLOBAL bool arlsDisableGammaCorrection _INIT(true); // activate if WLED_GLOBAL bool arlsForceMaxBri _INIT(false); // enable to force max brightness if source has very dark colors that would be black #ifdef WLED_ENABLE_DMX - #if defined(ESP8266) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S2) + #if defined(CONFIG_IDF_TARGET_ESP32P4) + #error "DMX output is not supported on ESP32-P4 (esp_dmx library excluded)" + #elif defined(ESP8266) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S2) WLED_GLOBAL DMXESPSerial dmx; #else //ESP32 WLED_GLOBAL SparkFunDMX dmx; diff --git a/wled00/wled_boards.h b/wled00/wled_boards.h new file mode 100644 index 0000000000..190797304e --- /dev/null +++ b/wled00/wled_boards.h @@ -0,0 +1,119 @@ +/* + WLED board capabilities: uses CONFIG_IDF_TARGET_... to extract board capability flags. + You can still use CONFIG_IDF_TARGET_ in the source code; this file provides shortcuts for repeating capability checks. +*/ +#pragma once + +#ifndef WLED_BOARDS_H +#define WLED_BOARDS_H +#include "NodeStruct.h" // to get generic NODE_TYPE_IDs + +/* + * Structure: the below part uses isolated "#if defined()" instead of a chain of if ... elif ... else + * so that the constant WLED_BOARD will be set exactly once unless there are conflicting build_flags. + * In case that several blocks are active, it causes a compiler error to easily spot the problem + * "error: redefinition of 'constexpr const unsigned int WLED_BOARD'" + */ + +/* TODO: add + WLED_HAVE_TOUCH (for button.cpp) + WLED_HAVE_I2S0_LEDS (for bus_wrapper.h) + WLED_HAVE_I2S1_LEDS (for bus_wrapper.h) + (find a name) // On ESP32-C3 only the first 2 RMT channels are usable for transmitting (bus_wrapper.h) + (find a name) // ESP32, S3, P4 can use SparkFunDMX (wled.h, dmx_output.cpp) + WLED_ALLOW_LOLIN_WIFI_FIX // (wled.h) + */ + + +#if defined(ESP8266) +// Capabilities of good-old 8266 + // has no FPU + // bitshift with rounding is faster than integer division + // no byte-accessible fast RTC memory (newer esp32 variants only) + // no parallel I2S LEDs driver +constexpr unsigned WLED_BOARD = NODE_TYPE_ID_ESP8266; + + // sanity check for esp32 + #if defined(ARDUINO_ARCH_ESP32) || defined(ESP32) + #error "ARDUINO_ARCH_ESP32 or ESP32 is defined together with ESP8266. Please fix your buildenv." + #endif +#endif + +#if CONFIG_IDF_TARGET_ESP32 +// Capabilities of classic ESP32 and classic PICO-D4/D2/D3 + #define WLED_HAVE_FAST_FLOAT 1 // has an FPU for fast floating point (single precision) + #define WLED_HAVE_FAST_int_DIVIDE 1 // integer division is fast (no need to use bitshifts with rounding instead of integer division) + // no byte-accessible fast RTC memory (newer esp32 variants only) + #define WLED_HAVE_IRAM_32BIT_HEAP 1 // only classic ESP32 has "32bit accessible only" aka IRAM type heap + + #define WLED_HAS_PARALLEL_I2S 1 // classic esp32 has I2S parallel leds driver (NeoPixelBus) + + constexpr unsigned WLED_BOARD = NODE_TYPE_ID_ESP32; + // sanity checks + #if (SOC_CPU_CORES_NUM < 2) + #error "ESP32 single-core is not supported." + #endif +#endif + +#if CONFIG_IDF_TARGET_ESP32S3 +// Capabilities of ESP32-S3 + #define WLED_HAVE_FAST_FLOAT 1 // has an FPU for fast floating point (single precision) + #define WLED_HAVE_FAST_int_DIVIDE 1 // integer division is fast (no need to use bitshifts with rounding instead of integer division) + #define WLED_HAVE_RTC_MEMORY_HEAP 1 // has byte-accessible fast RTC memory that can be used as heap + // no 4byte-accessible IRAM heap + + #define WLED_HAS_PARALLEL_I2S 1 // esp32-S3 supports I2S parallel leds driver (NeoPixelBus) + + constexpr unsigned WLED_BOARD = NODE_TYPE_ID_ESP32S3; + // sanity checks + #if (SOC_CPU_CORES_NUM < 2) + #error "ESP32-S3 single-core is not supported." + #endif +#endif + +#if CONFIG_IDF_TARGET_ESP32S2 +// Capabilities of ESP32-S2 + // has no FPU + #define WLED_HAVE_FAST_int_DIVIDE 1 // integer division is fast (no need to use bitshifts with rounding instead of integer division) + #define WLED_HAVE_RTC_MEMORY_HEAP 1 // has byte-accessible fast RTC memory that can be used as heap + // no 4byte-accessible IRAM heap + + #define WLED_HAS_PARALLEL_I2S 1 // esp32-S2 supports I2S parallel leds driver (NeoPixelBus) + + constexpr unsigned WLED_BOARD = NODE_TYPE_ID_ESP32S2; +#endif + +#if CONFIG_IDF_TARGET_ESP32C3 +// Capabilities of ESP32-C3 + // has no FPU + // bitshift with rounding is faster than integer division + #define WLED_HAVE_RTC_MEMORY_HEAP 1 // has byte-accessible fast RTC memory that can be used as heap + // no 4byte-accessible IRAM heap + // no parallel I2S LEDs driver + + constexpr unsigned WLED_BOARD = NODE_TYPE_ID_ESP32C3; +#endif + +#if CONFIG_IDF_TARGET_ESP32P4 +// Capabilities of ESP32-P4 + #define WLED_HAVE_FAST_FLOAT 1 // has an FPU for fast floating point (single precision) + // TBC: is bitshift with rounding is faster than integer division ? + #define WLED_HAVE_FAST_int_DIVIDE 1 // integer division is fast (no need to use bitshifts with rounding instead of integer division) + #define WLED_HAVE_RTC_MEMORY_HEAP 1 // TBC: does it have byte-accessible fast RTC memory that can be used as heap ? + // no 4byte-accessible IRAM heap + // no parallel I2S LEDs driver + #define WLED_HAS_PARALLEL_PARLIO 1 // (unsupported) P4 allows parallel leds driving with PARLIO unit + + constexpr unsigned WLED_BOARD = NODE_TYPE_ID_ESP32P4; + + // sanity checks + #if (SOC_CPU_CORES_NUM < 2) + #error "ESP32-P4 single-core is not supported." + #endif +#endif + + +// sanity check: the constexpr assignment below will fail when WLED_BOARD is not set by the previous blocks +constexpr unsigned wled_boards_sanity_check = 0 + WLED_BOARD; + +#endif // WLED_BOARDS_H diff --git a/wled00/wled_ethernet.h b/wled00/wled_ethernet.h index 6b8f0ba56f..7e6aaaefef 100644 --- a/wled00/wled_ethernet.h +++ b/wled00/wled_ethernet.h @@ -30,6 +30,8 @@ extern const ethernet_settings ethernetBoards[]; #define WLED_ETH_RSVD_PINS_COUNT 6 extern const managed_pin_type esp32_nonconfigurable_ethernet_pins[WLED_ETH_RSVD_PINS_COUNT]; + +managed_pin_type ethernetClockPin(const ethernet_settings& settings); #endif -#endif \ No newline at end of file +#endif diff --git a/wled00/wled_metadata.cpp b/wled00/wled_metadata.cpp index 4b0e304bbc..46dad2cf95 100644 --- a/wled00/wled_metadata.cpp +++ b/wled00/wled_metadata.cpp @@ -4,7 +4,8 @@ #ifndef WLED_VERSION #warning WLED_VERSION was not set - using default value of 'dev' - #define WLED_VERSION dev + //#define WLED_VERSION dev + #define WLED_VERSION 17.0.0-devV5 // ToDO: remove once that set_metadata.py is fixed #endif #ifndef WLED_RELEASE_NAME #warning WLED_RELEASE_NAME was not set - using default value of 'Custom'