B4A Library [class] AsyncStreamsText - Useful when working with streams of text

Status
Not open for further replies.
When a message (set of bytes) is sent over a network channel, of any type, there is no guarantee that the whole message will arrive as a single set of bytes.

The message might be split or merged together with other messages.

One way to overcome this issue is to initialize AsyncStreams in "prefix" mode. In this mode a 4 bytes header is added to each message with the message length. This allows AsyncStreams to internally build the messages correctly. However you can only use prefix mode if both sides of the connection adhere to this protocol. If for example you connect to a Bluetooth GPS then you cannot use prefix mode.

AsyncStreamsText can help you if:
1. The data sent is text and not binary data.
2. Each message ends with an end of line character (both Unix and Windows formats will work).

AsyncStreamsText works by handling the NewData event and looking for the end of line characters.

Using AsyncStreamsText is simple:
B4X:
Sub Process_Globals
   Private ast As AsyncStreamsText
   Private server As ServerSocket
End Sub

Sub Globals
End Sub

Sub Activity_Create(FirstTime As Boolean)
   If FirstTime Then
      server.Initialize(5555, "server")
      Log(server.GetMyWifiIP)
      server.Listen
   End If
End Sub

Sub server_NewConnection (Successful As Boolean, NewSocket As Socket)
   If Successful Then
      If ast.IsInitialized Then ast.Close
      ast.Initialize(Me, "ast", NewSocket.InputStream, NewSocket.OutputStream) 'initialize AsyncStreamsText with the socket streams.
   Else
      Log(LastException)
   End If
   server.Listen
End Sub

Sub ast_NewText(Text As String)
   Log("Text: " & Text)
   Log(Text.Length)
End Sub

Sub ast_Terminated
   Log("Connection terminated")
End Sub

Sub Activity_Click
   ast.Write("this is an example..." & Chr(10) & Chr(13))
End Sub

NewText event is raised each time that there is a complete message available.

Note that AsyncStreamsText.Write writes text and not bytes.
The charset field sets the encoding used to convert the bytes to string and vice versa.
 

Attachments

  • AsyncStreamsText.bas
    1.8 KB · Views: 2,539
Last edited:

Max72

New Member
Licensed User
Hi all,
I'm using asyncstreamtext in a B4J application to get data by USB from PIC processor, but when I receive characters I don't receive the correct ASCII number that i supposed to receive, what I get is a blob string without any meaning.
Example. I'm waiting for this message (it's a string of course): "<ERR:4:xx;" I receive "?<??*???x?H?"
The ASCII numbers are completely wrong, some are negative! I've just applied the .bas and in Main the Sub astream_NewText, initialized astream (Me, "astream", sp.GetInputStream, sp.GetOutputStream).
If I try with a terminal program or VB.net all works fine.
Any hint?
 

agus mulyana

Member
Licensed User
Hi erel,

According to the previous post, i have a same problem , when i use an asynchronous text class and combine it with USB serial, it not working properly, so, if you don't mind, please help me....or any suggestion for fix it, is very useful for me

Thank you so much
 

agus mulyana

Member
Licensed User
Hi erel, here is my code, and it is not working properly, please help me, in my code, i want to receive data from ARDUINO, through OTG USB, and i combine usb serial with asychronous text, but still error :

#Region Project Attributes
#ApplicationLabel: USB Serial Asinkron
#VersionCode: 1
#VersionName:
#SupportedOrientations: unspecified
#CanInstallToExternalStorage: false
#End Region

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

Sub Process_Globals
Dim usb As UsbSerial
Dim astreams As AsyncStreams
Dim ast As AsyncStreamsText

End Sub

Sub Globals
Dim lbl_data As Label
End Sub

Sub Activity_Create(FirstTime As Boolean)

Activity.LoadLayout("1")

End Sub

Sub btnOpen_Click
If usb.Open(9600) Then
Log("Connected successfully!")
lbl_data.Text = "koneksi sukses "
astreams.Initialize(usb.GetInputStream, usb.GetOutputStream, "astreams")
' ast.Initialize(Me, "ast", usb.InputStream, usb.OutputStream) 'initialize AsyncStreamsText with the socket streams.
ast.Initialize(Me, "ast", usb.GetInputStream, usb.GetOutputStream ) 'initialize AsyncStreamsText with the socket streams.


Else
Log("Error opening USB port")
lbl_data.Text = "koneksi gagal "
End If
End Sub

Sub Astreams_NewData (Buffer() As Byte)
Log("NewData")
'Log(BytesToString(Buffer, 0, Buffer.Length, "UTF8"))
End Sub
Sub ast_NewText(Text As String)
lbl_data.Text = Text
End Sub

Sub btnClose_Click
astreams.Close
ast.Close
End Sub

Sub btnSend_Click
astreams.Write("abcde".GetBytes("UTF8"))
ast.Write("test")
End Sub

Sub AStreams_Error
Log("Error: " & LastException)
astreams.Close
End Sub
Sub Astreams_Terminated
Log("Terminated")
astreams.Close
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub
 

Max72

New Member
Licensed User
Hi Erel,
sorry for delay in my answer.
I solved the problem, it was a mistake on serial port configuration: I've inverted databits and stopbit values! :oops:
Now it works fine! Thanks a lot!
 

