PicoC: String auswerten, Code frisst sich

Einklappen
X
 
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge
  • Benjamin Jobst
    Lox Guru
    • 25.08.2015
    • 1194

    #1

    PicoC: String auswerten, Code frisst sich

    Hallo zusammen,

    heute hätte ich einmal wieder ein kleines Rätsel für alle PicoC-Profis unter uns!

    Folgende Situation:
    Ich erzeuge mit einem separaten Programm-Baustein aus einem Wetter-Service (aerisapi) einen String mit 24 Temperatur-Werten, den ich über Text-Ausgang und -Eingang des Programmbausteins in mein Hauptprogramm übertrage. Die einzelnen Werte sind mit Semikolon voneinander getrennt. Der String sieht folgendermaßen aus:


    12;13;13;13;13;12;11;9;9;9;9;8;8;7;7;7;6;7;7;7;9;1 1;13;13;
    Als nächstes möchte ich diesen String wieder in die 24 einzelnen Werte auftrennen und die Temperaturen in einem int-Array ablegen. Dazu habe ich die folgende Funktion aufgebaut:

    //Temperaturprognosen importieren und im globalen arrayTProg ablegen
    void func_ImportTemps()
    {
    char * strTemps;
    char strVal[3];
    int itempPos;

    strTemps=getinputtext(0);

    for (int i=0;i<constProgStunden;i++)
    {
    itempPos=strfind(strTemps,";",0);
    strncpy(strVal,strTemps,itempPos);
    arrayTProg[i]=batoi(strVal);
    strTemps=strstrskip(strTemps,";");
    }
    free(strTemps);
    //free(strVal);
    }
    Nun läuft der Code per se eigentlich ganz passabel, allerdings nicht ganz langzeit-stabil. Nach einigen Stunden (irgendwie immer kurz, nachdem ich aufhöre, das System zu beobachten und mit mit der Config trenne??) bleibt der Code ohne Fehlermeldung hängen und jagt die CPU-Auslastung des MS auf 99%.
    Ursprünglich dachte ich an ein Allokations-Problem durch die Pointer, die ich anlege bzw. die in der Funktion entstehen, allerdings läuft in solchen Fällen eine explizite "alloc"-Fehlermeldung auf. Die bleibt hier aus...
    Wenn ich die Funktion auskommentiere und den restlichen Code laufen lasse, bleibt dieser Fehler anscheinend aus.


    Im Monitor konnte ich bisher keine Fehlermeldung finden. Cycle duration liegt bei ca. 80-100us, Contextswitches:0. Das sind quasi alle Meldungen, die aufploppen bei "Mehr Info" für Allgemein, Programm und Datei.

    Jetzt bin ich mit meinem bisher angelernten PicoC-Wissen am Ende. Da der Wetterdienst mehr als nur die Temperaturen liefert, würde ich ihn gerne getrennt stehen lassen und nur die Temperaturen übergeben.
    Fällt jemandem von euch da noch etwas ein, woran sich das Programm fressen könnte bzw. wie man das umgehen kann?




    Wäre sehr dankbar ;-)
    Zuletzt geändert von Benjamin Jobst; 24.09.2015, 08:54.
    MfG Benny
  • svethi
    Lebende Foren Legende
    • 25.08.2015
    • 6313

    #2
    Irgendwie scheint da was zu fehlen, oder wofür soll die 2. einleitende geschweifte Klammer sein??
    Ich vermute mal, dass Du da eine Schleifen hast. Und in dieser Schleifen legst Du dann immer wieder ein Array an??

    Gruß Sven


    mal eben von unterwegs ...
    Miniserver; KNX; Vitogate; EnOcean (EnOceanPi); Loxone Air; Caldav-Kalenderanbindung; RaspberryPi und für keine Frickellösung zu schade :-)

    Kommentar

    • kerrick
      Smart Home'r
      • 03.09.2015
      • 91

      #3
      Ich hab den code mal auf coliru getestet (Spezialfunktionen nach bestem Wissen selbst implementiert): http://coliru.stacked-crooked.com/a/fc5eb3a0f803f351

      Folgende Punkte sind mir aufgefallen:
      • Du prüfst nicht, ob itempPos gültig ist, d.h. kein ";" mehr da ist.
      • du leerst strVal[] nicht. D.h. wenn "11" gelesen wurde und danach "9", dann wird daraus eine 91.

      Der erste Punkt könnte undefiniertes Verhalten veruarsachen und damit möglicherweise der Grund für dein Problem sein. Tritt aber eigentlich nur auf, wenn am Input etwas anders ist als du erwartest.

      Edit: Da fällt mir auch noch ein:
      • dass "1 1" aus deinem Beispiel zu 1 wird. Weiß nicht, ob das so gewollt ist, bzw. ob "1 1" gültiger Input ist.
      • Zahlen mit mehr als 3 Stellen auch undefiniertes Verhalten hervorrufen werden.

      Zuletzt geändert von kerrick; 24.09.2015, 11:04.

      Kommentar

      • Benjamin Jobst
        Lox Guru
        • 25.08.2015
        • 1194

        #4
        @kerrick: Danke für die Infos, das sint schon mal gute Inputs.

        Das mit dem leeren von strVal[ ] habe ich tatsächlich verschwitzt...
        Was die erwarteten Werte angeht: Eine Validierung habe ich im Moment nicht implementiert, da meine auflaufenden Daten zuverlässig nach dem Muster aus Integer-Werten generiert werden. Beim Testen kann ich meine Daten schnell überprüfen, sollte ein Fehler auftreten, deshalb habe ich hier weitesgehend darauf verzichtet... wird aber natürlich (in begrenzem Umfang) noch implementiert.
        Mit dem fehlenden ";" hast du Recht, habe ich jetzt "nachgerüstet", aber das sollte m.M.n. nicht für den Fehler verantwortlich sein, da meine bisher ausgegebenen Werte immer ein ; am Ende aufwiesen.
        Mehr als 3 Stellen werden bei mir auch nicht vorkommen, da Temperatur-Werte in Form von Integer.

        Ich hatte schon einmal Probleme mit den String-verarbeitenden Funktionen, damals konnte ich aber ein Workaround finden. Hier ist mir bisher kein passendes eingefallen. Ich würde die Werte auch gerne ohne den Umweg über einen String verarbeiten, aber mir ist noch keine saubere Lösung eingefallen - ein Umweg über Virtuelle Eingänge ist auch fehleranfällig...
        MfG Benny

        Kommentar

        • kerrick
          Smart Home'r
          • 03.09.2015
          • 91

          #5
          Dann sehe ich noch, dass du
          Code:
          free(strTemps)
          aufrufst. Habe mal die Doku überflogen aber in der Funktionsbeschreibung nichts gefunden was besagt, man müsse den Speicher freigeben. Steht das irgendwo anders als allgemeiner Hinweis? Kenne mich da nicht gut aus.
          Wenn du Speicher freigibst, der dir nicht gehört, könnten auch schlimme Dinge passieren.

          Kommentar

          • Benjamin Jobst
            Lox Guru
            • 25.08.2015
            • 1194

            #6
            PicoC-Doku:
            • All functions which return a pointer must reallocate the memory with free (), unless the pointer was passed as a parameter.
            Ohne free() habe ich eben das Problem
            :140:32 out of memory (Alloc)
            MfG Benny

            Kommentar

            • Blinket
              Azubi
              • 28.08.2015
              • 4

              #7
              Hallo, hier einmal ein anderer Ansatz. macht das gleiche, jedoch wird hier nur der Pointer inkrementiert.

              Code:
              void func_ImportTemps()
              {
                  static const int MAX_SIZE_FOR_VALUE = 5;
              
                  char* pszDelimiter = ";";
                  int iDelimiterLength = 1;
                  
                  char pszCurrentTemperature[MAX_SIZE_FOR_VALUE];
                  int iInputBufferLen = 0;
                  int iCurrentPositionInArray = 0;
              
                  char* pszInputBuffer = getinputtext(0);
                  iInputBufferLen = strlen(pszInputBuffer);
              
                  if (iInputBufferLen > 0)
                  {
                      char* pszCurrentValue = strstr(pszInputBuffer, pszDelimiter);
              
                      while (pszCurrentValue != NULL)
                      {
                          memcpy(pszCurrentTemperature, pszInputBuffer, (pszCurrentValue - pszInputBuffer));
                          pszCurrentTemperature[pszCurrentValue - pszInputBuffer] = '\0';
              
                          if (strlen(pszCurrentTemperature) > 0 && (iCurrentPositionInArray < MAX_ARRAY_VALUES))
                          {
                              anValues[iCurrentPositionInArray] = atoi(pszCurrentTemperature);
                              ++iCurrentPositionInArray;
                          }
              
                          pszInputBuffer = pszCurrentValue + iDelimiterLength;
                          pszCurrentValue = strstr(pszInputBuffer, pszDelimiter);
                      }
                  }
              
                  // All functions which return a pointer must reallocate the memory with free (), unless the pointer was passed as a parameter.
                  // See: http://www.loxone.com/dede/service/dokumentation/loxone-config/programm/programm.html#Underlying
                  free(pszInputBuffer);
              }
              Eine paar Fragen stellen sich mir noch, wenn die Auslastung so hoch geht. Wie oft wird die Funktion aufgerufen? Wird wenn es mehrere male passiert der sleep() aufgerufen der empfohlen wird um die CPU nicht zu überlasten?

              Kommentar

              • Jan W.
                Lox Guru
                • 30.08.2015
                • 1369

                #8
                Hallo Benny,

                hier noch ein paar Anmerkungen: Du setzt strTemps=getinputtext(0); und musst daher den allokierten Speicher mit free wieder freigeben. Das hast Du ja in Post #6 noch mal richtig dargestellt. Allerdings änderst Du die Variable IN der Schleife (strstrskip) und somit gibt das free NACH der Schleife nur den letzten allokierten Speicher wieder frei. Hier sind wohl 2 Variablen notwendig.

                Gruß Jan
                Zuletzt geändert von Jan W.; 25.09.2015, 01:01.
                Miniserver v14.5.12.7, 2x Ext., 2x Relay Ext., 2x Dimmer Ext., DMX Ext., 1-Wire Ext., Gira KNX Tastsensor 3 Komfort, Gira KNX Präsenzmelder, Fenster- und Türkontakte, Loxone Regen- und Windsensor, Gira Dual Q Rauchmelder vernetzt, 1x Relais-Modul
                Loxberry: SmartMeter, MS Backup, CamConnect, Weather4Lox
                Lüftung: Helios KWL EC 370W ET mit Modbus TCP - via Pico-C
                Heizung: Stiebel Eltron WPF 5 cool (Sole-Wasser WP) mit ISG, FB-Heizung mit 18 Kreisen, Erdsonde - via modbus/TCP
                Node-RED: IKEA Tradfri

                Kommentar

                • Benjamin Jobst
                  Lox Guru
                  • 25.08.2015
                  • 1194

                  #9
                  Hallo Jan,

                  danke für die Info. Dass mit free() nur noch der dann verbleibende verknüpfte Bereich wieder freigegeben wird, habe ich so nicht bedacht...
                  Ich habe meine Übergabe jetzt komplett umgestellt und eindeutige Identifier für jeden Wert davor gesetzt. Dadurch kann ich mit strfind() einfacher arbeiten, da ich jetzt nicht das x-te ";" suchen muss... Mal sehen, ob das jetzt stabil läuft.
                  MfG Benny

                  Kommentar

                  • Benjamin Jobst
                    Lox Guru
                    • 25.08.2015
                    • 1194

                    #10
                    So, ein Update: Nach der Umstellung lief der Code erst mal so wie er sollte.
                    Jetzt habe ich noch ein paar Teile hinzugefügt und auf einmal kommt etwas auch für mich ganz neues:
                    Der erste Programmdurchlauf geht ohne Probleme, beim zweiten Durchlauf bekomme ich die Fehlermeldung "variable xx is undefined". Bei der angeblichen Variablen handelt es sich dabei abwechselnd um die Funktion httpget(), printf() oder um eine tatsächliche char-variable. An der Definition selbst kann es also nicht liegen.
                    Hat vielleicht jemand eine Idee, woran es hier scheitern könnte?
                    MfG Benny

                    Kommentar

                    Lädt...