Advertisement
Tatantyler

CRFv3.1 Modem Emulator

Aug 17th, 2013
543
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 6.21 KB | None | 0 0
  1. -- Modem Emulation Protocol over CRFv3.1, using multicast
  2.  
  3. local fake_modems = {}
  4.  
  5. local open_channels = {}
  6.  
  7. local peripheral_old = {}
  8.  
  9. local listen_all = false -- Should we emit *all* fake modem messages, no matter if we even have a fake modem open to the sending channel?
  10.  
  11. for i,v in pairs(peripheral) do
  12.     peripheral_old[i] = v
  13. end
  14.  
  15. if not LANClient then
  16.     error("The LAN Client API has not loaded yet!")
  17. end
  18.  
  19. LANClient.join_group(2)
  20.  
  21. peripheral.isPresent = function(side)
  22.     if fake_modems[side] ~= nil then
  23.         return true
  24.     end
  25.     return peripheral_old.isPresent(side)
  26. end
  27.  
  28. peripheral.getType = function(side)
  29.     if fake_modems[side] ~= nil then
  30.         return "modem"
  31.     end
  32.     return peripheral_old.getType(side)
  33. end
  34.  
  35. peripheral.getMethods = function(side)
  36.     if fake_modems[side] ~= nil then
  37.         return {"isOpen", "open", "close", "closeAll", "transmit", "isWireless"}
  38.     end
  39.     return peripheral_old.getMethods(side)
  40. end
  41.  
  42. peripheral.call = function(side, method, ...)
  43.     local args = {...}
  44.     if fake_modems[side] ~= nil then
  45.         if fake_modems[side][method] then
  46.             return fake_modems[side][method](unpack(args))
  47.         end
  48.     end
  49.     return peripheral_old.call(side, method, unpack(args))
  50. end
  51.  
  52. peripheral.getNames = function()
  53.     local names = peripheral_old.getNames()
  54.     for i,v in pairs(fake_modems) do
  55.         table.insert(names, i)
  56.     end
  57.     return names
  58. end
  59.  
  60. peripheral.wrap = function(side)
  61.     if fake_modems[side] ~= nil then
  62.         return fake_modems[side] -- we're trusting the caller to not screw with the modem object
  63.     end
  64.     return peripheral_old.wrap(side)
  65. end
  66.  
  67. function backgroundListener()
  68.     while true do
  69.         local sender, msg = LANClient.receive()
  70.         local data = textutils.unserialize(msg)
  71.         if type(data) == "table" then
  72.             --print("Got a message from "..sender)
  73.             if data[1] == "ModemEmulator" then
  74.                 local sCh = tonumber(data[2])
  75.                 local rCh = tonumber(data[3])
  76.                 local modemData = data[4]
  77.                 --[[
  78.                 print("Got a fake modem message from "..sender)
  79.                 print("sch: "..sCh.." type: "..type(sCh))
  80.                 print("rch: "..rCh.." type: "..type(rCh))
  81.                 print("data: "..modemData)
  82.                 local foundSide = false
  83.                 ]]
  84.                 if open_channels[sCh] then
  85.                     local side = next(fake_modems) -- Get the first modem we find
  86.                     os.queueEvent("modem_message", side, sCh, rCh, modemData, 0)
  87.                     --print("side: "..side)
  88.                 elseif listen_all then -- fuck it, emit as an obviously fake event
  89.                     os.queueEvent("modem_message", "listen_all", sCh, rCh, modemData, 0)
  90.                     --print("side: listen_all")
  91.                 end
  92.             end
  93.         end
  94.     end
  95. end
  96.  
  97. local function create_fake_modem()
  98.     local modem = {
  99.         channels = {},
  100.         isWireless = function() return true end,
  101.         isFake = function() return true end,
  102.     }
  103.     modem.transmit = function(channel, replyChannel, data)
  104.         LANClient.send(-2, textutils.serialize({"ModemEmulator", channel, replyChannel, data}))
  105.     end
  106.     modem.isOpen = function(channel)
  107.         if open_channels[channel] then
  108.             --print("open_channels["..channel.."] :"..open_channels[channel])
  109.             return true
  110.         end
  111.         return false
  112.     end
  113.     modem.open = function(channel)
  114.         --print("ch: "..channel.." type: "..type(channel))
  115.         if open_channels[channel] then
  116.             open_channels[channel] = open_channels[channel]+1
  117.         else
  118.             open_channels[channel] = 1
  119.         end
  120.         --print("open_channels["..channel.."] :"..open_channels[channel])
  121.         modem.channels[channel] = true
  122.     end
  123.     modem.close = function(channel)
  124.         if open_channels[channel] then
  125.             open_channels[channel] = open_channels[channel]-1
  126.             if open_channels[channel] <= 0 then
  127.                 open_channels[channel] = nil
  128.             end
  129.             modem.channels[channel] = nil
  130.         end
  131.     end
  132.     modem.closeAll = function()
  133.         local copy = {}
  134.         for i,v in pairs(modem.channels) do
  135.             copy[i] = v
  136.         end
  137.         for i,v in pairs(copy) do
  138.             modem.close(i)
  139.         end
  140.     end
  141.     return modem
  142. end
  143.  
  144. function register_modem(side)
  145.     if peripheral.isPresent(side) then
  146.         return false
  147.     end
  148.     fake_modems[side] = create_fake_modem()
  149.     return true
  150. end
  151.  
  152. function unregister_modem(side)
  153.     if fake_modems[side] then
  154.         fake_modems[side] = nil
  155.     else
  156.         return false
  157.     end
  158.     return true
  159. end
  160.  
  161. function get_all_listen()
  162.     return listen_all
  163. end
  164.  
  165. function toggle_all_listen()
  166.     listen_all = not listen_all
  167.     return listen_all
  168. end
  169.  
  170. function get_open_channels()
  171.     return open_channels
  172. end
  173.  
  174. if shell then
  175.     local file = fs.open(shell.getRunningProgram(), "r")
  176.     if file then
  177.         local l = file.readLine()
  178.         file.close()
  179.         if string.match(l, "Modem Emulation Protocol") then
  180.             if not modem_emulator then -- The API's useless if the background function isn't running
  181.                 error("The modem_emulator API has not loaded yet!")
  182.             end
  183.             local args = {...}
  184.             if #args == 2 then
  185.                 if args[1] == "register" then
  186.                     if register_modem(args[2]) then
  187.                         print("Virtual modem successfully created.")
  188.                     else
  189.                         print("A peripheral already exists there.")
  190.                     end
  191.                 elseif args[1] == "unregister" then
  192.                     if unregister_modem(args[2]) then
  193.                         print("Virtual modem successfully deleted.")
  194.                     else
  195.                         print("No peripheral exists there.")
  196.                     end
  197.                 end
  198.             elseif (#args == 1) and (args[1] == "listen_all") then
  199.                 if toggle_all_listen() then
  200.                     print("All-Listen enabled.")
  201.                 else
  202.                     print("All-Listen disabled.")
  203.                 end
  204.             else
  205.                 print("modem_emulator -- Modem emulator API and interface")
  206.                 print(string.rep("-", term.getSize()))
  207.                 print("Usage: modem_emulator [action] [side]")
  208.                 print("Actions:")
  209.                 print("register (\"modem_emulator register [side]\"): Create a new virtual modem.")
  210.                 print("unregister (\"modem_emulator unregister [side]\"): Delete a virtual modem.")
  211.                 print("listen_all (\"modem_emulator listen_all\"): Toggle listen state; when on, then we emit all events regardless of whether we have a modem opened to the sending channel.")
  212.             end
  213.         end
  214.     end
  215. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement