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

Help with timers

Started by thislooksfun, 22 May 2013 - 03:12 PM
thislooksfun #1
Posted 22 May 2013 - 05:12 PM
Hello! I am working on a program and I am trying to make it update every 5 seconds using a timer. My problem is that the timer ID returned by os.setTimer isn't the same as the timer ID returned by os.pullEvent("timer"). Does anyone know why? Everything else is working perfectly, I just can't figure out how to make this behave. Thanks in advance!

If you *need* to see the code, it's here. It is pretty big though, just FYI.
Spoiler

--[[Variables]]--
version = "v0.1"
subRouters = {}
subComputers = {}
master = "nil";
connected = false;
headerOnline = "Router "..version.." | This router is connected to #";
headerOffline = "Router "..version.." | This router is currently LAN only.";
header = headerOffline;
--[[Functions]]--
function isTable(var)
  if var[1] ~= nil then
	return true;
  else
	return false;
  end
end
function tryToConnect()
  if connected then
	message = "ping";
  else
	message = "CONNENT";
  end

  timeoutID = os.startTimer(.5);
  sendMessage(channels.connectionChannel, channels.connectionChannel, nil, message)

  local event, p1, p2, p3, p4, p5 = os.pullEvent();

  if event == "modem_message" then
  
	modemSide, senderChannel, replyChannel, message, senderDistance = p1, p2, p3, p4, p5;
  
	if senderChannel == channels.connectionChannel then
	  success, sender, to, messageString = deobf(message);
	  if success then
		if connected then
		  if messageString == "pong" then
			return true, sender;
		  end
		else
		  if messageString == "ACK" then
			sendMessage(channels.connectionChannel, channels.connectionChannel, nil, "RCONNECTED "..computerID);
			return true, sender;
		  end
		end
	  end
	end
  elseif event == "timer" and p1 == timeoutID then
	return false, "nil";
  end
end
function searchForComputer(computerID)
  for i = 1, #subComputers do
	if subComputers[i] == computerID then
	  return 1
	end
  end

  for i = 1, #subRouters do
	sendMessage(channels.computerSearchChannel, channels.computerSearchChannel, nil, computerID);
  end
end
function drawScreen()
  term.setCursorPos(1,1);
  term.clearLine();
  write(header);

  for i = 2, h do
	term.setCursorPos(1,i);
	if i == 2 or i == h then
	  for j = 1, w do
		if j == 1 or j == w then
		  write("+");
		else
		  write("-");
		end
	  end
	else
	  write("|");
	  term.setCursorPos(w,i);
	  write("|");
	end
  end

  term.setCursorPos(2,3);
end
function sendMessage(channel, replyChannel, to, message)
  message = {computerID, to, message};
  modem.transmit(channel, replyChannel, textutils.serialize(message));
end
function deobf(message)
  term.scroll(1);
  term.setCursorPos(2,h-1);
  term.clearLine()

  sucess, desearMessage = pcall(textutils.unserialize, message);

  if not pcall(isTable, desearMessage) then
	write("The message isn't a table");
	drawScreen()
	return false;
  else
	drawScreen()
	return true, desearMessage[1], desearMessage[2], desearMessage[3];
  end
end
function log(message)
  term.scroll(1);
  term.setCursorPos(2,h-1);
  term.clearLine()

  write("Forwarded message from computer #"..desearMessage[1].." to #"..master);
  drawScreen()
end

--[[Main Code]]--
connected, master = tryToConnect();
while true do
  if connected then
	header = headerOnline..master;
  else
	header = headerOffline;
  end
  timerID = os.startTimer(5);
  drawScreen();
  local event, p1, p2, p3, p4, p5 = os.pullEvent();

  if event == "modem_message" then

	modemSide, senderChannel, replyChannel, message, senderDistance = p1, p2, p3, p4, p5;
  
	success, sender, to, messageString = deobf(message);

	if success then
	  if senderChannel == channels.connectionChannel then
		request = messageString;
		if request == "CONNENT" then
		  sendMessage(channels.connectionChannel, channels.connectionChannel, sender, "ACK");
		elseif string.sub(request, 1, 10) == "CCONNECTID" and to == computerID then
		  table.insert(subComputers, #subComputers + 1, tonum(string.sub(request, 12)));
		elseif string.sub(request, 1, 10) == "RCONNECTID" and to == computerID then
		  table.insert(subRouters, #subRouters + 1, tonum(string.sub(request, 12)));
		elseif request == "ping" then
		  sendMessage(channels.connectionChannel, channels.connectionChannel, sender, "pong");
		end
	  else
		connected, master = tryToConnect();
		if senderChannel == channels.computerSearchChannel then
		  computerToFind = messageString;
		  searchForComputer(computerToFind);
		else
		  --Search for the computer ID under this router, if not found, forward the message to the next router up.
		  log(message);
		end
	  end
	end
  elseif event == "timer" and p1 == timerID then
	print("TimerID = "..timerID);
	print("p1 = "..p1);
	sleep(1);
	term.clear();
	connected, master = tryToConnect();
  end
end
BlankTitle #2
Posted 22 May 2013 - 05:42 PM
If you want to make it send a command every 5 seconds why not just do a repeat and sleep?

while true do
sleep(5)
--your code here
end
thislooksfun #3
Posted 22 May 2013 - 05:59 PM
If you want to make it send a command every 5 seconds why not just do a repeat and sleep?

while true do
sleep(5)
--your code here
end

I am trying to make a message relay so that you can send messages farther than the max range of a modem, and the timer is to check if it is still connected to another computer. I still need it to receive messages from other computers though, so I'm using a timer instead of a sleep.
thislooksfun #4
Posted 23 May 2013 - 08:01 AM
The part that isn't working is here:
Spoiler

-snip-

--[[Main Code]]--
connected, master = tryToConnect();

while true do
  if connected then
	header = headerOnline..master;
  else
	header = headerOffline;
  end
  timerID = os.startTimer(5);  --Here is where the timerID is stored
  drawScreen();
  local event, p1, p2, p3, p4, p5 = os.pullEvent();  --Here is where is *should* return the timerID

  if event == "modem_message" then
    -snip-
  elseif event == "timer" and p1 == timerID then  --This never returns true. If I remove the 'and p1 == timer' then it gets returned true, but 'p1' is never the same as 'timerID' any ideas why?
	print("TimerID = "..timerID);
	print("p1 = "..p1);
	sleep(1);
	term.clear();
	connected, master = tryToConnect();
  end
end
LordIkol #5
Posted 23 May 2013 - 08:28 AM
i could find no error
even when i test the code it just runs fine.
Suggest the error is somewhere in the snipped lines, if you dont mind show us the whole code then i will have a look at it again

and for the case you did not know, you dont need to put ; at the end of a line in lua :)/>
but that should not make problems, would just save some time

here is my testcode :


timerID = os.startTimer(2)  --Here is where the timerID is stored
print(timerID)
  local event, p1, p2, p3, p4, p5 = os.pullEvent()  --Here is where is *should* return the timerID
if event == "timer" and p1 == timerID then  --This never returns true. If I remove the 'and p1 == timer' then it gets returned true, but 'p1' is never the same as 'timerID' any ideas why?
		print("TimerID = "..timerID)
		print("p1 = "..p1)
end

greets
Loki
thislooksfun #6
Posted 23 May 2013 - 09:04 AM
i could find no error
even when i test the code it just runs fine.
Suggest the error is somewhere in the snipped lines, if you dont mind show us the whole code then i will have a look at it again

and for the case you did not know, you dont need to put ; at the end of a line in lua :)/>/>
but that should not make problems, would just save some time

here is my testcode :


timerID = os.startTimer(2)  --Here is where the timerID is stored
print(timerID)
  local event, p1, p2, p3, p4, p5 = os.pullEvent()  --Here is where is *should* return the timerID
if event == "timer" and p1 == timerID then  --This never returns true. If I remove the 'and p1 == timer' then it gets returned true, but 'p1' is never the same as 'timerID' any ideas why?
		print("TimerID = "..timerID)
		print("p1 = "..p1)
end

greets
Loki

The full code is in my first post. I know you don't need to use semicolons in LUA, but I use other languages as well, namely Java, and it's a habit I try to maintain.
LordIkol #7
Posted 23 May 2013 - 09:36 AM
oh sorry buddy, overlooked the spoiler :D/>
will have a look at it when im back home in some hours

greetz Loki
thislooksfun #8
Posted 23 May 2013 - 09:38 AM
oh sorry buddy, overlooked the spoiler :D/>/>
will have a look at it when im back home in some hours

greetz Loki

