Bytearray(40) + Bytearray(41) in eine vorzeichenbehaftete Interger verwandeln

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

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

    Bytearray(40) + Bytearray(41) in eine vorzeichenbehaftete Interger verwandeln

    Hallo Leute,

    irgendwie bin ich Gedankentechnisch in einer Sackgasse. Sollte es können, aber es klappt nicht.

    Ich habe ein Datenarray von 68 Bytes.
    Byte 40 und Byte 41 sind der gesuchte Wert, der ein vorzeichenbehaftetes Integer enthalten sollte.

    Beispiel:

    Data(40).ToString ergibt "233" oder Data(40).ToString("X2") Hex "E9"
    Data(41).ToString ergibt "238" oder Data(41).ToString("X2") Hex "EE"

    EE E9 = -4375

    Der gesuchte Wert ist -4375.

    Wie komme ich mit VB.Net von den beiden Bytes zu dieser zahl "-4375"?
    Bilder
    • 15082024174713.jpg

      57,91 kB, 453×227, 15 mal angesehen
    • 15082024184309.jpg

      34,88 kB, 416×216, 14 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 1 mal editiert, zuletzt von „dive26“ ()

    233 or 238 << 8 = 61161 = -4375

    VB.NET-Quellcode

    1. Public Sub Test_dive26()
    2. Dim s1 As UShort = 233
    3. Dim s2 As UShort = 238
    4. Dim r = Convert.ToUInt16(233 Or 238 << 8)
    5. Dim result1 = -Convert.ToInt32(Not r) - 1
    6. Dim result2 = Convert.ToUInt32(r) - 2 ^ 16
    7. End Sub


    Freundliche Grüsse

    exc-jdbi

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „exc-jdbi“ ()

    @exc-jdbi

    Vielen Dank.
    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“ ()

    Hi
    Hmm, ich mag diese Bitschubserei mit L/RShift, wenn es nicht unbedingt erforderlich ist, nicht besonders und 2 Bytes müssten doch ein Short ergeben oder? Von daher wäre meine Idee:

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    3. Dim Data As Byte() = New Byte() {0, 0, 0, 233, 238}
    4. Debug.Print(BitConverter.ToInt16(Data, 3).ToString)
    5. End Sub
    6. End Class
    Mfg -Franky-
    Kann man sicher machen.

    Ich nutze auch immer die Werkzeuge von .Net. Aber um es überhaupt einmal zu verstehen (schliesslich sind wir hier in einem Technischen Forum), ist der Weg über das 2-Komplementär noch ziemlich sinnvoll. Nachher kann man es ja machen wie man es will.

    Der BitConverter macht das ja auch nicht anders, oder zumindest ähnlich.

    Freundliche Grüsse

    exc-jdbi

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „exc-jdbi“ ()

    Haudruferzappeltnoch schrieb:

    Bitschubsen wird aber ja wohl auch das Effizienteste sein.
    Das stimmt.
    Wenn es auf Effizienz ankommt, sollten wir aber nicht in VB.Net programmieren, sondern in Assembler. ;)

    Bitschubsen ist tatsächlich das, was letztendlich auf Maschinensprache abläuft.
    Aber dafür haben wir ja effiziente Compiler.

    Um die Theorie zu verstehen sind solche Übungen sicher hilfreich.
    Aber in den Context eines .Net-Programms passt ein BitConverter-Aufruf sicher besser als ein BitShift.
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --

    exc-jdbi schrieb:

    Der BitConverter macht das ja auch nicht anders, oder zumindest ähnlich.

    Dazu müsste man in das Framework schauen was da im BitConverter genau gemacht wird um ein Vergleich zum Bitschubsen zu haben. Schätze aber das da auch nur von Pointer zu Pointer kopiert wird. Wahrscheinlich so, wie ich das in VB6 auch machen würde (auf die schnelle ohne Prüfung ob das Array dimensioniert/initialisiert und ob der startIndex gültig ist).
    Spoiler anzeigen

    Visual Basic-Quellcode

    1. Option Explicit
    2. Private Declare Sub CopyMemory Lib "Kernel32.dll" _
    3. Alias "RtlMoveMemory" ( _
    4. ByRef pTo As Any, _
    5. ByRef uFrom As Any, _
    6. ByVal lSize As Long)
    7. Private Sub Form_Load()
    8. Dim Data(4) As Byte
    9. Data(0) = 0
    10. Data(1) = 0
    11. Data(2) = 0
    12. Data(3) = 233
    13. Data(4) = 238
    14. Debug.Print BitConverter_ToInt16(Data, 3)
    15. End Sub
    16. Private Function BitConverter_ToInt16(ByRef value() As Byte, _
    17. ByVal startIndex As Long) As Integer
    18. Call CopyMemory(BitConverter_ToInt16, value(startIndex), 2)
    19. End Function

    Mfg -Franky-
    Was du noch machen könntest, ist du könntest dir ein Schnipsel aus dem Array ziehen:

    C#-Quellcode

    1. var data = new byte[63];
    2. // fill data
    3. var myBytes = data[40..41];
    4. short myShortBE = BinaryPrimitives.ReadInt16BigEndian(myBytes);
    5. short myShortLE = BinaryPrimitives.ReadInt16LittleEndian(myBytes);


    Hier noch ein Schnipsel aus echtem Code:

    C#-Quellcode

    1. using var authFile = File.Open(file, FileMode.Open, FileAccess.Read);
    2. // ...
    3. authFile.ReadExactly(remainingData, 0, (int)authFile.Length - nextOffset);
    4. var remainingData = new byte[(int)authFile.Length - nextOffset];
    5. // ...
    6. authData.magicNumber = BinaryPrimitives.ReadInt64BigEndian(remainingData[nextOffset..(nextOffset += sizeof(Int64))]);
    7. // ...
    8. authData.privKey = remainingData[(nextOffset)..(nextOffset += authData.keyLength)]; // dynamische Datenlänge wird vorher ausgelesen


    Am Ende des Tages bekommst du so auch genau das, was du brauchst. Roh-Daten vom Netzwerk sind z.B. immer BigEndian und müssen (je nach Plattform) zu LE umgewandelt werden (sprich einmal die Byte-Reihenfolge muss durchgetauscht werden. 0<->4 1<->3).
    Quellcode lizensiert unter CC by SA 2.0 (Creative Commons Share-Alike)

    Meine Firma: Procyon Systems

    Selbstständiger Softwareentwickler & IT-Techniker.

    -Franky- schrieb:

    man in das Framework


    Wenn ich die Doks das jetzt richtig interpretiert habe, gibt es in DotNet Core nun die generische Unsafe- und MemoryMarshal Runtime-Klasse. Die Methode ReadUnaligned macht hierbei genau das, was es machen muss, mit den Bytes.

    learn.microsoft.com/en-us/dotn…eadunaligned?view=net-8.0

    Freundliche Grüsse

    exc-jdbi
    Vielen Dank. Ich hatte das Thema schon mal vor einigen Jahren hier. Aber wenn man es braucht, dann erinnert man sich nicht mehr daran.

    Habe jetzt mein Datagramm komplett durch und finde nach den OBIS-Kennzahlen nun auch meine Daten und kann diese mit Bitconverter (32 Bit) zusammensetzen. Hier der erste Code, der garantiert noch viele Verbesserungsmöglichkeiten bietet ;)

    VB.NET-Quellcode

    1. Public Sub BGW_SMAMulticast_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BGW_SMAMulticast.DoWork
    2. If My.Settings.Datenquelle <> 5 Then Exit Sub
    3. Dim SMA_client As New UdpClient With {
    4. .ExclusiveAddressUse = False
    5. }
    6. SMA_client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, True)
    7. Dim localEp As New IPEndPoint(IPAddress.Parse("0.0.0.0"), 9522)
    8. SMA_client.Client.Bind(localEp)
    9. Dim by(4) As Byte
    10. Dim SMA_Bezug As Double
    11. Dim SMA_Einspeisung As Double
    12. While StopModbus = False
    13. Dim Data() As Byte = SMA_client.Receive(Nothing)
    14. If Data.Count > 599 Then 'Normal 608 bytes lang, gibt aber noch ältere Smartmeter die nur 600 bytes senden
    15. For i As Integer = 0 To Data.Count - 8
    16. If Data(i) = 1 And Data(i + 1) = 4 And Data(i + 2) = 0 Then 'Suche nach 1.4.0
    17. by(0) = Data(i + 6)
    18. by(1) = Data(i + 5)
    19. by(2) = Data(i + 4)
    20. by(3) = Data(i + 3)
    21. SMA_Bezug = BitConverter.ToInt32(by, 0)
    22. If IstNaN(SMA_Bezug) Then SMA_Bezug = 0 Else SMA_Bezug /= 10 'Ergebnis in Watt
    23. End If
    24. If Data(i) = 2 And Data(i + 1) = 4 And Data(i + 2) = 0 Then 'Suche nach 2.4.0
    25. by(0) = Data(i + 6)
    26. by(1) = Data(i + 5)
    27. by(2) = Data(i + 4)
    28. by(3) = Data(i + 3)
    29. SMA_Einspeisung = BitConverter.ToInt32(by, 0)
    30. If IstNaN(SMA_Einspeisung) Then SMA_Einspeisung = 0 Else SMA_Einspeisung /= 10 'Ergebnis in Watt
    31. End If
    32. 'Hier die Werte in die Gridvariablen schreiben
    33. If SMA_Einspeisung > 0 Then
    34. Inverter1_Grid = SMA_Einspeisung / 1000 'Ergebnis in Kilowatt
    35. ElseIf SMA_Bezug > 0 Then
    36. Inverter1_Grid = SMA_Bezug / 1000 * -1 'Ergebnis in Kilowatt
    37. Else
    38. Inverter1_Grid = 0
    39. End If
    40. Inverter_Grid = Inverter1_Grid
    41. 'Hauptform.Label_HexDebug.Visible = True
    42. 'Hauptform.Label_HexDebug.Text = "Bezug: " + SMA_Bezug.ToString + " Einspeisung: " + SMA_Einspeisung.ToString
    43. Next i
    44. End If
    45. SMA_MultiCast_Counter += 1
    46. If SMA_MultiCast_Counter > 20000 Then SMA_MultiCast_Counter = 1
    47. Thread.Sleep(50) 'nicht länger, da sich sonst die Multicast-Antworten "aufstauen", falls 1000ms, 500ms oder 200ms Cast-Intervall eingestellt sind.
    48. End While
    49. SMA_client.Close()
    50. SMA_client.Dispose()
    51. End Sub


    Vielleich ein paar Hintergrundinfos:
    Der SMA Smart Meter (Home Manager 2.0) sendet in Sekundenabständen Multicast-Messages mit seinen Daten ins Netzwerk. Diese fange ich ab und lese dann den Bezugs- und Einspeisewert aus.
    Die Datensatzbeschreibung besagt, dass die 4-Byte Werte (Indian) nach den OBIS-Werten kommt. Also beispielsweise suche ich den Wert 1.4.0 in den byte-Daten und danach befinden sich dann die 4 Bits mit dem entsprechenden Wert. Da das Datagramm jederzeit von SMA geändert werden könnte, kann man nicht zwingend direkt den Index anspringen, da sich dieser verändern kann, wenn andere Werte darüber eingefügt werden (war schon mal 2021 der Fall).



    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“ ()