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,538
Last edited:

Martin Larsen

Active Member
Licensed User
Please use [code]code here...[/code] tags when posting code.

Note that AsyncStreamsText is more sophisticated than the code you previously used. It collects the text so if a message is split into several "packets" it will still be parsed correctly.

I have edited the post to include code tags. It looks much better that way :)

AsyncStreamsText is without doubt more sophisticated, but my code actually also collects packets as btText is a global variable. So even if the text arrives in chunks it is appended to btText and only interpreted when a CRLF is detected.
 

Reyes5

Member
Licensed User
Hi Erel,
I am still strugling with using AsyncStreamText class in your bluetooth example.
I have to communicate with a microprocessor uart over BT.
It worked fine in older android versions with textreader and writer ... but I have to port to Android KitKat and Lollipop now.
Your Bluetooth example with Asyncstreams works fine, than I try to build it with AsyncStreamText class,
but then I get this error as soon as BT is connected :

** Activity (main) Resume **
** Activity (main) Resume **
RE000505

:00:00:12:06:52:81
connected: true
** Activity (main) Pause, UserClosed = false **
** Activity (chatactivity) Create, isFirst = true **
Error occurred on line: 17 (asyncstreamstext)
java.lang.RuntimeException: Object should first be initialized (InputStream).
at anywheresoftware.b4a.AbsObjectWrapper.getObject(AbsObjectWrapper.java:46)
at anywheresoftware.b4a.samples.bluetooth.asyncstreamstext._initialize(asyncstreamstext.java:55)
at anywheresoftware.b4a.samples.bluetooth.chatactivity._activity_create(chatactivity.java:308)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:636)
at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:305)
at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:238)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:121)
at anywheresoftware.b4a.samples.bluetooth.chatactivity.afterFirstLayout(chatactivity.java:98)
at anywheresoftware.b4a.samples.bluetooth.chatactivity.access$100(chatactivity.java:16)
at anywheresoftware.b4a.samples.bluetooth.chatactivity$WaitForLayout.run(chatactivity.java:76)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
** Activity (chatactivity) Resume **

I add the zip of the project.
Where do I go in error ? Thanks very much for your help !
Paul.
 

Attachments

  • BluetoothTXT.zip
    59.5 KB · Views: 146

HARRY

Active Member
Licensed User
Hi,

I want to use AsyncStreamsText as a client. The server is an Arduino, which collects data. The B4A program reads over Wifi from time to time the collected data. In the Arduino program I take care of CRLF when needed.

Up till now I cannot find a complete example to use AsyncStreamsText as a client. With complete I mean with connecting/disconnecting to the server, initializing the sockets , etc.. Can somebody help me?

Harry
 

GuyBooth

Active Member
Licensed User
I want to use this approach for my code but struggling to make it work.
I have tried the class and example exactly as written, and added a line in the FIrstTime loop to prove that the server initializes.
The server initializes, but the event server_NewConnection doesn't trigger. As a result the ast doesn't initialize, and the code fails when activity_Click is triggered.
The log is:

B4X:
** Activity (main) Create, isFirst = true **


192.168.3.121


Server.IsInitialized is true
** Activity (main) Resume **


java.lang.RuntimeException: Object was not initialized.


    at anywheresoftware.b4a.debug.Debug.PushSubsStack(Debug.java:121)
    at b4a.example.asyncstreamstext._write(asyncstreamstext.java:240)
    at b4a.example.main._activity_click(main.java:343)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:511)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:187)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:175)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:171)
    at anywheresoftware.b4a.objects.ViewWrapper$1.onClick(ViewWrapper.java:77)
    at android.view.View.performClick(View.java:4222)
    at android.view.View$PerformClick.run(View.java:17273)
    at android.os.Handler.handleCallback(Handler.java:615)
    at android.os.Handler.dispatchMessage(Handler.java:92)
    at android.os.Looper.loop(Looper.java:137)
    at android.app.ActivityThread.main(ActivityThread.java:4895)
    at java.lang.reflect.Method.invokeNative(Native Method)


    at java.lang.reflect.Method.invoke(Method.java:511)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:994)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:761)
    at dalvik.system.NativeStart.main(Native Method)

