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

Offload Program from Wireless Turtle

Started by urlmichael, 15 April 2014 - 03:22 PM
urlmichael #1
Posted 15 April 2014 - 05:22 PM
Hello,

I am currently writing my first extensive program on a wireless Turtle. Though it's not completely necessary, it would be convenient if I could send that program to a computer with a modem attached.

Is there simple command to do this? How do I link my Turtle and my computer?

Any help would be appreciated.

Thanks.
guesswhat123212 #2
Posted 15 April 2014 - 05:45 PM
you can send the program but the receiving turtle/computer has to be setup to do it. I will edit this post with some sample code in a sec.


--sending device--

function sendfile(filename)
  f = fs.open(filename,"r")
  fd = f.readall()
  f.close()
  rednet.send(receivingID, fd)
end


--receiveing device--

function getFile()
  sid, msg = rednet.receive()
  f = fs.open(filename,"w")
  f.writeline(msg)
  f.close()
end


that should do it if I remember correctly. You can also add another rednet msg to get the filename from the sending computer (or just put it into a table)
Edited on 15 April 2014 - 03:51 PM
apemanzilla #3
Posted 15 April 2014 - 05:45 PM
Easiest way would be to use the HTTP API. Otherwise, try this simple code:

Computer

local filename = "FILENAME"
local side = "MODEMSIDE"

rednet.open(side)
local t = fs.open(filename,"w")
t.write(rednet.receive())
t.close()

Turtle

local filename = "FILENAME"
local side = "MODEMSIDE"
local id = 1 -- Computer's ID

rednet.open(side)
local t = fs.open(filename,"r")
rednet.send(t.readAll(),id)
t.close()

Change the variables at the top, then run the program on the computer FIRST and then the one on the turtle. If all goes well, you should have the file saved on the computer now as whatever you wanted it to be named.

Edit:
you can send the program but the receiving turtle/computer has to be setup to do it. I will edit this post with some sample code in a sec.
I win? :P/>
Edited on 15 April 2014 - 03:46 PM
Agoldfish #4
Posted 15 April 2014 - 06:22 PM
It is also worth mentioning that you can type id into a computer/turtle to find the id of it.
urlmichael #5
Posted 15 April 2014 - 06:49 PM
Easiest way would be to use the HTTP API. Otherwise, try this simple code:

Computer

local filename = "FILENAME"
local side = "MODEMSIDE"

rednet.open(side)
local t = fs.open(filename,"w")
t.write(rednet.receive())
t.close()

Turtle

local filename = "FILENAME"
local side = "MODEMSIDE"
local id = 1 -- Computer's ID

rednet.open(side)
local t = fs.open(filename,"r")
rednet.send(t.readAll(),id)
t.close()

Change the variables at the top, then run the program on the computer FIRST and then the one on the turtle. If all goes well, you should have the file saved on the computer now as whatever you wanted it to be named.

Awesome, thanks for the help. However,

local side = left
rednet.open(side)
rednet:6: string expected

Is "left" not the right way to input that the modem is on the left side of the computer? This error makes it seem like "left" isn't a viable answer to what side the modem is on.

Thanks
CometWolf #6
Posted 15 April 2014 - 07:00 PM
You forgot the quotes. Also left is the left of the computer when you are facing the screen.
apemanzilla #7
Posted 15 April 2014 - 07:15 PM
You forgot the quotes. Also left is the left of the computer when you are facing the screen.
What this guy said :P/>
urlmichael #8
Posted 15 April 2014 - 07:33 PM
Ahhh… I got it. Sorry, I'm new to rednet.

The solution was twofold.
1) Needed quotes
2)

rednet.open( "left" )

instead of

rednet.open("left")
Lyqyd #9
Posted 15 April 2014 - 07:37 PM
The extra spacing is unnecessary. It works equally well with and without.
apemanzilla #10
Posted 15 April 2014 - 07:57 PM
Ahhh… I got it. Sorry, I'm new to rednet.

The solution was twofold.
1) Needed quotes
2)

rednet.open( "left" )

instead of

rednet.open("left")

rednet.open("left")
Is exactly the same as

rednet.open( "left" )
is the same as

