Hi guys, need some advice here. This code works perfectly as far as I can tell, but despite hours of research and trials I have not succeeded in creating that special event
SerialController.DataAvailable:
Sub DataAvailable()
' This event is fired when data is available. The messages we are waiting for comes in bits & pieces,
' at random times and in random sizes, only the order of the bits is correct...
' This event may fire at very short intervals, in principal once for every byte, or in bursts of a few bytes,
' Eg. at 19200 Baud there could be as little as 1/19200 Sec (52uS) between events.
' We must be outta here before the next event fires, or there will be trouble. (that's what we believe).
' We want to spend an ABSOLUTE MINIMUM of time here!
' If lengthy message processing takes place then multiple messages may have cued up in the serial buffer,
' but that is no problem, we get them all one-by-one in chronological order (FIFO)
' Message format:
' [:] [2-byte FrameNumber] [4-byte EncryptionKey] [4-byte Address] [4-64 bytes Payload] [2-byte CRC16] [CR]
'
'Dim i As Integer = Me.LookAhead.InStr(Chr( 13)) 'Position of EndOfMessage
If i > 0 Then 'There is at least one complete message (left) in the serial buffer
NewSerialMessage = Me.Read(i)'Read message and it's CR out of serial buffer
NewSerialMessage = Left(NewSerialMessage, NewSerialMessage.Len - 1) ' Remove the CR from message
'we can not call a lengthy method from here, instead trigger an event to execute the code, then get out:
'RaiseEvent(NewSerialMessage) XXXXXX ??
End If
End Sub
Dont try & handle the message at the end of the receipt of the data (ie/ DONT raise an event there)
Add the message to a queue (an array that you append to but only ever remove from the front) that is handled by a timer etc
That keeps your receipt of data fast and messages are handled in order
The queue can be examined by a timer etc that has a low period
But as Norman points out, this may be the wrong approach. The new event will run in line with the DataAvailable event (ie., it doesn’t return until it is finished, so the DataAvailable event doesn’t return until the new event is finished, which means the entire app waits for the processing of the new event to complete). If processing a message will take any appreciable time, spin it off into a queue that is processed by a timer or thread.
When you add an event definition like this it means either a subclass, instance or a method added via add handler WILL be run right then
Its not magic
And that WILL mean that handling data will NOT be “as fast as possible”
It will be as fast as your event handling code is
And that CAN be a problem when/if you have a lot of data to deal with that comes in rapidly
This is why I suggested adding a “queue” (really an array that you add complete messages to)
You Append new ones to the end and only ever read from the first item - item 0
In fact a simple subclass of Serial can be used to do this
something like this
Class MyNewSerial
Inherits Serial
private msgQueue() as String
private myTimer as Timer
EventDef HandleMessage( message as String )
Sub Open()
myTimer = new Timer
AddHandler mytimer.action, addressOf TimerHandler
myTimer.period = 5
myTimer.Mode = timer.ModeMultiple
End
Sub Close
myTimer.Mode = timer.ModeOff
RemoveHandler mytimer.action, addressOf TimerHandler
End
Sub TimerHandler( obj as Timer)
if msgQue.Ubound > 0 then
dim tmp as string = msgQueue(0)
msgQueue.Remove 0
// NOW RAISE AN EVENT AS YOUR NOT IN YOUR DATA RECEIVED EVENT !!!!!!
HandleMessage( tmp )
end if
End
Sub DataAvailable()
' This event is fired when data is available. The messages we are waiting for comes in bits & pieces,
' at random times and in random sizes, only the order of the bits is correct...
' This event may fire at very short intervals, in principal once for every byte, or in bursts of a few bytes,
' Eg. at 19200 Baud there could be as little as 1/19200 Sec (52uS) between events.
' We must be outta here before the next event fires, or there will be trouble. (that's what we believe).
' We want to spend an ABSOLUTE MINIMUM of time here!
' If lengthy message processing takes place then multiple messages may have cued up in the serial buffer,
' but that is no problem, we get them all one-by-one in chronological order (FIFO)
' Message format:
' [:] [2-byte FrameNumber] [4-byte EncryptionKey] [4-byte Address] [4-64 bytes Payload] [2-byte CRC16] [CR]
'
'Dim i As Integer = Me.LookAhead.InStr(Chr( 13)) 'Position of EndOfMessage
If i > 0 Then 'There is at least one complete message (left) in the serial buffer
NewSerialMessage = Me.Read(i)'Read message and it's CR out of serial buffer
NewSerialMessage = Left(NewSerialMessage, NewSerialMessage.Len - 1) ' Remove the CR from message
'we can not call a lengthy method from here, instead trigger an event to execute the code, then get out:
msgQueue.append newSerialMessage
End If
End Sub
End Class
But as Norman points out, this may be the wrong approach. The new event will run in line with the DataAvailable event (ie., it doesn’t return until it is finished, so the DataAvailable event doesn’t return until the new event is finished, which means the entire app waits for the processing of the new event to complete). If processing a message will take any appreciable time, spin it off into a queue that is processed by a timer or thread.[/quote]
Ok… I figured that as soon as I’ve left the DataAvailable event it would be free to fire again without trouble, even if I’m fully occupied in that new event… This is not correct ?
I would say its important you read the various documentation about how Xojo and its event system works so you dont assume the wrong things - which you seem to be doing in this case
Ok, I’ll test your FIFO buffer approach.
I’m a XOJO NUB, more used to low level embedded/MCU where events (interrupts) may come
in parallel like a hail storm from different sources
Events are definitely not the equivalent of interrupts
And there’s no built in mechanism that queues them
The OS may queue up things like keypresses & mouse moves but that the OS doing it - not Xojo’s runtime