Advertisement
Rihlsul

ElevatorControl Door 1.02

Apr 5th, 2013
1,197
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 18.04 KB | None | 0 0
  1. local version = 1.02
  2.  
  3. local DoorConfig = {}
  4. local DoorScreen = {}
  5. local doorSettingsFile = "Door.Settings"
  6. local cabinPresent = false
  7.  
  8. local displayHandle = nil
  9.  
  10. --local floorMap = { }
  11.  
  12. local KeepWaiting = true
  13.  
  14.  
  15. -- ######################################################
  16. -- ##  Load the API                                    ##
  17. -- ######################################################
  18.  
  19. if fs.exists("ECAPI") then --Check to make sure that the entered API exists
  20.   os.loadAPI("ECAPI")
  21.   print("ECAPI loaded.")
  22. else
  23.   print("That API does not exist.  Retrieving from PasteBin")
  24.   -- we get it automagically
  25.   shell.run("pastebin","get", "1mcEVzzP", "ECAPI")
  26.   os.loadAPI("ECAPI")
  27.   print("ECAPI loaded.")
  28. end
  29.  
  30.  
  31. -- ######################################################
  32. -- ##  Setup Configuration                             ##
  33. -- ######################################################
  34.  
  35. local DefaultConfig = {}
  36. DefaultConfig = ECAPI.addConfigOption(DefaultConfig,"Version",version,"Please do not change this.")
  37. DefaultConfig = ECAPI.addConfigOption(DefaultConfig,"Network","","Elevator network name:")
  38. DefaultConfig = ECAPI.addConfigOption(DefaultConfig,"Modem","","Which side is the modem?",'side')
  39. DefaultConfig = ECAPI.addConfigOption(DefaultConfig,"Call","","Which side waits for call input?",'side')
  40. DefaultConfig = ECAPI.addConfigOption(DefaultConfig,"Detect","","Which side detects the Cabin?",'side')
  41. DefaultConfig = ECAPI.addConfigOption(DefaultConfig,"Display","","Which side is the Display monitor?",'side')
  42. DefaultConfig = ECAPI.addConfigOption(DefaultConfig,"Door","","Which side controls the Door?",'side')
  43. DefaultConfig = ECAPI.addConfigOption(DefaultConfig,"Debug","error","What level of debug output?")
  44. DefaultConfig = ECAPI.addConfigOption(DefaultConfig,"Floor","","Which floor is this?",'numeric')
  45. DefaultConfig = ECAPI.addConfigOption(DefaultConfig,"Description","","What description to display?")
  46. DefaultConfig = ECAPI.addConfigOption(DefaultConfig,"FloorPW","","Floor Password:",'pass')
  47. DefaultConfig = ECAPI.addConfigOption(DefaultConfig,"ConfigPW","","Config. Password:",'pass')   -- note, this is per machine
  48.  
  49. local function networkName()
  50.     return ECAPI.getConfigOption(DoorConfig,"Network")
  51. end
  52.  
  53. local function modemSide()
  54.     return ECAPI.getConfigOption(DoorConfig,"Modem")
  55. end
  56.  
  57. local function callSide()
  58.     return ECAPI.getConfigOption(DoorConfig,"Call")
  59. end
  60.  
  61. local function detectSide()
  62.     return ECAPI.getConfigOption(DoorConfig,"Detect")
  63. end
  64.  
  65. local function doorSide()
  66.     return ECAPI.getConfigOption(DoorConfig,"Door")
  67. end
  68.  
  69. local function displaySide()
  70.     return ECAPI.getConfigOption(DoorConfig,"Display")
  71. end
  72.  
  73. local function whichFloor()
  74.     return ECAPI.getConfigOption(DoorConfig,"Floor")
  75. end
  76.  
  77. local function floorDesc()
  78.     return ECAPI.getConfigOption(DoorConfig,"Description")
  79. end
  80.  
  81.  
  82. -- ######################################################
  83. -- ##  Terminal Functions                              ##
  84. -- ######################################################
  85.  
  86. local function termClear()
  87.     ECAPI.printDoorTemplate(DoorConfig)
  88.     DoorScreen = ECAPI.setupScreen(DoorScreen)
  89.     term.setCursorPos(3,18)
  90.     write("Command: ")
  91. end
  92.  
  93.  
  94. local function justPrintInfo(DoorScreen,moduleID,sourceID,floorID,newLine)
  95.     local t = "["..ECAPI.padLeft(moduleID,6," ").."]"
  96.     t = t .. "["..ECAPI.padLeft(sourceID,4," ")..":"
  97.     t = t .. ECAPI.padLeft(floorID,2," ").."]: " .. newLine
  98.    
  99.     if (ECAPI.getConfigOption(DoorConfig,"Debug") == "info") then
  100.         DoorScreen = ECAPI.justPrintLine(DoorScreen,t)
  101.     end
  102.     return DoorScreen
  103. end
  104.  
  105. local function justPrintLine(newLine)
  106.     DoorScreen = ECAPI.justPrintLine(DoorScreen,newLine)
  107. end
  108.  
  109.  
  110. -- functions?
  111.  
  112. local function registerFloor()
  113.     -- Now that we're started, notify the network controller
  114.     ECAPI.openModem(modemSide())
  115.     --password support:
  116.     local pass = ECAPI.getConfigOption(DoorConfig,"FloorPW")
  117.     if (pass == nil) then pass = "" else pass = ECAPI.encrypt(pass,networkName()) end
  118.     -- Descriptions are flagged with a * if it's password protected
  119.     ECAPI.broadcast(networkName(),"addFloor|"..whichFloor().."|"..floorDesc().."|"..pass)
  120. end
  121.  
  122. local function powerToggle(whichSide,stateStr)
  123.     local state = false
  124.     if string.lower(stateStr) == "true" then
  125.         state = true
  126.     end
  127.     redstone.setOutput(whichSide,state)
  128. end
  129.  
  130. local function displayFloor(text)
  131.     peripheral.call(displaySide(), "setCursorPos", 1, 1)
  132.     peripheral.call(displaySide(), "setTextScale", 2.2)
  133.     peripheral.call(displaySide(), "write", ECAPI.padLeft(text,3," "))
  134. end
  135.  
  136. local function displayUp(text)
  137.     peripheral.call(displaySide(), "setTextScale", 2.2)
  138.     peripheral.call(displaySide(), "setCursorPos", 3, 2)
  139.     peripheral.call(displaySide(), "write", text)
  140. end
  141.  
  142. local function displayDown(text)
  143.     peripheral.call(displaySide(), "setTextScale", 2.2)
  144.     peripheral.call(displaySide(), "setCursorPos", 3, 2)
  145.     peripheral.call(displaySide(), "write", text)
  146. end
  147.  
  148. local function reconfig(args)
  149.     if (ECAPI.checkPassword(DoorScreen,DoorConfig,"ConfigPW")) then
  150.         local what = args[1]
  151.         if (what == nil) or (what == "") then
  152.             DoorConfig = DefaultConfig
  153.             createNewSettings()
  154.         else
  155.             what = ECAPI.caseCheck(DoorConfig,what)
  156.             if (args[2] == nil) then
  157.                 DoorScreen, DoorConfig = ECAPI.getConfigFromUser(DoorScreen, DoorConfig,what)
  158.             else
  159.                 DoorConfig = ECAPI.setConfigOption(DoorConfig,what,table.concat(args," ",2))
  160.             end
  161.             -- Make sure to SAVE changes
  162.             ECAPI.table_save(DoorConfig,doorSettingsFile)
  163.            
  164.             -- notify the network's Motor controller
  165.             registerFloor()
  166.  
  167.             -- Check if the cabin is present at the end of startup
  168.             if (redstone.getInput(callSide()) == true) then
  169.                 cabinPresent = true
  170.             end
  171.            
  172.         end
  173.     else
  174.         justPrintLine("Invalid password.")
  175.     end
  176. end
  177.  
  178. local function sendFloorPW(sendID)
  179.     ECAPI.send(sendID,'floorpw|'..ECAPI.encrypt(ECAPI.getConfigOption(DoorConfig,'FloorPW'),networkName()))
  180. end
  181.  
  182. -- Control functions
  183.  
  184. local function openDoor()
  185.     --ECAPI.printLine("open door")
  186.     redstone.setOutput(doorSide(),false)
  187. end
  188.  
  189. local function closeDoor()
  190.     --ECAPI.printLine("close door")
  191.     redstone.setOutput(doorSide(),true)
  192. end
  193.  
  194.  
  195. -- ######################################################
  196. -- ##  Settings Functions                              ##
  197. -- ######################################################
  198.  
  199. local function createNewSettings()
  200.     DoorConfig = DefaultConfig
  201.     termClear()
  202.     --DoorScreen = ECAPI.printConfig(DoorConfig,DoorScreen)
  203.  
  204.     -- Confirm settings with the user, then save to file
  205.     DoorScreen = ECAPI.addPrintLine(DoorScreen,"No settings file found.  Setup method:")
  206.     justPrintLine(" 1) Normal Configuration")
  207.     justPrintLine(" 2) Import from Floor")
  208.     local setupMethod = ECAPI.getInput("Which: ")
  209.     if (setupMethod == nil) or (setupMethod == "") then
  210.         setupMethod = 1
  211.     end
  212.     setupMethod = tonumber(setupMethod)
  213.    
  214.     if setupMethod == 1 then
  215.  
  216.         -- To ensure this code plays nice with multiple elevators, Unique network names are required (as best as can)
  217.         DoorScreen, DoorConfig = ECAPI.getConfigFromUser(DoorScreen,DoorConfig,"Network")
  218.         DoorScreen = ECAPI.printConfig(DoorConfig,DoorScreen,"Network")
  219.        
  220.         -- Confirm modem side
  221.         DoorScreen, DoorConfig = ECAPI.getConfigFromUser(DoorScreen,DoorConfig,"Modem")
  222.         DoorScreen = ECAPI.printConfig(DoorConfig,DoorScreen,"Modem")
  223.        
  224.         -- Confirm call input side
  225.         DoorScreen, DoorConfig = ECAPI.getConfigFromUser(DoorScreen,DoorConfig,"Call")
  226.         DoorScreen = ECAPI.printConfig(DoorConfig,DoorScreen,"Call")
  227.        
  228.         -- Confirm detect input side
  229.         DoorScreen, DoorConfig = ECAPI.getConfigFromUser(DoorScreen,DoorConfig,"Detect")
  230.         DoorScreen = ECAPI.printConfig(DoorConfig,DoorScreen,"Detect")
  231.  
  232.         -- Confirm display output side
  233.         DoorScreen, DoorConfig = ECAPI.getConfigFromUser(DoorScreen,DoorConfig,"Display")
  234.         DoorScreen = ECAPI.printConfig(DoorConfig,DoorScreen,"Display")
  235.        
  236.         -- Confirm door output side
  237.         DoorScreen, DoorConfig = ECAPI.getConfigFromUser(DoorScreen,DoorConfig,"Door")
  238.         DoorScreen = ECAPI.printConfig(DoorConfig,DoorScreen,"Door")
  239.  
  240.         -- Confirm floor #
  241.         DoorScreen, DoorConfig = ECAPI.getConfigFromUser(DoorScreen,DoorConfig,"Floor")
  242.         DoorScreen = ECAPI.printConfig(DoorConfig,DoorScreen,"Floor")
  243.  
  244.         -- Confirm floor description
  245.         DoorScreen, DoorConfig = ECAPI.getConfigFromUser(DoorScreen,DoorConfig,"Description")
  246.         DoorScreen = ECAPI.printConfig(DoorConfig,DoorScreen,"Description")
  247.  
  248.         -- Debug output level
  249.         DoorScreen, DoorConfig = ECAPI.getConfigFromUser(DoorScreen,DoorConfig,"Debug")
  250.         DoorScreen = ECAPI.printConfig(DoorConfig,DoorScreen,"Debug")
  251.     else
  252.         -- Still need network name, modem side, and new floor #
  253.  
  254.         -- To ensure this code plays nice with multiple elevators, Unique network names are required (as best as can)
  255.         DoorScreen, DoorConfig = ECAPI.getConfigFromUser(DoorScreen,DoorConfig,"Network")
  256.         DoorScreen = ECAPI.printConfig(DoorConfig,DoorScreen,"Network")
  257.         -- Confirm modem side
  258.         DoorScreen, DoorConfig = ECAPI.getConfigFromUser(DoorScreen,DoorConfig,"Modem")
  259.         DoorScreen = ECAPI.printConfig(DoorConfig,DoorScreen,"Modem")
  260.         -- Confirm floor #
  261.         DoorScreen, DoorConfig = ECAPI.getConfigFromUser(DoorScreen,DoorConfig,"Floor")
  262.         DoorScreen = ECAPI.printConfig(DoorConfig,DoorScreen,"Floor")
  263.        
  264.         -- Now request the info from which floor?
  265.         local sourceFloor = ECAPI.getInput("Source floor? ")
  266.         ECAPI.openModem(modemSide())
  267.         justPrintLine("Broadcasting: setupcopy|"..sourceFloor)
  268.         ECAPI.broadcast(networkName(),"setupcopy|"..sourceFloor)
  269.        
  270.         -- wait until we get the right rednet event
  271.         local setupCopied = false
  272.         local newSetup = { }
  273.         repeat
  274.             local sendID, rawmessage, distance = rednet.receive()
  275.             local packet = ECAPI.explode("|",rawmessage)
  276.             if packet[1] == networkName() then
  277.                 if string.lower(packet[2]) ==     'setupdata'       then
  278.                     newSetup = textutils.unserialize(packet[3])
  279.                     setupCopied = true
  280.                 end
  281.             end
  282.         until setupCopied == true
  283.  
  284.         -- copy the data
  285.         DoorConfig = ECAPI.setConfigOption(DoorConfig,"Call",ECAPI.getConfigOption(newSetup,"Call"))
  286.         DoorConfig = ECAPI.setConfigOption(DoorConfig,"Detect",ECAPI.getConfigOption(newSetup,"Detect"))
  287.         DoorConfig = ECAPI.setConfigOption(DoorConfig,"Display",ECAPI.getConfigOption(newSetup,"Display"))
  288.         DoorConfig = ECAPI.setConfigOption(DoorConfig,"Door",ECAPI.getConfigOption(newSetup,"Door"))
  289.         DoorConfig = ECAPI.setConfigOption(DoorConfig,"Debug",ECAPI.getConfigOption(newSetup,"Debug"))
  290.         DoorConfig = ECAPI.setConfigOption(DoorConfig,"Description",ECAPI.getConfigOption(newSetup,"Description"))
  291.         DoorConfig = ECAPI.setConfigOption(DoorConfig,"FloorPW",ECAPI.getConfigOption(newSetup,"FloorPW"))
  292.         DoorConfig = ECAPI.setConfigOption(DoorConfig,"ConfigPW",ECAPI.getConfigOption(newSetup,"ConfigPW"))
  293.     end
  294.     -- Write to file
  295.     ECAPI.table_save(DoorConfig,doorSettingsFile)
  296.     termClear()
  297.     if (setupMethod == 2) then justPrintLine("Make sure to review CONFIG settings.") end
  298. end
  299.  
  300. local function startupConfirmation()
  301.     -- Check if there's a settings file
  302.     if fs.exists(doorSettingsFile) then
  303.         termClear()
  304.         DoorConfig = ECAPI.table_load(doorSettingsFile)
  305.         ECAPI.verifyConfig(DefaultConfig,DoorConfig)
  306.         termClear()
  307.         DoorScreen = ECAPI.justPrintLine(DoorScreen,"Settings loaded.")
  308.         os.sleep(0.5)
  309.     else
  310.         createNewSettings()
  311.     end
  312.     -- notify the network's Motor controller
  313.    
  314.     registerFloor()
  315.     -- Check if the cabin is present at the end of startup
  316.     if (redstone.getInput(callSide()) == true) then
  317.         cabinPresent = true
  318.     end
  319.    
  320.     -- Close all doors by default
  321.     closeDoor()
  322. end
  323.  
  324.  
  325.  
  326. -- ######################################################
  327. -- ##  Input Actions                                   ##
  328. -- ######################################################
  329.  
  330. -- MAX Topic summary: 36 characters
  331. --                    |-----------------------------------|
  332. local helpTopics = {
  333.     ["reboot"]      = { "Restart this terminal." ,},
  334.     ["clear"]       = { "Refresh the terminal screen." ,},
  335.     ["config"]      = { "Prints the current settings. Will not print",
  336.                         "any set passwords." ,},
  337.     ["reconfig"]    = { "With no parameters, re-run the whole setup.",
  338.                         "RECONFIG [option] to change a single setting",
  339.                         "Note: Reconfig can be password protected via",
  340.                         "the ConfigPW setting. If this password is",
  341.                         "lost, you will need server admin help or be",
  342.                         "forced to recreate the terminal." ,},
  343.     ["broadcast"]   = { "Manually broadcast <message>",},
  344.     ["send"]        = { "Manually send <id> <message>",},
  345.     ["power"]       = { "Manually toggle power <side>",},
  346. }
  347.  
  348. local function printHelp(topic)
  349.     justPrintLine("Help on '"..string.upper(topic).."':")
  350.     local t = helpTopics[topic]
  351.     for _, text in ipairs(t) do
  352.         justPrintLine("  "..text)
  353.     end
  354. end
  355.  
  356. local commands = {
  357.     ["help"] = function (x)
  358.             if (x[1] ~= nil) then
  359.                 printHelp(x[1])
  360.             else
  361.                 justPrintLine("Please use HELP [COMMAND]. ? for Command List")
  362.             end
  363.         end,
  364.     ["reboot"] = function (x) os.reboot() end,
  365.     ["clear"] = function (x) termClear() end,
  366.     ["broadcast"] = function (x)
  367.             DoorScreen = justPrintInfo(DoorScreen,"REDNET",nil,nil,"Broadcast: "..table.concat(x," ",2))
  368.             ECAPI.broadcast(networkName(),table.concat(x," "))
  369.         end,
  370.     ["send"] = function (x)
  371.             DoorScreen = justPrintInfo(DoorScreen,"REDNET",nil,nil,"Send("..tonumber(x[1]).."): "..table.concat(x," ",2))
  372.             ECAPI.send(networkName(),tonumber(x[1]),table.concat(x," ",2))
  373.         end,
  374.    
  375.     ["config"] = function (x)
  376.             justPrintLine("Current Configuration:")
  377.             justPrintLine("-------------------------------")
  378.             ECAPI.printConfig(DoorConfig,DoorScreen)
  379.         end,
  380.     ["reconfig"] = function (x) reconfig(x) end,
  381.  
  382.     ["power"] = function (x) powerToggle(x[1], x[2]) end,
  383. }
  384.  
  385.  
  386. local function printCommands()
  387.     local col = 1
  388.     local row = {}
  389.     for named, _ in pairs(commands) do
  390.         if (col < 5) then row[col] = string.upper(named) end
  391.         col = col + 1
  392.         if (col == 5) then
  393.             justPrintLine(ECAPI.padLeft(row[1],12," ")..ECAPI.padLeft(row[2],12," ")..ECAPI.padLeft(row[3],12," ")..ECAPI.padLeft(row[4],11," "))
  394.             row = {}
  395.             col = 1
  396.         end
  397.     end
  398.     if (col > 1) then
  399.         -- handles 'remainders'
  400.         justPrintLine(ECAPI.padLeft(row[1],12," ")..ECAPI.padLeft(row[2],12," ")..ECAPI.padLeft(row[3],12," ")..ECAPI.padLeft(row[4],11," "))
  401.     end
  402. end
  403.  
  404. local function processCommands(input)  
  405.     local arg = ECAPI.explode(" ",input)
  406.     local command = arg[1]
  407.     table.remove(arg,1)
  408.     if ECAPI.tableContainsKey(commands, command) then
  409.         commands[command](arg)
  410.     else
  411.         justPrintLine("Unknown command '"..command.."'. Commands are:")
  412.         printCommands()
  413.     end
  414. end
  415.  
  416.  
  417.  
  418. -- ######################################################  
  419. -- ##  Handler Functions                               ##
  420. -- ######################################################
  421.  
  422. -- User input listener
  423. local function userConsole()
  424.     while KeepWaiting do
  425.         processCommands(ECAPI.getInput("Command:"))
  426.     end
  427. end
  428.  
  429.  
  430. -- Redstone listener
  431. local function redstoneListener()
  432.     while KeepWaiting do
  433.         event, param1, param2 = os.pullEvent("redstone")
  434.        
  435.         -- The players have pushed a button
  436.         if event == "redstone" and redstone.getInput(callSide()) == true then
  437.             --ECAPI.printLine("Call detection")
  438.             ECAPI.broadcast(networkName(),"call")
  439.         end
  440.        
  441.         -- if the cabin was not present, and we get a redstone on detect side, it just arrived
  442.         if (event == "redstone") and (redstone.getInput(detectSide()) == true) then
  443.             --ECAPI.printLine("Cabin detection")
  444.             cabinPresent = true
  445.             ECAPI.broadcast(networkName(),"arrival|"..whichFloor())
  446.             displayFloor(whichFloor())
  447.         end
  448.        
  449.         -- if the redstone on the detect side shuts off, the cabin just departed
  450.         if (event == "redstone") and (redstone.getInput(detectSide()) == false) then
  451.             --ECAPI.printLine("Cabin departure")
  452.             cabinPresent = false
  453.             ECAPI.broadcast(networkName(),"departure")
  454.         end
  455.     end
  456. end
  457.  
  458. -- Rednet listener
  459. local function rednetListener()
  460.     ECAPI.openModem(modemSide())
  461.     while KeepWaiting do
  462.         local sendID, rawmessage, distance = rednet.receive()
  463.         local packet = ECAPI.explode("|",rawmessage)
  464.         if packet[1] == networkName() then
  465.             --ECAPI.printLine("Message received ["..sendID.."]: "..table.concat(packet,"|",2))
  466.            
  467.             if string.lower(packet[2]) ==     'controlreset'       then
  468.                 -- If the control computer issues a reset broadcast, re-register with it.
  469.                 os.sleep(math.random(2.0,4.0))
  470.                 --ECAPI.printLine("Re-registering")
  471.                 registerFloor()
  472.                 if (redstone.getInput(detectSide()) == true) then
  473.                     -- also call out if the cabin is at this level
  474.                     ECAPI.broadcast(networkName(),"arrival")
  475.                 end
  476.                
  477.             elseif string.lower(packet[2]) == 'opendoor'           then
  478.                 --ECAPI.printLine("open door request "..ECAPI.padLeft(packet[3],5,' ').."?"..os.getComputerID())
  479.                 if packet[3] == tostring(os.getComputerID()) then
  480.                     openDoor()
  481.                 else
  482.                     closeDoor()
  483.                 end
  484.            
  485.             elseif string.lower(packet[2]) == 'closedoor'          then
  486.                 closeDoor()
  487.             elseif string.lower(packet[2]) == 'arrival'           then
  488.                 displayFloor(packet[3])
  489.             elseif string.lower(packet[2]) == 'displayup'           then
  490.                 displayUp(packet[3])
  491.             elseif string.lower(packet[2]) == 'displaydown'           then
  492.                 displayDown(packet[3])
  493.             elseif string.lower(packet[2]) == 'locate'           then
  494.                 if (redstone.getInput(detectSide()) == true) then
  495.                     -- also call out if the cabin is at this level
  496.                     ECAPI.broadcast(networkName(),"arrival")
  497.                 end
  498.             elseif string.lower(packet[2]) == 'reboot'           then
  499.                 os.reboot()
  500.             elseif string.lower(packet[2]) == 'sendpw'           then
  501.                 sendFloorPW(sendID)
  502.             elseif string.lower(packet[2]) == 'setupcopy'       then
  503.                 if tonumber(packet[3]) == whichFloor() then
  504.                     ECAPI.send(networkName(),sendID,'setupdata|'..textutils.serialize(DoorConfig))
  505.                 end
  506.             end
  507.         end
  508.     end
  509. end
  510.  
  511. -- ######################################################
  512. -- ##  Actual Run Program                              ##
  513. -- ######################################################
  514.  
  515. startupConfirmation()
  516. parallel.waitForAll(userConsole,redstoneListener,rednetListener)
  517. --while KeepWaiting do
  518. --  ECAPI.printLine("")
  519. --  processCommands(ECAPI.getInput("Operation:"))
  520. --end
  521.  
  522. --startupConfirmation()
  523. --openModem()
  524. --broadcast("addFloor|1")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement