B4J Question byte in binary format to number conversion after reading on usb

mario53

Member
Licensed User
Longtime User
I have a tool that sends this:
Every second 12 bytes are transmitted in binary format (val.
0..255).
I can intercept the transmission but I can't transform the bytes into numbers (val. 0..255).
advice is welcome thanks
 

emexes

Expert
Licensed User
Maybe something like this:

B4X:
Sub AStreams_NewData (Buffer() As Byte)
    Log("Received " & Buffer.Length & " bytes")
    For I = 0 to Buffer.Length - 1
        Log(I & Tab & Bit.And(Buffer(I), 0xFF))    'convert signed bytes -128..127 to unsigned 0..255'
    Next
End Sub

or this:

B4X:
]Sub AStreams_NewData (Buffer() As Byte)
    Dim NumBytes As Int = Buffer.Length
    If NumBytes > 12 Then
        NumBytes = 12
    End If
 
    Dim N(NumBytes) As Int
    For I = 0 to NumBytes - 1
        N(I) = Bit.And(Buffer(I), 0xFF)    'convert signed bytes -128..127 to unsigned 0..255'
    Next
 
    Log(N.As(List))    'to display an Array, pretend it's a List
End Sub
 
Last edited:
Upvote 0

emexes

Expert
Licensed User
12 bytes are transmitted in binary format

What are the 12 bytes? ie what is the format of the packet being sent by the tool?

Actually, if you could post some sample packets eg a few Log output lines from:

B4X:
Sub AStreams_NewData (Buffer() As Byte)
    Log(Buffer.As(List))    'to display an Array, pretend it's a List
End Sub

that'd be great.
 
Upvote 0

emexes

Expert
Licensed User
Lol it's not display segment data from a multimeter, is it? That stuff is a PITA to decode. Straightforward, but tedious.
 
Upvote 0

mario53

Member
Licensed User
Longtime User
this is what the tool sends me:

1) START (start sequence) 250 (FA Hex) fixed code
2) Minutes 0-59
3) Seconds 0-59
4) Period 1-4
5) LOCAL Points 0-199
6) GUEST Points 0-199
7) Timeout 0-3
8) Timeout 0-3
9) N.1 0-9
10)N.2 0-9
11) Data integrity checksum (XOR) 0-255 (variable)
12) STOP (end sequence) 253 (FD Hex) fixed code

now I'll try what @Emicrania suggested
 
Upvote 0

emexes

Expert
Licensed User
Looks good.

The presence of START and STOP bytes suggests that it might have been through a serial-over-USB conversion at some point, and so it might not always arrive at your program in nice 12-byte clumps, one per event. Sometimes the process splits packets up so that half arrives in one event and then the remainder in the next event. But... cross that bridge when you get to it, might not even happen. If it does, the START and STOP bytes should catch it when it happens.

The checksum looks easy enough. Only question is whether it includes the START and/or STOP bytes. I've seen all combinations.

B4X:
Sub PacketOk(Buffer() As Byte) As Boolean
    If Buffer.Length <> 12 Then Return False    'or < 12 ?
    If Buffer(0) <> 0xFA Then Return False    'START byte    '
    If Buffer(11) <> 0xFD Then Return False    'STOP byte
 
    Dim CheckValue As Byte = 0
    For I = 1 to 10    'not including START and STOP bytes
        CheckValue = Bit.XOR(CheckValue, Buffer(I))
    Next
    If CheckValue <> 0 Then Return False
 
    Return True    'if gets to here, must be good
End Sub
 
Last edited:
Upvote 0

mario53

Member
Licensed User
Longtime User
before the last migraine tip i tried this.
the result in the attached file
how do i convert these bytes?

B4X:
Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private xui As XUI
    Private Button1 As B4XView
    
    Private sp As Serial
    Private astream As AsyncStreams
    Private SerialBuffer As String

    Dim timer1 As Timer
    Dim counter1 As Int = 0
    Dim bytesSec As Int = 0
    
    'Dim SerialBuffer As String ' replaced by B4XBytesBuilder
    
    Dim bBuilder As B4XBytesBuilder
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Layout1")
    MainForm.Show
    
    timer1.Initialize("timer1", 1000)
    timer1.Enabled = True
    SerialBuffer=""
    
    sp.Initialize("sp")
 
    Log(sp.ListPorts)
 
    'SerialBuffer = ""
    bBuilder.Initialize
    bBuilder.Clear
    'Dim searchFor() As Byte = Array As Byte(0xFA,0xFD)
    'Log("0" & searchFor(0))
    'Log("1" & searchFor(1))
    'Return
    If sp.ListPorts.Size > 0 Then
        sp.Open(sp.ListPorts.Get(0))
        sp.SetParams(9600, 8, 1, 0) ' baud: 9600, 115200, 500000
 
        astream.Initialize(sp.GetInputStream, sp.GetOutputStream, "astream")
    Else
        Log("No serial port found")
    End If
 
End Sub

Sub Button1_Click
    xui.MsgboxAsync("Hello World!", "B4X")
End Sub

Sub timer1_tick
    bytesSec = counter1
    counter1 = 0
    Log("bytes/Sec: " & bytesSec)
End Sub

Sub AStream_NewData (Buffer() As Byte)
    ' Old way to avoid breaking the message (replaced by B4XBytesBuilder):
    
    SerialBuffer =  SerialBuffer & BytesToString(Buffer, 0, Buffer.Length, "UTF8")
    Log("Lung.  Buffer: " & SerialBuffer.Length & CRLF)
    Log("Serial Buffer" & SerialBuffer)
    
    Return
    

