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

[help]wireless peripheral api

Started by KingofGamesYami, 06 May 2014 - 08:30 PM
KingofGamesYami #1
Posted 06 May 2014 - 10:30 PM
I've decided (because of pocket computers) to create an api that allows you to control peripherals wirelessly through a "slave" computer. I would like to know how peripherals work, and how I would overwrite them the way I want (meaning: I want to keep the same commands).

I currently have:

main

local modem = peripheral.wrap("top")

oldos = {}
for k, v in pairs(os) do
	oldos[k] = v
end
function os.pullEventRaw(...)
	local args = {...}
	if args[1] == "wpe" then
		event = oldos.pullEvent("modem_message")
		if type(event[5]) == "table" and event[5][1] == "wpe" then
			return unpack(event[5][2])
		else
			return os.pullEventRaw(unpack(args))
		end
	else
		local event = {oldos.pullEventRaw(unpack(args))}
	end
 	if event[1] == "modem_message" and type(event[5]) == "table" and event[5][1] == "wpe" and (#args == 0 or (#args = 1 and args[1] = "wpe")) then
  		return unpack(event[5][2])
	else
 		return unpack(event)
 	end
end

function setModem(side)
	modem = peripheral.wrap(side)
end

function wrap(side, channela, channelb)
	local per, call = {
	side = side,
	channela = channela,
	channelb = channelb,
}, {}
	modem.transmit(channela, channelb, side)
	modem.open(channela)
	msg = {os.pullEvent("modem_message")}
	for k, v in pairs(msg[4]) do
		call[k] = function(...)
			modem.transmit(channela, channelb, {side = side, call = v, params = {...}})
			return ({os.pullEvent("modem_message")})[4]
		end
	end
	setmetatable(per, {__index = call})
	return per
end
and
slave

local args = {...}
if #args < 3 then
	error("incomplete arguments")
elseif #args > 3 then
	error("too many arguments")
elseif type(args[1]) ~= "string" or type(args[2]) ~= "string" or type(args[3]) ~= "string" then
	error("One or more of your arguments isn't a string!")
end

local valid = false
for i = 1, 6 do
	if args[3] == ({rs.getSides()})[i] then
		valid = true
	end
end
if not valid then
	error("side is not valid")
end

local modem = peripheral.wrap(args[3])
modem.open(args[1])

while true do
	event = {os.pullEvent()}
	if event[1] == "modem_message" and type(event[5]) == "table" then
		local response = peripheral.call(event[5].side, event[5].call, event[5].params)
                modem.transmit(args[1], args[2], response)
	elseif event[1] == "modem_message" and type(event[5]) == "string"
		modem.transmit(args[1], args[2], peripheral.wrap(event[5]))
	else
		modem.transmit(args[1], args[2], {"wpe", event})
	end
end
Note: a &amp; b are undefined for now… I'm not sure if I will have the user set them or if they will be pre-determined.
Edited on 07 May 2014 - 08:35 PM
CometWolf #2
Posted 06 May 2014 - 10:57 PM
I've never done such a thing myself, but i'd imagine it's pretty simple. One thing i noted with your code, was how you try to create the new peripheral function table.

	    for k, v in pairs(msg[4]) do
			    per[k] = modem.transmit(channela, channelb, v)
	    end
This won't work, as you're storing the result of modem.transmit in per[k], not an actual function.

	    for k, v in pairs(msg[4]) do
			    per[k] = function(...)
				  modem.transmit(channela, channelb, {call = v,params = {...}})
				  return {os.pullEvent("modem_message")}[5]
			    end
	    end
Obviously you'd want some timeout, connection confirm and id confirmation on this stuff aswell, but you get the idea. It needs to be a function
KingofGamesYami #3
Posted 06 May 2014 - 11:52 PM
I've never done such a thing myself, but i'd imagine it's pretty simple. One thing i noted with your code, was how you try to create the new peripheral function table.

		for k, v in pairs(msg[4]) do
				per[k] = modem.transmit(channela, channelb, v)
		end
This won't work, as you're storing the result of modem.transmit in per[k], not an actual function.

		for k, v in pairs(msg[4]) do
				per[k] = function(...)
				  modem.transmit(channela, channelb, {call = v,params = {...}})
				  return {os.pullEvent("modem_message")}[5]
				end
		end
Obviously you'd want some timeout, connection confirm and id confirmation on this stuff aswell, but you get the idea. It needs to be a function
Thanks for the hint! I have some experience overwriting an api, as I did create a TurtleTracker with a "returnHome" function.
I don't think it's complicated, but the modem_message part is the most difficult.
PS: is there a way to check if the request timed out? I know you do os.pullEvent("modem_message", 5) for a 5 sec wait, but I want my code to error when it doesn't get a response in that amount of time.
Edited on 06 May 2014 - 09:54 PM
HometownPotato #4
Posted 07 May 2014 - 12:01 AM
You may want to change 'return {os.pullEvent("modem_message")}[5]' to ' 'return ({os.pullEvent("modem_message")})[5]' since I always seem to have problems in all versions of Lua doing {…}[x] as opposed to ({…})[x]

Yeah, I meant change sorry.
Edited on 06 May 2014 - 10:27 PM
KingofGamesYami #5
Posted 07 May 2014 - 12:13 AM
You may want to chance 'return {os.pullEvent("modem_message")}[5]' to ' 'return ({os.pullEvent("modem_message")})[5]' since I always seem to have problems in all versions of Lua doing {…}[x] as opposed to ({…})[x]
I'm going to assume you ment change instead of chance, and thanks for the advice.

What I really need now is how to tell the slave which wrapped peripheral it should use… or rather how to get the info out of this example:


mon = wp.wrap("right", 10, 10)
mon.write("hello") --how do I get that this is calling the peripheral associated with "right" on the 10 frequency?
Edited on 06 May 2014 - 10:18 PM
Bomb Bloke #6
Posted 07 May 2014 - 12:40 AM
In the "wrap" function, before you added in your remote-call functions, you might do this:

per.side = side
per.channela = channela
per.channelb = channelb

Now that data should be accessible via self.
KingofGamesYami #7
Posted 07 May 2014 - 12:45 AM
In the "wrap" function, before you added in your remote-call functions, you might do this:

per.side = side
per.channela = channela
per.channelb = channelb

Now that data should be accessible via self.
ugh… I thought to use self you had to use

per = {
command = function(self) --#do stuff 
end
}
per:command()
but then, thats what I get from teaching myself by looking at other peoples code (Lyqyd's touchpoint api)
edit: updated wrap function

function wrap(side, channela, channelb)
	local per = {
	side = side,
	channela = channela,
	channelb = channelb,
}
	modem.open(channelb)
	modem.transmit(channela, channelb, side)
	msg = {os.pullEvent("modem_message")}
	for k, v in pairs(msg[4]) do
		per[k] = function(...)
			modem.transmit(channela, channelb, {call = v, params = {...}})
			return ({os.pullEvent("modem_message")})[4]
		end
	end
	return per
end
Edited on 06 May 2014 - 10:52 PM
Bomb Bloke #8
Posted 07 May 2014 - 01:06 AM
Something like that. Or "per.command(per)".

Also;

        for k, v in pairs(msg[4]) do
                per[k] = function(self, ...)
                        modem.transmit(self.channela, self.channelb, {call = self.side, params = {...}})
                        return ({os.pullEvent("modem_message")})[4]
                end
        end

Or some such thing. I must confess this isn't something I've tried (at least in Lua). You'll need to tweak your slave's wrapping code, by the way - it doesn't seem to properly make use of what's sent to it. Or you could just forget about wrapping things on the slave side and just use peripheral.call for everything. Yeah, probably go with that.

I suspect metatables might offer something more to your liking here, but if so I'll leave the explanation to someone with more experience in the area.
KingofGamesYami #9
Posted 07 May 2014 - 01:37 AM
Something like that. Or "per.command(per)".

Also;

        for k, v in pairs(msg[4]) do
                per[k] = function(self, ...)
                        modem.transmit(self.channela, self.channelb, {call = self.side, params = {...}})
                        return ({os.pullEvent("modem_message")})[4]
                end
        end

Or some such thing. I must confess this isn't something I've tried (at least in Lua). You'll need to tweak your slave's wrapping code, by the way - it doesn't seem to properly make use of what's sent to it. Or you could just forget about wrapping things on the slave side and just use peripheral.call for everything. Yeah, probably go with that.

I suspect metatables might offer something more to your liking here, but if so I'll leave the explanation to someone with more experience in the area.
I've been updating the slave, just haven't posted what I have (yet). I know how/what a metatable is/does whatever, and it would be a better idea in this case I think.

edit:

setmetatable(per, {__index = msg[4]})
something like this?

nevermind… with that, I wouldn't be able to add the fact that it is sending/recieving a message.
Edited on 06 May 2014 - 11:43 PM
KingofGamesYami #10
Posted 07 May 2014 - 02:04 AM
I just thought of this… How would one get a "mouse_click" event with this? The program needs something that constantly checks for updates from the slave, but I don't want to screw up someone's program by making them use parallel and creating a "waitforevent" function.
Edited on 07 May 2014 - 12:06 AM
Bomb Bloke #11
Posted 07 May 2014 - 02:25 AM
It's either a co-routine, or you implement a customised os.pullEvent() function.

For example: You're probably aware that the RedNet API is a wrapper for the API available to modems. When you send a modem message, a rednet message event also gets generated.

This is done by a function in the rednet API that sits there waiting for modem messages to come in. When it spots one, it generates a corresponding rednet event. When a given computer boots, it runs this function in parallel with the shell, so that rednet API function is loaded and active at all times (regardless as to whether the system even has a modem).

In your case, you'd likely find it easier to embed two functions in your API: one which overrides os.pullEvent(), and one that restores the original version of os.pullEvent(). The override would basically call the original function, check to see whether the incoming event was a peripheral-related modem message, and if so queue a related "spoof" event (returning the received event unaltered if not).
KingofGamesYami #12
Posted 07 May 2014 - 02:37 AM
It's either a co-routine, or you implement a customised os.pullEvent() function.

For example: You're probably aware that the RedNet API is a wrapper for the API available to modems. When you send a modem message, a rednet message event also gets generated.

This is done by a function in the rednet API that sits there waiting for modem messages to come in. When it spots one, it generates a corresponding rednet event. When a given computer boots, it runs this function in parallel with the shell, so that rednet API function is loaded and active at all times (regardless as to whether the system even has a modem).

In your case, you'd likely find it easier to embed two functions in your API: one which overrides os.pullEvent(), and one that restores the original version of os.pullEvent(). The override would basically call the original function, check to see whether the incoming event was a peripheral-related modem message, and if so queue a related "spoof" event (returning the received event unaltered if not).
something like

oldos = {}
for k, v in pairs(os) do
 oldos[k] = v
end
function os.pullEvent()
 event = {oldos.pullEvent()}
 if event[1] == "modem_message" and event[5][1] == "wpe" then
  return unpack(event[5][2])
 else
  return unpack(event)
 end
end
Edited on 07 May 2014 - 12:37 AM
Bomb Bloke #13
Posted 07 May 2014 - 03:49 AM
Something like that. You wouldn't need to backup all the pointers in "os" (just os.pullEvent), you'd require an additional check to ensure event[5] is a table before trying to index into it, and you'd need to account for event filters.
KingofGamesYami #14
Posted 07 May 2014 - 12:51 PM
Something like that. You wouldn't need to backup all the pointers in "os" (just os.pullEvent), you'd require an additional check to ensure event[5] is a table before trying to index into it, and you'd need to account for event filters.
Would I also need to overwrite os.pullEventRaw? some programs will use it.


oldos = {}
for k, v in pairs(os) do
	oldos[k] = v
end
function os.pullEvent(...)
	local args = {...}
	if args[1] == "wpe" then
		event = oldos.pullEvent("modem_message")
		if type(event[5]) == "table" and event[5][1] == "wpe" then
			return unpack(event[5][2])
		else
			return os.pullEvent(unpack(args))
		end
	else
		local event = {oldos.pullEvent(unpack(args))}
	end
 	if event[1] == "modem_message" and type(event[5]) == "table" and event[5][1] == "wpe" and (#args == 0 or (#args = 1 and args[1] = "wpe")) then
  		return unpack(event[5][2])
	else
 		return unpack(event)
 	end
end
Edited on 07 May 2014 - 11:01 AM
Bomb Bloke #15
Posted 07 May 2014 - 01:03 PM
That entirely up to you. If you do so, however, then there's no need to override os.pullEvent (as that also uses os.pullEventRaw - os.pullEvent only really exists to do this same sort of thing; it looks for a certain event ("terminate") and performs a special action when it spots it ("kills your script")).
KingofGamesYami #16
Posted 07 May 2014 - 01:10 PM
If I overwrite os.pullEventRaw, and do this:

return os.pullEventRaw(unpack(args))
will this turn os.pullEvent() into an os.pullEventRaw(), thus unintentionally making peoples scripts un-terminatable?
Bomb Bloke #17
Posted 07 May 2014 - 01:16 PM
You'd only need to worry about that if you specifically rigged os.pullEventRaw to look for "terminate" events and prevented it from passing them on to os.pullEvent. That is to say, you'd need to go out of your way to break that functionality.
KingofGamesYami #18
Posted 07 May 2014 - 01:27 PM
You'd only need to worry about that if you specifically rigged os.pullEventRaw to look for "terminate" events and prevented it from passing them on to os.pullEvent. That is to say, you'd need to go out of your way to break that functionality.
Ok thanks. Wasn't sure how that would work.
KingofGamesYami #19
Posted 07 May 2014 - 10:57 PM
My "slave" script is erroring now;
-snip- I'm dumb…
Edited on 07 May 2014 - 09:09 PM
Bomb Bloke #20
Posted 07 May 2014 - 11:24 PM
Hmm. Can't really see a problem there, but there's a missing "then" on line 28.

By the way, aren't all args guarenteed to be strings - I'm not sure why you're checking for this? I also got the impression modem.open() doesn't take them - wouldn't you need to use tonumber(args[1])?
KingofGamesYami #21
Posted 07 May 2014 - 11:33 PM
Hmm. Can't really see a problem there, but there's a missing "then" on line 28.

By the way, aren't all args guarenteed to be strings - I'm not sure why you're checking for this? I also got the impression modem.open() doesn't take them - wouldn't you need to use tonumber(args[1])?

Yeah, the problem I was having was on line 22, the slave has been completely debugged now.. however the actual api is being annoying >.< I wish there was an emulator (for mac) that I could test this particular code on…

One of the problems was the tonumber thing, I simply added

args[1] = tunumber(args[1])
args[2] = tonumber(args[2])

Also, when I coded the checking thing I wasn't sure how command line arguments work. I thought they would have to do "top" to generate a string, instead of plain top.

If you care to look through the code, the error is expected ')' on line 21 in my "main" script.
Bomb Bloke #22
Posted 07 May 2014 - 11:49 PM
This may be what you're after. Runs in your web browser, can access Pastebin and everything.

On line 19 you've got this:

(#args = 1 and args[1] = "wpe")

… when you should have this:


(#args == 1 and args[1] == "wpe")
KingofGamesYami #23
Posted 08 May 2014 - 12:02 AM
This may be what you're after. Runs in your web browser, can access Pastebin and everything.
problem is, cant use peripherals (wireless modems). This means my code will error every time I try to call the modem… which defeats the purpose of testing.
KingofGamesYami #24
Posted 08 May 2014 - 10:20 PM
I am now getting:

Cannot serialize function
on my slave:
Spoiler

local args = {...}

if #args < 3 then
	error("Incomplete arguments", 2)
elseif #args > 3 then
	error("Too many arguments", 2)
end

assert(tonumber(args[1]), args[1].." isn't a number!")
assert(tonumber(args[2]), args[2].." isn't a number!")
args[1] = tonumber(args[1])
args[2] = tonumber(args[2])

local valid = false
for i = 1, 6 do
	if args[3] == (rs.getSides())[i] then
		valid = true
	end
end
if not valid then
	error("Side is not valid")
end

local modem = peripheral.wrap(args[3])
modem.open(args[2])

local function reply(info)
	modem.transmit(args[1], args[2], textutils.serialize(info))
end

while true do
	event = {os.pullEvent()}
	if event[1] == "modem_message" and type(event[5]) == "table" then
		local response = {peripheral.call(event[5].side, event[5].call, unpack(event[5].params))}
		reply(response)
	elseif event[1] == "modem_message" and type(event[5]) == "string" then
		reply(peripheral.wrap(event[5]))
	else
		reply({"wpe", event})
	end
end

if I don't serialize, my main program breaks

Spoiler

local modem = peripheral.wrap("back")

local oldos = {}
for k, v in pairs(os) do
	oldos[k] = v
end

function os.pullEventRaw(...)
	local args = {...}
	local event
	if args[1] == "wpe" then
		event = oldos.pullEvent("modem_message")
		if type(event[4]) == "table" and event[4][1] == "wpe" then
			return unpack(event[4][2])
		else
			return os.pullEventRaw(unpack(args))
		end
	else
		event = {oldos.pullEventRaw(unpack(args))}
	end
 	if event[1] == "modem_message" and type(event[5]) == "table" and event[5][1] == "wpe" and #args == 2 and args[1] == "wpe" then
  		return unpack(event[5][2])
	else
 		return unpack(event)
 	end
end

function setModem(side)
	modem = peripheral.wrap(side)
end

function wrap(side, channela, channelb)
	local per, call = {
	side = side,
	channela = channela,
	channelb = channelb,
}, {}
	modem.transmit(channela, channelb, side)
	modem.open(channela)
	msg = {os.pullEvent("modem_message")}
	msg[4] = textutils.unserialize(msg[4])
	for k, v in pairs(msg[4]) do
		call[k] = function(...)
			modem.transmit(channela, channelb, {side = side, call = k, params = {...}})
			return(unpack({os.pullEvent("modem_message")})[4])
		end
	end
	setmetatable(per, {__index = call})
	return per
end
Edited on 08 May 2014 - 08:20 PM
CometWolf #25
Posted 08 May 2014 - 10:53 PM
You don't need to serialize tables to send them via rednet, but the functions won't work either way. What you want is the name of the functions, not the functions themselves.
KingofGamesYami #26
Posted 12 May 2014 - 11:40 PM
Reviving topic, new problem, updated code… but don't feel like making another post in ask-a-pro

Anyway, my test program is now freezing up, and won't get past using wrap("left", 204, 204). I believe the problem is in the api, considering I *tried* to add some code to prevent random messages from messing it up(not that that was likely anyway, as the data was exchanged within… idk how short of a time XD). I know the slave is sending the table, since I added 'print' into the code as a bonus debug feature (i will enable/disable this later).

api

local modem = peripheral.wrap("back")

local oldos = {}
for k, v in pairs(os) do
	oldos[k] = v
end

local function test(event)
	if event.type == "peripheral" or event.type == "terminal" then
		return true
	elseif event.type == "turtle" or event.type == "fs" then
		return true
	else
		return false
	end
end

function os.pullEventRaw(...)
	local args = {...}
	local event = {oldos.pullEventRaw(unpack(args))}
 	if event[1] == "modem_message" and type(event[5]) == "table" and test(event[5]) then
  		event[5].info[1] = event[3].."_"..event[5].info[1]
  		return unpack(event[5].info)
	else
 		return unpack(event)
 	end
end

function setModem(side)
	if peripheral.getType(side) == "modem" then
		modem = peripheral.wrap(side)
	else
		error("Modem expected, got "..peripheral.getType(side).."!", 2)
	end
	if not modem.isWireless() then
		modem = peripheral.wrap("back")
		error("Expected Wireless Modem, got Wired Modem!", 2)
	end
end

function wrap(side, channela, channelb)
	if not tonumber(channela) then
		error("Expected Number, got ".. type(channela).."!", 2)
	end
	if not tonumber(channelb) then
		error("Expected Number, got ".. type(channela).."!", 2)
	end
	local per, call = {
		side = side,
		channela = channela,
		channelb = channelb,
	}, {}
	modem.open(channela)
	modem.transmit(channela, channelb, {side = side, type = "wrap_peripheral"})
	repeat
		local msg = {os.pullEvent("modem_message")}
		if type(msg[5]) == "table" and msg[5].type == "peripheral" then
			for k, v in pairs(msg[5].info) do
				call[v] = function(...)
					modem.transmit(channela, channelb, {type = "call", side = side, call = v, params = {...}})
					repeat
						local event = {os.pullEvent("modem_message")}
						if event[5].type == "peripheral" then
							return unpack(event[5].info)
						end
					until(event[5].type == "peripheral")
				end
			end
		end
	until(msg[5].type == "peripheral")
	setmetatable(per, {__index = call})
	return per
end

function call(side, channela, channelb, method, ...)
	if not tonumber(channela) then
		error("Expected number, got "..type(channela).."!", 2)
	end
	if not tonumber(channelb) then
		error("Expected number, got "..type(channelb).."!", 2)
	end
	if not tostring(method) then
		error("Expected string, got "..type(method).."!", 2)
	end
	modem.open(channela)
	modem.transmit(channela, channelb, {type = "call", side = side, call = method, params = {...}})
	while true do
		local event = {os.pullEvent("modem_message")}
		if event[5].type == "peripheral" then
			return(unpack(event[5].info))
		end
	end
end

function term(channela, channelb)
	local per, call = {
		channela = channela,
		channelb = channelb,
	}, {}
	modem.open(channela)
	modem.transmit(channela, channelb, {type = "wrap_term"})
	repeat
		local msg = {os.pullEvent("modem_message")}
		if type(msg[5]) == "table" and msg[5].type == "terminal" then
			for k, v in pairs(msg[5].info) do
				call[k] = function(...)
					modem.transmit(channela, channelb, {type = "terminal_call", call = k, params = {...}})
					repeat
						local event = {os.pullEvent("modem_message")}
						if event[5].type == "terminal" then
							return unpack(event[5].info)
						end
					until(event[5].type == "terminal")
				end
			end
		end
	until(msg[5].type == "terminal")
	setmetatable(per, {__index = call})
	return per
end

function turtle(channela, channelb)
	local per, call = {
		channela = channela,
		channelb = channelb,
	}, {}
	modem.open(channela)
	modem.transmit(channela, channelb, {type = "wrap_turtle"})
	repeat
	local msg = {os.pullEvent("modem_message")}
		if type(msg[5]) == "table" and msg[5].type == "turtle" then
			for k, v in pairs(msg[5].info) do
				call[k] = function(...)
					modem.transmit(channela, channelb, {type = "turtle_call", call = k, params = {...}})
					repeat
						local event = {os.pullEvent("modem_message")}
						if event[5].type == "turtle" then
							return unpack(event[5].info)
						end
					until(event[5].type == "turtle")
				end
			end
		end
	until(event[5].type == "turtle")
	setmetatable(per, {__index = call})
	return per
end

function fs(channela, channelb)
	local per, call = {
		channela = channel,
		channelb = channelb,
	}, {}
	modem.open(channela)
	modem.transmit(channela, channelb, {type = "wrap_fs"})
	repeat
	local msg = {os.pullEvent("modem_message")}
		if type(msg[5]) == "table" and msg[5].type == "fs" then
			for k, v in pairs(msg[5].info) do
				call[k] = function(...)
					modem.transmit(channela, channelb, {type = "fs_call", call = k, params = {...}})
					repeat
						local event = {os.pullEvent("modem_message")}
						if event[5].type == "fs" then
							return unpack(event[5].info)
						end
					until(event[5].type == "fs")
				end
			end
		end
	until(event[5].type == "fs")
	setmetatable(per, {__index = call})
	return per
end
slave

local args = {...}

if #args < 3 then
	error("Incomplete arguments", 0)
elseif #args > 3 then
	error("Too many arguments", 0)
end

assert(tonumber(args[1]), args[1].." isn't a number!")
assert(tonumber(args[2]), args[2].." isn't a number!")
args[1] = tonumber(args[1])
args[2] = tonumber(args[2])

local valid = false
if not peripheral.getType(args[3]) == "modem" then
	error("Side is not valid", 0)
end
local modem = peripheral.wrap(args[3])
if not modem.isWireless() then
	error("Modem isn't wireless")
else
	modem.open(args[2])
end

local function reply(info)
	modem.transmit(args[1], args[2], {info = info, type = "peripheral"})
end

while true do
	event = {os.pullEvent()}
	if event[1] == "modem_message" and type(event[5]) == "table" and event[5].type == "call" then
		local response = {peripheral.call(event[5].side, event[5].call, unpack(event[5].params))}
		reply(response)
		term.setTextColor(colors.blue)
		print("peripheral response sent")
	elseif event[1] == "modem_message" and type(event[5]) == "table" and event[5].type == "wrap_peripheral" then
		local methods = peripheral.getMethods(event[5].side)
		reply(methods)
		term.setTextColor(colors.red)
		print("peripheral table sent")
	elseif event[1] == "modem_message" and type(event[5]) == "table" and event[5].type == "wrap_term" then
		local t = term.native()
		modem.transmit(args[1], args[2], {info = t, type = "term"})
		term.setTextColor(colors.lime)
		print("terminal table sent")
	elseif event[1] == "modem_message" and type(event[5]) == "table" and event[5].type == "wrap_turtle" then
		if turtle then
			modem.transmit(args[1], args[2] {info = turtle, type = "turtle"})
			term.setTextColor(colors.orange)
			print("turtle table sent")
		else
			modem.transmit(args[1], args[2], {info = nil, type = "turtle"})
			term.setTextColor(colors.orange)
			print("turtle does not exist")
		end
	elseif event[1] == "modem_message" and type(event[5]) == "table" and event[5].type == "terminal" then
		local response = term.native()[event[5].info](unpack(event[5].params))
		modem.transmit(args[1], args[2], {info = response, type = "terminal"})
		term.setTextColor(colors.cyan)
		print("terminal response sent")
	elseif event[1] == "modem_message" and type(event[5]) == "table" and event[5].type == "turtle" then
		local response = turtle[event[5].info](unpack(event[5].params))
		term.setTextColor(colors.green)
		print("turtle response sent")
	else
		reply(event)
		term.setTextColor(colors.magenta)
		print("peripheral event sent")
	end
end