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

[Question] Remotely updating a remote controlled turtle startup program

Started by ssotangkur, 24 October 2012 - 06:36 PM
ssotangkur #1
Posted 24 October 2012 - 08:36 PM
I have a remote controlled turtle is already listening for commands from the control computer.
I'd like to be able to send a command w/ an updated program which will replace the program that is currently running and have that program run. As long as my programs aren't buggy, I shouldn't need to go over to the turtle again to upload a program.

Is there a way to do this?
ChunLing #2
Posted 24 October 2012 - 09:14 PM
Yes. Have a table of functions like:
local t_func = {
receivefile = function(flnm)
	local cntnt
	flnm,cntnt = flnm:match("(%S+)%s*(.*)")
	 local hndl = fs.open(flnm,"w") hndl.write(cntnt) hndl.close()
	rednet.send(controllerID,flnm.." Updated")
end,
servefile = function(flnm)
	flnm = flnm:match("%S+")
	local hndl = fs.open(flnm,"r")
	rednet.send(controllerID,hndl.readAll()) hndl.close()
executefile = function(prms)
	local tprm = {prms:gmatch("%w+")}
	shell.run(unpack(tprm))
rednet.send(controllerID,tprm[1].." executed")
end,
}
Then have a part of your rednet receive logic loop that looks like:
repeat senderID,rdntmessage = rednet.receive() until senderID == controllerID
funcname, parameterstring = rdntmessage:match("^(%a+)%s*(.*)")
if t_func[funcname] then t_func[funcname](parameterstring) end
What this does is take a rednet messages until it finds one that comes from the controllerID. Then it tries to parse that into an initial alphanumeric sequence and whatever comes after a space (example, "receivefile somefilename Something to put in the file." should produce a funcname = "receivefile" and a parameterstring = "somefilename Something to put in the file.").

Then it checks if there is a function in t_func matching funcname, and if there is, it calls that function with parameterstring as an argument. The functions are all designed to further parse the parameterstring into something useful to them. The function t_func.receivefile takes its string and strips off the first part to use as a filename, then uses the rest as the file contents.

You can also set this up using textutils.unserialize() to unpack a table of information, but this only works if you're going to have a setup on the controller that uses textutils.serialize() to pack the information, which is certainly possible and probably a better way to present a clean user interface on the controller.

Ugh, posted the wrong version of receive file. And what happened to the indentation there?
Edited on 24 October 2012 - 07:19 PM
ChunLing #3
Posted 24 October 2012 - 09:25 PM
This probably needs some modification if you're going to send a very long program, I'm not sure whether rednet messages can be longer than 127 characters long. Basically, in that case you'd need an "recieveapphend" function to rebuild the longer file one line at a time.
Tiin57 #4
Posted 24 October 2012 - 11:33 PM
Also, this should have gone in Ask A Pro.
ssotangkur #5
Posted 25 October 2012 - 12:24 AM
Thanks for the quick response!
I did try doing this by serializing a table and it works.
There doesn't seem to be a 127 char limit anymore. My file had over 137 lines and it seemed to go through fine.
ssotangkur #6
Posted 25 October 2012 - 12:27 AM
I thought I had put this in Ask the Pros, but for some reason it got added here. That explains why I couldn't find it again when I went back to the "Ask the Pros" forum.
ChunLing #7
Posted 25 October 2012 - 02:03 AM
Good. But my bad, that executefile function won't work, cause I'm using gmatch all wrong. It should be:
executefile = function(prms)
    local tprm,ndx = {},1
    for v in prms:gmatch("%w+") do tprm[ndx] = v ndx = ndx+1 end
    shell.run(unpack(tprm))
    rednet.send(controllerID,tprm[1].." executed")
end,
My bad.