Reyes5

Member
Licensed User
Hi, I always have use the old textreader and writer to communicate over Bluetooth with my microprocessor.
It worked fine till Android 4.1 Now, on newer versions 4.2 and + , it no longer works.

Therefore I wanted to use asyncstreamtext.
It compiles OK, but when app runs I get error : java.lang.RuntimeExeption:Object was not initialised. My code looks like this :

B4X:
Sub Process_Globals
    Dim answer As String
    Dim sndStr As String
       Private ast As AsyncStreamsText
       Private server As ServerSocket
   
End Sub

Sub Globals
    Dim waiting As Label
    Dim sendlist As Button
    Dim btnSend As Button
    Dim txtLog As EditText
    Dim txtSend As EditText
End Sub

Sub Activity_Create(FirstTime As Boolean)
   
    Main.connected = False
    If FirstTime Then
              server.Initialize(5555, "server")
                  Log(server.GetMyWifiIP)
              server.Listen

    End If

    Activity.LoadLayout("bluetooth")
    Activity.Title = "Send Show"
    Activity.AddMenuItem("Connect", "mnuConnect")
    Activity.AddMenuItem("Disconnect", "mnuDisconnect")
    sendlist.Visible = False
    sendlist.Enabled = False
    mnuConnect_Click
   
End Sub
Sub Activity_Resume
    If Main.Serial1.IsEnabled = False Then
        Msgbox("Please enable Bluetooth.", "")
    End If
End Sub

and

B4X:
Sub server_NewConnection (Successful As Boolean, NewSocket As Socket)
  If Successful Then
  If ast.IsInitialized Then ast.Close
       ToastMessageShow("before ast init " , False)

  ast.Initialize(Me, "ast", NewSocket.InputStream, NewSocket.OutputStream) 'initialize AsyncStreamsText with the socket streams.
  Else
  Log(LastException)
  End If
  server.Listen
End Sub

Sub ast_NewText(Text As String)
  Log("Text: " & Text)
  answer = Text
End Sub

Sub ast_Terminated
  Log("Connection terminated")
End Sub

in between, I try this :

B4X:
Sub btnSend_Click
   If Main.connected Then
     ast.Write("STARTUP" & Chr(10) & Chr(13))
     txtSend.Text = ""
   Else
     Msgbox("Please connect Bluetooth.", "")
   End If
End Sub

Than, it produces the error : java.lang.RuntimeExeption:Object was not initialised.
What am I missing? The class is in the project.

Many thanks for your quick reply ! Paul.
 

Reyes5

Member
Licensed User
Hi Erel, this one :
ast.Write("STARTUP" & Chr(10) & Chr(13))

strange, when I run it in debug, the error on android is different : error occured in sub: java.io.UnsupportedEncodingExeption ...

sorry, I do not understand ...
 

Reyes5

Member
Licensed User
Please post the full error message from the logs.

ok, here you go :

at anywheresoftware.b4a.BA.raiseEvent2(BA.java:173)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:161)
at anywheresoftware.b4a.BA.raiseEvent(BA.java:157)
at anywheresoftware.b4a.objects.ViewWrapper$1.onClick(ViewWrapper.java:66)
at android.view.View.performClick(View.java:4438)
at android.view.View$PerformClick.run(View.java:18422)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5001)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
at dalvik.system.NativeStart.main(Native Method)
java.lang.RuntimeException: Object was not initialized.
java.lang.RuntimeException: Object was not initialized.
at anywheresoftware.b4a.debug.Debug.PushSubsStack(Debug.java:124)
at rollin.eyes.led.asyncstreamstext._write(asyncstreamstext.java:247)
at rollin.eyes.led.bluetooth._sendlist_click(bluetooth.java:613)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:173)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:161)
at anywheresoftware.b4a.BA.raiseEvent(BA.java:157)
at anywheresoftware.b4a.objects.ViewWrapper$1.onClick(ViewWrapper.java:66)
at android.view.View.performClick(View.java:4438)
at android.view.View$PerformClick.run(View.java:18422)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5001)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
at dalvik.system.NativeStart.main(Native Method)
 

Reyes5

Member
Licensed User
Indeed, with a test it looks like it is not initialised.
Strange, it never runs trough sub server_NewConnection, where the init should happen ...
What line should cause to run sub server_NewConnection ?

What do you mean with "where is the encoding error" ?
thanks !
 

Martin Larsen

Active Member
Licensed User
This makes bluetooth serial communication much easier :)

Before I had to use this (which is probably similar to what goes on inside AsyncStreamText):
B4X:
Sub AStream_NewData (Buffer() As Byte)
    Dim s As String = BytesToString(Buffer, 0, Buffer.Length, "UTF8")
    btText = btText & s
    Dim i As Int = btText.IndexOf(Chr(13) & Chr(10))
    If i>=0 Then
        Dim cmd As String = btText.SubString2(0, i)
        btText = btText.SubString(i).Trim
        LogMessage("You", cmd.Trim)
    End If
End Sub
Now just:

B4X:
Sub AStream_NewText(text As String)
    cmd = text.Trim
    LogMessage("You", cmd.Trim)
End Sub
 
Last edited:
Status
Not open for further replies.
Top