Zuviel Werbung? - > Hier kostenlos beim SPS-Forum registrieren

Ergebnis 1 bis 4 von 4

Thema: Probleme beim CSV Datei schreiben mit ByteArray auf WAGO 750-8202

  1. #1
    Registriert seit
    06.12.2018
    Beiträge
    2
    Danke
    2
    Erhielt 0 Danke für 0 Beiträge

    Unglücklich


    Zuviel Werbung?
    -> Hier kostenlos registrieren
    Hey zusammen,
    ich bin relativ neu in der SPS Welt und versuche gerade mit Hilfe der WAGO Beispiel Syslibfile.lib Projekte eigene CSV Dateien schreiben zu lassen.
    Umgesetzt wird das Projekt auf einem WAGO 750-8202 und in CoDeSys 2.3 programmiert.

    tl;dr:
    In den erfolgreich geschriebenen Dateien finde ich nach dem Block aus Zeitangabe, Werten und Zeilenabschluss-Steuerzeichen zusätzliche Zeichen, welche dort ungewollt geschrieben wurden.
    Könnte der Fehler in meiner Zeigerarithmetik liegen?


    Langfassung:
    In einer WerteGenerieren()-Funktion wird mir ein selbstdefinierter Datentyp befüllt: Darin ein eindimensionales Array mit 10 Werten (gc_ColumnCount := 9 global definiert) und die aktuelle Systemzeit:
    Code:
    TYPE typCSV :
        STRUCT
            dtTageszeit:DT;
            Wert:ARRAY[0..gc_ColumnCount] OF REAL;
        END_STRUCT
    END_TYPE
    Danach wird in einem Konvertierungs-Funktionsblock die Umwandlung von typCSV (EingangsArray) in ein ByteArray vorgenommen.
    Dazu lasse ich das ByteArray: ARRAY[0..gc_RawDataSize] OF BYTE vor jeder Ausführung löschen und nutze im Anschluss die Zeigerarithmetik aus dem WAGO Beispiel Projekt:
    Code:
    FOR z:=0 TO gc_RawDataSize BY 1 DO                                       (* ByteArray löschen *)
        ByteArray[z] := 0;
    END_FOR
    
    ptString := ADR(ByteArray);                                                        (* Pointer auf Anfang des Bytearrays *)
    index := 0;
    
    ptString^ := DT_TO_STRING(EingangsArray.dtTageszeit);                        (* Zeitstempel --> Bytefeld *)
    index := index + LEN(ptString^);                                                    (* feststellen wieviel Byte benutzt sind *)
    ptString := ADR(ByteArray[index]);                                                    (* Pointer auf Ende des Wertes *)
    
    FOR i:=0 TO gc_ColumnCount BY 1 DO
        ptString^:= trenner;                                                            (* Trennzeichen hinter letzten Wert *)
        index := index + LEN(ptString^);
        ptString := ADR(ByteArray[index]);
    
        ptString^ := REAL_TO_STRING(EingangsArray.Wert[i]);                        (* Wert in ByteArray schreiben *)
        index := index + LEN(ptString^);
        ptString := ADR(ByteArray[index]);
    END_FOR
    
    ptString^:= '$r$n';                                                                    (* new line *)
    index := index + LEN(ptString^);
    ptString := ADR(ByteArray[index]);
    Das ByteArray ist natürlich um einiges größer (durch gc_RawDataSize := 100 global festgelegt) als die Summer aller zu schreibenden Werte (usw.) in Byte.

    Der Konvertierungs-Funktionsblock wird im Programm Dateischreiben aufgerufen. Beim Aufruf der Konvertierungsinstanz wird auch die WerteGenerieren()-Funktion aufgerufen.
    Das zurückgegebene ByteArray wird nun wie folgt geschrieben:
    Code:
    Konvertierungsinstanz(trenner:= ';', EingangsArray:= WerteGenerieren(), convert_ready=> , ByteArray=> );
    
    groesse := SysFileGetSize(g_sDateiname);                                            (* Größe der Datei feststellen *)
    IF Konvertierungsinstanz.convert_ready THEN
        handle := SysFileOpen(g_sDateiname, g_zugriff);                                    (* g_zugriff wird mit 'a' initialisiert *)                                                                                           
        groesse := groesse + SysFileWrite(handle, ADR(Konvertierungsinstanz.ByteArray),SIZEOF(Konvertierungsinstanz.ByteArray));
        file_ok := SysFileClose(handle);                                                    (* Datei schließen *)
    END_IF
    Nach dem Schreiben steht alles Gewünschte in der erzeugten / erweiterten Datei.

    Mein Problem ist, dass nach einem Null-Byte hinter dem Zeilenende-Steuerzeichen ein abgehacktes Datum (15 Byte lang) vom Format DATE_AND_TIME folgt.
    Am Besten zu sehen in einem Hex-Editor (Das Markierte ist der unbewusst geschriebene Datumsteil):
    Datei.JPG

    Es ist hinter jedem geschriebenen Daten(ByteArray)block. Manchmal fehlen die Zeichen, manchmal stehen dort irgendwelche Zeichen, aber kein Datum... dann sogar im Null-Teil nach hinten verschoben.
    Habe ich bei meiner Zeigerarithmetik einen Fehler gemacht oder ist es ein anderer Fehler?
    Könnte es auch eine WAGO/Controller spezifische Beschränkung geben, welche ich übersehe?

    Ich lasse extra bei jedem Konvertierungsaufruf das ByteArray aufs neue mit Nullen beschreiben, von daher kann ich mir nicht erklären, warum hinter den Zeilenende-Steuerzeichen keine Nullen stehen...

    Gibt es vielleicht eine andere Methode mein ByteArray zu füllen/ zu löschen oder sollte ich es mit Strings schreiben versuchen?
    Ich will allerdings später viel mehr Werte schreiben, sodass die allgemeine String Längenbeschränkung ein Problem darstellt.

    Vielen Dank für eure Hilfe.
    MfG
    TiI
    Geändert von TiI (06.12.2018 um 18:38 Uhr)
    Zitieren Zitieren Probleme beim CSV Datei schreiben mit ByteArray auf WAGO 750-8202  

  2. #2
    Registriert seit
    13.12.2011
    Beiträge
    2.082
    Danke
    233
    Erhielt 279 Danke für 248 Beiträge

    Standard

    Du führst die einzelnen File-Befehle zu schnell aus. Die einzelnen FBs haben Rückmeldungen, wann sie fertig sind und welchen Status sie haben. Den nächsten Befehl darf man erst ausführen wenn der vorhergehende beendet ist. Der Schreiben Befehl benötigt z.B. meist mehr als einen Zyklus, deswegen kommt bei Dir einiges durcheinander.
    Geändert von oliver.tonn (06.12.2018 um 18:55 Uhr)

  3. Folgender Benutzer sagt Danke zu oliver.tonn für den nützlichen Beitrag:

    TiI (11.12.2018)

  4. #3
    Registriert seit
    23.06.2009
    Ort
    Sassnitz
    Beiträge
    12.749
    Danke
    1.038
    Erhielt 3.752 Danke für 3.030 Beiträge

    Standard

    Deine Zeigerarithmetik ist korrekt. Die unerwarteten Zeichen in der Datei entstehen vermutlich erst beim Datei-Schreiben, was bei Dir zu früh "abgewürgt" wird, wie oliver.tonn schon anmerkte.

    Man könnte die csv-Zeile verständlicher mit CONCAT zusammensetzen. Dann braucht auch nicht das ganze Array vorher gelöscht werden sondern nur das erste Byte ( ByteArray[0] := 0; )
    (Wieviele Zeichen darf ein String lang sein für CONCAT bei WAGO? Sind bei WAGO die String-Funktionen "thread-safe"? Wenn nicht, dann darf CONCAT nicht in verschiedenen Task verwendet werden.)


    Zitat Zitat von TiI Beitrag anzeigen
    Das ByteArray ist natürlich um einiges größer (durch gc_RawDataSize := 100 global festgelegt) als die Summer aller zu schreibenden Werte (usw.) in Byte.
    Vorsicht, ich denke für reale Zahlenwerte ist Dein Bytearray zu klein! Echte REAL-Werte können/werden mehr Nachkommastellen haben. Im ungünstigsten Fall können schon allein die 10 Real-Werte und Semikolons mehr als 100 Zeichen ergeben, dazu kommen noch 22 Zeichen Zeitstempel und 2 Zeichen Zeilenende.

    Gibt es eine genaue Dokumentation, wie bei WAGO die Ausgabe von REAL_TO_STRING aussieht?
    Gibt es bei WAGO eine Funktion um einen Real mit Formatvorgabe in einen String zu konvertieren (z.B. REAL_TO_FMTSTR?)?

    Harald
    Es ist immer wieder überraschend, wie etwas plötzlich funktioniert, sobald man alles richtig macht.

    FAQ: Linkliste SIMATIC-Kommunikation über Ethernet

  5. Folgender Benutzer sagt Danke zu PN/DP für den nützlichen Beitrag:

    TiI (11.12.2018)

  6. #4
    TiI ist offline Neuer Benutzer
    Themenstarter
    Registriert seit
    06.12.2018
    Beiträge
    2
    Danke
    2
    Erhielt 0 Danke für 0 Beiträge

    Standard


    Zuviel Werbung?
    -> Hier kostenlos registrieren
    Hey, danke erstmal an euch für die Anregungen:

    in der CoDeSys Programmierungsanleitung von 3S - Smart Software Solutions und in der Beschreibung zur SysFileLib steht leider nichts von einer Methode, wie ich auf das Ende des Schreibvorgangs warten könnte.
    Die SysFileWrite Funktion gibt (nach Erfolg?) nur einen DWORD zurück, welcher die Anzahl der geschriebenen Bytes enthält.

    Da ich in ST schreibe, werden die Befehle doch generell nacheinander abgearbeitet. Von welchem Zyklus reden wir also, wenn mein Schreibvorgang eurer Meinung nach in der Mitte unterbrochen wird? Ich habe dem Task zum Schreiben meiner Datei mehr als 10 sek gegeben, das Ergebnis bleibt leider gleich... also mit den ungewollten abgehackten Datum. Egal ob ich nur 10 Werte und ein 100 Byte Array schreibe oder 400 Werte in ein 3000 Byte Array.

    Wie könnte ich den SysFileWrite Vorgang (in einer Task) "auslagern", sodass sein Schreibvorgang nicht unterbrochen wird?
    Für mich sieht es so aus, als würde der Schreibvorgang keinerlei Probleme haben fertig zu werden.
    Ich überprüfe jetzt vor jedem Schreibvorgang ob mir vorher die SysFileClose Funktion ein TRUE lieferte.
    Nur in diesem Fall erlaube ich beim nächsten zyklischen Aufruf des Schreib-Tasks die SysFileWrite Funktion.
    Laut der der CoDeSys Programmierungsanleitung wird mit dem SysFileClose die Datei endgültig geschrieben und abgelegt.
    Es sollte mir laut meinem Verständnis ein TRUE liefern, wenn der Schreibvorgang geglückt ist und die Datei zum schließen nicht mehr gelockt ist.
    Das deckt sich auch mit dem Dateiinhalt danach.

    Ich bin ein wenig ratlos worauf ich noch prüfen kann oder welche Funktionen ich nutzen sollte
    Würden mir vielleicht die Async Funktionen (SysFileOpenAsync, SysFileWriteAsync, SysFileCloseAsync) weiterhelfen?

    ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    Um mal das ganze mal mit Strings zu testen, habe ich folgende Konvertierung geschrieben:
    Code:
    WriteBuffer:            STRING(2000);                                        (*  STRING *)
    
    ========================================================
    WriteBuffer := '';
    WriteBuffer := CONCAT(WriteBuffer, DT_TO_STRING(EingangsArray.dtTageszeit));            (* Zeitstempel --> Bytefeld *)
    
    FOR i:=0 TO gc_ColumnCount BY 1 DO
        WriteBuffer := CONCAT( WriteBuffer, trenner );
        WriteBuffer := CONCAT( WriteBuffer, REAL_TO_STRING(EingangsArray.Wert[i]) );
    END_FOR
    
    WriteBuffer := CONCAT( WriteBuffer, '$R$N' );                                                    (* new line *)
    Das hat leider nichts gebracht. Es gibt keine dynamischen Strings in CoDeSys 2.3.
    Alle String Funktionen können nur mit 250 Zeichen umgehen, sodass CONCAT bei größeren Strings nicht mehr funktioniert und ab 255 Zeichen nichts weiter an WriteBuffer anfügen will

    Habt ihr noch weitere Tipps für mich?
    Würden mir die OSCAT Bibliotheken in diesem Fall etwas bringen? Gibt es dort erweiterte / dynamische Datentypen?

    Vielen Dank für eure Hilfe
    VG
    TiI

Ähnliche Themen

  1. Antworten: 18
    Letzter Beitrag: 13.04.2017, 15:43
  2. Antworten: 1
    Letzter Beitrag: 24.03.2015, 07:36
  3. Zeilenumbruch beim .csv Datei schreiben
    Von Beycker im Forum CODESYS und IEC61131
    Antworten: 3
    Letzter Beitrag: 24.09.2014, 14:13
  4. Wago: CSV Datei auf FTP Server schreiben
    Von beginner87 im Forum WAGO
    Antworten: 7
    Letzter Beitrag: 30.09.2013, 21:52
  5. Antworten: 1
    Letzter Beitrag: 22.10.2012, 12:42

Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •