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

Status
Not open for further replies.

Erel

Administrator
Staff member
Licensed User
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

Last edited:

positrom2

Active Member
Licensed User
Is there some advantage of the AsyncStreamsText example compared to using textreader since in both variants only text can be transmitted?

When I compile or invoke the libraries (network and random access) the windows firewall is asking if java shall be blocked or not. I am curious on the reason for internet access when it seems not to be needed...
Regards, positrom2
 

Erel

Administrator
Staff member
Licensed User
Is there some advantage of the AsyncStreamsText example compared to using textreader since in both variants only text can be transmitted?
You cannot use TextReader with network streams. This will block the main thread.

When I compile or invoke the libraries (network and random access) the windows firewall is asking if java shall be blocked or not. I am curious on the reason for internet access when it seems not to be needed...
This is not related to these libraries. This is probably Java which tries to check for updates.
 

positrom2

Active Member
Licensed User
Hi Erel,
thanks for the answers.
You cannot use TextReader with network streams. This will block the main thread.
I am using textreader in BT and WiFi connections. What happens, is that the code will wait "forever" until text (data numbers) are coming in terminated by CR&LF (or one of those, not sure). Although that is waisting CPU time, it assures that I know that I am subsequently processing the actual data. Consider trying to synchronize the steps of a stepper motor with data read in corresponding to the actual position of the motor. Would that be possible with asyncstreams? If data were fetched as they come in and the data processing would run independently I suspect that synchronization is less than straightforward to achieve.

As you see, I am following the asyncstream posts since I would like to receive the data in binary format (I had some posts here on this issue earlier). So the questions are if my assumptions mentioned here are right - and if not how - how your example could be modified to receive a binary data stream.
Regards, positrom2
 

Erel

Administrator
Staff member
Licensed User
I should have written: you should not use TextReader with network streams. Also note that on Android 4+ (when targetSdkVersion > 11) you will get an exception in that case.

AsyncStreams objects handles binary data. You do not need to do anything special. I think that it is better if you start a new thread and give more details about the problem you are trying to solve.
 

Stulish

Active Member
Licensed User
Also,

Could this be used with USBSerial Comms??

Thanks

Stu
 

PhilN

Member
Licensed User
Hi Errol, thanks for the AsyncStreamsText Class. When I run the app (your example code), I am getting an error:
asyncstreamstext_write (java line: 140)
java.io.UnsupportedEncodingException:

Not sure how to fix it. :sign0163:
 

merlin2049er

Well-Known Member
Licensed User
What happens when you load a module? Does it show up somewhere that it's loaded?

Ok, on a new tab. Neat.
 
Last edited:

Tom Christman

Active Member
Licensed User
I'm trying the code listing in the first post (by Erel) substituting a Usb connection for server connection, and the "Private ast As AsyncSteamsText" line in Process Globals is not accepted (red) in B4A. I also downloaded the attached AstreamsText.bas which is a "class" which doesn't appear to be connected to the presented code. What am I doing wrong, as I'm trying to use the posted code to receive text from a ucomputer via a usb connection. The usb connection funtions with the AsyncStreams code, but I have a problem with errors in byte reception, and the data is text anyway.
 

Tom Christman

Active Member
Licensed User
Erel Thanks for the speedy reply and
Yes I added the module.
I then replaced

B4X:
Sub Process_Globals
Private ast As AsyncSteamsText
Private server As ServerSocket
End Sub
with

B4X:
Sub Process_Globals
Dim ast As AsyncStreamsText
Dim usb As UsbSerial
End Sub
Then I substituted the posted code section

B4X:
Sub Activity_Create(FirstTime AsBoolean)
If FirstTime Then
server.Initialize(5555, "server")Log(server.GetMyWifiIP)
server.Listen
EndIf
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
With this code

B4X:
Sub Activity_Create(FirstTime As Boolean)
   Activity.LoadLayout("1")
   btnClose.Enabled = False
   btnSend.Enabled = False
End Sub

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")
     usb.SetParameters(9600,8,1,0)
     usb.UsbTimeout = 1000
    
     Dim dev As Int
     dev = usb.Open(9600)
     'usb.UsbTimeout=100
    
     If dev <> usb.USB_NONE Then
       Log("Connected successfully!")
       btnOpen.Enabled = False
       btnClose.Enabled = True
       btnSend.Enabled = True
      ast.Initialize(usb.GetInputStream, usb.GetOutputStream, "ast")
      
     Else
       Log("Error opening USB port")
     End If
   Else
     usb.RequestPermission
   End If
  
End Sub
And the code
B4X:
ast.Initialize(usb.GetInputStream, usb.GetOutputStream, "ast")
gives a compiler error.
 
Last edited:
Status
Not open for further replies.
Top