# ASCII in STRING umwandeln, um Werte aus einer XML-Datei auszulesen



## Lex (3 Juli 2018)

*ASCII in STRING umwandeln, um Werte aus einer JSON/XML-Datei auszulesen*

Hallo alle zusammen,

ich hoffe ihr könnt mein Fehlendes Wissen in der Programmiersprache ST füllen und mir bei meinem Problem weiter helfen, da ich alles in CFC nur programmiere.

Ich besitze einen DENON Verstärker der per HTTP-Befehl gesteuert und ausgelesen werden kann. Dies wird per Baustein "FbHTTP_Get" realisiert wobei ein Buffer (Buffer-Statusabfrage) mit 281 Byte-Einträgen gefüllt wird. Diese müssen per ASCII-Tabelle in Character (STRING) umgewandelt werden.

Ich habe es bereits geschafft BYTE-Einträge, die im "Buffer_Statusabfrage" in einem ARRAY enthalten sind laut ASCII-Tabelle in Characters umzuwandeln (siehe Bild "CHAR_TO_STRING). 

Bild *CHAR_TO_STRING:*



Als kleines Beispiel: Die Byte Zahl *"70"* bedeutet laut ASCII-Tabelle in Character umgewandelt den Buchstaben *"F"*.

Wie bereits weiter oben erwähnt spiegeln die 281 Byte-Einträge diese XML-Seite wieder (siehe Bild "HTTP-Ausgabe").

Bild *HTTP-Ausgabe:*



Ich weiß bereits das z.B. der Buffer_Statusabfrage [61] der Buchstabe "O" und der Buffer_Statusabfrage [62] der Buchstabe "N"für den Powerzustand ausgiebt. D.h. ist der Verstärker EINGESCHALTET ist das laut Bild "HTTP-Ausgabe" das Wort "ON" nach dem Wort <value> usw....

Mein vorhaben ist es jedoch auch die momentane Volume (Lautsträke) auszulesen. Bedauerlicherweise ändert sich der Array-Eintrag je nach Betriebszustand des Verstärkers. Ist der Verstärker EINGESCHALTET besitzt das "*-*" vor der Zahl "52.5" den "Buffer_Statusabfrage [212]", ist der Verstärker AUSGESCHALTET besitzt das "-" den "Buffer_Statusabfrage [213]". Das liegt daran das, dass Wort weiter oben (aus Bild "HTTP-Ausgabe") von ON auf OFF wechselt und somit einen Eintrag mehr einnimmt und sich es um einen Array-Eintrag verschiebt. 
Im Onlinemodus sieht es wie folgt aus... ebenso sieht man eine Realisierung um den Betriebszustand (AN oder AUS) des Verstärkers festzustellen.

Bild *Onlinestatus:*



Wie kann ich nun zuverlässt diese Werte aus der XML-Datei (HTTP-Ausgabe) in e!COCKPIT auslesen?

Ich habe mir gedacht das ich vll. das gesamte ARRAY von "Buffer_Statusabfrage" mit meinem ST-Code (CHAR_TO_STRING) in einen "einzigen" STRING umwandel. Dann mit Hilfe des Baustein "FIND" (String Function) die erste Überschrift wie im Bild "HTTP-Ausgabe" zu sehen nach " <MasterVolume> " suche und dann mit dem Baustein "LEFT" (String Function), sieben Array-Einträge (für den Eintrag " <value> ") weiter springe, um dann immer an der korrekten Stelle zu sein, um z.B. die Laustärke auslesen zu können.

Wäre dies zu umständlich oder gibt es eine bessere Möglichkeit?
Würde mich wahnsinnig über einen ST-Code oder auch in CFC freuen, z.B. wie es programmiert werden könnte um das gesamte Array umgewandelt als ein einzigen String darzustellen.



Gruß Lex


----------



## oliver.tonn (3 Juli 2018)

Was die Wandlung in Strings angeht machst Du Dir das Leben meiner Meinung nach zu schwer. Der Verstärker sendet doch schon Texte. Erstell Dir Doch einfach eine Variable vom Typ STRING diese Variable füllst Du zunächst mit MEMSET mit 0, damit wenn der übertragene Text mal kürzer ist das Endezeichen vorhanden ist, dann kopierst Du mit MEMCPY den Inhalt des Puffers in den String. Nun kannst Du mit den entsprechenden Stringbefehlen durchsuchen und einzelne Teile rausziehen und dann z.B. in Zahlen umwandeln.
Ich kenne jetzt die WAGO Bibliotheken nicht, aber vielleicht gibt es da ja auch welche um XML-Dateien/Strings zu durchsuchen.


----------



## Lex (3 Juli 2018)

Hallo Oliver,

vielen lieben Dank für die schnelle Rückmeldung!
Wenn ich es richtig verstanden habe Wandel ich laut deiner Lösung aber die Bytes nicht per ASCII-Tabelle um. Wie kann ich dann genau nach einem Eintrag wie z.B. "MasterVolume" suchen? Es sind dadurch nur Zahlen gegeben die mehrmals immer wieder vorkommen könnten.

Wäre es möglich ein Beispiel auf die schnelle zu programmieren, in ST oder am liebsten in CFC?


Gruß Alex


----------



## oliver.tonn (3 Juli 2018)

Hallo, Du hast recht, auf den ersten Blick enthält Dein ARRAY OF BYTES nur Zahlen, z.B. die Zahl 65Dez. Nur was die Zahlen bedeuten oder wie Sie interpretiert werden ist z.B. vom Variablentyp abhängig indem die 65Dez steht. Angenommen in Deinem ARRAY mit dem Namen ab8_Test, stehen die Dezimalzahlen 72, 65, 76, 76, 79. Parallel hast Du eine Stringvariable mit dem Namen s_Test und der Größe 10 angelegt die Du zunächst mit MEMSET(ADR(s_Test), 0, SIZEOF(s_Test)) mit dem Stringendezeichen von Codesys (der 0) füllst. Wenn Du jetzt die fünf "Zahlen" aus dem ARRAY mit MEMCPY(ADR(s_Test), ADR(ab8_Test), 5) in die Stringvariable kopierst und Dir dann dessen Inhalt anschaust steht da HALLO drin, ganz ohne das Du irgendetwas konvertiert hast. Schaust Du Dir dagegen den Speicherbereich der Variable an siehst Du wieder 72, 65, 76, 76, 79, und der Vollständigkeit halber noch 6 * 0 (Der Speicherbedarf eines Strings ist immer um 1 Byte größer, wegen dem Endezeichen, Siemens z.B. arbeitet hier anders).


----------



## Thruser (3 Juli 2018)

Hallo,

Oliver macht das gleiche wie Du, nur das er gleich mehrere Zeichen umwandelt anstelle von einem.

Du verwendest da ja auch keine Tabelle, sonst hättest Du da etwas wie


```
if (c=65) then char_sto_string := "A"
```
stehen.

Sieh Dir ansonsten doch mal die Buffer Management Operationen in der Oscat Bilbliothek an, a hast Du auch eine Suchmethode, sowie die Umwandlung dabei.


Gruß


----------



## oliver.tonn (3 Juli 2018)

Thruser schrieb:


> Oliver macht das gleiche wie Du, nur das er gleich mehrere Zeichen umwandelt anstelle von einem.


Achtung!!! Klugscheißerei.
Genaugenommen wird hier nichts gewandelt, sondern "nur" unterschiedlich interpretiert/angezeigt, ähnlich wie wenn man zwischen einer Anzeige in Hex, Dezimal oder Binär umschaltet, im Speicher steht bei allen drei Varianten immer das gleiche, so auch hier .


----------



## KLM (3 Juli 2018)

Moin, ich war mal so frei ...
Hoffe es stört Dich nicht, wenn Du parallel auch gleich noch Mute und Co auswerten kannst 


```
FUNCTION FC_GetXmlValueMulti : ARRAY[1..10] OF STRING(20)

VAR_INPUT
    pabRxBuffer        : POINTER TO ARRAY[1..500] OF BYTE;
    udiRxNByte        : UDINT;
    asAttributeName    : ARRAY[1..10] OF STRING;
END_VAR


VAR
    udiIdx            : UDINT;
    pbChar            : POINTER TO BYTE;
    psChar            : POINTER TO STRING(1);
    sChar            : STRING(1);
    sTmp            : STRING;
    xStart, xStartM, xEnd, xIgnor, xFound, xCopyValue    : BOOL;
    iFoundIdx            : INT;
    i                : INT;
END_VAR
```


```
FOR i := 1 TO 10 DO
    FC_GetXmlValueMulti[ i ] := 'attribute not found';
END_FOR
pbChar := pabRxBuffer;


FOR udiIdx := 1 TO udiRxNByte +1 DO


    xIgnor :=pbChar^ = 16#2F;    (* '/' *)
    xStartM := pbChar^ = 16#3C;    (* '<' *)
    xEnd := (pbChar^ = 16#3E) OR (xStartM AND xCopyValue);    (* '>' *)




    IF (xStart OR xCopyValue) AND NOT xEnd AND NOT xIgnor THEN
        psChar := pbChar;
        IF pbChar^ = 16#0 THEN EXIT; END_IF    (* EOF string *)
        sChar := psChar^;
        sTmp := CONCAT(sTmp, sChar);
    ELSIF xEnd THEN
        IF xFound AND NOT xCopyValue THEN
            xCopyValue := TRUE;
        ELSIF xFound AND  xCopyValue THEN
            FC_GetXmlValueMulti[ iFoundIdx ] := sTmp;
            xFound := FALSE;
            xCopyValue := FALSE;
        ELSE
            FOR i := 1 TO 10 DO
                 IF (sTmp = asAttributeName[ i ]) AND (asAttributeName[ i ] <> '') THEN
                    xFound := TRUE;
                    iFoundIdx := i;
                    EXIT;
                END_IF
            END_FOR
        END_IF
        sTmp := '';
    END_IF


    xStart := (xStart OR xStartM) AND NOT xEnd AND NOT xIgnor;
    pbChar := pbChar +1;
END_FOR
```

Programmaufruf je nach Sprach in etwa so ...


```
asAttributeName    : ARRAY[1..10] OF STRING := 'MasterVolume', 'VolumeDisplay', 'dummy', 'Mute', 6('');
    asAttributeValue    : ARRAY[1..10] OF STRING(20);
--------------
asAttributeValue := FC_GetXmlValueMulti(pabRxBuffer, udiRxNByte, asAttributeName);
```

Edit: Ist mit CODESYS 2 geschrieben, hoffe der e!C Compiler meckert nich irgendwo.


----------



## KLM (3 Juli 2018)

Schaut in CODESYS 2 so aus. Anm.: Die Funktion ohne Array war mein erster Versuch, ist sonst aber gleich.


----------



## Lex (4 Juli 2018)

Erstmal vielen lieben DANK an @oliver.tonn , @Thruser und @KLM!

@KLM:

Genau so etwas hatte ich mir vorgestellt wie du es eigentlich schon fertig abgeliefert hast ;-)
Hätte jedoch noch Fragen zu deinem Programm:

1.) Wie genau würde es wie im meinem Bild zu sehen fertig aussehen? 




2.)
Da ich nicht wie bereits erwähnt fit in ST bin, bräuchte ich zu paar Sachen Deklarationshilfe. Laut deinem Programmaufrufs-Code befinden sich zwei Variablen mit der selben Bezeichnung (asAttributeValue). Wie soll das funktionieren und we ist das bei dir gemeint da du diese "---------------" noch verwendet hast (als Trennlinie für etwas?).

3.)
Ebenso wollte ich nachfragen was ich wo verändern müsste um nach anderen Variablen zu suchen, für andere XML-Dateien? Bräuchte ich hier einfach nur in der Zeile bei " asAttributeName : ARRAY[1..10] OF STRING :='MasterVolume', 'VolumeDisplay', 'dummy', 'Mute', 6(''); " die Einträger "MasterVolume ; VolumeDisplay usw." ändern?

4.)
Wo müsste ich was verändern um dem Baustein (FC_GetXmlValueMulti) mit der richtigen XML-Datei zu füttern. Wird bestimmt über den Buffer laufen, aber was müsste ich wo, wie bei mir bereits Realisiert, an deinem Baustein am Eingang ändern?

Vll könntest du mir dabei nochmals helfen KLM in meiner CFC-Programmierung, oder auch jemand anderes.
Ebenso bräuchte ich Hilfe zu den drei aufkommenden Deklarationsfehlern. Wüsste nicht was falsch sein sollte.

