Compare commits

...

10 Commits

Author SHA1 Message Date
markqvist
0a15b4c6c1
Merge branch 'master' into master 2024-05-18 00:15:13 +02:00
markqvist
62db09571d
Merge pull request #504 from jacobeva/hash-feature
Add ability to get target and calculated firmware hash from device
2024-05-18 00:04:24 +02:00
Mark Qvist
444ae0206b Added better handling on Windows of interfaces that are non-adoptable for AutoInterface 2024-05-17 23:54:48 +02:00
Mark Qvist
4b07e30b9d Updated version 2024-05-17 23:54:04 +02:00
markqvist
583e65419e
Merge pull request #506 from liamcottle/feature/windows-auto-interface
Implement AutoInterface support on Windows
2024-05-17 16:32:33 +02:00
liamcottle
1564930a51 auto interface working on windows 2024-05-17 04:09:11 +12:00
markqvist
b81b1de4eb
Merge pull request #500 from faragher/master
Windows DTR timing fix
2024-05-15 20:06:36 +02:00
jacob.eva
746a38f818
Add ability to get target and calculated firmware hash from device 2024-05-13 22:55:49 +01:00
faragher
3551662187 Changing log levels 2024-05-08 02:19:59 -05:00
faragher
f7f34e0ea3 Windows DTR timing adjustments 2024-05-08 02:14:29 -05:00
5 changed files with 282 additions and 196 deletions

View File

@ -77,6 +77,15 @@ class AutoInterface(Interface):
ifas = self.netinfo.ifaddresses(ifname) ifas = self.netinfo.ifaddresses(ifname)
return ifas return ifas
def interface_name_to_index(self, ifname):
# socket.if_nametoindex doesn't work with uuid interface names on windows, it wants the ethernet_0 style
# we will just get the index from netinfo instead as it seems to work
if RNS.vendor.platformutils.is_windows():
return self.netinfo.interface_names_to_indexes()[ifname]
return socket.if_nametoindex(ifname)
def __init__(self, owner, name, group_id=None, discovery_scope=None, discovery_port=None, multicast_address_type=None, data_port=None, allowed_interfaces=None, ignored_interfaces=None, configured_bitrate=None): def __init__(self, owner, name, group_id=None, discovery_scope=None, discovery_port=None, multicast_address_type=None, data_port=None, allowed_interfaces=None, ignored_interfaces=None, configured_bitrate=None):
from RNS.vendor.ifaddr import niwrapper from RNS.vendor.ifaddr import niwrapper
super().__init__() super().__init__()
@ -172,69 +181,90 @@ class AutoInterface(Interface):
suitable_interfaces = 0 suitable_interfaces = 0
for ifname in self.list_interfaces(): for ifname in self.list_interfaces():
if RNS.vendor.platformutils.is_darwin() and ifname in AutoInterface.DARWIN_IGNORE_IFS and not ifname in self.allowed_interfaces: try:
RNS.log(str(self)+" skipping Darwin AWDL or tethering interface "+str(ifname), RNS.LOG_EXTREME) if RNS.vendor.platformutils.is_darwin() and ifname in AutoInterface.DARWIN_IGNORE_IFS and not ifname in self.allowed_interfaces:
elif RNS.vendor.platformutils.is_darwin() and ifname == "lo0": RNS.log(str(self)+" skipping Darwin AWDL or tethering interface "+str(ifname), RNS.LOG_EXTREME)
RNS.log(str(self)+" skipping Darwin loopback interface "+str(ifname), RNS.LOG_EXTREME) elif RNS.vendor.platformutils.is_darwin() and ifname == "lo0":
elif RNS.vendor.platformutils.is_android() and ifname in AutoInterface.ANDROID_IGNORE_IFS and not ifname in self.allowed_interfaces: RNS.log(str(self)+" skipping Darwin loopback interface "+str(ifname), RNS.LOG_EXTREME)
RNS.log(str(self)+" skipping Android system interface "+str(ifname), RNS.LOG_EXTREME) elif RNS.vendor.platformutils.is_android() and ifname in AutoInterface.ANDROID_IGNORE_IFS and not ifname in self.allowed_interfaces:
elif ifname in self.ignored_interfaces: RNS.log(str(self)+" skipping Android system interface "+str(ifname), RNS.LOG_EXTREME)
RNS.log(str(self)+" ignoring disallowed interface "+str(ifname), RNS.LOG_EXTREME) elif ifname in self.ignored_interfaces:
elif ifname in AutoInterface.ALL_IGNORE_IFS: RNS.log(str(self)+" ignoring disallowed interface "+str(ifname), RNS.LOG_EXTREME)
RNS.log(str(self)+" skipping interface "+str(ifname), RNS.LOG_EXTREME) elif ifname in AutoInterface.ALL_IGNORE_IFS:
else: RNS.log(str(self)+" skipping interface "+str(ifname), RNS.LOG_EXTREME)
if len(self.allowed_interfaces) > 0 and not ifname in self.allowed_interfaces:
RNS.log(str(self)+" ignoring interface "+str(ifname)+" since it was not allowed", RNS.LOG_EXTREME)
else: else:
addresses = self.list_addresses(ifname) if len(self.allowed_interfaces) > 0 and not ifname in self.allowed_interfaces:
if self.netinfo.AF_INET6 in addresses: RNS.log(str(self)+" ignoring interface "+str(ifname)+" since it was not allowed", RNS.LOG_EXTREME)
link_local_addr = None else:
for address in addresses[self.netinfo.AF_INET6]: addresses = self.list_addresses(ifname)
if "addr" in address: if self.netinfo.AF_INET6 in addresses:
if address["addr"].startswith("fe80:"): link_local_addr = None
link_local_addr = self.descope_linklocal(address["addr"]) for address in addresses[self.netinfo.AF_INET6]:
self.link_local_addresses.append(link_local_addr) if "addr" in address:
self.adopted_interfaces[ifname] = link_local_addr if address["addr"].startswith("fe80:"):
self.multicast_echoes[ifname] = time.time() link_local_addr = self.descope_linklocal(address["addr"])
RNS.log(str(self)+" Selecting link-local address "+str(link_local_addr)+" for interface "+str(ifname), RNS.LOG_EXTREME) self.link_local_addresses.append(link_local_addr)
self.adopted_interfaces[ifname] = link_local_addr
self.multicast_echoes[ifname] = time.time()
nice_name = self.netinfo.interface_name_to_nice_name(ifname)
if nice_name != None and nice_name != ifname:
RNS.log(f"{self} Selecting link-local address {link_local_addr} for interface {nice_name} / {ifname}", RNS.LOG_EXTREME)
else:
RNS.log(f"{self} Selecting link-local address {link_local_addr} for interface {ifname}", RNS.LOG_EXTREME)
if link_local_addr == None: if link_local_addr == None:
RNS.log(str(self)+" No link-local IPv6 address configured for "+str(ifname)+", skipping interface", RNS.LOG_EXTREME) RNS.log(str(self)+" No link-local IPv6 address configured for "+str(ifname)+", skipping interface", RNS.LOG_EXTREME)
else:
mcast_addr = self.mcast_discovery_address
RNS.log(str(self)+" Creating multicast discovery listener on "+str(ifname)+" with address "+str(mcast_addr), RNS.LOG_EXTREME)
# Struct with interface index
if_struct = struct.pack("I", socket.if_nametoindex(ifname))
# Set up multicast socket
discovery_socket = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
discovery_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
if hasattr(socket, "SO_REUSEPORT"):
discovery_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
discovery_socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_IF, if_struct)
# Join multicast group
mcast_group = socket.inet_pton(socket.AF_INET6, mcast_addr) + if_struct
discovery_socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mcast_group)
# Bind socket
if self.discovery_scope == AutoInterface.SCOPE_LINK:
addr_info = socket.getaddrinfo(mcast_addr+"%"+ifname, self.discovery_port, socket.AF_INET6, socket.SOCK_DGRAM)
else: else:
addr_info = socket.getaddrinfo(mcast_addr, self.discovery_port, socket.AF_INET6, socket.SOCK_DGRAM) mcast_addr = self.mcast_discovery_address
RNS.log(str(self)+" Creating multicast discovery listener on "+str(ifname)+" with address "+str(mcast_addr), RNS.LOG_EXTREME)
discovery_socket.bind(addr_info[0][4]) # Struct with interface index
if_struct = struct.pack("I", self.interface_name_to_index(ifname))
# Set up thread for discovery packets # Set up multicast socket
def discovery_loop(): discovery_socket = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
self.discovery_handler(discovery_socket, ifname) discovery_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
if hasattr(socket, "SO_REUSEPORT"):
discovery_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
discovery_socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_IF, if_struct)
thread = threading.Thread(target=discovery_loop) # Join multicast group
thread.daemon = True mcast_group = socket.inet_pton(socket.AF_INET6, mcast_addr) + if_struct
thread.start() discovery_socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mcast_group)
suitable_interfaces += 1 # Bind socket
if RNS.vendor.platformutils.is_windows():
# window throws "[WinError 10049] The requested address is not valid in its context"
# when trying to use the multicast address as host, or when providing interface index
# passing an empty host appears to work, but probably not exactly how we want it to...
discovery_socket.bind(('', self.discovery_port))
else:
if self.discovery_scope == AutoInterface.SCOPE_LINK:
addr_info = socket.getaddrinfo(mcast_addr+"%"+ifname, self.discovery_port, socket.AF_INET6, socket.SOCK_DGRAM)
else:
addr_info = socket.getaddrinfo(mcast_addr, self.discovery_port, socket.AF_INET6, socket.SOCK_DGRAM)
discovery_socket.bind(addr_info[0][4])
# Set up thread for discovery packets
def discovery_loop():
self.discovery_handler(discovery_socket, ifname)
thread = threading.Thread(target=discovery_loop)
thread.daemon = True
thread.start()
suitable_interfaces += 1
except Exception as e:
nice_name = self.netinfo.interface_name_to_nice_name(ifname)
if nice_name != None and nice_name != ifname:
RNS.log(f"Could not configure the system interface {nice_name} / {ifname} for use with {self}, skipping it. The contained exception was: {e}", RNS.LOG_ERROR)
else:
RNS.log(f"Could not configure the system interface {ifname} for use with {self}, skipping it. The contained exception was: {e}", RNS.LOG_ERROR)
if suitable_interfaces == 0: if suitable_interfaces == 0:
RNS.log(str(self)+" could not autoconfigure. This interface currently provides no connectivity.", RNS.LOG_WARNING) RNS.log(str(self)+" could not autoconfigure. This interface currently provides no connectivity.", RNS.LOG_WARNING)
@ -253,7 +283,7 @@ class AutoInterface(Interface):
socketserver.UDPServer.address_family = socket.AF_INET6 socketserver.UDPServer.address_family = socket.AF_INET6
for ifname in self.adopted_interfaces: for ifname in self.adopted_interfaces:
local_addr = self.adopted_interfaces[ifname]+"%"+ifname local_addr = self.adopted_interfaces[ifname]+"%"+str(self.interface_name_to_index(ifname))
addr_info = socket.getaddrinfo(local_addr, self.data_port, socket.AF_INET6, socket.SOCK_DGRAM) addr_info = socket.getaddrinfo(local_addr, self.data_port, socket.AF_INET6, socket.SOCK_DGRAM)
address = addr_info[0][4] address = addr_info[0][4]
@ -380,7 +410,7 @@ class AutoInterface(Interface):
announce_socket = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) announce_socket = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
addr_info = socket.getaddrinfo(self.mcast_discovery_address, self.discovery_port, socket.AF_INET6, socket.SOCK_DGRAM) addr_info = socket.getaddrinfo(self.mcast_discovery_address, self.discovery_port, socket.AF_INET6, socket.SOCK_DGRAM)
ifis = struct.pack("I", socket.if_nametoindex(ifname)) ifis = struct.pack("I", self.interface_name_to_index(ifname))
announce_socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_IF, ifis) announce_socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_IF, ifis)
announce_socket.sendto(discovery_token, addr_info[0][4]) announce_socket.sendto(discovery_token, addr_info[0][4])
announce_socket.close() announce_socket.close()
@ -433,8 +463,8 @@ class AutoInterface(Interface):
try: try:
if self.outbound_udp_socket == None: if self.outbound_udp_socket == None:
self.outbound_udp_socket = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) self.outbound_udp_socket = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
peer_addr = str(peer)+"%"+str(self.peers[peer][0]) peer_addr = str(peer)+"%"+str(self.interface_name_to_index(self.peers[peer][0]))
addr_info = socket.getaddrinfo(peer_addr, self.data_port, socket.AF_INET6, socket.SOCK_DGRAM) addr_info = socket.getaddrinfo(peer_addr, self.data_port, socket.AF_INET6, socket.SOCK_DGRAM)
self.outbound_udp_socket.sendto(data, addr_info[0][4]) self.outbound_udp_socket.sendto(data, addr_info[0][4])

View File

@ -536,46 +536,40 @@ class Reticulum:
if (("interface_enabled" in c) and c.as_bool("interface_enabled") == True) or (("enabled" in c) and c.as_bool("enabled") == True): if (("interface_enabled" in c) and c.as_bool("interface_enabled") == True) or (("enabled" in c) and c.as_bool("enabled") == True):
if c["type"] == "AutoInterface": if c["type"] == "AutoInterface":
if not RNS.vendor.platformutils.is_windows(): group_id = c["group_id"] if "group_id" in c else None
group_id = c["group_id"] if "group_id" in c else None discovery_scope = c["discovery_scope"] if "discovery_scope" in c else None
discovery_scope = c["discovery_scope"] if "discovery_scope" in c else None discovery_port = int(c["discovery_port"]) if "discovery_port" in c else None
discovery_port = int(c["discovery_port"]) if "discovery_port" in c else None multicast_address_type = c["multicast_address_type"] if "multicast_address_type" in c else None
multicast_address_type = c["multicast_address_type"] if "multicast_address_type" in c else None data_port = int(c["data_port"]) if "data_port" in c else None
data_port = int(c["data_port"]) if "data_port" in c else None allowed_interfaces = c.as_list("devices") if "devices" in c else None
allowed_interfaces = c.as_list("devices") if "devices" in c else None ignored_interfaces = c.as_list("ignored_devices") if "ignored_devices" in c else None
ignored_interfaces = c.as_list("ignored_devices") if "ignored_devices" in c else None
interface = AutoInterface.AutoInterface( interface = AutoInterface.AutoInterface(
RNS.Transport, RNS.Transport,
name, name,
group_id, group_id,
discovery_scope, discovery_scope,
discovery_port, discovery_port,
multicast_address_type, multicast_address_type,
data_port, data_port,
allowed_interfaces, allowed_interfaces,
ignored_interfaces ignored_interfaces
) )
if "outgoing" in c and c.as_bool("outgoing") == False:
interface.OUT = False
else:
interface.OUT = True
interface.mode = interface_mode
interface.announce_cap = announce_cap
if configured_bitrate:
interface.bitrate = configured_bitrate
if ifac_size != None:
interface.ifac_size = ifac_size
else:
interface.ifac_size = 16
if "outgoing" in c and c.as_bool("outgoing") == False:
interface.OUT = False
else: else:
RNS.log("AutoInterface is not currently supported on Windows, disabling interface.", RNS.LOG_ERROR); interface.OUT = True
RNS.log("Please remove this AutoInterface instance from your configuration file.", RNS.LOG_ERROR);
RNS.log("You will have to manually configure other interfaces for connectivity.", RNS.LOG_ERROR); interface.mode = interface_mode
interface.announce_cap = announce_cap
if configured_bitrate:
interface.bitrate = configured_bitrate
if ifac_size != None:
interface.ifac_size = ifac_size
else:
interface.ifac_size = 16
if c["type"] == "UDPInterface": if c["type"] == "UDPInterface":
device = c["device"] if "device" in c else None device = c["device"] if "device" in c else None

View File

@ -290,7 +290,7 @@ except Exception as e:
print("No access to directory "+str(CNF_DIR)+". This utility needs file system access to store firmware and data files. Cannot continue.") print("No access to directory "+str(CNF_DIR)+". This utility needs file system access to store firmware and data files. Cannot continue.")
print("The contained exception was:") print("The contained exception was:")
print(str(e)) print(str(e))
exit(99) graceful_exit(99)
squashvw = False squashvw = False
@ -332,6 +332,7 @@ class RNode():
self.checksum = None self.checksum = None
self.device_hash = None self.device_hash = None
self.firmware_hash = None self.firmware_hash = None
self.firmware_hash_target = None
self.signature = None self.signature = None
self.signature_valid = False self.signature_valid = False
self.locally_signed = False self.locally_signed = False
@ -479,6 +480,8 @@ class RNode():
escape = False escape = False
command_buffer = command_buffer+bytes([byte]) command_buffer = command_buffer+bytes([byte])
if (len(command_buffer) == 33): if (len(command_buffer) == 33):
if command_buffer[0] == 0x01:
self.firmware_hash_target = command_buffer[1:]
if command_buffer[0] == 0x02: if command_buffer[0] == 0x02:
self.firmware_hash = command_buffer[1:] self.firmware_hash = command_buffer[1:]
@ -580,7 +583,7 @@ class RNode():
except Exception as e: except Exception as e:
raise e raise e
exit() graceful_exit()
def updateBitrate(self): def updateBitrate(self):
try: try:
@ -596,7 +599,7 @@ class RNode():
self.version = str(self.major_version)+"."+minstr self.version = str(self.major_version)+"."+minstr
def detect(self): 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, KISS.CMD_BOARD, 0x00, KISS.FEND, KISS.CMD_DEV_HASH, 0x01, KISS.FEND, KISS.CMD_HASHES, 0x02, KISS.FEND]) 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, KISS.CMD_BOARD, 0x00, KISS.FEND, KISS.CMD_DEV_HASH, 0x01, KISS.FEND, KISS.CMD_HASHES, 0x01, KISS.FEND, KISS.CMD_HASHES, 0x02, KISS.FEND])
written = self.serial.write(kiss_command) written = self.serial.write(kiss_command)
if written != len(kiss_command): if written != len(kiss_command):
raise IOError("An IO error occurred while detecting hardware for "+self(str)) raise IOError("An IO error occurred while detecting hardware for "+self(str))
@ -606,6 +609,7 @@ class RNode():
written = self.serial.write(kiss_command) written = self.serial.write(kiss_command)
if written != len(kiss_command): if written != len(kiss_command):
raise IOError("An IO error occurred while sending host left command to device") raise IOError("An IO error occurred while sending host left command to device")
sleep(1)
def set_display_intensity(self, intensity): def set_display_intensity(self, intensity):
data = bytes([intensity & 0xFF]) data = bytes([intensity & 0xFF])
@ -773,7 +777,7 @@ class RNode():
sleep(0.6) sleep(0.6)
if self.eeprom == None: if self.eeprom == None:
RNS.log("Could not download EEPROM from device. Is a valid firmware installed?") RNS.log("Could not download EEPROM from device. Is a valid firmware installed?")
exit() graceful_exit()
else: else:
self.parse_eeprom() self.parse_eeprom()
@ -819,7 +823,7 @@ class RNode():
if self.checksum != checksum: if self.checksum != checksum:
self.provisioned = False self.provisioned = False
RNS.log("EEPROM checksum mismatch") RNS.log("EEPROM checksum mismatch")
exit() graceful_exit()
else: else:
RNS.log("EEPROM checksum correct") RNS.log("EEPROM checksum correct")
@ -1000,7 +1004,7 @@ def ensure_firmware_file(fw_filename):
RNS.log("One or more required firmware files are missing from the extracted RNode") RNS.log("One or more required firmware files are missing from the extracted RNode")
RNS.log("Firmware archive. Installation cannot continue. Please try extracting the") RNS.log("Firmware archive. Installation cannot continue. Please try extracting the")
RNS.log("firmware again with the --extract-firmware option.") RNS.log("firmware again with the --extract-firmware option.")
exit(184) graceful_exit(184)
vf = open(vfpath, "rb") vf = open(vfpath, "rb")
release_info = vf.read().decode("utf-8").strip() release_info = vf.read().decode("utf-8").strip()
@ -1010,7 +1014,7 @@ def ensure_firmware_file(fw_filename):
else: else:
RNS.log("No extracted firmware is available, cannot continue.") RNS.log("No extracted firmware is available, cannot continue.")
RNS.log("Extract a firmware from an existing RNode first, using the --extract-firmware option.") RNS.log("Extract a firmware from an existing RNode first, using the --extract-firmware option.")
exit(183) graceful_exit(183)
else: else:
try: try:
@ -1044,7 +1048,7 @@ def ensure_firmware_file(fw_filename):
RNS.log("Check your internet connection and try again.") RNS.log("Check your internet connection and try again.")
RNS.log("If you don't have Internet access currently, use the --fw-version option to manually specify a version.") RNS.log("If you don't have Internet access currently, use the --fw-version option to manually specify a version.")
RNS.log("You can also use --extract to copy the firmware from a known-good RNode of the same model.") RNS.log("You can also use --extract to copy the firmware from a known-good RNode of the same model.")
exit() graceful_exit()
except Exception as e: except Exception as e:
# if custom firmware url, don't fallback # if custom firmware url, don't fallback
if fw_url != None: if fw_url != None:
@ -1052,7 +1056,7 @@ def ensure_firmware_file(fw_filename):
RNS.log("Check your internet connection and try again.") RNS.log("Check your internet connection and try again.")
RNS.log("If you don't have Internet access currently, use the --fw-version option to manually specify a version.") RNS.log("If you don't have Internet access currently, use the --fw-version option to manually specify a version.")
RNS.log("You can also use --extract to copy the firmware from a known-good RNode of the same model.") RNS.log("You can also use --extract to copy the firmware from a known-good RNode of the same model.")
exit() graceful_exit()
RNS.log("") RNS.log("")
RNS.log("WARNING!") RNS.log("WARNING!")
@ -1081,7 +1085,7 @@ def ensure_firmware_file(fw_filename):
selected_version = release_info.split()[0] selected_version = release_info.split()[0]
if selected_version == "not": if selected_version == "not":
RNS.log("No valid version found for this board, exiting.") RNS.log("No valid version found for this board, exiting.")
exit(199) graceful_exit(199)
selected_hash = release_info.split()[1] selected_hash = release_info.split()[1]
if not os.path.isdir(UPD_DIR+"/"+selected_version): if not os.path.isdir(UPD_DIR+"/"+selected_version):
@ -1092,7 +1096,7 @@ def ensure_firmware_file(fw_filename):
else: else:
RNS.log("Online firmware version check was disabled, but no firmware version specified for install.") RNS.log("Online firmware version check was disabled, but no firmware version specified for install.")
RNS.log("use the --fw-version option to manually specify a version.") RNS.log("use the --fw-version option to manually specify a version.")
exit(98) graceful_exit(98)
# if custom firmware url, use it # if custom firmware url, use it
if fw_url != None: if fw_url != None:
@ -1126,7 +1130,7 @@ def ensure_firmware_file(fw_filename):
if selected_hash == None: if selected_hash == None:
RNS.log("No release hash found for "+fw_filename+". The firmware integrity could not be verified.") RNS.log("No release hash found for "+fw_filename+". The firmware integrity could not be verified.")
exit(97) graceful_exit(97)
RNS.log("Verifying firmware integrity...") RNS.log("Verifying firmware integrity...")
fw_file = open(UPD_DIR+"/"+selected_version+"/"+fw_filename, "rb") fw_file = open(UPD_DIR+"/"+selected_version+"/"+fw_filename, "rb")
@ -1137,24 +1141,24 @@ def ensure_firmware_file(fw_filename):
else: else:
RNS.log("") RNS.log("")
RNS.log("Firmware corrupt. Try clearing the local firmware cache with: rnodeconf --clear-cache") RNS.log("Firmware corrupt. Try clearing the local firmware cache with: rnodeconf --clear-cache")
exit(96) graceful_exit(96)
except Exception as e: except Exception as e:
RNS.log("An error occurred while checking firmware file integrity. The contained exception was:") RNS.log("An error occurred while checking firmware file integrity. The contained exception was:")
RNS.log(str(e)) RNS.log(str(e))
exit(95) graceful_exit(95)
except Exception as e: except Exception as e:
RNS.log("Could not download required firmware file: ") RNS.log("Could not download required firmware file: ")
RNS.log(str(update_target_url)) RNS.log(str(update_target_url))
RNS.log("The contained exception was:") RNS.log("The contained exception was:")
RNS.log(str(e)) RNS.log(str(e))
exit() graceful_exit()
except Exception as e: except Exception as e:
RNS.log("An error occurred while reading version information for "+str(fw_filename)+". The contained exception was:") RNS.log("An error occurred while reading version information for "+str(fw_filename)+". The contained exception was:")
RNS.log(str(e)) RNS.log(str(e))
exit() graceful_exit()
def rnode_open_serial(port): def rnode_open_serial(port):
import serial import serial
@ -1171,6 +1175,21 @@ def rnode_open_serial(port):
write_timeout = None, write_timeout = None,
dsrdtr = False dsrdtr = False
) )
def graceful_exit(C=0):
if RNS.vendor.platformutils.is_windows():
RNS.log("Windows detected; delaying DTR",RNS.LOG_VERBOSE)
if rnode:
RNS.log("Sending \"Leave\" to Rnode",RNS.LOG_VERBOSE)
rnode.leave() # Leave has wait built in
elif rnode_serial:
RNS.log("Closing raw serial",RNS.LOG_VERBOSE)
sleep(1) # Wait for MCU to complete operation before DTR goes false
rnode_serial.close()
RNS.log("Exiting: Code "+str(C),RNS.LOG_INFO)
exit(C)
device_signer = None device_signer = None
force_update = False force_update = False
@ -1186,7 +1205,7 @@ def main():
print("RNode Config Utility needs pyserial to work.") print("RNode Config Utility needs pyserial to work.")
print("You can install it with: pip3 install pyserial") print("You can install it with: pip3 install pyserial")
print("") print("")
exit() graceful_exit()
try: try:
if not util.find_spec("cryptography"): if not util.find_spec("cryptography"):
@ -1196,7 +1215,7 @@ def main():
print("RNode Config Utility needs the cryptography module to work.") print("RNode Config Utility needs the cryptography module to work.")
print("You can install it with: pip3 install cryptography") print("You can install it with: pip3 install cryptography")
print("") print("")
exit() graceful_exit()
import serial import serial
from serial.tools import list_ports from serial.tools import list_ports
@ -1245,6 +1264,8 @@ def main():
parser.add_argument("-k", "--key", action="store_true", help="Generate a new signing key and exit") # parser.add_argument("-k", "--key", action="store_true", help="Generate a new signing key and exit") #
parser.add_argument("-S", "--sign", action="store_true", help="Display public part of signing key") parser.add_argument("-S", "--sign", action="store_true", help="Display public part of signing key")
parser.add_argument("-H", "--firmware-hash", action="store", help="Display installed firmware hash") parser.add_argument("-H", "--firmware-hash", action="store", help="Display installed firmware hash")
parser.add_argument("-K", "--get-target-firmware-hash", action="store_true", help=argparse.SUPPRESS) # Get target firmware hash from device
parser.add_argument("-L", "--get-firmware-hash", action="store_true", help=argparse.SUPPRESS) # Get calculated firmware hash from device
parser.add_argument("--platform", action="store", metavar="platform", type=str, default=None, help="Platform specification for device bootstrap") parser.add_argument("--platform", action="store", metavar="platform", type=str, default=None, help="Platform specification for device bootstrap")
parser.add_argument("--product", action="store", metavar="product", type=str, default=None, help="Product specification for device bootstrap") # parser.add_argument("--product", action="store", metavar="product", type=str, default=None, help="Product specification for device bootstrap") #
parser.add_argument("--model", action="store", metavar="model", type=str, default=None, help="Model code for device bootstrap") parser.add_argument("--model", action="store", metavar="model", type=str, default=None, help="Model code for device bootstrap")
@ -1264,14 +1285,14 @@ def main():
if args.version: if args.version:
print("rnodeconf "+program_version) print("rnodeconf "+program_version)
exit(0) graceful_exit(0)
if args.clear_cache: if args.clear_cache:
RNS.log("Clearing local firmware cache...") RNS.log("Clearing local firmware cache...")
import shutil import shutil
shutil.rmtree(UPD_DIR) shutil.rmtree(UPD_DIR)
RNS.log("Done") RNS.log("Done")
exit(0) graceful_exit(0)
if args.fw_version != None: if args.fw_version != None:
selected_version = args.fw_version selected_version = args.fw_version
@ -1279,7 +1300,7 @@ def main():
check_float = float(selected_version) check_float = float(selected_version)
except ValueError: except ValueError:
RNS.log("Selected version \""+selected_version+"\" does not appear to be a number.") RNS.log("Selected version \""+selected_version+"\" does not appear to be a number.")
exit() graceful_exit()
if args.fw_url != None: if args.fw_url != None:
fw_url = args.fw_url fw_url = args.fw_url
@ -1318,7 +1339,7 @@ def main():
except Exception as e: except Exception as e:
RNS.log("Invalid key data supplied") RNS.log("Invalid key data supplied")
exit(0) graceful_exit(0)
if args.use_extracted and ((args.update and args.port != None) or args.autoinstall): if args.use_extracted and ((args.update and args.port != None) or args.autoinstall):
print("") print("")
@ -1357,11 +1378,11 @@ def main():
selected_port = portlist[c_port-1] selected_port = portlist[c_port-1]
except Exception as e: except Exception as e:
print("That port does not exist, exiting now.") print("That port does not exist, exiting now.")
exit() graceful_exit()
if selected_port == None: if selected_port == None:
print("Could not select port, exiting now.") print("Could not select port, exiting now.")
exit() graceful_exit()
port_path = selected_port.device port_path = selected_port.device
port_product = selected_port.product port_product = selected_port.product
@ -1378,7 +1399,7 @@ def main():
if selected_port == None: if selected_port == None:
print("Could not find specified port "+str(args.port)+", exiting now") print("Could not find specified port "+str(args.port)+", exiting now")
exit() graceful_exit()
port_path = selected_port.device port_path = selected_port.device
port_product = selected_port.product port_product = selected_port.product
@ -1393,7 +1414,7 @@ def main():
except Exception as e: except Exception as e:
RNS.log("Could not open the specified serial port. The contained exception was:") RNS.log("Could not open the specified serial port. The contained exception was:")
RNS.log(str(e)) RNS.log(str(e))
exit() graceful_exit()
rnode = RNode(rnode_serial) rnode = RNode(rnode_serial)
rnode.usb_serial_id = port_serialno rnode.usb_serial_id = port_serialno
@ -1457,10 +1478,10 @@ def main():
print("Could not read firmware information from device") print("Could not read firmware information from device")
print("\nRNode firmware extraction failed") print("\nRNode firmware extraction failed")
exit(180) graceful_exit(180)
else: else:
print("\nFirmware extraction is currently only supported on ESP32-based RNodes.") print("\nFirmware extraction is currently only supported on ESP32-based RNodes.")
exit(170) graceful_exit(170)
if args.autoinstall: if args.autoinstall:
clear() clear()
@ -1494,11 +1515,11 @@ def main():
selected_port = portlist[c_port-1] selected_port = portlist[c_port-1]
except Exception as e: except Exception as e:
print("That port does not exist, exiting now.") print("That port does not exist, exiting now.")
exit() graceful_exit()
if selected_port == None: if selected_port == None:
print("Could not select port, exiting now.") print("Could not select port, exiting now.")
exit() graceful_exit()
port_path = selected_port.device port_path = selected_port.device
port_product = selected_port.product port_product = selected_port.product
@ -1516,7 +1537,7 @@ def main():
if selected_port == None: if selected_port == None:
print("Could not find specified port "+str(args.port)+", exiting now") print("Could not find specified port "+str(args.port)+", exiting now")
exit() graceful_exit()
port_path = selected_port.device port_path = selected_port.device
port_product = selected_port.product port_product = selected_port.product
@ -1531,7 +1552,7 @@ def main():
except Exception as e: except Exception as e:
RNS.log("Could not open the specified serial port. The contained exception was:") RNS.log("Could not open the specified serial port. The contained exception was:")
RNS.log(str(e)) RNS.log(str(e))
exit() graceful_exit()
rnode = RNode(rnode_serial) rnode = RNode(rnode_serial)
rnode.usb_serial_id = port_serialno rnode.usb_serial_id = port_serialno
@ -1549,7 +1570,7 @@ def main():
print("\nThis device is already installed and provisioned. No further action will") print("\nThis device is already installed and provisioned. No further action will")
print("be taken. If you wish to completely reinstall this device, you must first") print("be taken. If you wish to completely reinstall this device, you must first")
print("wipe the current EEPROM. See the help for more info.\n\nExiting now.") print("wipe the current EEPROM. See the help for more info.\n\nExiting now.")
exit() graceful_exit()
print("\n---------------------------------------------------------------------------") print("\n---------------------------------------------------------------------------")
print(" Device Selection") print(" Device Selection")
@ -1735,7 +1756,7 @@ def main():
input() input()
except Exception as e: except Exception as e:
print("That device type does not exist, exiting now.") print("That device type does not exist, exiting now.")
exit() graceful_exit()
selected_platform = None selected_platform = None
selected_model = None selected_model = None
@ -1764,7 +1785,7 @@ def main():
except Exception as e: except Exception as e:
print("That MCU type does not exist, exiting now.") print("That MCU type does not exist, exiting now.")
exit() graceful_exit()
print("\nWhat transceiver module does your board use?\n") print("\nWhat transceiver module does your board use?\n")
print("[1] SX1276/SX1278 with antenna port on PA_BOOST pin") print("[1] SX1276/SX1278 with antenna port on PA_BOOST pin")
@ -1781,7 +1802,7 @@ def main():
except Exception as e: except Exception as e:
print("That transceiver type does not exist, exiting now.") print("That transceiver type does not exist, exiting now.")
exit() graceful_exit()
elif selected_product == ROM.PRODUCT_RNODE: elif selected_product == ROM.PRODUCT_RNODE:
@ -1833,7 +1854,7 @@ def main():
# selected_platform = ROM.PLATFORM_ESP32 # selected_platform = ROM.PLATFORM_ESP32
except Exception as e: except Exception as e:
print("That model does not exist, exiting now.") print("That model does not exist, exiting now.")
exit() graceful_exit()
else: else:
print("\nWhat model is this T3S3?\n") print("\nWhat model is this T3S3?\n")
print("[1] 410 - 525 MHz (with SX1268 chip)") print("[1] 410 - 525 MHz (with SX1268 chip)")
@ -1853,7 +1874,7 @@ def main():
selected_platform = ROM.PLATFORM_ESP32 selected_platform = ROM.PLATFORM_ESP32
except Exception as e: except Exception as e:
print("That model does not exist, exiting now.") print("That model does not exist, exiting now.")
exit() graceful_exit()
elif selected_product == ROM.PRODUCT_TBEAM: elif selected_product == ROM.PRODUCT_TBEAM:
selected_mcu = ROM.MCU_ESP32 selected_mcu = ROM.MCU_ESP32
@ -1882,7 +1903,7 @@ def main():
selected_platform = ROM.PLATFORM_ESP32 selected_platform = ROM.PLATFORM_ESP32
except Exception as e: except Exception as e:
print("That band does not exist, exiting now.") print("That band does not exist, exiting now.")
exit() graceful_exit()
elif selected_product == ROM.PRODUCT_T32_10: elif selected_product == ROM.PRODUCT_T32_10:
selected_mcu = ROM.MCU_ESP32 selected_mcu = ROM.MCU_ESP32
@ -1904,7 +1925,7 @@ def main():
selected_platform = ROM.PLATFORM_ESP32 selected_platform = ROM.PLATFORM_ESP32
except Exception as e: except Exception as e:
print("That band does not exist, exiting now.") print("That band does not exist, exiting now.")
exit() graceful_exit()
elif selected_product == ROM.PRODUCT_T32_20: elif selected_product == ROM.PRODUCT_T32_20:
selected_mcu = ROM.MCU_ESP32 selected_mcu = ROM.MCU_ESP32
@ -1926,7 +1947,7 @@ def main():
selected_platform = ROM.PLATFORM_ESP32 selected_platform = ROM.PLATFORM_ESP32
except Exception as e: except Exception as e:
print("That band does not exist, exiting now.") print("That band does not exist, exiting now.")
exit() graceful_exit()
elif selected_product == ROM.PRODUCT_T32_21: elif selected_product == ROM.PRODUCT_T32_21:
selected_mcu = ROM.MCU_ESP32 selected_mcu = ROM.MCU_ESP32
@ -1954,7 +1975,7 @@ def main():
selected_platform = ROM.PLATFORM_ESP32 selected_platform = ROM.PLATFORM_ESP32
except Exception as e: except Exception as e:
print("That band does not exist, exiting now.") print("That band does not exist, exiting now.")
exit() graceful_exit()
elif selected_product == ROM.PRODUCT_H32_V2: elif selected_product == ROM.PRODUCT_H32_V2:
selected_mcu = ROM.MCU_ESP32 selected_mcu = ROM.MCU_ESP32
@ -1976,7 +1997,7 @@ def main():
selected_platform = ROM.PLATFORM_ESP32 selected_platform = ROM.PLATFORM_ESP32
except Exception as e: except Exception as e:
print("That band does not exist, exiting now.") print("That band does not exist, exiting now.")
exit() graceful_exit()
elif selected_product == ROM.PRODUCT_H32_V3: elif selected_product == ROM.PRODUCT_H32_V3:
selected_mcu = ROM.MCU_ESP32 selected_mcu = ROM.MCU_ESP32
@ -2014,7 +2035,7 @@ def main():
selected_platform = ROM.PLATFORM_NRF52 selected_platform = ROM.PLATFORM_NRF52
except Exception as e: except Exception as e:
print("That band does not exist, exiting now.") print("That band does not exist, exiting now.")
exit() graceful_exit()
if selected_model != ROM.MODEL_FF and selected_model != ROM.MODEL_FE: if selected_model != ROM.MODEL_FF and selected_model != ROM.MODEL_FE:
fw_filename = models[selected_model][4] fw_filename = models[selected_model][4]
@ -2042,7 +2063,7 @@ def main():
fw_filename = "rnode_firmware_esp32_generic.zip" fw_filename = "rnode_firmware_esp32_generic.zip"
except Exception as e: except Exception as e:
print("That ESP32 board does not exist, exiting now.") print("That ESP32 board does not exist, exiting now.")
exit() graceful_exit()
if fw_filename == None: if fw_filename == None:
print("") print("")
@ -2052,7 +2073,7 @@ def main():
print("") print("")
print_donation_block() print_donation_block()
print("") print("")
exit() graceful_exit()
if args.use_extracted: if args.use_extracted:
fw_filename = "extracted_rnode_firmware.zip" fw_filename = "extracted_rnode_firmware.zip"
@ -2082,7 +2103,7 @@ def main():
raise ValueError() raise ValueError()
except Exception as e: except Exception as e:
print("OK, aborting now.") print("OK, aborting now.")
exit() graceful_exit()
args.key = True args.key = True
args.port = selected_port.device args.port = selected_port.device
@ -2099,7 +2120,7 @@ def main():
except Exception as e: except Exception as e:
RNS.log("Could not obain firmware package for your board") RNS.log("Could not obain firmware package for your board")
RNS.log("The contained exception was: "+str(e)) RNS.log("The contained exception was: "+str(e))
exit() graceful_exit()
rnode.disconnect() rnode.disconnect()
@ -2140,7 +2161,7 @@ def main():
RNS.log("Could not load device signing key") RNS.log("Could not load device signing key")
exit() graceful_exit()
if args.key: if args.key:
if not os.path.isfile(FWD_DIR+"/device.key"): if not os.path.isfile(FWD_DIR+"/device.key"):
@ -2153,7 +2174,7 @@ def main():
RNS.log("Could not create new device signing key at "+str(FWD_DIR+"/device.key")+". The contained exception was:") RNS.log("Could not create new device signing key at "+str(FWD_DIR+"/device.key")+". The contained exception was:")
RNS.log(str(e)) RNS.log(str(e))
RNS.log("Please ensure filesystem access and try again.") RNS.log("Please ensure filesystem access and try again.")
exit(81) graceful_exit(81)
else: else:
try: try:
device_signer = RNS.Identity.from_file(FWD_DIR+"/device.key") device_signer = RNS.Identity.from_file(FWD_DIR+"/device.key")
@ -2161,7 +2182,7 @@ def main():
RNS.log("Could not load device signing key from "+str(FWD_DIR+"/device.key")+". The contained exception was:") RNS.log("Could not load device signing key from "+str(FWD_DIR+"/device.key")+". The contained exception was:")
RNS.log(str(e)) RNS.log(str(e))
RNS.log("Please restore or clear the key and try again.") RNS.log("Please restore or clear the key and try again.")
exit(82) graceful_exit(82)
if not os.path.isfile(FWD_DIR+"/signing.key"): if not os.path.isfile(FWD_DIR+"/signing.key"):
RNS.log("Generating a new EEPROM signing key...") RNS.log("Generating a new EEPROM signing key...")
@ -2199,7 +2220,7 @@ def main():
RNS.log("The firmware directory does not exist, can't write key!") RNS.log("The firmware directory does not exist, can't write key!")
if not args.autoinstall: if not args.autoinstall:
exit() graceful_exit()
def get_partition_hash(platform, partition_file): def get_partition_hash(platform, partition_file):
try: try:
@ -2241,7 +2262,7 @@ def main():
RNS.log(" sudo apt install "+flasher) RNS.log(" sudo apt install "+flasher)
RNS.log("") RNS.log("")
RNS.log("Please install \""+flasher+"\" and try again.") RNS.log("Please install \""+flasher+"\" and try again.")
exit() graceful_exit()
elif platform == ROM.PLATFORM_AVR: elif platform == ROM.PLATFORM_AVR:
flasher = "avrdude" flasher = "avrdude"
if which(flasher) is not None: if which(flasher) is not None:
@ -2260,7 +2281,7 @@ def main():
RNS.log(" sudo apt install avrdude") RNS.log(" sudo apt install avrdude")
RNS.log("") RNS.log("")
RNS.log("Please install \""+flasher+"\" and try again.") RNS.log("Please install \""+flasher+"\" and try again.")
exit() graceful_exit()
elif platform == ROM.PLATFORM_ESP32: elif platform == ROM.PLATFORM_ESP32:
numeric_version = float(selected_version) numeric_version = float(selected_version)
flasher_dir = UPD_DIR+"/"+selected_version flasher_dir = UPD_DIR+"/"+selected_version
@ -2720,7 +2741,8 @@ def main():
RNS.log(" sudo apt install esptool") RNS.log(" sudo apt install esptool")
RNS.log("") RNS.log("")
RNS.log("Please install \""+flasher+"\" and try again.") RNS.log("Please install \""+flasher+"\" and try again.")
exit() graceful_exit()
elif platform == ROM.PLATFORM_NRF52: elif platform == ROM.PLATFORM_NRF52:
flasher = "adafruit-nrfutil" flasher = "adafruit-nrfutil"
if which(flasher) is not None: if which(flasher) is not None:
@ -2734,7 +2756,7 @@ def main():
RNS.log(" pip3 install --user adafruit-nrfutil") RNS.log(" pip3 install --user adafruit-nrfutil")
RNS.log("") RNS.log("")
RNS.log("Please install \""+flasher+"\" and try again.") RNS.log("Please install \""+flasher+"\" and try again.")
exit() graceful_exit()
if args.port: if args.port:
wants_fw_provision = False wants_fw_provision = False
@ -2749,7 +2771,7 @@ def main():
if selected_version == None: if selected_version == None:
RNS.log("Missing parameters, cannot continue") RNS.log("Missing parameters, cannot continue")
exit(68) graceful_exit(68)
if fw_filename == "extracted_rnode_firmware.zip": if fw_filename == "extracted_rnode_firmware.zip":
try: try:
@ -2765,12 +2787,12 @@ def main():
RNS.log("Waiting for ESP32 reset...") RNS.log("Waiting for ESP32 reset...")
time.sleep(7) time.sleep(7)
else: else:
exit() graceful_exit()
except Exception as e: except Exception as e:
RNS.log("Error while flashing") RNS.log("Error while flashing")
RNS.log(str(e)) RNS.log(str(e))
exit(1) graceful_exit(1)
else: else:
fw_src = UPD_DIR+"/"+selected_version+"/" fw_src = UPD_DIR+"/"+selected_version+"/"
@ -2783,7 +2805,7 @@ def main():
zip.extractall(fw_src) zip.extractall(fw_src)
except Exception as e: except Exception as e:
RNS.log("Could not decompress firmware from downloaded zip file") RNS.log("Could not decompress firmware from downloaded zip file")
exit() graceful_exit()
RNS.log("Firmware decompressed") RNS.log("Firmware decompressed")
RNS.log("Flashing RNode firmware to device on "+args.port) RNS.log("Flashing RNode firmware to device on "+args.port)
@ -2807,15 +2829,15 @@ def main():
RNS.log("Some boards have trouble flashing at high speeds, and you can") RNS.log("Some boards have trouble flashing at high speeds, and you can")
RNS.log("try flashing with a lower baud rate, as in this example:") RNS.log("try flashing with a lower baud rate, as in this example:")
RNS.log("rnodeconf --autoinstall --baud-flash 115200") RNS.log("rnodeconf --autoinstall --baud-flash 115200")
exit() graceful_exit()
except Exception as e: except Exception as e:
RNS.log("Error while flashing") RNS.log("Error while flashing")
RNS.log(str(e)) RNS.log(str(e))
exit(1) graceful_exit(1)
else: else:
RNS.log("Firmware file not found") RNS.log("Firmware file not found")
exit() graceful_exit()
RNS.log("Opening serial port "+args.port+"...") RNS.log("Opening serial port "+args.port+"...")
try: try:
@ -2824,7 +2846,7 @@ def main():
except Exception as e: except Exception as e:
RNS.log("Could not open the specified serial port. The contained exception was:") RNS.log("Could not open the specified serial port. The contained exception was:")
RNS.log(str(e)) RNS.log(str(e))
exit() graceful_exit()
rnode = RNode(rnode_serial) rnode = RNode(rnode_serial)
ports = list_ports.comports() ports = list_ports.comports()
@ -2839,7 +2861,7 @@ def main():
except Exception as e: except Exception as e:
RNS.log("Serial port opened, but RNode did not respond. Is a valid firmware installed?") RNS.log("Serial port opened, but RNode did not respond. Is a valid firmware installed?")
print(e) print(e)
exit() graceful_exit()
if rnode.detected: if rnode.detected:
if rnode.platform == None or rnode.mcu == None: if rnode.platform == None or rnode.mcu == None:
@ -2850,7 +2872,10 @@ def main():
if args.eeprom_wipe: if args.eeprom_wipe:
RNS.log("WARNING: EEPROM is being wiped! Power down device NOW if you do not want this!") RNS.log("WARNING: EEPROM is being wiped! Power down device NOW if you do not want this!")
rnode.wipe_eeprom() rnode.wipe_eeprom()
exit()
# TODO: Add conditional for avoiding this reset on nRF
rnode.hard_reset()
graceful_exit()
RNS.log("Reading EEPROM...") RNS.log("Reading EEPROM...")
rnode.download_eeprom() rnode.download_eeprom()
@ -2880,12 +2905,12 @@ def main():
if args.update: if args.update:
RNS.log("ERROR: No firmware found for this board. Cannot update.") RNS.log("ERROR: No firmware found for this board. Cannot update.")
exit() graceful_exit()
if args.update: if args.update:
if not rnode.provisioned: if not rnode.provisioned:
RNS.log("Device not provisioned. Cannot update device firmware.") RNS.log("Device not provisioned. Cannot update device firmware.")
exit(1) graceful_exit(1)
if args.use_extracted: if args.use_extracted:
fw_filename = "extracted_rnode_firmware.zip" fw_filename = "extracted_rnode_firmware.zip"
@ -2904,21 +2929,21 @@ def main():
if args.fw_version != None: if args.fw_version != None:
RNS.log("Specified firmware version ("+selected_version+") is already installed on this device") RNS.log("Specified firmware version ("+selected_version+") is already installed on this device")
RNS.log("Override with -U option to install anyway") RNS.log("Override with -U option to install anyway")
exit(0) graceful_exit(0)
else: else:
RNS.log("Latest firmware version ("+selected_version+") is already installed on this device") RNS.log("Latest firmware version ("+selected_version+") is already installed on this device")
RNS.log("Override with -U option to install anyway") RNS.log("Override with -U option to install anyway")
exit(0) graceful_exit(0)
if rnode.version > selected_version: if rnode.version > selected_version:
if args.fw_version != None: if args.fw_version != None:
RNS.log("Specified firmware version ("+selected_version+") is older than firmware already installed on this device") RNS.log("Specified firmware version ("+selected_version+") is older than firmware already installed on this device")
RNS.log("Override with -U option to install anyway") RNS.log("Override with -U option to install anyway")
exit(0) graceful_exit(0)
else: else:
RNS.log("Latest firmware version ("+selected_version+") is older than firmware already installed on this device") RNS.log("Latest firmware version ("+selected_version+") is older than firmware already installed on this device")
RNS.log("Override with -U option to install anyway") RNS.log("Override with -U option to install anyway")
exit(0) graceful_exit(0)
if not fw_file_ensured and selected_version != None: if not fw_file_ensured and selected_version != None:
ensure_firmware_file(fw_filename) ensure_firmware_file(fw_filename)
@ -2931,13 +2956,13 @@ def main():
zip.extractall(fw_src) zip.extractall(fw_src)
except Exception as e: except Exception as e:
RNS.log("Could not decompress firmware from downloaded zip file") RNS.log("Could not decompress firmware from downloaded zip file")
exit() graceful_exit()
RNS.log("Firmware decompressed") RNS.log("Firmware decompressed")
except Exception as e: except Exception as e:
RNS.log("Could not obtain firmware package for your board") RNS.log("Could not obtain firmware package for your board")
RNS.log("The contained exception was: "+str(e)) RNS.log("The contained exception was: "+str(e))
exit() graceful_exit()
if fw_filename == "extracted_rnode_firmware.zip": if fw_filename == "extracted_rnode_firmware.zip":
update_full_path = EXT_DIR+"/extracted_rnode_firmware.version" update_full_path = EXT_DIR+"/extracted_rnode_firmware.version"
@ -2979,7 +3004,7 @@ def main():
except Exception as e: except Exception as e:
RNS.log("Could not open the specified serial port. The contained exception was:") RNS.log("Could not open the specified serial port. The contained exception was:")
RNS.log(str(e)) RNS.log(str(e))
exit() graceful_exit()
rnode = RNode(rnode_serial) rnode = RNode(rnode_serial)
thread = threading.Thread(target=rnode.readLoop, daemon=True).start() thread = threading.Thread(target=rnode.readLoop, daemon=True).start()
@ -2989,7 +3014,7 @@ def main():
except Exception as e: except Exception as e:
RNS.log("Serial port opened, but RNode did not respond. Is a valid firmware installed?") RNS.log("Serial port opened, but RNode did not respond. Is a valid firmware installed?")
print(e) print(e)
exit() graceful_exit()
if rnode.detected: if rnode.detected:
if rnode.platform == None or rnode.mcu == None: if rnode.platform == None or rnode.mcu == None:
@ -3013,19 +3038,19 @@ def main():
RNS.log("Firmware update completed successfully") RNS.log("Firmware update completed successfully")
else: else:
RNS.log("An error occurred while flashing the new firmware, exiting now.") RNS.log("An error occurred while flashing the new firmware, exiting now.")
exit() graceful_exit()
except Exception as e: except Exception as e:
RNS.log("Error while updating firmware") RNS.log("Error while updating firmware")
RNS.log(str(e)) RNS.log(str(e))
else: else:
RNS.log("Firmware update file not found") RNS.log("Firmware update file not found")
exit() graceful_exit()
if args.eeprom_dump: if args.eeprom_dump:
RNS.log("EEPROM contents:") RNS.log("EEPROM contents:")
RNS.log(RNS.hexrep(rnode.eeprom)) RNS.log(RNS.hexrep(rnode.eeprom))
exit() graceful_exit()
if args.eeprom_backup: if args.eeprom_backup:
try: try:
@ -3039,7 +3064,7 @@ def main():
except Exception as e: except Exception as e:
RNS.log("EEPROM was successfully downloaded from device,") RNS.log("EEPROM was successfully downloaded from device,")
RNS.log("but file could not be written to disk.") RNS.log("but file could not be written to disk.")
exit() graceful_exit()
if isinstance(args.display, int): if isinstance(args.display, int):
di = args.display di = args.display
@ -3064,7 +3089,7 @@ def main():
RNS.log("Setting display address to "+RNS.hexrep(da, delimit=False)) RNS.log("Setting display address to "+RNS.hexrep(da, delimit=False))
rnode.set_display_address(ord(da)) rnode.set_display_address(ord(da))
rnode.hard_reset() rnode.hard_reset()
exit() graceful_exit()
else: else:
RNS.log("Invalid display address specified") RNS.log("Invalid display address specified")
@ -3134,23 +3159,23 @@ def main():
print("") print("")
rnode.disconnect() rnode.disconnect()
exit() graceful_exit()
else: else:
RNS.log("EEPROM is invalid, no further information available") RNS.log("EEPROM is invalid, no further information available")
exit() egraceful_xit()
if args.rom: if args.rom:
if rnode.provisioned and not args.autoinstall: if rnode.provisioned and not args.autoinstall:
RNS.log("EEPROM bootstrap was requested, but a valid EEPROM was already present.") RNS.log("EEPROM bootstrap was requested, but a valid EEPROM was already present.")
RNS.log("No changes are being made.") RNS.log("No changes are being made.")
exit() graceful_exit()
else: else:
if rnode.signature_valid: if rnode.signature_valid:
RNS.log("EEPROM bootstrap was requested, but a valid EEPROM was already present.") RNS.log("EEPROM bootstrap was requested, but a valid EEPROM was already present.")
RNS.log("No changes are being made.") RNS.log("No changes are being made.")
exit() graceful_exit()
else: else:
if args.autoinstall: if args.autoinstall:
RNS.log("Clearing old EEPROM, this will take about 15 seconds...") RNS.log("Clearing old EEPROM, this will take about 15 seconds...")
@ -3196,7 +3221,7 @@ def main():
except Exception as e: except Exception as e:
RNS.log("Could not create device serial number, exiting") RNS.log("Could not create device serial number, exiting")
RNS.log(str(e)) RNS.log(str(e))
exit() graceful_exit()
serialno = counter+1 serialno = counter+1
model = None model = None
@ -3298,7 +3323,7 @@ def main():
RNS.log(str(e)) RNS.log(str(e))
else: else:
RNS.log("No signing key found") RNS.log("No signing key found")
exit() graceful_exit()
if model == ROM.MODEL_A1 or model == ROM.MODEL_A6: if model == ROM.MODEL_A1 or model == ROM.MODEL_A6:
rnode.hard_reset() rnode.hard_reset()
@ -3454,10 +3479,10 @@ def main():
file.close() file.close()
except Exception as e: except Exception as e:
RNS.log("WARNING: Could not backup device EEPROM to disk") RNS.log("WARNING: Could not backup device EEPROM to disk")
exit() graceful_exit()
else: else:
RNS.log("EEPROM was written, but validation failed. Check your settings.") RNS.log("EEPROM was written, but validation failed. Check your settings.")
exit() graceful_exit()
except Exception as e: except Exception as e:
RNS.log("An error occurred while writing EEPROM. The contained exception was:") RNS.log("An error occurred while writing EEPROM. The contained exception was:")
RNS.log(str(e)) RNS.log(str(e))
@ -3465,7 +3490,7 @@ def main():
else: else:
RNS.log("Invalid data specified, cancelling EEPROM write") RNS.log("Invalid data specified, cancelling EEPROM write")
exit() graceful_exit()
if args.sign: if args.sign:
if rnode.provisioned: if rnode.provisioned:
@ -3479,14 +3504,14 @@ def main():
else: else:
if device_signer == None: if device_signer == None:
RNS.log("No device signer loaded, cannot sign device") RNS.log("No device signer loaded, cannot sign device")
exit(78) graceful_exit(78)
else: else:
new_device_signature = device_signer.sign(rnode.device_hash) new_device_signature = device_signer.sign(rnode.device_hash)
rnode.store_signature(new_device_signature) rnode.store_signature(new_device_signature)
RNS.log("Device signed") RNS.log("Device signed")
else: else:
RNS.log("This device has not been provisioned yet, cannot create device signature") RNS.log("This device has not been provisioned yet, cannot create device signature")
exit(79) graceful_exit(79)
if args.firmware_hash != None: if args.firmware_hash != None:
if rnode.provisioned: if rnode.provisioned:
@ -3499,17 +3524,33 @@ def main():
RNS.log("Firmware hash set") RNS.log("Firmware hash set")
except Exception as e: except Exception as e:
RNS.log("The provided value was not a valid SHA256 hash") RNS.log("The provided value was not a valid SHA256 hash")
exit(78) graceful_exit(78)
else: else:
RNS.log("This device has not been provisioned yet, cannot set firmware hash") RNS.log("This device has not been provisioned yet, cannot set firmware hash")
graceful_exit(77)
if args.get_target_firmware_hash:
if rnode.provisioned:
RNS.log(f"The target firmware hash is: {rnode.firmware_hash_target.hex()}")
else:
RNS.log("This device has not been provisioned yet, cannot get firmware hash")
exit(77)
if args.get_firmware_hash:
if rnode.provisioned:
RNS.log(f"The actual firmware hash is: {rnode.firmware_hash.hex()}")
else:
RNS.log("This device has not been provisioned yet, cannot get firmware hash")
exit(77) exit(77)
if rnode.provisioned: if rnode.provisioned:
if args.normal: if args.normal:
rnode.setNormalMode() rnode.setNormalMode()
RNS.log("Device set to normal (host-controlled) operating mode") RNS.log("Device set to normal (host-controlled) operating mode")
exit() graceful_exit()
if args.tnc: if args.tnc:
if not (args.freq and args.bw and args.txp and args.sf and args.cr): if not (args.freq and args.bw and args.txp and args.sf and args.cr):
RNS.log("Please input startup configuration:") RNS.log("Please input startup configuration:")
@ -3554,7 +3595,7 @@ def main():
RNS.log("Device set to TNC operating mode") RNS.log("Device set to TNC operating mode")
sleep(1.0) sleep(1.0)
exit() graceful_exit()
else: else:
RNS.log("This device contains a valid firmware, but EEPROM is invalid.") RNS.log("This device contains a valid firmware, but EEPROM is invalid.")
RNS.log("Probably the device has not been initialised, or the EEPROM has been erased.") RNS.log("Probably the device has not been initialised, or the EEPROM has been erased.")
@ -3564,12 +3605,14 @@ def main():
print("") print("")
parser.print_help() parser.print_help()
print("") print("")
exit() graceful_exit()
except KeyboardInterrupt: except KeyboardInterrupt:
print("") print("")
exit() graceful_exit()
graceful_exit()
def extract_recovery_esptool(): def extract_recovery_esptool():
if not os.path.isfile(RT_PATH): if not os.path.isfile(RT_PATH):
@ -3583,7 +3626,7 @@ def extract_recovery_esptool():
except Exception as e: except Exception as e:
RNS.log("Error: Could not extract recovery ESP-Tool. The contained exception was:") RNS.log("Error: Could not extract recovery ESP-Tool. The contained exception was:")
RNS.log(str(e)) RNS.log(str(e))
exit(181) graceful_exit(181)
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@ -1 +1 @@
__version__ = "0.7.4" __version__ = "0.7.5"

View File

@ -11,6 +11,25 @@ def interfaces() -> List[str]:
adapters = RNS.vendor.ifaddr.get_adapters(include_unconfigured=True) adapters = RNS.vendor.ifaddr.get_adapters(include_unconfigured=True)
return [a.name for a in adapters] return [a.name for a in adapters]
def interface_names_to_indexes() -> dict:
adapters = RNS.vendor.ifaddr.get_adapters(include_unconfigured=True)
results = {}
for adapter in adapters:
results[adapter.name] = adapter.index
return results
def interface_name_to_nice_name(ifname) -> str:
try:
adapters = RNS.vendor.ifaddr.get_adapters(include_unconfigured=True)
for adapter in adapters:
if adapter.name == ifname:
if hasattr(adapter, "nice_name"):
return adapter.nice_name
except:
return None
return None
def ifaddresses(ifname) -> dict: def ifaddresses(ifname) -> dict:
adapters = RNS.vendor.ifaddr.get_adapters(include_unconfigured=True) adapters = RNS.vendor.ifaddr.get_adapters(include_unconfigured=True)
ifa = {} ifa = {}