Android Question Log line split problem

cpin

New Member
Hello everyone I'm new here, I have a school project to do with B4A and I have a problem with it. I hope I post this in the right place and I will try to explain as clearly as I can but it'll probably be long.
Basically, I have an arduino that simulates a bike moving, it's giving me a line every 5 seconds with the latitude and longitude of the bike :

1610121908051.png


So I made an application on my phone that reads the data and show them to the log :

1610122697560.png

As you can see, my problem is that sometimes the lines randomly split into 2 lines and I don't know why. In the picture, after the first line, 5 seconds later I get 2 lines but it's supposed to be just 1. The 5th line is split too but this time only with one character.

I considered that it was ok because I only need the numbers in the line so I did this code to get all 4 numbers :

Get the numbers:
Private Sub serial_DataAvailable (Buffer() As Byte)
    Dim data As String
    data = bc.StringFromBytes(Buffer,"ASCII")
    Dim coordonnees(4) As String
   
    Dim m As Matcher = Regex.Matcher("\d+", data)
    For i = 0 To 3
    If m.Find Then
        coordonnees(i) = m.Match
    End If
    Next

      Log(coordonnees(0) & " " & coordonnees(1) & " " & coordonnees(2) & " " & coordonnees(3))
   
End Sub

It gives me this :

1610126119200.png

My latitude is lati = coordonnes(0) & " " & coordonnes(1) and my longitude is longi = coordonnes(2) & " " & coordonnes(3) .
So as you can see it works but on the 3rd line of log (so 2nd transmission of arduino), "4338 20628" are coordonnes(0) and coordonnes(1) but on the next line "00509 17113" are coordonnes(0) and coordonnes(1) as well because it's another line from the log as I showed before so Lati get erased by Longi in a way. How can I conter this problem ? I would like to have "4338 20628 00509 17113" on only 1 line of the log. I tried multiple things and none of them were concluant. I hope someone can help me and I will explain differently if you did'nt understand !
 

Attachments

  • 1610126462730.png
    1610126462730.png
    11.7 KB · Views: 114
Last edited:

emexes

Expert
Licensed User
It is probably because the data is arriving byte-by-byte rather than in all-at-once blocks or lines, and sometimes you (or the library you're using to get the serial data) read it when only half of a line has arrived, and the remainder of the line is picked up by the next read.

A solution is to add each read to a buffer, and then get the lines by searching for the end-of-line, eg something like:

B4X:
Buffer$ = Buffer$ & IncomingData$

Do    'in a loop in case Buffer$ contains more than one line
    P = Instr(Buffer$, Chr$(13))    'look for end-of-line character in buffer
    If P = 0 Then
        Exit Do    'exit loop if doesn't contain whole line
    End If

    WholeLine$ = Left$(Buffer$, P - 1)    'get line (without end-of-line character)
    Buffer$ = Mid$(Buffer$, P + 1)    'remove line from buffer (or more accurately: keep the rest of the buffer :-)

    HandleLogLine(WholeLine$)
Loop
 
Last edited:
Upvote 0

cpin

New Member
It is probably because the data is arriving byte-by-byte rather than in all-at-once blocks or lines, and sometimes you (or the library you're using to get the serial data) read it when only half of a line has arrived, and the remainder of the line is picked up by the next read.

A solution is to add each read to a buffer, and then get the lines by searching for the end-of-line, eg something like:

B4X:
Buffer$ = Buffer$ & IncomingData$

Do    'in a loop in case Buffer$ contains more than one line
    P = Instr(Buffer$, Chr$(13))    'look for end-of-line character in buffer
    If P = 0 Then
        Exit Do    'exit loop if doesn't contain whole line
    End If

    WholeLine$ = Left$(Buffer$, P - 1)    'get line (without end-of-line character)
    Buffer$ = Mid$(Buffer$, P + 1)    'remove line from buffer

    HandleLogLine(WholeLine$)
Loop
Thanks for the reply, I understand what you mean, I'm indeed reading the data byte by byte, here's the full code if you want to see it :

Read data:
#Region  Project Attributes
    #ApplicationLabel: B4A Example
    #VersionCode: 1
    #VersionName:
    'SupportedOrientations possible values: unspecified, landscape or portrait.
    #SupportedOrientations: unspecified
    #CanInstallToExternalStorage: False
    #BridgeLogger: True
#End Region

#Region  Activity Attributes
    #FullScreen: False
    #IncludeTitle: True
#End Region


Sub Process_Globals
    Private usbserial As felUsbSerial
    Private manager As UsbManager
    Private bc As ByteConverter
End Sub

Sub Globals
    
End Sub

Sub Activity_Create(FirstTime As Boolean)
    If FirstTime Then
        manager.Initialize
    End If
    Activity.LoadLayout("Layout2")
End Sub



Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

Sub Bouton_Click
    If manager.GetDevices.Length = 0 Then
        Log("Veuillez connecter un appareil via le cable USB")
    Else
        Dim device As UsbDevice = manager.GetDevices(0)
        
        If manager.HasPermission(device) = False Then
            Log("Veuillez autoriser la connection et réessayer")
            manager.RequestPermission(device)
        Else
            usbserial.Initialize("serial", device, -1)
            usbserial.BaudRate = 250000
            usbserial.DataBits = usbserial.DATA_BITS_8
            usbserial.StartReading
        End If
    End If
End Sub

Private Sub serial_DataAvailable (Buffer() As Byte)
    Dim data As String
    data = bc.StringFromBytes(Buffer,"ASCII")
    Log(data)
End Sub

However what I don't understand is the "P=0" , I understand what you want me to do but the last character of my line is always a "," so why 0 ?
 
Upvote 0

cpin

New Member
I finally solved my problem, I understood your code and I did something similar with the length of the buffer which is supposed to be 42. The variable Ligne is defined as global :

B4X:
Private Sub serial_DataAvailable (Buffer() As Byte)
    Dim data As String
    data = bc.StringFromBytes(Buffer,"ASCII")
    Log("data = " & data)

    If Buffer.Length < 42 Then
        Ligne = Ligne & data
    Else
        Ligne = data
    End If
    
    If Ligne.Length >= 42 Then
        Log("Ligne = " & Ligne)
        Ligne = ""
    End If
End Sub

Thanks a lot for your help.
 
Upvote 0

emexes

Expert
Licensed User
the length of the buffer which is supposed to be 42
ditto Life, The Universe, and Everything so we must be on the right track here 🍻

But if you have time, you'd be better checking for the presence of the line terminator rather than relying on the line length not changing. Because, in the real world, it will.

Erel's suggestion of using AsyncStreamsText is good too, now that you've experience what's happening under the hood by rolling your own code to handle it.
Thanks a lot for your help.
No worries. Everybody who's ever received data serially has been down this path at least once.
 
Upvote 0

TPK01

New Member
Hello, I have the same problem of cpin, and I try what you said, but it doesn't work, please can you help me I don't understand why it doesn't work.

PS : Ligne is a global variable

B4X:
Private Sub serial_DataAvailable (Buffer() As Byte)
    
    
    Dim data As String
    
    data = bc.StringFromBytes(Buffer,"ASCII")
    
    
    If Buffer.Length < 28 Then
        
        Ligne = Ligne & data
        
    Else
        
        Ligne = data
        
    End If
    
    If data = "" Then
    
    Else
        Label1.Text = Ligne
    
    End If
        
    Ligne = ""   
    
    Log(Ligne)
    
    
    
    
    End Sub


I receive that :

View attachment 107385
 
Upvote 0

TPK01

New Member
But if you have time, you'd be better checking for the presence of the line terminator rather than relying on the line length not changing. Because, in the real world, it will.

Can you give me an example for that, because I'm trying to do this unsuccessfully please.

Thanks
 
Upvote 0
Top