ModBus und 32-bit Werte (Dword)

[ol]
[li]Für den ModBus scheint die Word-order von 32-bit-Werten nicht eindeutig festgelegt zu sein. Zumindest konnte ich bisher keine entsprechende Spezifikation dazu finden, und die auf dem Markt befindlichen ModBus-Geräte sind nicht einheitlich programmiert.
[/li]Die derzeitige IPS-ModBus-Implementierung (2.30 #1799) geht bei 32-bit Werten offensichtlich fest davon aus, daß in der Reihenfolge LSW (Least Significant Word 16bit) gefolgt vom MSW (Most Significant Word 16bit) übertragen wird. Das produziert bei Geräten, die in der Reihenfolge MSW gefolgt vom LSW übertragen, natürlich sehr merkwürdige Ergebnisse. Prinzipiell kann man die Werte vor/nach der Übertragung zwar mir einem Script und zusätzlichen Variablen umformen, aber es wäre sehr viel übersichtlicher, wenn bei der Configuration der ModBus-devices für die 32-bit Werte unterschiedliche Datentypen zur Verfügung stehen würden. z.B.:32bit – Unsigned – LSW-MSW
32bit – Unsigned – MSW-LSW
32bit – Signed – LSW-MSW
32bit – Signed – MSW-LSW
32bit – Float – LSW-MSW
32bit – Float – MSW-LSW

[li]Wohl weil IPS-Variablen kein 32bit-Unsigned kennen, wird dieser Modbus-Daten-Typ von IPS auf eine Integer-Variable abgebildet, was natürlich zu Fehlinterpretationen führen kann. Würde es vielleicht Sinn machen (zumindest optional) 32bit-Unsigned Modbus-Werte auf IPS-Float-Variablen abzubilden?
[/li][/ol]

Gruss,

Andreas

Ich kann Andreas nur beipflichten. Es ist total verwirrend, wenn man einen 32Bit unsigned Datentyp definiert und im IPS dann ein negativer Wert abgebildet wird nur weil das MSB gesetzt ist. Eine Abbildung in Real wäre an dieser Stelle absolut sinnvoll.

Gruß
Rubberduck

In meinen Augen ist das keine gute Idee!
Wer Datenaustausch mit unterschiedlichen Systemen betreibt, muss sich über die Fallstricke (MSB/LSB, Zahlenbereiche) klar sein.
Unsigned Int wird gerne für „Bitleisten“ verwendet um z.B. Statusinformationen zu übertragen. Und hier handelst du dir mit einer automatischen Wandlung nach Real wieder mehr Ärger ein.

Gruß
Dieter

Dieter, mir sind die Fallstricke sehr wohl klar, da ich beruflich viel mit dem Thema zu tun habe. Aber das Grundproblem ist, dass IPS intern scheinbar keine 32Bit Integer-Werte abbilden kann. Wenn ich von einem Fremdgerät einen Wert von FFFFFFFFh bekomme sollte nicht -1 als Ergebnis herauskommen sondern 4,294,967,295.
Man könnte jetzt sagen: lese doch einfach 2 Stk 16Bit Datensätze ein. Schaut man in das Debug-Fenster beim Modbus, sieht man, dass IPS die Daten einzeln von der Gegenstelle einliest. Es wird nicht, wie bei Modbus möglich ,gleich ein ganzer Adressbereich gelesen, sondern jede Instanz extra. Ist ja normalerweise kein Problem. Aber wenn ich einen 32Bit-Wert auf 2x16Bit einlese, kann es vorkommen, dass zwischen beiden Lesevorgängen von der Gegenstelle der Wert geändert wird. Dann habe ich 16Bit vom alten und 16Bit vom neuen Wert.

Ich gebe dir recht, dass die Wandlung auf Float für Bitweise Nachbearbeitung auch keine optimale Lösung ist. Die aktuelle Wandlung ist aber genauso wenig optimal. Hoffe, paresy findet eine optimale Lösung, die alle Bedürfnisse abdeckt.

Gruß
Rubberduck

Es gibt keine optimale Lösung. Intern ist ein 32Bit unsigned Int kein Problem. Das Problem ist, dass PHP keine 32Bit unsigned Ints kann. Und solange PHP diese nicht kann, gibt es keine optimale Lösung für das Problem. Es sei denn ihr haltet es für sinnvoll einen 32Bit Unsinged Int in 2x16Bit Variablen zu splitten.

Das Little/Big-Endian Problem müsst ihr mich noch einmal erklären… Welche Geräte nutzen das andersrum? Das ModBus Protokoll spezifiziert, dass immer Big-Endian verwendet wird.

paresy

Hallo paresy,

meiner Meinung nach können wir uns das ersparen, wenn 32Bit unsigned seitens PHP nicht geht. Eine Aufsplittung würde für meine Sache dann genauso eine Umrechnung benötigen. Da können wir es so lassen, wie es ist und du ersparst dir Arbeit.:slight_smile:

Das Little/Big-Endian Problem habe ich bei den Integer-Werten nicht. Aber dafür so ein ähnliches Problem bei den Floating-Point-Umrechnungen: http://www.ip-symcon.de/forum/f41/hilfe-modbus-floatingpoint-umrechnung-bringt-falsche-werte-12191/

Gruß
Rubberduck

Das Little/Big-Endian Problem müsst ihr mich noch einmal erklären… Welche Geräte nutzen das andersrum? Das ModBus Protokoll spezifiziert, dass immer Big-Endian verwendet wird.

z.B. Meßgeräte von Schneider Electric bzw. Merlin Gerin
Habe gerade ein PM9C von Schneider Electric angeschlossen. Dort werden die 32-bit Registerwerte immer in der Reihenfolge MSW-LSW übertragen, was meiner Erinnerung nach der Big-Endian definition entspricht.
Falls der PM9C Instruction sheet (GHE12248AC.pdf) nicht zu finden sein sollte, kann ich es auch per Mail schicken.

Gruss,

Andreas

Eine Option ob die Bytes geswappt werden, kann ich einbauen. Wollt ihr es lieber pro ModBus Instanz, oder lieber direkt im ModBus-Gateway, sodass es alle Unter-Instanzen betrifft? (Mir scheint das zweite besser, da es ja normalerweise das Gerät betrifft und das Gerät ja innerhalb sich selbst konsistent in dieser Eigenschaft arbeiten sollte)

paresy

Auf Instanz-Ebene wäre es auf alle Fälle flexibler. Ist zwar mehr Arbeit zum Parametrieren, aber wer weiß schon, welche Geräte noch in Zukunft mit IPS reden wollen. Für meine Bedürfnisse wäre es egal wo die Einstellmöglichkeit sitzt.

So wie Andreas es angeführt hat (wenn ich es richtig verstanden habe), sollte es aber ein Word-Swap sein. Das würde mir auch meine Floating-Point-Umrechnung ersparen und ich könnte die direkt eingelesenen Werte weiterverarbeiten.

Gruß
Rubberduck

Eine Option ob die Bytes geswappt werden, kann ich einbauen. Wollt ihr es lieber pro ModBus Instanz, oder lieber direkt im ModBus-Gateway, sodass es alle Unter-Instanzen betrifft?

Es wird kein Byte-Swap benötigt!
Die beiden 16-bit Wort-Hälften sind vertauscht bei 32-bit Transfers!
Wo das letztendlich angepasst werden kann (pro ModBus Instanz oder im ModBus-Gateway), ist eigentlich egal.

Zum Verdeutlichen was im Moment passiert, nur noch mal ein Beispiel:


IPS sendet zunächst einen Dword-request für Adresse 1008 an ein PM9C um die
Wechselspannung zwischen zwei Phasen in mV als 32-bit Wert zurückzubekommen
(normalerweise Werte zwischen 380000 und 400000 mV):

Für den Rücktransport des 32-bit Wertes erscheint im Debug-Log des ModBus-Servers folgendes:
 Received Modbus RTU frame (9):                01 03 04 00 05 F4 9C AC 9B 
 Forwarding packet from serial(0) to tcp(0), PDU: 03 04 00 05 F4 9C 
 Sending TCP-packet:         00 00 00 00 00 07 01 03 04 00 05 F4 9C 

Im IPS-debug-Fenster vom Modbus socket erscheint daraufhin:
  21.11.2010 22:08:07.00 |             Received | 03 04 00 05 F4 9C

Als Ergebnis erscheint daraufhin im IPS-ModBus-Device-Value:  -191102971
Hexadezimal ergibt das:  0xF49C0005

Als Ergebnis sollte aber 0x0005F49C (390300 mV sein) erscheinen.

Das heißt der Byte-Strom wird von IPS in der richtigen Reihenfolge empfangen.
Aber dann wird der IPS-Value aus den 4 übermittelten Daten-Bytes in der Byte-Reihenfolge B3-B4-B1-B2 zusammengebaut und nicht den Big-Endian-Regeln entsprechend B1-B2-B3-B4, was aber eigentlich der Normalfall sein sollte.

Hoffe das einigermassen verständlich dargestellt zu haben.

Gruß,

Andreas

Ja. Hast du. Für die Geräte, die ich zum Testen hatte, wurde dieses Swapping benötigt. Ich habe für die nächste Version eingebaut, dass man dieses Swapping für 32Bit Werte deaktivieren kann.

paresy