wdt reset load 0x4010f000, len 1384, room 16 tail 8 chksum 0x2d csum 0x2d v951ae

Du musst auch nicht mein Programm umschreiben, ich soll ja etwas lernen.
Ich werde versuchen mit deinem Beispielprogramm mein Programm umzuschreiben.
Super, großes Danke combie!

Ob man hier jetzt Funktionszeiger verwenden muss ist fraglich. Ich habe das hier schon als Alternative gezeigt, aber praktisch verwendet hier jeder switch/case. Auch wenn es anders vor allem bei komplizierten Abläufen damit schöner geht. Bei kleinen Projekten ist switch/case aber ok.

Das große Vorteil ist halt das die Logik mit den Zustandswechseln in den Funktionen ist und man keine externe Kontrollstruktur braucht. Kleine switch/case Konstrukte sind recht übersichtlich. Aber große sind es nicht

Eine andere Möglichkeit ist es die nächste Funktion in den Rückgabe-Wert zu packen

struct nextFunc
{
  nextFunc(*next)(void);  //Zeiger auf Funktion ohne Parameter die ein nextFunc struct zurück gibt
};

//Hilfsfunktion um Funktion in struct zu verpacken. Funktion übergeben um struct zu bekommen.
inline nextFunc getNext(nextFunc(*func)(void))
{
  nextFunc next = { func };
  return next;
}

unsigned long printMillis;    //Verzögerung für Serial Ausgabe. Könnte auch LED blinken o.ö. sein
unsigned long funcMillis;     //Verzögerung für Funktionswechsel

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  static nextFunc next = { function1 }; //Zeiger auf nächste Funktion. Wird mit Start-Funktion initalisiert
  next = next.next(); //Zeiger auf nächste Funktion holen und aufrufen. Rückgabewert abspeichern
}

bool checkTimer(unsigned long& previousMillis, const unsigned long interval)
{
  if (millis() - previousMillis > interval)
  {
    previousMillis = millis();
    return true;
  }
  else
    return false;
}

struct nextFunc function1()
{
  
  if (checkTimer(printMillis, 1000))
    Serial.println("Function 1");

  if (checkTimer(funcMillis, 5000))   //wenn Zeit abgelaufen nächste Funktion zurückgeben
    return getNext(function2);
  else
    return getNext(function1);  //gleiche Funktion aufrufen
}

struct nextFunc function2()
{
  if (checkTimer(printMillis, 1000))
    Serial.println("Function 2");

  if (checkTimer(funcMillis, 3000))
    return getNext(function1);
  else
    return getNext(function2);
}

Das Trick mit dem struct ist notwendig damit keine rekursive Definition hat. Ohne das müsste man einen Funktionszeiger auf eine Funktion definieren die einen Zeiger zurückgibt den man gerade definieren will.
Alternativ kann man einen void-Zeiger zurückgeben, aber den muss man dann auf die eigentliche Funktion casten. Das ist nicht schön

Den Timer Kram kann man auch anders machen. Ich wollte nur das während der Funktionsausführung was gemacht wird und man den Wechsel sieht

Es gibt noch eine weitere Variante mit einer Zustandstabelle. Da kann man auch schön getrennte Funktionen für den eigentlichen Zustand und den Übergang angeben. Und man hat alle Aktionen einem Array, wodurch man sofort eine Übersicht hat was insgesamt geschieht. Die Logik ist aber doch recht kompliziert und für kleine Projekte ist es etwas übertrieben. Bei komplizierten Abläufen ist es aber besser

Ob man hier jetzt Funktionszeiger verwenden muss ist fraglich.

Sicherlich!
Es gibt einige Möglichkeiten Automaten zu bauen,....

Hier störte mich hauptsächlich die Bezeichnerwahl.
Die passte/passt nun gar nicht zu meiner CodeLeseMusterErkennung.

Danke combie und Serenifly für eure Tipps für den endlichen Automat!
Sie werden die Basis für meine nächsten Programme.

Habe nun die Statemachine/Schrittkette des Programms mit Funktionspointern nach dem Beispiel von combie geändert. Durch das einfache Beispiel hat es prima geklappt!
Leider will das Programm trotzdem nicht so recht… :
Wenn die Wlan Verbindung getrennt wird, dann hängt sich nach einer gewissen Zeit das Programm leider auf und startet von neuem.
Kann es sein, dass es mit der NTP Zeit Abfrage zusammenhängt?
Habe das Programm in der Anlage. Könnt ihr den Fehler entdecken?
Bedanke mich schon im Voraus für eure Hilfe und Geduld!

P.S. Zudem bin ich für eventuelle Tipps und Tricks immer offfen.

main.cpp (19.1 KB)

Hi

Was passiert, wenn Du per WLan eine Anfrage abschickst (abschicken willst), es aber gar kein WLan gibt?
Wenn Das blockierend wirkt, wird im nächsten Schritt der Wachhund bissig - könnte Das So zusammen hängen?

Vll. nur was per WLan versenden, wenn sicher gestellt ist, daß wir auch 'Drin' sind.

MfG

Netzverbindungen können schon mal etwas länger dauern, auch wenn man "drin" ist.

Da sollte dann der yield()-Aufruf in der Warteroutine auf die Antwort rein (zur Not die Lib anpassen).
Das habe ich bei der Direktzugriffslib für MySQL auch gemacht und zusätzlich eine Methode eingebaut, die mir mitteilt, ob es einen Timeout gab.

Gruß Tommy

@postmaster-ino:
Danke für deiner schnellen Info.
Da ich mich auf ein Beispiel Sketch gestützt habe war ich der Meinung, dass der Ausfall der WLAN Verbindung "intern" mitberücksichtigt wurde. Also den "bösen Hund" werde ich mal versuchen zu "beruhigen" :smiley:

@Tommy56:
Danke für deiner schnellen Info.
Wo würdest du persönlich den yield()-Aufruf in dem NTP-Code einfügen? Also brauche ich deiner Meinung nach nicht unbedingt eine WLAN Verbindung Abfrage einzubauen und es sollte nur mit dem yield() ausreichen.

Hi

yield() beruhigt den Wachhund - Es ändert Nichts daran, daß Du 'hängen bleibst', wenn das Versenden mangels vorhandenem WLan nicht funktioniert.
yield(); wird übrigens auch innerhalb delay(); aufgerufen, ein delay(0); sollte somit das Gleiche machen.

MfG

LOOIIS:
@Tommy56:
Wo würdest du persönlich den yield()-Aufruf in dem NTP-Code einfügen? Also brauche ich deiner Meinung nach nicht unbedingt eine WLAN Verbindung Abfrage einzubauen und es sollte nur mit dem yield() ausreichen.

Wenn Du schon keine WLAN-Verbindung hast, hat die Abfrage ja keinen Sinn.
Nur das yield() kann nur bei langsamer Verbindung helfen. Nebenher musst Du die Zeit erfassen, um einen Timeout zu erkennen. das ist aber in getNtpTime schon drin. Das yield() könnte vor oder nach Udp.parsePacket().

Gruß Tommy

Also ist das Beste ich mache eine Kombination aus einer WLAN Verbindung Abfrage in Kombination mit einem yield() / delay().
Habe es jetzt so verscuht zu lösen, mal sehen ob es klappt…

/*-------- NTP code ----------*/

const int NTP_PACKET_SIZE = 48; // NTP time is in the first 48 bytes of message
byte packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming & outgoing packets

time_t getNtpTime()   {
  IPAddress ntpServerIP; // NTP server's ip address
  static uint8_t num = 0;  // Nummer des NTP-Pool-Servers 4 für Fehlertest
  spf("Connected: %s\r\n", WiFi.status() == WL_CONNECTED ? "yes" : "no");
  if (WiFi.status() == WL_CONNECTED) {     //NTP-Abfrage nur bei WLAN Verbindung
  yield();      //um den Watch Dog Timer bei langsamer Internetverbindung in den Griff zu halten in Verbindung mit einem Timeout (noch zu machen bzw getNTPTime hat es bereits enthalten)!!!!
  while (Udp.parsePacket() > 0) ; // discard any previously received packets
  spn("Transmit NTP Request");
  // get a random server from the pool
  spn(num);
  WiFi.hostByName(ntpServerName[num], ntpServerIP);
  sp(ntpServerName[num]);
  sp(": ");
  spn(ntpServerIP);
  sendNTPpacket(ntpServerIP);
  uint32_t beginWait = millis();
  while (millis() - beginWait < 1500) {
    int size = Udp.parsePacket();
    if (size >= NTP_PACKET_SIZE) {
      spn("Receive NTP Response");
      Udp.read(packetBuffer, NTP_PACKET_SIZE);  // read packet into the buffer
      unsigned long secsSince1900;
      // convert four bytes starting at location 40 to a long integer
      secsSince1900 =  (unsigned long)packetBuffer[40] << 24;
      secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
      secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
      secsSince1900 |= (unsigned long)packetBuffer[43];
      lastSyncTime = secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR;
      newSync = true;
      return lastSyncTime;
    }
  }
  
  spn("No NTP Response :-(");
  num = ++num %4;
  }
  now();
  
  return 0; // return 0 if unable to get the time
}

Du hast von den beiden parsePacket leider genau das falsche als Bezugspunkt genutzt :wink:
Vesser so:

/*-------- NTP code ----------*/

const int NTP_PACKET_SIZE = 48; // NTP time is in the first 48 bytes of message
byte packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming & outgoing packets