rednet.open((((              "left"             ))))
urlmichael #11
Posted 16 April 2014 - 02:29 PM
Hmmm… Well, it was being janky for me, but this worked. So I guess it's OK in the end
KingofGamesYami #12
Posted 17 April 2014 - 04:06 AM
I tried adapting this code for something, but it's doing something weird:
Sending Computer

rednet.open("left")
local file = fs.open("test", "r")
rednet.broadcast(file:readAll())
file:close()
rednet.close("left")
Recieving Turtle

rednet.open("right")
local sID, file = rednet.receive()
print("Recieved"..file)
local tFile = fs.open("temp", "w")
tFile:writeLine(file)
tFile:close()
rednet.close("right")
print("Executing...")
shell.run("temp")
the test file:

turtle.turnRight()
turtle.forward()
the temp file This is where it messes up

{}
Why is it generating this?? I have no idea where it gets "{}" from.
Bomb Bloke #13
Posted 17 April 2014 - 09:22 AM
Presumably the turtle is printing "Recieved{}"?

Maybe get the sending computer to print a copy of what it read from "test". My guess is that you're getting it to read a file from the root of the computer's file structure, but the file you want it to read is elsewhere.
CometWolf #14
Posted 17 April 2014 - 09:48 AM
You're using the fs functions wrong.

tFile:writeLine(file)
would be the equivalent of

tFile.writeLine(tFile,file)
im suprised it dosen't error lol. The correct usage is

tFile.writeLine(file)
KingofGamesYami #15
Posted 17 April 2014 - 01:30 PM
Presumably the turtle is printing "Recieved{}"?

Maybe get the sending computer to print a copy of what it read from "test". My guess is that you're getting it to read a file from the root of the computer's file structure, but the file you want it to read is elsewhere.
No, actually the turtle is printing the contents of the file I sent. (eg. Recieved turtle.turnRight()\nturtle.forward())
You're using the fs functions wrong.

tFile:writeLine(file)
would be the equivalent of

tFile.writeLine(tFile,file)
im suprised it dosen't error lol. The correct usage is

tFile.writeLine(file)
so, I should use

tFile.writeLine(file)
instead of

tFile:writeLine(file)
apemanzilla #16
Posted 17 April 2014 - 01:38 PM
Presumably the turtle is printing "Recieved{}"?

Maybe get the sending computer to print a copy of what it read from "test". My guess is that you're getting it to read a file from the root of the computer's file structure, but the file you want it to read is elsewhere.
No, actually the turtle is printing the contents of the file I sent. (eg. Recieved turtle.turnRight()\nturtle.forward())
You're using the fs functions wrong.

tFile:writeLine(file)
would be the equivalent of

tFile.writeLine(tFile,file)
im suprised it dosen't error lol. The correct usage is

tFile.writeLine(file)
so, I should use

tFile.writeLine(file)
instead of

