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

possible openperipheral bug

Started by p3p, 14 April 2015 - 06:42 PM
p3p #1
Posted 14 April 2015 - 08:42 PM
while experimenting with coroutines and handling event loss during peripheral calls I am having an odd issue, if I try and use peripheral call on an openperipheral peripheral inside a coroutine, (I understand the entire comutercraft system runs on coroutines and thats what makes this odd) it triggers an internal error.

[20:31:27] [Coroutine-258/INFO] [OpenMods]: Unwrapped error during method getPlayers(9) execution on peripheral openperipheral_sensor, args: []
java.lang.ArrayIndexOutOfBoundsException

This is how I reproduced the error I was having:
openpsensor = peripheral.wrap("top")
remote_computer = peripheral.wrap("computer_1")
--module
function sensor_reader()
  while true do
	--standard peripheral is fine
	print(remote_computer.getID())
	--internal error here
	status, value = pcall(openpsensor.getPlayers)
	if status == true then
	  print(textutils.serialize(value))
	else
	  print(value)
	end
	coroutine.yield()
  end
end
--state
local modules = { ["next_pid"] = 1, ["routines"] = {}, ["event_router"] = {}, ["events"] = {} }
function modules.add(func)
  modules.routines[modules.next_pid] = coroutine.create(func)
  modules.next_pid = modules.next_pid + 1
end
--Kernel
function process()
  while true do
	for i,v in ipairs(modules.routines) do
	  coroutine.resume(v)
	end
	--openperipheral works here
	status, value = pcall(openpsensor.getPlayers)
	if status == true then
	  print(textutils.serialize(value))
	else
	  print(value)
	end
	os.pullEvent("tick")
  end
end
function event_distribute()
  while true do
	local event = {os.pullEvent()}
  end
end
function ticker()
  while true do
	os.queueEvent("tick")
	os.sleep(0.05)
  end
end
--startup
modules.add(sensor_reader)
parallel.waitForAny(process, event_distribute, ticker)

I would just like some feedback as to whether this is my misuse of coroutines or a real issue
Bomb Bloke #2
Posted 14 April 2015 - 11:27 PM
It's your misuse of coroutines. Your conventional CC function will often, when it yields, specify parameters asking for certain event types. Whether it does or not, it'll very nearly always expect event data back when it resumes, and you're not supplying it. Certainly openpsensor.getPlayers will want event data back, otherwise it wouldn't be yielding in the first place - if you resume its coroutine without supplying it then yeah, it'll crash!

A super-basic example of how you'd run a single coroutine:

local function myFunc()
        for i = 1, 10 do
                print(i)
                sleep(1)
        end
end

-- Initialise coroutine:
local myCoroutine = coroutine.create(myFunc)
local ok, requestedEvent = coroutine.resume(myCoroutine)

-- Run coroutine to completion:
while coroutine.status(myCoroutine) ~= "dead" do
        local myEvent = {os.pullEvent(requestedEvent)}
        ok, requestedEvent = coroutine.resume(myCoroutine, unpack(myEvent))
end

-- Coroutine has finished execution.

Really though, I don't see why you've got the "modules" stuff in there. Why not just let the parallel API handle it all for you?

openpsensor = peripheral.wrap("top")
remote_computer = peripheral.wrap("computer_1")
sleepDuration = 1
myTimer = os.startTimer(sleepDuration)

function sensor_reader()
	while true do
		status, value = pcall(openpsensor.getPlayers)
		
		if status == true then
			print(textutils.serialize(value))
		else
			print(value)
		end
		
		sleep(sleepDuration)  -- This could go, as openP is technically yielding for you; but why flog the processor?
	end
end

function process()
	while true do
		-- Do whatever it was you wanted this loop to do; kernel stuff I think you said?

		local myEvent = {os.pullEvent()}
		
		if myEvent[1] == "timer" and myEvent[2] == myTimer then
			myTimer = os.startTimer(sleepDuration)
		elseif myEvent[1] == "whatever other events you wanted to wait for..."
			...
		end
	end
end

--startup
parallel.waitForAny(process, sensor_reader)
p3p #3
Posted 15 April 2015 - 12:40 AM
Ah that explains that, thank you,
I was aware of how the events where distributed but for some reason I didn't think of that, the design is indeed far overly complicated for the example but that was just a reproduction of my problem, the modules are basically drivers that are loaded when a device is detected, they then register with the event system and the driver responds to events, the problems started when my drivers started yielding in the event chain and the events where eaten, to avoid that i need to run then in a seperate parallel method, which caused more problems, but I'm getting there,
Thanks again for the help