diff --git a/platformio.ini b/platformio.ini index 52bce034..434ace8e 100644 --- a/platformio.ini +++ b/platformio.ini @@ -75,7 +75,7 @@ lib_deps = build_flags = -D APP=StarBase -D PIOENV=$PIOENV - -D VERSION=24091708 ; Date and time (GMT!), update at every commit!! + -D VERSION=24092014 ; Date and time (GMT!), update at every commit!! -D LFS_THREADSAFE ; enables use of semaphores in LittleFS driver -D STARBASE_DEVMODE -mtext-section-literals ;otherwise [UserModLive::setup()]+0xa17): dangerous relocation: l32r: literal target out of range (try using text-section-literals) diff --git a/src/Sys/SysModModel.cpp b/src/Sys/SysModModel.cpp index 3f237d77..7be0903c 100644 --- a/src/Sys/SysModModel.cpp +++ b/src/Sys/SysModModel.cpp @@ -278,6 +278,11 @@ bool SysModModel::callVarOnChange(JsonObject var, unsigned8 rowNr, bool init) { while (rowNr >= (*valuePointer).size()) (*valuePointer).push_back(UINT16_MAX); //create vector space if needed... (*valuePointer)[rowNr] = value; } + else if (var["type"] == "text" || var["type"] == "fileEdit") { + std::vector *valuePointer = (std::vector *)pointer; + while (rowNr >= (*valuePointer).size()) (*valuePointer).push_back(VectorString()); //create vector space if needed... + strcpy((*valuePointer)[rowNr].s, value.as()); + } else if (var["type"] == "coord3D") { std::vector *valuePointer = (std::vector *)pointer; while (rowNr >= (*valuePointer).size()) (*valuePointer).push_back({-1,-1,-1}); //create vector space if needed... diff --git a/src/Sys/SysModModel.h b/src/Sys/SysModModel.h index dfa757af..16dee862 100644 --- a/src/Sys/SysModModel.h +++ b/src/Sys/SysModModel.h @@ -274,22 +274,20 @@ class Variable { void postDetails(uint8_t rowNr) { - if (rowNr != UINT8_MAX) - { - - ppf("varPostDetails pre "); - print->printVar(var); - ppf("\n"); - - //check if post init added: parent is already >=0 - if (order() >= 0) { - for (JsonArray::iterator childVarIt=children().begin(); childVarIt!=children().end(); ++childVarIt) { //use iterator to make .remove work!!! - // for (JsonObject &childVarIt: children) { //use iterator to make .remove work!!! - JsonObject childVar = *childVarIt; - Variable childVariable = Variable(childVar); - JsonArray valArray = childVariable.valArray(); - if (!valArray.isNull()) - { + ppf("varPostDetails pre "); + print->printVar(var); + ppf("\n"); + + //check if post init added: parent is already >=0 + if (order() >= 0) { + for (JsonArray::iterator childVarIt=children().begin(); childVarIt!=children().end(); ++childVarIt) { //use iterator to make .remove work!!! + // for (JsonObject &childVarIt: children) { //use iterator to make .remove work!!! + JsonObject childVar = *childVarIt; + Variable childVariable = Variable(childVar); + JsonArray valArray = childVariable.valArray(); + if (!valArray.isNull()) + { + if (rowNr != UINT8_MAX) { if (childVariable.order() < 0) { //if not updated valArray[rowNr] = (char*)0; // set element in valArray to 0 @@ -309,20 +307,27 @@ class Variable { ppf("remove allnulls %s\n", childVariable.id()); children().remove(childVarIt); } + web->addResponse("details", "rowNr", rowNr); } - else { - print->printJson("remove non valArray", childVar); + else + print->printJson("dev array but not rowNr", var); + } + else { + if (childVariable.order() < 0) { //if not updated + // childVar["value"] = (char*)0; + ppf("varPostDetails %s.%s <- null\n", id(), childVariable.id()); + // setValue(var, -99, rowNr); //set value -99 + // childVariable.order(-childVariable.order()); + print->printJson("remove", childVar); children().remove(childVarIt); } - } - } //if new added - ppf("varPostDetails post "); - print->printVar(var); - ppf("\n"); - web->addResponse("details", "rowNr", rowNr); - } + } + } //if new added + ppf("varPostDetails post "); + print->printVar(var); + ppf("\n"); //post update details web->addResponse("details", "var", var); diff --git a/src/Sys/SysModNetwork.cpp b/src/Sys/SysModNetwork.cpp index 919a793f..4d462c56 100644 --- a/src/Sys/SysModNetwork.cpp +++ b/src/Sys/SysModNetwork.cpp @@ -16,6 +16,10 @@ #include "SysModUI.h" #include "SysModModel.h" #include "User/UserModMDNS.h" +#include "SysModPins.h" + +#include + SysModNetwork::SysModNetwork() :SysModule("Network") {}; @@ -51,30 +55,136 @@ void SysModNetwork::setup() { default: return false; }}); - ui->initText(parentVar, "nwstatus", nullptr, 32, true, [](JsonObject var, unsigned8 rowNr, unsigned8 funType) { switch (funType) { //varFun + ui->initText(parentVar, "rssi", nullptr, 32, true, [](JsonObject var, unsigned8 rowNr, unsigned8 funType) { switch (funType) { //varFun case onUI: - ui->setLabel(var, "Status"); + ui->setLabel(var, "Wifi signal"); return true; default: return false; }}); - ui->initText(parentVar, "rssi", nullptr, 32, true, [](JsonObject var, unsigned8 rowNr, unsigned8 funType) { switch (funType) { //varFun + ui->initSelect(parentVar, "ethernet", 0, false, [this](JsonObject var, uint8_t rowNr, uint8_t funType) { switch (funType) { //varFun + case onUI: { + JsonArray options = ui->setOptions(var); + options.add("None"); + options.add("Manual"); + options.add("Olimex ESP32 Gateway"); + options.add("Other"); + options.add("Another"); + options.add("tbd"); + return true; + } + case onChange: + Variable(var).preDetails(); + mdl->setValueRowNr = rowNr; + + if (var["value"] == 1) {//manual + ui->initNumber(var, "ethaddr", (uint16_t)0, 0, 255, false, [this](JsonObject var, uint8_t rowNr, uint8_t funType) { switch (funType) { //varFun + case onUI: + ui->setLabel(var, "Address"); + return true; + case onChange: + successfullyConfiguredEthernet = false; + return true; + default: return false; + }}); + ui->initPin(var, "ethpower", 14, false, [this](JsonObject var, uint8_t rowNr, uint8_t funType) { switch (funType) { //varFun + case onUI: + ui->setLabel(var, "Power"); + return true; + case onChange: + successfullyConfiguredEthernet = false; + return true; + default: return false; + }}); + ui->initPin(var, "ethmdc", 23, false, [this](JsonObject var, uint8_t rowNr, uint8_t funType) { switch (funType) { //varFun + case onUI: + ui->setLabel(var, "mdc"); + return true; + case onChange: + successfullyConfiguredEthernet = false; + return true; + default: return false; + }}); + ui->initPin(var, "ethmdio", 18, false, [this](JsonObject var, uint8_t rowNr, uint8_t funType) { switch (funType) { //varFun + case onUI: + ui->setLabel(var, "mdio"); + return true; + case onChange: + successfullyConfiguredEthernet = false; + return true; + default: return false; + }}); + ui->initSelect(var, "ethtype", ETH_PHY_LAN8720, false, [this](JsonObject var, uint8_t rowNr, uint8_t funType) { switch (funType) { //varFun + case onUI: { + ui->setLabel(var, "Type"); + JsonArray options = ui->setOptions(var); + options.add("LAN8720"); + options.add("TLK110"); + options.add("RTL8201"); + options.add("DP83848"); + options.add("DM9051"); + options.add("KSZ8041"); + options.add("KSZ8081"); + options.add("MAX"); + return true; + } + case onChange: + successfullyConfiguredEthernet = false; + return true; + default: return false; + }}); + ui->initSelect(var, "ethclkmode", ETH_CLOCK_GPIO17_OUT, false, [this](JsonObject var, uint8_t rowNr, uint8_t funType) { switch (funType) { //varFun + case onUI: { + ui->setLabel(var, "Clock mode"); + JsonArray options = ui->setOptions(var); + options.add("GPIO0_IN"); + options.add("GPIO0_OUT"); + options.add("GPIO16_OUT"); + options.add("GPIO17_OUT"); + return true; + } + case onChange: + successfullyConfiguredEthernet = false; + return true; + default: return false; + }}); + } + + Variable(var).postDetails(rowNr); + mdl->setValueRowNr = UINT8_MAX; + + successfullyConfiguredEthernet = false; + // initEthernet(); //try to connect + + return true; + default: return false; + }}); + + ui->initText(parentVar, "nwstatus", nullptr, 32, true, [](JsonObject var, unsigned8 rowNr, unsigned8 funType) { switch (funType) { //varFun case onUI: - ui->setLabel(var, "Wifi signal"); + ui->setLabel(var, "Status"); return true; default: return false; }}); + } void SysModNetwork::loop1s() { handleConnection(); //once per second is enough mdl->setUIValueV("rssi", "%d dBm", WiFi.RSSI()); + mdl->setUIValueV("nwstatus", "Connected %s (e:%s s:%s)", WiFi.localIP().toString().c_str(), ETH.localIP().toString().c_str(), WiFi.softAPIP().toString().c_str()); + initEthernet(); +} + +void SysModNetwork::loop10s() { + if (millis() < 60000) + ppf("%s %s %s\n", WiFi.localIP().toString().c_str(), ETH.localIP().toString().c_str(), WiFi.softAPIP().toString().c_str()); // show IP the first minute } void SysModNetwork::handleConnection() { if (lastReconnectAttempt == 0) { // do this only once ppf("lastReconnectAttempt == 0\n"); - initConnection(); + initConnection(); //WiFi connection return; } @@ -82,11 +192,11 @@ void SysModNetwork::handleConnection() { handleAP(); } - //if not connected to Wifi - if (!(WiFi.localIP()[0] != 0 && WiFi.status() == WL_CONNECTED)) { //!Network.isConfirmedConnection() + //if not connected // || ETH.localIP()[0] != 0 + if (!((WiFi.localIP()[0] != 0 && WiFi.status() == WL_CONNECTED))) { //!Network.isConfirmedConnection() if (isConfirmedConnection) { //should not be confirmed as not connected -> lost connection -> retry ppf("Disconnected!\n"); - initConnection(); + initConnection(); //WiFi connection } //if no connection for more then 6 seconds (was 12) @@ -95,8 +205,8 @@ void SysModNetwork::handleConnection() { initAP(); } } else if (!isConfirmedConnection) { //newly connected - mdl->setUIValueV("nwstatus", "Connected %d.%d.%d.%d", WiFi.localIP()[0], WiFi.localIP()[1], WiFi.localIP()[2], WiFi.localIP()[3]); - ppf("Connected %s\n", WiFi.localIP().toString().c_str()); + mdl->setUIValueV("nwstatus", "Connected %s (e:%s s:%s)", WiFi.localIP().toString().c_str(), ETH.localIP().toString().c_str(), WiFi.softAPIP().toString().c_str()); + ppf("Connected %s %s %s\n", WiFi.localIP().toString().c_str(), ETH.localIP().toString().c_str(), WiFi.softAPIP().toString().c_str()); isConfirmedConnection = true; @@ -184,4 +294,119 @@ void SysModNetwork::handleAP() { } } dnsServer.processNextRequest(); //for captiveportal +} + +typedef struct EthernetSettings { + uint8_t eth_address; + int eth_power; + int eth_mdc; + int eth_mdio; + eth_phy_type_t eth_type; + #ifndef CONFIG_IDF_TARGET_ESP32S3 + eth_clock_mode_t eth_clk_mode; + #endif +} ethernet_settings; + +bool SysModNetwork::initEthernet() { + + if (successfullyConfiguredEthernet) { + // DEBUG_PRINTLN(F("initE: ETH already successfully configured, ignoring")); + return false; + } + + pinsM->deallocatePin(UINT8_MAX, "Eth"); + + uint8_t ethernet = mdl->getValue("ethernet"); + + ethernet_settings es; + + bool result; + + switch (ethernet) { + case 0: //none + return false; + case 1: //manual + { + es = { + mdl->getValue("ethaddr"), // eth_address, + mdl->getValue("ethpower"), // eth_power, + mdl->getValue("ethmdc"), // eth_mdc, + mdl->getValue("ethmdio"), // eth_mdio, + mdl->getValue("ethtype"), // eth_type, + mdl->getValue("ethclkmode") // eth_clk_mode + }; + + } + break; + case 2: //Olimex + { + //WLEDMM: Olimex-ESP32-Gateway (like QuinLed-ESP32-Ethernet + es = { + 0, // eth_address, + 5, // eth_power, + 23, // eth_mdc, + 18, // eth_mdio, + ETH_PHY_LAN8720, // eth_type, + ETH_CLOCK_GPIO17_OUT // eth_clk_mode + }; + } + break; + default: + es = { + 0, // eth_address, + 5, // eth_power, + 23, // eth_mdc, + 18, // eth_mdio, + ETH_PHY_LAN8720, // eth_type, + ETH_CLOCK_GPIO17_OUT // eth_clk_mode + }; + } + + // looks like not needed until now (at least not for Olimex) + // if(es.eth_power>0 && es.eth_type==ETH_PHY_LAN8720) { + // pinMode(es.eth_power, OUTPUT); + // digitalWrite(es.eth_power, 0); + // delayMicroseconds(150); + // digitalWrite(es.eth_power, 1); + // delayMicroseconds(10); + // } + + pinsM->allocatePin(es.eth_power, "Eth", "power"); + pinsM->allocatePin(es.eth_mdc, "Eth", "mdc"); + pinsM->allocatePin(es.eth_mdio, "Eth", "mdio"); + + // update the clock pin.... + if (es.eth_clk_mode == ETH_CLOCK_GPIO0_IN) { + pinsM->allocatePin(0, "Eth", "clock"); + } else if (es.eth_clk_mode == ETH_CLOCK_GPIO0_OUT) { + pinsM->allocatePin(0, "Eth", "clock"); + } else if (es.eth_clk_mode == ETH_CLOCK_GPIO16_OUT) { + pinsM->allocatePin(16, "Eth", "clock"); + } else if (es.eth_clk_mode == ETH_CLOCK_GPIO17_OUT) { + pinsM->allocatePin(17, "Eth", "clock"); + } else { + ppf("dev initE: Failing due to invalid eth_clk_mode (%d)\n", es.eth_clk_mode); + return false; + } + + if (!ETH.begin( + (uint8_t) es.eth_address, + (int) es.eth_power, + (int) es.eth_mdc, + (int) es.eth_mdio, + (eth_phy_type_t) es.eth_type, + (eth_clock_mode_t) es.eth_clk_mode + )) { + ppf("initC: ETH.begin() failed\n"); + // de-allocate the allocated pins + // for (managed_pin_type mpt : pinsToAllocate) { + // pinManager.deallocatePin(mpt.pin, PinOwner::Ethernet); + // } + return false; + } + + successfullyConfiguredEthernet = true; + ppf("initC: *** Ethernet successfully configured! %s ***\n", ETH.localIP().toString().c_str()); // WLEDMM + return true; + } \ No newline at end of file diff --git a/src/Sys/SysModNetwork.h b/src/Sys/SysModNetwork.h index 61e8c325..e32b9ebb 100644 --- a/src/Sys/SysModNetwork.h +++ b/src/Sys/SysModNetwork.h @@ -23,6 +23,7 @@ class SysModNetwork:public SysModule { void setup(); void loop1s(); + void loop10s(); void handleConnection(); void initConnection(); @@ -30,7 +31,8 @@ class SysModNetwork:public SysModule { void handleAP(); void initAP(); void stopAP(); - + bool initEthernet(); + private: bool apActive = false; unsigned32 lastReconnectAttempt = 0; @@ -38,6 +40,9 @@ class SysModNetwork:public SysModule { bool isConfirmedConnection = false; DNSServer dnsServer; byte stacO = 0; //stationCount + + bool successfullyConfiguredEthernet = false; //currently only one call to ETH.begin is possible, wether successful or not: reboot needed for other attempt + }; extern SysModNetwork *net; \ No newline at end of file diff --git a/src/Sys/SysModPins.cpp b/src/Sys/SysModPins.cpp index b8591856..f7266abc 100644 --- a/src/Sys/SysModPins.cpp +++ b/src/Sys/SysModPins.cpp @@ -35,6 +35,8 @@ void SysModPins::setup() { ui->initPin(tableVar, "pinNr", UINT16_MAX, true, [this](JsonObject var, unsigned8 rowNr, unsigned8 funType) { switch (funType) { //varFun case onSetValue: + var.remove("value"); + ppf("pinNr onSetValue %s %d\n", var["value"].as().c_str(), getNrOfAllocatedPins()); for (forUnsigned8 rowNr = 0; rowNr < getNrOfAllocatedPins(); rowNr++) mdl->setValue(var, getPinNr(rowNr), rowNr); return true; @@ -46,6 +48,7 @@ void SysModPins::setup() { ui->initText(tableVar, "pinOwner", nullptr, 32, true, [this](JsonObject var, unsigned8 rowNr, unsigned8 funType) { switch (funType) { //varFun case onSetValue: + var.remove("value"); for (forUnsigned8 rowNr = 0; rowNr < getNrOfAllocatedPins(); rowNr++) mdl->setValue(var, JsonString(getNthAllocatedPinObject(rowNr).owner, JsonString::Copied), rowNr); return true; @@ -57,6 +60,7 @@ void SysModPins::setup() { ui->initText(tableVar, "pinDetails", nullptr, 256, true, [this](JsonObject var, unsigned8 rowNr, unsigned8 funType) { switch (funType) { //varFun case onSetValue: + var.remove("value"); for (forUnsigned8 rowNr = 0; rowNr < getNrOfAllocatedPins(); rowNr++) { // ppf("pinDetails[%d] d:%s\n", rowNr, getNthAllocatedPinObject(rowNr).details); mdl->setValue(var, JsonString(getNthAllocatedPinObject(rowNr).details, JsonString::Copied), rowNr); @@ -143,14 +147,17 @@ void SysModPins::allocatePin(unsigned8 pinNr, const char * owner, const char * d } void SysModPins::deallocatePin(unsigned8 pinNr, const char * owner) { - ppf("deallocatePin %d %s\n", pinNr, owner); - if (pinNr < NUM_DIGITAL_PINS) { - if (strcmp(pinObjects[pinNr].owner, owner) != 0) - ppf("deallocatePin %d: not owner %s!=%s", pinNr, owner, pinObjects[pinNr].owner); - else { - strcpy(pinObjects[pinNr].owner, ""); - strcpy(pinObjects[pinNr].details, ""); - pinsChanged = true; + for (int p = 0; p