Timer within a timer

Hi - I’m new to Xojo and still getting my feet wet, though I have several years of programming experience in C++ and assembly.

For a project I’m working on I want to have Timer scanning the serial ports for a particular connected device, then a second timer that gets kicked off after sending a query on each port that acts as a timeout while waiting for a response.

The first timer’s working fine, as are the serial connections, but for some reason the second timer is not. (That is - the second timer works when enabled directly, but when enabling from within the first timer it never seems to trigger). Here’s a simplified loop that’s inside the Action event handler of the first timer:


responseTimer.Mode = Timer.ModeSingle
Loop until timerDone

In the Action event handler for responseTimer I set

Any idea why responseTimer is never getting triggered?

Remove your Do…Loop Until loop altogether. Set your responseTimer mode then call your TextArea1.AppendText(“End”+Chr(13)) from the Action Event of the timer. Don’t use “timerDone” at all. You are confusing the issue with too many loops.

Also, better to use Xojo’s “endOfLine” than rely on Chr(13) to be valid on all platforms

Also, Timers are not Threads, they always fire on the main thread during idle time.

Timer action events are executed one at a time on the same thread, meaning the second Timer must wait for the first Timer to fully exit its Action event.

[quote=412545:@Jesse Rosen]Do
Loop until timerDone[/quote]
While the first timer’s action event is looping, it blocks all other system and UI. No other Timer can fire, no mouse clicks can be responded to, no keyboard entry, etc.

Thanks for the replies - I’ve got a better sense of how the timer is implemented now. So I think I’ve got a way that works for my current project. But in general is there a good pattern in Xojo for doing synchronous communication over a serial port with a timeout in the case of a break in communication?

Here’s how I’d do it:

Subclass the Serial for your device and add a Timeout property as Integer with a default that makes sense. Add a Timer property that gets initialized in the Constructor with an AddHandler, and torn down in the Destructor.

Override the Write method to start the Timer after super.Write and the DataAvailable event to stop the Timer when appropriate (the incoming data is complete). The Timer itself will raise a TimedOut event if allowed to fire.

Some untested code:

MyDevice As Serial

Property Timeout As Integer = 10
Private Property TimeoutTimer As Timer

Event DataAvailable()
Event TimedOut()

Sub Constructor()
  TimeoutTimer = new Timer
  TimeoutTimer.Mode = 0
  AddHandler TimeoutTimer.Action, WeakAddressOf TimeoutTimer_Action
End Sub

Sub Destructor()
  if TimeoutTimer isa object then
    TimeoutTimer.Mode = 0
    RemoveHandler TimeoutTimer.Action, WeakAddressOf TimeoutTimer_Action
    TimeoutTimer = nil
  end if
End Sub

Sub TimeoutTimer_Action (sender As Timer)
  #pragma unused sender

  RaiseEvent TimedOut
End Sub

Sub Write (data As String)
  super.Write( data )
  TimeoutTimer.Period = Timeout * 1000
  TimeoutTimer.Mode = 1
End Sub

On DataAvailable()
  // Check to make sure it's complete, then
  if itIsComplete then
    TimeoutTimer.Mode = 0
    RaiseEvent DataAvailable()
  end if

Is not a thing. Embrace async/event driven processing.

@Kem Tekinay Thanks- that helped a lot. (I’ve been busy with a hardware project and only got back to this today). I did something similar to what you suggested and it works. After spending much of the last decade writing embedded code in severely memory-constrained systems it’s taking a while to adjust to the paradigms of this kind of event-driven programming!