[spinel] handle link metrics (#6228)

This commit allows the spinel interface to deal with link metrics.

There are 7 new properties introduced:
- THREAD_LINK_METRICS_QUERY
- THREAD_LINK_METRICS_QUERY_RESULT
- THREAD_LINK_METRICS_PROBE
- THREAD_LINK_METRICS_MGMT_ENH_ACK
- THREAD_LINK_METRICS_MGMT_ENH_ACK_IE
- THREAD_LINK_METRICS_MGMT_FORWARD
- THREAD_LINK_METRICS_MGMT_RESPONSE
This commit is contained in:
Piotr Koziar
2021-04-06 07:42:46 -07:00
committed by GitHub
parent fa09e8a75d
commit 77d3af396c
6 changed files with 504 additions and 4 deletions
+7
View File
@@ -1344,6 +1344,13 @@ const char *spinel_prop_key_to_cstr(spinel_prop_key_t prop_key)
{SPINEL_PROP_THREAD_CSL_TIMEOUT, "THREAD_CSL_TIMEOUT"},
{SPINEL_PROP_THREAD_CSL_CHANNEL, "THREAD_CSL_CHANNEL"},
{SPINEL_PROP_THREAD_DOMAIN_NAME, "THREAD_DOMAIN_NAME"},
{SPINEL_PROP_THREAD_LINK_METRICS_QUERY, "THREAD_LINK_METRICS_QUERY"},
{SPINEL_PROP_THREAD_LINK_METRICS_QUERY_RESULT, "THREAD_LINK_METRICS_QUERY_RESULT"},
{SPINEL_PROP_THREAD_LINK_METRICS_PROBE, "THREAD_LINK_METRICS_PROBE"},
{SPINEL_PROP_THREAD_LINK_METRICS_MGMT_ENH_ACK, "THREAD_LINK_METRICS_MGMT_ENH_ACK"},
{SPINEL_PROP_THREAD_LINK_METRICS_MGMT_ENH_ACK_IE, "THREAD_LINK_METRICS_MGMT_ENH_ACK_IE"},
{SPINEL_PROP_THREAD_LINK_METRICS_MGMT_FORWARD, "THREAD_LINK_METRICS_MGMT_FORWARD"},
{SPINEL_PROP_THREAD_LINK_METRICS_MGMT_RESPONSE, "THREAD_LINK_METRICS_MGMT_RESPONSE"},
{SPINEL_PROP_THREAD_MLR_REQUEST, "THREAD_MLR_REQUEST"},
{SPINEL_PROP_THREAD_MLR_RESPONSE, "THREAD_MLR_RESPONSE"},
{SPINEL_PROP_THREAD_BACKBONE_ROUTER_PRIMARY, "THREAD_BACKBONE_ROUTER_PRIMARY"},
+196
View File
@@ -466,6 +466,8 @@ enum
SPINEL_STATUS_ALREADY = 19, ///< The operation is already in progress.
SPINEL_STATUS_ITEM_NOT_FOUND = 20, ///< The given item could not be found.
SPINEL_STATUS_INVALID_COMMAND_FOR_PROP = 21, ///< The given command cannot be performed on this property.
SPINEL_STATUS_UNKNOWN_NEIGHBOR = 22, ///< The neighbor is unknown.
SPINEL_STATUS_NOT_CAPABLE = 23, ///< The target is not capable of handling requested operation.
SPINEL_STATUS_RESPONSE_TIMEOUT = 24, ///< No response received from remote node
SPINEL_STATUS_JOIN__BEGIN = 104,
@@ -725,6 +727,43 @@ enum
SPINEL_RADIO_LINK_TREL_UDP6 = 1,
};
// Statuses that can be received as a result of:
// @ref SPINEL_PROP_THREAD_LINK_METRICS_QUERY
// @ref SPINEL_PROP_THREAD_LINK_METRICS_MGMT_ENH_ACK
// @ref SPINEL_PROP_THREAD_LINK_METRICS_MGMT_FORWARD
enum
{
SPINEL_LINK_METRICS_STATUS_SUCCESS = 0,
SPINEL_LINK_METRICS_STATUS_CANNOT_SUPPORT_NEW_SERIES = 1,
SPINEL_LINK_METRICS_STATUS_SERIESID_ALREADY_REGISTERED = 2,
SPINEL_LINK_METRICS_STATUS_SERIESID_NOT_RECOGNIZED = 3,
SPINEL_LINK_METRICS_STATUS_NO_MATCHING_FRAMES_RECEIVED = 4,
SPINEL_LINK_METRICS_STATUS_OTHER_ERROR = 254
};
// Metric ids used for:
// @ref SPINEL_PROP_THREAD_LINK_METRICS_QUERY
// @ref SPINEL_PROP_THREAD_LINK_METRICS_QUERY_RESULT
// @ref SPINEL_PROP_THREAD_LINK_METRICS_MGMT_ENH_ACK
// @ref SPINEL_PROP_THREAD_LINK_METRICS_MGMT_FORWARD
enum
{
SPINEL_THREAD_LINK_METRIC_PDU_COUNT = (1 << 0),
SPINEL_THREAD_LINK_METRIC_LQI = (1 << 1),
SPINEL_THREAD_LINK_METRIC_LINK_MARGIN = (1 << 2),
SPINEL_THREAD_LINK_METRIC_RSSI = (1 << 3),
};
// Frame types used for:
// @ref SPINEL_PROP_THREAD_LINK_METRICS_MGMT_FORWARD
enum
{
SPINEL_THREAD_FRAME_TYPE_MLE_LINK_PROBE = (1 << 0),
SPINEL_THREAD_FRAME_TYPE_MAC_DATA = (1 << 1),
SPINEL_THREAD_FRAME_TYPE_MAC_DATA_REQUEST = (1 << 2),
SPINEL_THREAD_FRAME_TYPE_MAC_ACK = (1 << 3),
};
// Parameter ids used for:
// @ref SPINEL_PROP_THREAD_MLR_REQUEST
enum
@@ -1216,6 +1255,7 @@ enum
SPINEL_CAP_THREAD_BORDER_ROUTER = (SPINEL_CAP_THREAD__BEGIN + 4),
SPINEL_CAP_THREAD_SERVICE = (SPINEL_CAP_THREAD__BEGIN + 5),
SPINEL_CAP_THREAD_CSL_RECEIVER = (SPINEL_CAP_THREAD__BEGIN + 6),
SPINEL_CAP_THREAD_LINK_METRICS = (SPINEL_CAP_THREAD__BEGIN + 7),
SPINEL_CAP_THREAD_BACKBONE_ROUTER = (SPINEL_CAP_THREAD__BEGIN + 8),
SPINEL_CAP_THREAD__END = 1152,
@@ -2964,6 +3004,160 @@ enum
*/
SPINEL_PROP_THREAD_DOMAIN_NAME = SPINEL_PROP_THREAD_EXT__BEGIN + 44,
/// Link metrics query
/** Format: `6CC` - Write-Only
*
* Required capability: `SPINEL_CAP_THREAD_LINK_METRICS`
*
* `6` : IPv6 destination address
* `C` : Series id (0 for Single Probe)
* `C` : List of requested metric ids encoded as bit fields in single byte
*
* +---------------+----+
* | Metric | Id |
* +---------------+----+
* | Received PDUs | 0 |
* | LQI | 1 |
* | Link margin | 2 |
* | RSSI | 3 |
* +---------------+----+
*
* If the query succeeds, the NCP will send a result to the Host using
* @ref SPINEL_PROP_THREAD_LINK_METRICS_QUERY_RESULT.
*
*/
SPINEL_PROP_THREAD_LINK_METRICS_QUERY = SPINEL_PROP_THREAD_EXT__BEGIN + 45,
/// Link metrics query result
/** Format: `6Ct(A(t(CD)))` - Unsolicited notifications only
*
* Required capability: `SPINEL_CAP_THREAD_LINK_METRICS`
*
* `6` : IPv6 destination address
* `C` : Status
* `t(A(t(CD)))` : Array of structs encoded as following:
* `C` : Metric id
* `D` : Metric value
*
* +---------------+----+----------------+
* | Metric | Id | Value format |
* +---------------+----+----------------+
* | Received PDUs | 0 | `L` (uint32_t) |
* | LQI | 1 | `C` (uint8_t) |
* | Link margin | 2 | `C` (uint8_t) |
* | RSSI | 3 | `c` (int8_t) |
* +---------------+----+----------------+
*
*/
SPINEL_PROP_THREAD_LINK_METRICS_QUERY_RESULT = SPINEL_PROP_THREAD_EXT__BEGIN + 46,
/// Link metrics probe
/** Format `6CC` - Write only
* Required capability: `SPINEL_CAP_THREAD_LINK_METRICS`
*
* Send a MLE Link Probe message to the peer.
*
* `6` : IPv6 destination address
* `C` : The Series ID for which this Probe message targets at
* `C` : The length of the Probe message, valid range: [0, 64]
*
*/
SPINEL_PROP_THREAD_LINK_METRICS_PROBE = SPINEL_PROP_THREAD_EXT__BEGIN + 47,
/// Link metrics Enhanced-ACK Based Probing management
/** Format: 6Cd - Write only
*
* Required capability: `SPINEL_CAP_THREAD_LINK_METRICS`
*
* `6` : IPv6 destination address
* `C` : Indicate whether to register or clear the probing. `0` - clear, `1` - register
* `C` : List of requested metric ids encoded as bit fields in single byte
*
* +---------------+----+
* | Metric | Id |
* +---------------+----+
* | LQI | 1 |
* | Link margin | 2 |
* | RSSI | 3 |
* +---------------+----+
*
* Result of configuration is reported asynchronously to the Host using the
* @ref SPINEL_PROP_THREAD_LINK_METRICS_MGMT_RESPONSE.
*
* Whenever Enh-ACK IE report is received it is passed to the Host using the
* @ref SPINEL_PROP_THREAD_LINK_METRICS_MGMT_ENH_ACK_IE property.
*
*/
SPINEL_PROP_THREAD_LINK_METRICS_MGMT_ENH_ACK = SPINEL_PROP_THREAD_EXT__BEGIN + 48,
/// Link metrics Enhanced-ACK Based Probing IE report
/** Format: SEA(t(CD)) - Unsolicited notifications only
*
* Required capability: `SPINEL_CAP_THREAD_LINK_METRICS`
*
* `S` : Short address of the Probing Subject
* `E` : Extended address of the Probing Subject
* `t(A(t(CD)))` : Struct that contains array of structs encoded as following:
* `C` : Metric id
* `D` : Metric value
*
* +---------------+----+----------------+
* | Metric | Id | Value format |
* +---------------+----+----------------+
* | LQI | 1 | `C` (uint8_t) |
* | Link margin | 2 | `C` (uint8_t) |
* | RSSI | 3 | `c` (int8_t) |
* +---------------+----+----------------+
*
*/
SPINEL_PROP_THREAD_LINK_METRICS_MGMT_ENH_ACK_IE = SPINEL_PROP_THREAD_EXT__BEGIN + 49,
/// Link metrics Forward Tracking Series management
/** Format: 6CCC - Write only
*
* Required capability: `SPINEL_CAP_THREAD_LINK_METRICS`
*
* `6` : IPv6 destination address
* `C` : Series id
* `C` : Tracked frame types encoded as bit fields in single byte, if equal to zero,
* accounting is stopped and a series is removed
* `C` : Requested metric ids encoded as bit fields in single byte
*
* +------------------+----+
* | Frame type | Id |
* +------------------+----+
* | MLE Link Probe | 0 |
* | MAC Data | 1 |
* | MAC Data Request | 2 |
* | MAC ACK | 3 |
* +------------------+----+
*
* +---------------+----+
* | Metric | Id |
* +---------------+----+
* | Received PDUs | 0 |
* | LQI | 1 |
* | Link margin | 2 |
* | RSSI | 3 |
* +---------------+----+
*
* Result of configuration is reported asynchronously to the Host using the
* @ref SPINEL_PROP_THREAD_LINK_METRICS_MGMT_RESPONSE.
*
*/
SPINEL_PROP_THREAD_LINK_METRICS_MGMT_FORWARD = SPINEL_PROP_THREAD_EXT__BEGIN + 50,
/// Link metrics management response
/** Format: 6C - Unsolicited notifications only
*
* Required capability: `SPINEL_CAP_THREAD_LINK_METRICS`
*
* `6` : IPv6 source address
* `C` : Received status
*
*/
SPINEL_PROP_THREAD_LINK_METRICS_MGMT_RESPONSE = SPINEL_PROP_THREAD_EXT__BEGIN + 51,
/// Multicast Listeners Register Request
/** Format `t(A(6))A(t(CD))` - Write-only
* Required capability: `SPINEL_CAP_NET_THREAD_1_2`
@@ -4746,6 +4940,8 @@ SPINEL_API_EXTERN const char *spinel_capability_to_cstr(spinel_capability_t capa
SPINEL_API_EXTERN const char *spinel_radio_link_to_cstr(uint32_t radio);
SPINEL_API_EXTERN const char *spinel_link_metrics_status_to_cstr(uint8_t status);
// ----------------------------------------------------------------------------
#if defined(__cplusplus)
+12
View File
@@ -135,6 +135,14 @@ spinel_status_t NcpBase::ThreadErrorToSpinelStatus(otError aError)
ret = SPINEL_STATUS_ITEM_NOT_FOUND;
break;
case OT_ERROR_UNKNOWN_NEIGHBOR:
ret = SPINEL_STATUS_UNKNOWN_NEIGHBOR;
break;
case OT_ERROR_NOT_CAPABLE:
ret = SPINEL_STATUS_NOT_CAPABLE;
break;
case OT_ERROR_RESPONSE_TIMEOUT:
ret = SPINEL_STATUS_RESPONSE_TIMEOUT;
break;
@@ -1926,6 +1934,10 @@ template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CAPS>(void)
SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_CAP_SRP_CLIENT));
#endif
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_CAP_THREAD_LINK_METRICS));
#endif
#if OPENTHREAD_CONFIG_DUA_ENABLE
SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_CAP_DUA));
#endif
+30
View File
@@ -337,6 +337,30 @@ protected:
void HandleJoinerCallback(otError aError);
#endif
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
static void HandleLinkMetricsReport_Jump(const otIp6Address * aSource,
const otLinkMetricsValues *aMetricsValues,
uint8_t aStatus,
void * aContext);
void HandleLinkMetricsReport(const otIp6Address * aSource,
const otLinkMetricsValues *aMetricsValues,
uint8_t aStatus);
static void HandleLinkMetricsMgmtResponse_Jump(const otIp6Address *aSource, uint8_t aStatus, void *aContext);
void HandleLinkMetricsMgmtResponse(const otIp6Address *aSource, uint8_t aStatus);
static void HandleLinkMetricsEnhAckProbingIeReport_Jump(otShortAddress aShortAddress,
const otExtAddress * aExtAddress,
const otLinkMetricsValues *aMetricsValues,
void * aContext);
void HandleLinkMetricsEnhAckProbingIeReport(otShortAddress aShortAddress,
const otExtAddress * aExtAddress,
const otLinkMetricsValues *aMetricsValues);
#endif
static void HandleMlrRegResult_Jump(void * aContext,
otError aError,
uint8_t aMlrStatus,
@@ -364,6 +388,12 @@ protected:
otError EncodeChildInfo(const otChildInfo &aChildInfo);
#endif
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
otError DecodeLinkMetrics(otLinkMetrics *aMetrics, bool aAllowPduCount);
otError EncodeLinkMetricsValues(const otLinkMetricsValues *aMetricsValues);
#endif
#if OPENTHREAD_CONFIG_UDP_FORWARD_ENABLE
static void HandleUdpForwardStream(otMessage * aMessage,
uint16_t aPeerPort,
+10 -4
View File
@@ -553,16 +553,22 @@ NcpBase::PropertyHandler NcpBase::FindSetPropertyHandler(spinel_prop_key_t aKey)
OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_THREAD_CSL_TIMEOUT),
OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_THREAD_CSL_CHANNEL),
#endif
#if OPENTHREAD_FTD
#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
#if OPENTHREAD_FTD && (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_THREAD_DOMAIN_NAME),
#endif
#if OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_THREAD_LINK_METRICS_QUERY),
OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_THREAD_LINK_METRICS_PROBE),
OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_THREAD_LINK_METRICS_MGMT_ENH_ACK),
OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_THREAD_LINK_METRICS_MGMT_FORWARD),
#endif
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE && OPENTHREAD_CONFIG_COMMISSIONER_ENABLE
OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_THREAD_MLR_REQUEST),
#endif
#if OPENTHREAD_CONFIG_DUA_ENABLE
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_DUA_ENABLE
OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_THREAD_DUA_ID),
#endif
#if OPENTHREAD_FTD
#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_THREAD_BACKBONE_ROUTER_LOCAL_STATE),
OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_THREAD_BACKBONE_ROUTER_LOCAL_CONFIG),
+249
View File
@@ -209,6 +209,84 @@ exit:
return error;
}
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
otError NcpBase::DecodeLinkMetrics(otLinkMetrics *aMetrics, bool aAllowPduCount)
{
otError error = OT_ERROR_NONE;
uint8_t metrics = 0;
SuccessOrExit(error = mDecoder.ReadUint8(metrics));
if (metrics & SPINEL_THREAD_LINK_METRIC_PDU_COUNT)
{
VerifyOrExit(aAllowPduCount, error = OT_ERROR_INVALID_ARGS);
aMetrics->mPduCount = true;
}
if (metrics & SPINEL_THREAD_LINK_METRIC_LQI)
{
aMetrics->mLqi = true;
}
if (metrics & SPINEL_THREAD_LINK_METRIC_LINK_MARGIN)
{
aMetrics->mLinkMargin = true;
}
if (metrics & SPINEL_THREAD_LINK_METRIC_RSSI)
{
aMetrics->mRssi = true;
}
exit:
return error;
}
otError NcpBase::EncodeLinkMetricsValues(const otLinkMetricsValues *aMetricsValues)
{
otError error = OT_ERROR_NONE;
SuccessOrExit(error = mEncoder.OpenStruct());
if (aMetricsValues->mMetrics.mPduCount)
{
SuccessOrExit(error = mEncoder.OpenStruct());
SuccessOrExit(error = mEncoder.WriteUint8(SPINEL_THREAD_LINK_METRIC_PDU_COUNT));
SuccessOrExit(error = mEncoder.WriteUint32(aMetricsValues->mPduCountValue));
SuccessOrExit(error = mEncoder.CloseStruct());
}
if (aMetricsValues->mMetrics.mLqi)
{
SuccessOrExit(error = mEncoder.OpenStruct());
SuccessOrExit(error = mEncoder.WriteUint8(SPINEL_THREAD_LINK_METRIC_LQI));
SuccessOrExit(error = mEncoder.WriteUint8(aMetricsValues->mLqiValue));
SuccessOrExit(error = mEncoder.CloseStruct());
}
if (aMetricsValues->mMetrics.mLinkMargin)
{
SuccessOrExit(error = mEncoder.OpenStruct());
SuccessOrExit(error = mEncoder.WriteUint8(SPINEL_THREAD_LINK_METRIC_LINK_MARGIN));
SuccessOrExit(error = mEncoder.WriteUint8(aMetricsValues->mLinkMarginValue));
SuccessOrExit(error = mEncoder.CloseStruct());
}
if (aMetricsValues->mMetrics.mRssi)
{
SuccessOrExit(error = mEncoder.OpenStruct());
SuccessOrExit(error = mEncoder.WriteUint8(SPINEL_THREAD_LINK_METRIC_RSSI));
SuccessOrExit(error = mEncoder.WriteInt8(aMetricsValues->mRssiValue));
SuccessOrExit(error = mEncoder.CloseStruct());
}
SuccessOrExit(error = mEncoder.CloseStruct());
exit:
return error;
}
#endif
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_CSL_PERIOD>(void)
{
@@ -3039,6 +3117,105 @@ exit:
}
#endif // OPENTHREAD_CONFIG_MAC_FILTER_ENABLE
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_LINK_METRICS_QUERY>(void)
{
otError error = OT_ERROR_NONE;
struct otIp6Address address;
uint8_t seriesId;
otLinkMetrics linkMetrics = {};
SuccessOrExit(error = mDecoder.ReadIp6Address(address));
SuccessOrExit(error = mDecoder.ReadUint8(seriesId));
SuccessOrExit(error = DecodeLinkMetrics(&linkMetrics, true));
error =
otLinkMetricsQuery(mInstance, &address, seriesId, &linkMetrics, &NcpBase::HandleLinkMetricsReport_Jump, this);
exit:
return error;
}
template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_LINK_METRICS_PROBE>(void)
{
otError error = OT_ERROR_NONE;
struct otIp6Address address;
uint8_t seriesId;
uint8_t length;
SuccessOrExit(error = mDecoder.ReadIp6Address(address));
SuccessOrExit(error = mDecoder.ReadUint8(seriesId));
SuccessOrExit(error = mDecoder.ReadUint8(length));
error = otLinkMetricsSendLinkProbe(mInstance, &address, seriesId, length);
exit:
return error;
}
template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_LINK_METRICS_MGMT_ENH_ACK>(void)
{
otError error = OT_ERROR_NONE;
struct otIp6Address address;
uint8_t controlFlags;
otLinkMetrics linkMetrics = {};
SuccessOrExit(error = mDecoder.ReadIp6Address(address));
SuccessOrExit(error = mDecoder.ReadUint8(controlFlags));
SuccessOrExit(error = DecodeLinkMetrics(&linkMetrics, false));
error = otLinkMetricsConfigEnhAckProbing(mInstance, &address, static_cast<otLinkMetricsEnhAckFlags>(controlFlags),
controlFlags ? &linkMetrics : nullptr,
&NcpBase::HandleLinkMetricsMgmtResponse_Jump, this,
&NcpBase::HandleLinkMetricsEnhAckProbingIeReport_Jump, this);
exit:
return error;
}
template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_THREAD_LINK_METRICS_MGMT_FORWARD>(void)
{
otError error = OT_ERROR_NONE;
struct otIp6Address address;
uint8_t seriesId;
uint8_t types;
otLinkMetrics linkMetrics = {};
otLinkMetricsSeriesFlags seriesFlags = {};
SuccessOrExit(error = mDecoder.ReadIp6Address(address));
SuccessOrExit(error = mDecoder.ReadUint8(seriesId));
SuccessOrExit(error = mDecoder.ReadUint8(types));
SuccessOrExit(error = DecodeLinkMetrics(&linkMetrics, true));
if (types & SPINEL_THREAD_FRAME_TYPE_MLE_LINK_PROBE)
{
seriesFlags.mLinkProbe = true;
}
if (types & SPINEL_THREAD_FRAME_TYPE_MAC_DATA)
{
seriesFlags.mMacData = true;
}
if (types & SPINEL_THREAD_FRAME_TYPE_MAC_DATA_REQUEST)
{
seriesFlags.mMacDataRequest = true;
}
if (types & SPINEL_THREAD_FRAME_TYPE_MAC_ACK)
{
seriesFlags.mMacAck = true;
}
error = otLinkMetricsConfigForwardTrackingSeries(mInstance, &address, seriesId, seriesFlags, &linkMetrics,
&NcpBase::HandleLinkMetricsMgmtResponse_Jump, this);
exit:
return error;
}
#endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_MODE>(void)
{
uint8_t numericMode;
@@ -4125,6 +4302,78 @@ void NcpBase::HandleJoinerCallback(otError aError)
}
#endif
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
void NcpBase::HandleLinkMetricsReport_Jump(const otIp6Address * aSource,
const otLinkMetricsValues *aMetricsValues,
uint8_t aStatus,
void * aContext)
{
static_cast<NcpBase *>(aContext)->HandleLinkMetricsReport(aSource, aMetricsValues, aStatus);
}
void NcpBase::HandleLinkMetricsReport(const otIp6Address * aSource,
const otLinkMetricsValues *aMetricsValues,
uint8_t aStatus)
{
SuccessOrExit(mEncoder.BeginFrame(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, SPINEL_CMD_PROP_VALUE_IS,
SPINEL_PROP_THREAD_LINK_METRICS_QUERY_RESULT));
SuccessOrExit(mEncoder.WriteIp6Address(*aSource));
SuccessOrExit(mEncoder.WriteUint8(aStatus));
SuccessOrExit(EncodeLinkMetricsValues(aMetricsValues));
SuccessOrExit(mEncoder.EndFrame());
exit:
return;
}
void NcpBase::HandleLinkMetricsMgmtResponse_Jump(const otIp6Address *aSource, uint8_t aStatus, void *aContext)
{
static_cast<NcpBase *>(aContext)->HandleLinkMetricsMgmtResponse(aSource, aStatus);
}
void NcpBase::HandleLinkMetricsMgmtResponse(const otIp6Address *aSource, uint8_t aStatus)
{
SuccessOrExit(mEncoder.BeginFrame(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, SPINEL_CMD_PROP_VALUE_IS,
SPINEL_PROP_THREAD_LINK_METRICS_MGMT_RESPONSE));
SuccessOrExit(mEncoder.WriteIp6Address(*aSource));
SuccessOrExit(mEncoder.WriteUint8(aStatus));
SuccessOrExit(mEncoder.EndFrame());
exit:
return;
}
void NcpBase::HandleLinkMetricsEnhAckProbingIeReport_Jump(otShortAddress aShortAddress,
const otExtAddress * aExtAddress,
const otLinkMetricsValues *aMetricsValues,
void * aContext)
{
static_cast<NcpBase *>(aContext)->HandleLinkMetricsEnhAckProbingIeReport(aShortAddress, aExtAddress,
aMetricsValues);
}
void NcpBase::HandleLinkMetricsEnhAckProbingIeReport(otShortAddress aShortAddress,
const otExtAddress * aExtAddress,
const otLinkMetricsValues *aMetricsValues)
{
SuccessOrExit(mEncoder.BeginFrame(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, SPINEL_CMD_PROP_VALUE_IS,
SPINEL_PROP_THREAD_LINK_METRICS_MGMT_ENH_ACK_IE));
SuccessOrExit(mEncoder.WriteUint16(aShortAddress));
SuccessOrExit(mEncoder.WriteEui64(*aExtAddress));
SuccessOrExit(EncodeLinkMetricsValues(aMetricsValues));
SuccessOrExit(mEncoder.EndFrame());
exit:
return;
}
#endif
// ----------------------------------------------------------------------------
// MARK: Outbound Datagram Handling
// ----------------------------------------------------------------------------