That's fine, thanks for the help! I will try to figure it out in the meantime, but I doubt I will make it work.
thislooksfun #9
Posted 23 May 2013 - 09:45 AM
If you want the full code with syntactic highlighting, here is the pastebin: http://pastebin.com/xCrjp7b8
LordIkol #10
Posted 23 May 2013 - 09:51 AM
from looking through the code i could not see a problem.
Code is well structured
checked if there is a problem with the if clauses but everything seems to be fine.
will have to do a litte bit debugging when im home.

i would try to set both timers to local value just to see if sth changes.
maybe take out the p1 == TimerID so that the event fires and add print("TimeoutID = "..timeoutID) after print("TimerID = "..timerID); to see if p1 matches the TimeoutID instead of TimerID

only worked one time with the timers but i will see if i can help.
Maybe someone else will jump in meanwhile :D/>

greets
thislooksfun #11
Posted 23 May 2013 - 11:01 AM
The problem was this:
Spoiler

-snip-

--[[Main Code]]--
connected, master = tryToConnect();

while true do
  if connected then
	header = headerOnline..master;
  else
	header = headerOffline;
  end
  timerID = os.startTimer(5);		--This line was the problem
  drawScreen();
  local event, p1, p2, p3, p4, p5 = os.pullEvent();

  if event == "modem_message" then
	-snip-
  elseif event == "timer" and p1 == timerID then
	print("TimerID = "..timerID);
	print("p1 = "..p1);
	sleep(1);
	term.clear();
	connected, master = tryToConnect();
  end
end

Basically what was happening was that I was starting a new timer before the old one finished, therefore it wasn't ever returning true. I have updated the pastebin with the fixed code if you want to compare it. Thanks for the help!

-tlf
theoriginalbit #12
Posted 23 May 2013 - 11:24 AM
I was actually just about to post that, that was the problem, when I refreshed the page to see you had figured it out :)/> good job :)/>
I do have an unrelated fix for you, that will cause a bug later given particular info.

Your code as it is now.

function isTable(var)
  if var[1] ~= nil then
	return true;
  else
	return false;
  end
end

if the variable passed through is not a table then you will get an error that says something like so
attempt to index a <type> value
where <type> will say string, boolean, number, nil, or function.

To fix this use the type function. This function returns what type the variable (or data at the pointer address) actually is. Code example of what type outputs
Spoiler

var = "hello"
print(type(var))
would output "string"



var = 1234
print(type(var))
would output "number"



var = { "hello", 1234 }
print(type(var))
would output "table"



function var()
end
print(type(var))
would output "function"



var = true
print(type(var))
would output "boolean"



var
print(type(var))
would output "nil"

so in the example of how you would use it would be

function isTable(var)
  return type(var) == "table"
end
which if the type is a table, it will return true, else it will return false

— BIT
Edited on 23 May 2013 - 09:25 AM
thislooksfun #13
Posted 23 May 2013 - 11:33 AM
I was actually just about to post that, that was the problem, when I refreshed the page to see you had figured it out :)/> good job :)/>
I do have an unrelated fix for you, that will cause a bug later given particular info.

Your code as it is now.

function isTable(var)
  if var[1] ~= nil then
	return true;
  else
	return false;
  end
end

if the variable passed through is not a table then you will get an error that says something like so
attempt to index a <type> value
where <type> will say string, boolean, number, nil, or function.

To fix this use the type function. This function returns what type the variable (or data at the pointer address) actually is. Code example of what type outputs
Spoiler

var = "hello"
print(type(var))
would output "string"



var = 1234
print(type(var))
would output "number"



var = { "hello", 1234 }
print(type(var))
would output "table"



function var()
end
print(type(var))
would output "function"



var = true
print(type(var))
would output "boolean"



var
print(type(var))
would output "nil"

so in the example of how you would use it would be

function isTable(var)
  return type(var) == "table"
end
which if the type is a table, it will return true, else it will return false

— BIT

I will use that, thanks! I had run into that error, so I was calling it in a pcall, but that is a more elegant solution.
Cozzimoto #14
Posted 30 May 2013 - 08:43 PM
i actually made this very neat program mainly using timers,

here is the program: http://pastebin.com/ve8K48kU

and if you want to watch my video explaining it in detail, here is the link: http://www.youtube.com/watch?v=a3MDdReB-6c

i use OOP to control all the timers being fired to update the age of the message through rednet