Create a custom event handler

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

Have you created the event definition in your subclass? Also the correct code to raise the event is RaiseEvent (NewSerialMessage).

what subclass? Do I have to subclass the serial controller ?

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

RaiseEvent  Untitled(NewSerialMessage)

Do at least compile, but I can’t add code to the event definition. Something else that need to be done?

Yes.

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

[quote=282303:@Tim Hare]Yes.

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 ?

The code called by Raise Event gets run - right then & there
ALL of it
And you dont leave the event until that code completes

So if that code is slow your data handling is slow and … well … problems

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