tFile:writeLine(file)
Yes. fs.open return values are tables with the functions themselves, whereas io.open returns are OOP style "classes" and therefore use colon notation.
Shrooblord #17
Posted 17 April 2014 - 06:12 PM
Alternatively, you could use the textutils.serialize and textutils.unserialize commands to send the file over as a string. This way you can send whole scores of programs over rednet in only few operations. For example, I use this program to send updates through a set of machines running the same programs, but are also being updated in the background (this is just a direct copy-paste for illustration, so expect some things that don't necessarily make sense for your case):
Spoiler

local prog = {"startup", "update", "build"} -- A table containing the names of programs that will be sent.

local filessent = 0
local currentfile = 0


function fileSend()
  local file = fs.open(prog[currentfile], "r")
  local data = textutils.serialize {
	cmd = "getfile",
	program = prog[currentfile],
	content = file:readAll()
  }
  file:close()
  rednet.send(rID, data)
  local _, updateSuccess = rednet.receive() --The '_' here is to catch the computer's ID that is returned by rednet.receive(), but which we are not interested in right now; we only want to know if the update was succesful.
  if updateSuccess and updateSuccess == "File update complete." then
	filessent = filessent + 1
	print(prog[currentfile].." was sent successfully ("..currentfile.."/"..table.getn(prog).." files)")
	return true
  else
	print("File "..currentfile.." named "..prog[currentfile].." was not sent successfully.")
	return false
  end
end

rednet.open("left")

rednet.send(rID,table.getn(prog)) --This sends the client computer the number of files that await sending.
	  while filessent < table.getn(prog) do
		currentfile = currentfile + 1
		if fileSend() == false then
		  print("An error occured during file transmission. Update for "..rID.." was aborted.")
		  break
		end
	  end

rednet.close("left")

(I have omitted some irrelevant lines of code such as gathering when a client actually needs an update, whether the client is eligible for update (only computer IDs known by the system get updated) and so forth, but that would only complicate my example and confuse things.)

This function will send all files the computer is told to send and display which file out of how many total files was sent - the screen reads "startup was sent succesfully (1/3)" -, or, if the update was not performed successfully, which file it was that broke the process (there will be actions taken if the function sendUpdate() returns false i.e. if the file was not sent successfully, but that's not relevant here). It does so by first sending the file and then listening for the receiving computer's response, which is given by:

Spoiler

local _, numberoffiles = rednet.receive() --Here is received how many files require receiving. Again, the underscore is there because we're not interested in the sender's ID and thus it is stored in a random variable we're not going to use.
	  fileamount = tonumber(numberoffiles)
	  writtenfiles = 0
		--The update!
		print("Receiving data from Master control...")
		function receiveFiles()
		  while true do
			local _, data = textutils.unserialize(rednet.receive())

			--Now to ensure that there is no crash
			if data and data.cmd and data.cmd == "getfile" then
			  print("Data received. Writing program.")
			  local file = fs.open(data.program, "w")
				file:write(data.content)
			  file:close()
			  print("Program written.")
			  writtenfiles = writtenfiles + 1
			  rednet.send(mID,"File update complete.")
			  break
			end	  
		  end
		end
		while writtenfiles < fileamount do
		  receiveFiles()
		end

So in the end, what is sent here is a number of programs sent as strings that will be received and written out again as the same programs with the same name as the original that was sent for update. Now, in the sent program, you could include things that switch automatically to the new version of the program as it's still being executed etc. etc. to keep the system running during an update (I will elaborate if you want to know more). The boon to this is that you need only one master controller computer to update an entire system - in my case, I use this as a central hub for all my Turtles. All relevant Turtles receive one batch of updates, another receives another batch, all using these two simple programs.

Hope to have given you an alternative method and insight into sending and receiving files - good luck!
apemanzilla #18
Posted 17 April 2014 - 08:41 PM
Sorry, what? What does textutils.serialize have to do with it? We read the file into a string anyways… This is just overcomplicating things…
CometWolf #19
Posted 17 April 2014 - 09:20 PM
rednet.send serializes and unserializes tables automatically anyways >.>
Lyqyd #20
Posted 17 April 2014 - 10:11 PM
It actually doesn't call the serialization functions. The Java side of things handles transporting strings, numbers, tables, etc.
CometWolf #21
Posted 17 April 2014 - 10:23 PM
Right, i asked you about that once before didn't i :P/>
Shrooblord #22
Posted 17 April 2014 - 10:27 PM
Sorry, what? What does textutils.serialize have to do with it? We read the file into a string anyways… This is just overcomplicating things…
Hm, maybe I created this in a version where this was not the case? Is that possible? Though this code isn't actually that old, probably about a month or maybe two ago.
In any case, what I liked about the method was that you could easily create a system where you can specify what programs to send initially and the code would handle the rest from then on forwards. No need to dig back down into your own program (no matter how easy that is - it can always be a little easier and if that requires it to be more complex to begin with, maybe that's best) - just edit one little line at the top of the code and it all sends everything as you wish.

But maybe I have overcomplicated it. I tend to do that. I Googled 'sending programs over rednet computercraft' and found this post, which basically means that the heart of my code isn't actually 'my code' but was just something I found that works. xD
Well, whatever - use whichever method you prefer - I like this one, to be honest.

However, the following is true (found on the page of that link I just posted):
The problem with this is that if the program doesn't know that it's a file that was sent to them by another computer that it's supposed to "download", it'll just pick up any old rednet broadcast and close before its ready, nor does it know the name/path of the file it's supposed to save it as. It's not enough to just check if the sender ID is correct because you might want to send a file from another computer.
Which is probably why I employed the method - the whole serialize method sends three variables over the rednet at the same time as the program, which enables you to safeguard the receiving computer. You could do it with simple confirmation pings between the two computers, of course, but like I said, I like this method.
Edited on 17 April 2014 - 08:30 PM