mirror of
https://github.com/espressif/openthread.git
synced 2026-08-09 12:17:47 +00:00
[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:
@@ -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"},
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user