mirror of
https://github.com/markqvist/Reticulum.git
synced 2025-12-17 01:14:21 -05:00
Added support for configuring RNode WiFi settings to rnodeconf
This commit is contained in:
parent
1179757893
commit
b2d6ed733d
3 changed files with 195 additions and 36 deletions
|
|
@ -757,6 +757,10 @@ class RNodeInterface(Interface):
|
||||||
self.timeout = 1500
|
self.timeout = 1500
|
||||||
RNS.log(f"BLE connection {self.port} to RNode now open")
|
RNS.log(f"BLE connection {self.port} to RNode now open")
|
||||||
|
|
||||||
|
if self.tcp != None and self.tcp.connected:
|
||||||
|
self.timeout = 1000
|
||||||
|
RNS.log(f"TCP connection tcp://{self.tcp_host} to RNode now open")
|
||||||
|
|
||||||
RNS.log("Configuring RNode interface...", RNS.LOG_VERBOSE)
|
RNS.log("Configuring RNode interface...", RNS.LOG_VERBOSE)
|
||||||
self.initRadio()
|
self.initRadio()
|
||||||
if (self.validateRadioState()):
|
if (self.validateRadioState()):
|
||||||
|
|
|
||||||
|
|
@ -380,6 +380,7 @@ class RNodeInterface(Interface):
|
||||||
else:
|
else:
|
||||||
if self.use_ble:
|
if self.use_ble:
|
||||||
RNS.log(f"Opening BLE connection for {self}...")
|
RNS.log(f"Opening BLE connection for {self}...")
|
||||||
|
self.timeout = 1250
|
||||||
if self.ble != None and self.ble.running == False:
|
if self.ble != None and self.ble.running == False:
|
||||||
self.ble.close()
|
self.ble.close()
|
||||||
self.ble.cleanup()
|
self.ble.cleanup()
|
||||||
|
|
@ -394,6 +395,7 @@ class RNodeInterface(Interface):
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
||||||
if self.use_tcp:
|
if self.use_tcp:
|
||||||
|
self.timeout = 1000
|
||||||
RNS.log(f"Opening TCP connection for {self}...")
|
RNS.log(f"Opening TCP connection for {self}...")
|
||||||
if self.tcp != None and self.tcp.running == False:
|
if self.tcp != None and self.tcp.running == False:
|
||||||
self.tcp.close()
|
self.tcp.close()
|
||||||
|
|
|
||||||
|
|
@ -97,10 +97,15 @@ class KISS():
|
||||||
CMD_BT_CTRL = 0x46
|
CMD_BT_CTRL = 0x46
|
||||||
CMD_BT_PIN = 0x62
|
CMD_BT_PIN = 0x62
|
||||||
CMD_DIS_IA = 0x69
|
CMD_DIS_IA = 0x69
|
||||||
|
CMD_WIFI_MODE = 0x6A
|
||||||
|
CMD_WIFI_SSID = 0x6B
|
||||||
|
CMD_WIFI_PSK = 0x6C
|
||||||
|
CMD_WIFI_CHN = 0x6E
|
||||||
CMD_BOARD = 0x47
|
CMD_BOARD = 0x47
|
||||||
CMD_PLATFORM = 0x48
|
CMD_PLATFORM = 0x48
|
||||||
CMD_MCU = 0x49
|
CMD_MCU = 0x49
|
||||||
CMD_FW_VERSION = 0x50
|
CMD_FW_VERSION = 0x50
|
||||||
|
CMD_CFG_READ = 0x6D
|
||||||
CMD_ROM_READ = 0x51
|
CMD_ROM_READ = 0x51
|
||||||
CMD_ROM_WRITE = 0x52
|
CMD_ROM_WRITE = 0x52
|
||||||
CMD_ROM_WIPE = 0x59
|
CMD_ROM_WIPE = 0x59
|
||||||
|
|
@ -245,6 +250,10 @@ class ROM():
|
||||||
ADDR_CONF_PINT = 0xB6
|
ADDR_CONF_PINT = 0xB6
|
||||||
ADDR_CONF_BSET = 0xB7
|
ADDR_CONF_BSET = 0xB7
|
||||||
ADDR_CONF_DIA = 0xB9
|
ADDR_CONF_DIA = 0xB9
|
||||||
|
ADDR_CONF_WIFI = 0xBA
|
||||||
|
ADDR_CONF_WCHN = 0xBB
|
||||||
|
ADDR_CONF_SSID = 0x00
|
||||||
|
ADDR_CONF_PSK = 0x21
|
||||||
|
|
||||||
INFO_LOCK_BYTE = 0x73
|
INFO_LOCK_BYTE = 0x73
|
||||||
CONF_OK_BYTE = 0x73
|
CONF_OK_BYTE = 0x73
|
||||||
|
|
@ -402,6 +411,7 @@ class RNode():
|
||||||
self.platform = None
|
self.platform = None
|
||||||
self.mcu = None
|
self.mcu = None
|
||||||
self.eeprom = None
|
self.eeprom = None
|
||||||
|
self.cfg_sector = None
|
||||||
self.major_version = None
|
self.major_version = None
|
||||||
self.minor_version = None
|
self.minor_version = None
|
||||||
self.version = None
|
self.version = None
|
||||||
|
|
@ -461,12 +471,17 @@ class RNode():
|
||||||
in_frame = False
|
in_frame = False
|
||||||
data_buffer = b""
|
data_buffer = b""
|
||||||
command_buffer = b""
|
command_buffer = b""
|
||||||
|
elif (in_frame and byte == KISS.FEND and command == KISS.CMD_CFG_READ):
|
||||||
|
self.cfg_sector = data_buffer
|
||||||
|
in_frame = False
|
||||||
|
data_buffer = b""
|
||||||
|
command_buffer = b""
|
||||||
elif (byte == KISS.FEND):
|
elif (byte == KISS.FEND):
|
||||||
in_frame = True
|
in_frame = True
|
||||||
command = KISS.CMD_UNKNOWN
|
command = KISS.CMD_UNKNOWN
|
||||||
data_buffer = b""
|
data_buffer = b""
|
||||||
command_buffer = b""
|
command_buffer = b""
|
||||||
elif (in_frame and len(data_buffer) < 512):
|
elif (in_frame and len(data_buffer) < 1024):
|
||||||
if (len(data_buffer) == 0 and command == KISS.CMD_UNKNOWN):
|
if (len(data_buffer) == 0 and command == KISS.CMD_UNKNOWN):
|
||||||
command = byte
|
command = byte
|
||||||
elif (command == KISS.CMD_ROM_READ):
|
elif (command == KISS.CMD_ROM_READ):
|
||||||
|
|
@ -480,6 +495,17 @@ class RNode():
|
||||||
byte = KISS.FESC
|
byte = KISS.FESC
|
||||||
escape = False
|
escape = False
|
||||||
data_buffer = data_buffer+bytes([byte])
|
data_buffer = data_buffer+bytes([byte])
|
||||||
|
elif (command == KISS.CMD_CFG_READ):
|
||||||
|
if (byte == KISS.FESC):
|
||||||
|
escape = True
|
||||||
|
else:
|
||||||
|
if (escape):
|
||||||
|
if (byte == KISS.TFEND):
|
||||||
|
byte = KISS.FEND
|
||||||
|
if (byte == KISS.TFESC):
|
||||||
|
byte = KISS.FESC
|
||||||
|
escape = False
|
||||||
|
data_buffer = data_buffer+bytes([byte])
|
||||||
elif (command == KISS.CMD_DATA):
|
elif (command == KISS.CMD_DATA):
|
||||||
if (byte == KISS.FESC):
|
if (byte == KISS.FESC):
|
||||||
escape = True
|
escape = True
|
||||||
|
|
@ -788,6 +814,50 @@ class RNode():
|
||||||
if written != len(kiss_command):
|
if written != len(kiss_command):
|
||||||
raise IOError("An IO error occurred while sending firmware update command to device")
|
raise IOError("An IO error occurred while sending firmware update command to device")
|
||||||
|
|
||||||
|
def set_wifi_mode(self, mode):
|
||||||
|
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_WIFI_MODE, mode])+bytes([KISS.FEND])
|
||||||
|
written = self.serial.write(kiss_command)
|
||||||
|
if written != len(kiss_command):
|
||||||
|
raise IOError("An IO error occurred while sending wifi mode command to device")
|
||||||
|
|
||||||
|
def set_wifi_channel(self, channel):
|
||||||
|
try: ch = int(channel)
|
||||||
|
except: raise ValueError("Invalid WiFi channel")
|
||||||
|
if ch < 1 or ch > 14: raise ValueError("Invalid WiFi channel")
|
||||||
|
ch_data = bytes([ch])
|
||||||
|
data = KISS.escape(ch_data)
|
||||||
|
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_WIFI_CHN])+data+bytes([KISS.FEND])
|
||||||
|
|
||||||
|
written = self.serial.write(kiss_command)
|
||||||
|
if written != len(kiss_command):
|
||||||
|
raise IOError("An IO error occurred while sending wifi channel to device")
|
||||||
|
|
||||||
|
def set_wifi_ssid(self, ssid):
|
||||||
|
if ssid == None: data = bytes([0x00])
|
||||||
|
else:
|
||||||
|
ssid_data = ssid.encode("utf-8")+bytes([0x00])
|
||||||
|
if len(ssid_data) < 0 or len(ssid_data) > 33: raise ValueError("Invalid SSID length")
|
||||||
|
data = KISS.escape(ssid_data)
|
||||||
|
|
||||||
|
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_WIFI_SSID])+data+bytes([KISS.FEND])
|
||||||
|
|
||||||
|
written = self.serial.write(kiss_command)
|
||||||
|
if written != len(kiss_command):
|
||||||
|
raise IOError("An IO error occurred while sending wifi SSID to device")
|
||||||
|
|
||||||
|
def set_wifi_psk(self, psk):
|
||||||
|
if psk == None: data = bytes([0x00])
|
||||||
|
else:
|
||||||
|
psk_data = psk.encode("utf-8")+bytes([0x00])
|
||||||
|
if len(psk_data) < 8 or len(psk_data) > 33: raise ValueError("Invalid psk length")
|
||||||
|
data = KISS.escape(psk_data)
|
||||||
|
|
||||||
|
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_WIFI_PSK])+data+bytes([KISS.FEND])
|
||||||
|
|
||||||
|
written = self.serial.write(kiss_command)
|
||||||
|
if written != len(kiss_command):
|
||||||
|
raise IOError("An IO error occurred while sending wifi SSID to device")
|
||||||
|
|
||||||
def initRadio(self):
|
def initRadio(self):
|
||||||
self.setFrequency()
|
self.setFrequency()
|
||||||
self.setBandwidth()
|
self.setBandwidth()
|
||||||
|
|
@ -894,7 +964,7 @@ class RNode():
|
||||||
kiss_command = bytes([KISS.FEND, KISS.CMD_ROM_READ, 0x00, KISS.FEND])
|
kiss_command = bytes([KISS.FEND, KISS.CMD_ROM_READ, 0x00, 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 configuring radio state")
|
raise IOError("An IO error occurred while downloading EEPROM")
|
||||||
|
|
||||||
sleep(0.6)
|
sleep(0.6)
|
||||||
if self.eeprom == None:
|
if self.eeprom == None:
|
||||||
|
|
@ -903,6 +973,15 @@ class RNode():
|
||||||
else:
|
else:
|
||||||
self.parse_eeprom()
|
self.parse_eeprom()
|
||||||
|
|
||||||
|
def download_cfg_sector(self):
|
||||||
|
self.cfg_sector = None
|
||||||
|
kiss_command = bytes([KISS.FEND, KISS.CMD_CFG_READ, 0x00, KISS.FEND])
|
||||||
|
written = self.serial.write(kiss_command)
|
||||||
|
if written != len(kiss_command):
|
||||||
|
raise IOError("An IO error occurred while downloading config sector")
|
||||||
|
|
||||||
|
sleep(0.6)
|
||||||
|
|
||||||
def parse_eeprom(self):
|
def parse_eeprom(self):
|
||||||
global squashvw;
|
global squashvw;
|
||||||
try:
|
try:
|
||||||
|
|
@ -1365,6 +1444,12 @@ def main():
|
||||||
parser.add_argument("-B", "--bluetooth-off", action="store_true", help="Turn device bluetooth off")
|
parser.add_argument("-B", "--bluetooth-off", action="store_true", help="Turn device bluetooth off")
|
||||||
parser.add_argument("-p", "--bluetooth-pair", action="store_true", help="Put device into bluetooth pairing mode")
|
parser.add_argument("-p", "--bluetooth-pair", action="store_true", help="Put device into bluetooth pairing mode")
|
||||||
|
|
||||||
|
parser.add_argument("-w", "--wifi", action="store", metavar="mode", default=None, help="Set WiFi mode (OFF, AP or STATION)")
|
||||||
|
parser.add_argument("--channel", action="store", metavar="channel", default=None, help="Set WiFi channel")
|
||||||
|
parser.add_argument("--ssid", action="store", metavar="ssid", default=None, help="Set WiFi SSID (NONE to delete)")
|
||||||
|
parser.add_argument("--psk", action="store", metavar="psk", default=None, help="Set WiFi PSK (NONE to delete)")
|
||||||
|
parser.add_argument("--show-psk", action="store_true", default=False, help="Display stored WiFi PSK")
|
||||||
|
|
||||||
parser.add_argument("-D", "--display", action="store", metavar="i", type=int, default=None, help="Set display intensity (0-255)")
|
parser.add_argument("-D", "--display", action="store", metavar="i", type=int, default=None, help="Set display intensity (0-255)")
|
||||||
parser.add_argument("-t", "--timeout", action="store", metavar="s", type=int, default=None, help="Set display timeout in seconds, 0 to disable")
|
parser.add_argument("-t", "--timeout", action="store", metavar="s", type=int, default=None, help="Set display timeout in seconds, 0 to disable")
|
||||||
parser.add_argument("-R", "--rotation", action="store", metavar="rotation", type=int, default=None, help="Set display rotation, valid values are 0 through 3")
|
parser.add_argument("-R", "--rotation", action="store", metavar="rotation", type=int, default=None, help="Set display rotation, valid values are 0 through 3")
|
||||||
|
|
@ -3558,17 +3643,14 @@ def main():
|
||||||
graceful_exit()
|
graceful_exit()
|
||||||
|
|
||||||
if args.config:
|
if args.config:
|
||||||
|
rnode.download_cfg_sector()
|
||||||
eeprom_reserved = 200
|
eeprom_reserved = 200
|
||||||
if rnode.platform == ROM.PLATFORM_ESP32:
|
if rnode.platform == ROM.PLATFORM_ESP32: eeprom_size = 296
|
||||||
eeprom_size = 296
|
elif rnode.platform == ROM.PLATFORM_NRF52: eeprom_size = 296
|
||||||
elif rnode.platform == ROM.PLATFORM_NRF52:
|
else: eeprom_size = 4096
|
||||||
eeprom_size = 296
|
|
||||||
else:
|
|
||||||
eeprom_size = 4096
|
|
||||||
|
|
||||||
eeprom_offset = eeprom_size-eeprom_reserved
|
eeprom_offset = eeprom_size-eeprom_reserved
|
||||||
def ea(a):
|
def ea(a): return a+eeprom_offset
|
||||||
return a+eeprom_offset
|
|
||||||
ec_bt = rnode.eeprom[ROM.ADDR_CONF_BT]
|
ec_bt = rnode.eeprom[ROM.ADDR_CONF_BT]
|
||||||
ec_dint = rnode.eeprom[ROM.ADDR_CONF_DINT]
|
ec_dint = rnode.eeprom[ROM.ADDR_CONF_DINT]
|
||||||
ec_dadr = rnode.eeprom[ROM.ADDR_CONF_DADR]
|
ec_dadr = rnode.eeprom[ROM.ADDR_CONF_DADR]
|
||||||
|
|
@ -3578,40 +3660,66 @@ def main():
|
||||||
ec_pint = rnode.eeprom[ROM.ADDR_CONF_PINT]
|
ec_pint = rnode.eeprom[ROM.ADDR_CONF_PINT]
|
||||||
ec_bset = rnode.eeprom[ROM.ADDR_CONF_BSET]
|
ec_bset = rnode.eeprom[ROM.ADDR_CONF_BSET]
|
||||||
ec_dia = rnode.eeprom[ROM.ADDR_CONF_DIA]
|
ec_dia = rnode.eeprom[ROM.ADDR_CONF_DIA]
|
||||||
|
ec_wifi = rnode.eeprom[ROM.ADDR_CONF_WIFI]
|
||||||
|
ec_wchn = rnode.eeprom[ROM.ADDR_CONF_WCHN]
|
||||||
|
ec_ssid = None
|
||||||
|
ec_psk = None
|
||||||
|
|
||||||
|
if ec_wchn < 1 or ec_wchn > 14: ec_wchn = 1
|
||||||
|
if rnode.cfg_sector:
|
||||||
|
ssid_bytes = b""
|
||||||
|
for i in range(0, 32):
|
||||||
|
byte = rnode.cfg_sector[ROM.ADDR_CONF_SSID+i]
|
||||||
|
if byte == 0xFF: byte = 0x00
|
||||||
|
if byte == 0x00: break
|
||||||
|
else: ssid_bytes += bytes([byte])
|
||||||
|
|
||||||
|
try: ec_ssid = ssid_bytes.decode("utf-8")
|
||||||
|
except Exception as e: print(f"Error: Could not decode WiFi SSID read from device")
|
||||||
|
|
||||||
|
psk_bytes = b""
|
||||||
|
for i in range(0, 32):
|
||||||
|
byte = rnode.cfg_sector[ROM.ADDR_CONF_PSK+i]
|
||||||
|
if byte == 0xFF: byte = 0x00
|
||||||
|
if byte == 0x00: break
|
||||||
|
else: psk_bytes += bytes([byte])
|
||||||
|
|
||||||
|
try: ec_psk = psk_bytes.decode("utf-8")
|
||||||
|
except Exception as e: print(f"Error: Could not decode WiFi PSK read from device")
|
||||||
|
if not args.show_psk and ec_psk: ec_psk = "*"*len(ec_psk)
|
||||||
|
|
||||||
print("\nDevice configuration:")
|
print("\nDevice configuration:")
|
||||||
if ec_bt == 0x73:
|
if ec_bt == 0x73: print(f" Bluetooth : Enabled")
|
||||||
print(f" Bluetooth : Enabled")
|
else: print(f" Bluetooth : Disabled")
|
||||||
else:
|
if ec_wifi == 0x01: print(f" WiFi : Enabled (Station)")
|
||||||
print(f" Bluetooth : Disabled")
|
if ec_wifi == 0x02: print(f" WiFi : Enabled (AP)")
|
||||||
if ec_dia == 0x00:
|
else: print(f" WiFi : Disabled")
|
||||||
print(f" Interference avoidance : Enabled")
|
if ec_wifi == 0x01 or ec_wifi == 0x02:
|
||||||
else:
|
if not ec_wchn: print(f" Channel : Unknown")
|
||||||
print(f" Interference avoidance : Disabled")
|
else: print(f" Channel : {ec_wchn}")
|
||||||
|
if not ec_ssid: print(f" SSID : Not set")
|
||||||
|
else: print(f" SSID : {ec_ssid}")
|
||||||
|
if not ec_psk: print(f" PSK : Not set")
|
||||||
|
else: print(f" PSK : {ec_psk}")
|
||||||
|
if ec_dia == 0x00: print(f" Interference avoidance : Enabled")
|
||||||
|
else: print(f" Interference avoidance : Disabled")
|
||||||
print( f" Display brightness : {ec_dint}")
|
print( f" Display brightness : {ec_dint}")
|
||||||
if ec_dadr == 0xFF:
|
if ec_dadr == 0xFF: print(f" Display address : Default")
|
||||||
print(f" Display address : Default")
|
else: print(f" Display address : {RNS.hexrep(ec_dadr, delimit=False)}")
|
||||||
else:
|
if ec_bset == 0x73 and ec_dblk != 0x00: print(f" Display blanking : {ec_dblk}s")
|
||||||
print(f" Display address : {RNS.hexrep(ec_dadr, delimit=False)}")
|
else: print(f" Display blanking : Disabled")
|
||||||
if ec_bset == 0x73 and ec_dblk != 0x00:
|
|
||||||
print(f" Display blanking : {ec_dblk}s")
|
|
||||||
else:
|
|
||||||
print(f" Display blanking : Disabled")
|
|
||||||
if ec_drot != 0xFF:
|
if ec_drot != 0xFF:
|
||||||
if ec_drot == 0x00:
|
if ec_drot == 0x00: rstr = "Landscape"
|
||||||
rstr = "Landscape"
|
if ec_drot == 0x01: rstr = "Portrait"
|
||||||
if ec_drot == 0x01:
|
if ec_drot == 0x02: rstr = "Landscape 180"
|
||||||
rstr = "Portrait"
|
if ec_drot == 0x03: rstr = "Portrait 180"
|
||||||
if ec_drot == 0x02:
|
|
||||||
rstr = "Landscape 180"
|
|
||||||
if ec_drot == 0x03:
|
|
||||||
rstr = "Portrait 180"
|
|
||||||
print(f" Display rotation : {rstr}")
|
print(f" Display rotation : {rstr}")
|
||||||
else:
|
else:
|
||||||
print(f" Display rotation : Default")
|
print(f" Display rotation : Default")
|
||||||
if ec_pset == 0x73:
|
if ec_pset == 0x73: print(f" Neopixel Intensity : {ec_pint}")
|
||||||
print(f" Neopixel Intensity : {ec_pint}")
|
|
||||||
print("")
|
print("")
|
||||||
|
|
||||||
|
rnode.leave()
|
||||||
graceful_exit()
|
graceful_exit()
|
||||||
|
|
||||||
if args.eeprom_dump:
|
if args.eeprom_dump:
|
||||||
|
|
@ -3722,6 +3830,51 @@ def main():
|
||||||
input()
|
input()
|
||||||
rnode.leave()
|
rnode.leave()
|
||||||
|
|
||||||
|
if args.channel:
|
||||||
|
try:
|
||||||
|
RNS.log(f"Setting WiFi channel to {args.channel}")
|
||||||
|
rnode.set_wifi_channel(args.channel)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Could not set WiFi channel: {e}")
|
||||||
|
graceful_exit()
|
||||||
|
|
||||||
|
if args.ssid:
|
||||||
|
try:
|
||||||
|
if args.ssid.lower() == "none":
|
||||||
|
ssid_str = None
|
||||||
|
RNS.log(f"Deleting WiFi SSID")
|
||||||
|
else:
|
||||||
|
ssid_str = str(args.ssid)
|
||||||
|
RNS.log(f"Setting WiFi SSID to: {ssid_str}")
|
||||||
|
rnode.set_wifi_ssid(ssid_str)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Could not set WiFi SSID: {e}")
|
||||||
|
graceful_exit()
|
||||||
|
|
||||||
|
if args.psk:
|
||||||
|
try:
|
||||||
|
if args.psk.lower() == "none":
|
||||||
|
psk_str = None
|
||||||
|
RNS.log(f"Deleting WiFi PSK")
|
||||||
|
else:
|
||||||
|
psk_str = str(args.psk)
|
||||||
|
RNS.log(f"Setting WiFi PSK")
|
||||||
|
rnode.set_wifi_psk(psk_str)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Could not set WiFi PSK: {e}")
|
||||||
|
graceful_exit()
|
||||||
|
|
||||||
|
if args.wifi:
|
||||||
|
try:
|
||||||
|
RNS.log(f"Setting WiFi mode...")
|
||||||
|
mode = 0x00
|
||||||
|
if str(args.wifi).lower().startswith("sta"): mode = 0x01
|
||||||
|
elif str(args.wifi).lower().startswith("ap"): mode = 0x02
|
||||||
|
rnode.set_wifi_mode(mode)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Could not set WiFi mode: {e}")
|
||||||
|
graceful_exit()
|
||||||
|
|
||||||
if args.info:
|
if args.info:
|
||||||
if rnode.provisioned:
|
if rnode.provisioned:
|
||||||
timestamp = struct.unpack(">I", rnode.made)[0]
|
timestamp = struct.unpack(">I", rnode.made)[0]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue