B4J Question UDP reply to client

Declan

Well-Known Member
Licensed User
Longtime User
I have a broker written in B4j that receives data packets from a remote Arduino device.
Once the data packet is received, I then query a MySQL database table for device configuration settings and create a String to Tx.
I must now send this String to the Arduino.
How do I reply to the remote Arduino device?

On receipt of the UDP packet, I receive the following logs:
B4X:
ListenForClients started...
Server Initialized: 10.0.17.2-5000
Server Listening for connections...
Data Received...
Server Listening for connections...
Got: CONFIGIS002
Len Received: 11
Got Config
Config ID: IS002
Got This: CONFIGIS002
Config TX: 00,176,25,20000,30,24

RDC:
B4X:
Sub getConfig(myDeviceID As String)
    'sql.get_configs=SELECT tracking, wakecount, maxvibs, vibinterval, trackcount, checkvib FROM devices WHERE deviceid=?
    Dim myTracking As String
    Dim myWakeCount As String
    Dim myMaxVibs As String
    Dim myVibInterval As String
    Dim myTrackCount As String
    Dim myCheckVib As String
    Dim myConfigTX As String

    Dim req As DBRequestManager = CreateRequest
    Dim cmd As DBCommand = CreateCommand("get_configs", Array(myDeviceID))
    Wait For (req.ExecuteQuery(cmd, 0, Null)) JobDone(j As HttpJob)
    If j.Success Then
        req.HandleJobAsync(j, "req")
        Wait For (req) req_Result(res As DBResult)
        For Each row() As Object In res.Rows
            myTracking = row(res.Columns.Get("tracking"))
            myWakeCount = row(res.Columns.Get("wakecount"))
            myMaxVibs = row(res.Columns.Get("maxvibs"))
            myVibInterval = row(res.Columns.Get("vibinterval"))
            myTrackCount = row(res.Columns.Get("trackcount"))
            myCheckVib = row(res.Columns.Get("checkvib"))
           
            myConfigTX = myTracking & "," & myWakeCount &"," & myMaxVibs & "," & myVibInterval & "," & myTrackCount & "," & myCheckVib
           
            Log("Config TX: " & myConfigTX)
        Next
    Else
        Log("ERROR: " & j.ErrorMessage)
    End If
    j.Release
End Sub

I must send the string "myConfigTX" to the remote Arduino device
 

teddybear

Well-Known Member
Licensed User
1. Package the string you want to send back into UDPPacket, it includes data, Arduino ip, Arduino udp port.
2. The server udp sends the UDPPcket like you do in Arduino such as udp.send(yourpacket).
 
Upvote 0

Declan

Well-Known Member
Licensed User
Longtime User
I have the following code on the server to receive UDP data from Arduino on Port 5100.
However, it fails to establish a connection:
B4X:
#Region Project Attributes
    #MainFormWidth: 600
    #MainFormHeight: 200
#End Region

Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private xui As XUI
   
    Dim UDPSocket1 As UDPSocket
    Private txtLogs As B4XView
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Layout1")
    MainForm.Show
   

    UDPSocket1.Initialize("UDP", 5100, 8000)

'    Dim Packet As UDPPacket
'    Dim data() As Byte
'    data = "Hello from Android".GetBytes("UTF8")
'    Packet.Initialize(data, "197.234.129.17", 5100)
'    UDPSocket1.Send(Packet)
   
End Sub

Sub UDP_PacketArrived (Packet As UDPPacket)
    Dim msg As String
    msg = BytesToString(Packet.Data, Packet.Offset, Packet.Length, "UTF8")
    Log("Message received: " & msg )
    UpdateLogs(msg)
End Sub

Sub UpdateLogs(strLog As String)
    DateTime.DateFormat = "yyyy-MM-dd HH:mm:ss"
    txtLogs.Text =  DateTime.Date(DateTime.now) & ": " & strLog & CRLF & txtLogs.Text
End Sub
 
Upvote 0

teddybear

Well-Known Member
Licensed User
Try this code, see ipaddress
B4X:
Sub UDP_PacketArrived (Packet As UDPPacket)
    
    Dim msg As String
    msg = BytesToString(Packet.Data, Packet.Offset, Packet.Length, "UTF8")
    Log("Message received: " & msg )
    UpdateLogs(msg)

    Dim Packet As UDPPacket
    Dim data() As Byte
    data = "Hello from Android".GetBytes("UTF8")
    Log(Packet.HostAddress) 'See what ipaddress is?
    Packet.Initialize(data, Packet.HostAddress , 5100)
    UDPSocket1.Send(Packet)
End Sub
 
Upvote 0

Declan

Well-Known Member
Licensed User
Longtime User
Try this code, see ipaddress
B4X:
Sub UDP_PacketArrived (Packet As UDPPacket)
   
    Dim msg As String
    msg = BytesToString(Packet.Data, Packet.Offset, Packet.Length, "UTF8")
    Log("Message received: " & msg )
    UpdateLogs(msg)

    Dim Packet As UDPPacket
    Dim data() As Byte
    data = "Hello from Android".GetBytes("UTF8")
    Log(Packet.HostAddress) 'See what ipaddress is?
    Packet.Initialize(data, Packet.HostAddress , 5100)
    UDPSocket1.Send(Packet)
End Sub
I am failing to establish a connection from my Android device on port 5100 of the server.
I don't know is the following code is correct in AppStart:
B4X:
UDPSocket1.Initialize("UDP", 5100, 8000)
 
Upvote 0

teddybear

Well-Known Member
Licensed User
I am failing to establish a connection from my Android device on port 5100 of the server.
I don't know is the following code is correct in AppStart:
B4X:
UDPSocket1.Initialize("UDP", 5100, 8000)
You should use a different port with b4j in Arduino device. Why is server port 5000 in b4j log, but UDPSocket1.Initialize("UDP", 5100, 8000) in AppStart ?
B4j port is 5000?
Arduino is 5100?
if yes you shuold UDPSocket1.Initialize("UDP", 5000, 8000) in AppStart.
 
Last edited:
Upvote 0

teddybear

Well-Known Member
Licensed User
Arduino has no ports, it uses Serial1 Hardware Serial.
So you should use serial port to send the string back instead of udp
I wonder how you do Initialize udp and why you don't use udp to receive data in Arduino ? but you want to reply to client using udp.
 
Last edited:
Upvote 0

Declan

Well-Known Member
Licensed User
Longtime User
So you should use serial port to send the string back instead of udp
No,
From the Arduino I establish a UDP connection to the server.
Once connected, I then send the data from the Arduino to the server.
On the Arduino end, I keep the connection alive and wait for the reply from the server.
Once reply has been received by the Arduino, I close the connection.
 
Upvote 0

teddybear

Well-Known Member
Licensed User
No,
From the Arduino I establish a UDP connection to the server.
Once connected, I then send the data from the Arduino to the server.
On the Arduino end, I keep the connection alive and wait for the reply from the server.
Once reply has been received by the Arduino, I close the connection.
It is incorrect to use UDP,
UDP protocol is connectionless communication . it has no handshaking dialogues.
 
Last edited:
Upvote 0

Declan

Well-Known Member
Licensed User
Longtime User
It is incorrect to use UDP,
UDP protocol is connectionless communication .
The only reason I am using UDP is the HTTP proved to be very unreliable.
Testing HTTP I had a failure rate of over 80%
Testing UDP I had a 0% failure rate
This all has something to do with the GSM networks and I must work around that
 
Upvote 0

teddybear

Well-Known Member
Licensed User
The only reason I am using UDP is the HTTP proved to be very unreliable.
Testing HTTP I had a failure rate of over 80%
Testing UDP I had a 0% failure rate
This all has something to do with the GSM networks and I must work around that
2 options:
1. Initialize a port for receiving udp data in Arduino
2.Using Mqtt for data exchange between Arduino and B4J
 
Upvote 0

teddybear

Well-Known Member
Licensed User
I am curious that you have already used udp to receive data in b4j, why not use udp to receive data from b4j in Arduino?
 
Last edited:
Upvote 0

Declan

Well-Known Member
Licensed User
Longtime User
why not use udp to receive data from b4j in Arduino
That is exactly what I am trying to achieve.
I have two ports open on my server:
Port 5000 is a Broker that receives a string from Arduino containing GPS and other data.
This Broker uses Sockets.
I can also send the UDP string "CONFIGIS002" to this port 5000 and the log is as follows:
Log:
B4X:
ListenForClients started...
Server Initialized: 10.0.17.2-5000
Server Listening for connections...
Data Received...
Server Listening for connections...
Got: CONFIGIS002
Len Received: 11
Got Config
Config ID: IS002
Got This: CONFIGIS002
Config TX: 00,176,25,20000,30,24
Code:
B4X:
#Region Project Attributes
    #MainFormWidth: 600
    #MainFormHeight: 200
#End Region

Sub Process_Globals
    'port of the broker
    Private PORT As Int = 5000
    'port for rdc
    Private RDC_PORT As Int = 4001
    'server IP addres
    Private SERVER_IP As String = "localhost"
   
    Type DBResult (Tag As Object, Columns As Map, Rows As List)
    Type DBCommand (Name As String, Parameters() As Object)
    Private const rdcLink As String = $"http://${SERVER_IP}:${RDC_PORT}/rdc"$
       
    Private fx As JFX
    Private MainForm As Form
    Private client As Socket
    Private SERVER As ServerSocket
    Private astream As AsyncStreams
    Private txtLogs As TextArea
   
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("1") 'Load the layout file.
    MainForm.Show
    Form1.Title = $"Invictus - Africa Broker - ${PORT}/${RDC_PORT}"$
    txtLogs.Text = ""
    ListenForClients
End Sub


Sub UpdateLogs(strLog As String)
    DateTime.DateFormat = "yyyy-MM-dd HH:mm:ss"
    txtLogs.Text =  DateTime.Date(DateTime.now) & ": " & strLog & CRLF & txtLogs.Text
End Sub

Sub ListenForClients
    Log("ListenForClients started...")
    SERVER.Initialize(PORT, "server")
    Log("Server Initialized: " & SERVER.GetMyIP & "-" & PORT)
    Do While True
        SERVER.Listen
        Log("Server Listening for connections...")
        Wait For Server_NewConnection (Successful As Boolean, NewSocket As Socket)
        If Successful Then
            NewConnection(NewSocket)
        End If
        Sleep(1000) 'prevent a busy loop if there is an error
    Loop
End Sub

Sub NewConnection (NewSocket As Socket)
    CloseExistingConnection
    client = NewSocket
    astream.Initialize(client.InputStream, client.OutputStream, "astream")
    Log("Data Received...")
End Sub

Sub CloseExistingConnection
    If astream.IsInitialized Then
        astream.Close
    End If
    If client.IsInitialized And client.Connected Then
        client.Close
    End If
End Sub


Sub astream_Terminated
    'Log($"IAQ Broker Terminated: ${LastException.Message}"$)
    astream_Error
End Sub

Sub astream_Error
    'Log($"IAQ Broker Error: ${LastException.Message}"$)
End Sub

Sub AStream_NewData (Buffer() As Byte)
    Try
        Dim lat As String
        Dim ns As String
        Dim lon As String
        Dim ew As String
        Dim myVolts As String
       
        Dim myPercent As String
       
        Dim msgID As String
        Dim myDeviceID As String
        Dim mySignal As String
        Dim mySpeed As String
       
        Dim MyStr As String
        Dim OAOD As String = Chr(13) & Chr(10)
        Dim resp As String = "HTTP/1.1 200 OK" & OAOD  & "Content-Length: 0" & OAOD & OAOD
        '
        MyStr = BytesToString(Buffer,0,Buffer.Length,"UTF-8")
        MyStr = MyStr.trim

        astream.Write(resp.GetBytes("UTF8"))
        astream.SendAllAndClose
       
        Log("Got: " & MyStr)
        Log("Len Received: " & MyStr.Length)
       
        If MyStr.IndexOf("CONFIG") > -1 Then
            Log("Got Config")
            myDeviceID = MyStr.SubString(MyStr.Length - 5)
            Log ("Config ID: " & myDeviceID)
            getConfig(myDeviceID)
           
        End If

        If MyStr.Length > 100 Then
            MyStr = MyStr.SubString(MyStr.Length - 43)
        End If
       
        Log("Got This: " & MyStr)
        If (MyStr.Length = 43) Then 'Or (MyStr.Length = 39) Then
           
            Dim strVersion() As String

            strVersion = Regex.Split("#",MyStr)
            Log("Split version: " & MyStr)
       
            lat = strVersion(0)
            ns = strVersion(1)
            lon = strVersion(2)
            ew = strVersion(3)
            myVolts = strVersion(4)
            myPercent = strVersion(5)
            msgID = strVersion(6)
            myDeviceID = strVersion(7)
            mySignal = strVersion(8)
            mySpeed = strVersion(9)
           
            If mySpeed.Length() = 2 Then
                mySpeed = "0" & mySpeed
            End If
       
            Log("Lat: " & lat)
            Log("NS: " & ns)
            Log("Lon: " & lon)
            Log("EW: " & ew)
            Log("Volts: " & myVolts)
            Log("Percent: " & myPercent)
            Log("msgID: " & msgID)
            Log("myDeviceID: " & myDeviceID)
            Log("mySignal: " & mySignal)
            Log("mySpeed: " & mySpeed)
       
            Dim latDec As String
            latDec = Bit.ParseInt(lat, 16)
            Dim lonDec As String
            lonDec = Bit.ParseInt(lon, 16)
       
            Log("Lat Dec: " & latDec)
            Log("Lon Dec: " & lonDec)
       
            Dim LatFull As String
            Dim LatSub As String
            LatFull = latDec.SubString2(0,2)
            Log("Lat Full: " & LatFull)
            LatSub = latDec.SubString2(2,8)
            Log("Lat Sub: " & LatSub)
            LatSub = (LatSub / 60)
            Log("Lat Sub / 60: " & LatSub)
            LatSub = (LatSub / 10000)
            Log("Lat Sub / 10,000: " & LatSub)
           
            Dim posDecimalLat As Int
            posDecimalLat = LatSub.IndexOf(".")
            Log("posDecimalLat: " & posDecimalLat)
            LatSub = LatSub.SubString(posDecimalLat)
            Log("Final LatSub: " & LatSub)
               
            lat = LatFull & LatSub
               
            If(ns = "S") Then
                lat = (0 - lat)
                lat = NumberFormat(lat,0,6)
                Log("Lat Final: " & lat)
            End If
            If(ns = "N") Then
                lat = NumberFormat(lat,0,6)
                Log("Lat Final: " & lat)
            End If

            Dim LonFull As String
            Dim LonSub As String
            LonFull = lonDec.SubString2(0,2)
            Log("Lon Full: " & LonFull)
            LonSub = lonDec.SubString2(2,8)
            Log("Lon Sub: " & LonSub)
            LonSub = (LonSub / 60)
            Log("Lon Sub / 60: " & LonSub)
           
            LonSub = (LonSub / 10000)
            Log("Lon Sub / 10,000: " & LonSub)
            Dim posDecimalLon As Int
            posDecimalLon = LonSub.IndexOf(".")
            Log("posDecimalLon: " & posDecimalLon)
            LonSub = LonSub.SubString(posDecimalLon)
            Log("Final LonSub: " & LonSub)
           
            lon = LonFull & LonSub
       
            If(ew = "W") Then
                lon = (0 - lon)
                lon = NumberFormat(lon,0,6)
                Log("Lon Final: " & lon)
            End If
            If(ew = "E") Then
                lon = NumberFormat(lon,0,6)
                Log("Lon Final: " & lon)
            End If

'    'write the record to the db
            Wait For (writeTrans(myDeviceID, lat, lon, myVolts, myPercent, msgID, mySignal, mySpeed, MyStr)) Complete (Done As Boolean)
'    'show logs after write to database
            UpdateLogs($"Trans write: ${Done}: ${myDeviceID} - ${msgID} - ${MyStr}"$)
        End If
    Catch
        Log("New Data Received: " & LastException)
    End Try
End Sub

Sub getConfig(myDeviceID As String)
    Dim myTracking As String
    Dim myWakeCount As String
    Dim myMaxVibs As String
    Dim myVibInterval As String
    Dim myTrackCount As String
    Dim myCheckVib As String
    Dim myConfigTX As String

    Dim req As DBRequestManager = CreateRequest
    Dim cmd As DBCommand = CreateCommand("get_configs", Array(myDeviceID))
    Wait For (req.ExecuteQuery(cmd, 0, Null)) JobDone(j As HttpJob)
    If j.Success Then
        req.HandleJobAsync(j, "req")
        Wait For (req) req_Result(res As DBResult)
        For Each row() As Object In res.Rows
            myTracking = row(res.Columns.Get("tracking"))
            myWakeCount = row(res.Columns.Get("wakecount"))
            myMaxVibs = row(res.Columns.Get("maxvibs"))
            myVibInterval = row(res.Columns.Get("vibinterval"))
            myTrackCount = row(res.Columns.Get("trackcount"))
            myCheckVib = row(res.Columns.Get("checkvib"))
           
            ' This is the string that I need to send to Arduino
            myConfigTX = myTracking & "," & myWakeCount &"," & myMaxVibs & "," & myVibInterval & "," & myTrackCount & "," & myCheckVib
           
            Log("Config TX: " & myConfigTX)
        Next
    Else
        Log("ERROR: " & j.ErrorMessage)
    End If
    j.Release
End Sub

Sub writeTrans(myDeviceID As String,lat As String,lon As String,myVolts As String, myPercent As String, msgID As String, mySignal As String, mySpeed As String, MyStr As String) As ResumableSub
    Dim date_string As String
    'date time format to be used
    DateTime.DateFormat = "dd-MMM-yyyy"
    DateTime.TimeFormat = "HH:mm:ss"
    date_string = DateTime.Date(DateTime.Now) & " " & DateTime.Time(DateTime.Now)
   
    Dim myfleet As String
    Dim myfriendname As String
   
    '**********************************
    ' Get "fleet" / "friendname" from table "devices"
    Dim req As DBRequestManager = CreateRequest
    Dim cmd As DBCommand = CreateCommand("get_fleet_friendname", Array(myDeviceID))
    Wait For (req.ExecuteQuery(cmd, 0, Null)) JobDone(j As HttpJob)
    If j.Success Then
        req.HandleJobAsync(j, "req")
        Wait For (req) req_Result(res As DBResult)
        For Each row() As Object In res.Rows
            myfleet = row(res.Columns.Get("fleet"))
            Log("fleet: " & myfleet)
            myfriendname = row(res.Columns.Get("friendname"))
            Log("FriendName: " & myfriendname)

        Next
