Modbus TCP BOOL-Wert senden

Hallo zusammen,

ich habe ein Problem bei meinem ersten eigenem Modul, ich möchte über Modbus einen Bool-Wert senden doch leider erzeugt IP-Symcon immer ein Zeichen zuviel im Sendetex.
Zum Testen habe möchte ich eine Bool-Variable auf meiner Wago einschalten.
Hier mein PHP Code:

 
public function switch(bool $Switch)
    {
        $Address_Switch = 12287 + $this->ReadPropertyInteger("E-Address");
        $send = pack("a*",chr(255).chr(0));
        $send =utf8_encode($send);
        $this->SendDebug('Switch send', $send, 0);
        $Value = $this->SendDataToParent(json_encode(Array("DataID" => "{E310B701-4AE7-458E-B618-EC13A1A6F6A8}", "Function" => 5, "Address" => $Address_Switch , "Quantity" => 1, "Data" => $send));
    }

Hier die Ausgabe vom Client-Socket:


00 75 00 00 00 07 01 05 30 63 FF 00 

Wie man sieht liest Symcon anscheinend die Länge falsch aus, im Protokoll steht das 7 Zeichen gesendet werden, aber es werden nur 6 Übertragen was ja auch richtig ist, nur die 7 ist falsch.
Wenn ich die gleiche Funktion über die integrierte Modusanbindung realisiere funktioniert alles.


00 75 00 00 00 06 01 05 30 63 FF 00 

Was mache ich falsch?

Ist das Problem auch da wenn du Chr(0).Chr(0) senden würdest? (Das pack ist eigentlich gar nicht notwendig)
Auf den ersten Blick sieht das ganz gut aus.

paresy

Nein dann funktioniert alles.

Gesendet von iPhone mit Tapatalk

Ich kann das Problem auf jeden Fall nachstellen. Auf die Schnelle habe ich jedoch keine Lösung, da ich dafür einiges intern mehr umbauen muss.

paresy

Danke für deine schnelle Reaktion,
ich habe jetzt versucht das Problem noch etwas weiter einzugrenzen und es schein so als ob alle Werte die über 127 liegen fälschlicherweise als 2 Zeichen gezählt zu werden.
Das Problem ist auch bei Modbusfunktion 6 der Fall.

Bei Zahlwert 127 stimmt die Ausgabe:

$send = pack("a*",chr(127).chr(0));
        $send =utf8_encode($send);
        $this->SendDebug('Switch send', $send, 0);
        $Value = $this->SendDataToParent(json_encode(Array("DataID" => "{E310B701-4AE7-458E-B618-EC13A1A6F6A8}", "Function" => 6, "Address" => 12387 , "Quantity" => , "Data" => $send)));
TRANSMIT | 00 6D 00 00 00 06 01 06 30 63 7F 00 

Ab Zahlwert 128 passt es nicht mehr:

$send = pack("a*",chr(128).chr(0));
        $send =utf8_encode($send);
        $this->SendDebug('Switch send', $send, 0);
        $Value = $this->SendDataToParent(json_encode(Array("DataID" => "{E310B701-4AE7-458E-B618-EC13A1A6F6A8}", "Function" => 6, "Address" => 12387 , "Quantity" => 1, "Data" => $send)));
TRANSMIT | 00 6E 00 00 00 07 01 06 30 63 80 00 

Passiert bei 2 Werten über 127 genauso:

$send = pack("a*",chr(128).chr(128));
        $send =utf8_encode($send);
        $this->SendDebug('Switch send', $send, 0);
        $Value = $this->SendDataToParent(json_encode(Array("DataID" => "{E310B701-4AE7-458E-B618-EC13A1A6F6A8}", "Function" => 6, "Address" => 12387 , "Quantity" => 1, "Data" => $send)));
TRANSMIT | 00 73 00 00 00 08 01 06 30 63 80 80 

Ja. Es ist ein Problem mit der utf8 Kodierung. Nach dem utf8_encode ist ein Zeichen mehr da. Dies wird zwar am Ende korrekt per utf8_decode wieder reduziert, jedoch ist es an der Stelle wo die Länge berechnet wird nicht da. Das Problem tritt bei der nativen Instanz nicht auf, da diese Umkodierung dort nicht zutrifft.

paresy

Sorry, wenn ich das Thema wieder aufgreife, aber ich habe auch Probleme damit :frowning:

Hallo paresy,

darf man wissen, wie ihr die Daten bei der nativen Instanz Übertragt und ob es diese Möglichkeit für uns als Modul-Entwickler auch gibt?

Anscheinend wird das utf8_decode beim senden im ClientSocket nicht gemacht. Ich habe bei meinem Modul nämlich beim Schreiben von ModBus das folgende Problem (nur bei Werten > 127 wie auch bartjaysimpson bereits oben beschrieben hat):


$Value = pack('g', 1500.0); //Float 32Bit LittleEndian

$sendData['DataID'] = '{E310B701-4AE7-458E-B618-EC13A1A6F6A8}'; //ModBus Gateway RX/TX
$sendData['Function'] = $Function;
$sendData['Address'] = $Address;
$sendData['Quantity'] = $Quantity;
$sendData['Data'] = utf8_encode($Value);

//Fehler-Debugging Werte > 127 
echo '$Value HEX: '; var_dump(bin2hex($Value));
echo '$Value UTF-8 HEX: '; var_dump(bin2hex(utf8_encode($Value)));
echo '$sendData: '; var_dump(json_encode($sendData));
echo 'json_encode ERROR: '; var_dump(json_last_error_msg());

$result = $this->SendDataToParent(json_encode($sendData));

Wenn ich diesen Code ausführe, bekomme ich folgende Ausgaben:


$Value HEX: string(8) "0080bb44"
$Value UTF-8 HEX: string(12) "00c280c2bb44"
$sendData: string(122) "{"DataID":"{E310B701-4AE7-458E-B618-EC13A1A6F6A8}","Function":16,"Address":1040,"Quantity":2,"Data":"\u0000\u0080\u00bbD"}"
json_encode ERROR: string(8) "No error"

Der ursprüngliche HEX-Wert wurde also von utf8_encode um 2 Bytes (jeweils 0xc2) erweitert um die Werte > 127 (0x80 und 0xbb) ‚zu codieren‘. json_encode hat dann am Anfang noch 06 (\u00) hinzugefügt um 00 ‚zu schützen‘. Soweit i.O.

Im Debug-Log vom ModBus-Gateway erhalte ich nun aber folgenden Eintrag:

TRANSMIT 10 04 10 00 02 06 00 C2 80 C2 BB 44

Der Daten-Teil ist hier nach wie vor UTF-8 codiert: 06 00 C2 80 C2 BB 44
Das wäre hier auch noch i.O. wenn der ClientSocket das noch ändern würde.

Aber auch im Debug-Log vom ClientSocket bekomme ich folgende Ausgabe:

TRANSMIT 00 1F 00 00 00 0D 01 10 04 10 00 02 06 00 C2 80 C2 BB 44

Der Daten-Teil ist hier nach wie vor UTF-8 codiert: 06 00 C2 80 C2 BB 44

Irgendwo dazwischen wird dann das 06 am Anfang der Daten noch entfernt und am Ende wird beim mir im ModBus-Slave Simulator im Register 401041-42 folgender Wert abgelegt: 00 C2 80 C2
Also nur die ersten 4 Bytes des UTF-8 codierten Teils, was ja aus Sicht des Slaves auch korrekt ist, da er mit den letzten 2 Bytes (BB 44) nichts anfangen kann. Der Wert kommt so aber beim Slave natürlich falsch an.

Nehme ich einen anderen Wert für $Value, welcher keine Zeichen > 127 erzeugt (z.B. 2400.0), dann wird der Wert durch utf8_encode nicht verändert und am Ende landet im ModBus-Register der korrekte Wert 00 00 16 45

Wenn ich das Ganze mit der nativen IPS ModBus-Instanz durchspiele, habe ich auch bei einem Wert von 1500.0 überall korrekt den Wert von 00 80 bb 44
Das heisst für mich, ihr sendet die Daten irgendwie anders durch den Datenfluss :confused:

Ist das nun ein Bug im ModBus-Gateway / ClientSocket von IPS oder muss ich die Daten vorher irgendwie anders aufbereiten?

Wenn ich Paresy richtig verstanden habe, passiert grob folgendes. Pseudocodes des Splitters. Dieser ist ja vmtl tatsächlich in C++ implementiert. Und da ist das Problem, das man die Verbindung einerseits mit dem internen Modbus Geräten (die den json utf8 Quatsch nicht brauchen) und mit den php Modulen nicht korrekt ausweret.

function receiveFromChild($dataflow){
$daten = $dataflow->Data;
$laenge = strlen($daten);
if(/*Daten kommen über php Modul*/){
   $weiter = json_decode($daten);
}
// tue irgendwas und berücksichtige dabei $laenge
$blub->Data = /*magic verarbeitete Daten*/;
$this->SendToParent($blub);

Ich vermute, dass UTF8 alle Zeichen über 127 (ASCII) umwandelt.

Genau. Das ist leider noch ein interner Fehler, sodass aktuell PHP Module dies nicht zuverlässig nutzen können :frowning:

Ein Fix dafür kommt zur 5.6.

paresy

Cool. Danke für den Nachtrag mit dem Fix. Ich hatte ja vor über einem Jahr ein eigenes Modul für Modbus TCP gebaut bzgl. schnellerer Interaktion. Leider lief das nicht so wie von mir erwartet. Meine Idee wäre jetzt, das nochmal aufleben zu lassen und einfach nur aus 64bit (big Real) 64 Coils zu machen. Die ale einzelne Variable auszuspucken und entsprechend über ReuqestAction schaltbar zu machen.

Das würde in einigen meiner Installationen immerhin aus 100 Anfragen noch 10 machen (wenn man die Integer, etc. außen vor lässt).

Ein Fix dafür kommt zur 5.6.

Super! Dann kann ich ab 5.6 meine „Umgehung des Problems“ dann wieder aus dem Modul entfernen.

Bis dahin erstelle ich einfach die komplette TCP-Message und sende diese direkt an den Client-Socket mit ‚CSCK_SendText($SocketID, $sendData)‘ (da brauche ich keine UTF-8 Konvertierung :D).

Werde da aber in dem Fall nicht zu viel Zeit darin investieren, sonst seid ihr plötzlich mit 5.6 schneller fertig als ich mit meinem Modul :slight_smile:

Mal so ganz blöd gefragt: Warum brauche ich bei CSCK_SendText keine UTF Konvertierung? Findet die nicht intern auch statt? Greift der Befehl nicht auch in die Dataflow Kette?

CSCK_SendText sendet den String 1:1.
Ebenso wie RegVar_SendText.
Was intern passiert siehst du ja nicht. Und für den Datenfluss aus den PHP-SDK muss es UTF8 wegen dem JSON sein.
Michael

Genau. Ich sehe nicht was passiert. Könnte mir halt vorstellen, dass die Schnittstelle PHP->C++ immer JSON verlangt. So alleine aus Gründen der Einheitlichkeit. Daher die Überlegung, ob da z.B. intern immer ein json_encode passiert, ich das aber nicht sehe.

Der Datenfluss basiert immer auf JSON. Und JSON erwartet wiederum korrektes UTF8.

Das ist aber nicht das Problem [emoji1] Egal, ein Fix kommt zur 5.6 und löst das eher interne Problem :slight_smile:

paresy

Ist absehbar, dass ein Fix vielleicht schon in einer der nächsten „Beta“ Versionen auftaucht?

Gemäss Changelog der 6.0 ist das Problem nun behoben.
Bei mir funktioniert es jetzt jedenfalls korrekt und ich habe das Provisorium in meinem Modul soeben entfernt.

Vielen Dank! :blush:

1 „Gefällt mir“