I have run out of ideas - can anyone help? This should be soooo simple :( ...
 

mr23

Active Member
Licensed User
I want to use this approach for my code but struggling to make it work.
I have tried the class and example exactly as written, and added a line in the FIrstTime loop to prove that the server initializes.
The server initializes, but the event server_NewConnection doesn't trigger. As a result the ast doesn't initialize, and the code fails when activity_Click is triggered.
The log is:

B4X:
** Activity (main) Create, isFirst = true **


192.168.3.121


Server.IsInitialized is true
** Activity (main) Resume **


java.lang.RuntimeException: Object was not initialized.


    at anywheresoftware.b4a.debug.Debug.PushSubsStack(Debug.java:121)
...

I have run out of ideas - can anyone help? This should be soooo simple :( ...


It would help get a response if you posted a simplified version of your code, or a zip of the project.
 

GuyBooth

Active Member
Licensed User
Sorry if I wasn't clear, but this is entirely based on the example at the beginning of this thread - I haven't been able to get far enough to incorporate it into my own project at this stage.
From what I see in my tests, the server_NewConnection has to be triggered by an incoming message - but I have to send a message first in order to trigger an incoming one. Catch 22 if this is the case ... so what is missing from the example?
 

Declan

Well-Known Member
Licensed User
Hi,
I am attempting to use AsyncStreamsText to read the message received on the USB from an Arduino UNO.
I have modified the USB Serial Example code.
The code compiles OK, but when I run the app on my Android device:
I get the messagebox displaying the Device Information.
BUT, when I press the OK button on the MessageBox, I get:
"Unfortunately, USB Serial Example has stopped"

The code where the app stops is:
B4X:
Sub btnOpen_Click
   If usb.UsbPresent = usb.USB_NONE Then
     Log("Msgbox - no device")
     Msgbox("No USB device or accessory detected!", "Error")
     Log("Msgbox - returned")
     Return
   End If
  
    Log("Checking permission")
    If (usb.HasPermission) Then
        Msgbox(usb.DeviceInfo, "Device Information")
        Dim dev As Int
        dev = usb.Open(9600)       
        If dev <> usb.USB_NONE Then
            Log("Connected successfully!")
            btnOpen.Enabled = False
            btnClose.Enabled = True
            btnSend.Enabled = True           
            ast.Initialize(usb,"ast",usb.GetInputStream,usb.GetOutputStream)
        Else
            Log("Error opening USB port")
        End If
    Else
        usb.RequestPermission
    End If
End Sub

I cannot understand what is causing the app to stop?
 

Declan

Well-Known Member
Licensed User
Thanks Erel,
I do not get anything written to the log.
I have attached my project code.
 

Attachments

  • UsbSerialText.zip
    15.8 KB · Views: 125

Chuckman200

New Member
Licensed User
All,

I am missing something with AsysnStreamsText
I am just using Erel's sample code.
Upon Compiling I receive the following error:

B4A version: 5.80 BETA #1
Parsing code. Error
Error parsing program.
Error description: Unknown type: asyncstreamstext
Are you missing a library reference?
Occurred on line: 16 (Main)
Dim ast As AsyncStreamsText


I thought that AsyncStreams was a portion of the Random Access Library.
Reviewing the documentation it has no member "Text"
Is their another Library I should include?

Thank you all for the help.
 

wiwit

Member
Licensed User
Hallo , I changes the Astreams to AST,
But there is a mistake

B4X:
Sub Process_Globals
Private ast As AsyncStreamsText
End Sub

Sub Serial1_Connected (Success As Boolean)
    If Success Then
        ToastMessageShow("Connection Successfully", False)
        ast.Initialize(Me, "ast",Serial1.InputStream, Serial1.OutputStream)
        'AStreams.Initialize(Serial1.InputStream, Serial1.OutputStream, "AStreams")
        connected = True
        vib.Vibrate (100)
        RemoveViews
        Activity.LoadLayout("1")
      
    Else
        connected = False
        Msgbox("BT Not found ", "Error Connecting")
        vib.Vibrate (60)
    End If
End Sub

Sub mnudisconnect_click
    vib.Vibrate(60)
    connected = False:ast.Close:Serial1.Disconnect 'connected = False:AStreams.Close:Serial1.Disconnect
    ToastMessageShow("Disconnecting Successfully", False)
End Sub

Sub Activity_Pause (UserClosed As Boolean)
    If UserClosed Then
        ast.Close   '  AStreams.Close
        Serial1.Disconnect
    End If
End Sub


Sub AStreams_NewData (Buffer() As Byte) 'Sub AStreams_NewData (Buffer() As Byte)
    Dim bc As ByteConverter
    Dim msg As String = bc.StringFromBytes(Buffer, "UTF8")
    Log("msg = " & msg.Length & " [" & msg & "]")
  
        Dim EqualsAt As Int = msg.IndexOf("=")    'INI
    If EqualsAt < 0 Then
    Log("invalid setting line: " & msg)
  
    Else
        Dim SettingId As String = msg.SubString2(0, EqualsAt)
        Dim SettingValue As String = msg.SubString(EqualsAt + 1)

            Select Case SettingId 
            Case "s1"
                Label1.Text = SettingValue

            Case "s2"
            Label2.Text = SettingValue

  
            Case "s3"
                Label4.Text = SettingValue
              
        End Select
    End If
End Sub

Sub sent_data
    If connected Then
        If ast.IsInitialized = False Then :Return:End If 'If AStreams.IsInitialized = False Then :Return:End If
        Dim buffer() As Byte
        buffer = data_button.GetBytes("UTF8")
            ast.Write(buffer) ' AStreams.Write(buffer)
    End If
    getar.Vibrate (50)
End Sub

B4X:
Generating R file.    (0.00s)
Compiling generated Java code.    Error
B4A line: 285
ast.Write(buffer) ' AStreams.Write(buffer)
javac 1.8.0_221
src\axc\P\main.java:1430: error: no suitable method found for NumberToString(byte[])
_ast._write /*String*/ (BA.NumberToString(_buffer));
                          ^
    method BA.NumberToString(double) is not applicable
      (argument mismatch; byte[] cannot be converted to double)
    method BA.NumberToString(float) is not applicable
      (argument mismatch; byte[] cannot be converted to float)
    method BA.NumberToString(int) is not applicable
      (argument mismatch; byte[] cannot be converted to int)
    method BA.NumberToString(long) is not applicable
      (argument mismatch; byte[] cannot be converted to long)
    method BA.NumberToString(Number) is not applicable
      (argument mismatch; byte[] cannot be converted to Number)
1 error

where did the error come from, is there a solution?
thank you
 
Status
Not open for further replies.
Top