Creating a timer using Lua - timer

I would like to create a timer using Lua, in a way that I could specify a callback function to be triggered after X seconds have passed.
What would be the best way to achieve this? ( I need to download some data from a webserver that will be parsed once or twice an hour )
Cheers.

If milisecond accuracy is not needed, you could just go for a coroutine solution, which you resume periodically, like at the end of your main loop, Like this:
require 'socket' -- for having a sleep function ( could also use os.execute(sleep 10))
timer = function (time)
local init = os.time()
local diff=os.difftime(os.time(),init)
while diff<time do
coroutine.yield(diff)
diff=os.difftime(os.time(),init)
end
print( 'Timer timed out at '..time..' seconds!')
end
co=coroutine.create(timer)
coroutine.resume(co,30) -- timer starts here!
while coroutine.status(co)~="dead" do
print("time passed",select(2,coroutine.resume(co)))
print('',coroutine.status(co))
socket.sleep(5)
end
This uses the sleep function in LuaSocket, you could use any other of the alternatives suggested on the Lua-users Wiki

Try lalarm, here:
http://www.tecgraf.puc-rio.br/~lhf/ftp/lua/
Example (based on src/test.lua):
-- alarm([secs,[func]])
alarm(1, function() print(2) end); print(1)
Output:
1
2

If it's acceptable for you, you can try LuaNode. The following code sets a timer:
setInterval(function()
console.log("I run once a minute")
end, 60000)
process:loop()

use Script.SetTimer(interval, callbackFunction)

After reading this thread and others I decided to go with Luv lib. Here is my solution:
uv = require('luv') --luarocks install luv
function set_timeout(timeout, callback)
local timer = uv.new_timer()
local function ontimeout()
uv.timer_stop(timer)
uv.close(timer)
callback()
end
uv.timer_start(timer, timeout, 0, ontimeout)
return timer
end
set_timeout(1000, function() print('ok') end) -- time in ms
uv.run() --it will hold at this point until every timer have finished

On my Debian I've install lua-lgi packet to get access to the GObject based libraries.
The following code show you an usage demonstrating that you can use few asynchronuous callbacks:
local lgi = require 'lgi'
local GLib = lgi.GLib
-- Get the main loop object that handles all the events
local main_loop = GLib.MainLoop()
cnt = 0
function tictac()
cnt = cnt + 1
print("tic")
-- This callback will be called until the condition is true
return cnt < 10
end
-- Call tictac function every 2 senconds
GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, 2, tictac)
-- You can also use an anonymous function like that
GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, 1,
function()
print( "There have been ", cnt, "tic")
-- This callback will never stop
return true
end)
-- Once everything is setup, you can start the main loop
main_loop:run()
-- Next instructions will be still interpreted
print("Main loop is running")
You can find more documentation about LGI here

Related

knife.timer on Lua syntax - not behaving as expected

