Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --[[
- Turtle Input Output System (Working name)
- Takes in a string of basic commands and executes them
- All commands are two characters long
- On command start up
- Max command string length of 256?
- Max instruction length of 99 (jump instructions)
- Keeps list of blocks in inventory
- Slot 1 is reserved for onboard fuel
- Keeps list of functions in this script
- Turns command string into function ID and number in a list
- -example-
- command string
- "CFMF10TR1DF1" or "cfmf10tr1df1"
- function ID and number list
- 1 {cf,-1}
- 2 {mf, 10}
- 3 {tr, 1}
- 4 {df, 1}
- Calling a variable followed by a number x will set the variable to that number
- -example-
- "L110" will set variable N1 to 10
- Command IDs (x represents number input (Min 0, Max 99), v represents an variable)
- In format of Command String - Description
- --Movement--
- MF - Move forward
- MU - Move upward
- MD - Move downward
- MB - Move backward
- TR - Turn right
- TL - Turn left
- --Digging--
- DU - Dig up
- DD - Dig down
- DF - Dig forward
- DA - Dig down, forward, and up
- --Inspecting blocks--
- IUvx - Detect up, if something found then set v to x
- IIvx - Detect forward, if something found then set v to x (IF is reserved by lua)
- IDvx - Detect down, if something found then set v to x
- IAvx - Detect all, if something found then set v to x
- --Compairing blocks--
- CUvx - Compare up, if block matches selected block then set v to x
- CFvx - Compare forward, if block matches selected block then set v to x
- CDvx - Compare down, if block matches selected block then set v to x
- CAvx - Compare all, if any block matches selected block then set v to x
- --Placing blocks--
- PF - Place selected block forward
- PU - Place block upward
- PD - Place block downward
- --Dropping items--
- TF - Drop forward items from selected slot
- TU - Drop upward items from selected slot
- TD - Drop downward items from selected slot
- --Status packets (Not implimented yet)--
- SI - Send a packet back to a server with the current inventory
- SF - Send a packet back to a server with current fuel level
- SG - Send a packet back to a server with current GPS location and facing
- SE - Send a packet back to a server saying instructions completed (Maybe do automatically)
- --Misc--
- ED - Add current instruction to the call stack
- HT - Halt instruction, ends program
- RT - Go to instuction at top of callstack, pop callstack
- RF - Refuel the turtle using fuel in current slot
- TI - Takes inventory of current blocks and items and updates inventory list
- SSx - Selects the slot with ID of x
- WTx - Waits for x number of seconds
- FAx - Adds x to top of function stack (used to load in function)
- INv - If v is 0 then set to 1, otherwise set to 0
- CSvx - Checks slot x for items, if items exist then set v to 1 otherwise set v to 0
- --Jump instructions--
- JIx - Jump to instruction x
- FJx - Jump to instruction stored in function array at index x, add current instruction + 1 to call stack
- LJvx - Jump to instruction on top of stack unless v is x, also reduces v by 1 when jumping
- BJvx - Jump to instruction on top of stack unless v is false/0
- --Maths--
- SUvx - Subtract x from v
- ADvx - Add x to v
- --Variables--
- E1 - Number of spaces left in inventory
- I1 - current instruction
- B1-9 - Boolean value, 0 for false and 1 for true
- A1 - Array of numbers, used to store a set of data to return as a packet later
- N1-9 - Holds a number from 0 to 99
- --]]
- --[[
- All data packets have a set structure made of four sections
- First Section - IP Address of target system
- Second Section - IP Address of sending system
- Third Section - Type of packet being sent (what protocol does packet follow)
- Fourth Section - The main data the packet is transporting
- For testing, the IP address will be the same as the device ID.
- In the future this will be changed to allow for proper routing and
- security measures.
- The protocol the packet follows is a string in all caps
- (CDP,ERP,DRP,UPP,etc) to allow for universal understanding (and style)
- An IP address of 0 for the target system means that the packet is for
- the router to work with. Trying to assign a different device this IP will fail
- as the router will intercept all packets with that IP.
- --]]
- --Variables
- local networkDeviceSide = "left" --Change this to where network device is
- deviceType = "turtle"
- tIOSversion = "2.3.2"
- ipAddress = {-1,-1,-1}
- routerID = -1 --The computer ID of the router, allowing for responses to be returned
- message = {}
- packet = {}
- localFunctions = {}
- local instructionCount = 1
- local turtleInventory = {}
- local serverIP = {-1,-1,-1}
- local callStack = {}
- local functionStack = {}
- local variablesList = {
- e1 = 0,
- i1 = 0,
- b1 = 0,
- b2 = 0,
- b3 = 0,
- b4 = 0,
- b5 = 0,
- b6 = 0,
- b7 = 0,
- b8 = 0,
- b9 = 0,
- a1 = {},
- n1 = 0,
- n2 = 0,
- n3 = 0,
- n4 = 0,
- n5 = 0,
- n6 = 0,
- n7 = 0,
- n8 = 0,
- n9 = 0
- }
- local function sendPacket (
- targetIP, --Table
- protocol, --String
- data --Any
- )
- --[[
- This function sends a packet to an IP address in the network.
- Each packet needs to follow the rules of packet construction.
- If the target IP is 0 then the packet will be sent to the default router.
- If the sending IP is -1 then that means the IP hasn't been set yet
- and will need to be to recieve packets from devices other than the router.
- --]]
- --Checking if there is a default router to send packet to, otherwise skip all code
- if routerID == -1 then
- print("Default router not set")
- goto skip
- end
- --Checking if packet components have the right data types, otherwise skip all code
- if not (type(targetIP) == "table") or not (type(protocol) == "string") then
- print("Improperly formatted packet")
- goto skip
- end
- --Packet construction
- local packet = {
- targetIP,
- ipAddress,
- protocol,
- data
- }
- --Sending packet
- print(targetIP[1].."."..targetIP[2].."."..targetIP[3] .. " " .. ipAddress[1].."."..ipAddress[2].."."..ipAddress[3] .. " " .. protocol .. " " .. type(data))
- rednet.send(routerID,packet)
- ::skip::
- end
- local function digAll()
- turtle.digDown()
- turtle.dig()
- turtle.digUp()
- end
- local function takeInventory ()
- variablesList["e1"] = 0
- turtleInventory = {}
- local itemInfo = {}
- for i = 1, 16, 1 do
- itemInfo = turtle.getItemDetail(i,true)
- table.insert(turtleInventory,itemInfo)
- if(itemInfo == nil) then
- variablesList["e1"] = variablesList["e1"] + 1
- end
- end
- end
- local function addToCallStack ()
- table.insert(callStack,instructionCount)
- end
- local function returnTo()
- instructionCount = callStack[#callStack]
- table.remove(callStack,#callStack)
- end
- local function sendInventory()
- sendPacket(serverIP,"DP",{"inventory",turtleInventory})
- end
- local function sendFuelLevel()
- sendPacket(serverIP,"DP",{"fuel",turtle.getFuelLevel()})
- end
- local function sendGPS()
- sendPacket(serverIP,"DP",{"gps",gps.locate()})
- end
- local function sendIntructionComplete()
- sendPacket(serverIP,"DP",{"intruction","Completed"})
- end
- local function jumpTo(count)
- instructionCount = count
- end
- local function functionJump(count)
- table.insert(callStack,instructionCount+1)
- instructionCount = functionStack[count]
- end
- local function functionAdd(count)
- table.insert(functionStack,count)
- end
- local function loopJump(varName,count)
- if variablesList[varName] > count and #callStack > 0 then
- instructionCount = callStack[#callStack]
- variablesList[varName] = variablesList[varName] - 1
- elseif #callStack > 0 then
- table.remove(callStack,#callStack)
- end
- end
- local function boolJump(varName,count)
- if variablesList[varName] > 0 then
- instructionCount = callStack[#callStack]
- else
- table.remove(callStack,#callStack)
- end
- end
- local function detectUp(varName,count)
- if turtle.detectUp() then
- variablesList[varName] = count
- end
- end
- local function detectFront(varName,count)
- if turtle.detect() then
- variablesList[varName] = count
- end
- end
- local function detectDown(varName,count)
- if turtle.detectDown() then
- variablesList[varName] = count
- end
- end
- local function detectAll(varName,count)
- if (turtle.detectUp() or turtle.detect() or turtle.detectDown()) then
- variablesList[varName] = count
- end
- end
- local function compareUp(varName,count)
- if turtle.compareUp() then
- variablesList[varName] = count
- end
- end
- local function compareFront(varName,count)
- if turtle.compare() then
- variablesList[varName] = count
- end
- end
- local function compareDown(varName,count)
- if turtle.compareDown() then
- variablesList[varName] = count
- end
- end
- local function compareAll(varName,count)
- if (turtle.compareUp() or turtle.compare() or turtle.compareDown()) then
- variablesList[varName] = count
- end
- end
- local function addTo(varName,count)
- varName = varName + count
- end
- local function subFrom(varName,count)
- varName = varName - count
- end
- local function checkSlot(varName,count)
- inventoryInfo = turtle.getItemDetail(count)
- if inventoryInfo == nil then
- varName = 0
- else
- varName = 1
- end
- end
- --Holds all of the basic turtle functions we may need
- local basicInstructionsDict = {
- mf = turtle.forward,
- mu = turtle.up,
- md = turtle.down,
- mb = turtle.back,
- tr = turtle.turnRight,
- tl = turtle.turnLeft,
- du = turtle.digUp,
- dd = turtle.digDown,
- df = turtle.dig,
- da = digAll,
- pf = turtle.place,
- pu = turtle.placeUp,
- pd = turtle.placeDown,
- tf = turtle.drop,
- tu = turtle.dropUp,
- td = turtle.dropDown,
- rf = turtle.refuel,
- ti = takeInventory,
- ed = addToCallStack,
- rt = returnTo,
- si = sendInventory,
- sf = sendFuelLevel,
- sg = sendGPS,
- se = sendIntructionComplete
- }
- --One Argument Instructions
- local advancedInstructionsDict = {
- --si = , Uses networking functions combine with existing network code
- --sf = ,
- --sg = ,
- --se = ,
- ss = turtle.select,
- wt = sleep,
- fj = functionJump,
- ji = jumpTo,
- pp = print,
- fa = functionAdd
- }
- --Two Argument Instructions
- local veryAdvancedInstructionsDict = {
- lj = loopJump,
- bj = boolJump,
- iu = detectUp,
- ii = detectFront,
- id = detectDown,
- ia = detectAll,
- cu = compareUp,
- cf = compareFront,
- cd = compareDown,
- ca = compareAll,
- su = addTo,
- ad = subFrom,
- cs = checkSlot
- }
- local function instructionExecuter(instructionSet)
- instructionCount = 1
- while instructionCount <= #instructionSet do
- --for instructionCount = 1, #instructionSet, 1 do
- local instruction = instructionSet[instructionCount]
- --Checking for halt instruction
- if instruction == "ht" then
- goto breaking
- end
- --Checking functions
- if basicInstructionsDict[instruction] then
- --If instruction is basic then run it
- basicInstructionsDict[instruction]()
- elseif advancedInstructionsDict[instruction] then
- --If instruction is advanced then run it, the next instruction should be an argument
- --Index instructionCount one more time to account for argument
- instructionCount = instructionCount + 1
- if variablesList[instructionSet[instructionCount]] then
- advancedInstructionsDict[instruction](variablesList[instructionSet[instructionCount]])
- else
- advancedInstructionsDict[instruction](tonumber(instructionSet[instructionCount]))
- end
- elseif veryAdvancedInstructionsDict[instruction] then
- --If instruction is very advanced then run it, the next two instructions should be arguments
- instructionCount = instructionCount + 2
- if variablesList[instructionSet[instructionCount]] then
- veryAdvancedInstructionsDict[instruction](
- instructionSet[instructionCount-1],
- variablesList[instructionSet[instructionCount]]
- )
- else
- veryAdvancedInstructionsDict[instruction](
- instructionSet[instructionCount-1],
- tonumber(instructionSet[instructionCount])
- )
- end
- elseif variablesList[instruction] then
- --Checking variables
- --If variable then set variable equal to next argument
- instructionCount = instructionCount + 1
- if variablesList[instructionSet[instructionCount]] then
- variablesList[instruction] = variablesList[instructionSet[instructionCount]]
- else
- variablesList[instruction] = tonumber(instructionSet[instructionCount])
- end
- end
- instructionCount = instructionCount + 1
- variablesList["i1"] = instructionCount
- end
- ::breaking::
- --Resetting the variables back to 0
- local variablesList = {
- e1 = 0,
- i1 = 0,
- b1 = 0,
- b2 = 0,
- b3 = 0,
- b4 = 0,
- b5 = 0,
- b6 = 0,
- b7 = 0,
- b8 = 0,
- b9 = 0,
- a1 = {},
- n1 = 0,
- n2 = 0,
- n3 = 0,
- n4 = 0,
- n5 = 0,
- n6 = 0,
- n7 = 0,
- n8 = 0,
- n9 = 0
- }
- end
- local function commandStringParser(commandString)
- local tempString = ""
- local instructionSet = {}
- for i = 1, #commandString, 1 do
- tempString = tempString .. string.sub(commandString,i,i)
- if math.fmod(i,2) == 0 then
- table.insert(instructionSet,tempString)
- --print(tempString)
- tempString = ""
- end
- end
- return instructionSet
- end
- local function responseRDP ()
- --[[
- Router Discovery Protocol
- Used by a router to discover other routers and build up a internetwork routing table.
- After recieving a routing table, start adding it to router routing table
- Routing table info:
- 1 - IP of router
- 2 - ID of next hop
- 3 - IP of next hop? (for future tracert)
- 4 - Number of hops to IP (To find shortest route)
- Routers will not have themselves on their own routing tables
- --]]
- end
- local function responseCDP ()
- --[[
- Computer Discovery Protocol
- Used by a router to discover devices on the network then assign them IP addresses
- and set itself as the device's default router. Devices already with an IP and
- default router do not respond to CDP packets to avoid confusion on the side of
- the router.
- --]]
- --If the device already has an IP and assigned Router then skip all code
- if not (ipAddress == -1) and not (routerID == -1) then goto skip end
- --Sets the device's default router to the device ID that sent the packet
- routerID = message[1]
- --Send CDP packet to router (IP 0) with the ID of the device
- sendPacket({0,0,0},"CDP",os.getComputerID())
- --An IP packet should be sent in the near future to this device to assign IP
- ::skip::
- end
- local function responseERP ()
- --[[
- Echo Request Protocol is used to see if an IP address is responding.
- Sending an ERP packet will cause the device to send a return packet back to the
- source device.
- --]]
- if packet[4] == "Ping" then
- sendPacket(packet[2],"ERP","pong")
- end
- end
- local function responseDRP ()
- --Device Request Protocol
- sendPacket(packet[2],"DRP",deviceType)
- end
- local function responseUPP ()
- --Unknown Packet Protocol
- end
- local function responseIP ()
- --[[
- Internet Protocol
- Used by router to give a device an IP address. Will only be accepted if the
- router is the default router the device knows. If the default router is
- unassigned then the IP packet is dropped. The data on the packet should
- be a number.
- --]]
- --Checking if routerID is assigned
- print(routerID)
- if routerID == -1 then goto skip end
- --Checking if routerID is the same as the message sender
- if not (routerID == message[1]) then goto skip end
- --Setting the IP of the device to the one sent by the router
- ipAddress = packet[4]
- --Sending IP packet with the device type to the router
- sendPacket({0,0,0},"IP",deviceType)
- ::skip::
- end
- local function responseDP ()
- --Data Packet (How to respond to generic data packets)
- print("Instruct: " .. packet[4])
- serverIP = packet[2]
- instructionExecuter(commandStringParser(packet[4]))
- end
- local function responseAP ()
- --Acknowledgement Packet
- end
- function mainLoop ()
- --This function runs continuously and allows the device to respond to requests and packets
- while true do
- print("Ready to recieve message")
- --Wait until rednet message recieved
- message = {rednet.receive()}
- --Pulling out the packet inside of the message
- packet = (message[2])
- --Checking if packet is properly formatted, if it is not then drop packet and continue loop
- if #packet < 4 then goto continue end
- if not (packet[3] == "CDP") then
- print("Packet Type: " .. packet[3])
- end
- if localFunctions["response"..packet[3]] then
- --If protocol exists
- if not (packet[3] == "CDP") then
- print("Running response "..packet[3])
- end
- localFunctions["response"..packet[3]]()
- --table.insert(dataQueue,packet)
- else
- --Send UPP packet to source device if protocol is unknown
- print("Unknown")
- sendPacket(packet[1],"UPP","Unknown Packet Type: "..packet[3])
- end
- --]]
- ::continue::
- --End of cycle upkeep
- --Resetting last received message and packet back to their default states
- message = {}
- packet = {}
- end
- end
- --Finding all of the local functions and storing them
- index = 1
- while true do
- key, data = debug.getlocal(1,index)
- if not key then break end
- --print(key)
- if type(data) == "function" then
- if debug.getinfo(data, "S").what == "Lua" then
- localFunctions[key] = data
- end
- end
- index = index + 1
- end
- --Turning on the network capabilities of the device
- peripheralNames = peripheral.getNames()
- for i = 1, #peripheralNames, 1 do
- if peripheral.hasType(peripheralNames[i],"modem") then
- rednet.open(peripheralNames[i])
- end
- end
- --Calling the mainLoop to start program
- print("tIOS version: v"..tIOSversion)
- print("Starting mainLoop")
- mainLoop()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement