This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Creator13's profile picture

os.pullEvent in a loop

Started by Creator13, 03 August 2012 - 07:40 PM
Creator13 #1
Posted 03 August 2012 - 09:40 PM
I'm trying to make a program that controls a 7-segment counter. Now the counter part works, but I have lots of trouble with some fancy features like quitting the program or forcing the counter to restart. I tried to put an os.pullEvent() in the loop the counter also uses for changing and displaying the current number. That didn't really work.
I don't have the original code anymore, but i wrote another little test program to just figure out the best way to do it. I didn't found any.


os.pullEvent = os.pullEventRaw
function clear()
    term.clear()
    term.setCursorPos(1,1)
end
clear()
local i = 0
print("Press [q] to exit")
while true do
    print(i)
    i = i + 1
    event, param1 = os.pullEvent()
    if event == "char" and param1 == "q" or param1 == "Q" then
	    break
    else
    end
    sleep(1)
end
clear()
print "You stopped the program"

Now what code should do, but doesn't, is printing numbers, with a 1 second delay, counting up until q is pressed. Then it should print "you stopped the program". I'm sure this is a very simple question, but I'm still a newbie to Lua, so please help me…
Luanub #2
Posted 03 August 2012 - 10:01 PM
The best thing to do would be to try and use the parallel API.

The code would look something like this.


local function timer()
-- put your timer code here
end

local function stop()
--exit code here
end

while true do
parallel.waitForAny( timer, stop)
end

Hope this helps. I'll play with it some and try to get you a better example.
PixelToast #3
Posted 03 August 2012 - 10:04 PM
-snip-
MysticT #4
Posted 03 August 2012 - 10:06 PM
The problem is that os.pullEvent will wait until there's an event (a key press, rednet message, etc.). You can use a timer instead of sleep to draw the counter:

local function clear()
  term.clear()
  term.setCursorPos(1, 1)
end

local i = 0
local timer = os.startTimer(1)

clear()
print("Press [q] to exit")
while true do
  local evt, arg = os.pullEvent()
  if evt == "timer" then
    if arg == timer then
	  i = i + 1
	  print(i)
    end
  elseif evt == "char" then
    if arg == "q" or arg == "Q" then
	  break
    end
  end
end
clear()
print("You stopped the program")

if event == "char" and param1 == "q" or param1 == "Q" then
break
else
param1 isnt a string, its a number that represents the key that your pressing
you can use the keys api to easialy find the number or you can use this guide:
http://www.minecraft.../wiki/Key_codes
That's for "key" events, not "char".
Luanub #5
Posted 03 August 2012 - 10:10 PM
Yea don't try and use the parallel, it does not work for this. MysticT's way is the best solution for your issue.
Creator13 #6
Posted 05 August 2012 - 09:54 AM
I tested MysticT's code (I only edited the name of some of the variables), and it still doesn't work right. When I start the program, it says "Press [q] to continue" and after one second, "1" appears. Then it stops counting. But I can quit the program by pressing "q".
Luanub #7
Posted 05 August 2012 - 11:01 AM
Move this line into the while true loop. The timer is only getting started once.


local timer = os.startTimer(1)
Edited on 05 August 2012 - 09:03 AM
Creator13 #8
Posted 05 August 2012 - 11:16 AM
How do I implement a restart function in this?
I already edited the code, but if I press "r" it stops counting, but doesn't stop the program, and I can quit again with "q":


local function clear()
    term.clear()
    term.setCursorPos(1, 1)
end
local i = 0
clear()
print("Press [q] to exit, [r] to restart")
while true do
    local timer = os.startTimer(1)
    local event, param1 = os.pullEvent()
    if event == "timer" then
	    if param1 == timer then
		    i = i + 1
		    print(i)
	    end
    elseif event == "char" then
	    if param1 == "q" or param1 == "Q" then
		    break
	    end
    elseif event == "char" then
	    if param1 == "r" or param1 == "R" then
		    i = 0
	    end
    end
end
print("You stopped the program")
Luanub #9
Posted 05 August 2012 - 11:51 AM
You can get that to work by removing the verification if statement "if param1 == timer" and just do the math and print. However I would advise against it your clock will become out of time and the ticks will be much less then 1 second. The timer that was running will keep running even though you press R so you will end up with more then 1 timer running at a time.

If you do it, maybe add a short sleep to allow the first timer to complete. That may keep it semi accurate.
Creator13 #10
Posted 05 August 2012 - 01:20 PM
isn't there another way to do it? The problem is that the counter must run at exactly 1 second delay.
MysticT #11
Posted 05 August 2012 - 04:14 PM
I forgot to restart the timer, this should work:

local function clear()
  term.clear()
  term.setCursorPos(1, 1)
end

local i = 0
local timer = os.startTimer(1)

clear()
print("Press [q] to exit")
while true do
  local evt, arg = os.pullEvent()
  if evt == "timer" then
	if arg == timer then
	  i = i + 1
	  print(i)
	  timer = os.startTimer(1)
	end
  elseif evt == "char" then
    local c = string.lower(arg)
	if arg == "q" then
	  break
    elseif arg == "r" then
	  i = 0
	end
  end
end
clear()
print("You stopped the program")
I also added the reset function.
Creator13 #12
Posted 05 August 2012 - 06:58 PM
This code doesn't work too. Only if I press a random key, it counts. "q" And "r" just don't work (they act like all other keys). I tried cut the first timer and replaced the second with the first, but then it doesn't count, but I cab terminate it with "q". I can't see if "r" works.
MysticT #13
Posted 05 August 2012 - 09:23 PM
Derp. I forgot to change the ifs to use the lowercase variable. Change this part:

local c = string.lower(arg)
if arg == "q" then
  break
elseif arg == "r" then
  i = 0
end
To this:

local c = string.lower(arg)
if c == "q" then
  break
elseif c == "r" then
  i = 0
end
It should work (although it should work like it was before, just not if you press Q or R instead of q and r).
Luanub #14
Posted 05 August 2012 - 10:49 PM
Yeah its still not going to work right. For 1 the code to restart the timer is inside the if event == timer statement. Therefor it needs a timer to go off before it will start one and if you press a key there is no timer running.

Try adding another os.startTimer(1) in the elseif c == "r" statement and see if that will do the trick.
MysticT #15
Posted 05 August 2012 - 10:55 PM
Yeah its still not going to work right. For 1 the code to restart the timer is inside the if event == timer statement. Therefor it needs a timer to go off before it will start one and if you press a key there is no timer running.

Try adding another os.startTimer(1) in the elseif c == "r" statement and see if that will do the trick.
Actually the timer is started in this line:

local timer = os.startTimer(1)
And then restarted every time it triggers:

if evt == "timer" then
  if arg == timer then
    i = i + 1
    print(i)
    timer = os.startTimer(1) -- restarts the timer
  end
end

I forgot to restart it when reseting the counter (when you press r). Just add the line:

timer = os.startTimer(1)
after:

elseif c == "r" then
  i = 0
Creator13 #16
Posted 06 August 2012 - 07:13 PM
Thanks, it finally works! I'll post the final code later, so that it is clear for everyone who had the same problem. (I also optimized a few things)

Edit:
This is the code:

os.pullEvent = os.pullEventRaw
local function clear()
    term.clear()
    term.setCursorPos(1, 1)
end
local i = 0
local timer = os.startTimer(1)
clear()
print("Press [q] to exit, [r] to restart")
while true do
    local evt, arg = os.pullEvent()
    if evt == "timer" then
	    if arg == timer then
		    i = i + 1
		    print(i)
		    timer = os.startTimer(1)
	    end
    elseif evt == "char" then
	    local c = string.lower(arg)
		    if c == "q" then
			    break
    elseif c == "r" then
		  clear()
		  print("Press [q] to exit, [r] to restart")
		  i = 0
		  timer = os.startTimer(1)
	    end
    end
end
clear()
print("You stopped the program")
Also, I'm wondering why I can't put "local" in front of this first line ("os.pullEvent = os.pullEventRaw") it gives this error:

bios:206: [string "test2"]:1: unexpected symbol