B4J Code Snippet B4A - Sockets and AsyncStreams

@DonManfred actually provided the foundation for this, and I thought it worthy of a snippet.

This involves connecting an android device to an AP and getting data that a scale controller is publishing to it via a RS232 to Ethernet device (every second). If nothing is listening, the data simple vanishes into byte ether...

Globals
B4X:
Sub Process_Globals

    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
    Dim sock As Socket ' Network lib
    Dim AStreams As AsyncStreams ' RandomAccesfile lib  
    Public wghtmsg As String = ""

End Sub

Pause and Resume Subs
B4X:
Sub Activity_Pause (UserClosed As Boolean)

        AStreams.Close  ' close any open stuff... (safe call if not inited)
        sock.Close

End Sub


Sub Activity_Resume
   
    If AStreams.IsInitialized Then ' close any open socket (not likely since Pause took care of this...)
        AStreams.Close
    End If
   
    If sock.IsInitialized Then   ' close any open stream
        sock.Close
    End If

    StartScale   ' create new scale socket object
   
End Sub


Sub StartScale
   
    sock.Initialize("Scalecontroller")
    sock.Connect("10.131.199.3",10001, 10000)
    ' IP address, port, timeout (10 seconds)
    ToastMessageShow(" Connecting to Scale Controller... ",False)

End Sub

Sub Scalecontroller_Connected (Successful As Boolean) ' raised on either success or failure (timeout)
    Log($"Scalecontroller_Connected: (${Successful})"$)
    If Successful Then
        AStreams.Initialize(sock.InputStream,   Null, "Scale") 
       ' create a new stream. Here we only need the input stream from the controller
       ' create an output stream if you wish to talk back to it.
    Else
        ToastMessageShow(" Connection to Scale Controller Failed! ",True)
        SetWeight   '  If, after 10 seconds we cannot connect (some hard problem) then allow manual input    
    End If      
  
End Sub

Now that we are connected to the IP and port, let's get the data

B4X:
Sub Scale_NewData (Buffer() As Byte)

' of course, the following example is specific to my needs - yours WILL vary...

    Dim w As String = ""
    w  = BytesToString(Buffer, 0, Buffer.Length, "UTF8")  ' temp var for processing in buffer
       Log("length of w: "&w.Length&" string: "&w)  ' show the length and what is inside...
 
'  Note: serial to ethernet device has a 2k buffer. This will be sent on first open but string is not 17 chars long (2017 bytes) - so ignore...

    If  w.Length = 17 Then    ' A valid string IS 17 characters long (no more - no less)
       For i = 0 To w.Length-1  ' this was used to see exactly what the string was made of (for testing).  Many space characters in it...
          Log(" i: "&i& "  ["&w.SubString2(i,i+1)&"]")  ' what is each character in string
          Log(" i: "&i& "  ["&Buffer(i)&"]")                   ' what is each buffer byte value
        Next
     
        wghtmsg = w.SubString2(3, 15)  '  this is the center (valid weight) portion of the passed buffer. The rest are control - info characters and carriage return
     
        If w.SubString2(2,3) = Chr(34) Then  '     if byte 3 is a " , then the value of weight is negative .  ( you can't """ to do this, hence the Chr(34) )
           wghtmsg = "-"& wghtmsg.Trim  ' append a " - " (minus sign) to the trimmed weight value (get rid of spaces fore and aft)
        End If
     
        If w.SubString2(2,3) = "(" Then    ' if this char is at location, it means the scale has not yet stabilized (truck is driving on and shaking it)
           wghtmsg = "*"&wghtmsg.Trim&"*"  ' Add " * " to the string to indicate Not Stable
        End If
     
        wghtmsg = wghtmsg.Trim  ' trim this public var again
     
        lblweight.Text = wghtmsg.Trim&" lb"   ' add " lb" to the label text (not really needed)
    End If
 
    Log("  weight: "&lblweight.Text)
End Sub


Sub Scale_Error ' on error
    ToastMessageShow("Scale Error: "&LastException.Message, True)
    Log("Scale_Error: "&LastException.Message)
End Sub

Sub Scale_Terminated ' if terminated somehow....
    Log("Scale_Terminated")
    If AStreams.IsInitialized Then   ' close everything if terminated.  Also - close in Pause!
        AStreams.Close
        sock.Close
    End If

End Sub

Sub SetWeight   ' if mobile device can't reach AP, then have driver type in the weight
                       '  from the digital display on the scale controller (which most always works - 99.8%)

  Dim i As Int
  Dim xlo As String
  Dim kbrd As Phone
   
  xlo = "" ' NumberFormat2(lo ,1,1,1,False)

  Dim param As BD_InputBoxParams
  Dim bd As BetterDialogs
  param.Initialize
  param.Default = xlo
  param.InputType = param.INPUT_TYPE_DECIMAL_NUMBERS
  param.InputTextSize = 24
  param.Question = "Provide The Vehicle Weight"
  param.QuestionTextSize = 28
  param.SpaceBetween = 15dip
  param.Multiline = False
  i = bd.InputBox(" Controller Connection Failed! ",param,"OK","Cancel","",DefCM.BLC)

  If i = DialogResponse.POSITIVE  Then
        wghtmsg = param.Answer
  End If
 
  kbrd.HideKeyboard(Activity)

End Sub

There you have it. A simple and elegant way to use a socket and stream to get data from, in this case, an access point broadcasting on a specific address and port.

Cheers
 
Last edited:
Top