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:
Hubert Miś
2017-01-12 06:01:25 -08:00
committed by Jonathan Hui
parent 490eabb0e1
commit 6ef5ef33fa
2 changed files with 154 additions and 11 deletions
+98 -2
View File
@@ -57,6 +57,7 @@ import traceback
import optparse
import binascii
import struct
import string
import textwrap
@@ -175,6 +176,7 @@ class SpinelCliCmd(Cmd, SpinelCodec):
'networkidtimeout',
'networkname',
'panid',
'parent',
'ping',
'prefix',
'releaserouterid',
@@ -545,7 +547,53 @@ class SpinelCliCmd(Cmd, SpinelCodec):
Done
\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):
"""\033[1m
@@ -982,8 +1030,36 @@ class SpinelCliCmd(Cmd, SpinelCodec):
def do_leaderdata(self, line):
"""
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):
"""
@@ -1174,6 +1250,26 @@ class SpinelCliCmd(Cmd, SpinelCodec):
"""
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):
"""
ping <ipaddr> [size] [count] [interval]
+56 -9
View File
@@ -169,7 +169,7 @@ class SpinelCodec(object):
return None
@classmethod
def parse_fields(cls, payload, spinel_format):
def get_payload_size(cls, spinel_format):
map_lengths = {
'b': 1,
'c': 1,
@@ -182,7 +182,8 @@ class SpinelCodec(object):
'E': 8,
'e': 6,
}
result = []
result = 0
idx = 0
while idx < len(spinel_format):
@@ -195,15 +196,55 @@ class SpinelCodec(object):
struct_end = idx + spinel_format[idx:].index(')')
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))
payload = payload[struct_len:]
idx = struct_end + 1
else:
result.append(cls.parse_field(payload, spinel_format))
payload = payload[map_lengths[spinel_format[idx]]:]
result.append(cls.parse_field(payload, format))
payload = payload[cls.get_payload_size(format):]
idx += 1
@@ -391,9 +432,9 @@ class SpinelPropertyHandler(SpinelCodec):
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)
@@ -406,11 +447,13 @@ class SpinelPropertyHandler(SpinelCodec):
def THREAD_NETWORK_DATA(self, _, 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_VERSION(self, _wpan_api, payload): pass
def THREAD_STABLE_NETWORK_DATA_VERSION(self, _wpan_api, payload):
return self.parse_C(payload)
def __init__(self):
self.autoAddresses = set()
@@ -543,6 +586,9 @@ class SpinelPropertyHandler(SpinelCodec):
def THREAD_ROUTER_SELECTION_JITTER(self, _, 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):
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_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_NEIGHBOR_TABLE: WPAN_PROP_HANDLER.THREAD_NEIGHBOR_TABLE,
SPINEL.PROP_MESHCOP_JOINER_ENABLE: WPAN_PROP_HANDLER.MESHCOP_JOINER_ENABLE,
SPINEL.PROP_MESHCOP_JOINER_CREDENTIAL: WPAN_PROP_HANDLER.MESHCOP_JOINER_CREDENTIAL,