Earlier on, I posted a showing of my early network code here: Link
Since then I've done a lot of tweaking, programming and adjusting. I now have a fully functional remote reactor (Big Reactors) control suite.
In this post I will be sharing and explaining my main communication code, as well as a few screen shots and a video.
This program is not perfect, and is continually growing, but I feel sharing it may help someone overcome some of the issues I struggled to overcome.
Here's a (really crappy) walk-through of my base: https://www.youtube....I7N51zbMwygkVbw
I'll begin with a little walk-through of my system:
The Reactor:
As you can see, there is a single reactor core so it's a small reactor, and it is controlled by the computer infront.
This guy simply listens for commands over the network and reacts to requests for data.
The numbers you see here are my debug for changing the rod depth.
Continuing on, we go to the main computer floor:
There are a few systems in here, as well as some OpenComputer systems.
First we'll start with the big screen:
On boot, this is the first display screen. It refreshes about every 5 seconds and displays some pretty important information.
In the screen control computer you can see the options:
We'll select option 1, because the other options are just computer control options.
Then if we look at the big screen:
Above we now see some more detailed reactor information. Very useful for remote monitoring and such.
Moving on, we have our Reactor Server:
Option 1 is the same as on the big screen:
But option 2 allows us to have a little control over the reactor:
From there I can either shut down, or turn on the reactor. I can also adjust the control rod depth. Very useful for heat management and control.
Here's the whole building:
It's a 5 level building, with 3 levels underground. The top floor is the control room, and the very bottom is the reactor. It's stored pretty deep to prevent an explosion destroying our ME drives.
So all in all, it looks like a pretty simple system, but it really took a lot of programming to get there!
I'll start with the Screen code:
--Modem Communication Numbering -- 1/2 Screen to Server 1 -- 2/1 Server 1 to Screen --3/4 Screen to Power Emergency PC -- 4/3 Pwr Em. PC to Screen local modem = peripheral.wrap('back') local screen = peripheral.wrap('top') --begin functions function ps(n) --similar to print screen.write(n) x,y=screen.getCursorPos() y=y+1 screen.setCursorPos(1,y) end ---------------------------------------- function w(n) --write same line x1,y1=screen.getCursorPos() screen.setCursorPos(1,y1) screen.clearLine() screen.write(n) end ---------------------------------------- function reset() --places cursor to left again x1,y1=screen.getCursorPos() screen.setCursorPos(1,y1) end ---------------------------------------- function send(chan,reply,m) --transmits a message modem.transmit(chan,reply,m) end ---------------------------------------- function get(getchan,tmout)--listener, will timeout or wait, and passes message into msg if tmout==nil then tmout=100000000000000000000000000000 --change to call event w/o timer end modem.open(getchan) --opens port chk=modem.isOpen(getchan) --checks to make sure it is open if chk==true then --will set listener --mm = os.pullEvent("modem_message") timeout = os.startTimer(tmout) while true do event = {os.pullEvent()} if event[1] == "modem_message" then --print'Worked' --print(event[1].." "..event[2].." "..event[3].." "..event[4].." "..event[5].." "..event[6]) msg=event[5] returnchan=event[4] chan2=event[3] --print(chan2) --Used for debug success=1 break elseif event[1] == "timer" and event[2] == timeout then success=0 break elseif event[1] == "stop_main" then --to allow system to shutdown without cluttering screen return end end end if chk==false then --send error# to screen print('Error 100: Failed to Bind Port '..chan..'.') end end ---------------------------------------- function chksvr(sendchan,svrnum,gettmout) --allows me to easily check multiple servers without writing code for a month. send(sendchan,2,"ping") get(2,gettmout) if success==1 and msg=="ping" then screen.setCursorPos(1,svrnum+2) w("Server "..svrnum..": Online") end if success==0 then screen.setCursorPos(1,svrnum+2) w("Server "..svrnum..": DOWN") end --sleep(5) end ---------------------------------------- function main() --this guy will check that we're not shutting down, then run our various checks while true do timeout2 = os.startTimer(2) eventData = {os.pullEvent()} if eventData[1] == "stop_main" then sleep(10000000) --here to prevent main moving on... >.< return elseif eventData[1] == "timer" and eventData[2] == timeout2 then --Power system checks/screen listenR() --Server Checks/Screen chksvr(1,1,.1) --Server 1 Status chksvr(3,2,.1) --Server 2 Status chksvr(5,3,.1) --Server 3 Status fx,fy=screen.getCursorPos()--Re-align stuff, may have a function to do this, but scrolling up is too much work. screen.setCursorPos(1,fy+1) ps("")--Following displays live data from reactor screen.clearLine() ps(" ---Reactor Status---") screen.clearLine() ps("Core Temp: "..fuelTemp.."C") screen.clearLine() ps("Casing Temp: "..casingTemp.."C") screen.clearLine() ps("Fuel Amount: "..fuelLvl.."mB") screen.clearLine() ps("Energy/tick: "..energyTick.."RF/t") screen.clearLine() ps("Held Energy: "..storedEnergy.."RF") screen.clearLine() sleep(.5) --Screen choice chk end end end ---------------------------------------- function scch() --this guy handles user input, screen selection and begins the shutdown process while true do print'Welcome to the Screen Server' print'Please select an option:' print'1: Reactor Monitor' print'2: System Control Touch Monitor' print'3: System Shutdown' sel=io.read() sel=sel+1-1 if sel==0 then --Junk really print'Scanning...' --sleep(1) end if sel==1 then --Displays a static display of all reactor functions | Does not refresh os.queueEvent("stop_main") screen.clear() screen.setCursorPos(1,1) ps('Current Reactor status:') ps("Reactor Active: "..tostring(active)) ps("Stored Energy: "..storedEnergy.."RF") ps("Fuel Temp: "..fuelTemp.."C") ps("Casing Temp: "..casingTemp.."C") ps("Fuel Level: "..fuelLvl.."mB") ps("Waste Level: "..wasteLvl.."mB") ps("Energy/Tick: "..energyTick.."RF/t") ps("Reactivity: "..reactivity.."%") print('Press enter to continue...') io.read() screen.clear() screen.setCursorPos(1,1) os.reboot() end if sel==2 then --Future print'Coming soon.' end if sel==3 then --Will stop everything and shut the system down print'Shutting down!' os.queueEvent("stop_main") --sends the shutdown event --os.pullEvent("stop_main") sleep(.5) screen.clear() screen.setCursorPos(1,1) ps("Warning! System Shutting Down!") sleep(5) --delay to allow the user to know what's happening screen.clear() os.shutdown() --BYE :D/>/>/> end term.clear() term.setCursorPos(1,1) --just cause, we want to clean up after we're done selecting other choices end end ---------------------------------------- function listenR() --This function queues and grabs the latest reactor status information | Should have used a for or while loop... :(/>/>/> but this allows debugging --print'ListeningR...' send(9,10,"req") sleep(.8)--Not sure why but this is required for accurate reading! get(10) active=msg --print(active) sleep(.1) get(11) storedEnergy=msg --print(storedEnergy) sleep(.1) get(12) fuelTemp=msg --print(fuelTemp) sleep(.1) get(13) casingTemp=msg --print(casingTemp) sleep(.1) get(14) fuelLvl=msg --print(fuelLvl) sleep(.1) get(15) wasteLvl=msg --print(wasteLvl) sleep(.1) get(16) energyTick=msg --print(energyTick) sleep(.1) get(17) reactivity=msg --print(reactivity) sleep(.1) end ----------------------------------------- --end functions --Body screen.clear() --start by cleaning up incase of improper shutdown. screen.setCursorPos(1,1) ps("Kizz Tower Control: ONLINE") --Tell everyone we're alive ps("") ps("Loading...") --Tell people we're not ready yet parallel.waitForAll(scch,main) --all systems go, let's run this baby! --end body
Incase you want to see the code in a more readable format: http://pastebin.com/T62p4rVN
As of now I don't think I need to explain the code. It's pretty documented. If you would like some explanation, I will be more than happy to later . Just leave a reply asking for it.
Next up we have the Reactor Server code. This server is located in the control room, and is not the computer attached to the reactor.
--Server 1 Control Server. Controls Main Reactor System local modem = peripheral.wrap('back') function send(chan,reply,m) modem.transmit(chan,reply,m) end function get(chan,tmout)--listener if tmout==nil then tmout=100000000000000000000000000000 --change to call event w/o timer end modem.open(chan) --opens port chk=modem.isOpen(chan) --checks to make sure it is open if chk==true then --will set listener --mm = os.pullEvent("modem_message") timeout = os.startTimer(tmout) while true do event = {os.pullEvent()} if event[1] == "modem_message" then --print'Worked' --print(event[1].." "..event[2].." "..event[3].." "..event[4].." "..event[5].." "..event[6]) msg=event[5] returnchan=event[4] chan=event[3] return elseif event[1] == "timer" and event[2] == timeout then break end end end if chk==false then --send error# to screen print('Error 100: Failed to Bind Port '..chan..'.') end end function listen() print'Listening...' while true do get(1) --print(msg) send(2,1,"ping") --sleep(.5) --os.reboot() end end function listenR() print'ListeningR...' while true do send(9,10,"req") get(10) active=msg --print(active) get(11) storedEnergy=msg --print(storedEnergy) get(12) fuelTemp=msg --print(fuelTemp) get(13) casingTemp=msg --print(casingTemp) get(14) fuelLvl=msg --print(fuelLvl) get(15) wasteLvl=msg --print(wasteLvl) get(16) energyTick=msg --print(energyTick) get(17) reactivity=msg --print(reactivity) sleep(5) end end function test() while true do term.clear() term.setCursorPos(1,1) print'Welcome to Server 1.' print'System online.' print'Please make a choice:' print'1: Reactor Monitor' print'2: Reactor Control' print'3: Shutdown' print'4: Reboot' print'5: Terminate' ch=io.read() ch=ch+1-1 if ch==1 then print'Welcome to the Reactor Control Center' print'Current status:' print("Reactor Active: "..tostring(active)) print("Current Stored Energy: "..storedEnergy.."RF") print("Fuel Temp: "..fuelTemp.."C") print("Casing Temp: "..casingTemp.."C") print("Fuel Level: "..fuelLvl.."mB") print("Waste Level: "..wasteLvl.."mB") print("Energy/Tick: "..energyTick.."RF/t") print("Reactivity: "..reactivity.."%") print'Press enter to continue...' io.read() end if ch==2 then print'---Reactor Control---' print'Please make a choice:' if active==true then print'1: Turn Reactor off' end if active==false then print'1: Turn Reactor on' end print'2: Set Control Rod Level (0-100%)' sel=io.read() sel=sel+1-1 if sel==1 and active==true then send(100,1,"pwrOFF") print'Shutting Reactor Down' sleep(1) end if sel==1 and active==false then send(100,1,"pwrON") print'Powering on Reactor' sleep(1) end if sel==2 then print'Please input desired rod level for all rods(0-100% with no % symbol):' rlvl=io.read() rlvl=rlvl+1-1 send(100,1,"rodsLvl") sleep(.1) send(50,1,rlvl) print('Sent '..rlvl.." to the reactor.") sleep(1) end end if ch==3 then print'Shutting down!' sleep(1) os.shutdown() end if ch==4 then print'Rebooting!' sleep(1) os.reboot() end if ch==5 then print'Terminating program!' sleep(1) term.clear() term.setCursorPos(1,1) break end end end active=failed storedEnergy=failed fuelTemp=failed casingTemp=failed fuelLvl=failed wasteLvl=failed energyTick=failed reactivity=failed parallel.waitForAll(test,listen,listenR)
Again, the pastebin, for easy reading: http://pastebin.com/SL656QmH
And finally, the code for the reactor computer. This is the computer directly attached to the reactor:
--Reactor Receiver PC local reactor=peripheral.wrap('back') local modem=peripheral.wrap('right') function send(chan,reply,m) modem.transmit(chan,reply,m) end function get(chan,tmout)--listener if tmout==nil then tmout=100000000000000000000000000000 --change to call event w/o timer end modem.open(chan) --opens port chk=modem.isOpen(chan) --checks to make sure it is open if chk==true then --will set listener --mm = os.pullEvent("modem_message") timeout = os.startTimer(tmout) while true do event = {os.pullEvent()} if event[1] == "modem_message" then --print'Worked' --print(event[1].." "..event[2].." "..event[3].." "..event[4].." "..event[5].." "..event[6]) msg=event[5] returnchan=event[4] chan=event[3] break elseif event[1] == "timer" and event[2] == timeout then break end end end if chk==false then --send error# to screen print('Error 100: Failed to Bind Port '..chan..'.') end end --Reactor Control/Monitor Vars function update() chkCn=reactor.getConnected() chkActive=reactor.getActive() chkEnergyStored=reactor.getEnergyStored() chkFuelTemp=reactor.getFuelTemperature() chkCasingTemp=reactor.getCasingTemperature() chkFuel=reactor.getFuelAmount() chkWaste=reactor.getWasteAmount() chkEnergyTick=reactor.getEnergyProducedLastTick() chkReactivity=reactor.getFuelReactivity() end function reactorPowerCtrl(n) reactor.setActive(n) end function setAllRodLvl(n) reactor.setAllControlRodLevels(n) end function ejectWaste(n) reactor.doEjectWaste(n) end --Passing code: Passes all reactor monitoring vars to Server 1 function request() print'Listening' while true do update() get(9) if msg=="req" then send(10,9,chkActive) sleep(.1) send(11,9,chkEnergyStored) sleep(.1) send(12,9,chkFuelTemp) sleep(.1) send(13,9,chkCasingTemp) sleep(.1) send(14,9,chkFuel) sleep(.1) send(15,9,chkWaste) sleep(.1) send(16,9,chkEnergyTick) sleep(.1) send(17,9,chkReactivity) --sleep(5) end end end function comms() chkCn=reactor.getConnected() if chkCn==true then request() end if chkCn==false then print'Failed to connect to reactor...' sleep(1) end end function watchdog() while true do get(100) --print(msg) if msg=="pwrON" then reactorPowerCtrl(true) end if msg=="pwrOFF" then reactorPowerCtrl(false) end if msg=="rodsLvl" then get(50) print(msg) rlvl=msg+1-1 if rlvl>=0 and rlvl<=100 then setAllRodLvl(rlvl) end end end end parallel.waitForAll(comms,watchdog)
And the pastebin: http://pastebin.com/8bi29H56
Later on, if requested, I'd be happy to explain some more of this code.
Hope you enjoyed!
Edited by Kizz, 17 July 2014 - 01:46 PM.