If anyone is familiar with knife.timer on Lua, could you please look at my code and tell me what I have out of order?
I'm hoping to do two things:
have a countdown timer that ticks down every second and
have a timer that after six seconds begins blinking my characters for 3 more seconds before changing state.
With the following code, my countdown timer starts at 9 but gets well into the negative tens. My characters begin to blink after what feels like 4 seconds, and continue blinking for a few seconds after changing state.
I have Timer:update(dt) in main, so I'm not sure why the timing is off. And I thought the finish would not call the change state function until the characters' 16 iterations of blinking were done.
function PlayerPilotState:update(dt)
self.player.currentAnimation:update(dt)
Timer.every(1, function()
self.timer = self.timer - 1
end)
Timer.after(6, function()
Timer.every(0.2, function()
self.player.blinking = not self.player.blinking
self.player.otherPlayer.blinking = not self.player.otherPlayer.blinking
end):finish(function()
self.player:changeState('falling')
self.player.otherPlayer:changeState('falling')
end):limit(16)
end)
end
Thanks!
With the basic countdown timer, you never specify when it should stop. Try using :limit(9) or self.timer = math.max(0,self.timer - 1)
2.Have you timed it properly (it's hard to feel how much time has passed), since you use Timer.after. The :finish() function happens inside the :after(), and after the :every(), which could cause things to be weird. I suggest adding the :limit before the :finish().
Timer.after(6, function()
Timer.every(0.2, function()
self.player.blinking = not self.player.blinking
self.player.otherPlayer.blinking = not self.player.otherPlayer.blinking
end):limit(16):finish(function()
self.player:changeState('falling')
self.player.otherPlayer:changeState('falling')
end)
end)
Both of the above comments were extremely useful. It turns out that putting timers under update is a bad idea because they either are calling new timers or refreshing strangely. What I ended up with, and works perfectly is:
function PlayerPilotState:enter(params)
Timer.every(1, function()
self.timer = self.timer - 1
end)
Timer.after(6, function()
Timer.every(0.2, function()
self.player.blinking = not self.player.blinking
self.player.otherPlayer.blinking = not self.player.otherPlayer.blinking
end)
:limit(15)
:finish(function()
self.player.blinking = false
self.player.otherPlayer.blinking = false
self.player:changeState('falling')
self.player.otherPlayer:changeState('falling')
end)
end)
end
A follow up question I would have, is how to do this without using an enter function? I guess any function call that called only once (with maybe a boolean flag to call it) would work. Thanks!

lua timing sound files

I'm a musician attempting to write a music reading programme for guitarists.
I want to time two consecutive sounds so that the first stops when the second begins. Each should last a predetermined duration (defined in this example as 72 in 60000/72). As a beginner coder I'm struggling and would really appreciate any help.
-- AUDIO 1 --
local aa = audio.loadStream(sounds/chord1.mp3)
audio.play(aa)
-- TIMER 1 --
local timeLimit = 1
local function timerDown()
timeLimit = timeLimit-1
if(timeLimit==0)then
end
end
timer.performWithDelay( 60000/72, timerDown, timeLimit )
-- TIMER 2 --
local timeLimit = 1
local function timerDown()
timeLimit = timeLimit-1
if(timeLimit==0)then
-- AUDIO 2 --
local aa = audio.loadStream(sounds/chord2.mp3])
audio.play(aa)
end
end
timer.performWithDelay( 60000/72, timerDown, timeLimit )
There are a few things to note here. Sorry for the wall of text!
Strings (text)
Must be enclosed in quotes.
local aa = audio.loadStream(sounds/chord1.mp3)
becomes:
local aa = audio.loadStream('sounds/chord1.mp3')
Magic numbers
Values which aren't explained anywhere should be avoided. They make code harder to understand and harder to maintain or modify.
timer.performWithDelay(60000/72, timerDown, timeLimit)
becomes:
-- Might be slight overkill but hopefully you get the idea!
local beatsToPlay = 10
local beatsPerMinute = 72
local millisPerMinute = 60 * 1000
local playTimeMinutes = beatsToPlay / beatsPerMinute
local playTimeMillis = playTimeMinutes * millisPerMinute
timer.performWithDelay(playTimeMillis, timerDown, timeLimit)
Corona API
It is an invaluable skill when programming to be able to read and understand documentation. Corona's API is documented here.
audio.loadStream()'s docs tell you that it returns an audio handle which you can use to play sounds which is what you've got already. It also reminds you that you should dispose of the handle when you are done so you'll need to add that in.
timer.performWithDelay()'s docs tell you that it needs the delay time in milliseconds and a listener which is what will be activated at that time, so you will need to write a listener of some description. If you follow the link to listener or if you look at the examples further down the page then you'll see that a simple function will suffice.
audio.play() is fine as it is but if you read the docs then it informs you of some more functionality which you could use to your advantage. Namely the options parameter, which includes duration and onComplete. duration is how long - in millis - to play the sound. onComplete is a listener which will be triggered when the sound has finished playing.
The result
Using timers only:
local function playAndQueue(handle, playTime, queuedHandle, queuedPlayTime)
audio.play(handle, { duration = playTime })
timer.performWithDelay(playTime, function(event)
audio.dispose(handle)
audio.play(queuedHandle, { duration = queuedPlayTime })
end)
timer.performWithDelay(playTime + queuedPlayTime, function(event)
audio.dispose(queuedHandle)
end)
end
local audioHandle1 = audio.loadStream('sounds/chord1.mp3')
local audioHandle2 = audio.loadStream('sounds/chord2.mp3')
local beatsToPlay = 10
local beatsPerMinute = 72
local millisPerMinute = 60 * 1000
local playTimeMinutes = beatsToPlay / beatsPerMinute
local playTimeMillis = playTimeMinutes * millisPerMinute
playAndQueue(audioHandle1, playTimeMillis, audioHandle2, playTimeMillis)
Using onComplete:
local function playAndQueue(handle, playTime, queuedHandle, queuedPlayTime)
-- Before we can set the 1st audio playing we have to define what happens
-- when it is done (disposes self and starts the 2nd audio).
-- Before we can start the 2nd audio we have to define what happens when
-- it is done (disposes of the 2nd audio handle)
local queuedCallback = function(event)
audio.dispose(queuedHandle)
end
local callback = function(event)
audio.dispose(handle)
local queuedOpts = {
duration = queuedPlayTime,
onComplete = queuedCallback
}
audio.play(queuedHandle, queuedOpts)
end
local opts = {
duration = playTime,
onComplete = callback
}
audio.play(handle, opts)
end
local audioHandle1 = audio.loadStream('sounds/chord1.mp3')
local audioHandle2 = audio.loadStream('sounds/chord2.mp3')
local beatsToPlay = 10
local beatsPerMinute = 72
local millisPerMinute = 60 * 1000
local playTimeMinutes = beatsToPlay / beatsPerMinute
local playTimeMillis = playTimeMinutes * millisPerMinute
playAndQueue(audioHandle1, playTimeMillis, audioHandle2, playTimeMillis)
You might find that using onComplete works out better than pure timers since you might end up disposing the audio handle just before is is done being used for playback (and causing errors). I haven't had any experience with Corona so I'm not sure how robust its timer or audio libraries are.

lua synchronous call C asynchronous function

c call lua with the following code
if ( lua_pcallk(L, 0, LUA_MULTRET, 0, ctx, pcallk_continue) != 0 )
{}
the lua code is
local coroutine = coroutine
co = coroutine.create( function (...)
c.call(...)
-- [run here]
end )
c.call() is an asynchronous c function(it call lua_yieldk() at the end of the function, util the network recv the data and call lua_resume() )
return lua_yieldk(L, 0, 0, yield_continue);
it run to yield_continue function, but not run to the line of "[run here]", why?
the reference URL: http://www.lua.org/manual/5.2/manual.html#4.7
This is main idea with dispatcher.
Worker thread start async operation and switch to dispatcher thread.
Dispatcher thread polls async operations and when they done switch to
worker thread.
-- basic async operation queue
local ASYNC_RECV = {}
-- Put operation to queue and wait
local function recv()
local co = coroutine.running()
-- here we start async operation
ASYNC_RECV[co] = true
-- here we switch to dispatcher
return coroutine.yield()
end
coroutine.wrap(function()
for i = 1, 10 do print(recv()) end
end)()
-- main Loop
-- here we poll all async operation and
-- resume according coroutines
while true do
-- we have no async operation
if not next(ASYNC_RECV) then break end
for co in pairs(ASYNC_RECV) do
ASYNC_RECV[co] = nil -- mark operation is done
coroutine.resume(co, "some string") -- send result to coroutine
end
end
And here work example with libuv as dispatcher
local uv = require "lluv"
local function sleep(timeout)
local co = coroutine.running()
-- here we start async operation
uv.timer():start(timeout, function(timer)
timer:close() -- just close unused timer.
-- dispatcher(libuv) call this callback and
-- callback switch to coroutine
coroutine.resume(co)
end)
coroutine.yield()
end
coroutine.wrap(function()
for i = 1, 10 do
print("Tick")
sleep(1000)
end
end)()
uv.run()

How to run a function during a limited time?

I've a function and would like to call here each 2 seconds during 3 seconds.
I tried timer.performwithDelay() but it doesn't answer to my question.
Here is the function I want to call each 2 secondes during 3 seconds :
function FuelManage(event)
if lives > 0 and pressed==true then
lifeBar[lives].isVisible=false
lives = lives - 1
-- print( lifeBar[lives].x )
livesValue.text = string.format("%d", lives)
end
end
How can I use timer.performwithDelay(2000, callback, 1) to call my function FuelManage(event) ?
So it looks like what you are actually after is to start a few check 2 seconds from "now", for a duration of 3 seconds. You can schedule registering and unregistering for the enterFrame events. Using this will call your FuelManage function every time step during the period of interest:
function cancelCheckFuel(event)
Runtime:removeListener('enterFrame', FuelManager)
end
function FuelManage(event)
if lives > 0 and pressed==true then
lifeBar[lives].isVisible=false
lives = lives - 1
-- print( lifeBar[lives].x )
livesValue.text = string.format("%d", lives)
end
end
-- fuel management:
local startFuelCheckMS = 2000 -- start checking for fuel in 2 seconds
local fuelCheckDurationMS = 3000 -- check for 3 seconds
local stopFuelCheckMS = startFuelCheckMS + fuelCheckDurationMS
timer.performWithDelay(
startFuelCheckMS,
function() Runtime:addEventListener('enterFrame', FuelManager) end,
1)
timer.performWithDelay(
stopFuelCheckMS,
function() Runtime:removeEventListener('enterFrame', FuelManager) end,
1)
If this is too high frequency, then you'll want to use a timer, and keep track of time:
local fuelCheckDurationMS = 3000 -- check for 3 seconds
local timeBetweenChecksMS = 200 -- check every 200 ms
local totalCheckTimeMS = 0
local startedChecking = false
function FuelManage(event)
if lives > 0 and pressed==true then
lifeBar[lives].isVisible=false
lives = lives - 1
-- print( lifeBar[lives].x )
livesValue.text = string.format("%d", lives)
end
if totalCheckTimeMS < 3000 then
timer.performWithDelay(timeBetweenChecksMS, FuelManage, 1)
if startedChecking then
totalCheckTimeMS = totalCheckTimeMS + timeBetweenChecksMS
end
startedChecking = true
end
end
-- fuel management:
local startFuelCheckMS = 2000 -- start checking for fuel in 2 seconds
timer.performWithDelay(startFuelCheckMS, FuelManage, 1)
Set a timer inside a timer like this:
function FuelManage(event)
if lives > 0 and pressed==true then
lifeBar[lives].isVisible=false
lives = lives - 1
-- print( lifeBar[lives].x )
livesValue.text = string.format("%d", lives)
end
end
-- Main timer, called every 2 seconds
timer.performwithDelay(2000, function()
-- Sub-timer, called every second for 3 seconds
timer.performwithDelay(1000, FuelManage, 3)
end, 1)
Be careful though because the way it's setup know you will have an infinite number of timer running very soon... Since the first timer has a lower lifetime than the second one. So you might think if you would like to secure the second timer by making sure it's cancelled first before calling it again, this kind of thing.

Construct dynamic timer with lua

I have created a timer called "timer", but I'm trying to create a function that will arm or disarm timer which is specified in it parameters
timer = sys.timer.create()
function MainTimer(timerName, action, time)
if action == "arm" then
timerName:arm(time)
else
timerName:disarm()
end
end
MainTimer("timer", "arm", 30)
but I'm getting an error from lua saying lua:272: attempt to call method 'arm' (a nil value)
where you think I did a mistake.
Thank you
Extra quotes :-)
MainTimer(timer, "arm", 30)

Resources