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

[Solved] [Lua] [Question] coroutine, os.pullEvent()

Started by Oddstr13, 20 May 2012 - 04:05 PM
Oddstr13 #1
Posted 20 May 2012 - 06:05 PM
Why dosn't this code print "Event: <event>" when a event occurs?

Basicly what i'm trying to do is making a networking library that runs in the background and sends a event once there is data to read.

So far it works just great, but i can't seem to get it to run in the background.
The coroutine seems to yield permanently once os.pullEvent() or sleep() is called within the coroutine.


--#!lua
local function coroutineloop()
  local doloop = true
  while doloop do
	e, v1, v2, v3 = os.pullEvent()
	print("Event: " .. e)
	if e == "key" and v1 == 15 then doloop = false end -- Stop loop if tab key is pressed
  end
end
--coroutineloop() -- This works just as expected
local cr = coroutine.create(coroutineloop)
coroutine.resume(cr)
print(cr)
while true do
  --e, v1 = os.pullEvent()
  --if e == "key" and v1 == 43 then coroutine.resume(cr) end -- Resume coroutine if pipe is pressed
  sleep(10)
  print(coroutine.status(cr))
end
Cloudy #2
Posted 20 May 2012 - 07:23 PM
Why dosn't this code print "Event: <event>" when a event occurs?

Basicly what i'm trying to do is making a networking library that runs in the background and sends a event once there is data to read.

So far it works just great, but i can't seem to get it to run in the background.
The coroutine seems to yield permanently once os.pullEvent() or sleep() is called within the coroutine.


--#!lua
local function coroutineloop()
  local doloop = true
  while doloop do
	e, v1, v2, v3 = os.pullEvent()
	print("Event: " .. e)
	if e == "key" and v1 == 15 then doloop = false end -- Stop loop if tab key is pressed
  end
end
--coroutineloop() -- This works just as expected
local cr = coroutine.create(coroutineloop)
coroutine.resume(cr)
print(cr)
while true do
  --e, v1 = os.pullEvent()
  --if e == "key" and v1 == 43 then coroutine.resume(cr) end -- Resume coroutine if pipe is pressed
  sleep(10)
  print(coroutine.status(cr))
end

In the code you posted the coroutine.resume line is commented out… Maybe that's the issue?
MysticT #3
Posted 20 May 2012 - 07:25 PM
You have to resume the coroutine after it yields. It's easier to use the parallel api, cause when you create a coroutine you have to handle it yourself, so the shell can't run at the same time, so no background running.
This makes a function run in the background at the same time as the shell:

local function background()
  while true do
	local evt = os.pullEvent()
	print("Event: ", evt)
  end
end

local function runShell()
  shell.run("/rom/programs/shell")
end

parallel.waitForAny(background, runShell)
Change the background function to do whatever you want and it would run with the shell, just don't forget to add some yield (os.pullEvent, sleep, etc.) or the shell won't work (and it would throw an error).
Oddstr13 #4
Posted 20 May 2012 - 08:29 PM
SpoilerWhy dosn't this code print "Event: <event>" when a event occurs?

Basicly what i'm trying to do is making a networking library that runs in the background and sends a event once there is data to read.

So far it works just great, but i can't seem to get it to run in the background.
The coroutine seems to yield permanently once os.pullEvent() or sleep() is called within the coroutine.


--#!lua
local function coroutineloop()
  local doloop = true
  while doloop do
	e, v1, v2, v3 = os.pullEvent()
	print("Event: " .. e)
	if e == "key" and v1 == 15 then doloop = false end -- Stop loop if tab key is pressed
  end
end
--coroutineloop() -- This works just as expected
local cr = coroutine.create(coroutineloop)
coroutine.resume(cr)
print(cr)
while true do
  --e, v1 = os.pullEvent()
  --if e == "key" and v1 == 43 then coroutine.resume(cr) end -- Resume coroutine if pipe is pressed
  sleep(10)
  print(coroutine.status(cr))
end

In the code you posted the coroutine.resume line is commented out… Maybe that's the issue?
I was just testing a bit, that coroutine.resume() just resulted in the coroutine status changing to "dead"

You have to resume the coroutine after it yields. It's easier to use the parallel api, cause when you create a coroutine you have to handle it yourself, so the shell can't run at the same time, so no background running.
This makes a function run in the background at the same time as the shell:

local function background()
  while true do
	local evt = os.pullEvent()
	print("Event: ", evt)
  end
end

local function runShell()
  shell.run("/rom/programs/shell")
end

parallel.waitForAny(background, runShell)
Change the background function to do whatever you want and it would run with the shell, just don't forget to add some yield (os.pullEvent, sleep, etc.) or the shell won't work (and it would throw an error).

What i'm trying to do is something simmilar to the rednet api, i would like to be able to start the coroutine with a function that dosn't block (test.listen("back") f.ex.), then the coroutine queues a event when a packet is received.

I have had a look at the rednet code, but i don't quite understand how it manages to do just that.

I would post my library code, but i really want to finnish it before publishing it.

Here is a small part of the api, the one that handles the coroutine.
The function receive() is almost allways yielding, using os.pullEvent()
Spoiler

local function coroutineloop(io)
  if io == nil then io = "back" end
  print("listening on" .. io)
  local run = true
  while run do
	local packet, reason = receive(io, 5)
	if packet == nil then
	  if reason == "urnetclose" then
		listeners[io] = nil
		run = false
		print("Stopping...")
	  end
	else
	  os.queueEvent("urnet", packet)
	end
  end
end

function listen(io)
  if io == nil then io = "back" end
  if listeners[io] == nil then
	local cr = coroutine.create(coroutineloop)
	coroutine.resume(cr, io)
	print(cr)
	listeners[io] = cr
	return true
  else
	return false
  end
end

function close(io)
  if io == nil then io = "back" end
  os.queueEvent("urnetclose", io)
end

And here is the test program using the api:
Spoiler

--#!lua
os.loadAPI("urnet")

for k,v in pairs(urnet) do
  print(tostring(k) .. ": " .. tostring(v))
end

urnet.listen("back")

while true do
  e, v1, v2, v3 = os.pullEvent()
  print(tostring(e) .. ", " .. tostring(v1) .. ", " .. tostring(v2) .. ", " .. tostring(v3))
  if e == "key" then
	if v1 == 15 then
	  urnet.close("back")
	elseif v1 == 26 then
	  for k,v in pairs(urnet.listeners) do
		print("Status " .. k .. ": " .. tostring(coroutine.status(v)))
	  end
	elseif v1 == 53 then
	  print("Reloading urnet..")
	  os.unloadAPI("urnet")
	  os.loadAPI("urnet")
	  print("urnet reloaded.")
	end
  end
end
MysticT #5
Posted 20 May 2012 - 11:49 PM
rednet actually does what I told you, just that it doesn't do it in the rednet code. If you take a look at the bios you'll see these lines at the end:

local ok, err = pcall( function()
    parallel.waitForAny(
        function()
            rednet.run()
        end,
        function()
            os.run( {}, "rom/programs/shell" )
        end
    )
end )
That's what makes rednet run in the background.
Oddstr13 #6
Posted 21 May 2012 - 12:18 AM
rednet actually does what I told you, just that it doesn't do it in the rednet code. If you take a look at the bios you'll see these lines at the end:

local ok, err = pcall( function()
	parallel.waitForAny(
		function()
			rednet.run()
		end,
		function()
			os.run( {}, "rom/programs/shell" )
		end
	)
end )
That's what makes rednet run in the background.

Uh, oh, rednet have an unfair adventage then.
I will see what i can do with some startup file magick.

Thanks for the help! :P/>/>
MysticT #7
Posted 21 May 2012 - 12:25 AM
No problem. You can use the code I posted above in a startup program, it would run any function you want in the background and start the shell. It would make the shell run twice, but there shouldn't be any problem. You could add an os.shutdown() at the end so it shuts down the computer when the new shell exits or your function ends.
Oddstr13 #8
Posted 21 May 2012 - 04:06 PM
Works like a charm. Thanks again :P/>/>