I am new to B4A and am trying to communicate with a Serial device using USBSerial v2.4
I am having difficulty clearly understanding event code priorities for timer events and Astreams_NewData.
The priority of B4A's internal messaging queue system is not clearly explained (at least I can't find documentation)
I want to query a USB>Serial printer by sending the relevant ESCPOS command (working, no problems)
But after sending I need to read a status data byte returned as a result of the above command (using Astreams _NewData, working)
I can do all this OK.
I want to implement a timeout waiting for reply in case the printer is not connected so the app doesn't hang waiting on a reply that will never come.
This is what I'm doing. I am not using Starter Service, all code is in Main.
1. Send ESC POS query status command to printer.
2. Set a (global process) flag RX_NewDataFlag = False (this flag is changed to True by Astreams _NewData event to indicate that we received something)
3. Set a (global process) flag RX_Time_Expired = False and Enable RX timer (ticks every 500mS). The Timer is initialized in Sub Activity_Create by RxTimer.Initialize("RxTimer", 500). The idea here is to use the RX timer to determine if we have finished waiting for an expected reply.
4. Loop until the RX_Time_Expired flag changes to True, indicating that timeout has occurred
5. Check RX_NewDataFlag to see if it is True (meaning data was received). If no data then flag would be False so print error message.
And now the relevant code:
RXTimer_Tick:
Astreams1_NewData:
escpos_getstatus:
Button2_Click:
I am having trouble with this because it seems that the sequence of events that occur is wrong:
From the Log: (I am running in release mode on some cheap 7" tablet, with B4A bridge & #BridgeLogger: True for logging)
Astreams _NewData is running AFTER I thought it would, so that the RX_NewDataFlag check in Button2_Click fails and "Printer Error" is displayed.
It seems that _NewData runs AFTER Button2_Click code is finished?!
If the _Tick code runs as expected why not _NewData?
Further questions:
1. When does a Timer _Tick or Astreams _NewData event actually run? Anywhere in the middle of another sub's code or ONLY AFTER the sub code has finished?
(if you are familiar with embedded programming like Arduino you know that an Interrupt can occur anytime and the interrupt code will run after each instruction is complete). So I was hoping that B4A would be the same way. However from looking at Log messages it appears that event code only executes after the currently executed sub or event code is done - is this true?
2. Does Astreams _NewData event have the same priority as other events (e.g. Timer _Tick)? The problem is the _NewData event code is running later than it should so the RX_NewDataFlag doesn't get changed to True before the check.
Why is _NewData not running when it should?
How can I make the _NewData a higher priority event so it occurs sooner? (Do I need to move _NewData to starter service? Will it have higher priority)
3. How the the internal B4A messaging system work? Is there anything like DoEvents to get the _NewData code to run sooner?
4. Is there a B4A wiki? (apart from the tutorials/beginner's guide/user's guide). While the forum is helpful a properly organized wiki would be wonderful to have.
Apologies if I have missed something here. I have spent 2 days on this and am a little frustrated!
Thanks for reading, hope someone can help!
I am having difficulty clearly understanding event code priorities for timer events and Astreams_NewData.
The priority of B4A's internal messaging queue system is not clearly explained (at least I can't find documentation)
I want to query a USB>Serial printer by sending the relevant ESCPOS command (working, no problems)
But after sending I need to read a status data byte returned as a result of the above command (using Astreams _NewData, working)
I can do all this OK.
I want to implement a timeout waiting for reply in case the printer is not connected so the app doesn't hang waiting on a reply that will never come.
This is what I'm doing. I am not using Starter Service, all code is in Main.
1. Send ESC POS query status command to printer.
2. Set a (global process) flag RX_NewDataFlag = False (this flag is changed to True by Astreams _NewData event to indicate that we received something)
3. Set a (global process) flag RX_Time_Expired = False and Enable RX timer (ticks every 500mS). The Timer is initialized in Sub Activity_Create by RxTimer.Initialize("RxTimer", 500). The idea here is to use the RX timer to determine if we have finished waiting for an expected reply.
4. Loop until the RX_Time_Expired flag changes to True, indicating that timeout has occurred
5. Check RX_NewDataFlag to see if it is True (meaning data was received). If no data then flag would be False so print error message.
And now the relevant code:
RXTimer_Tick:
B4X:
Sub RxTimer_Tick
'timer ticks 500mS (RxTimer is setup in ActivityCreate)
Log("RxTimer tick!")
RxTimerTickCount = RxTimerTickCount + 1
If RxTimerTickCount = 4 Then
RX_Time_Expired = True
RxTimer.Enabled = False 'disable timer
RxTimerTickCount = 0 ' reset Rx counter for next pass
Button2.Text = "Query Status" ' change from wait to normal text
End If
End Sub
Astreams1_NewData:
B4X:
Sub AStreams1_NewData (Buffer() As Byte)
' This code handles incoming serial data from USB serial port
'
RX_NewDataFlag = True ' we received new data so set flag so other code knows
Dim temp As String
Dim y As Int
Log("NewData Data Length: " & (Buffer.Length))
For y = 0 To Buffer.Length -1
temp = Buffer(y)
temp = Bit.ToHexString(temp)
If temp.Length = 1 Then temp = "0" & temp
temp = temp.ToUpperCase
Log("RECEIVE (Hex): " & temp)
EditText1.Text = temp
Next
End Sub
escpos_getstatus:
B4X:
Sub escpos_getstatus(function_n)
' Query Printer Status by sending DLE EOT command and receiving status byte (has reply wait timeout so will not hang for disconnected printer)
Log("escpos_getstatus - enter")
RX_NewDataFlag = False ' set "did we receive new data flag" false
' send status cmd
astreams1.Write(Array As Byte(0x10, 0x04, function_n)) ' ESC d data
Button2.Text = "Waiting"
Log("escpos_getstatus - exit")
End Sub
Button2_Click:
B4X:
Sub Button2_Click
' Sends TRANSMIT REAL TIME STATUS command
Log("Button2 - about to call escpos_getstatus")
' prepare for receive (setup timer)
RX_Time_Expired = False ' RxTimer_Tick code will set to true when time up
RxTimer.Enabled = False
RxTimer.Enabled = True ' disabling then enabling timer ensures that full timing period will begin when enabled (i.e timer reset)
Log("Button2 - started rx timer")
escpos_getstatus(1) ' send the command
Do While RX_Time_Expired = False
DoEvents ' how do I wait here until flag set without using DoEvents?
Loop
' what is happening is RX_Time_Expired gets set True by _Tick but RX_NewDataFlag is False since Astreams1_NewData hasn't run yet!
Log("Button2 - RXNewDataFlag = " & RX_NewDataFlag)
If RX_NewDataFlag = False Then
lblStatus.Text = "Printer Error, no reply (check connection)"
lblStatus.Visible = True
Else
lblStatus.Text = "Printer Connected, Status = 0x" & RX_data_byte
lblStatus.Visible = True
End If
End Sub
I am having trouble with this because it seems that the sequence of events that occur is wrong:
From the Log: (I am running in release mode on some cheap 7" tablet, with B4A bridge & #BridgeLogger: True for logging)
B4X:
Button2 - about to call escpos_getstatus
Button2 - started rx timer
escpos_getstatus - enter
escpos_getstatus - exit
RxTimer tick!
RxTimer tick!
RxTimer tick!
RxTimer tick!
Button2 - RXNewDataFlag = false
NewData Data Length: 1 <<< AStreams1_NewData now runs!
RECEIVE (Hex): 16
It seems that _NewData runs AFTER Button2_Click code is finished?!
If the _Tick code runs as expected why not _NewData?
Further questions:
1. When does a Timer _Tick or Astreams _NewData event actually run? Anywhere in the middle of another sub's code or ONLY AFTER the sub code has finished?
(if you are familiar with embedded programming like Arduino you know that an Interrupt can occur anytime and the interrupt code will run after each instruction is complete). So I was hoping that B4A would be the same way. However from looking at Log messages it appears that event code only executes after the currently executed sub or event code is done - is this true?
2. Does Astreams _NewData event have the same priority as other events (e.g. Timer _Tick)? The problem is the _NewData event code is running later than it should so the RX_NewDataFlag doesn't get changed to True before the check.
Why is _NewData not running when it should?
How can I make the _NewData a higher priority event so it occurs sooner? (Do I need to move _NewData to starter service? Will it have higher priority)
3. How the the internal B4A messaging system work? Is there anything like DoEvents to get the _NewData code to run sooner?
4. Is there a B4A wiki? (apart from the tutorials/beginner's guide/user's guide). While the forum is helpful a properly organized wiki would be wonderful to have.
Apologies if I have missed something here. I have spent 2 days on this and am a little frustrated!
Thanks for reading, hope someone can help!