*NACHTRAG:

*Habe es im nachhinein doch noch selbst geschafft. Die zwei Codes von KLM wurden in eine Function in e!COCKPIT 1:1 kopiert und anschließend wie im Bild "Offline" zu sehen als Baustein (FC_GetXmlValueMulti) im Programm aufgerufen und verknüpft. 
Ich bin wahnsinnig HAPPY über eure Hilfe und vor allem deiner KLM. Das fertige Programm sieht wie folgt aus:

*Offline:*



*Online:
*




Gruß Lex


----------



## Thruser (4 Juli 2018)

Hi,

KLM wird wohl später noch antworten. Ich fange mal an.



Lex schrieb:


> Erstmal vielen lieben DANK an @oliver.tonn , @Thruser und @KLM!
> 
> 2.)
> Da ich nicht wie bereits erwähnt fit in ST bin, bräuchte ich zu paar Sachen Deklarationshilfe. Laut deinem Programmaufrufs-Code befinden sich zwei Variablen mit der selben Bezeichnung (asAttributeValue). Wie soll das funktionieren und we ist das bei dir gemeint da du diese "---------------" noch verwendet hast (als Trennlinie für etwas?).


die ersten beiden Zeilen sind die Variablendeklaration und kommen in das obere Fenster. Die unterste Zeile ist der Programmaufruf in ST, den kannst Du hier nicht verwenden da CFC



Lex schrieb:


> 4.)
> Wo müsste ich was verändern um dem Baustein (FC_GetXmlValueMulti) mit der richtigen XML-Datei zu füttern. Wird bestimmt über den Buffer laufen, aber was müsste ich wo, wie bei mir bereits Realisiert, an deinem Baustein am Eingang ändern?


In pabRxBuffer muß der Empfangsbuffer vom FbHTTP_Get Baustein, also auch adr(Buffer_Statusabfrage). udiRxBuffer ist die Anzahl der empfangenen Bytes ByteCount_Status.



Lex schrieb:


> Vll könntest du mir dabei nochmals helfen KLM in meiner CFC-Programmierung, oder auch jemand anderes.
> Ebenso bräuchte ich Hilfe zu den drei aufkommenden Deklarationsfehlern. Wüsste nicht was falsch sein sollte.



Arrays werden unter e!Cockpit (Codesys 3.5) etwas anders initialisiert. Da müssen noch eckige Klammern drum.

```
[FONT=arial][COLOR=#333333]asAttributeName : ARRAY[1..10] OF STRING[/COLOR][COLOR=#333333]:=[[/COLOR][COLOR=#333333]'MasterVolume', 'VolumeDisplay', 'dummy', 'Mute', 6('')];
[/COLOR][/FONT]
```


@KLM
sollte man nicht vielleicht auch noch CR und LF mit rausfiltern?

Gruß


----------



## Lex (4 Juli 2018)

Vielen DANK Thruser... warst leider anscheinend schon dabei zu antworten als ich den *NACHTRAG* gepostet hatte, tut mir leid. Das letzte Problem mit der Dekleration (Lösung: eckige Klammer) ist somit jetzt auch Vergangenheit.

p.S.: Was bedeutet die *6(' ') *eigentlich in diesere Dekleration     *asAttributeName    : ARRAY[1..10] OF STRING := 'MasterVolume', 'VolumeDisplay', 'dummy', 'Mute', 6('');      *? (Für mich als Info)


Danke nochmals.


----------



## Thruser (4 Juli 2018)

Hi,

das bedeutet, dass die nächsten 6 Arrayeinträge mit '' ('' für Leerstring) gefüllt werden.

Gruß


----------



## Lex (4 Juli 2018)

Wieso muss das gemacht werden? Habe es jetzt bei mir nicht deklariert und es funktioniert dennoch.


----------



## Thruser (4 Juli 2018)

Hi,

es muß wahrscheinlich nicht gemacht werden, die werden automatisch mit Leerstrings gefüllt. Es kann aber mal sein, daß man andere default Werte benötigt. Außerdem ist es so sauberer von der Programmierung, indem man alle Arraypositionen besetzt. In anderen Programmiersprachen kann es zu Fehlern führen.

Wie hast Du das Array denn initialisiert?

Gruß


----------



## Lex (4 Juli 2018)

Ich habe es momentan so gelöst:




Da ich denn Status des Verstärkers immer aktualisieren muss, habe ich es derzeitig mit dem Baustein "FbBlinker" gelöst. Ist das so richtig oder gibt es bessere/ Ressourcenschonendere Lösungen. Momentan ist der Blinker folgendermaßen eingestellt:


tTimeHigh: t#1s
tTimeLow: t#5s

Eigentlich müsste sich der Status erst nach einer Änderung automatisch aktualisieren und nicht alle fünf Sekunden.



Gruß Lex


----------



## Thruser (5 Juli 2018)

Nicht vorgebene Felder werden also automatisch mit '' (Leerstring) initialisiert.

Was meinst Du mit 'nach einer Änderung'? Der Verstärker meldet sich ja nicht bei der Steuerung automatisch wenn sich etwas geändert hat, daher mußt Du regelmäßig den Status abfragen.

Ich hätte den normalen TON Timerbaustein verwendet und da als Eingang die negierte Visu_Taster_ ... _MZ_Statusabfrage. Die Variabel muß ja auf True gesetzt werden damit der HTTP Baustein anfängt zu arbeiten und wird dann wenn der Auftrag abgearbeitet ist auf False gesetzt. Da die Variable jetzt auch noch durch den Blinker Baustein gesetzt wird kann ich mir vorstellen, daß es da zu Konflikten kommen kann, je nachdem wie der Baustein arbeitet und die Variable setzt.

Gruß


----------



## KLM (5 Juli 2018)

Moin,
alles Fragen zum Quellcode scheinen geklärt. Besten Dank Thruser.
Ohne zyklische Abfrage wirst Du die Änderung nicht feststellen. Nachdem der Get FB den Trigger aber wahrscheinlich selbst wieder zurücksetzt (?) würde ich nicht mit einem Blinker arbeiten, sondern mit einem puls-generiertem Set. Also ne Kombination aus einem TON oder TOF mit Flankenerkennung. Eingang des Zeitbausteins ist dann sein eigener negierter Ausgang. Wenn Du den noch mit dem Busy AND verknüfpst vermeidest Du Trigger-Befehle ohne Wirkung.
Bei Deinem Programm wäre aber noch die Frage, ob nicht mein Praser FB einen Trigger vertragen könnte. Sonst rattert der in jedem Zyklus alle ASCII Bytes durch.



> @KLM
> sollte man nicht vielleicht auch noch CR und LF mit rausfiltern?


Hatte die XML nicht und hab geraten, dass da CR LF drin sind. Muss aber nicht zwingend und ggf. sind auch noch Tabs dring. Ist aber egal, weil der Praser nur auf die Anfangs- und Endzeichen <> schaut. Alles dazwischen wird nicht berücksichtigt.


----------



## Lex (5 Juli 2018)

Danke euch beiden für die schnellen Antworten!



> @KLM
> Nachdem der Get FB den Trigger aber wahrscheinlich selbst wieder zurücksetzt (?)...



Ja das macht er, nach ca. 1 Sekunden.



> @KLM
> Hatte die XML nicht und hab geraten, dass da CR LF drin sind.



Also wenn mit *LF = Line Feed *gemeint ist, kann ich dies bestätigen, dass diese in der XML-Datei vorhanden sind. Sie werden im Buffer-Array als Byte (10) abgespeichert.



> @KLM
> Bei Deinem Programm wäre aber noch die Frage, ob nicht mein Praser FB einen Trigger vertragen könnte. Sonst rattert der in jedem Zyklus alle ASCII Bytes durch.



Aus Logischer Sicht würde ich diese Frage mit *JA *beantworten. Denn von meinem Wissen her ist dies immer nur Vorteilhaft und Ressourcenschonender für den Controller, oder sehe ich das falsch?

Habe es hoffentlich richtig verstanden mit dem TON-Baustein. Wäre die 1. Variante oder die 2. Variante richtig, siehe Bilder?

*1. Variante:*



*2. Variante:
*


----------



## Lex (5 Juli 2018)

@KLM

Hätte noch eine letzte Frage zu deiner Funktion um die XML-Werte auszulesen.
Ich habe das gleiche Verfahren mit meinem Receiver. Dieser spuckt folgende XML-Datei aus (siehe Bild "Receiver_XML-Ausgabe").

Bild Receiver_XML-Ausgabe:



Jedoch wird der gesuchte Wert leider nicht korrekt herausgefiltert. Dies liegt daran da sich folgendes in der XML-Datei gegenüber dem Denon-Receiver, *zwei Werte unterhalb der Überschrift* mit dem Pfeil befindet (siehe Bild "Receiver_XML-Ausgabe"). 
Um es besser zu verstehen gliedere ich es hier nochmal auf:
*--> <e2service>**<e2servicereference> WERT 1 </e2servicereference>                     *in dieser Zeile ist der erste Wert unterhalb der Überschrift mit dem aufgeklappten Pfeil​*<e2servicename> WERT 2 </e2servicename> *                               in dieser Zeile ist der zweite Wert unterhalb der Überschrift mit dem aufgeklappten Pfeil​.​.​.
​Was müsste man in deiner Function abändern damit das Programm wie im nächsten Bild die korrekten, anstelle komischer Werte ausgibt?

Bild Receiver_XML_GesuchteWerte:





Gruß Lex


----------



## Thruser (5 Juli 2018)

Hallo,

habe gerade 1,5h mit dm CFC Editor gekämpft. So sollte das funktionieren, ist aber nicht getestet.



Lex schrieb:


> Also wenn mit *LF = Line Feed *gemeint ist, kann ich dies bestätigen, dass diese in der XML-Datei vorhanden sind. Sie werden im Buffer-Array als Byte (10) abgespeichert.


Ja damit ist Line Feed gemeint (CR=Carriage Return). Wird wahrscheinlich zwischen > und < auftreten, nicht zwischen < und >. Am besten Du lädst mal die XML Datei hoch, dann kann man sich das direkt ansehen. Ein Screenshot ist etwas ungünstig.



Lex schrieb:


> Aus Logischer Sicht würde ich diese Frage mit *JA *beantworten. Denn von meinem Wissen her ist dies immer nur Vorteilhaft und Ressourcenschonender für den Controller, oder sehe ich das falsch?
> 
> Habe es hoffentlich richtig verstanden mit dem TON-Baustein. Wäre die 1. Variante oder die 2. Variante richtig, siehe Bilder?





So sollte es richtig sein. Probleme bereitet mit nur Dein Visu Taster. Der darf nur ein Impuls setzen. Habe mit der Visu noch nicht gearbeitet und kenne daher die Einstellmöglichkeiten.

Die Doku von Wago ist da leider wieder sehr dürftig bezüglich xTrigger, xBusy und xError. Von einem anderen Baustein weiß ich, daß man xTrigger setzen muß und wenn die Aufgabe erledigt ist, dann wird xTrigger zurückgesetzt. Wann dann xBusy gesetzt wird und wann xError weiß ich nicht. Bei meinem Beispiel verwende ich jetzt xTrigger.

Ich habe auch noch versucht die beingte Verwendung von FC_GetXmlValueMulti zu zeigen. Dazu mußt Du auf dem Baustein ein Rechtsklick machen und EN/ENO wählen, dann kann man die Ausführung von einer Bedingung abhängig machen. Hier jetzt Beendung des FbHTTP_Get Bausteins.

Gruß


----------



## Thruser (5 Juli 2018)

Hi,



Lex schrieb:


> Um es besser zu verstehen gliedere ich es hier nochmal auf:
> *--> <e2service>**<e2servicereference> WERT 1 </e2servicereference>                     *in dieser Zeile ist der erste Wert unterhalb der Überschrift mit dem aufgeklappten Pfeil​*<e2servicename> WERT 2 </e2servicename> *                               in dieser Zeile ist der zweite Wert unterhalb der Überschrift mit dem aufgeklappten Pfeil​



Du darfst nur die unterste Ebene, da wo direkt die Daten stehen in die Liste aufnehmen, also nur <e2servicereference> und <e2servicename>, nicht <e2service>

Gruß


----------



## Lex (5 Juli 2018)

@Thruser



> Du darfst nur die unterste Ebene, da wo direkt die Daten stehen in die Liste aufnehmen, also nur <e2servicereference> und <e2servicename>, nicht <e2service>



Das habe ich doch gemacht, siehe Bild "Receiver_XML_GesuchteWerte".

Jedoch wird beim gesuchtem Wert *"e2sercivename"* als Ausgabe *"$N$T"* ausgegeben und nicht *"ZDF HD"*.
Habe noch umfangreichere XML-Dateien zum Receiver, siehe Anhang. 
*
Bild:*



P.S.: Wie kann ich hier Dateien einfügen?


Gruß Lex


----------



## Thruser (5 Juli 2018)

Lex schrieb:


> Das habe ich doch gemacht, siehe Bild "Receiver_XML_GesuchteWerte".



Nö:



Das e2service muß da weg.



Lex schrieb:


> Habe noch umfangreichere XML-Dateien zum Receiver, siehe Anhang.
> P.S.: Wie kann ich hier Dateien einfügen?


Du mußt in den erweiterten Editor, nicht unten direkt antworten sondern erst auf erweitert klicken, dann ist dort eine Büroklammer.

Gruß


----------



## Lex (5 Juli 2018)

Habe die zwei XML-Dateien vom Receiver in den Anhang getan.


Wegen dem Wert "e2servicename" habe ich dir jetzt nochmal im Onlinemodus ein Bild angehängt. Ich wollte mit dem vorherigem Bild zeigen das bei allen drei Varianten nur die erste mit "e2service" etwas ausgespuckt hat.

*Bild:
*



P.S.: Zum Thema TON-Baustein, diese Variante von dir funktioniert leider nicht. Wie im Bild "TON-Baustein" zu sehen verbleibt die Steuerung in diesem Zustand permanent. Wird auf den Visu_Button (Taster) gedrückt passiert auch nichts mehr.







Gruß


----------



## Thruser (5 Juli 2018)

Hallo,

zum TON, Du mußt noch die Variable am xTrigger Eingang des FbHTTP_Get Bausteins ändern zu Trigger_Denon_... Außerdem hast Du die Invertierung am Eingang des Timers übersehen.

Zum Hochladen: xml in txt umwandeln oder packen zur Zip Datei. Zip und txt nimmt das Board glaube ich an.

Das andere muß ich mir erst ansehen. Muß ich wohl doch meinen 8204 rausholen. Eventuell weiß KML auf die schnelle rat.

Gruß


----------



## Thruser (5 Juli 2018)

So, ich weiß jetzt woran es liegt. Bei Deinem ersten Satz Daten sind die Werte in einem Child-Item (value) gespeichert. Bei den neuen Daten sind sie direkt enthalten.

Eventuell funktioniert folgendes dafür (Achtung neue Funktion):

```
FUNCTION FC_GetXmlValueMulti2 : ARRAY[1..10] OF STRING(20)


VAR_INPUT
    pabRxBuffer        : POINTER TO ARRAY[1..500] OF BYTE;
    udiRxNByte        : UDINT;
    asAttributeName    : ARRAY[1..10] OF STRING;
END_VAR




VAR
    udiIdx            : UDINT;
    pbChar            : POINTER TO BYTE;
    psChar            : POINTER TO STRING(1);
    sChar            : STRING(1);
    sTmp            : STRING;
    xStart, xStartM, xEnd, xIgnor, xFound, xCopyValue    : BOOL;
    iFoundIdx            : INT;
    i                : INT;
END_VAR
```


```
FOR i := 1 TO 10 DO
    FC_GetXmlValueMulti2[ i ] := 'attribute not found';
END_FOR
pbChar := pabRxBuffer;




FOR udiIdx := 1 TO udiRxNByte +1 DO


    xIgnor :=pbChar^ = 16#2F;    (* '/' *)
    xStartM := pbChar^ = 16#3C;    (* '<' *)
    xEnd := (pbChar^ = 16#3E) OR (xStartM AND xFound);    (* '>' *)


    IF (xStart OR xFound) AND NOT xEnd AND NOT xIgnor THEN
        psChar := pbChar;
        IF pbChar^ = 16#0 THEN EXIT; END_IF    (* EOF string *)
        sChar := psChar^;
        sTmp := CONCAT(sTmp, sChar);
    ELSIF xEnd THEN
        IF xFound THEN
            FC_GetXmlValueMulti2[ iFoundIdx ] := sTmp;
            xFound := FALSE;
        ELSE
            FOR i := 1 TO 10 DO
                 IF (sTmp = asAttributeName[ i ]) AND (asAttributeName[ i ] <> '') THEN
                    xFound := TRUE;
                    iFoundIdx := i;
                    EXIT;
                END_IF
            END_FOR
        END_IF
        sTmp := '';
    END_IF


    xStart := (xStart OR xStartM) AND NOT xEnd AND NOT xIgnor;
    pbChar := pbChar +1;
END_FOR
```
Das ist aber noch nicht getestet.

Gruß

NACHTRAG: Bei den umfangreichen XML Antworten wirst Du aber in neue Probleme laufen. Da macht der folgene Abschnitt Probleme:

```
<e2tunerinfo>
            <e2nim>
                <name>Tuner A</name>
                <type>BCM7346 (internal) (DVB-S2)</type>
            </e2nim>
            <e2nim>
                <name>Tuner B</name>
                <type>BCM7346 (internal) (DVB-S2)</type>
            </e2nim>
            <e2nim>
                <name>Tuner C</name>
                <type>Si2168 (DVB-T2)</type>
            </e2nim>
        </e2tunerinfo>
```
Da wirst Du mit name und Type nur Tuner C, sowie Si2168(DVB-T2) bekommen.

/EDIT: Fehlendes THEN hinzugefügt, der vollständigkeit halber


----------



## KLM (5 Juli 2018)

Moin, ich meinte es so ... (sorry, hab daheim nur CDS 2.3 und CFC ist da schon ein Krampf. Die Implementierung in e!C ist ohne die Shortcuts ja noch schlimmer)



Edit: Hab mir grad die Lösung von Thruser angeschaut. Geht auch. Viele Wege führen ...


----------



## Lex (5 Juli 2018)

Also die Antwort ging echt schnell *Thruser* und dann noch direkt mit einem neuem Code. Auch an dir ein Danke *KLM*. Habe den neuen Code bereits implementiert, jedoch wird an einer Stelle gemeckert, siehe Bild.


----------



## KLM (5 Juli 2018)

Mit dem anderen Format, kann mein erster Praser gar nicht verwendet werden, bzw. müsste umgebaut werden. Der schaut in der ersten Version auf ein "<", hängt alle folgenden Zeichen in einen temporären Sting zusammen und wenn ein ">" kommt, vergleicht die Funktion den temporären Sting mit den gesuchten Attributen. Ist ein Attribut gefunden wird die folgende Kombinatin "<xxx>" (hier immer "<value>") ignoriert und das ">" von "<xxx>" als Startzeichen zum einlesen des Wertes genutzt. Ein folgendes "<" beendet den Zusammenbau des Wertes.
Ob die Anpassung von Thruser für die neue Formatierung passt, sollte sich ja schnell ausprobieren lassen ....


----------



## KLM (5 Juli 2018)

Die Fehlermeldung ist doch eindeutig. Der Compiler erwartet "IF <Boolscher Ausdruck> THEN <Anweisung 1>; <Anweisung n>; END_IF. Soll heißen, Du hast das THEN vergessen.


----------



## Lex (5 Juli 2018)

Habe ich bereits KLM, jedoch wie bereits in einem Post zuvor mit einem kleinem Fehler ;-) 
Haben anscheinen parallel geschrieben.

*Nachtrag:
*
Ich haben den neuen CODE korrigiert und mit Erfolg getestet. Funktioniert einwandfrei.


----------



## KLM (5 Juli 2018)

Wunderbar. Dann lass ein Daumen hoch/Danke da, da freut sich der Thruser.


----------



## Thruser (7 Juli 2018)

KLM schrieb:


> Wunderbar. Dann lass ein Daumen hoch/Danke da, da freut sich der Thruser.



Naja, es war aber Deine Funktion die ich nur ein bisschen modifiziert habe..

@Lex, läuft denn jetzt alles? Du hast Dir da ja einiges vorgenommen.

Gruß


----------



## KLM (7 Juli 2018)

> Naja, es war aber Deine Funktion die ich nur ein bisschen modifiziert habe..


Sich in ein fremdes Programm einzudenken und es zu modifizieren ist meist schwerer, als ein neues zu schreiben.



> Du hast Dir da ja einiges vorgenommen.


Man wächst mit seinen Aufgaben


----------



## Lex (7 Juli 2018)

Es funktioniert alles wunderbar. 
Wenn ihr zwei Spezialisten auf noch eine Modifikation Lust hättet, könntet ihr mir gerne nochmals helfen ;-)
Ich habe es selbst versucht euer Programm umzumodifizieren, doch ohne Erfolg.
Es geht um folgendes:

Bei meiner Türkommunikation möchte ich gerne die Zustände gewisser Kontakte überprüfen. Somit ist es das selbe Verfahren wie zuvor, jedoch sind die Zeichen bei diesen XML-Daten anders, siehe folgendes Dokument.

https://www.google.de/url?sa=t&sour...FjAAegQIARAB&usg=AOvVaw39qf6jFTeLcgeRbWLqpR86

In diesem PDF sind hauptsächlich nur die Kapitel 5.9 (Switch-Status) und Kapitel 5.15 (Call-Status) für mich interessant. Ebenso sind in diesen Kapiel die ausgeworfenen XML-Daten abgebildet. Zu beiden Kapitel würden mich wieder die jeweiligen Ergebnisse interessieren... doch leider schaffe ich es nicht diese wieder heraus zu filtern.


Gruß Lex


----------



## Thruser (7 Juli 2018)

Hi,

das ist kein XML sondern JSON. Da sind die Daten anders strukturiert.

Und wie willst Du die Daten abfragen? Für jeden Schalter einzeln oder gesammelt, also nur /api/switch/status oder /api/switch/status&switch=1, denn dadurch ändert sich auch die Ausgabe.

Würde frühestens morgen dazu kommen mir das mal weiter anzusehen.

Gruß


----------



## Lex (7 Juli 2018)

Hi Thruser,

tut mir leid mit dem Datenformat... hatte mich verschrieben und nicht nachkontrolliert. Also ich wprde es gerne am liebsten haben wenn jeder switch einzeln. Ebenso wäre auch sehr wichtig die Statuse aus dem Kapitel 5.15 zu bekommen. 

D.h. jeden Parameter für sich:
session = call identifier
Direkten = Call direction (incoming, outgoing) 
State = Call state (connecting, ringin, connected)

Vielen lieben dank schon einmal Thruser!!!


----------



## KLM (10 Juli 2018)

Für das Phrasen von JSON Formatierung gibt's schon eine fertige Bibliothek von WAGO. Kuckst Du hier: https://www.wago.com/de/d/APP_WagoLibJSON_01


----------



## KLM (10 Juli 2018)

Vergiss es, Du bist ja bei e!C. Aber JSON Bibliothek hab ich da auch schon gesehen. Such einfach nach dem Stichwort "json" im Bibliotheksverwalter und frag beim Support, wenn es noch nich im aktuellen 1.4er Release enthalten ist. Hab ich schon gesehen, muss also min. als Beta schon verfügbar sein.


----------



## Thruser (10 Juli 2018)

Hall,

bin noch nicht dazu gekommen. Wollte jetzt anfangen.

@KLM
hab schon bei den mitgelieferten Bibliotheken gesucht, aber nichts gefunden. Gerade wegen Iot, Cloud und MQTT dachte ich, da gäbe es was. Er findet nur etwas mit JSON bei WagoAppWeatherForecast, aber nichts was man nutzen kann.
Deine lib kann man leider auch nicht importieren, da fehlt das Paßwort. Aber vielleicht kann man sich da etwas von der Beschreibung akupfern.

Gruß


----------



## Thruser (11 Juli 2018)

Hallo,

habe verschiedene Methoden überlegt was man da machen könnte, bin aber zu keinem vernünftigen Ergebnis gekommen, wie man das am besten lösen könnte. Entweder man programmiert einigermassen allgemeine Lösungen, so wie bei der XML Lösung oder man macht  einzelne Lösungen, die für ein spezielles Problem da sind.

Beispiel für eine allgemeine Lösung:

Ausgang mit Array[1..10,1..2] OF STRING(20) -> entsprechende Wertepaare

```
Beispiel switch
success result switches switch active switch active switch active '' ''
true    {      [        1      true   2      false  3      false  ]  }

Beispiel call status
success result sessions session direction state   '' ''
true    {      [        1       outgoing  ringing ]  }

Beispiel error
success error code param description ''
false   {     12   port  invalid par }
```

Da muß man dann wieder die ganzen Wertepaare durchgehen. Oder eine Lösung wie die der Lib von KLM gestern.

Oder eben spezielle Funktionen wie
FC_Switch_1 mit Eingang des ByteArray und Ausgang als Bool
oder
FC_Switches mit Eingang ByteArray und mehrere Ausgänge Switch1, Switch2 als Bool

Ist natürlich auch einiges an Arbeit die ganzen Lösungen zu programmieren.

Um daher auf Deine ursprüngliche Frage zurückzukommen, ich habe mir die Wago Bibliotheken noch einmal angesehen. Da gibt es die WagoAppString, die hat die Funktion 'StringRef_to_PrintableString', damit sollte man das Byte/CharArray in einen String umwandeln können.


```
StringRef_to_PrintableString (FUN)

Interface variables 


Scope  Name                   Type            Comment 

Return StringRef_to_Printable String          STRING(255)   

Input  pInString              POINTER TO BYTE pointer to the input string 

Function

Converts a reference to a character STRING into a CODESYS-printable string.

 
Function Description

Non-printable characters are converted to spaces (‘ ‘). If a zero is encountered, this will be interpreted as the end of the string. Upper Control chars like 16#7f (DEL) and 16#80..9f are printable in CODESYS and will thus not be replaced.
```

Eine ähnliche Funktion ist in der Oscat lib. Da kann man den Quellcode ansehen. Oder Du folgst dem Github Link von hier: http://www.oscat.de/community/index.php/topic,4425.0.html da kannst Du den Quellcode direkt einsehen.

Bei der Wago Funktion hast Du den Vorteil, daß einige nicht darstellbare Zeichen die im Array vorkommen ersetzt werden.

Du mußt nur aufpassen, die max. Anzahl der Zeichen in den Strings beträgt bei Wago 255 und bei Oscat 250. Falls die Response mehr Zeichen hat mußt Du bei der Übergabe der Adresse des CharArray einen Offset dazuaddieren um andere Bereiche der Response auszuwerten.

Leider läßt sich der Beschreibung auch nicht entnehmen ob die Antwort in Unicode ist oder nicht. Bei Unicode funktioniert das alles nicht. Laut Hilfe con e!cockpit wird zwar auch wstring unterstützt, aber die ganzen Funktionen spielen da (noch) nicht mit.

Hoffe das hilft Dir etwas weiter.


----------



## Lex (12 Juli 2018)

Hi Thruser und KLM,

vielen Dank für eure Anregungen und Vorschläge. 
Hätte eine Frage an den ersten Codebereich von dir Thruser. 
Fehlen bezüglich diesem Code nicht die Deklarierungen? Dies ist doch kein fertiges Programm zum filtern von den Zuständen der Switches?
Werde aber den Support bezüglich einer fertigen Bibliothek zur Bearbeitungen von JSON-Daten in e!Cockpit erfragen.



Gruß Lex


----------



## Thruser (17 August 2018)

Hallo Lex,

kannst Du mir mal bitte ein paar Beispiele mit den Antworten geben. Am besten als Textdateien anhängen. Die Abfrage entweder mit dem Browser oder wget machen.

Habe mein Controller endlich wieder am laufen und probier dann mal ein paar Sachen aus.

Danke und Gruß


----------



## Lex (17 August 2018)

Hallo Thruser,

eigentlich ist alles wie im Beitrag #35 im PDF vorhanden. Dort sind auch alle Antworten zur jeweiligen Http-Anfrage abgebildet.

Hier nochmals der Link zum PDF:

https://www.google.de/url?sa=t&sourc...eLcgeRbWLqpR86


Von Interesse sind hauptsächlich folgende Kapitel:



Kapitel 5.9 (Switch-Status) 
Kapite 5.12 (IO-Status)
Kapitel 5.15 (Call-Status) 

Im Anhang findest du dennoch die verlangten Textdokumente. Habe zusätzlich auch die .JSON-Dateien hinzugepackt.
Ebenso bin ich sehr froh über deine Rückmeldung und möchte mich dafür sehr herzlich Bedanken!


Gruß Lex


----------



## Thruser (17 August 2018)

Hallo,

in dem Dokument steht leider nicht ob die Einrückungen mit Tabs oder Leerzeichen erfolgen und welche/s Zeilenendezeichen verwendet wird. Auch ob Unicode oder ASCII steht nicht frin.

Und so muß ich nicht alles abtippen und habe mal reale Daten zum testen.

Danke und Gruß


----------



## Lex (17 August 2018)

Hi Thruser,

wüsste nicht wie ich das realisieren soll das die Infos in den Daten drine enthalten sind. Habe dir deswegen die originalen JSON Dateien angehängt. Wenn du was wüsstest wie es funktioniert gib mir bitte grad bescheid.



Gruß Lex


----------



## Thruser (17 August 2018)

Hi,





Lex schrieb:


> Hi Thruser,
> 
> wüsste nicht wie ich das realisieren soll das die Infos in den Daten drine enthalten sind. Habe dir deswegen die originalen JSON Dateien angehängt. Wenn du was wüsstest wie es funktioniert gib mir bitte grad bescheid.
> 
> ...


alles Gut. Es ist alles enthalten. Man muß sich die Dateien nur mit dem Hex Editor ansehen. Oder online das Array in der SPS mit der Antwort.

Gruß


----------



## Thruser (8 April 2019)

Hallo,

habe gerade gesehen, daß es jetzt in der aktuellen e!cockpit Version 1.5.0.3 die Bibliothek WagoAppJSON gibt.

Die neisten Funktionen sind nicht sehr gut dokumentiert bis auf die Methode Fb_JSON_ParseAndModify.GetValueByPath die Du benötigst.

Gruß


----------



## Lex (22 April 2019)

Hi Thruser,

vielen lieben Dank für die Info! 
Ich hatte es gesehen nach dem ich ich schlau gemacht hatte, welche neuen Bibs in diesem Update implementiert wurden. 

P.S.: Dir noch Frohe Ostern!


----------

