From fb77e574cba34f16780b7dc9920a58aac32122f2 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Tue, 4 Oct 2016 15:25:42 -0700 Subject: [PATCH] Add new spinel property THREAD_NEIGHBOR_TABLE and its support in Ncp (#742) This commit adds a new spinel property `THREAD_NEIGHBOR_TABLE` and its get handler in `NcpBase` class. --- doc/spinel-protocol-src/spinel-tech-thread.md | 18 ++++- src/ncp/ncp_base.cpp | 66 +++++++++++++++++++ src/ncp/ncp_base.hpp | 1 + src/ncp/spinel.c | 4 ++ src/ncp/spinel.h | 6 ++ 5 files changed, 94 insertions(+), 1 deletion(-) diff --git a/doc/spinel-protocol-src/spinel-tech-thread.md b/doc/spinel-protocol-src/spinel-tech-thread.md index 08313f1cf..931f5763c 100644 --- a/doc/spinel-protocol-src/spinel-tech-thread.md +++ b/doc/spinel-protocol-src/spinel-tech-thread.md @@ -185,7 +185,7 @@ Specifies the self imposed random delay in seconds a REED waits before registering to become an Active Router. ### PROP 5386: PROP_THREAD_PREFERRED_ROUTER_ID -* Type: Write +* Type: Write-Only * Packed-Encoding: `C` Specifies the preferred Router Id. Upon becoming a router/leader the node @@ -193,3 +193,19 @@ attempts to use this Router Id. If the preferred Router Id is not set or if it can not be used, a randomly generated router id is picked. This property can be set only when the device role is either detached or disabled. + +### PROP 5387: SPINEL_PROP_THREAD_NEIGHBOR_TABLE +* Type: Read-Only +* Packed-Encoding: `A(T(ESLCcCbLL))` + +Data per item is: + +* `E`: Extended/long address +* `S`: RLOC16 +* `L`: Age +* `C`: Link Quality In +* `c`: Average RSS +* `C`: Mode (bit-flags) +* `b`: `true` if neighbor is a child, `false` otherwise. +* `L`: Link Frame Counter +* `L`: MLE Frame Counter diff --git a/src/ncp/ncp_base.cpp b/src/ncp/ncp_base.cpp index 0c31f20d3..42667545f 100644 --- a/src/ncp/ncp_base.cpp +++ b/src/ncp/ncp_base.cpp @@ -116,6 +116,7 @@ const NcpBase::GetPropertyHandlerEntry NcpBase::mGetPropertyHandlerTable[] = { SPINEL_PROP_THREAD_LEADER_ADDR, &NcpBase::GetPropertyHandler_THREAD_LEADER_ADDR }, { SPINEL_PROP_THREAD_PARENT, &NcpBase::GetPropertyHandler_THREAD_PARENT }, { SPINEL_PROP_THREAD_CHILD_TABLE, &NcpBase::GetPropertyHandler_THREAD_CHILD_TABLE }, + { SPINEL_PROP_THREAD_NEIGHBOR_TABLE, &NcpBase::GetPropertyHandler_THREAD_NEIGHBOR_TABLE }, { SPINEL_PROP_THREAD_LEADER_RID, &NcpBase::GetPropertyHandler_THREAD_LEADER_RID }, { SPINEL_PROP_THREAD_LEADER_WEIGHT, &NcpBase::GetPropertyHandler_THREAD_LEADER_WEIGHT }, { SPINEL_PROP_THREAD_LOCAL_LEADER_WEIGHT, &NcpBase::GetPropertyHandler_THREAD_LOCAL_LEADER_WEIGHT }, @@ -2018,6 +2019,71 @@ exit: return errorCode; } +ThreadError NcpBase::GetPropertyHandler_THREAD_NEIGHBOR_TABLE(uint8_t header, spinel_prop_key_t key) +{ + ThreadError errorCode = kThreadError_None; + otNeighborInfoIterator iter = OT_NEIGHBOR_INFO_ITERATOR_INIT; + otNeighborInfo neighInfo; + uint8_t modeFlags; + + SuccessOrExit(errorCode = OutboundFrameBegin()); + SuccessOrExit(errorCode = OutboundFrameFeedPacked("Cii", header, SPINEL_CMD_PROP_VALUE_IS, key)); + + while (otGetNextNeighborInfo(mInstance, &iter, &neighInfo) == kThreadError_None) + { + modeFlags = 0; + + if (neighInfo.mRxOnWhenIdle) + { + modeFlags |= kThreadMode_RxOnWhenIdle; + } + + if (neighInfo.mSecureDataRequest) + { + modeFlags |= kThreadMode_SecureDataRequest; + } + + if (neighInfo.mFullFunction) + { + modeFlags |= kThreadMode_FullFunctionDevice; + } + + if (neighInfo.mFullNetworkData) + { + modeFlags |= kThreadMode_FullNetworkData; + } + + SuccessOrExit( + errorCode = OutboundFrameFeedPacked( + "T(" + SPINEL_DATATYPE_EUI64_S // EUI64 Address + SPINEL_DATATYPE_UINT16_S // Rloc16 + SPINEL_DATATYPE_UINT32_S // Age + SPINEL_DATATYPE_UINT8_S // Link Quality In + SPINEL_DATATYPE_INT8_S // Average RSS + SPINEL_DATATYPE_UINT8_S // Mode (flags) + SPINEL_DATATYPE_BOOL_S // Is Child + SPINEL_DATATYPE_UINT32_S // Link Frame Counter + SPINEL_DATATYPE_UINT32_S // MLE Frame Counter + ")", + neighInfo.mExtAddress.m8, + neighInfo.mRloc16, + neighInfo.mAge, + neighInfo.mLinkQualityIn, + neighInfo.mAverageRssi, + modeFlags, + neighInfo.mIsChild, + neighInfo.mLinkFrameCounter, + neighInfo.mMleFrameCounter + )); + } + + SuccessOrExit(errorCode = OutboundFrameSend()); + +exit: + return errorCode; +} + ThreadError NcpBase::GetPropertyHandler_THREAD_ASSISTING_PORTS(uint8_t header, spinel_prop_key_t key) { ThreadError errorCode = kThreadError_None; diff --git a/src/ncp/ncp_base.hpp b/src/ncp/ncp_base.hpp index 175c76c8e..473b33642 100644 --- a/src/ncp/ncp_base.hpp +++ b/src/ncp/ncp_base.hpp @@ -315,6 +315,7 @@ private: ThreadError GetPropertyHandler_THREAD_LEADER_ADDR(uint8_t header, spinel_prop_key_t key); ThreadError GetPropertyHandler_THREAD_PARENT(uint8_t header, spinel_prop_key_t key); ThreadError GetPropertyHandler_THREAD_CHILD_TABLE(uint8_t header, spinel_prop_key_t key); + ThreadError GetPropertyHandler_THREAD_NEIGHBOR_TABLE(uint8_t header, spinel_prop_key_t key); ThreadError GetPropertyHandler_THREAD_LEADER_RID(uint8_t header, spinel_prop_key_t key); ThreadError GetPropertyHandler_THREAD_LEADER_WEIGHT(uint8_t header, spinel_prop_key_t key); ThreadError GetPropertyHandler_THREAD_LOCAL_LEADER_WEIGHT(uint8_t header, spinel_prop_key_t key); diff --git a/src/ncp/spinel.c b/src/ncp/spinel.c index dc3b7fda9..e47532266 100644 --- a/src/ncp/spinel.c +++ b/src/ncp/spinel.c @@ -1177,6 +1177,10 @@ spinel_prop_key_to_cstr(spinel_prop_key_t prop_key) ret = "SPINEL_PROP_THREAD_PREFERRED_ROUTER_ID"; break; + case SPINEL_PROP_THREAD_NEIGHBOR_TABLE: + ret = "SPINEL_PROP_THREAD_NEIGHBOR_TABLE"; + break; + default: break; } diff --git a/src/ncp/spinel.h b/src/ncp/spinel.h index f682a6652..f17025a8a 100644 --- a/src/ncp/spinel.h +++ b/src/ncp/spinel.h @@ -535,6 +535,12 @@ typedef enum SPINEL_PROP_THREAD_PREFERRED_ROUTER_ID = SPINEL_PROP_THREAD_EXT__BEGIN + 10, + /// Thread Neighbor Table + /** Format: `A(T(ESLCcCbLL))` + * eui64, rloc16, age, inLqi ,aveRSS, mode, isChild. linkFrameCounter, mleCounter + */ + SPINEL_PROP_THREAD_NEIGHBOR_TABLE = SPINEL_PROP_THREAD_EXT__BEGIN + 11, + SPINEL_PROP_THREAD_EXT__END = 0x1600, SPINEL_PROP_IPV6__BEGIN = 0x60,