Modbus TCP - Wie die abgefragten Integer-Register-Werte "zusammenbauen" in String, Long, Double, etc...

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 44 Antworten in diesem Thema. Der letzte Beitrag () ist von dive26.

    So, @dive26 ich habe erste Informationen sammeln können, aber habe noch keinen 100% Überblick. Tu mich grad auch schwer weil schon spät.

    Was ich jetzt schon dazu sagen kann:
    Die EasyModbusTCP ist für diesen Zweck unbrauchbar, weil die nur die Funktionscodes 1, 2, 3, 4, 5, 6, 15, 16 und 23 unterstützt sind, um einen Upload zu starten wird der Funktionscode 0x41, was in Dezimal 65 ist verwendet. Eigene Funktionscodes ist nichts implementiert.

    Die WSMBT könnte möglichweise auch unbrauchbar sein, da bin ich aber noch nicht ganz sicher, aber glaube mit 97.5% Wahrscheinlichkeit unbrauchbar. Die WSMBT hat zwar Funktionen für UserDefined-Zeugs, wo man auch einen eigenen Funktionscode angeben kann, aber nur um in UserDefined Coils und Register zu schreiben. Daher mein starker Zweifel.

    Was ich vermute:
    Mann muss selbst das Protokoll studieren, selbst die Anfrage machen und die weitere Kommunikation, so wie das auf dem Bild der Huawei Doku Seite 91 Figure 6-6 File uploading process dargestellt ist.

    Morgen Nachmittag schaue ich weiter, gucke mir dann mal das hier genauer an:
    modbus.org/docs/Modbus_Application_Protocol_V1_1b.pdf

    Sollte das Protokoll wie manche im Netz sagen einfach gestrickt sein, stehen die Chancen gut das gebacken zu bekommen, selbst wenn die Bibliotheken unbrauchbar sind für diesen Zweck.

    Eine Frage habe ich noch. Dieser Inverter ist sicherlich ein Slave oder?
    @BitBrösel

    ​Eine Frage habe ich noch. Dieser Inverter ist sicherlich ein Slave oder?


    Die Konfiguration sieht so aus:
    Auf dem Hautpwechselrichter (Modbus ID 2) steckt ein WLAN Dongle (Modbus ID 0) und der zweite Wechselrichter hat (Modbus ID 3).
    Mein Rechner ist Master und die Zielgeräte sind Slave.
    Die 34 Optimierer sind auf Wechselrichter zwei (Modbus ID 3) installiert.

    ​Morgen Nachmittag schaue ich weiter, gucke mir dann mal das hier genauer an:modbus.org/docs/Modbus_Application_Protocol_V1_1b.pdfSollte das Protokoll wie manche im Netz sagen einfach gestrickt sein, stehen die Chancen gut das gebacken zu bekommen, selbst wenn die Bibliotheken unbrauchbar sind für diesen Zweck.

    Das wäre ja toll wenn das wirklich irgendwie hinzubekommen wäre.

    Habe gestern (heute) noch lange gegoogelt. Auch Huawei hält sich bei diesem Thema bedeckt und verweist nur auf die Beschreibung. Auch im Huawei Forum haben andere keine Antwort auf die Frage nach einem Beispielquellcode (in irgend einer Sprache) erhalten.
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at
    @BitBrösel

    Habe da etwas gefunden für Funktionscode 65. Das würde sich mit Kapitel 6.3.7.1.1 der Schnittstellenbeschreibung decken.


    docs.osisoft.com/bundle/pi-int…age/function-code-65.html

    Some PLC's are able to understand function code 65,
    which is a non-standard Modbus function code. One type of PLC that
    understands function code 65 is called an HTMUX box. If such a PLC
    receives function code 65, it knows that a 4-byte floating point should
    be returned.



    Each register that can be read with function code 65
    contains 4 bytes of information. Standard registers can hold only two
    bytes of information. Function code 65 is similar to data type 4 above,
    except that there is no need to map a single register to two different
    registers. Each register can already hold 4 bytes.



    Wenn ich das richtig verstanden habe, sendet man an eine bestimmte Registeradresse diese Daten (mit WriteRegister ...).
    Dann wartet man eine bestimmte Zeit ab (2000 ms) und liest den selben Register wieder aus und erhält dann die Daten?

    Hier habe ich auch noch etwas gefunden was vielleicht helfen könnte: github.com/Emilv2/huawei_solar
    Leider kenne ich mich mit Phyton nicht so aus.
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at
    @BitBrösel

    Ich habe etwas interessantes gefunden um das Rad nicht zweimal erfinden zu müssen.
    Damit kann ich schon normale "HoldingRegister" auslesen.

    Es läuft mit Sockets und nur mit .NET Boardmitteln.
    Vielleicht kann man das als Basis für die Funktion 65 (0x41) verwenden.
    Ich bin leider zu wenig schlau um das hinzubekommen ;-).
    Dateien
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at
    Ich habe auch noch was, wo man mal gucken kann. das fehlte mir bei dem Src auf Github.
    gitlab.com/Emilv2/huawei-solar/-/tree/master


    Ich kann erst am Wochenende weiter schauen. Aber etwas was mich irritiert. Warum muss man was Uploaden? Kann es nicht sein , das die Daten doch schon irgendwo in einem Register sind? Ich hatte irgendwo auch etwas mit Register über 30000 gesehen, finde es gerade nicht wieder. Ich habe den Verdacht, das man damit nur ein Update auslöst, ab diesem wird dann alle 5 Minuten ein Update gemacht, kommt mir wenn das nicht so ist, wie ein Fehldesign vor. Gibt ja immerhin UShort.MaxValue Register, genug für Hunderte Optimizer.

    Schau mal ob du in dem Code bei Gitlab Register-Indizes dazu findest.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „BitBrösel“ ()

    @BitBrösel

    Vielen Dank für Deinen Einsatz.

    Ich habe das so verstanden (kann mich aber auch irren).

    1. Es wird ein Befehl 65 (0x41) mit 4 Bytes gesendet.
    2. Eine definierte Zeitspanne warten (2 Sekunden laut Huawei)
    3. Response auslesen

    Und das irgendwie ein paar mal hin und her.
    Eine Echte "Datei" wird zwar nicht gesendet, aber ein paar Daten über den Socket (das nennen die Dann fileupload).

    Ich habe auch schon kontakt mit dem Huawei-Support aufgenommen.
    Auch der Deutschland-Huawei-Vertreter ist schon mit mir in Kontakt.
    Vielleicht bekommen wir einen Sourcecode in irgend einer Sprache präsentiert, den wir dann in VB.NET nachbauen können.

    Die Oberfläche und die interne Verarbeitungslogik ist so gut wie fertig (noch Optimierer-Dummy-Daten drin, bis Echtdaten vorliegen) ;-).
    Bilder
    • 27102022161310.jpg

      411,24 kB, 1.083×715, 60 mal angesehen
    • 27102022161319.jpg

      301,51 kB, 986×706, 64 mal angesehen
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at
    Ah ja, also das ist dann schon mal etwas klarer. Denn ich war am Rätseln, was und weshalb man da etwas hochzuladen hat, wenn da eh was anderes kommt. Ich werde am Wochenende mal selbst eine Implementation von Modbus anlegen, das ist durchaus etwas was ich auch für RaspBerry PIs, Arduinos oder STM32 nutzen könnte. Testen kann ich das ja ganz einfach mit den EasyModbus-Emulator.

    Danach kann ich zumindest weitere Empfehlungen geben, bzw. eine Sub vorbereiten und du kannst das dann bei dir testen. Wenn es wirklich nur das ist, dann sollte es einfach sein, wenn man Modbus gut kennt.

    Edit @dive26
    Ich hab da gerade so eine ganz bekloppte Idee.

    Du sagtes man schreibt 4 Bytes, ich sehe gerade in 6.3.7.1.2, Table 6-18 auch 4 Bytes. Nimm mal einen TcpClient oder nutze Sockets, verbinde dich und schreibe einfach diese Bytes

    1->0x41 //Funktionscode
    2->0x6 //Sub-Funktioncode
    3->0x3 // DataLength, in der Descrition steht 3, also probieren
    4->0x44 //filetype, also V101

    Wenn eine Antwort kommt, alles was kommt lesen und in eine Datei schreiben, so wie es kommt. Wenn eine Antwort kam, häng die Datei mal hier an. Wenn es die Daten sind, die du willst, mach ich eine Klasse und du kannst auswerten.

    Sollte keine Antwort kommen, schreibe noch 4 Bytes, so wie 6.3.7.1.3 "Completing the Data Upload", wenn die bei Huawei sagen 4 Bytes schreiben, sollte das eigentlich reichen.

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „BitBrösel“ ()

    @BitBrösel

    Habe folgenden Code dazu erstellt. Aber es kommt keine Rückmeldung vom Inverter:

    VB.NET-Quellcode

    1. Imports System.Net
    2. Imports System.Net.Sockets
    3. Imports System.Threading
    4. Public Class FC03Form
    5. Dim Modbus_Socket As Socket = Nothing
    6. Private Function Display(data As Byte()) As String
    7. Dim result As String = String.Empty
    8. For Each item As Byte In data
    9. result += String.Format("{0:X2} ", item)
    10. Next
    11. Return result
    12. End Function
    13. Private Sub Button_SendeHuawei_Click(sender As Object, e As EventArgs) Handles Button_SendeHuawei.Click
    14. txtResult.Text = ""
    15. Modbus_Socket = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
    16. Modbus_Socket.ReceiveBufferSize = 256
    17. Modbus_Socket.SendBufferSize = 256
    18. Dim M_server As IPEndPoint = New IPEndPoint(IPAddress.Parse("192.168.0.188"), 502)
    19. 'Mit dem Server verbinden
    20. Debug.Print("Verbinde mit Server")
    21. Modbus_Socket.Connect(M_server)
    22. Modbus_Socket.SendTimeout = 3000
    23. Modbus_Socket.ReceiveTimeout = 3000
    24. Debug.Print("OK")
    25. Dim frame As Byte() = New Byte(3) {65, 5, 3, 68} ' 0x41, 0x06, 0x03, 0x44
    26. frame(0) = 65 'unnötig da oben bereits in geschweiften Klammern?
    27. frame(1) = 5 'unnötig da oben bereits in geschweiften Klammern?
    28. frame(2) = 3 'unnötig da oben bereits in geschweiften Klammern?
    29. frame(3) = 68 'unnötig da oben bereits in geschweiften Klammern?
    30. txtSendMsg.Text = Me.Display(frame) ' Formatierte Ausgabe in einem Textfeld
    31. 'Daten senden
    32. Debug.Print("Sende Daten")
    33. Modbus_Socket.Send(frame, frame.Length, SocketFlags.None) 'Sende zu Socket
    34. Debug.Print("OK")
    35. Thread.Sleep(3000) ' 3 Sekunden Zeit geben
    36. 'Daten empfangen
    37. Dim buffRecei As Byte() = New Byte(255) {}
    38. Dim ns As NetworkStream = New NetworkStream(Modbus_Socket)
    39. ns.ReadTimeout = 10000 'Mehr als 10 Sekunden darf es nicht dauern
    40. If ns.CanRead Then
    41. Debug.Print("Empfange Daten")
    42. '####### Gegenstelle reagiert nicht - hier kommt die Fehlermeldung:
    43. Dim rs As Integer = Modbus_Socket.Receive(buffRecei, buffRecei.Length, SocketFlags.None)
    44. Debug.Print("OK")
    45. End If
    46. If IsDBNull(buffRecei) Then
    47. Debug.Print("Keine Rückgabedaten")
    48. Else
    49. txtResult.Text = Display(buffRecei) ' Formatierte Ausgabe in einem Textfeld
    50. End If
    51. Modbus_Socket.Close()
    52. End Sub
    53. End Class



    Alternativ habe ich auch noch das versucht:

    VB.NET-Quellcode



    Fehlermeldung bei Zeile 60:
    Verbinde mit Server
    OK
    Sende Daten
    OK
    Empfange Daten
    Ausnahme ausgelöst: "System.Net.Sockets.SocketException" in System.dllEin Ausnahmefehler des Typs "System.Net.Sockets.SocketException" ist in System.dll aufgetreten.
    Ein Verbindungsversuch ist fehlgeschlagen, da die Gegenstelle nach einer bestimmten Zeitspanne nicht richtig reagiert hat, oder die hergestellte Verbindung war fehlerhaft, da der verbundene Host nicht reagiert hat


    Ob ich als Sub-Funktionscode 5 oder 6 schicke macht auch keinen Unterschied.
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „dive26“ ()

    Mir kommt die 3 komisch vor, probier auch mal mit datalength 0 und 1

    Und ja, die 4 Zeile wo du die Bytes erneut zuweist sind unnötig.

    Sieh mal in der FC03Form, das Projekt das du hochgeladen hast, in dem Projekt schreib mal die Bytes

    Also allein verbinden und die 4 BYtes können nicht reichen, beim Lesen, wird mehr geschrieben,

    VB.NET-Quellcode

    1. Dim frame As Byte() = New Byte(10) {} ' Total 11 Bytes
    2. frame(0) = CByte(id \ 256) ' Transaction Identifier High
    3. frame(1) = CByte(id Mod 256) ' Transaction Identifier Low
    4. frame(2) = 0 ' Protocol Identifier High
    5. frame(3) = 0 ' Protocol Identifier Low
    6. frame(4) = 0 ' Message Length High.
    7. frame(5) = 5 ' Message Length Low(5 bytes to follow)
    8. frame(6) = slaveAddress ' The Unit Identifier(slave Address/Slave Id).
    9. frame(7) = &h41
    10. frame(8) = &h6
    11. frame(9) = &h3 ' oder 0 oder 1
    12. frame(10) = &h44


    Oder auch mal Je Feld je HIGH und LOW. Wenn ich das so sehe, denke ich mir, meine Güte mehr ist das nicht? Hatte am Wochenende was zu knobeln erwartet, wenn ich so in die Register schreiben kann und lesen, dann ist das nach dem ich das Protokoll studiert hab, in kürzester Zeit fertig, aber halt nur die Standart Dinger. Ich hätte eher in die Mapp schauen sollen.

    Dieser Beitrag wurde bereits 7 mal editiert, zuletzt von „BitBrösel“ ()

    Das hatte ich auch noch versucht (ging irgendwie in meinem Post oben unter):

    VB.NET-Quellcode

    1. Dim frame As Byte() = New Byte(7) {}
    2. frame(0) = Convert.ToByte("0x41", 16) 'Functionscode
    3. frame(1) = Convert.ToByte("0x05", 16) 'Sub-Funktionscode
    4. frame(2) = Convert.ToByte("0x05", 16) 'Data Lenght (1 + N)
    5. frame(3) = Convert.ToByte("0x44", 16) 'File type (Unique ID of a file)
    6. frame(4) = Convert.ToByte("0x00", 16) 'Leere Bytes (N)
    7. frame(5) = Convert.ToByte("0x00", 16) 'Leere Bytes (N)
    8. frame(6) = Convert.ToByte("0x00", 16) 'Leere Bytes (N)
    9. frame(7) = Convert.ToByte("0x00", 16) 'Leere Bytes (N)


    Aber ja, Du könnstes Recht haben. Da gibts immer high und low.
    Werde ich morgen gleich mal ausprobieren.
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at
    @BitBrösel

    Habe mich bis halb drei in der Früh damit gespielt.
    Ich erhalte nun Rückmeldungen, mit denen kann ich aber nichts anfangen.
    Womöglich passt das Datenpaket noch nicht.

    Ich hänge mal den kompletten Code ran.
    Habe alles etwas gekürzt um es übersichtlicher zu machen.
    Die original "Read Holding Register" Funktion ist auch noch dabei (die funktioniert ja), damit man dies 1:1 vergleichen kann.

    Im Anhang habe ich Screenshots gemacht mit welchen Eingabewerte ich welche Ausgabewerte erhalten habe.
    Vielleicht siehst Du meinen Fehler auf den ersten Blick.

    Die Bytes 0-6 sind 100% die richtigen, da abweichende Werte keine Antwort vom Server bringen.
    Byte 7 bis 11 sollten normalerweise das "Upload-File-Paket" sein. Byte 7 müsste passen, aber wenn ich die Bytes auf die 4 notwendigen Bytes aufteile, bleibt mir immer eins übrig ;-).

    VB.NET-Quellcode

    1. Option Strict On
    2. Imports System.Net
    3. Imports System.Net.Sockets
    4. Imports System.Threading
    5. Public Class FC03Form
    6. 'Declare variables & constants.
    7. Private mSocket As Socket = Nothing
    8. Private Const IP As String = "192.168.0.188"
    9. Private Const Port As UShort = 502
    10. Private Sub FC03Form_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    11. Try
    12. Me.Connect() ' Connect to device.
    13. Catch ex As Exception
    14. MessageBox.Show(Me, ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
    15. End Try
    16. End Sub
    17. Private Sub FC03Form_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
    18. Try
    19. Me.Disconnect() ' Disconnect with device.
    20. Catch ex As Exception
    21. MessageBox.Show(Me, ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
    22. End Try
    23. End Sub
    24. ''' <summary>
    25. ''' Function: Connect to device.
    26. ''' </summary>
    27. Private Sub Connect()
    28. Me.mSocket = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
    29. Me.mSocket.ReceiveBufferSize = 256
    30. Me.mSocket.SendBufferSize = 256
    31. Dim server As IPEndPoint = New IPEndPoint(IPAddress.Parse(FC03Form.IP), FC03Form.Port)
    32. Me.mSocket.Connect(server)
    33. End Sub
    34. ''' <summary>
    35. ''' Function: disconnect with device.
    36. ''' </summary>
    37. Private Sub Disconnect()
    38. If Not IsDBNull(Me.mSocket) Then
    39. Me.mSocket.Close()
    40. End If
    41. End Sub
    42. ''' <summary>
    43. ''' Function: Display frame.
    44. ''' </summary>
    45. ''' <param name="data">frame: byte()</param>
    46. ''' <returns>frame: String</returns>
    47. Private Function Display(data As Byte()) As String
    48. Dim result As String = String.Empty
    49. For Each item As Byte In data
    50. result += String.Format("{0:X2} ", item)
    51. Next
    52. Return result
    53. End Function
    54. ''' <summary>
    55. ''' Original Funktion die Holding Register (Funktionscode 3) ausliest
    56. ''' Diese Funktion funktioniert einwandfrei
    57. ''' </summary>
    58. ''' <param name="sender"></param>
    59. ''' <param name="e"></param>
    60. Private Sub btnReadHoldingRegisters_Click(sender As Object, e As EventArgs) Handles btnReadHoldingRegisters.Click
    61. Try
    62. Dim slaveAddress As Byte = 3 ' The Unit Identifier
    63. Dim functionCode As Byte = 3 ' Function.
    64. Dim id As UShort = functionCode ' Transaction Identifier .
    65. Dim startAddress As UShort = 30070 ' Starting Address .
    66. Dim numberOfPoints As UShort = 4 ' Quantity of Registers . Read 2 real(float) number. Note: Unit Word(1 Word = 2byte= 16bit, 1 Real/Float = 4byte= 2 Word = 32 bits).
    67. Dim frame As Byte() = New Byte(11) {} ' Total 12 Bytes
    68. frame(0) = CByte(id \ 256) ' Transaction Identifier High
    69. frame(1) = CByte(id Mod 256) ' Transaction Identifier Low
    70. frame(2) = 0 ' Protocol Identifier High
    71. frame(3) = 0 ' Protocol Identifier Low
    72. frame(4) = 0 ' Message Length High.
    73. frame(5) = 6 ' Message Length Low(6 bytes to follow)
    74. frame(6) = slaveAddress ' The Unit Identifier(slave Address/Slave Id).
    75. frame(7) = functionCode ' Function.
    76. frame(8) = CByte(startAddress \ 256) ' Starting Address High.
    77. frame(9) = CByte(startAddress Mod 256) ' Starting Address Low.
    78. frame(10) = CByte(numberOfPoints \ 256) ' Quantity of Registers High
    79. frame(11) = CByte(numberOfPoints Mod 256) 'Quantity of Registers Low
    80. txtSendMsg.Text = Me.Display(frame) ' Zeige zu sendende Bytes im Textfeld
    81. ' Send Data
    82. Me.mSocket.Send(frame, frame.Length, SocketFlags.None)
    83. Thread.Sleep(100) ' Delay 100ms.
    84. ' Received data.
    85. Dim buffRecei As Byte() = New Byte(255) {}
    86. Dim ns As NetworkStream = New NetworkStream(Me.mSocket)
    87. If ns.CanRead Then
    88. Dim rs As Integer = Me.mSocket.Receive(buffRecei, buffRecei.Length, SocketFlags.None)
    89. End If
    90. If IsDBNull(buffRecei) Then
    91. Return
    92. End If
    93. Dim sizeBytes = buffRecei(8) ' The data byte received.
    94. If (functionCode = buffRecei(7)) Then
    95. Dim byteMsg As Byte() = New Byte(8 + sizeBytes) {}
    96. Array.Copy(buffRecei, 0, byteMsg, 0, byteMsg.Length)
    97. txtReceiMsg.Text = Me.Display(byteMsg) ' Display frame: received.
    98. Dim data As Byte() = New Byte(sizeBytes - 1) {} ' Okay: Ready!!!
    99. Array.Copy(buffRecei, 9, data, 0, data.Length)
    100. ' Process data.
    101. Dim result As UShort() = DataType.Word.ToArray(data) ' Convert byte array to ushort array.
    102. txtResult.Text = String.Empty
    103. For Each item As UShort In result
    104. txtResult.Text += String.Format("{0}/ ", item)
    105. Next
    106. End If
    107. Catch ex As Exception
    108. MessageBox.Show(Me, ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
    109. End Try
    110. End Sub
    111. ''' <summary>
    112. ''' Huawei-defined Funktion die (Funktionscode 65) ausliest
    113. ''' Diese Funktion funktioniert liefert eine Antwort mit einem Fehlercode zurück
    114. ''' da wohl einige mitgeschickte Daten falsch sind.
    115. ''' </summary>
    116. ''' <param name="sender"></param>
    117. ''' <param name="e"></param>
    118. Private Sub Button_0x41_Click(sender As Object, e As EventArgs) Handles Button_0x41.Click
    119. Try
    120. Dim FunctionCode As Byte = 65 ' SubFunction.
    121. Dim SubfunctionCode As Byte = 5 ' SubFunction.
    122. 'Es müssen mindestens 11 Bytes sein.
    123. 'Bei weniger kommt keine Rückmeldung vom Server
    124. 'Mehr macht nichts
    125. 'Bytes 0-6 sind 100% korrekt - hier habe ich alles durchgetestet
    126. 'Bytes 7-1x bekomme ich nicht gebacken.
    127. Dim frame As Byte() = New Byte(11) {}
    128. frame(0) = CByte(FunctionCode \ 256) ' Funktionscode 65 (0x41)
    129. frame(1) = CByte(FunctionCode Mod 256) ' Funktionscode65 (0x41)
    130. frame(2) = 0 ' Alles andere als 0 ergibt keine Antwort vom Server
    131. frame(3) = 0 ' Alles andere als 0 ergibt keine Antwort vom Server
    132. frame(4) = CByte(6 \ 256) ' Message Length High - 6 ist korrekt, alle anderen Daten ergeben keine Antwort vom Server
    133. frame(5) = CByte(6 Mod 256) ' Message Length Low - 6 ist korrekt, alle anderen Daten ergeben keine Antwort vom Server
    134. frame(6) = 3 ' Das ist die Modbus Geräte ID (in meinem Fall die 3) ###FIX KORREKT
    135. 'Frame 7 kann nur SubFunctionsCode sein
    136. '0 ergibt eine Response mit 80
    137. '5 ergibt eine Response mit 85
    138. '65 ergibt eine Response mit C1 (Fehler) und den Fehlercode 3 "Illegal data value"
    139. 'Also kann hier nur der Subfunctionscode (5 / 0x05) reinkommen
    140. frame(7) = SubfunctionCode 'Wird hier 0 übergeben kommt die Rückmeldung 80, bei 5 kommt 85 als Rückmeldung in Byte 8 des response
    141. frame(8) = 3 '?
    142. frame(9) = 68 '?
    143. frame(10) = 0 '?
    144. frame(11) = 0 '?
    145. ' Zeige zu sendende Bytes im Textfeld
    146. txtSendMsg.Text = Me.Display(frame)
    147. 'Ergebnis der Ausgabe: 00 41 00 00 00 06 03 41 05 02 44 00
    148. ' Send Data
    149. Me.mSocket.Send(frame, frame.Length, SocketFlags.None)
    150. Thread.Sleep(100) ' Delay 100ms.
    151. ' Received data.
    152. Dim buffRecei As Byte() = New Byte(256) {}
    153. Dim ns As NetworkStream = New NetworkStream(Me.mSocket)
    154. If ns.CanRead Then
    155. Dim rs As Integer = Me.mSocket.Receive(buffRecei, buffRecei.Length, SocketFlags.None)
    156. End If
    157. ' Zeige zu sendende Bytes im Textfeld
    158. txtResult.Text = Me.Display(buffRecei)
    159. 'Ergebnis der Ausgabe: 00 41 00 00 00 03 03 C1 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    160. 'C1 = Error Code
    161. '03 = Fehler "Illegal data value"
    162. 'The value contained in the query data field is not an allowable value for the server (Or slave). The
    163. 'value indicates a fault in the structure of the
    164. ' remainder of a complex request, such as an
    165. 'incorrectly implied length. It specifically does Not
    166. 'mean that a data item submitted for storage in a
    167. 'register has a value outside the expectation of
    168. 'the Application program since the Modbus
    169. 'protocol Is unaware of the significance of any
    170. 'particular value of any particular register.
    171. Catch ex As Exception
    172. MessageBox.Show(Me, ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
    173. End Try
    174. End Sub
    175. End Class
    Bilder
    • Rückgabewert_80_01.jpg

      301,28 kB, 1.412×511, 58 mal angesehen
    • Rückgabewert_85_01#.jpg

      427,61 kB, 1.659×640, 55 mal angesehen
    • Rückgabewert_85_01.jpg

      297,04 kB, 1.370×498, 45 mal angesehen
    • Rückgabewert_C1_03.jpg

      296,23 kB, 1.298×454, 49 mal angesehen
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at

    dive26 schrieb:

    '65 ergibt eine Response mit C1 (Fehler) und den Fehlercode 3 "Illegal data value"


    Das muss nicht bedeuten, das der Sub-FunktionsCode reicht oder das der Funktionscode falsch ist. Eine Antwort ist gut, besser als keine. Denn das heißt da funktioniert schon was. Kommt keine ist Grundsätzlich was falsch.

    0x03 Illegal Data Value
    The value contained in the query data field is notan allowable value for the server (or slave). Thevalue indicates a fault in the structure of theremainder of a complex request, such as anincorrectly implied length. It specifically does notmean that a data item submitted for storage in aregister has a value outside the expectation ofthe application program since the Modbusprotocol is unaware of the significance of anyparticular value of any particular register.


    Also den Funktionscode ganz vorne rein ist komplett falsch. Dort kommt eine eindeutige ID(Transaction Identifier) für Requests hin, nach jedem Request sollte die also ums 1 steigen. so das jeder Request identifiziert werden kann(Das sollte dann auch in der Antwort zu finden sein). Die ersten 7 Bytes sind immer ein MBAP-Header

    2 Bytes Transaction Identifier
    2 Bytes Protocol Identifier müssen beide 0 sein
    2 Bytes Lenght, Anzahl der Bytes die nach diesen beiden Bytes geschrieben werden. also Anzahl folgende Bytes inkl. das 1 Byte für Unit ID
    1 Byte Unit Identifier, also die ID vom Slave oder Master

    Aber ich Depp, sehe mehr und mehr einen Zusammenhang, ich hatte nicht ganz korrekt gelesen. Man sollte nicht zu viel parallel machen.
    Führe Schritt 1 aus und zeige uns das Ergebnis(Antwort der Gegenstelle)

    Ich habe ein wenig Code vorbereitet, den ich aber nicht testen kann. Kommt eine Antwort?

    VB.NET-Quellcode

    1. Private Sub DoRequest()
    2. Dim frameStartUpload() As Byte = GetFrameStartUpload(&H44)
    3. Dim mbap() As Byte = GetMBAP(&H3, frameStartUpload.Length)
    4. 'mbap schreiben
    5. 'und sofort FrameStartUpload
    6. 'Antwort auswerten
    7. End Sub
    8. Private Function GetFrameStartUpload(fileType As Byte) As Byte()
    9. Dim functionsCode As Byte = &H41
    10. Dim subFunctionsCode As Byte = &H5
    11. Dim dataLenght As Byte = 1 ' 1+N, N = Customdata lenght, we dont send customdata
    12. Return New Byte(3) {functionsCode, subFunctionsCode, dataLenght, fileType}
    13. End Function
    14. Private Function GetFrameStartUpload(fileType As Byte, customData() As Byte) As Byte()
    15. Dim functionsCode As Byte = &H41
    16. Dim subFunctionsCode As Byte = &H5
    17. Dim dataLenght As Byte = CByte(1 + customData.Length) ' 1+N, N = Customdata lenght
    18. Dim frame() As Byte = New Byte(3 + customData.Length) {}
    19. frame(0) = functionsCode
    20. frame(1) = subFunctionsCode
    21. frame(2) = dataLenght
    22. frame(3) = fileType
    23. Array.Copy(customData, 0, frame, 4, customData.Length)
    24. Return frame
    25. End Function
    26. Private Function GetMBAP(unitId As Byte, dataLenght As Integer) As Byte()
    27. Static id As Integer = 0
    28. Dim mbap() As Byte = New Byte(6) {}
    29. mbap(0) = CByte(id \ 256)
    30. mbap(1) = CByte(id Mod 256)
    31. mbap(2) = 0
    32. mbap(3) = 0
    33. mbap(4) = CByte((dataLenght + 1) \ 256)
    34. mbap(5) = CByte((dataLenght + 1) Mod 256)
    35. mbap(6) = unitId
    36. id += 1
    37. Return mbap
    38. End Function


    Gibt dann 3 Möglichkeiten
    1->Keine Antwort
    2->FehlerResponse
    3->Daten wie in Table 6-16 beschrieben.
    @BitBrösel

    Hier die Antwort (siehe Screenshot).
    Bei jeder weiteren Anfrage erhöht sich der Protocol identifier beim senden und empfangen (Frame 2).

    Das mitschicken von Customdata (egal welchen Wert diese haben) brachte das selbe Ergebnis.
    Bilder
    • bitbröselversion.jpg

      286,6 kB, 1.382×475, 56 mal angesehen
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „dive26“ ()

    Nächste Anfrage irritiert mich. Hast du daraus 2 Anfragen gemacht? Eine war gedacht. Also beide Arrays schreiben und dann eine Antwort auswerten. IGut ich weiß nicht wie die gegenstelle liest, evtl. ist das so besser. Der unterschied bei den beiden Anworten könnte die Request ID sein, falls du 2 Request gemacht hast. Du könntest mal mit id = 6 starten, wenn dann 6 und danach 7 drin ist, ist das die TransactionId.

    VB.NET-Quellcode

    1. Private Sub DoRequest()
    2. Dim frameStartUpload() As Byte = GetFrameStartUpload(&H44)
    3. Dim mbap() As Byte = GetMBAP(&H3, frameStartUpload.Length)
    4. Dim buffer() As Byte = ConcatBytes(mbap, frameStartUpload)
    5. 'buffer schreiben
    6. 'Antwort auswerten
    7. End Sub
    8. Private Function ConcatBytes(first() As Byte, second() As Byte) As Byte()
    9. Dim buffer() As Byte = New Byte(first.Length + second.Length - 1) {}
    10. System.Buffer.BlockCopy(first, 0, buffer, 0, first.Length)
    11. System.Buffer.BlockCopy(second, 0, buffer, first.Length, second.Length)
    12. Return buffer
    13. End Function
    @BitBrösel

    ich war zu voreilig und du zu schnell mit der Antwort.
    Vergiss meine erste Antwort. Ich habe diese überarbeitet.

    Ich habe nur new New Byte(6) {}

    VB.NET-Quellcode

    1. Private Function GetMBAP(unitId As Byte, dataLenght As Integer) As Byte()
    2. Static id As Integer = 0
    3. Dim mbap() As Byte = New Byte(6) {}
    4. mbap(0) = CByte(id \ 256)
    5. mbap(1) = CByte(id Mod 256)
    6. mbap(2) = 0
    7. mbap(3) = 0
    8. mbap(4) = CByte((dataLenght + 1) \ 256)
    9. mbap(5) = CByte((dataLenght + 1) Mod 256)
    10. mbap(6) = unitId
    11. id += 1
    12. Return mbap
    13. End Functionn


    durch New Byte(6 + dataLenght) {} ersetzt, da obiger Code keine Rückmeldung brachte.
    Die Datenlänge ist ja alles nachkommende.

    VB.NET-Quellcode

    1. Private Function GetMBAP(unitId As Byte, dataLenght As Integer) As Byte()
    2. Static id As Integer = 0
    3. Dim mbap() As Byte = New Byte(6 + dataLenght) {}
    4. mbap(0) = CByte(id \ 256)
    5. mbap(1) = CByte(id Mod 256)
    6. mbap(2) = 0
    7. mbap(3) = 0
    8. mbap(4) = CByte((dataLenght + 1) \ 256)
    9. mbap(5) = CByte((dataLenght + 1) Mod 256)
    10. mbap(6) = unitId
    11. id += 1
    12. Return mbap
    13. End Function
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „dive26“ ()

    Ah ja, da war ein Missverständnis, daher siehe meinen letzten Post. Gedacht war schreibe den mbap, nächste Zeile schreibe den frame, dann die Antwort lesen.

    Edit @dive26
    Weil wir im MBAP die Länge angeben, wird die Gegenseite versuchen so viele Bytes zu lesen, da du den frame nicht geschrieben hast, konnte auch nichts kommen. Kombiniere meine beiden Codes. Und probier es dann noch einmal.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „BitBrösel“ ()

    @BitBrösel

    Ah ja, da war ein Missverständnis, daher siehe meinen letzten Post. Gedacht war schreibe den mbap, nächste Zeile schreibe den frame, dann die Antwort lesen.

    Edit @dive26
    Weil wir im MBAP die Länge angeben, wird die Gegenseite versuchen so viele Bytes zu lesen, da du den frame nicht geschrieben hast, konnte auch nichts kommen. Kombiniere meine beiden Codes. Und probier es dann noch einmal.


    Ich steh irgendwie auf dem Schlauch und weis nicht was Du damit meinst. Was solle ich wann senden?

    Ich mache es gerade so:

    VB.NET-Quellcode

    1. Private Sub DoRequest()
    2. 'Dim CustomData() As Byte = {1, 2, 3, 4}
    3. 'Dim frameStartUpload() As Byte = GetFrameStartUpload(&H44, CustomData)
    4. Dim frameStartUpload() As Byte = GetFrameStartUpload(&H44) ' 41 05 01 44
    5. txtSendMsg.Text = Me.Display(frameStartUpload) 'Zeige zu sendende Bytes
    6. Dim mbap() As Byte = GetMBAP(&H3, frameStartUpload.Length) ' 00 00 00 00 00 05 03 00 00 00 00
    7. txtSendMsg1.Text = Me.Display(mbap) 'Zeige zu sendende Bytes
    8. ' Senden und empfangen
    9. Me.mSocket.Send(mbap, mbap.Length, SocketFlags.None)
    10. Thread.Sleep(100)
    11. Dim buffRecei As Byte() = New Byte(256) {}
    12. Dim ns1 As NetworkStream = New NetworkStream(Me.mSocket)
    13. If ns1.CanRead Then
    14. Dim rs As Integer = Me.mSocket.Receive(buffRecei, buffRecei.Length, SocketFlags.None)
    15. ' Ergebnis: 00 00 00 00 00 03 03 80 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    16. txtResult.Text = Me.Display(buffRecei) 'Zeige empfangene Bytes
    17. End If
    18. End Sub


    Nur ​Dim frameStartUpload() As Byte = GetFrameStartUpload(&H44) ' 41 05 01 44 alleine zu senden bringt keine Rückmeldung.
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at
    Noch kurz zu den Antworten, die bei deinem Versuch kamen, die gegenstelle hat dir das zurückgeschrieben was du geschrieben hast.
    00-00-00-00-00-05-03
    2 Bytes TranactionId
    2 Bytes Protokoll ID
    2 Bytes Datalenght
    1 Byte Device ID

    Den Frame hattest du ja nicht geschrieben

    Also wie ich sagte, entweder

    1->MBap schreiben
    2->Frame schreiben
    3->Antwort lesen

    oder

    1->Mbap und Frame verketten
    2->buffer schreiben
    3->Antowrt lesen

    mit folgenden Code sehen die Requests dann so aus, wie ich mir das vorstelle:

    Quellcode

    1. 00-00-00-00-00-05-03-41-05-01-44
    2. selber request mit id +1
    3. 00-01-00-00-00-05-03-41-05-01-44
    4. selber request wieder mit id +1
    5. 00-02-00-00-00-05-03-41-05-01-44


    VB.NET-Quellcode

    1. ​Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    2. DoRequest()
    3. 'DoRequest()
    4. 'DoRequest()
    5. End Sub
    6. Private Sub DoRequest()
    7. Dim frameStartUpload() As Byte = GetFrameStartUpload(&H44)
    8. Dim mbap() As Byte = GetMBAP(&H3, frameStartUpload.Length)
    9. Dim buffer() As Byte = ConcatBytes(mbap, frameStartUpload)
    10. For i As Integer = 0 To buffer.Length - 1
    11. Debug.Write(buffer(i).ToString("x2"))
    12. If i <> buffer.Length - 1 Then
    13. Debug.Write("-")
    14. End If
    15. Next
    16. Debug.WriteLine("")
    17. 'buffer schreiben
    18. 'Antwort auswerten
    19. End Sub
    20. Private Function ConcatBytes(first() As Byte, second() As Byte) As Byte()
    21. Dim buffer() As Byte = New Byte(first.Length + second.Length - 1) {}
    22. System.Buffer.BlockCopy(first, 0, buffer, 0, first.Length)
    23. System.Buffer.BlockCopy(second, 0, buffer, first.Length, second.Length)
    24. Return buffer
    25. End Function
    26. Private Function GetFrameStartUpload(fileType As Byte) As Byte()
    27. Dim functionsCode As Byte = &H41
    28. Dim subFunctionsCode As Byte = &H5
    29. Dim dataLenght As Byte = 1 ' 1+N, N = Customdata lenght, we dont send customdata
    30. Return New Byte(3) {functionsCode, subFunctionsCode, dataLenght, fileType}
    31. End Function
    32. Private Function GetFrameStartUpload(fileType As Byte, customData() As Byte) As Byte()
    33. Dim functionsCode As Byte = &H41
    34. Dim subFunctionsCode As Byte = &H5
    35. Dim dataLenght As Byte = CByte(1 + customData.Length) ' 1+N, N = Customdata lenght
    36. Dim frame() As Byte = New Byte(3 + customData.Length) {}
    37. frame(0) = functionsCode
    38. frame(1) = subFunctionsCode
    39. frame(2) = dataLenght
    40. frame(3) = fileType
    41. Array.Copy(customData, 0, frame, 4, customData.Length)
    42. Return frame
    43. End Function
    44. Private Function GetMBAP(unitId As Byte, dataLenght As Integer) As Byte()
    45. Static id As Integer = 0
    46. Dim mbap() As Byte = New Byte(6) {}
    47. mbap(0) = CByte(id \ 256)
    48. mbap(1) = CByte(id Mod 256)
    49. mbap(2) = 0
    50. mbap(3) = 0
    51. mbap(4) = CByte((dataLenght + 1) \ 256)
    52. mbap(5) = CByte((dataLenght + 1) Mod 256)
    53. mbap(6) = unitId
    54. id += 1
    55. Return mbap
    56. End Function
    @BitBrösel

    Danke für Deinen ergänzten Code.
    Auch hier ergibt sich das selbe Ergebnis (siehe Screenshot).


    In der Funktion GetMBAP habe ich Deinen Code rauskommentiert und den funktionierenden reingeschrieben.
    Mit Deiner Zeile gibt es keine Socket-Rückmeldung.

    VB.NET-Quellcode

    1. Private Function GetMBAP(unitId As Byte, dataLenght As Integer) As Byte()
    2. Static id As Integer = 0
    3. 'Dim mbap() As Byte = New Byte(6) {} 'hiermit gibt es keine Rückmeldung vom Socket
    4. Dim mbap() As Byte = New Byte(6 + dataLenght) {}
    5. mbap(0) = CByte(id \ 256)
    6. mbap(1) = CByte(id Mod 256)
    7. mbap(2) = 0
    8. mbap(3) = 0
    9. mbap(4) = CByte((dataLenght + 1) \ 256)
    10. mbap(5) = CByte((dataLenght + 1) Mod 256)
    11. mbap(6) = unitId
    12. id += 1
    13. Return mbap
    14. End Function



    Ich finde es super, dass Du so viel Energie in die Sache steckts. Aber ich möchte das auch nicht überstrapazieren.
    Ich würde mal sagen wir lassen ein paar Tage vergehen. Vielleicht bekomme ich inzwischen von Huawei einen Beispielcode.
    Falls sich da nichts ergibt, können wir hier ja immer noch try and error machen ;-).
    Bilder
    • immernochnichtanders.jpg

      356,48 kB, 1.696×528, 50 mal angesehen
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at
    @dive26

    Für heute habe ich aber noch was, weis nicht ob das jetzt Zufall ist. Ich sehe
    03 80
    Das ist eine Zahl die ich zuordnen kann. :D

    Du hast 34 Optimierer V101
    4 Bytes FileVersion
    8 Bytes Reserved
    N Bytes Data, 12 + NumberOfOptimizers * 26

    Rechnen wir mal...
    12 + 34 * 26 = 896

    896 sind in Hex-Darstellung
    0x380
    oder auch mit führender 0
    0x0380

    Möglicherweise fehlt dann noch der Request zum "Complete Upload Data", die Antwort darauf würde mich mal interessieren.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „BitBrösel“ ()