time_t getNtpTime()   {
  IPAddress ntpServerIP; // NTP server's ip address
  static uint8_t num = 0;  // Nummer des NTP-Pool-Servers 4 für Fehlertest
  spf("Connected: %s\r\n", WiFi.status() == WL_CONNECTED ? "yes" : "no");
  if (WiFi.status() == WL_CONNECTED) {     //NTP-Abfrage nur bei WLAN Verbindung
Verbindung mit einem Timeout (noch zu machen bzw getNTPTime hat es bereits enthalten)!!!!
  while (Udp.parsePacket() > 0) ; // discard any previously received packets
  spn("Transmit NTP Request");
  // get a random server from the pool
  spn(num);
  WiFi.hostByName(ntpServerName[num], ntpServerIP);
  sp(ntpServerName[num]);
  sp(": ");
  spn(ntpServerIP);
  sendNTPpacket(ntpServerIP);
  uint32_t beginWait = millis();
  while (millis() - beginWait < 1500) {
    int size = Udp.parsePacket();
    yield();      //um den Watch Dog Timer bei langsamer Internetverbindung in den Griff zu halten in 
    if (size >= NTP_PACKET_SIZE) {
      spn("Receive NTP Response");
      Udp.read(packetBuffer, NTP_PACKET_SIZE);  // read packet into the buffer
      unsigned long secsSince1900;
      // convert four bytes starting at location 40 to a long integer
      secsSince1900 =  (unsigned long)packetBuffer[40] << 24;
      secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
      secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
      secsSince1900 |= (unsigned long)packetBuffer[43];
      lastSyncTime = secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR;
      newSync = true;
      return lastSyncTime;
    }
  }
 
  spn("No NTP Response :-(");
  num = ++num %4;
  }
  now();
 
  return 0; // return 0 if unable to get the time
}

Gruß Tommy

Musste ja falsch sein :disappointed_relieved:
...zum Glück gibt es euch Profis, welche uns Leihen immer wieder tatkräftig und sehr rasch bei der Umsetzung unserer Projekte mit Wissen, Erfahrung, Tipps und Tricks unterstützen und dabei auch die nötige Geduld haben!!!
Nochmals großes Danke!
TOP Forum mit TOP Leuten!!! 8) 8) 8)

Leider hat die WLAN Verbindung Abfrage nicht den gewünschten Erfolg gebracht… :fearful:
Wenn die Wlan Verbindung getrennt wird, dann hängt sich nach einer gewissen Zeit das Programm leider auf und startet von neuem…
Kann ich irgendwie herausfinden wer den Reset auslöst bzw. wo das Programm hängen bleibt?

Entweder über den ESP-Exception-Decoder oder die Boot-Meldungen.

Gruß Tommy

Kann ich irgendwie herausfinden wer den Reset auslöst bzw. wo das Programm hängen bleibt?

In der Bootmeldung des ESP wird dir der Resetgrund mitgeteilt.
Und bei Exceptions auch der genaue Ort des Auftretens.

Und, dass langlaufende Schleifen Gift sind, hast du ja mittlerweile mitbekommen.
Diese sollte man rigoros eliminieren, statt überall yield() einzustreuen.
Alle Blockaden entfernen.

Der ESP schafft locker 1/4 Million loop() Durchläufe pro Sekunde, wenn man ihm die Chance gibt.

Das ist völlig richtig.
Leider ist man bei Netzwerkzugriffen nicht der Einzige, der die Geschwindigkeit bestimmt.

Gruß Tommy

Leider ist man bei Netzwerkzugriffen nicht der Einzige, der die Geschwindigkeit bestimmt.

Wohl wahr!
Und genau darum sollte man den Hintergrund Prozessen genügend Zeit zu billigen.

Z.B. den NTP Request Zyklus (eigentlich auch alles andere) in Stücke hacken und von einem endlichen Automaten abhandeln lassen.
So geht der goldene Weg auf einem System, welches auf kooperativem Multitasking beruht.

Unter einem Präemptiven OS kann man das anders gestalten. Da verursacht ein lang laufender Programm Abschnitt nicht solche Schmerzen.

Danke für eure Hilfsbereitschaft bzw. Infos.
Habe "nur" die Bootmeldungen bekommen:

Sketchname: src\main.cpp
Build: Mon Jun 10 21:13:48 2019
SDK:3.0.0-dev(c0f7b44)/Core:2.5.0=20500000/lwIP:STABLE-2_1_2_RELEASE/glue:1.1/BearSSL:6778687

....Connected: yes

 Connected to FRITZ!Box 4020 UT
IP address: XXXXXX
Starting UDP
Local port: 8888
Connected: yes
Transmit NTP Request
0
1.de.pool.ntp.org: 81.7.16.52
No NTP Response :-(
Connected: yes
Transmit NTP Request
1
2.de.pool.ntp.org: 62.113.233.18
No NTP Response :-(
Connected: yes
Transmit NTP Request
2
3.de.pool.ntp.org: 217.79.179.106
No NTP Response :-(
Connected: yes
Transmit NTP Request
3
4.de.pool.ntp.org: 4.0.0.0
No NTP Response :-(
Connected: yes
Transmit NTP Request
0
1.de.pool.ntp.org: 81.7.16.52
No NTP Response :-(
Connected: yes
Transmit NTP Request
1
2.de.pool.ntp.org: 62.113.233.18
No NTP Response :-(
Connected: no
….
….
Connected: no


 ets Jan  8 2013,rst cause:4, boot mode:(3,7)

wdt reset
load 0x4010f000, len 1384, room 16 
tail 8
chksum 0x2d
csum 0x2d
v951aeffa
~ld

Wie bekommt man auch die ESP-Exception?

@combie:
Wie würdest du also den NTP Request modular aufbauen?

Das mit den Codetags konntest Du schon mal.

Gruß Tommy