End Sub
 

Attachments

  • Immagine.PNG
    Immagine.PNG
    14.7 KB · Views: 36
Upvote 0

emexes

Expert
Licensed User
I'm not home at moment but I'm pretty certain if I could read your post on a big screen I'd be like:

no, no, no, that's not going to work

Have you found that the bytes are coming in other than as 12-byte groups? Because if you don't need to work around that issue, then your task will be much easier and simpler.
 
Upvote 0

emexes

Expert
Licensed User
Righto, this will assemble incoming bytes into 12-byte packets that start with 0xFA and end with 0xFD, and sling them to HandlePacket()

B4X:
Sub Process_Globals
    Dim PacketSize As Int = 12
    Dim PacketBuffer As String
  
    Dim StartOfPacketByte As Int = 0xFA
    Dim EndOfPacketByte As Int = 0xFD
End Sub

Sub AStreams_NewData(Buffer() As Byte)
    '''Log("NewData" & TAB & DateTime.Now & TAB & B.As(List))
 
    For Each ChByte As Byte In Buffer    'ChByte is -128..127
        Dim ChInt As Int = Bit.And(ChByte, 0xFF)    'ChInt is 0..255

        PacketBuffer = PacketBuffer & Chr(ChInt)    'add next packet byte
        If PacketBuffer.Length > PacketSize Then    'limit to max packet size
            PacketBuffer = PacketBuffer.SubString(1)
        End If
      
        If ChInt = EndOfPacketByte Then    'if we are at end of packet (note: could be checksum byte)
            If PacketBuffer.Length = PacketSize Then    'and we plausibly have entire packet
                If PacketBuffer.StartsWith(Chr(StartOfPacketByte)) Then    'and the packet starts with correct byte
                    HandlePacket(PacketBuffer)
                    PacketBuffer = ""    'none of the packet just processed, will be used in any subsequent packets
                End If
            End If
        End If
    Next
End Sub

Sub HandlePacket(Packet as String)
    Dim sb As StringBuilder
    sb.Initialize
    For I = 0 To Packet.Length - 1
        If I <> 0 Then sb.Append(" ")
        sb.Append(Asc(Packet.CharAt(I)))
    Next
    Log("HandlePacket" & TAB & sb.ToString)
End Sub
 
Last edited:
Upvote 0

emexes

Expert
Licensed User
Is it finding packets?

I should have done it using BytesBuilder but I could see you'd already made a start using a String as a buffer, so I followed your lead.

Strings have a method .CharAt to extract a single character ("byte") that is simpler than using .SubString2

eg "Mario53".CharAt(3) will return "i" and Asc("Mario53".CharAt(3)) will return its ASCII ("byte") value 105
 
Upvote 0

mario53

Member
Licensed User
Longtime User
Hai scoperto che i byte arrivano in gruppi diversi da 12 byte? Perché se non hai bisogno di aggirare questo problema, il tuo compito sarà molto più facile e semplice.
esatto penso che mi adatterò a pacchetti diversi dal 12, è troppo complicato superare questo ostacolo, comunque grazie per le soluzioni proposte.
Avrei dovuto farlo usando BytesBuilder, ma ho visto che avevi già iniziato usando una String come buffer, quindi ho seguito il tuo esempio.

Le stringhe hanno un metodo .CharAt per estrarre un singolo carattere ("byte") che è più semplice rispetto all'utilizzo di .SubString2

ad esempio "Mario53".CharAt(3) restituirà "i" e Asc("Mario53".CharAt(3)) restituirà il suo valore ASCII ("byte") 105
molto interessante proverò a sostituire con il nuovo metodo ma so poco di BytesBuilder, studierò
Grazie per l'aiuto
 
Upvote 0

emexes

Expert
Licensed User
è troppo complicato superare questo ostacolo

I cannot tell if you are 1/ relishing the challenge, or 2/ giving up. 🙃

Don't give up. The end-of-packet STOP byte actually makes it relatively easy and efficient. You only need to check the buffer for a valid packet when (after) you receive a STOP byte. You don't need to check for a valid packet before you see the STOP byte, because we know there won't be one, because it will be incomplete, because the last byte (the STOP byte) hasn't been received yet.

Does the documentation for your USB tool list any other packet types, additional to the 12 byte packet that you are already reading?

Do they all use the same STOP byte value? (probably)

Do they all used the same START byte value? (probably not)
 
Last edited:
Upvote 0

mario53

Member
Licensed User
Longtime User
I cannot tell if you are 1/ relishing the challenge, or 2/ giving up. 🙃

maybe I'm giving up, because in the meantime I tried to create the exe with "Package Standalone" and it shows me the form and then exits, I tried to put a message at the beginning of the "AppStart" but it exits first.
what happens other programs are created.
thanks
 
Upvote 0

emexes

Expert
Licensed User
Does your program work from inside the B4J IDE?

But not when you package it up into a standalone Windows EXE?

That sounds like it should be a new question. 🍻
 
Upvote 0

mario53

Member
Licensed User
Longtime User
compilation does not give errors
I don't know what can happen in debugging it works
thanks for any help
 

Attachments

  • scoreBord.PNG
    scoreBord.PNG
    11.8 KB · Views: 21
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
Upvote 0
Top