Compare commits

...

32 Commits

Author SHA1 Message Date
Mark Qvist 700601d63e Updated documentation and manual 2022-12-23 23:32:38 +01:00
Mark Qvist 274c7199b0 Updated version 2022-12-23 23:27:37 +01:00
Mark Qvist 7960226883 Fixed missing path invalidation on failed link establishments made from a shared instance client 2022-12-23 23:26:50 +01:00
Mark Qvist bb74878e94 Reordered property assignment 2022-12-23 23:24:26 +01:00
Mark Qvist 549d22be68 Updated documentation and manual 2022-12-22 21:13:44 +01:00
Mark Qvist 5c2c935b6f Updated version 2022-12-22 21:08:02 +01:00
Mark Qvist 8402541c73 Faster roaming path recovery for multiple interface non-transport instances 2022-12-22 20:17:09 +01:00
Mark Qvist c34c268a6a Added carrier change detection flag to AutoInterface 2022-12-22 18:20:34 +01:00
Mark Qvist 8fcdc4613c Adjusted loglevels 2022-12-22 18:20:13 +01:00
Mark Qvist f645fa569b Fixed AutoInterface multicast echoes failing on interfaces with rolling MAC addresses on every re-connect 2022-12-22 17:46:46 +01:00
Mark Qvist 469947dab9 Updated manual 2022-12-22 15:49:47 +01:00
Mark Qvist 2386fc3635 Updated documentation and manual 2022-12-22 15:11:53 +01:00
Mark Qvist e9e98a00c2 Updated version 2022-12-22 15:07:36 +01:00
Mark Qvist b305eb8e0a Improved path response handling. Prepared destination path response handling for multi-path Transport. 2022-12-22 11:28:56 +01:00
Mark Qvist dd7931d421 Added signal quality stats to announce log output 2022-12-22 11:26:59 +01:00
Mark Qvist 191dce1301 Updated manual 2022-12-20 21:13:23 +01:00
Mark Qvist 3b5a27ba60 Updated readme 2022-12-20 21:08:08 +01:00
Mark Qvist 3c91f7f18b Updated documentation 2022-12-20 20:57:49 +01:00
Mark Qvist 171457713b Improved RNode hotplug over Bluetooth on Android 2022-12-20 15:17:46 +01:00
Mark Qvist 67ee8d6aab Added originator check to path rediscovery on failed links 2022-12-19 01:31:00 +01:00
Mark Qvist 13fa7d49d9 Added automatic path rediscovery on failed link establishments 2022-12-19 01:15:49 +01:00
Mark Qvist 66d921e669 Improved resource advertisement retry handling 2022-12-19 01:10:34 +01:00
Mark Qvist 85f60ea04e Added check for already transferring resource to Link class 2022-12-19 01:04:49 +01:00
Mark Qvist 4870e741f6 Added link request proof signature validation for every transport hop 2022-12-18 21:27:14 +01:00
Mark Qvist f71c1986af Added Heltec USB issue notice to autoinstaller 2022-12-16 23:34:31 +01:00
Mark Qvist 30d8e351dd Updated version 2022-12-16 23:21:22 +01:00
Mark Qvist 5e62e3bc22 Merge branch 'master' of https://git.unsigned.io/markqvist/Reticulum 2022-12-15 21:17:16 +01:00
Mark Qvist 1a67e276ad Updated broken link. Fixes #174. Thanks @mkinney! 2022-12-15 21:16:20 +01:00
Mark Qvist df37a4a884 Updated broken link 2022-12-15 21:15:47 +01:00
Mark Qvist d26bbbd59f Merge branch 'master' of https://git.unsigned.io/markqvist/Reticulum 2022-12-15 17:14:15 +01:00
Mark Qvist 2a264fa7d6 Fixed invalid driver proxy for Qinheng CH34x chips on Android 2022-12-15 17:14:09 +01:00
Mark Qvist d5e0a461cf Fixed invalid check for None 2022-11-25 00:42:22 +01:00
30 changed files with 308 additions and 162 deletions
+2 -2
View File
@@ -37,7 +37,7 @@ The full documentation for Reticulum is available at [markqvist.github.io/Reticu
You can also [download the Reticulum manual as a PDF](https://github.com/markqvist/Reticulum/raw/master/docs/Reticulum%20Manual.pdf)
For more info, see [unsigned.io/projects/reticulum](https://unsigned.io/projects/reticulum/)
For more info, see [reticulum.network](https://reticulum.network/)
## Notable Features
- Coordination-less globally unique addressing and identification
@@ -63,7 +63,7 @@ For more info, see [unsigned.io/projects/reticulum](https://unsigned.io/projects
- Low cost of keeping links open at only 0.44 bits per second
## Development Roadmap
While Reticulum is already a fully featured and functional networking stack, many improvements and additions are planned for the future.
While Reticulum is already a fully featured and functional networking stack, many improvements and additions are actively being worked on, and planned for the future.
To learn more about the direction and future of Reticulum, please see the [Development Roadmap](./Roadmap.md).
+2 -2
View File
@@ -33,7 +33,7 @@ def hkdf(length=None, derive_from=None, salt=None, context=None):
if length == None or length < 1:
raise ValueError("Invalid output key length")
if derive_from == "None" or derive_from == "":
if derive_from == None or derive_from == "":
raise ValueError("Cannot derive key from empty input material")
if salt == None or len(salt) == 0:
@@ -54,4 +54,4 @@ def hkdf(length=None, derive_from=None, salt=None, context=None):
block = hmac_sha256(pseudorandom_key, block + context + bytes([i + 1]))
derived += block
return derived[:length]
return derived[:length]
+48 -20
View File
@@ -69,6 +69,8 @@ class Destination:
OUT = 0x12;
directions = [IN, OUT]
PR_TAG_WINDOW = 30
@staticmethod
def expand_name(identity, app_name, *aspects):
"""
@@ -132,6 +134,7 @@ class Destination:
self.proof_strategy = Destination.PROVE_NONE
self.mtu = 0
self.path_responses = {}
self.links = []
if identity == None and direction == Destination.IN and self.type != Destination.PLAIN:
@@ -163,7 +166,7 @@ class Destination:
return "<"+self.name+"/"+self.hexhash+">"
def announce(self, app_data=None, path_response=False, send=True):
def announce(self, app_data=None, path_response=False, attached_interface=None, tag=None, send=True):
"""
Creates an announce packet for this destination and broadcasts it on all
relevant interfaces. Application specific data can be added to the announce.
@@ -173,35 +176,60 @@ class Destination:
"""
if self.type != Destination.SINGLE:
raise TypeError("Only SINGLE destination types can be announced")
destination_hash = self.hash
random_hash = RNS.Identity.get_random_hash()[0:5]+int(time.time()).to_bytes(5, "big")
if app_data == None and self.default_app_data != None:
if isinstance(self.default_app_data, bytes):
app_data = self.default_app_data
elif callable(self.default_app_data):
returned_app_data = self.default_app_data()
if isinstance(returned_app_data, bytes):
app_data = returned_app_data
signed_data = self.hash+self.identity.get_public_key()+self.name_hash+random_hash
if app_data != None:
signed_data += app_data
now = time.time()
stale_responses = []
for entry_tag in self.path_responses:
entry = self.path_responses[entry_tag]
if now > entry[0]+Destination.PR_TAG_WINDOW:
stale_responses.append(entry_tag)
signature = self.identity.sign(signed_data)
for entry_tag in stale_responses:
self.path_responses.pop(entry_tag)
announce_data = self.identity.get_public_key()+self.name_hash+random_hash+signature
if (path_response == True and tag != None) and tag in self.path_responses:
# This code is currently not used, since Transport will block duplicate
# path requests based on tags. When multi-path support is implemented in
# Transport, this will allow Transport to detect redundant paths to the
# same destination, and select the best one based on chosen criteria,
# since it will be able to detect that a single emitted announce was
# received via multiple paths. The difference in reception time will
# potentially also be useful in determining characteristics of the
# multiple available paths, and to choose the best one.
RNS.log("Using cached announce data for answering path request with tag "+RNS.prettyhexrep(tag), RNS.LOG_EXTREME)
announce_data = self.path_responses[tag][1]
else:
destination_hash = self.hash
random_hash = RNS.Identity.get_random_hash()[0:5]+int(time.time()).to_bytes(5, "big")
if app_data != None:
announce_data += app_data
if app_data == None and self.default_app_data != None:
if isinstance(self.default_app_data, bytes):
app_data = self.default_app_data
elif callable(self.default_app_data):
returned_app_data = self.default_app_data()
if isinstance(returned_app_data, bytes):
app_data = returned_app_data
signed_data = self.hash+self.identity.get_public_key()+self.name_hash+random_hash
if app_data != None:
signed_data += app_data
signature = self.identity.sign(signed_data)
announce_data = self.identity.get_public_key()+self.name_hash+random_hash+signature
if app_data != None:
announce_data += app_data
self.path_responses[tag] = [time.time(), announce_data]
if path_response:
announce_context = RNS.Packet.PATH_RESPONSE
else:
announce_context = RNS.Packet.NONE
announce_packet = RNS.Packet(self, announce_data, RNS.Packet.ANNOUNCE, context = announce_context)
announce_packet = RNS.Packet(self, announce_data, RNS.Packet.ANNOUNCE, context = announce_context, attached_interface = attached_interface)
if send:
announce_packet.send()
+15 -3
View File
@@ -255,10 +255,22 @@ class Identity:
RNS.Identity.remember(packet.get_hash(), destination_hash, public_key, app_data)
del announced_identity
if hasattr(packet, "transport_id") and packet.transport_id != None:
RNS.log("Valid announce for "+RNS.prettyhexrep(destination_hash)+" "+str(packet.hops)+" hops away, received via "+RNS.prettyhexrep(packet.transport_id)+" on "+str(packet.receiving_interface), RNS.LOG_EXTREME)
if packet.rssi != None or packet.snr != None:
signal_str = " ["
if packet.rssi != None:
signal_str += "RSSI "+str(packet.rssi)+"dBm"
if packet.snr != None:
signal_str += ", "
if packet.snr != None:
signal_str += "SNR "+str(packet.snr)+"dB"
signal_str += "]"
else:
RNS.log("Valid announce for "+RNS.prettyhexrep(destination_hash)+" "+str(packet.hops)+" hops away, received on "+str(packet.receiving_interface), RNS.LOG_EXTREME)
signal_str = ""
if hasattr(packet, "transport_id") and packet.transport_id != None:
RNS.log("Valid announce for "+RNS.prettyhexrep(destination_hash)+" "+str(packet.hops)+" hops away, received via "+RNS.prettyhexrep(packet.transport_id)+" on "+str(packet.receiving_interface)+signal_str, RNS.LOG_EXTREME)
else:
RNS.log("Valid announce for "+RNS.prettyhexrep(destination_hash)+" "+str(packet.hops)+" hops away, received on "+str(packet.receiving_interface)+signal_str, RNS.LOG_EXTREME)
return True
+23 -13
View File
@@ -254,13 +254,14 @@ class RNodeInterface(Interface):
# Driver overrides for speficic chips
from usbserial4a import serial4a as pyserial
proxy = pyserial.get_serial_port
if vid == 0x1A86 and pid == 0x55D4:
# Force CDC driver for Qinheng CH34x
RNS.log("Using CDC driver for "+RNS.hexrep(vid)+":"+RNS.hexrep(pid), RNS.LOG_DEBUG)
from usbserial4a.cdcacmserial4a import CdcAcmSerial
proxy = CdcAcmSerial
serial = pyserial.get_serial_port(
serial = proxy(
port,
baudrate = 115200,
bytesize = 8,
@@ -281,7 +282,7 @@ class RNodeInterface(Interface):
serial.timeout = 0.1
elif vid == 0x10C4:
# Hardware parameters for SiLabs CP210x @ 115200 baud
serial.DEFAULT_READ_BUFFER_SIZE = 64
serial.DEFAULT_READ_BUFFER_SIZE = 64
serial.USB_READ_TIMEOUT_MILLIS = 12
serial.timeout = 0.012
elif vid == 0x1A86 and pid == 0x55D4:
@@ -328,11 +329,13 @@ class RNodeInterface(Interface):
from usbserial4a import serial4a as serial
self.parity = "N"
self.bt_target_device_name = target_device_name
self.bt_target_device_address = target_device_address
if allow_bluetooth:
self.bt_manager = AndroidBluetoothManager(
owner = self,
target_device_name = target_device_name,
target_device_address = target_device_address
target_device_name = self.bt_target_device_name,
target_device_address = self.bt_target_device_address
)
else:
@@ -543,6 +546,13 @@ class RNodeInterface(Interface):
RNS.log(str(self)+" USB write timeout set to "+str(self.serial.USB_WRITE_TIMEOUT_MILLIS)+"ms", RNS.LOG_DEBUG)
elif self.allow_bluetooth:
if self.bt_manager == None:
self.bt_manager = AndroidBluetoothManager(
owner = self,
target_device_name = self.bt_target_device_name,
target_device_address = self.bt_target_device_address
)
if self.bt_manager != None:
self.bt_manager.connect_any_device()
@@ -554,7 +564,7 @@ class RNodeInterface(Interface):
thread.start()
self.detect()
sleep(0.4)
sleep(0.5)
if not self.detected:
raise IOError("Could not detect device")
@@ -592,22 +602,22 @@ class RNodeInterface(Interface):
def initRadio(self):
self.setFrequency()
time.sleep(0.1)
time.sleep(0.15)
self.setBandwidth()
time.sleep(0.1)
time.sleep(0.15)
self.setTXPower()
time.sleep(0.1)
time.sleep(0.15)
self.setSpreadingFactor()
time.sleep(0.1)
time.sleep(0.15)
self.setCodingRate()
time.sleep(0.1)
time.sleep(0.15)
self.setRadioState(KISS.RADIO_STATE_ON)
time.sleep(0.1)
time.sleep(0.15)
def detect(self):
kiss_command = bytes([KISS.FEND, KISS.CMD_DETECT, KISS.DETECT_REQ, KISS.FEND, KISS.CMD_FW_VERSION, 0x00, KISS.FEND, KISS.CMD_PLATFORM, 0x00, KISS.FEND, KISS.CMD_MCU, 0x00, KISS.FEND])
@@ -1062,10 +1072,10 @@ class RNodeInterface(Interface):
try:
time.sleep(self.reconnect_w)
if self.serial != None and self.port != None:
RNS.log("Attempting to reconnect serial port "+str(self.port)+" for "+str(self)+"...", RNS.LOG_VERBOSE)
RNS.log("Attempting to reconnect serial port "+str(self.port)+" for "+str(self)+"...", RNS.LOG_EXTREME)
if self.bt_manager != None:
RNS.log("Attempting to reconnect Bluetooth device for "+str(self)+"...", RNS.LOG_VERBOSE)
RNS.log("Attempting to reconnect Bluetooth device for "+str(self)+"...", RNS.LOG_EXTREME)
self.open_port()
+11 -6
View File
@@ -78,6 +78,7 @@ class AutoInterface(Interface):
self.interface_servers = {}
self.multicast_echoes = {}
self.timed_out_interfaces = {}
self.carrier_changed = False
self.outbound_udp_socket = None
@@ -279,24 +280,26 @@ class AutoInterface(Interface):
if address["addr"].startswith("fe80:"):
link_local_addr = address["addr"].split("%")[0]
if link_local_addr != self.adopted_interfaces[ifname]:
# TODO: Remove
# RNS.log("Replacing link-local address for "+str(ifname), RNS.LOG_DEBUG)
old_link_local_address = self.adopted_interfaces[ifname]
RNS.log("Replacing link-local address "+str(old_link_local_address)+" for "+str(ifname)+" with "+str(link_local_addr), RNS.LOG_DEBUG)
self.adopted_interfaces[ifname] = link_local_addr
self.link_local_addresses.append(link_local_addr)
if old_link_local_address in self.link_local_addresses:
self.link_local_addresses.remove(old_link_local_address)
local_addr = link_local_addr+"%"+ifname
addr_info = socket.getaddrinfo(local_addr, self.data_port, socket.AF_INET6, socket.SOCK_DGRAM)
listen_address = addr_info[0][4]
if ifname in self.interface_servers:
# TODO: Remove
# RNS.log("Shutting down previous UDP socket server for "+str(ifname), RNS.LOG_DEBUG)
RNS.log("Shutting down previous UDP listener for "+str(self)+" "+str(ifname), RNS.LOG_DEBUG)
previous_server = self.interface_servers[ifname]
def shutdown_server():
previous_server.shutdown()
threading.Thread(target=shutdown_server, daemon=True).start()
# TODO: Remove
# RNS.log("Starting new UDP socket server for "+str(ifname), RNS.LOG_DEBUG)
RNS.log("Starting new UDP listener for "+str(self)+" "+str(ifname), RNS.LOG_DEBUG)
udp_server = socketserver.UDPServer(listen_address, self.handler_factory(self.processIncoming))
self.interface_servers[ifname] = udp_server
@@ -315,10 +318,12 @@ class AutoInterface(Interface):
if now - last_multicast_echo > self.multicast_echo_timeout:
if ifname in self.timed_out_interfaces and self.timed_out_interfaces[ifname] == False:
self.carrier_changed = True
RNS.log("Multicast echo timeout for "+str(ifname)+". Carrier lost.", RNS.LOG_WARNING)
self.timed_out_interfaces[ifname] = True
else:
if ifname in self.timed_out_interfaces and self.timed_out_interfaces[ifname] == True:
self.carrier_changed = True
RNS.log(str(self)+" Carrier recovered on "+str(ifname), RNS.LOG_WARNING)
self.timed_out_interfaces[ifname] = False
+9 -2
View File
@@ -272,6 +272,8 @@ class Link:
self.rtt = time.time() - self.request_time
self.attached_interface = packet.receiving_interface
self.__remote_identity = self.destination.identity
self.status = Link.ACTIVE
self.activated_at = time.time()
RNS.Transport.activate_link(self)
RNS.log("Link "+str(self)+" established with "+str(self.destination)+", RTT is "+str(round(self.rtt, 3))+"s", RNS.LOG_VERBOSE)
rtt_data = umsgpack.packb(self.rtt)
@@ -279,8 +281,6 @@ class Link:
rtt_packet.send()
self.had_outbound()
self.status = Link.ACTIVE
self.activated_at = time.time()
if self.callbacks.link_established != None:
thread = threading.Thread(target=self.callbacks.link_established, args=(self,))
thread.daemon = True
@@ -900,6 +900,13 @@ class Link:
def register_incoming_resource(self, resource):
self.incoming_resources.append(resource)
def has_incoming_resource(self, resource):
for incoming_resource in self.incoming_resources:
if incoming_resource.hash == resource.hash:
return True
return False
def cancel_outgoing_resource(self, resource):
if resource in self.outgoing_resources:
self.outgoing_resources.remove(resource)
+19 -13
View File
@@ -172,20 +172,26 @@ class Resource:
resource.consecutive_completed_height = 0
resource.link.register_incoming_resource(resource)
if not resource.link.has_incoming_resource(resource):
resource.link.register_incoming_resource(resource)
RNS.log("Accepting resource advertisement for "+RNS.prettyhexrep(resource.hash), RNS.LOG_DEBUG)
if resource.link.callbacks.resource_started != None:
try:
resource.link.callbacks.resource_started(resource)
except Exception as e:
RNS.log("Error while executing resource started callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR)
RNS.log("Accepting resource advertisement for "+RNS.prettyhexrep(resource.hash), RNS.LOG_DEBUG)
if resource.link.callbacks.resource_started != None:
try:
resource.link.callbacks.resource_started(resource)
except Exception as e:
RNS.log("Error while executing resource started callback from "+str(resource)+". The contained exception was: "+str(e), RNS.LOG_ERROR)
resource.hashmap_update(0, resource.hashmap_raw)
resource.hashmap_update(0, resource.hashmap_raw)
resource.watchdog_job()
resource.watchdog_job()
return resource
else:
RNS.log("Ignoring resource advertisement for "+RNS.prettyhexrep(resource.hash)+", resource already transferring", RNS.LOG_DEBUG)
return None
return resource
except Exception as e:
RNS.log("Could not decode resource advertisement, dropping resource", RNS.LOG_DEBUG)
return None
@@ -397,8 +403,7 @@ class Resource:
thread.start()
def __advertise_job(self):
data = ResourceAdvertisement(self).pack()
self.advertisement_packet = RNS.Packet(self.link, data, context=RNS.Packet.RESOURCE_ADV)
self.advertisement_packet = RNS.Packet(self.link, ResourceAdvertisement(self).pack(), context=RNS.Packet.RESOURCE_ADV)
while not self.link.ready_for_new_resource():
self.status = Resource.QUEUED
sleep(0.25)
@@ -445,7 +450,8 @@ class Resource:
try:
RNS.log("No part requests received, retrying resource advertisement...", RNS.LOG_DEBUG)
self.retries_left -= 1
self.advertisement_packet.resend()
self.advertisement_packet = RNS.Packet(self.link, ResourceAdvertisement(self).pack(), context=RNS.Packet.RESOURCE_ADV)
self.advertisement_packet.send()
self.last_activity = time.time()
self.adv_sent = self.last_activity
sleep_time = 0.001
+114 -30
View File
@@ -66,6 +66,7 @@ class Transport:
PATH_REQUEST_TIMEOUT = 15 # Default timuout for client path requests in seconds
PATH_REQUEST_GRACE = 0.35 # Grace time before a path announcement is made, allows directly reachable peers to respond first
PATH_REQUEST_RW = 2 # Path request random window
PATH_REQUEST_MI = 5 # Minimum interval in seconds for automated path requests
LINK_TIMEOUT = RNS.Link.STALE_TIME * 1.25
REVERSE_TIMEOUT = 30*60 # Reverse table entries are removed after 30 minutes
@@ -92,6 +93,7 @@ class Transport:
announce_handlers = [] # A table storing externally registered announce handlers
tunnels = {} # A table storing tunnels to other transport instances
announce_rate_table = {} # A table for keeping track of announce rates
path_requests = {} # A table for storing path request timestamps
discovery_path_requests = {} # A table for keeping track of path requests on behalf of other nodes
discovery_pr_tags = [] # A table for keeping track of tagged path requests
@@ -116,6 +118,8 @@ class Transport:
jobs_locked = False
jobs_running = False
job_interval = 0.250
links_last_checked = 0.0
links_check_interval = 1.0
receipts_last_checked = 0.0
receipts_check_interval = 1.0
announces_last_checked = 0.0
@@ -165,8 +169,7 @@ class Transport:
Transport.control_hashes.append(Transport.tunnel_synthesize_destination.hash)
Transport.jobs_running = False
thread = threading.Thread(target=Transport.jobloop)
thread.daemon = True
thread = threading.Thread(target=Transport.jobloop, daemon=True)
thread.start()
if RNS.Reticulum.transport_enabled():
@@ -266,8 +269,6 @@ class Transport:
except Exception as e:
RNS.log("Could not load tunnel table from storage, the contained exception was: "+str(e), RNS.LOG_ERROR)
RNS.log("Transport instance "+str(Transport.identity)+" started", RNS.LOG_VERBOSE)
# Synthesize tunnels for any interfaces wanting it
@@ -285,10 +286,44 @@ class Transport:
@staticmethod
def jobs():
outgoing = []
path_requests = []
Transport.jobs_running = True
try:
if not Transport.jobs_locked:
# Process active and pending link lists
if time.time() > Transport.links_last_checked+Transport.links_check_interval:
for link in Transport.pending_links:
if link.status == RNS.Link.CLOSED:
# If we are not a Transport Instance, finding a pending link
# that was never activated will trigger an expiry of the path
# to the destination, and an attempt to rediscover the path.
if not RNS.Reticulum.transport_enabled():
Transport.expire_path(link.destination.hash)
# If we are connected to a shared instance, it will take
# care of sending out a new path request. If not, we will
# send one directly.
if not Transport.owner.is_connected_to_shared_instance:
last_path_request = 0
if link.destination.hash in Transport.path_requests:
last_path_request = Transport.path_requests[link.destination.hash]
if time.time() - last_path_request > Transport.PATH_REQUEST_MI:
RNS.log("Trying to rediscover path for "+RNS.prettyhexrep(link.destination.hash)+" since an attempted link was never established", RNS.LOG_DEBUG)
if not link.destination.hash in path_requests:
path_requests.append(link.destination.hash)
Transport.pending_links.remove(link)
for link in Transport.active_links:
if link.status == RNS.Link.CLOSED:
Transport.active_links.remove(link)
Transport.links_last_checked = time.time()
# Process receipts list for timed-out packets
if time.time() > Transport.receipts_last_checked+Transport.receipts_check_interval:
while len(Transport.receipts) > Transport.MAX_RECEIPTS:
@@ -380,8 +415,32 @@ class Transport:
stale_links = []
for link_id in Transport.link_table:
link_entry = Transport.link_table[link_id]
if time.time() > link_entry[0] + Transport.LINK_TIMEOUT:
stale_links.append(link_id)
if link_entry[7] == True:
if time.time() > link_entry[0] + Transport.LINK_TIMEOUT:
stale_links.append(link_id)
else:
if time.time() > link_entry[8]:
stale_links.append(link_id)
last_path_request = 0
if link_entry[6] in Transport.path_requests:
last_path_request = Transport.path_requests[link_entry[6]]
# If this link request was originated from a local client
# attempt to rediscover a path to the destination, if this
# has not already happened recently.
lr_taken_hops = link_entry[5]
if lr_taken_hops == 0 and time.time() - last_path_request > Transport.PATH_REQUEST_MI:
RNS.log("Trying to rediscover path for "+RNS.prettyhexrep(link_entry[6])+" since an attempted local client link was never established", RNS.LOG_DEBUG)
if not link_entry[6] in path_requests:
path_requests.append(link_entry[6])
if not RNS.Reticulum.transport_enabled():
# Drop current path if we are not a transport instance, to
# allow using higher-hop count paths or reused announces
# from newly adjacent transport instances.
Transport.expire_path(link_entry[6])
# Cull the path table
stale_paths = []
@@ -504,6 +563,10 @@ class Transport:
Transport.tables_last_culled = time.time()
else:
# Transport jobs were locked, do nothing
pass
except Exception as e:
RNS.log("An exception occurred while running Transport jobs.", RNS.LOG_ERROR)
RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR)
@@ -513,6 +576,9 @@ class Transport:
for packet in outgoing:
packet.send()
for destination_hash in path_requests:
Transport.request_path(destination_hash)
@staticmethod
def transmit(interface, raw):
try:
@@ -540,9 +606,6 @@ class Transport:
Transport.jobs_locked = True
# TODO: This updateHash call might be redundant
# packet.update_hash()
sent = False
outbound_time = time.time()
@@ -998,15 +1061,19 @@ class Transport:
outbound_interface = Transport.destination_table[packet.destination_hash][5]
if packet.packet_type == RNS.Packet.LINKREQUEST:
now = time.time()
proof_timeout = now + RNS.Link.ESTABLISHMENT_TIMEOUT_PER_HOP * max(1, remaining_hops)
# Entry format is
link_entry = [ time.time(), # 0: Timestamp,
link_entry = [ now, # 0: Timestamp,
next_hop, # 1: Next-hop transport ID
outbound_interface, # 2: Next-hop interface
remaining_hops, # 3: Remaining hops
packet.receiving_interface, # 4: Received on interface
packet.hops, # 5: Taken hops
packet.destination_hash, # 6: Original destination hash
False] # 7: Validated
False, # 7: Validated
proof_timeout] # 8: Proof timeout timestamp
Transport.link_table[packet.getTruncatedHash()] = link_entry
@@ -1206,9 +1273,9 @@ class Transport:
retransmit_timeout = now + (RNS.rand() * Transport.PATHFINDER_RW)
if packet.receiving_interface.mode == RNS.Interfaces.Interface.Interface.MODE_ACCESS_POINT:
if hasattr(packet.receiving_interface, "mode") and packet.receiving_interface.mode == RNS.Interfaces.Interface.Interface.MODE_ACCESS_POINT:
expires = now + Transport.AP_PATH_TIME
elif packet.receiving_interface.mode == RNS.Interfaces.Interface.Interface.MODE_ROAMING:
elif hasattr(packet.receiving_interface, "mode") and packet.receiving_interface.mode == RNS.Interfaces.Interface.Interface.MODE_ROAMING:
expires = now + Transport.ROAMING_PATH_TIME
else:
expires = now + Transport.PATHFINDER_E
@@ -1381,10 +1448,11 @@ class Transport:
# Handling for linkrequests to local destinations
elif packet.packet_type == RNS.Packet.LINKREQUEST:
for destination in Transport.destinations:
if destination.hash == packet.destination_hash and destination.type == packet.destination_type:
packet.destination = destination
destination.receive(packet)
if packet.transport_id == None or packet.transport_id == Transport.identity.hash:
for destination in Transport.destinations:
if destination.hash == packet.destination_hash and destination.type == packet.destination_type:
packet.destination = destination
destination.receive(packet)
# Handling for local data packets
elif packet.packet_type == RNS.Packet.DATA:
@@ -1418,14 +1486,29 @@ class Transport:
if (RNS.Reticulum.transport_enabled() or for_local_client_link or from_local_client) and packet.destination_hash in Transport.link_table:
link_entry = Transport.link_table[packet.destination_hash]
if packet.receiving_interface == link_entry[2]:
# TODO: Should we validate the LR proof at each transport
# step before transporting it?
# RNS.log("Link request proof received on correct interface, transporting it via "+str(link_entry[4]), RNS.LOG_EXTREME)
new_raw = packet.raw[0:1]
new_raw += struct.pack("!B", packet.hops)
new_raw += packet.raw[2:]
Transport.link_table[packet.destination_hash][7] = True
Transport.transmit(link_entry[4], new_raw)
try:
if len(packet.data) == RNS.Identity.SIGLENGTH//8+RNS.Link.ECPUBSIZE//2:
peer_pub_bytes = packet.data[RNS.Identity.SIGLENGTH//8:RNS.Identity.SIGLENGTH//8+RNS.Link.ECPUBSIZE//2]
peer_identity = RNS.Identity.recall(link_entry[6])
peer_sig_pub_bytes = peer_identity.get_public_key()[RNS.Link.ECPUBSIZE//2:RNS.Link.ECPUBSIZE]
signed_data = packet.destination_hash+peer_pub_bytes+peer_sig_pub_bytes
signature = packet.data[:RNS.Identity.SIGLENGTH//8]
if peer_identity.validate(signature, signed_data):
RNS.log("Link request proof validated for transport via "+str(link_entry[4]), RNS.LOG_EXTREME)
new_raw = packet.raw[0:1]
new_raw += struct.pack("!B", packet.hops)
new_raw += packet.raw[2:]
Transport.link_table[packet.destination_hash][7] = True
Transport.transmit(link_entry[4], new_raw)
else:
RNS.log("Invalid link request proof in transport for link "+RNS.prettyhexrep(packet.destination_hash)+", dropping proof.", RNS.LOG_DEBUG)
except Exception as e:
RNS.log("Error while transporting link request proof. The contained exception was: "+str(e), RNS.LOG_ERROR)
else:
RNS.log("Link request proof received on wrong interface, not transporting it.", RNS.LOG_DEBUG)
else:
@@ -1600,7 +1683,7 @@ class Transport:
@staticmethod
def register_link(link):
RNS.log("Registering link "+str(link), RNS.LOG_DEBUG)
RNS.log("Registering link "+str(link), RNS.LOG_EXTREME)
if link.initiator:
Transport.pending_links.append(link)
else:
@@ -1608,7 +1691,7 @@ class Transport:
@staticmethod
def activate_link(link):
RNS.log("Activating link "+str(link), RNS.LOG_DEBUG)
RNS.log("Activating link "+str(link), RNS.LOG_EXTREME)
if link in Transport.pending_links:
Transport.pending_links.remove(link)
Transport.active_links.append(link)
@@ -1829,6 +1912,7 @@ class Transport:
on_interface.announce_allowed_at = now + wait_time
packet.send()
Transport.path_requests[destination_hash] = time.time()
@staticmethod
def path_request_handler(data, packet):
@@ -1905,10 +1989,9 @@ class Transport:
local_destination = next((d for d in Transport.destinations if d.hash == destination_hash), None)
if local_destination != None:
local_destination.announce(path_response=True)
local_destination.announce(path_response=True, tag=tag, attached_interface=attached_interface)
RNS.log("Answering path request for "+RNS.prettyhexrep(destination_hash)+interface_str+", destination is local to this system", RNS.LOG_DEBUG)
elif (RNS.Reticulum.transport_enabled() or is_from_local_client) and (destination_hash in Transport.destination_table):
packet = Transport.destination_table[destination_hash][6]
next_hop = Transport.destination_table[destination_hash][1]
@@ -1953,9 +2036,10 @@ class Transport:
# Forward path request on all interfaces
# except the local client
RNS.log("Forwarding path request from local client for "+RNS.prettyhexrep(destination_hash)+interface_str+" to all other interfaces", RNS.LOG_DEBUG)
request_tag = RNS.Identity.get_random_hash()
for interface in Transport.interfaces:
if not interface == attached_interface:
Transport.request_path(destination_hash, interface)
Transport.request_path(destination_hash, interface, tag = request_tag)
elif should_search_for_unknown:
if destination_hash in Transport.discovery_path_requests:
+6 -1
View File
@@ -1073,7 +1073,7 @@ def main():
print(" ["+str(pi)+"] "+str(port.device)+" ("+str(port.product)+", "+str(port.serial_number)+")")
pi += 1
print("\nWhat serial port is your device connected to? ", end="")
print("\nEnter the number of the serial port your device is connected to: ", end="")
try:
c_port = int(input())
if c_port < 1 or c_port > len(ports):
@@ -1206,6 +1206,11 @@ def main():
print("---------------------------------------------------------------------------")
print("Important! Using RNode firmware on Heltec devices should currently be")
print("considered experimental. It is not intended for production or critical use.")
print("")
print("Please also note that a number of users have reported issues with the serial")
print("to USB chips on Heltec LoRa V2 boards, resulting in intermittent USB comms")
print("and problems flashing and updating devices.")
print("")
print("The currently supplied firmware is provided AS-IS as a courtesey to those")
print("who would like to experiment with it. Hit enter to continue.")
print("---------------------------------------------------------------------------")
+1 -1
View File
@@ -1 +1 @@
__version__ = "0.4.2"
__version__ = "0.4.6"
Binary file not shown.
+1 -1
View File
@@ -1,4 +1,4 @@
# Sphinx build info version 1
# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
config: 458f32f98c8ba291b785b017881b2732
config: bb57e47d574f578f08360b71e3487c38
tags: 645f666f9bcd5a90fca523b33c5a78b7
+5 -9
View File
@@ -160,12 +160,13 @@ Installation
Once you have obtained compatible boards, you can install the `RNode Firmware <https://github.com/markqvist/RNode_Firmware>`_
using the `RNode Configuration Utility <https://github.com/markqvist/rnodeconfigutil>`_.
Make sure that ``Python3`` and ``pip`` is installed on your system, and then install
the config utility with ``pip``:
If you have installed Reticulum on your system, the ``rnodeconf`` program will already be
available. If not, make sure that ``Python3`` and ``pip`` is installed on your system, and
then install Reticulum with with ``pip``:
.. code::
pip3 install rnodeconf
pip3 install rns
Once installation has completed, it is time to start installing the firmware on your
devices. Run ``rnodeconf`` in auto-install mode like so:
@@ -176,12 +177,7 @@ devices. Run ``rnodeconf`` in auto-install mode like so:
The utility will guide you through the installation process by asking a series of
questions about your hardware. Simply follow the guide, and the utility will
auto-install and configure your devices
**Important Note!** It is currently recommended to use the v1.x line of the RNode firmware,
even though the v2.x line is available for early testing. The v2.x line should still be
considered an experimental pre-release. Only use the v2.x firmware line if you want to test
out the absolutely newest version, and don't care about stability.
auto-install and configure your devices.
.. _rnode-usage:
+1 -1
View File
@@ -1,6 +1,6 @@
var DOCUMENTATION_OPTIONS = {
URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'),
VERSION: '0.4.2 beta',
VERSION: '0.4.6 beta',
LANGUAGE: 'en',
COLLAPSE_INDEX: false,
BUILDER: 'html',
+3 -3
View File
@@ -6,7 +6,7 @@
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Support Reticulum" href="support.html" /><link rel="prev" title="Building Networks" href="networks.html" />
<meta name="generator" content="sphinx-5.2.2, furo 2022.09.29"/>
<title>Code Examples - Reticulum Network Stack 0.4.2 beta documentation</title>
<title>Code Examples - Reticulum Network Stack 0.4.6 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=d81277517bee4d6b0349d71bb2661d4890b5617c" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
@@ -141,7 +141,7 @@
</label>
</div>
<div class="header-center">
<a href="index.html"><div class="brand">Reticulum Network Stack 0.4.2 beta documentation</div></a>
<a href="index.html"><div class="brand">Reticulum Network Stack 0.4.6 beta documentation</div></a>
</div>
<div class="header-right">
<div class="theme-toggle-container theme-toggle-header">
@@ -167,7 +167,7 @@
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
</div>
<span class="sidebar-brand-text">Reticulum Network Stack 0.4.2 beta documentation</span>
<span class="sidebar-brand-text">Reticulum Network Stack 0.4.6 beta documentation</span>
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
<input class="sidebar-search" placeholder=Search name="q" aria-label="Search">
+3 -3
View File
@@ -4,7 +4,7 @@
<meta name="viewport" content="width=device-width,initial-scale=1"/>
<meta name="color-scheme" content="light dark"><link rel="index" title="Index" href="#" /><link rel="search" title="Search" href="search.html" />
<meta name="generator" content="sphinx-5.2.2, furo 2022.09.29"/><title>Index - Reticulum Network Stack 0.4.2 beta documentation</title>
<meta name="generator" content="sphinx-5.2.2, furo 2022.09.29"/><title>Index - Reticulum Network Stack 0.4.6 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=d81277517bee4d6b0349d71bb2661d4890b5617c" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
@@ -139,7 +139,7 @@
</label>
</div>
<div class="header-center">
<a href="index.html"><div class="brand">Reticulum Network Stack 0.4.2 beta documentation</div></a>
<a href="index.html"><div class="brand">Reticulum Network Stack 0.4.6 beta documentation</div></a>
</div>
<div class="header-right">
<div class="theme-toggle-container theme-toggle-header">
@@ -165,7 +165,7 @@
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
</div>
<span class="sidebar-brand-text">Reticulum Network Stack 0.4.2 beta documentation</span>
<span class="sidebar-brand-text">Reticulum Network Stack 0.4.6 beta documentation</span>
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
<input class="sidebar-search" placeholder=Search name="q" aria-label="Search">
+3 -3
View File
@@ -6,7 +6,7 @@
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Using Reticulum on Your System" href="using.html" /><link rel="prev" title="What is Reticulum?" href="whatis.html" />
<meta name="generator" content="sphinx-5.2.2, furo 2022.09.29"/>
<title>Getting Started Fast - Reticulum Network Stack 0.4.2 beta documentation</title>
<title>Getting Started Fast - Reticulum Network Stack 0.4.6 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=d81277517bee4d6b0349d71bb2661d4890b5617c" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
@@ -141,7 +141,7 @@
</label>
</div>
<div class="header-center">
<a href="index.html"><div class="brand">Reticulum Network Stack 0.4.2 beta documentation</div></a>
<a href="index.html"><div class="brand">Reticulum Network Stack 0.4.6 beta documentation</div></a>
</div>
<div class="header-right">
<div class="theme-toggle-container theme-toggle-header">
@@ -167,7 +167,7 @@
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
</div>
<span class="sidebar-brand-text">Reticulum Network Stack 0.4.2 beta documentation</span>
<span class="sidebar-brand-text">Reticulum Network Stack 0.4.6 beta documentation</span>
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
<input class="sidebar-search" placeholder=Search name="q" aria-label="Search">
+8 -11
View File
@@ -6,7 +6,7 @@
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Supported Interfaces" href="interfaces.html" /><link rel="prev" title="Understanding Reticulum" href="understanding.html" />
<meta name="generator" content="sphinx-5.2.2, furo 2022.09.29"/>
<title>Communications Hardware - Reticulum Network Stack 0.4.2 beta documentation</title>
<title>Communications Hardware - Reticulum Network Stack 0.4.6 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=d81277517bee4d6b0349d71bb2661d4890b5617c" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
@@ -141,7 +141,7 @@
</label>
</div>
<div class="header-center">
<a href="index.html"><div class="brand">Reticulum Network Stack 0.4.2 beta documentation</div></a>
<a href="index.html"><div class="brand">Reticulum Network Stack 0.4.6 beta documentation</div></a>
</div>
<div class="header-right">
<div class="theme-toggle-container theme-toggle-header">
@@ -167,7 +167,7 @@
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
</div>
<span class="sidebar-brand-text">Reticulum Network Stack 0.4.2 beta documentation</span>
<span class="sidebar-brand-text">Reticulum Network Stack 0.4.6 beta documentation</span>
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
<input class="sidebar-search" placeholder=Search name="q" aria-label="Search">
@@ -349,9 +349,10 @@ boards. The following boards are supported by the auto-installer.</p>
<span id="rnode-installation"></span><h3>Installation<a class="headerlink" href="#installation" title="Permalink to this heading">#</a></h3>
<p>Once you have obtained compatible boards, you can install the <a class="reference external" href="https://github.com/markqvist/RNode_Firmware">RNode Firmware</a>
using the <a class="reference external" href="https://github.com/markqvist/rnodeconfigutil">RNode Configuration Utility</a>.
Make sure that <code class="docutils literal notranslate"><span class="pre">Python3</span></code> and <code class="docutils literal notranslate"><span class="pre">pip</span></code> is installed on your system, and then install
the config utility with <code class="docutils literal notranslate"><span class="pre">pip</span></code>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip3</span> <span class="n">install</span> <span class="n">rnodeconf</span>
If you have installed Reticulum on your system, the <code class="docutils literal notranslate"><span class="pre">rnodeconf</span></code> program will already be
available. If not, make sure that <code class="docutils literal notranslate"><span class="pre">Python3</span></code> and <code class="docutils literal notranslate"><span class="pre">pip</span></code> is installed on your system, and
then install Reticulum with with <code class="docutils literal notranslate"><span class="pre">pip</span></code>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip3</span> <span class="n">install</span> <span class="n">rns</span>
</pre></div>
</div>
<p>Once installation has completed, it is time to start installing the firmware on your
@@ -361,11 +362,7 @@ devices. Run <code class="docutils literal notranslate"><span class="pre">rnodec
</div>
<p>The utility will guide you through the installation process by asking a series of
questions about your hardware. Simply follow the guide, and the utility will
auto-install and configure your devices</p>
<p><strong>Important Note!</strong> It is currently recommended to use the v1.x line of the RNode firmware,
even though the v2.x line is available for early testing. The v2.x line should still be
considered an experimental pre-release. Only use the v2.x firmware line if you want to test
out the absolutely newest version, and dont care about stability.</p>
auto-install and configure your devices.</p>
</section>
<section id="usage-with-reticulum">
<span id="rnode-usage"></span><h3>Usage with Reticulum<a class="headerlink" href="#usage-with-reticulum" title="Permalink to this heading">#</a></h3>
+3 -3
View File
@@ -6,7 +6,7 @@
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="What is Reticulum?" href="whatis.html" />
<meta name="generator" content="sphinx-5.2.2, furo 2022.09.29"/>
<title>Reticulum Network Stack 0.4.2 beta documentation</title>
<title>Reticulum Network Stack 0.4.6 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=d81277517bee4d6b0349d71bb2661d4890b5617c" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
@@ -141,7 +141,7 @@
</label>
</div>
<div class="header-center">
<a href="#"><div class="brand">Reticulum Network Stack 0.4.2 beta documentation</div></a>
<a href="#"><div class="brand">Reticulum Network Stack 0.4.6 beta documentation</div></a>
</div>
<div class="header-right">
<div class="theme-toggle-container theme-toggle-header">
@@ -167,7 +167,7 @@
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
</div>
<span class="sidebar-brand-text">Reticulum Network Stack 0.4.2 beta documentation</span>
<span class="sidebar-brand-text">Reticulum Network Stack 0.4.6 beta documentation</span>
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
<input class="sidebar-search" placeholder=Search name="q" aria-label="Search">
+3 -3
View File
@@ -6,7 +6,7 @@
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Building Networks" href="networks.html" /><link rel="prev" title="Communications Hardware" href="hardware.html" />
<meta name="generator" content="sphinx-5.2.2, furo 2022.09.29"/>
<title>Supported Interfaces - Reticulum Network Stack 0.4.2 beta documentation</title>
<title>Supported Interfaces - Reticulum Network Stack 0.4.6 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=d81277517bee4d6b0349d71bb2661d4890b5617c" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
@@ -141,7 +141,7 @@
</label>
</div>
<div class="header-center">
<a href="index.html"><div class="brand">Reticulum Network Stack 0.4.2 beta documentation</div></a>
<a href="index.html"><div class="brand">Reticulum Network Stack 0.4.6 beta documentation</div></a>
</div>
<div class="header-right">
<div class="theme-toggle-container theme-toggle-header">
@@ -167,7 +167,7 @@
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
</div>
<span class="sidebar-brand-text">Reticulum Network Stack 0.4.2 beta documentation</span>
<span class="sidebar-brand-text">Reticulum Network Stack 0.4.6 beta documentation</span>
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
<input class="sidebar-search" placeholder=Search name="q" aria-label="Search">
+3 -3
View File
@@ -6,7 +6,7 @@
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Code Examples" href="examples.html" /><link rel="prev" title="Supported Interfaces" href="interfaces.html" />
<meta name="generator" content="sphinx-5.2.2, furo 2022.09.29"/>
<title>Building Networks - Reticulum Network Stack 0.4.2 beta documentation</title>
<title>Building Networks - Reticulum Network Stack 0.4.6 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=d81277517bee4d6b0349d71bb2661d4890b5617c" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
@@ -141,7 +141,7 @@
</label>
</div>
<div class="header-center">
<a href="index.html"><div class="brand">Reticulum Network Stack 0.4.2 beta documentation</div></a>
<a href="index.html"><div class="brand">Reticulum Network Stack 0.4.6 beta documentation</div></a>
</div>
<div class="header-right">
<div class="theme-toggle-container theme-toggle-header">
@@ -167,7 +167,7 @@
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
</div>
<span class="sidebar-brand-text">Reticulum Network Stack 0.4.2 beta documentation</span>
<span class="sidebar-brand-text">Reticulum Network Stack 0.4.6 beta documentation</span>
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
<input class="sidebar-search" placeholder=Search name="q" aria-label="Search">
+4 -4
View File
@@ -6,7 +6,7 @@
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="prev" title="Support Reticulum" href="support.html" />
<meta name="generator" content="sphinx-5.2.2, furo 2022.09.29"/>
<title>API Reference - Reticulum Network Stack 0.4.2 beta documentation</title>
<title>API Reference - Reticulum Network Stack 0.4.6 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=d81277517bee4d6b0349d71bb2661d4890b5617c" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
@@ -141,7 +141,7 @@
</label>
</div>
<div class="header-center">
<a href="index.html"><div class="brand">Reticulum Network Stack 0.4.2 beta documentation</div></a>
<a href="index.html"><div class="brand">Reticulum Network Stack 0.4.6 beta documentation</div></a>
</div>
<div class="header-right">
<div class="theme-toggle-container theme-toggle-header">
@@ -167,7 +167,7 @@
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
</div>
<span class="sidebar-brand-text">Reticulum Network Stack 0.4.2 beta documentation</span>
<span class="sidebar-brand-text">Reticulum Network Stack 0.4.6 beta documentation</span>
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
<input class="sidebar-search" placeholder=Search name="q" aria-label="Search">
@@ -637,7 +637,7 @@ encrypted communication with it.</p>
<dl class="py method">
<dt class="sig sig-object py" id="RNS.Destination.announce">
<span class="sig-name descname"><span class="pre">announce</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">app_data</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">path_response</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">False</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">send</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">True</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Destination.announce" title="Permalink to this definition">#</a></dt>
<span class="sig-name descname"><span class="pre">announce</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">app_data</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">path_response</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">False</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">attached_interface</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">tag</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">send</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">True</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Destination.announce" title="Permalink to this definition">#</a></dt>
<dd><p>Creates an announce packet for this destination and broadcasts it on all
relevant interfaces. Application specific data can be added to the announce.</p>
<dl class="field-list simple">
+3 -3
View File
@@ -4,7 +4,7 @@
<meta name="viewport" content="width=device-width,initial-scale=1"/>
<meta name="color-scheme" content="light dark"><link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="#" />
<meta name="generator" content="sphinx-5.2.2, furo 2022.09.29"/><title>Search - Reticulum Network Stack 0.4.2 beta documentation</title><link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<meta name="generator" content="sphinx-5.2.2, furo 2022.09.29"/><title>Search - Reticulum Network Stack 0.4.6 beta documentation</title><link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=d81277517bee4d6b0349d71bb2661d4890b5617c" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo-extensions.css?digest=30d1aed668e5c3a91c3e3bf6a60b675221979f0e" />
@@ -138,7 +138,7 @@
</label>
</div>
<div class="header-center">
<a href="index.html"><div class="brand">Reticulum Network Stack 0.4.2 beta documentation</div></a>
<a href="index.html"><div class="brand">Reticulum Network Stack 0.4.6 beta documentation</div></a>
</div>
<div class="header-right">
<div class="theme-toggle-container theme-toggle-header">
@@ -164,7 +164,7 @@
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
</div>
<span class="sidebar-brand-text">Reticulum Network Stack 0.4.2 beta documentation</span>
<span class="sidebar-brand-text">Reticulum Network Stack 0.4.6 beta documentation</span>
</a><form class="sidebar-search-container" method="get" action="#" role="search">
<input class="sidebar-search" placeholder=Search name="q" aria-label="Search">
File diff suppressed because one or more lines are too long
+3 -3
View File
@@ -6,7 +6,7 @@
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="API Reference" href="reference.html" /><link rel="prev" title="Code Examples" href="examples.html" />
<meta name="generator" content="sphinx-5.2.2, furo 2022.09.29"/>
<title>Support Reticulum - Reticulum Network Stack 0.4.2 beta documentation</title>
<title>Support Reticulum - Reticulum Network Stack 0.4.6 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=d81277517bee4d6b0349d71bb2661d4890b5617c" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
@@ -141,7 +141,7 @@
</label>
</div>
<div class="header-center">
<a href="index.html"><div class="brand">Reticulum Network Stack 0.4.2 beta documentation</div></a>
<a href="index.html"><div class="brand">Reticulum Network Stack 0.4.6 beta documentation</div></a>
</div>
<div class="header-right">
<div class="theme-toggle-container theme-toggle-header">
@@ -167,7 +167,7 @@
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
</div>
<span class="sidebar-brand-text">Reticulum Network Stack 0.4.2 beta documentation</span>
<span class="sidebar-brand-text">Reticulum Network Stack 0.4.6 beta documentation</span>
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
<input class="sidebar-search" placeholder=Search name="q" aria-label="Search">
+3 -3
View File
@@ -6,7 +6,7 @@
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Communications Hardware" href="hardware.html" /><link rel="prev" title="Using Reticulum on Your System" href="using.html" />
<meta name="generator" content="sphinx-5.2.2, furo 2022.09.29"/>
<title>Understanding Reticulum - Reticulum Network Stack 0.4.2 beta documentation</title>
<title>Understanding Reticulum - Reticulum Network Stack 0.4.6 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=d81277517bee4d6b0349d71bb2661d4890b5617c" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
@@ -141,7 +141,7 @@
</label>
</div>
<div class="header-center">
<a href="index.html"><div class="brand">Reticulum Network Stack 0.4.2 beta documentation</div></a>
<a href="index.html"><div class="brand">Reticulum Network Stack 0.4.6 beta documentation</div></a>
</div>
<div class="header-right">
<div class="theme-toggle-container theme-toggle-header">
@@ -167,7 +167,7 @@
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
</div>
<span class="sidebar-brand-text">Reticulum Network Stack 0.4.2 beta documentation</span>
<span class="sidebar-brand-text">Reticulum Network Stack 0.4.6 beta documentation</span>
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
<input class="sidebar-search" placeholder=Search name="q" aria-label="Search">
+3 -3
View File
@@ -6,7 +6,7 @@
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Understanding Reticulum" href="understanding.html" /><link rel="prev" title="Getting Started Fast" href="gettingstartedfast.html" />
<meta name="generator" content="sphinx-5.2.2, furo 2022.09.29"/>
<title>Using Reticulum on Your System - Reticulum Network Stack 0.4.2 beta documentation</title>
<title>Using Reticulum on Your System - Reticulum Network Stack 0.4.6 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=d81277517bee4d6b0349d71bb2661d4890b5617c" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
@@ -141,7 +141,7 @@
</label>
</div>
<div class="header-center">
<a href="index.html"><div class="brand">Reticulum Network Stack 0.4.2 beta documentation</div></a>
<a href="index.html"><div class="brand">Reticulum Network Stack 0.4.6 beta documentation</div></a>
</div>
<div class="header-right">
<div class="theme-toggle-container theme-toggle-header">
@@ -167,7 +167,7 @@
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
</div>
<span class="sidebar-brand-text">Reticulum Network Stack 0.4.2 beta documentation</span>
<span class="sidebar-brand-text">Reticulum Network Stack 0.4.6 beta documentation</span>
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
<input class="sidebar-search" placeholder=Search name="q" aria-label="Search">
+3 -3
View File
@@ -6,7 +6,7 @@
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Getting Started Fast" href="gettingstartedfast.html" /><link rel="prev" title="Reticulum Network Stack Manual" href="index.html" />
<meta name="generator" content="sphinx-5.2.2, furo 2022.09.29"/>
<title>What is Reticulum? - Reticulum Network Stack 0.4.2 beta documentation</title>
<title>What is Reticulum? - Reticulum Network Stack 0.4.6 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=d81277517bee4d6b0349d71bb2661d4890b5617c" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
@@ -141,7 +141,7 @@
</label>
</div>
<div class="header-center">
<a href="index.html"><div class="brand">Reticulum Network Stack 0.4.2 beta documentation</div></a>
<a href="index.html"><div class="brand">Reticulum Network Stack 0.4.6 beta documentation</div></a>
</div>
<div class="header-right">
<div class="theme-toggle-container theme-toggle-header">
@@ -167,7 +167,7 @@
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
</div>
<span class="sidebar-brand-text">Reticulum Network Stack 0.4.2 beta documentation</span>
<span class="sidebar-brand-text">Reticulum Network Stack 0.4.6 beta documentation</span>
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
<input class="sidebar-search" placeholder=Search name="q" aria-label="Search">
+5 -9
View File
@@ -160,12 +160,13 @@ Installation
Once you have obtained compatible boards, you can install the `RNode Firmware <https://github.com/markqvist/RNode_Firmware>`_
using the `RNode Configuration Utility <https://github.com/markqvist/rnodeconfigutil>`_.
Make sure that ``Python3`` and ``pip`` is installed on your system, and then install
the config utility with ``pip``:
If you have installed Reticulum on your system, the ``rnodeconf`` program will already be
available. If not, make sure that ``Python3`` and ``pip`` is installed on your system, and
then install Reticulum with with ``pip``:
.. code::
pip3 install rnodeconf
pip3 install rns
Once installation has completed, it is time to start installing the firmware on your
devices. Run ``rnodeconf`` in auto-install mode like so:
@@ -176,12 +177,7 @@ devices. Run ``rnodeconf`` in auto-install mode like so:
The utility will guide you through the installation process by asking a series of
questions about your hardware. Simply follow the guide, and the utility will
auto-install and configure your devices
**Important Note!** It is currently recommended to use the v1.x line of the RNode firmware,
even though the v2.x line is available for early testing. The v2.x line should still be
considered an experimental pre-release. Only use the v2.x firmware line if you want to test
out the absolutely newest version, and don't care about stability.
auto-install and configure your devices.
.. _rnode-usage: