AsyncStreams vs InputStream

Scantech

Well-Known Member
Licensed User
Longtime User
After doing some research in here, there were some complaints about Inputstream bytes available is returning incorrect numbers. Only applies to HTC units. I am stuck and undecided on which one to use. I like using timers with InputStream instead of AsyncStreams (NewData Event). The reason, NewData Event is giving me some problems randomly. When I scroll around with my sliders, UI is busy, or modal screen is shown then NewData Event is either not raised or bytes returned in wrong sequence! As for the HTC units, I am trying to find a workaround for the InputStream but no success.
 

Scantech

Well-Known Member
Licensed User
Longtime User
You should go with AsyncStreams. If possible use prefix mode.
Are you sure that messages arrive in the wrong order? It shouldn't happen unless the Activity is paused.

Here is my code in the NewData event.

B4X:
Sub AStreams_NewData (Buffer() As Byte)


        msg = msg & BytesToString(Buffer, 0, Buffer.Length, "UTF8")
   msg = msg.Replace(Chr(13), Chr(10))

   'LAST CHAR THEN RESET
   If msg.EndsWith(">") Then       
      Log("AStream_NewData: " & msg)
      blnReadySend = True            'ELM IDLE STATE INDICATOR
      Timer_Timeout.Enabled = False      'RESET TIMEOUT
   Else If msg.Contains(">") Then
      Log("AStream_NewData: Bad Data " & msg)
      blnReadySend = True
      Timer_Timeout.Enabled = False
      msg = ""
   End If

End Sub
">" is the last Character received in message from the ELM Bluetooth Device.

I am still investigating whether it is my end or the AsyncStreams. I have to reinitialize the AsyncStreams when I get no data returned at random time. I am not 100% sure if my coding is solid. I have no problems with data corruption when the app is left untouched. Prefix mode will be difficult to use or impossible with this Bluetooth Device.
 
Last edited:
Upvote 0

Scantech

Well-Known Member
Licensed User
Longtime User
B4X:
Sub AStreams_NewData (Buffer() As Byte)


        msg = msg & BytesToString(Buffer, 0, Buffer.Length, "UTF8")
   msg = msg.Replace(Chr(13), Chr(10))
        Log("Astreams......: " & msg)

   'LAST CHAR THEN RESET
   If msg.EndsWith(">") Then       
      Log("AStream_NewData: " & msg)
      blnReadySend = True            'ELM IDLE STATE INDICATOR
      Timer_Timeout.Enabled = False      'RESET TIMEOUT
   Else If msg.Contains(">") Then
      Log("AStream_NewData: Bad Data " & msg)
      blnReadySend = True
      Timer_Timeout.Enabled = False
      msg = ""
   End If

End Sub

I have updated the NewData Event to log in msg at the 3rd code line. Check out the attached log (My log). Compare Attempt 1 to Attempt 2 data. Attempt 2 Data is the correct format
"AStream_NewData: 486B1041050009
>"
Attempt #1 can be duplicated (not always) by calling out modal form.
 

Attachments

  • log.txt
    1.1 KB · Views: 211
Last edited:
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
Unless you use prefix mode, you cannot assume that you receive a full message or that you receive a single message. It depends on the internal buffers state.

For example if you need to parse strings coming from a GPS device you should append the new data to a StringBuilder object, and check if there is a complete string each time.
 
Upvote 0

Scantech

Well-Known Member
Licensed User
Longtime User
Thanks Erel, I will give it a shot. I was reading the Core library on the StringBuilder and I was impressed on the time result.
 
Upvote 0

briant1972

Member
Licensed User
Longtime User
I had trouble with data getting chopped up using astreams. I wasn't sure which device was the problem, but I ended up adding a timer that was started when the new data event was raised, the timer was set to go off after a time delay which was the best I could do to make sure that data was done. Then, every time the new data even was raised, the timer was reset and the data was stacked until there wasn't data long enough for the timer timed out, then the data was assumed done and then parsed. Works great. The timer didn't need to run very long either since it turned out that the pauses in the data was less than 200ms.

Sub AStreams_NewData (Buffer() As Byte)
Timer1.Enabled = False
Timer1.Enabled = True
msg = msg & BytesToString(Buffer, 0, Buffer.Length, "UTF8")

End Sub

Sub Timer1_Tick
Parse_Stream
End Sub
 
Upvote 0

Scantech

Well-Known Member
Licensed User
Longtime User
I had trouble with data getting chopped up using astreams. I wasn't sure which device was the problem, but I ended up adding a timer that was started when the new data event was raised, the timer was set to go off after a time delay which was the best I could do to make sure that data was done. Then, every time the new data even was raised, the timer was reset and the data was stacked until there wasn't data long enough for the timer timed out, then the data was assumed done and then parsed. Works great. The timer didn't need to run very long either since it turned out that the pauses in the data was less than 200ms.

Sub AStreams_NewData (Buffer() As Byte)
Timer1.Enabled = False
Timer1.Enabled = True
msg = msg & BytesToString(Buffer, 0, Buffer.Length, "UTF8")

End Sub

Sub Timer1_Tick
Parse_Stream
End Sub

Briant, Thank you very much. I will plug in that code and see what happens.
 
Upvote 0

priusfan

Member
Licensed User
Longtime User
here is the way I do it (and it works well);
I use a stringbuffer named response because it is much more efficient than playing with plain string.
B4X:
Sub AStreams_NewData (Buffer() As Byte)
   ' this event is activated when we receive data
   ' we will do something only after receiving a ">" 
   ' that means the answer is complete 
    Dim rsp As String
    rsp = BytesToString(Buffer, 0, Buffer.Length, "UTF8")
   response.append(rsp)
   Ready_ForNext = rsp.EndsWith(">") 
   If Ready_ForNext Then
      decode(response)
      response.Initialize
      send_nextcmd   
   End If
End Sub

BTW, I use a good quality BT dongle, because the chinese clones are slow and not regular...
 
Upvote 0

Scantech

Well-Known Member
Licensed User
Longtime User
here is the way I do it (and it works well);
I use a stringbuffer named response because it is much more efficient than playing with plain string.
B4X:
Sub AStreams_NewData (Buffer() As Byte)
   ' this event is activated when we receive data
   ' we will do something only after receiving a ">" 
   ' that means the answer is complete 
    Dim rsp As String
    rsp = BytesToString(Buffer, 0, Buffer.Length, "UTF8")
   response.append(rsp)
   Ready_ForNext = rsp.EndsWith(">") 
   If Ready_ForNext Then
      decode(response)
      response.Initialize
      send_nextcmd   
   End If
End Sub

BTW, I use a good quality BT dongle, because the chinese clones are slow and not regular...

Hello Pruisfan, What brand are you using? Actually, the clone I am using is not that bad for the price you pay. It gets the job done and the data/sec is ok on the ecu that I have tested. Not sure about the CAN Bus system. I do not have one to test with. It does have data corruption problems at random times. I can't complain for the price I paid.
 
Last edited:
Upvote 0

maleche

Active Member
Licensed User
Longtime User
Looks great!
How is your data displayed?
What is the limit size of a listview in characters,bytes, etc.
Can a List hold endless (somewhat) data from which to scroll through after receiving serial data?

Thanks,
 
Upvote 0
Top