'        Log("deviceid: " & deviceid)
    Else
        Log("ERROR: " & j.ErrorMessage)
    End If
    j.Release
   
    Dim cmd As DBCommand = CreateCommand("write_trans", Array(myDeviceID,lat,lon,myVolts, myPercent,msgID,mySignal,mySpeed, myfleet, myfriendname,date_string,DateTime.Now))
    Dim j As HttpJob = CreateRequest.ExecuteBatch(Array(cmd), Null)
    Wait For(j) JobDone(j As HttpJob)
    If j.Success Then
        Log("write_trans OK")
    End If
    j.Release
    Return j.Success
End Sub

Sub CreateCommand(Name As String, Parameters() As Object) As DBCommand
    Dim cmd As DBCommand
    cmd.Initialize
    cmd.Name = Name
    If Parameters <> Null Then cmd.Parameters = Parameters
    Return cmd
End Sub

Sub CreateRequest As DBRequestManager
    Dim req As DBRequestManager
    req.Initialize(Me, rdcLink)
    Return req
End Sub

Sub Now As String
    DateTime.DateFormat = "dd-MM-yyyy HH:mm:ss"
    Dim dt As Long = DateTime.Now
    Return DateTime.Date(dt)
End Sub

Sub MapValues2ObjectArray(m As Map) As Object()
    Dim mtot As Int = m.size
    Dim mcnt As Int
    Dim obj(mtot) As Object
    For mcnt = 0 To mtot - 1
        Dim v As Object = m.GetValueAt(mcnt)
        obj(mcnt) = v
    Next
    Return obj
End Sub


Private Sub btnClear_Click
    txtLogs.Text = ""
End Sub

It is this string "00,176,25,20000,30,24" that I need to send back to the Arduino that sent the original message "CONFIGIS002"

The other port 5100 uses UDPSocket, but I do not receive the data from Arduino.
Code:
B4X:
#Region Project Attributes
    #MainFormWidth: 600
    #MainFormHeight: 200
#End Region

Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private xui As XUI
    
    Dim UDPSocket1 As UDPSocket
    Private txtLogs As B4XView
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Layout1")
    MainForm.Show
    

    UDPSocket1.Initialize("UDP", 5100, 8000)

'    Dim Packet As UDPPacket
'    Dim data() As Byte
'    data = "Hello from Android".GetBytes("UTF8")
'    Packet.Initialize(data, "197.234.129.17", 5100)
'    UDPSocket1.Send(Packet)
    
End Sub



Sub UDP_PacketArrived (Packet As UDPPacket)
    Dim msg As String
    msg = BytesToString(Packet.Data, Packet.Offset, Packet.Length, "UTF8")
    Log("Message received: " & msg )
    UpdateLogs(msg)
    Dim data() As Byte
    data = "Hello from Android".GetBytes("UTF8")
    Log(Packet.HostAddress) 'See what ipaddress is?
    Packet.Initialize(data, Packet.HostAddress , 5100)
    UDPSocket1.Send(Packet)
    
    Log("Message received: " & msg )
    UpdateLogs(msg)
End Sub

Sub UpdateLogs(strLog As String)
    DateTime.DateFormat = "yyyy-MM-dd HH:mm:ss"
    txtLogs.Text =  DateTime.Date(DateTime.now) & ": " & strLog & CRLF & txtLogs.Text
End Sub
 
Upvote 0

Declan

Well-Known Member
Licensed User
Longtime User
That's because you don't send udp data to b4j, you should learn what udp is and what it does.
I will implement this in the Arduino side, but it will take awhile.
Is it possible for me to reply to the Arduino with the first code posted where:
B4X:
        If MyStr.IndexOf("CONFIG") > -1 Then
            Log("Got Config")
            myDeviceID = MyStr.SubString(MyStr.Length - 5)
            Log ("Config ID: " & myDeviceID)
            getConfig(myDeviceID)
          
        End If
If not, I will implement the UPD side into the Adruino
Many, many thanks for all your valued input
 
Upvote 0
Top