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

os.pullEvent

Started by The_Glaive, 15 May 2018 - 09:19 PM
The_Glaive #1
Posted 15 May 2018 - 11:19 PM
Is there a way to get a computer to do things while also listening for an event using os.pullEvent?

I want to make an elevator network, using computers on each floor waiting for a redstone pulse using os.pullEvent("redstone") and then telling the computer on the lift that the elevator is on a specific floor. Then the computer on the lift would send redstone pulses to the elevator engine to either go up or down. The problem is, as far as I know, the os.pullEvent method halts the program until an even is pulled. How would you loop to raise or lower the elevator while also listening for an event (in order to stop when you are on the desired floor)?
Edited on 15 May 2018 - 09:20 PM
CLNinja #2
Posted 16 May 2018 - 12:24 AM
A ) This should be in ask a prop
B ) look on the wiki for Parallel
Edited on 15 May 2018 - 10:24 PM
Bomb Bloke #3
Posted 16 May 2018 - 02:25 AM
Technically speaking, a ComputerCraft computer cannot execute code while waiting for an event. It's either doing one or the other.

However, events don't have to be caught the very moment they occur - each system has an "event queue". New events are added to the end, and older events are pulled from the front. So if you're busy setting pulses when the user presses a button, you can still pull that event afterwards.

Where it gets complex is that certain functions will pull events for you - and if they don't like the ones they find, they'll discard them and keep pulling until they get what they want. The primary example is sleep() - it starts a timer, and then keeps discarding events from the front of the queue until it gets the associated timer event. This would cause you to "miss" incoming redstone pulses.

But for the case of an elevator, I don't believe that you should be needing to use any such functions. If your script needs to measure time (although I don't see why it would - I assume you're using more redstone circuitry to tell when the elevator arrives at each floor), then all you need to do is start the timers yourself, and rig up a loop that acts on both timer events and redstone events.

If you're really stuck, then it'd pay to provide more information as to how things are wired, and what your code currently looks like.
The_Glaive #4
Posted 21 May 2018 - 09:39 PM
I'm thinking about something like this:


os.loadAPI("button") -- load button api
os.loadAPI("parallel") -- load parallel api
m = peripheral.wrap("top") -- attaches a monitor to the top of the computer and calls the monitor 'm'
m.clear() -- clears the monitor

-- i will probably need global flags and variables here

function fillTable() -- initializes the table to be displayed on the monitor when this function is called
  button.setTable("Floor 1", floor1, 10,20,3,5) -- these button locations are place holders
  button.setTable("Floor 2", floor2, 22,32,3,5)
  button.setTable("Floor 3", floor3, 10,20,8,10)
  button.setTable("Floor 4", floor4, 22,32,8,10)
  button.setTable("Floor 5", floor5, 10,20,13,15)
  button.setTable("Cancel", cancel, 22,32,13,15)
end

function eleMoveUp()
  -- code to determine if the elevator needs to go up and returns boolean
end

function eleMoveDown()
  -- code to determine if the elevator needs to go down and returns boolean
end

function eleIdle()
  -- code to see if elevator is currently doing something and returns boolean (using eleMoveUp and eleMoveDown functions)
  -- returns true if BOTH eleMove* functions are false
end

function buttonPressed()
  -- checks to see if elevator is already doing something (using eleIdle function)
  -- if floor button is lower than current location it calls moveEleDown function
  -- if floor button is higher than current location it calls moveEleUp function
  -- if floor button is current location flash floor button using button api
  -- if cancel button is pressed it returns nil
  -- returns TARGET floor number
end

function elePosition()
  -- parallel api for os.eventPull() OR sleep to see if elevator is on that floor
  -- if elevator is on this computers floor broadcast to elevator network what floor the elevator is on
  -- update floor monitor display using button api
end

function moveEleUp()
  -- send redstone pulse to the up side of the elevator engine
end

function moveEleDown()
  -- send redstone pulse to the down side of the elevator engine
end

function getComputerName()
  -- returns string of the computer label
end

while true do
  -- use button api to load monitor
  -- use parallel api to ask each floor elevator for their label by rednet name and if the elevator is on their floor
		 --probably updating a global table of floor labels and assigning floor number to it
		 --I will also need to have it check for computer on the elevator to respond or it
		 --throws out an error
  -- use parallel api to ask elevator control computer if they are moving up or down or idle
  -- use button and parallel api to ask if a button has been pressed
	 -- if button is pressed, make sure elevator is idle and then find out if the elevator needs to go up or down
  -- move elevator until target floor is reached
  -- update button status (the floor that the elevator is on will be green, all others will be red, cancel button is gray)
end

I'm thinking I might need to break apart the buttonPressed function and use another function call to the moveEle* functions.
Edited on 21 May 2018 - 11:20 PM
Bomb Bloke #5
Posted 22 May 2018 - 04:43 AM
Not a fan of the glut of functions, I certainly wouldn't recommend breaking them down any further. As a general rule, if having a function would make your script longer than not, then you're probably falling into the trap of using it as a comment tag - and would be better off using a real tag instead.

If you intend to use the parallel API, then you probably won't want to be calling it within a loop - rather, it's generally best to create coroutines that loop themselves. It sounds like you'd want one which moves the elevator to from floor to floor, one which listens for input from the attached monitor, and one which listens for input from the other computers over rednet. If you're copying the behaviour of a "real" elevator, you'll want a table to keep track of which floors have had their call button pressed - the "input" loops will add to it, and the "movement" loop will inspect it and remove entries as it stops at each of them.

If you have access to bundled cables, then you may not need a computer on every floor.

If you plan to have a computer located inside the elevator, be aware that most elevator engines I'm aware of will cause onboard computers to reboot with each movement they make. While it's quite possible to code around this, you'll need to test for this behaviour early, as your script would need an entirely different structure in order to deal with it.
The_Glaive #6
Posted 22 May 2018 - 06:37 PM
Thanks for the heads up about the computer on the elevator.

I have access to bundled cable, but the version of mod pack I'm on is using CC1.58, which has support for bundled cable missing.
Bomb Bloke #7
Posted 23 May 2018 - 11:10 AM
RedNet Cables from MineFactory Reloaded should work in place of bundled ones.