diff --git a/doc/spinel-protocol-src/spinel-tech-thread.md b/doc/spinel-protocol-src/spinel-tech-thread.md index 43d93adb4..6d7e596fa 100644 --- a/doc/spinel-protocol-src/spinel-tech-thread.md +++ b/doc/spinel-protocol-src/spinel-tech-thread.md @@ -539,3 +539,26 @@ Data per item is: * `E`: Extended address of the child * `S`: RLOC16 of the child * `A(6)`: List of IPv6 addresses registered by the child (if any) + +### PROP 5410: SPINEL_PROP_THREAD_NEIGHBOR_TABLE_ERROR_RATES (#prop-thread-neighbor-table-error-rates) + +* Type: Read-Only +* Packing-Encoding: `A(t(ESSScc))` +* Required capability: `CAP_ERROR_RATE_TRACKING` + +This property provides link quality related info including +frame and (IPv6) message error rates for all neighbors. + +With regards to message error rate, note that a larger (IPv6) +message can be fragmented and sent as multiple MAC frames. The +message transmission is considered a failure, if any of its +fragments fail after all MAC retry attempts. + +Data per item is: + +* `E`: Extended address of the neighbor +* `S`: RLOC16 of the neighbor +* `S`: Frame error rate (0 -> 0%, 0xffff -> 100%) +* `S`: Message error rate (0 -> 0%, 0xffff -> 100%) +* `c`: Average RSSI (in dBm) +* `c`: Last RSSI (in dBm) diff --git a/src/ncp/ncp_base.cpp b/src/ncp/ncp_base.cpp index 889921c5e..e52ef3450 100644 --- a/src/ncp/ncp_base.cpp +++ b/src/ncp/ncp_base.cpp @@ -126,6 +126,9 @@ const NcpBase::PropertyHandlerEntry NcpBase::mGetPropertyHandlerTable[] = NCP_GET_PROP_HANDLER_ENTRY(THREAD_LEADER_RID), NCP_GET_PROP_HANDLER_ENTRY(THREAD_MODE), NCP_GET_PROP_HANDLER_ENTRY(THREAD_NEIGHBOR_TABLE), +#if OPENTHREAD_CONFIG_ENABLE_TX_ERROR_RATE_TRACKING + NCP_GET_PROP_HANDLER_ENTRY(THREAD_NEIGHBOR_TABLE_ERROR_RATES), +#endif NCP_GET_PROP_HANDLER_ENTRY(THREAD_NETWORK_DATA_VERSION), NCP_GET_PROP_HANDLER_ENTRY(THREAD_OFF_MESH_ROUTES), NCP_GET_PROP_HANDLER_ENTRY(THREAD_ON_MESH_NETS), @@ -1795,6 +1798,10 @@ otError NcpBase::GetPropertyHandler_CAPS(void) SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_CAP_CHANNEL_MONITOR)); #endif +#if OPENTHREAD_CONFIG_ENABLE_TX_ERROR_RATE_TRACKING + SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_CAP_ERROR_RATE_TRACKING)); +#endif + #if OPENTHREAD_CONFIG_ENABLE_STEERING_DATA_SET_OOB SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_CAP_OOB_STEERING_DATA)); #endif diff --git a/src/ncp/ncp_base.hpp b/src/ncp/ncp_base.hpp index fe033fe51..04931bcab 100644 --- a/src/ncp/ncp_base.hpp +++ b/src/ncp/ncp_base.hpp @@ -497,6 +497,9 @@ protected: NCP_GET_PROP_HANDLER(THREAD_LEADER_ADDR); NCP_GET_PROP_HANDLER(THREAD_PARENT); NCP_GET_PROP_HANDLER(THREAD_NEIGHBOR_TABLE); +#if OPENTHREAD_CONFIG_ENABLE_TX_ERROR_RATE_TRACKING + NCP_GET_PROP_HANDLER(THREAD_NEIGHBOR_TABLE_ERROR_RATES); +#endif NCP_GET_PROP_HANDLER(THREAD_LEADER_RID); NCP_GET_PROP_HANDLER(THREAD_LEADER_WEIGHT); #if OPENTHREAD_ENABLE_BORDER_ROUTER diff --git a/src/ncp/ncp_base_mtd.cpp b/src/ncp/ncp_base_mtd.cpp index 29dba5feb..a0d22d6af 100644 --- a/src/ncp/ncp_base_mtd.cpp +++ b/src/ncp/ncp_base_mtd.cpp @@ -627,6 +627,34 @@ exit: return error; } +#if OPENTHREAD_CONFIG_ENABLE_TX_ERROR_RATE_TRACKING + +otError NcpBase::GetPropertyHandler_THREAD_NEIGHBOR_TABLE_ERROR_RATES(void) +{ + otError error = OT_ERROR_NONE; + otNeighborInfoIterator iter = OT_NEIGHBOR_INFO_ITERATOR_INIT; + otNeighborInfo neighInfo; + + while (otThreadGetNextNeighborInfo(mInstance, &iter, &neighInfo) == OT_ERROR_NONE) + { + SuccessOrExit(error = mEncoder.OpenStruct()); + + SuccessOrExit(error = mEncoder.WriteEui64(neighInfo.mExtAddress)); + SuccessOrExit(error = mEncoder.WriteUint16(neighInfo.mRloc16)); + SuccessOrExit(error = mEncoder.WriteUint16(neighInfo.mFrameErrorRate)); + SuccessOrExit(error = mEncoder.WriteUint16(neighInfo.mMessageErrorRate)); + SuccessOrExit(error = mEncoder.WriteInt8(neighInfo.mAverageRssi)); + SuccessOrExit(error = mEncoder.WriteInt8(neighInfo.mLastRssi)); + + SuccessOrExit(error = mEncoder.CloseStruct()); + } + +exit: + return error; +} + +#endif // OPENTHREAD_CONFIG_ENABLE_TX_ERROR_RATE_TRACKING + otError NcpBase::GetPropertyHandler_THREAD_ASSISTING_PORTS(void) { otError error = OT_ERROR_NONE; diff --git a/src/ncp/spinel.c b/src/ncp/spinel.c index 6b46718a8..d95a43f63 100644 --- a/src/ncp/spinel.c +++ b/src/ncp/spinel.c @@ -1537,6 +1537,10 @@ spinel_prop_key_to_cstr(spinel_prop_key_t prop_key) ret = "PROP_THREAD_CHILD_TABLE_ADDRESSES"; break; + case SPINEL_PROP_THREAD_NEIGHBOR_TABLE_ERROR_RATES: + ret = "PROP_THREAD_NEIGHBOR_TABLE_ERROR_RATES"; + break; + case SPINEL_PROP_IPV6_LL_ADDR: ret = "PROP_IPV6_LL_ADDR"; break; @@ -2132,6 +2136,10 @@ const char *spinel_capability_to_cstr(unsigned int capability) ret = "CAP_CHANNEL_MONITOR"; break; + case SPINEL_CAP_ERROR_RATE_TRACKING: + ret = "CAP_ERROR_RATE_TRACKING"; + break; + case SPINEL_CAP_THREAD_COMMISSIONER: ret = "CAP_THREAD_COMMISSIONER"; break; diff --git a/src/ncp/spinel.h b/src/ncp/spinel.h index 28b8634ac..b2226063e 100644 --- a/src/ncp/spinel.h +++ b/src/ncp/spinel.h @@ -418,6 +418,7 @@ enum SPINEL_CAP_MAC_RAW = (SPINEL_CAP_OPENTHREAD__BEGIN + 1), SPINEL_CAP_OOB_STEERING_DATA = (SPINEL_CAP_OPENTHREAD__BEGIN + 2), SPINEL_CAP_CHANNEL_MONITOR = (SPINEL_CAP_OPENTHREAD__BEGIN + 3), + SPINEL_CAP_ERROR_RATE_TRACKING = (SPINEL_CAP_OPENTHREAD__BEGIN + 4), SPINEL_CAP_OPENTHREAD__END = 640, SPINEL_CAP_THREAD__BEGIN = 1024, @@ -1346,6 +1347,32 @@ typedef enum */ SPINEL_PROP_THREAD_CHILD_TABLE_ADDRESSES = SPINEL_PROP_THREAD_EXT__BEGIN + 33, + + /// Neighbor Table Frame and Message Error Rates + /** Format: `A(t(ESSScc))` + * Required capability: `CAP_ERROR_RATE_TRACKING` + * + * This property provides link quality related info including + * frame and (IPv6) message error rates for all neighbors. + * + * With regards to message error rate, note that a larger (IPv6) + * message can be fragmented and sent as multiple MAC frames. The + * message transmission is considered a failure, if any of its + * fragments fail after all MAC retry attempts. + * + * Data per item is: + * + * `E`: Extended address of the neighbor + * `S`: RLOC16 of the neighbor + * `S`: Frame error rate (0 -> 0%, 0xffff -> 100%) + * `S`: Message error rate (0 -> 0%, 0xffff -> 100%) + * `c`: Average RSSI (in dBm) + * `c`: Last RSSI (in dBm) + * + */ + SPINEL_PROP_THREAD_NEIGHBOR_TABLE_ERROR_RATES + = SPINEL_PROP_THREAD_EXT__BEGIN + 34, + SPINEL_PROP_THREAD_EXT__END = 0x1600, SPINEL_PROP_IPV6__BEGIN = 0x60,