mirror of
https://github.com/espressif/openthread.git
synced 2026-09-16 06:00:13 +00:00
Add 'parent', 'child' and 'leaderdata' commands to spinel-cli.py (#1136)
* Add 'leaderdata' command to spinel-cli.py. * Add 'parent' command to the spinel-cli.py. * Add 'child' command to the spinel-cli.py * Add THREAD_NEIGHBOR_TABLE property to codec in spinel-cli.
This commit is contained in:
@@ -57,6 +57,7 @@ import traceback
|
|||||||
|
|
||||||
import optparse
|
import optparse
|
||||||
|
|
||||||
|
import binascii
|
||||||
import struct
|
import struct
|
||||||
import string
|
import string
|
||||||
import textwrap
|
import textwrap
|
||||||
@@ -175,6 +176,7 @@ class SpinelCliCmd(Cmd, SpinelCodec):
|
|||||||
'networkidtimeout',
|
'networkidtimeout',
|
||||||
'networkname',
|
'networkname',
|
||||||
'panid',
|
'panid',
|
||||||
|
'parent',
|
||||||
'ping',
|
'ping',
|
||||||
'prefix',
|
'prefix',
|
||||||
'releaserouterid',
|
'releaserouterid',
|
||||||
@@ -545,7 +547,53 @@ class SpinelCliCmd(Cmd, SpinelCodec):
|
|||||||
Done
|
Done
|
||||||
\033[0m
|
\033[0m
|
||||||
"""
|
"""
|
||||||
pass
|
child_table = self.prop_get_value(SPINEL.PROP_THREAD_CHILD_TABLE)[0]
|
||||||
|
|
||||||
|
if line == 'list':
|
||||||
|
result = ''
|
||||||
|
for child_data in child_table:
|
||||||
|
child_data = child_data[0]
|
||||||
|
child_id = child_data[1] & 0x1FF
|
||||||
|
result += '{} '.format(child_id)
|
||||||
|
print(result)
|
||||||
|
print("Done")
|
||||||
|
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
child_id = int(line)
|
||||||
|
printed = False
|
||||||
|
for child_data in child_table:
|
||||||
|
child_data = child_data[0]
|
||||||
|
id = child_data[1] & 0x1FF
|
||||||
|
|
||||||
|
if id == child_id:
|
||||||
|
mode = ''
|
||||||
|
if child_data[7] & 0x08:
|
||||||
|
mode += 'r'
|
||||||
|
if child_data[7] & 0x04:
|
||||||
|
mode += 's'
|
||||||
|
if child_data[7] & 0x02:
|
||||||
|
mode += 'd'
|
||||||
|
if child_data[7] & 0x01:
|
||||||
|
mode += 'n'
|
||||||
|
|
||||||
|
print("Child ID: {}".format(id))
|
||||||
|
print("Rloc: {:04x}".format(child_data[1]))
|
||||||
|
print("Ext Addr: {}".format(binascii.hexlify(child_data[0])))
|
||||||
|
print("Mode: {}".format(mode))
|
||||||
|
print("Net Data: {}".format(child_data[4]))
|
||||||
|
print("Timeout: {}".format(child_data[2]))
|
||||||
|
print("Age: {}".format(child_data[3]))
|
||||||
|
print("LQI: {}".format(child_data[5]))
|
||||||
|
print("RSSI: {}".format(child_data[6]))
|
||||||
|
print("Done")
|
||||||
|
|
||||||
|
printed = True
|
||||||
|
|
||||||
|
if not printed:
|
||||||
|
print("Error")
|
||||||
|
except ValueError:
|
||||||
|
print("Error")
|
||||||
|
|
||||||
def do_childmax(self, line):
|
def do_childmax(self, line):
|
||||||
"""\033[1m
|
"""\033[1m
|
||||||
@@ -982,8 +1030,36 @@ class SpinelCliCmd(Cmd, SpinelCodec):
|
|||||||
def do_leaderdata(self, line):
|
def do_leaderdata(self, line):
|
||||||
"""
|
"""
|
||||||
leaderdata
|
leaderdata
|
||||||
|
|
||||||
|
Get the Thread network Leader Data.
|
||||||
|
|
||||||
|
> leaderdata
|
||||||
|
Partition ID: 1987912443
|
||||||
|
Weighting: 64
|
||||||
|
Data Version: 4
|
||||||
|
Stable Data Version: 129
|
||||||
|
Leader Router ID: 47
|
||||||
|
Done
|
||||||
"""
|
"""
|
||||||
pass
|
partition_id = self.prop_get_value(SPINEL.PROP_NET_PARTITION_ID)
|
||||||
|
weighting = self.prop_get_value(SPINEL.PROP_THREAD_LEADER_WEIGHT)
|
||||||
|
data_version = self.prop_get_value(SPINEL.PROP_THREAD_NETWORK_DATA_VERSION)
|
||||||
|
stable_version = self.prop_get_value(SPINEL.PROP_THREAD_STABLE_NETWORK_DATA_VERSION)
|
||||||
|
leader_id = self.prop_get_value(SPINEL.PROP_THREAD_LEADER_RID)
|
||||||
|
|
||||||
|
if partition_id is None or \
|
||||||
|
weighting is None or \
|
||||||
|
data_version is None or \
|
||||||
|
stable_version is None or \
|
||||||
|
leader_id is None:
|
||||||
|
print("Error")
|
||||||
|
else:
|
||||||
|
print("Partition ID: %d" % partition_id)
|
||||||
|
print("Weighting: %d" % weighting)
|
||||||
|
print("Data Version: %d" % data_version)
|
||||||
|
print("Stable Data Version: %d" % stable_version)
|
||||||
|
print("Leader Router ID: %d" % leader_id)
|
||||||
|
print("Done")
|
||||||
|
|
||||||
def do_leaderweight(self, line):
|
def do_leaderweight(self, line):
|
||||||
"""
|
"""
|
||||||
@@ -1174,6 +1250,26 @@ class SpinelCliCmd(Cmd, SpinelCodec):
|
|||||||
"""
|
"""
|
||||||
self.handle_property(line, SPINEL.PROP_MAC_15_4_PANID, 'H')
|
self.handle_property(line, SPINEL.PROP_MAC_15_4_PANID, 'H')
|
||||||
|
|
||||||
|
def do_parent(self, line):
|
||||||
|
"""
|
||||||
|
parent
|
||||||
|
|
||||||
|
Get the addresses of the parent node.
|
||||||
|
|
||||||
|
> parent
|
||||||
|
Ext Addr: 3ad35f9846ceb9c7
|
||||||
|
Rloc: bc00
|
||||||
|
Done
|
||||||
|
"""
|
||||||
|
ext_addr, rloc = self.prop_get_value(SPINEL.PROP_THREAD_PARENT)
|
||||||
|
|
||||||
|
if ext_addr is None or\
|
||||||
|
rloc is None:
|
||||||
|
print("Error")
|
||||||
|
else:
|
||||||
|
print("Ext Addr: {}".format(binascii.hexlify(ext_addr)))
|
||||||
|
print("Rloc: {:04x}".format(rloc))
|
||||||
|
|
||||||
def do_ping(self, line):
|
def do_ping(self, line):
|
||||||
"""
|
"""
|
||||||
ping <ipaddr> [size] [count] [interval]
|
ping <ipaddr> [size] [count] [interval]
|
||||||
|
|||||||
@@ -169,7 +169,7 @@ class SpinelCodec(object):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def parse_fields(cls, payload, spinel_format):
|
def get_payload_size(cls, spinel_format):
|
||||||
map_lengths = {
|
map_lengths = {
|
||||||
'b': 1,
|
'b': 1,
|
||||||
'c': 1,
|
'c': 1,
|
||||||
@@ -182,7 +182,8 @@ class SpinelCodec(object):
|
|||||||
'E': 8,
|
'E': 8,
|
||||||
'e': 6,
|
'e': 6,
|
||||||
}
|
}
|
||||||
result = []
|
|
||||||
|
result = 0
|
||||||
|
|
||||||
idx = 0
|
idx = 0
|
||||||
while idx < len(spinel_format):
|
while idx < len(spinel_format):
|
||||||
@@ -195,15 +196,55 @@ class SpinelCodec(object):
|
|||||||
struct_end = idx + spinel_format[idx:].index(')')
|
struct_end = idx + spinel_format[idx:].index(')')
|
||||||
|
|
||||||
struct_format = spinel_format[idx+2:struct_end]
|
struct_format = spinel_format[idx+2:struct_end]
|
||||||
struct_len = sum([map_lengths[c] for c in struct_format])
|
result += cls.get_payload_size(struct_format)
|
||||||
|
|
||||||
|
idx = struct_end + 1
|
||||||
|
else:
|
||||||
|
result += map_lengths[format]
|
||||||
|
idx += 1
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def parse_fields(cls, payload, spinel_format):
|
||||||
|
result = []
|
||||||
|
|
||||||
|
idx = 0
|
||||||
|
while idx < len(spinel_format):
|
||||||
|
format = spinel_format[idx]
|
||||||
|
|
||||||
|
if format == 'A':
|
||||||
|
if spinel_format[idx+1] != '(':
|
||||||
|
raise ValueError('Invalid structure format')
|
||||||
|
# TODO: count parentheses. There is a problem with arrays placed one by one.
|
||||||
|
array_end = idx + spinel_format[idx:].rindex(')')
|
||||||
|
|
||||||
|
array_format = spinel_format[idx+2:array_end]
|
||||||
|
|
||||||
|
array = []
|
||||||
|
while len(payload):
|
||||||
|
array.append(cls.parse_fields(payload, array_format))
|
||||||
|
payload = payload[cls.get_payload_size(array_format):]
|
||||||
|
|
||||||
|
result.append(tuple(array))
|
||||||
|
idx = array_end + 1
|
||||||
|
|
||||||
|
elif format == 'T':
|
||||||
|
if spinel_format[idx+1] != '(':
|
||||||
|
raise ValueError('Invalid structure format')
|
||||||
|
# TODO: count parentheses. There is a problem with nested structs.
|
||||||
|
struct_end = idx + spinel_format[idx:].index(')')
|
||||||
|
|
||||||
|
struct_format = spinel_format[idx+2:struct_end]
|
||||||
|
struct_len = cls.get_payload_size(struct_format)
|
||||||
|
|
||||||
result.append(cls.parse_fields(payload, struct_format))
|
result.append(cls.parse_fields(payload, struct_format))
|
||||||
payload = payload[struct_len:]
|
payload = payload[struct_len:]
|
||||||
|
|
||||||
idx = struct_end + 1
|
idx = struct_end + 1
|
||||||
else:
|
else:
|
||||||
result.append(cls.parse_field(payload, spinel_format))
|
result.append(cls.parse_field(payload, format))
|
||||||
payload = payload[map_lengths[spinel_format[idx]]:]
|
payload = payload[cls.get_payload_size(format):]
|
||||||
|
|
||||||
idx += 1
|
idx += 1
|
||||||
|
|
||||||
@@ -391,9 +432,9 @@ class SpinelPropertyHandler(SpinelCodec):
|
|||||||
|
|
||||||
def THREAD_LEADER_ADDR(self, _, payload): return self.parse_6(payload)
|
def THREAD_LEADER_ADDR(self, _, payload): return self.parse_6(payload)
|
||||||
|
|
||||||
def THREAD_PARENT(self, _wpan_api, payload): pass
|
def THREAD_PARENT(self, _wpan_api, payload): return self.parse_fields(payload, "ES")
|
||||||
|
|
||||||
def THREAD_CHILD_TABLE(self, _, payload): return self.parse_D(payload)
|
def THREAD_CHILD_TABLE(self, _, payload): return self.parse_fields(payload, "A(T(ESLLCCcC))")
|
||||||
|
|
||||||
def THREAD_LEADER_RID(self, _, payload): return self.parse_C(payload)
|
def THREAD_LEADER_RID(self, _, payload): return self.parse_C(payload)
|
||||||
|
|
||||||
@@ -406,11 +447,13 @@ class SpinelPropertyHandler(SpinelCodec):
|
|||||||
def THREAD_NETWORK_DATA(self, _, payload):
|
def THREAD_NETWORK_DATA(self, _, payload):
|
||||||
return self.parse_D(payload)
|
return self.parse_D(payload)
|
||||||
|
|
||||||
def THREAD_NETWORK_DATA_VERSION(self, _wpan_api, payload): pass
|
def THREAD_NETWORK_DATA_VERSION(self, _wpan_api, payload):
|
||||||
|
return self.parse_C(payload)
|
||||||
|
|
||||||
def THREAD_STABLE_NETWORK_DATA(self, _wpan_api, payload): pass
|
def THREAD_STABLE_NETWORK_DATA(self, _wpan_api, payload): pass
|
||||||
|
|
||||||
def THREAD_STABLE_NETWORK_DATA_VERSION(self, _wpan_api, payload): pass
|
def THREAD_STABLE_NETWORK_DATA_VERSION(self, _wpan_api, payload):
|
||||||
|
return self.parse_C(payload)
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.autoAddresses = set()
|
self.autoAddresses = set()
|
||||||
@@ -543,6 +586,9 @@ class SpinelPropertyHandler(SpinelCodec):
|
|||||||
def THREAD_ROUTER_SELECTION_JITTER(self, _, payload):
|
def THREAD_ROUTER_SELECTION_JITTER(self, _, payload):
|
||||||
return self.parse_C(payload)
|
return self.parse_C(payload)
|
||||||
|
|
||||||
|
def THREAD_NEIGHBOR_TABLE(self, _, payload):
|
||||||
|
return self.parse_fields(payload, 'A(T(ESLCcCbLL))')
|
||||||
|
|
||||||
def THREAD_CONTEXT_REUSE_DELAY(self, _, payload):
|
def THREAD_CONTEXT_REUSE_DELAY(self, _, payload):
|
||||||
return self.parse_L(payload)
|
return self.parse_L(payload)
|
||||||
|
|
||||||
@@ -738,6 +784,7 @@ SPINEL_PROP_DISPATCH = {
|
|||||||
SPINEL.PROP_THREAD_NETWORK_ID_TIMEOUT: WPAN_PROP_HANDLER.THREAD_NETWORK_ID_TIMEOUT,
|
SPINEL.PROP_THREAD_NETWORK_ID_TIMEOUT: WPAN_PROP_HANDLER.THREAD_NETWORK_ID_TIMEOUT,
|
||||||
SPINEL.PROP_THREAD_ACTIVE_ROUTER_IDS: WPAN_PROP_HANDLER.THREAD_ACTIVE_ROUTER_IDS,
|
SPINEL.PROP_THREAD_ACTIVE_ROUTER_IDS: WPAN_PROP_HANDLER.THREAD_ACTIVE_ROUTER_IDS,
|
||||||
SPINEL.PROP_THREAD_RLOC16_DEBUG_PASSTHRU: WPAN_PROP_HANDLER.THREAD_RLOC16_DEBUG_PASSTHRU,
|
SPINEL.PROP_THREAD_RLOC16_DEBUG_PASSTHRU: WPAN_PROP_HANDLER.THREAD_RLOC16_DEBUG_PASSTHRU,
|
||||||
|
SPINEL.PROP_THREAD_NEIGHBOR_TABLE: WPAN_PROP_HANDLER.THREAD_NEIGHBOR_TABLE,
|
||||||
|
|
||||||
SPINEL.PROP_MESHCOP_JOINER_ENABLE: WPAN_PROP_HANDLER.MESHCOP_JOINER_ENABLE,
|
SPINEL.PROP_MESHCOP_JOINER_ENABLE: WPAN_PROP_HANDLER.MESHCOP_JOINER_ENABLE,
|
||||||
SPINEL.PROP_MESHCOP_JOINER_CREDENTIAL: WPAN_PROP_HANDLER.MESHCOP_JOINER_CREDENTIAL,
|
SPINEL.PROP_MESHCOP_JOINER_CREDENTIAL: WPAN_PROP_HANDLER.MESHCOP_JOINER_CREDENTIAL,
|
||||||
|
|||||||
Reference in New Issue
Block a user