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

Wireless Towers

Started by johnnic, 11 December 2013 - 09:38 PM
johnnic #1
Posted 11 December 2013 - 10:38 PM
I would like to suggest adding a wireless tower which would listen for all wireless signals within the wireless modem range. It would transmit the signal to all other wireless towers that are possibly using the same ID or are linked. It could be a standalone block, or a peripheral.
Lyqyd #2
Posted 11 December 2013 - 10:41 PM
…or you could code it yourself. This is already possible to create in-game with some clever programming.
awsmazinggenius #3
Posted 11 December 2013 - 11:27 PM
Yep. Here is some very minimalistic code to get your ideas flowing (done with Rednet - you could do this with the Modem API as well)

log = fs.open("file name for a running log", "a")
rednet.open("side i think you know how to do this")
local _, m = rednet.receive()
rednet.broadcast(m) --# You could also rednet.send() to certain towers, or with a for loop to a list of other towers.
log.write(m)
log.flush
Note that I'm not great on my syntax - I'm feeling a little lazy. So don't guarantee that working - it's just a basic idea.
Edited on 11 December 2013 - 10:28 PM
distantcam #4
Posted 12 December 2013 - 12:56 AM
You'd want to rebroadcast the message in a specific way so two towers don't simply repeat messages between each other, but yeah this should be possible with some smart programming.

Edit: Oh, and you'll need the receiver to ignore repeated messages as multiple towers in range repeat the message.
Edited on 11 December 2013 - 11:58 PM
theoriginalbit #5
Posted 12 December 2013 - 01:20 AM
As distantcam stated you'll want to avoid message propagation. I'd say that the easiest method for this would be to implement a UUID (for example computer id and some incremental number) in the message which is stored in a table at each node. This is then checked and if present it does not relay the message.

Assuming the latest version of ComputerCraft you could do the following (making use of Rednet API for simplicity of code examples, Modem API could also be used)

Sender Code

rednet.open("left")
local nextId = 0
local compId = os.getComputerID()

local function sendMessage(message)
  local uuid = string.format("%d:%d", compId, nextId)
  rednet.broadcast({uuid = uuid; content = message})
  nextId = nextId + 1
end

sendMessage("Hello World!")

Repeater Code

rednet.open("left")
local prevMessages = {}

local function rebroadcast(msg)
  --# check that the message was a table and it has the uuid field
  if type(msg) ~= "table" or not msg.uuid then
	return false --# it didn't lets just ignore the message
  end

  --# check if the message has been handled before
  if not prevMessages[msg.uuid] then
	prevMessages[msg.uuid] = true --# mark it as received
	rednet.broadcast(msg)
	return true --# it was handled this time!
  end

  return false
end

while true do
  local _, msg = rednet.receive()
  rebroadcast(msg)
end

Receiver Code

rednet.open("left")
local prevMessages = {}

local function processMessage(msg)
  --# make sure that it is a valid message that we just received
  if type(msg) == "table" and msg.uuid and not prevMessages[msg.uuid] then
	prevMessages[msg.uuid] = true

	--# perform whatever else you want to on the message here, you've not seen this message before
  end
end

while true do
  local _, msg = rednet.receive()
  processMessage(msg)
end

As you can see from very simple examples above this task is not a difficult one to complete! And if you're running an older version of ComputerCraft requires a few extra steps of serialising and unserialising the rednet messages (as they were needed to be strings in older versions)
Edited on 12 December 2013 - 01:30 AM
distantcam #6
Posted 12 December 2013 - 02:24 AM

  --# check that the message was a table and it has the uuid field
  if type(msg) ~= "table" and not msg.uuid then

I think you want an "or" there, not an "and". Didn't quite De Morgan properly.
theoriginalbit #7
Posted 12 December 2013 - 02:30 AM
I think you want an "or" there, not an "and". Didn't quite De Morgan properly.
Whoops, yeh thanks. It was originally a different statement, forgot to swap it.
awsmazinggenius #8
Posted 12 December 2013 - 07:16 PM
You'd want to rebroadcast the message in a specific way so two towers don't simply repeat messages between each other, but yeah this should be possible with some smart programming.

Edit: Oh, and you'll need the receiver to ignore repeated messages as multiple towers in range repeat the message.
As distantcam stated you'll want to avoid message propagation. I'd say that the easiest method for this would be to implement a UUID (for example computer id and some incremental number) in the message which is stored in a table at each node. This is then checked and if present it does not relay the message.

Assuming the latest version of ComputerCraft you could do the following (making use of Rednet API for simplicity of code examples, Modem API could also be used)

Sender Code

rednet.open("left")
local nextId = 0
local compId = os.getComputerID()

local function sendMessage(message)
  local uuid = string.format("%d:%d", compId, nextId)
  rednet.broadcast({uuid = uuid; content = message})
  nextId = nextId + 1
end

sendMessage("Hello World!")

Repeater Code

rednet.open("left")
local prevMessages = {}

local function rebroadcast(msg)
  --# check that the message was a table and it has the uuid field
  if type(msg) ~= "table" or not msg.uuid then
	return false --# it didn't lets just ignore the message
  end

  --# check if the message has been handled before
  if not prevMessages[msg.uuid] then
	prevMessages[msg.uuid] = true --# mark it as received
	rednet.broadcast(msg)
	return true --# it was handled this time!
  end

  return false
end

while true do
  local _, msg = rednet.receive()
  rebroadcast(msg)
end

Receiver Code

rednet.open("left")
local prevMessages = {}

local function processMessage(msg)
  --# make sure that it is a valid message that we just received
  if type(msg) == "table" and msg.uuid and not prevMessages[msg.uuid] then
	prevMessages[msg.uuid] = true

	--# perform whatever else you want to on the message here, you've not seen this message before
  end
end

while true do
  local _, msg = rednet.receive()
  processMessage(msg)
end

As you can see from very simple examples above this task is not a difficult one to complete! And if you're running an older version of ComputerCraft requires a few extra steps of serialising and unserialising the rednet messages (as they were needed to be strings in older versions)

I did include a comment in my code for this purpose.
distantcam #9
Posted 12 December 2013 - 07:42 PM
I did include a comment in my code for this purpose.

Yeah, but a hard-coded whitelist would mean the code is not reusable, and a pain to set up on lots of towers.
theoriginalbit #10
Posted 12 December 2013 - 07:43 PM
I did include a comment in my code for this purpose.
It wasn't stated explicitly enough. You stated that rednet.send could be used, but not the benefit of doing so, also using that method would be annoying 'cause you'd need to do 1 of 2 things:
  1. have a different program for each tower due to the different towers it has in range (it would also need to know where to send each message based on the target, this is a lot of manual work)
  2. have the same program for each tower but write a very complicated program that includes node discovery, rolling updates of RIBs, and an implementation of a routing protocol such as OSPF.
Both of which are not required in the "dumb" implementation that I performed.
Edited on 12 December 2013 - 06:44 PM
awsmazinggenius #11
Posted 12 December 2013 - 11:33 PM
Um, I said "Get your ideas flowing". So mine is meant to be a few-line example. Yours is still better, but it is a lot longer.