[ESP32-P4] Fix WiFi/Eth issues on ESP32-P4 + optimize memory allocations

This commit is contained in:
TD-er
2025-10-25 20:12:01 +02:00
parent 497b15e514
commit 6f61cba2cd
33 changed files with 550 additions and 145 deletions
+1
View File
@@ -6,6 +6,7 @@
],
"f_cpu": "360000000L",
"f_flash": "80000000L",
"f_psram": "200000000L",
"flash_mode": "qio",
"mcu": "esp32p4",
"variant": "esp32p4",
@@ -17,9 +17,10 @@ struct NetworkDriverStruct
{
NetworkDriverStruct() = default;
bool onlySingleInstance = true;
bool alwaysPresent = false;
networkIndex_t fixedNetworkIndex = INVALID_NETWORK_INDEX;
bool onlySingleInstance = true;
bool alwaysPresent = false;
bool enabledOnFactoryReset = false;
networkIndex_t fixedNetworkIndex = INVALID_NETWORK_INDEX;
};
@@ -21,7 +21,6 @@ namespace net {
NetworkSettingsStruct::NetworkSettingsStruct()
{
memset(this, 0, sizeof(NetworkSettingsStruct));
}
void NetworkSettingsStruct::reset() {
@@ -37,5 +36,12 @@ void NetworkSettingsStruct::validate() {
}
UP_NetworkSettingsStruct MakeNetworkSettings()
{
void *calloc_ptr = special_calloc(1, sizeof(NetworkSettingsStruct));
UP_NetworkSettingsStruct T(new (calloc_ptr) NetworkSettingsStruct());
return T;
}
} // namespace net
} // namespace ESPEasy
@@ -50,11 +50,9 @@ private:
};
DEF_UP(NetworkSettingsStruct);
#define MakeNetworkSettings(T) void *calloc_ptr = special_calloc(1, sizeof(NetworkSettingsStruct)); \
UP_NetworkSettingsStruct T(new (calloc_ptr) NetworkSettingsStruct());
// Check to see if MakeNetworkSettings was successful
#define AllocatedNetworkSettings() (NetworkSettings.get() != nullptr)
UP_NetworkSettingsStruct MakeNetworkSettings();
} // namespace net
} // namespace ESPEasy
+16 -1
View File
@@ -29,7 +29,7 @@ bool write_NetworkAdapterFlags(ESPEasy::net::networkIndex_t networkindex, KeyVal
{
String str;
const bool res = NWPluginCall(NWPlugin::Function::NWPLUGIN_WEBFORM_SHOW_HW_ADDRESS, &TempEvent, str);
NWPluginCall(NWPlugin::Function::NWPLUGIN_WEBFORM_SHOW_HW_ADDRESS, &TempEvent, str);
}
{
@@ -66,6 +66,21 @@ bool write_NetworkAdapterFlags(ESPEasy::net::networkIndex_t networkindex, KeyVal
return true;
}
bool write_NetworkAdapterPort(ESPEasy::net::networkIndex_t networkindex,
KeyValueWriter *writer)
{
if (writer == nullptr) { return false; }
struct EventStruct TempEvent;
TempEvent.kvWriter = writer;
TempEvent.NetworkIndex = networkindex;
String str;
NWPluginCall(NWPlugin::Function::NWPLUGIN_WEBFORM_SHOW_PORT, &TempEvent, str);
return true;
}
bool write_IP_config(ESPEasy::net::networkIndex_t networkindex, KeyValueWriter*writer)
{
if (writer == nullptr) { return false; }
+3
View File
@@ -13,6 +13,9 @@ namespace net {
bool write_NetworkAdapterFlags(ESPEasy::net::networkIndex_t networkindex,
KeyValueWriter *writer);
bool write_NetworkAdapterPort(ESPEasy::net::networkIndex_t networkindex,
KeyValueWriter *writer);
bool write_IP_config(ESPEasy::net::networkIndex_t networkindex,
KeyValueWriter *writer);
#endif // ifdef ESP32
+27 -17
View File
@@ -61,6 +61,12 @@ bool NWPlugin_001(NWPlugin::Function function, EventStruct *event, String& strin
NetworkDriverStruct& nw = getNetworkDriverStruct(networkDriverIndex_t::toNetworkDriverIndex(event->idx));
nw.onlySingleInstance = true;
nw.alwaysPresent = true;
#ifdef ESP32P4
nw.enabledOnFactoryReset = false;
// ESPEasy::net::wifi::GetHostedMCUFwVersion() > 0x00020600;
#else
nw.enabledOnFactoryReset = true;
#endif
nw.fixedNetworkIndex = NWPLUGIN_ID_001 - 1; // Start counting at 0
break;
}
@@ -274,12 +280,25 @@ bool NWPlugin_001(NWPlugin::Function function, EventStruct *event, String& strin
}
# endif // ifdef ESP8266
case NWPlugin::Function::NWPLUGIN_WEBFORM_SHOW_PORT:
#ifdef ESP32P4
case NWPlugin::Function::NWPLUGIN_WEBFORM_SHOW_HW_ADDRESS:
{
// TODO TD-er: Show ESP32-P4 GPIOs for WiFi
if (event->kvWriter) {
success = ESPEasy::net::wifi::write_WiFi_Hosted_MCU_info(event->kvWriter);
}
break;
}
case NWPlugin::Function::NWPLUGIN_WEBFORM_SHOW_PORT:
{
if (event->kvWriter) {
// See HostedMCUStatus
}
break;
}
#endif
case NWPlugin::Function::NWPLUGIN_WEBFORM_SAVE:
{
// SSID 1
@@ -347,27 +366,18 @@ bool NWPlugin_001(NWPlugin::Function function, EventStruct *event, String& strin
case NWPlugin::Function::NWPLUGIN_WEBFORM_LOAD:
{
KeyValueWriter_WebForm writer(true);
#ifdef ESP32P4
ESPEasy::net::wifi::write_WiFi_Hosted_MCU_info(
writer.createChild(F("ESP-Hosted-MCU")).get());
#endif
addFormSubHeader(F("Wifi Credentials"));
// TODO Add pin configuration for ESP32P4.
// ESP32-C5 may use different SDIO pins.
// See: https://github.com/espressif/esp-hosted-mcu/blob/main/docs/sdio.md#esp32-p4-function-ev-board-host-pin-mapping
# ifdef ESP32P4
{
addRowLabel(F("ESP Hosted Firmware"));
esp_hosted_coprocessor_fwver_t ver_info{};
esp_hosted_get_coprocessor_fwversion(&ver_info);
addHtml(strformat(
F("%d.%d.%d"),
ver_info.major1,
ver_info.minor1,
ver_info.patch1));
}
# endif // ifdef ESP32P4
addFormTextBox(getLabel(LabelType::SSID), F("ssid"), SecuritySettings.WifiSSID, 31);
addFormPasswordBox(F("WPA Key"), F("key"), SecuritySettings.WifiKey, 63);
addFormTextBox(F("Fallback SSID"), F("ssid2"), SecuritySettings.WifiSSID2, 31);
+1
View File
@@ -51,6 +51,7 @@ bool NWPlugin_002(NWPlugin::Function function, EventStruct *event, String& strin
NetworkDriverStruct& nw = getNetworkDriverStruct(networkDriverIndex_t::toNetworkDriverIndex(event->idx));
nw.onlySingleInstance = true;
nw.alwaysPresent = true;
nw.enabledOnFactoryReset = false;
nw.fixedNetworkIndex = NWPLUGIN_ID_002 - 1; // Start counting at 0
break;
}
+73 -3
View File
@@ -44,7 +44,13 @@ bool NWPlugin_003(NWPlugin::Function function, EventStruct *event, String& strin
{
NetworkDriverStruct& nw = getNetworkDriverStruct(networkDriverIndex_t::toNetworkDriverIndex(event->idx));
nw.onlySingleInstance = true;
#ifdef ESP32P4
nw.alwaysPresent = true;
nw.enabledOnFactoryReset = true;
nw.fixedNetworkIndex = NWPLUGIN_ID_003 - 1; // Start counting at 0
#else
nw.alwaysPresent = false;
#endif
break;
}
@@ -102,9 +108,9 @@ bool NWPlugin_003(NWPlugin::Function function, EventStruct *event, String& strin
event->kvWriter->write({ EMPTY_STRING, s });
} else {
KeyValueStruct kv(F("Link Speed"), ETH.linkSpeed());
#if FEATURE_TASKVALUE_UNIT_OF_MEASURE
# if FEATURE_TASKVALUE_UNIT_OF_MEASURE
kv.setUnit(UOM_Mbps);
#endif
# endif
event->kvWriter->write(kv);
event->kvWriter->write({ F("Duplex Mode"), ETH.fullDuplex() ? F("Full Duplex") : F("Half Duplex") });
event->kvWriter->write({ F("Negotiation Mode"), ETH.autoNegotiation() ? F("Auto") : F("Manual") });
@@ -114,11 +120,75 @@ bool NWPlugin_003(NWPlugin::Function function, EventStruct *event, String& strin
break;
}
case NWPlugin::Function::NWPLUGIN_WEBFORM_SHOW_PORT:
case NWPlugin::Function::NWPLUGIN_WEBFORM_SHOW_HW_ADDRESS:
{
if (event->kvWriter) {
if (isValid(Settings.ETH_Phy_Type) && !isSPI_EthernetType(Settings.ETH_Phy_Type)) {
success = true;
if (event->kvWriter->summaryValueOnly()) {
KeyValueStruct kv(EMPTY_STRING);
kv.appendValue(toString(Settings.ETH_Phy_Type));
kv.appendValue(concat(F("MAC: "), ETH.macAddress()));
event->kvWriter->write(kv);
} else {
event->kvWriter->write({
F("Adapter"),
toString(Settings.ETH_Phy_Type) });
event->kvWriter->write({
F("MAC"),
ETH.macAddress(),
KeyValueStruct::Format::PreFormatted });
}
}
}
break;
}
case NWPlugin::Function::NWPLUGIN_WEBFORM_SHOW_PORT:
{
if (event->kvWriter) {
if (isValid(Settings.ETH_Phy_Type) && !isSPI_EthernetType(Settings.ETH_Phy_Type)) {
const __FlashStringHelper*labels[] = {
F("MDC"), F("MDIO"), F("Power") };
const int pins[] = {
Settings.ETH_Pin_mdc_cs,
Settings.ETH_Pin_mdio_irq,
Settings.ETH_Pin_power_rst
};
if (event->kvWriter->summaryValueOnly()) {
KeyValueStruct kv(EMPTY_STRING);
for (int i = 0; i < NR_ELEMENTS(labels); ++i) {
if (pins[i] >= 0) {
kv.appendValue(concat(labels[i], F(":&nbsp;")) + formatGpioLabel(pins[i], false));
}
}
if (kv._values.size()) {
success = true;
event->kvWriter->write(kv);
}
} else {
for (int i = 0; i < NR_ELEMENTS(labels); ++i) {
if (pins[i] >= 0) {
success = true;
event->kvWriter->write({
concat(labels[i], F(" GPIO")),
pins[i],
KeyValueStruct::Format::PreFormatted });
}
}
}
}
}
break;
}
case NWPlugin::Function::NWPLUGIN_WEBFORM_SAVE:
{
+72 -2
View File
@@ -107,9 +107,9 @@ bool NWPlugin_004(NWPlugin::Function function, EventStruct *event, String& strin
event->kvWriter->write({ EMPTY_STRING, s });
} else {
KeyValueStruct kv(F("Link Speed"), ETH.linkSpeed());
#if FEATURE_TASKVALUE_UNIT_OF_MEASURE
# if FEATURE_TASKVALUE_UNIT_OF_MEASURE
kv.setUnit(UOM_Mbps);
#endif
# endif
event->kvWriter->write(kv);
event->kvWriter->write({ F("Duplex Mode"), ETH.fullDuplex() ? F("Full Duplex") : F("Half Duplex") });
event->kvWriter->write({ F("Negotiation Mode"), ETH.autoNegotiation() ? F("Auto") : F("Manual") });
@@ -119,8 +119,77 @@ bool NWPlugin_004(NWPlugin::Function function, EventStruct *event, String& strin
break;
}
case NWPlugin::Function::NWPLUGIN_WEBFORM_SHOW_HW_ADDRESS:
{
if (event->kvWriter) {
if (isValid(Settings.ETH_Phy_Type) && isSPI_EthernetType(Settings.ETH_Phy_Type)) {
success = true;
if (event->kvWriter->summaryValueOnly()) {
KeyValueStruct kv(EMPTY_STRING);
kv.appendValue(toString(Settings.ETH_Phy_Type));
kv.appendValue(concat(F("MAC: "), ETH.macAddress()));
event->kvWriter->write(kv);
} else {
event->kvWriter->write({
F("Adapter"),
toString(Settings.ETH_Phy_Type) });
event->kvWriter->write({
F("MAC"),
ETH.macAddress(),
KeyValueStruct::Format::PreFormatted });
}
}
}
break;
}
case NWPlugin::Function::NWPLUGIN_WEBFORM_SHOW_PORT:
{
if (event->kvWriter) {
if (isValid(Settings.ETH_Phy_Type) && isSPI_EthernetType(Settings.ETH_Phy_Type)) {
int8_t spi_gpios[3]{};
if (Settings.getSPI_pins(spi_gpios)) {
const __FlashStringHelper*labels[] = {
F("CLK"), F("MISO"), F("MOSI"), F("CS"), F("IRQ"), F("RST") };
const int pins[] = {
spi_gpios[0],
spi_gpios[1],
spi_gpios[2],
Settings.ETH_Pin_mdc_cs,
Settings.ETH_Pin_mdio_irq,
Settings.ETH_Pin_power_rst
};
if (event->kvWriter->summaryValueOnly()) {
KeyValueStruct kv(EMPTY_STRING);
for (int i = 0; i < NR_ELEMENTS(labels); ++i) {
if (pins[i] >= 0) {
kv.appendValue(concat(labels[i], F(":&nbsp;")) + formatGpioLabel(pins[i], false));
}
}
if (kv._values.size()) {
success = true;
event->kvWriter->write(kv);
}
} else {
for (int i = 0; i < NR_ELEMENTS(labels); ++i) {
if (pins[i] >= 0) {
success = true;
event->kvWriter->write({
concat(labels[i], F(" GPIO")),
pins[i],
KeyValueStruct::Format::PreFormatted });
}
}
}
}
}
}
break;
}
@@ -360,6 +429,7 @@ bool NWPlugin_004(NWPlugin::Function function, EventStruct *event, String& strin
}
} // namespace net
} // namespace ESPEasy
#endif // ifdef USES_NW004
@@ -28,6 +28,8 @@ namespace wifi {
# define WIFI_STATE_MACHINE_AP_ONLY_TIMEOUT 60000
void ESPEasyWiFi_t::setup() {
if (!Settings.getNetworkEnabled(NETWORK_INDEX_WIFI_STA)) return;
// TODO TD-er: Must maybe also call 'disable()' first?
// TODO TD-er: Load settings
@@ -102,7 +102,11 @@ private:
// WiFi settings => Move to separate class/struct
#ifdef ESP32P4
bool _disabledAtBoot = false;
#else
bool _disabledAtBoot = false;
#endif
// bool _passiveScan = false;
// bool _includeHiddenSSID = false;
+161 -15
View File
@@ -33,7 +33,14 @@
# ifndef ESP32P4
# include <esp_phy_init.h>
# endif
# else
# include <esp_hosted.h>
extern "C" {
# include "esp_hosted_transport_config.h"
}
# include "port/esp/freertos/include/port_esp_hosted_host_config.h"
# endif // ifndef ESP32P4
# endif // ifdef ESP32
@@ -108,6 +115,7 @@ namespace wifi {
// - Start/stop of AP mode
// ********************************************************************************
bool WiFiConnected() {
if (!Settings.getNetworkEnabled(NETWORK_INDEX_WIFI_STA)) { return false; }
static uint32_t lastCheckedTime = 0;
const int32_t timePassed = timePassedSince(lastCheckedTime);
@@ -162,6 +170,132 @@ void exitWiFi() { ESPEasyWiFi.disable(); }
void loopWiFi() { ESPEasyWiFi.loop(); }
# ifdef ESP32P4
// ********************************************************************************
// ESP-Hosted-MCU
// ********************************************************************************
// Part of these ESP-Hosted-MCU related commands are original from Tasmota
// and parts are developed as a cooporation between ESPEasy and Tasmota.
uint32_t GetHostFwVersion()
{
const uint32_t host_version =
(ESP_HOSTED_VERSION_MAJOR_1 << 16) |
(ESP_HOSTED_VERSION_MINOR_1 << 8) |
(ESP_HOSTED_VERSION_PATCH_1);
return host_version;
}
int32_t GetHostedMCUFwVersion()
{
static int hosted_version = -1;
if (!esp_hosted_is_config_valid()) {
return 0;
}
if (-1 == hosted_version) {
hosted_version = 6; // v0.0.6
esp_hosted_coprocessor_fwver_t ver_info;
esp_err_t err = esp_hosted_get_coprocessor_fwversion(&ver_info); // This takes almost 4 seconds on <v0.0.6
if (err == ESP_OK) {
hosted_version = ver_info.major1 << 16 | ver_info.minor1 << 8 | ver_info.patch1;
} else {
// We can not know exactly, as API was added after 0.0.6
addLog(LOG_LEVEL_DEBUG, strformat(
F("WiFi : ESP-Hosted-MCU Error %d, hosted version 0.0.6 or older"), err));
}
}
return hosted_version;
}
String GetHostedFwVersion(EspHostTypes hostType)
{
const int32_t version = (hostType == EspHostTypes::ESP_HOSTED)
? GetHostedMCUFwVersion()
: GetHostFwVersion();
const uint16_t major1 = version >> 16;
const uint8_t minor1 = version >> 8;
const uint8_t patch1 = version;
return strformat(F("%d.%d.%d"), major1, minor1, patch1);
}
String GetHostedMCU()
{
// Function is not yet implemented in Arduino Core so emulate it here
if (equals(F(CONFIG_ESP_HOSTED_IDF_SLAVE_TARGET), F("esp32c6"))) {
return String("ESP32-C6");
}
return String("Unknown");
}
void HostedMCUStatus()
{
// Execute after HostedMCU is init by WiFi.mode()
static bool once_shown = false;
if (once_shown) { return; }
if (esp_hosted_is_config_valid()) {
once_shown = true;
char config[128] = { 0 };
struct esp_hosted_transport_config *pconfig;
if (ESP_TRANSPORT_OK == esp_hosted_transport_get_config(&pconfig)) {
if (pconfig->transport_in_use == H_TRANSPORT_SDIO) {
struct esp_hosted_sdio_config *psdio_config;
if (ESP_TRANSPORT_OK == esp_hosted_sdio_get_config(&psdio_config)) {
snprintf_P(config,
sizeof(config),
PSTR(" using GPIO%02d(CLK), GPIO%02d(CMD), GPIO%02d(D0), GPIO%02d(D1), GPIO%02d(D2), GPIO%02d(D3) and GPIO%02d(RST)"),
psdio_config->pin_clk.pin,
psdio_config->pin_cmd.pin,
psdio_config->pin_d0.pin,
psdio_config->pin_d1.pin,
psdio_config->pin_d2.pin,
psdio_config->pin_d3.pin,
psdio_config->pin_reset.pin);
}
}
}
addLog(LOG_LEVEL_INFO, strformat(
F("WiFi : ESP-Hosted-MCU %s v%s%s"),
GetHostedMCU().c_str(),
GetHostedFwVersion(EspHostTypes::ESP_HOSTED).c_str(),
config));
}
}
bool write_WiFi_Hosted_MCU_info(KeyValueWriter*writer)
{
if (writer == nullptr) { return false; }
if (writer->summaryValueOnly()) {
KeyValueStruct kv(EMPTY_STRING);
kv.appendValue(strformat(F("%s @ %s"), GetHostedMCU().c_str(), GetHostedFwVersion(EspHostTypes::ESP_HOSTED).c_str()));
kv.appendValue(concat(F("MAC: "), WiFi.macAddress()));
writer->write(kv);
} else {
writer->write({ F("ESP-Host Fw Version"), GetHostedFwVersion(EspHostTypes::ESP_HOST) });
writer->write({ F("ESP-Hosted-MCU Fw Version"), GetHostedFwVersion(EspHostTypes::ESP_HOSTED) });
writer->write({ F("ESP-Hosted-MCU Chip"), GetHostedMCU() });
writer->write({
F("MAC"),
WiFi.macAddress(),
KeyValueStruct::Format::PreFormatted });
}
return true;
}
# endif // ifdef ESP32P4
// ********************************************************************************
// Configure WiFi TX power
// ********************************************************************************
@@ -270,8 +404,8 @@ bool WiFiUseStaticIP() { return Settings.IP[0] != 0 && Settings.IP[0]
bool wifiAPmodeActivelyUsed()
{
if (!WifiIsAP(WiFi.getMode()) //|| (!WiFiEventData.timerAPoff.isSet())
) {
if (!WifiIsAP(WiFi.getMode()) // || (!WiFiEventData.timerAPoff.isSet())
) {
// AP not active or soon to be disabled in processDisableAPmode()
return false;
}
@@ -290,10 +424,11 @@ void setupStaticIPconfig() {
const IPAddress subnet(Settings.Subnet);
const IPAddress dns(Settings.DNS);
// WiFiEventData.dns0_cache = dns;
// WiFiEventData.dns0_cache = dns;
WiFi.config(ip, gw, subnet, dns);
#ifndef BUILD_NO_DEBUG
# ifndef BUILD_NO_DEBUG
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
addLogMove(LOG_LEVEL_INFO, strformat(
F("IP : Static IP : %s GW: %s SN: %s DNS: %s"),
@@ -302,7 +437,7 @@ void setupStaticIPconfig() {
formatIP(subnet).c_str(),
getValue(LabelType::DNS).c_str()));
}
#endif
# endif // ifndef BUILD_NO_DEBUG
}
// ********************************************************************************
@@ -343,14 +478,15 @@ void logConnectionStatus() {
}
}
# endif // ifdef ESP8266
/*
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
addLogMove(LOG_LEVEL_INFO, strformat(
F("WIFI : Arduino wifi status: %s ESPeasy internal wifi status: %s"),
ArduinoWifiStatusToString(WiFi.status()).c_str(),
WiFiEventData.ESPeasyWifiStatusToString().c_str()));
}
*/
/*
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
addLogMove(LOG_LEVEL_INFO, strformat(
F("WIFI : Arduino wifi status: %s ESPeasy internal wifi status: %s"),
ArduinoWifiStatusToString(WiFi.status()).c_str(),
WiFiEventData.ESPeasyWifiStatusToString().c_str()));
}
*/
# endif // ifndef BUILD_NO_DEBUG
}
@@ -373,7 +509,17 @@ bool setAP(bool enable) { return doSetAP(enable); }
bool setSTA_AP(bool sta_enable,
bool ap_enable) { return doSetSTA_AP(sta_enable, ap_enable); }
bool setWifiMode(WiFiMode_t new_mode) { return doSetWifiMode(new_mode); }
bool setWifiMode(WiFiMode_t new_mode) {
const bool res = doSetWifiMode(new_mode);
# ifdef ESP32P4
if (new_mode != WIFI_OFF) {
ESPEasy::net::wifi::HostedMCUStatus();
}
# endif // ifdef ESP32P4
return res;
}
void WifiScan(bool async,
uint8_t channel) { doWifiScan(async, channel); }
+40 -14
View File
@@ -15,13 +15,14 @@
# include "../DataStructs/WiFi_AP_Candidate.h"
# include "../../../src/Helpers/LongTermTimer.h"
# include "../../../src/Helpers/KeyValueWriter.h"
#ifdef ESP32
#define SOFTAP_STATION_COUNT WiFi.AP.stationCount()
#endif
#ifdef ESP8266
#define SOFTAP_STATION_COUNT WiFi.softAPgetStationNum()
#endif
# ifdef ESP32
# define SOFTAP_STATION_COUNT WiFi.AP.stationCount()
# endif
# ifdef ESP8266
# define SOFTAP_STATION_COUNT WiFi.softAPgetStationNum()
# endif
namespace ESPEasy {
@@ -40,14 +41,39 @@ namespace wifi {
# define WIFI_SCAN_INTERVAL_MINIMAL 60000 // in milliSeconds
bool WiFiConnected();
//void WiFiConnectRelaxed();
bool prepareWiFi();
bool checkAndResetWiFi();
void resetWiFi();
void initWiFi();
void exitWiFi();
void loopWiFi();
bool WiFiConnected();
// void WiFiConnectRelaxed();
bool prepareWiFi();
bool checkAndResetWiFi();
void resetWiFi();
void initWiFi();
void exitWiFi();
void loopWiFi();
# ifdef ESP32P4
// ********************************************************************************
// ESP-Hosted-MCU
// ********************************************************************************
// Part of these ESP-Hosted-MCU related commands are original from Tasmota
// and parts are developed as a cooporation between ESPEasy and Tasmota.
enum class EspHostTypes {
ESP_HOST,
ESP_HOSTED
};
uint32_t GetHostFwVersion();
int32_t GetHostedMCUFwVersion();
String GetHostedFwVersion(EspHostTypes hostType);
String GetHostedMCU();
void HostedMCUStatus();
bool write_WiFi_Hosted_MCU_info(KeyValueWriter*writer);
# endif // ifdef ESP32P4
# if FEATURE_SET_WIFI_TX_PWR
void SetWiFiTXpower();
@@ -169,6 +169,7 @@ bool doSetWifiMode(WiFiMode_t new_mode)
WiFi.STA.end();
# endif
} else {
/*
if (cur_mode == WIFI_OFF) {
registerWiFiEventHandler();
+16 -8
View File
@@ -374,13 +374,17 @@ void C013_Receive(struct EventStruct *event) {
if (mustMatch && !dataReply->matchesPluginID(Settings.getPluginID_for_task(dataReply->destTaskIndex))) {
// Mismatch in plugin ID from sending node
#ifndef BUILD_NO_DEBUG
if (loglevelActiveFor(LOG_LEVEL_ERROR)) {
String log = concat(F("P2P data : PluginID mismatch for task "), dataReply->destTaskIndex + 1);
log += concat(F(" from unit "), dataReply->sourceUnit);
log += concat(F(" remote: "), dataReply->deviceNumber.value);
log += concat(F(" local: "), Settings.getPluginID_for_task(dataReply->destTaskIndex).value);
addLogMove(LOG_LEVEL_ERROR, log);
addLogMove(LOG_LEVEL_ERROR, strformat(
F("P2P data : PluginID mismatch for task %d from unit %d remote: %d local: %d"),
dataReply->destTaskIndex + 1,
dataReply->sourceUnit,
dataReply->deviceNumber.value,
Settings.getPluginID_for_task(dataReply->destTaskIndex).value
));
}
#endif
} else {
struct EventStruct TempEvent(dataReply->destTaskIndex);
TempEvent.Source = EventValueSource::Enum::VALUE_SOURCE_UDP;
@@ -405,12 +409,16 @@ void C013_Receive(struct EventStruct *event) {
SensorSendTask(&TempEvent);
}
} else {
#ifndef BUILD_NO_DEBUG
// Mismatch in sensor types
if (loglevelActiveFor(LOG_LEVEL_ERROR)) {
String log = concat(F("P2P data : SensorType mismatch for task "), dataReply->destTaskIndex + 1);
log += concat(F(" from unit "), dataReply->sourceUnit);
addLogMove(LOG_LEVEL_ERROR, log);
addLogMove(LOG_LEVEL_ERROR, strformat(
F("P2P data : SensorType mismatch for task %d from unit %d"),
dataReply->destTaskIndex + 1,
dataReply->sourceUnit
));
}
#endif
}
}
}
@@ -75,21 +75,23 @@ bool ControllerDelayHandlerStruct::queueFull(controllerIndex_t controller_idx) c
int freeHeap = FreeMem();
{
/*
#ifdef USE_SECOND_HEAP
const int freeHeap2 = FreeMem2ndHeap();
#ifdef USE_SECOND_HEAP
const int freeHeap2 = FreeMem2ndHeap();
if (freeHeap2 < freeHeap) {
freeHeap = freeHeap2;
}
#endif // ifdef USE_SECOND_HEAP
*/
if (freeHeap2 < freeHeap) {
freeHeap = freeHeap2;
}
#endif // ifdef USE_SECOND_HEAP
*/
}
#ifdef ESP32
if (freeHeap > 50000)
#else
if (freeHeap > 5000)
#endif
if (freeHeap > 50000)
#else // ifdef ESP32
if (freeHeap > 5000)
#endif // ifdef ESP32
{
return false; // Memory is not an issue.
}
@@ -147,9 +149,10 @@ bool ControllerDelayHandlerStruct::isDuplicate(const Queue_element_base& element
// Try to add to the queue, if permitted by "delete_oldest"
// Return true when item was added, or skipped as it was considered a duplicate
bool ControllerDelayHandlerStruct::addToQueue(UP_Queue_element_base element) {
if (!element) {
if (!element) {
return false;
}
if (isDuplicate(*element)) {
return true;
}
@@ -165,11 +168,12 @@ bool ControllerDelayHandlerStruct::addToQueue(UP_Queue_element_base element) {
if (!queueFull(element->_controller_idx)) {
#ifdef USE_SECOND_HEAP
// Do not store in 2nd heap, std::list cannot handle 2nd heap well
HeapSelectDram ephemeral;
#endif // ifdef USE_SECOND_HEAP
sendQueue.push_back(std::move(element));
sendQueue.emplace_back(std::move(element));
return true;
}
@@ -213,7 +217,7 @@ Queue_element_base * ControllerDelayHandlerStruct::getNext() {
// Mark as processed and return time to schedule for next process.
// Return 0 when nothing to process.
// @param remove_from_queue indicates whether the elements should be removed from the queue.
unsigned long ControllerDelayHandlerStruct::markProcessed(bool remove_from_queue) {
uint32_t ControllerDelayHandlerStruct::markProcessed(bool remove_from_queue) {
if (sendQueue.empty()) { return 0; }
if (remove_from_queue) {
@@ -226,9 +230,9 @@ unsigned long ControllerDelayHandlerStruct::markProcessed(bool remove_from_queue
return getNextScheduleTime();
}
unsigned long ControllerDelayHandlerStruct::getNextScheduleTime() const {
uint32_t ControllerDelayHandlerStruct::getNextScheduleTime() const {
if (sendQueue.empty()) { return 0; }
unsigned long nextTime = lastSend + minTimeBetweenMessages;
uint32_t nextTime = lastSend + minTimeBetweenMessages;
if (timePassedSince(nextTime) > 0) {
nextTime = millis();
@@ -242,9 +246,7 @@ unsigned long ControllerDelayHandlerStruct::getNextScheduleTime() const {
// Set the "lastSend" to "now" + some additional delay.
// This will cause the next schedule time to be delayed to
// msecFromNow + minTimeBetweenMessages
void ControllerDelayHandlerStruct::setAdditionalDelay(unsigned long msecFromNow) {
lastSend = millis() + msecFromNow;
}
void ControllerDelayHandlerStruct::setAdditionalDelay(uint32_t msecFromNow) { lastSend = millis() + msecFromNow; }
size_t ControllerDelayHandlerStruct::getQueueMemorySize() const {
size_t totalSize = 0;
@@ -258,10 +260,10 @@ size_t ControllerDelayHandlerStruct::getQueueMemorySize() const {
}
void ControllerDelayHandlerStruct::process(
cpluginID_t cpluginID,
do_process_function func,
TimingStatsElements timerstats_id,
SchedulerIntervalTimer_e timerID)
cpluginID_t cpluginID,
do_process_function func,
TimingStatsElements timerstats_id,
SchedulerIntervalTimer_e timerID)
{
Queue_element_base *element(static_cast<Queue_element_base *>(getNext()));
@@ -20,7 +20,7 @@
#include "../Helpers/StringConverter.h"
#include <list>
#include <deque>
#include <memory> // For std::unique_ptr
#include <new> // std::nothrow
@@ -59,35 +59,36 @@ struct ControllerDelayHandlerStruct {
// Mark as processed and return time to schedule for next process.
// Return 0 when nothing to process.
// @param remove_from_queue indicates whether the elements should be removed from the queue.
unsigned long markProcessed(bool remove_from_queue);
uint32_t markProcessed(bool remove_from_queue);
unsigned long getNextScheduleTime() const;
uint32_t getNextScheduleTime() const;
// Set the "lastSend" to "now" + some additional delay.
// This will cause the next schedule time to be delayed to
// msecFromNow + minTimeBetweenMessages
void setAdditionalDelay(unsigned long msecFromNow);
void setAdditionalDelay(uint32_t msecFromNow);
size_t getQueueMemorySize() const;
void process(
cpluginID_t cpluginID,
do_process_function func,
TimingStatsElements timerstats_id,
cpluginID_t cpluginID,
do_process_function func,
TimingStatsElements timerstats_id,
SchedulerIntervalTimer_e timerID);
std::list<UP_Queue_element_base >sendQueue;
mutable UnitLastMessageCount_map unitLastMessageCount;
unsigned long lastSend = 0;
unsigned int minTimeBetweenMessages = CONTROLLER_DELAY_QUEUE_DELAY_DFLT;
unsigned long expire_timeout = 0;
uint8_t max_queue_depth = CONTROLLER_DELAY_QUEUE_DEPTH_DFLT;
uint8_t attempt = 0;
uint8_t max_retries = CONTROLLER_DELAY_QUEUE_RETRY_DFLT;
bool delete_oldest = false;
bool must_check_reply = false;
bool deduplicate = false;
bool useLocalSystemTime = false;
std::deque<UP_Queue_element_base>sendQueue;
mutable UnitLastMessageCount_map unitLastMessageCount;
uint32_t lastSend = 0;
uint32_t minTimeBetweenMessages = CONTROLLER_DELAY_QUEUE_DELAY_DFLT;
uint32_t expire_timeout = 0;
uint8_t max_queue_depth = CONTROLLER_DELAY_QUEUE_DEPTH_DFLT;
uint8_t attempt = 0;
uint8_t max_retries = CONTROLLER_DELAY_QUEUE_RETRY_DFLT;
bool delete_oldest = false;
bool must_check_reply = false;
bool deduplicate = false;
bool useLocalSystemTime = false;
};
+5 -1
View File
@@ -276,7 +276,7 @@
#endif
#ifndef DEFAULT_ETH_PHY_ADDR
#ifdef ESP32P4
#define DEFAULT_ETH_PHY_ADDR 1
#define DEFAULT_ETH_PHY_ADDR ETH_PHY_ADDR
#else
#define DEFAULT_ETH_PHY_ADDR 0
#endif
@@ -315,7 +315,11 @@
#endif
#ifndef DEFAULT_ETH_CLOCK_MODE
# if CONFIG_ETH_USE_ESP32_EMAC && FEATURE_ETHERNET
#ifdef ESP32P4
#define DEFAULT_ETH_CLOCK_MODE ESPEasy::net::EthClockMode_t::Ext_crystal
#else
#define DEFAULT_ETH_CLOCK_MODE static_cast<ESPEasy::net::EthClockMode_t>(0)
#endif
#else
#define DEFAULT_ETH_CLOCK_MODE (0)
#endif
+1 -1
View File
@@ -58,7 +58,7 @@ To create/register a plugin, you have to :
#define WEBSERVER_LOG
#endif
#ifndef WEBSERVER_GITHUB_COPY
#ifndef USE_SECOND_HEAP
#if !(defined(LIMIT_BUILD_SIZE) || defined(ESP8266))
#define WEBSERVER_GITHUB_COPY
#endif
#endif
@@ -17,12 +17,6 @@
#include <WiFiUdp.h>
ControllerSettingsStruct::ControllerSettingsStruct()
{
memset(this, 0, sizeof(ControllerSettingsStruct));
safe_strncpy(ClientID, F(CONTROLLER_DEFAULT_CLIENTID), sizeof(ClientID));
}
void ControllerSettingsStruct::reset() {
// Need to make sure every byte between the members is also zero
// Otherwise the checksum will fail and settings will be saved too often.
@@ -38,6 +32,9 @@ void ControllerSettingsStruct::reset() {
MustCheckReply = DEFAULT_CONTROLLER_MUST_CHECK_REPLY;
SampleSetInitiator = INVALID_TASK_INDEX;
KeepAliveTime = CONTROLLER_KEEP_ALIVE_TIME_DFLT;
// All these bits are already set to 0 by the memset call
/*
VariousBits1.mqtt_cleanSession = 0;
VariousBits1.mqtt_not_sendLWT = 0;
VariousBits1.mqtt_not_willRetain = 0;
@@ -50,6 +47,7 @@ void ControllerSettingsStruct::reset() {
VariousBits1.useLocalSystemTime = 0;
VariousBits1.TLStype = 0;
VariousBits1.mqttAutoDiscovery = 0;
*/
safe_strncpy(ClientID, F(CONTROLLER_DEFAULT_CLIENTID), sizeof(ClientID));
}
@@ -382,3 +380,14 @@ uint32_t ControllerSettingsStruct::getSuggestedTimeout(int index) const
}
return ClientTimeout;
}
UP_ControllerSettingsStruct doMakeControllerSettings()
{
// Need to make sure every byte between the members is also zero
// Otherwise the checksum will fail and settings will be saved too often.
// Therefore we're using calloc instead of malloc.
void * calloc_ptr = special_calloc(1,sizeof(ControllerSettingsStruct));
UP_ControllerSettingsStruct T(new (calloc_ptr) ControllerSettingsStruct());
if (T) T->reset();
return T;
}
@@ -125,7 +125,7 @@ struct ControllerSettingsStruct
};
ControllerSettingsStruct();
ControllerSettingsStruct() = default;
void reset();
@@ -271,7 +271,11 @@ private:
#include "../Helpers/Memory.h"
DEF_UP(ControllerSettingsStruct);
#define MakeControllerSettings(T) void * calloc_ptr = special_calloc(1,sizeof(ControllerSettingsStruct)); UP_ControllerSettingsStruct T(new (calloc_ptr) ControllerSettingsStruct());
UP_ControllerSettingsStruct doMakeControllerSettings();
#define MakeControllerSettings(T) UP_ControllerSettingsStruct T = doMakeControllerSettings();
// Check to see if MakeControllerSettings was successful
#define AllocatedControllerSettings() (ControllerSettings.get() != nullptr)
+1 -1
View File
@@ -477,7 +477,7 @@ public:
uint8_t Syslog_IP[4] = {0};
uint32_t UDPPort = 8266;
uint8_t SyslogLevel = 0;
uint8_t SerialLogLevel = 0;
uint8_t SerialLogLevel = 2;
uint8_t WebLogLevel = 0;
uint8_t SDLogLevel = 0;
uint32_t BaudRate = 115200;
+5 -1
View File
@@ -569,6 +569,7 @@ void SettingsStruct_tmpl<N_TASKS>::validate() {
// Make sure the WiFi and AP drivers are always added and set enabled when loading older settings,
// or factory default settings
bool fixedNetworkIndex_drivers_added = false;
for (ESPEasy::net::networkDriverIndex_t index; ESPEasy::net::validNetworkDriverIndex(index); ++index)
{
const ESPEasy::net::NetworkDriverStruct& nw = ESPEasy::net::getNetworkDriverStruct(index);
@@ -577,9 +578,12 @@ void SettingsStruct_tmpl<N_TASKS>::validate() {
const ESPEasy::net::nwpluginID_t nwpluginID = ESPEasy::net::getNWPluginID_from_NetworkDriverIndex(index);
if (getNWPluginID_for_network(nw.fixedNetworkIndex) != nwpluginID) {
setNWPluginID_for_network(nw.fixedNetworkIndex, nwpluginID);
setNetworkEnabled(nw.fixedNetworkIndex, true);
fixedNetworkIndex_drivers_added = true;
setNetworkEnabled(nw.fixedNetworkIndex, nw.enabledOnFactoryReset);
}
}
} else {
}
}
}
+22 -13
View File
@@ -487,19 +487,22 @@ KeyValueStruct getKeyValue(LabelType::Enum label, bool extendedValue)
return KeyValueStruct(F("WiFi Connection") /*, value*/);
}
case LabelType::WIFI_RSSI:
{
if (extendedValue) {
return KeyValueStruct(F("RSSI"), strformat(
F("%d [dBm] (%s)"),
WiFi.RSSI(),
WiFi.SSID().c_str()));
}
KeyValueStruct kv(F("RSSI"), WiFi.RSSI());
if (ESPEasy::net::wifi::WiFiConnected())
{
if (extendedValue) {
return KeyValueStruct(F("RSSI"), strformat(
F("%d [dBm] (%s)"),
WiFi.RSSI(),
WiFi.SSID().c_str()));
}
KeyValueStruct kv(F("RSSI"), WiFi.RSSI());
#if FEATURE_TASKVALUE_UNIT_OF_MEASURE
KV_SETUNIT(UOM_dBm);
KV_SETUNIT(UOM_dBm);
#endif
return kv;
}
return kv;
}
break;
case LabelType::IP_CONFIG:
{
KeyValueStruct kv(F("IP Config"), useStaticIP() ? F("static") : F("DHCP"));
@@ -510,7 +513,11 @@ KeyValueStruct getKeyValue(LabelType::Enum label, bool extendedValue)
case LabelType::IP6_LOCAL:
if (Settings.EnableIPv6()) {
return KeyValueStruct(F("IPv6 link local"), formatIP(ESPEasy::net::NetworkLocalIP6(), true));
auto ip = ESPEasy::net::NetworkLocalIP6();
if (ip != IN6ADDR_ANY) {
return KeyValueStruct(F("IPv6 link local"), formatIP(ip, true));
}
}
break;
case LabelType::IP6_GLOBAL:
@@ -1306,10 +1313,12 @@ String getFormNote(LabelType::Enum label)
}
#if FEATURE_TASKVALUE_UNIT_OF_MEASURE
String getFormUnit(LabelType::Enum label)
{
auto kv = getKeyValue(label);
return kv.getUnit();
}
#endif
#endif // if FEATURE_TASKVALUE_UNIT_OF_MEASURE
+3 -2
View File
@@ -85,7 +85,7 @@ static const char favicon_8b_ico[] PROGMEM = {
0x09, 0x35, 0x8e, 0xf2, 0xa6, 0xea, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45,
0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
static const unsigned int favicon_8b_ico_len = 390;
static constexpr unsigned int favicon_8b_ico_len = sizeof(favicon_8b_ico);
#endif
@@ -327,7 +327,7 @@ static const char jsToastMessageEnd[] PROGMEM = {
" },2000);"
"} "
};
#ifdef WEBSERVER_GITHUB_COPY
static const char jsClipboardCopyPart1[] PROGMEM = {
"<script>function setClipboard(){var cb='';"
// " max_loop = 100;"
@@ -359,6 +359,7 @@ static const char jsClipboardCopyPart3[] PROGMEM = {
"alert('Copied: \"' + cb + '\" to clipboard!'); }"
"</script>"
};
#endif
#ifdef WEBSERVER_INCLUDE_JS
// Manually minified js
+1 -1
View File
@@ -1048,7 +1048,7 @@ void format_SPI_pin_description(int8_t spi_gpios[3], taskIndex_t x, bool showCSp
if (Settings.InitSPI > static_cast<int>(SPI_Options_e::None)) {
const __FlashStringHelper*labels[] = { F("CLK"), F("MISO"), F("MOSI") };
for (int i = 0; i < 3; ++i) {
for (int i = 0; i < NR_ELEMENTS(labels); ++i) {
if (i != 0) {
html_BR();
}
+3 -2
View File
@@ -324,14 +324,14 @@ void html_add_Easy_color_code_script() {
#endif
void html_add_autosubmit_form() {
addHtml(F("<script><!--\n"
html_add_script(F("<!--\n"
// "function dept_onchange(frmselect) {frmselect.submit();}"
"function dept_onchange(e){e.submit()}"
// "function task_select_onchange(frmselect) {var element = document.getElementById('nosave'); if (typeof(element) != 'undefined' && element != null) {element.disabled = false; element.checked = true;} frmselect.submit();}"
"function task_select_onchange(e){var n=document.getElementById('nosave');void 0!==n&&null!=n&&(n.disabled=!1,n.checked=!0),e.submit()}"
// "function rules_set_onchange(rulesselect) {document.getElementById('rules').disabled = true; rulesselect.submit();}"
"function rules_set_onchange(e){document.getElementById('rules').disabled=!0,e.submit()}"
"\n//--></script>"));
"\n//-->"), false);
}
void html_add_script(const __FlashStringHelper * script, bool defer) {
@@ -374,6 +374,7 @@ void addHtmlError(const __FlashStringHelper * error) {
void addHtmlError(const String& error) {
if (error.length() > 0)
{
addLog(LOG_LEVEL_ERROR, error);
addHtml(F("<div class=\""));
if (error.startsWith(F("Warn"))) {
+1
View File
@@ -279,6 +279,7 @@ void handle_json()
#ifdef WEBSERVER_NETWORK
# ifdef ESP32
ESPEasy::net::write_NetworkAdapterFlags(x, writer->createChild(F("Interface")).get());
ESPEasy::net::write_NetworkAdapterPort(x, writer->createChild(F("Port")).get());
ESPEasy::net::write_IP_config(x, writer->createChild(F("IP")).get());
# endif // ifdef ESP32
#endif // ifdef WEBSERVER_NETWORK
+2 -2
View File
@@ -34,7 +34,7 @@ void addButton(const String& url, const String& label, const String& classes, bo
addHtml(label);
addHtml(F("</a>"));
}
# ifdef WEBSERVER_NEW_RULES
void addButtonWithSvg(const String& url, const String& label)
{
addButtonWithSvg(url, label, EMPTY_STRING, false);
@@ -105,7 +105,7 @@ void addDeleteButton(const String& url, const String& label)
true);
#endif // ifdef BUILD_MINIMAL_OTA
}
#endif
void addWideButton(const __FlashStringHelper * url, const __FlashStringHelper * label) {
html_add_wide_button_prefix(EMPTY_STRING, true);
addHtml(url);
+2 -1
View File
@@ -12,6 +12,7 @@ void addButton(const String& url, const String& label);
void addButton(const String& url, const String& label, const String& classes, bool enabled = true);
# ifdef WEBSERVER_NEW_RULES
void addButtonWithSvg(const String& url, const String& label);
void addButtonWithSvg(const String& url, const String& label, const String& svgPath, bool needConfirm);
@@ -19,7 +20,7 @@ void addButtonWithSvg(const String& url, const String& label, const String& svgP
void addSaveButton(const String& url, const String& label);
void addDeleteButton(const String& url, const String& label);
#endif
void addWideButton(const __FlashStringHelper * url, const __FlashStringHelper * label);
void addWideButton(const String& url, const String& label);
+7 -1
View File
@@ -59,7 +59,7 @@ void handle_networks()
// TODO TD-er: Implement saving submitted settings
const nwpluginID_t nwpluginID = nwpluginID_t::toPluginID(networkDriver_webarg_value);
MakeNetworkSettings(NetworkSettings);
auto NetworkSettings = MakeNetworkSettings();
if (Settings.getNWPluginID_for_network(networkindex) != nwpluginID)
{
@@ -393,6 +393,12 @@ void handle_networks_NetworkSettingsPage(ESPEasy::net::networkIndex_t networkind
KeyValueWriter_WebForm writer(F("Network Interface"));
ESPEasy::net::write_NetworkAdapterFlags(networkindex, writer.createChild().get());
}
/*
{
KeyValueWriter_WebForm writer(F("Port"));
ESPEasy::net::write_NetworkAdapterPort(networkindex, writer.createChild().get());
}
*/
{
KeyValueWriter_WebForm writer(F("IP Config"));
ESPEasy::net::write_IP_config(networkindex, writer.createChild().get());
+1 -1
View File
@@ -551,7 +551,7 @@ void Rule_showRuleTextArea(const String& fileName) {
size = streamFromFS(fileName, true);
addHtml(F("</textarea>"));
#if FEATURE_RULES_EASY_COLOR_CODE
addHtml(F("<script>initCM();</script>"));
html_add_script(F("initCM();"), false);
#endif
html_TR_TD();