Added RSSI and SNR reporting to packets on supported interfaces

This commit is contained in:
Mark Qvist 2021-10-12 16:34:17 +02:00
parent c37533d2c7
commit 1cf6570c2d
6 changed files with 97 additions and 7 deletions

View File

@ -283,6 +283,8 @@ class RNodeInterface(Interface):
def processIncoming(self, data): def processIncoming(self, data):
self.rxb += len(data) self.rxb += len(data)
self.owner.inbound(data, self) self.owner.inbound(data, self)
self.r_stat_rssi = None
self.r_stat_snr = None
def processOutgoing(self,data): def processOutgoing(self,data):

View File

@ -113,6 +113,8 @@ class Packet:
self.attached_interface = attached_interface self.attached_interface = attached_interface
self.receiving_interface = None self.receiving_interface = None
self.rssi = None
self.snr = None
def get_packed_flags(self): def get_packed_flags(self):
if self.context == Packet.LRPROOF: if self.context == Packet.LRPROOF:
@ -328,6 +330,7 @@ class PacketReceipt:
self.destination = packet.destination self.destination = packet.destination
self.callbacks = PacketReceiptCallbacks() self.callbacks = PacketReceiptCallbacks()
self.concluded_at = None self.concluded_at = None
self.proof_packet = None
if packet.destination.type == RNS.Destination.LINK: if packet.destination.type == RNS.Destination.LINK:
self.timeout = packet.destination.rtt * packet.destination.traffic_timeout_factor self.timeout = packet.destination.rtt * packet.destination.traffic_timeout_factor
@ -344,12 +347,12 @@ class PacketReceipt:
# Validate a proof packet # Validate a proof packet
def validate_proof_packet(self, proof_packet): def validate_proof_packet(self, proof_packet):
if hasattr(proof_packet, "link") and proof_packet.link: if hasattr(proof_packet, "link") and proof_packet.link:
return self.validate_link_proof(proof_packet.data, proof_packet.link) return self.validate_link_proof(proof_packet.data, proof_packet.link, proof_packet)
else: else:
return self.validate_proof(proof_packet.data) return self.validate_proof(proof_packet.data, proof_packet)
# Validate a raw proof for a link # Validate a raw proof for a link
def validate_link_proof(self, proof, link): def validate_link_proof(self, proof, link, proof_packet=None):
# TODO: Hardcoded as explicit proofs for now # TODO: Hardcoded as explicit proofs for now
if True or len(proof) == PacketReceipt.EXPL_LENGTH: if True or len(proof) == PacketReceipt.EXPL_LENGTH:
# This is an explicit proof # This is an explicit proof
@ -361,6 +364,8 @@ class PacketReceipt:
self.status = PacketReceipt.DELIVERED self.status = PacketReceipt.DELIVERED
self.proved = True self.proved = True
self.concluded_at = time.time() self.concluded_at = time.time()
self.proof_packet = proof_packet
if self.callbacks.delivery != None: if self.callbacks.delivery != None:
self.callbacks.delivery(self) self.callbacks.delivery(self)
return True return True
@ -388,7 +393,7 @@ class PacketReceipt:
return False return False
# Validate a raw proof # Validate a raw proof
def validate_proof(self, proof): def validate_proof(self, proof, proof_packet=None):
if len(proof) == PacketReceipt.EXPL_LENGTH: if len(proof) == PacketReceipt.EXPL_LENGTH:
# This is an explicit proof # This is an explicit proof
proof_hash = proof[:RNS.Identity.HASHLENGTH//8] proof_hash = proof[:RNS.Identity.HASHLENGTH//8]
@ -399,6 +404,8 @@ class PacketReceipt:
self.status = PacketReceipt.DELIVERED self.status = PacketReceipt.DELIVERED
self.proved = True self.proved = True
self.concluded_at = time.time() self.concluded_at = time.time()
self.proof_packet = proof_packet
if self.callbacks.delivery != None: if self.callbacks.delivery != None:
self.callbacks.delivery(self) self.callbacks.delivery(self)
return True return True
@ -417,6 +424,8 @@ class PacketReceipt:
self.status = PacketReceipt.DELIVERED self.status = PacketReceipt.DELIVERED
self.proved = True self.proved = True
self.concluded_at = time.time() self.concluded_at = time.time()
self.proof_packet = proof_packet
if self.callbacks.delivery != None: if self.callbacks.delivery != None:
self.callbacks.delivery(self) self.callbacks.delivery(self)
return True return True

View File

@ -511,6 +511,12 @@ class Reticulum:
if path == "next_hop": if path == "next_hop":
rpc_connection.send(self.get_next_hop(call["destination_hash"])) rpc_connection.send(self.get_next_hop(call["destination_hash"]))
if path == "packet_rssi":
rpc_connection.send(self.get_packet_rssi(call["packet_hash"]))
if path == "packet_snr":
rpc_connection.send(self.get_packet_snr(call["packet_hash"]))
rpc_connection.close() rpc_connection.close()
except Exception as e: except Exception as e:
RNS.log("An error ocurred while handling RPC call from local client: "+str(e), RNS.LOG_ERROR) RNS.log("An error ocurred while handling RPC call from local client: "+str(e), RNS.LOG_ERROR)
@ -545,6 +551,7 @@ class Reticulum:
rpc_connection.send({"get": "next_hop_if_name", "destination_hash": destination}) rpc_connection.send({"get": "next_hop_if_name", "destination_hash": destination})
response = rpc_connection.recv() response = rpc_connection.recv()
return response return response
else: else:
return str(RNS.Transport.next_hop_interface(destination)) return str(RNS.Transport.next_hop_interface(destination))
@ -554,9 +561,38 @@ class Reticulum:
rpc_connection.send({"get": "next_hop", "destination_hash": destination}) rpc_connection.send({"get": "next_hop", "destination_hash": destination})
response = rpc_connection.recv() response = rpc_connection.recv()
return response return response
else: else:
return RNS.Transport.next_hop(destination) return RNS.Transport.next_hop(destination)
def get_packet_rssi(self, packet_hash):
if self.is_connected_to_shared_instance:
rpc_connection = multiprocessing.connection.Client(self.rpc_addr, authkey=self.rpc_key)
rpc_connection.send({"get": "packet_rssi", "packet_hash": packet_hash})
response = rpc_connection.recv()
return response
else:
for entry in RNS.Transport.local_client_rssi_cache:
if entry[0] == packet_hash:
return entry[1]
return None
def get_packet_snr(self, packet_hash):
if self.is_connected_to_shared_instance:
rpc_connection = multiprocessing.connection.Client(self.rpc_addr, authkey=self.rpc_key)
rpc_connection.send({"get": "packet_snr", "packet_hash": packet_hash})
response = rpc_connection.recv()
return response
else:
for entry in RNS.Transport.local_client_snr_cache:
if entry[0] == packet_hash:
return entry[1]
return None
@staticmethod @staticmethod
def should_use_implicit_proof(): def should_use_implicit_proof():

View File

@ -76,6 +76,10 @@ class Transport:
# Reticulum instance # Reticulum instance
local_client_interfaces = [] local_client_interfaces = []
local_client_rssi_cache = []
local_client_snr_cache = []
LOCAL_CLIENT_CACHE_MAXSIZE = 512
jobs_locked = False jobs_locked = False
jobs_running = False jobs_running = False
job_interval = 0.250 job_interval = 0.250
@ -583,10 +587,29 @@ class Transport:
packet.receiving_interface = interface packet.receiving_interface = interface
packet.hops += 1 packet.hops += 1
if interface != None:
if hasattr(interface, "r_stat_rssi"):
if interface.r_stat_rssi != None:
packet.rssi = interface.r_stat_rssi
if len(Transport.local_client_interfaces) > 0: if len(Transport.local_client_interfaces) > 0:
Transport.local_client_rssi_cache.append([packet.packet_hash, packet.rssi])
while len(Transport.local_client_rssi_cache) > Transport.LOCAL_CLIENT_CACHE_MAXSIZE:
Transport.local_client_rssi_cache.pop()
if hasattr(interface, "r_stat_snr"):
if interface.r_stat_rssi != None:
packet.snr = interface.r_stat_snr
if len(Transport.local_client_interfaces) > 0:
Transport.local_client_snr_cache.append([packet.packet_hash, packet.snr])
while len(Transport.local_client_snr_cache) > Transport.LOCAL_CLIENT_CACHE_MAXSIZE:
Transport.local_client_snr_cache.pop()
if len(Transport.local_client_interfaces) > 0:
if Transport.is_local_client_interface(interface): if Transport.is_local_client_interface(interface):
packet.hops -= 1 packet.hops -= 1
elif Transport.interface_to_shared_instance(interface): elif Transport.interface_to_shared_instance(interface):
packet.hops -= 1 packet.hops -= 1

View File

@ -101,11 +101,31 @@ def program_setup(configdir, destination_hexhash, size=DEFAULT_PROBE_SIZE, full_
rtt = round(rtt*1000, 3) rtt = round(rtt*1000, 3)
rttstring = str(rtt)+" milliseconds" rttstring = str(rtt)+" milliseconds"
reception_stats = ""
if reticulum.is_connected_to_shared_instance:
reception_rssi = reticulum.get_packet_rssi(receipt.proof_packet.packet_hash)
reception_snr = reticulum.get_packet_snr(receipt.proof_packet.packet_hash)
if reception_rssi != None:
reception_stats += " [RSSI "+str(reception_rssi)+" dBm]"
if reception_snr != None:
reception_stats += " [SNR "+str(reception_snr)+" dBm]"
else:
if receipt.proof_packet != None:
if receipt.proof_packet.rssi != None:
reception_stats += " [RSSI "+str(receipt.proof_packet.rssi)+" dBm]"
if receipt.proof_packet.snr != None:
reception_stats += " [SNR "+str(receipt.proof_packet.snr)+" dBm]"
print( print(
"Valid reply received from "+ "Valid reply received from "+
RNS.prettyhexrep(receipt.destination.hash)+ RNS.prettyhexrep(receipt.destination.hash)+
"\nRound-trip time is "+rttstring+ "\nRound-trip time is "+rttstring+
" over "+str(hops)+" hop"+ms " over "+str(hops)+" hop"+ms+
reception_stats
) )

View File

@ -1 +1 @@
__version__ = "0.2.8" __version__ = "0.2.9"