how to do some processing at set time intervals

BlitzMax Forums/BlitzMax Programming/how to do some processing at set time intervals

Robo(Posted 2008) [#1]
I would like to know in blitz basic (bearing in mind i am new to this software) if there is a way (with an example, which would be nice) of calling a routine at a pre-determined interval.

In Liberty basic, this is so so easy, you just use

timer 1000, [subroutine]

where 1000 is 1000 milliseconds (or 1 second)

is it simialr in blitz basic ? I really want to use blitz because it seems much more powerful than liberty basic.


Brucey(Posted 2008) [#2]
There's BRL.Timer.


... there's also wx.wxTimer ;-)


Dreamora(Posted 2008) [#3]
real timers and event hooks.
But beside that no. Above feature looks like a scripting feature, not a feature of a binary code compiled language.


tonyg(Posted 2008) [#4]
SuperStrict
Const TICK_EVENT:Int=69
Function test_function:Object( id:Int,data:Object,context:Object )
	Local ev:TEvent=TEvent(data)
	
      Select ev.id
            Case TICK_EVENT
               Print "Hello World!"
      End Select

End Function
Local MY_EVENT:TEvent=CreateEvent(TICK_EVENT)
Local myTimer:TTImer = CreateTimer(1,MY_EVENT)
'Add our hook to the system
AddHook EmitEventHook,test_function
While EventID() <> EVENT_KEYDOWN
	PollEvent
EndWhile

although BRL have said CreateEvent should really be internal use only.
Not too friendly but does the job... I think.


GfK(Posted 2008) [#5]
Or a more noob-coder-friendly way:
Local myTimer:TTimer = CreateTimer(1)

While (Not KeyDown(KEY_ESCAPE)) And (Not AppTerminate())
	If myTimer.Ticks()
		Print "Timer ticked at " + MilliSecs() + " ms!"
		myTimer._Ticks = 0'reset timer tick counter
	EndIf
	Delay 1
Wend



Beaker(Posted 2008) [#6]
[Oops: doesn't seem to work anymore.]
Or try this: Interval system


Dreamora(Posted 2008) [#7]
they are all together as useless as they look like due to the restriction on the amount of timers BM will allow you.

You better do a virtual timer system with timed "callbacks" handler object that measures millisecs differences and calls the function (or through reflection as well method) after the given time and removing itself.


tonyg(Posted 2008) [#8]
@GfK, yep certainly easier but not as 'fire-and-forget'.
@Dreamora, all the suggestions answer the question so are not exactly 'useless'. I'd certainly like to see the method you're proposing so an example would be nice.


Brucey(Posted 2008) [#9]
A timer with timed "callbacks" measured in millisecs (of 100 in this case).

SuperStrict

Framework wx.wxApp
Import wx.wxTimer
Import BRL.StandardIO

Type MyApp Extends wxApp

	Field timer:MyTimer

	Method OnInit:Int()

		timer = MyTimer(New MyTimer.Create())
		timer.Start(100)
	
		Return True
	
	End Method

End Type

Type MyTimer Extends wxTimer

	Field count:Int

	Method Notify()	
		count:+1
		
		Print "Tick (" + count + ")"
		
		If count = 50 Then
			End
		End If
		
	End Method

End Type

New MyApp.run()


This is only one way of using wxTimer, of course.


Dreamora(Posted 2008) [#10]
SuperStrict

Import Datastruct.PriorityQueue

Type TVirtualThread
  field nextExecution:int
  field functionToCall(data:object)
  field data:object

  global prioQueue:TPriorityQueue = TPriorityQueue.Create()
  global lastCheck:int
  function create:TVirtualThread(functionToCall(data:object), data:object, timeToWait:int)
    local result:TVirtualThread = new TVirtualThread
    result.nextExecution = millisecs() + timeToWait
    result.functionToCall = functionToCall
    result.data = data
  end function

  function updateExecution()
    if millisecs() - lastCheck < 1 return
    local curTime:int = millisecs()
    local thread:TVirtualThread = TVirtualThread(prioQueue.top())
    while thread.nextExecution < curTime
      thread.functionToCall(thread.data)
      prioQueue.pop()
      thread = TVirtualThread(prioQueue.top()) 
    wend
  end function
end type



Datastruct PriorityQueue is a module I wrote myself. It is a high performant priorityqueue implemented with a heap under the hood

The code is not tested but should you give an idea of how to do it.

With Reflection you could even do objects with method calls using invoke.

The only thing you need to do is call TVirtualThread.updateExecution() in your mainloop (using a 1000 hz timer would be kind of worthless I feel)


TomToad(Posted 2008) [#11]
if your function doesn't need to be called at exact to the millisecond precision, you could just check the millisecs() timer in your main loop and call the routine from there.
Local Time:int = Millisecs() + 1000 ' one second later

While Not KeyHit(KEY_ESCAPE)
   If Millisecs() >= Time 'Check if second is up
      Time :+ 1000 'add another second to time
      DoFunction()
   End If
Wend



ImaginaryHuman(Posted 2008) [#12]
What I did, which only really works if you are running scripts and not normal code, is to do a multitasking scheduler like an o/s would do it, which gets called approximately every millisecond (which depends on execution times) to check that any high-priority scripts get to pre-empt other scripts. Works great for me but again I am actively going and checking on the time which is not the ideal scenario. But then again, the only way to do that properly is to have the hardware force something to happen, like an exception or interrupt which calls upon some kind of interrupt processor code that was pre-installed at a fixed memory address, but at least then this would totally pre-empt everything and tell you the timer ticked exactly when it did.


Czar Flavius(Posted 2008) [#13]
Poor Robo. His head is going to hurt so much. I suggest TomToad's as an easy to understand solution.


Dreamora(Posted 2008) [#14]
Problem is, tom toads isn't flexible. you can not just run any potential function at a later time ... only hardcoded ones at a given time. It is normally called "Timed Code Execution" and is used for physics updates, network updates and the like. Things that repeatively executed at a given frequency.

Not flexible timed, single time function execution.


Czar Flavius(Posted 2008) [#15]
Did you check your requirements, or respond to the requirements you wanted there to be :)

(bearing in mind i am new to this software)


Even I don't understand half the stuff in this post without thinking about it, and I wouldn't consider myself a beginner.


TomToad(Posted 2008) [#16]
@Dreamora: You're right that my method is not flexible, and the timing can vary a few milliseconds each call. But Robo asked how to call a function, not any potential function, and he did not specify how accurate he needed the timing to be.

My way works and is simple, and there is no reason to use a bulldozer to do a shovel's job. If my way suits him, he can use it. If he needs more flexibility, or doesn't like my method for some reason, then he can choose from other methods that have been posted.


Dreamora(Posted 2008) [#17]
Well the type of thing he asked remembers very much of asyncronous function call not "timed repetitive execution" thats why I put mine up.

For timed repetitive yours is definitely better.

But to have a single time execution at a later time of potentially any function like in his example ([subroutine] means any potential, not a single one over and over again), I assume you agree that it replicates the asked feature more suitable.

Both definitely a great technics and should be used together to suite all siutations at with the best approach