#5481 [low-power] implement link metrics - single probe

Merged Li Cao Irving-cl
Coverage Reach
src/core/thread/mle_router.cpp src/core/thread/mle.cpp src/core/thread/lowpan.cpp src/core/thread/network_data_leader_ftd.cpp src/core/thread/mesh_forwarder.cpp src/core/thread/network_diagnostic.cpp src/core/thread/address_resolver.cpp src/core/thread/mesh_forwarder_ftd.cpp src/core/thread/network_data.cpp src/core/thread/dua_manager.cpp src/core/thread/mlr_manager.cpp src/core/thread/network_data_leader.cpp src/core/thread/indirect_sender.cpp src/core/thread/router_table.cpp src/core/thread/topology.cpp src/core/thread/network_data_tlvs.hpp src/core/thread/link_metrics.cpp src/core/thread/discover_scanner.cpp src/core/thread/network_data_local.cpp src/core/thread/child_table.cpp src/core/thread/mle_tlvs.hpp src/core/thread/neighbor_table.cpp src/core/thread/network_diagnostic_tlvs.hpp src/core/thread/key_manager.cpp src/core/thread/csl_tx_scheduler.cpp src/core/thread/link_quality.cpp src/core/thread/topology.hpp src/core/thread/energy_scan_server.cpp src/core/thread/mle.hpp src/core/thread/time_sync_service.cpp src/core/thread/thread_netif.cpp src/core/thread/src_match_controller.cpp src/core/thread/network_data_notifier.cpp src/core/thread/network_data.hpp src/core/thread/panid_query_server.cpp src/core/thread/lowpan.hpp src/core/thread/announce_sender.cpp src/core/thread/mle_router.hpp src/core/thread/mle_types.hpp src/core/thread/router_table.hpp src/core/thread/announce_begin_server.cpp src/core/thread/key_manager.hpp src/core/thread/child_table.hpp src/core/thread/address_resolver.hpp src/core/thread/link_quality.hpp src/core/thread/mle_types.cpp src/core/thread/link_metrics_tlvs.hpp src/core/thread/indirect_sender.hpp src/core/thread/csl_tx_scheduler.hpp src/core/thread/mesh_forwarder.hpp src/core/thread/mesh_forwarder_mtd.cpp src/core/thread/thread_tlvs.hpp src/core/thread/tmf.cpp src/core/thread/network_data_leader_ftd.hpp src/core/thread/time_sync_service.hpp src/core/thread/dua_manager.hpp src/core/thread/network_data_leader.hpp src/core/thread/tmf.hpp src/core/thread/thread_netif.hpp src/core/thread/discover_scanner.hpp src/core/thread/mlr_manager.hpp src/core/thread/neighbor_table.hpp src/core/thread/src_match_controller.hpp src/core/meshcop/commissioner.cpp src/core/meshcop/dtls.cpp src/core/meshcop/dataset_manager.cpp src/core/meshcop/border_agent.cpp src/core/meshcop/joiner.cpp src/core/meshcop/dataset.cpp src/core/meshcop/dataset_manager_ftd.cpp src/core/meshcop/meshcop_tlvs.hpp src/core/meshcop/joiner_router.cpp src/core/meshcop/meshcop.cpp src/core/meshcop/meshcop_leader.cpp src/core/meshcop/meshcop_tlvs.cpp src/core/meshcop/dataset_local.cpp src/core/meshcop/energy_scan_client.cpp src/core/meshcop/panid_query_client.cpp src/core/meshcop/announce_begin_client.cpp src/core/meshcop/meshcop.hpp src/core/meshcop/commissioner.hpp src/core/meshcop/timestamp.cpp src/core/meshcop/dataset.hpp src/core/meshcop/timestamp.hpp src/core/meshcop/dataset_manager.hpp src/core/meshcop/border_agent.hpp src/core/meshcop/dtls.hpp src/core/meshcop/dataset_local.hpp src/core/meshcop/meshcop_leader.hpp src/core/meshcop/joiner_router.hpp src/core/meshcop/joiner.hpp src/core/mac/mac.cpp src/core/mac/mac_frame.cpp src/core/mac/sub_mac.cpp src/core/mac/data_poll_sender.cpp src/core/mac/data_poll_handler.cpp src/core/mac/mac_frame.hpp src/core/mac/mac_filter.cpp src/core/mac/link_raw.cpp src/core/mac/mac_types.cpp src/core/mac/mac_types.hpp src/core/mac/channel_mask.cpp src/core/mac/mac.hpp src/core/mac/sub_mac_callbacks.cpp src/core/mac/channel_mask.hpp src/core/mac/sub_mac.hpp src/core/mac/data_poll_handler.hpp src/core/mac/link_raw.hpp src/core/mac/mac_filter.hpp src/core/net/ip6.cpp src/core/net/dhcp6_client.cpp src/core/net/ip6_address.cpp src/core/net/dns_client.cpp src/core/net/dhcp6_server.cpp src/core/net/udp6.cpp src/core/net/netif.cpp src/core/net/sntp_client.cpp src/core/net/ip6_mpl.cpp src/core/net/icmp6.cpp src/core/net/ip6_filter.cpp src/core/net/ip6_headers.hpp src/core/net/dhcp6.hpp src/core/net/netif.hpp src/core/net/checksum.cpp src/core/net/ip6_address.hpp src/core/net/dns_headers.hpp src/core/net/udp6.hpp src/core/net/socket.hpp src/core/net/ip6_mpl.hpp src/core/net/icmp6.hpp src/core/net/sntp_client.hpp src/core/net/ip6_headers.cpp src/core/net/dhcp6_server.hpp src/core/net/ip6.hpp src/core/net/checksum.hpp src/core/net/tcp.hpp src/core/net/dns_client.hpp src/core/net/ip6_filter.hpp src/core/common/message.cpp src/core/common/settings.cpp src/core/common/instance.hpp src/core/common/tlvs.cpp src/core/common/timer.cpp src/core/common/trickle_timer.cpp src/core/common/settings.hpp src/core/common/linked_list.hpp src/core/common/message.hpp src/core/common/encoding.hpp src/core/common/logging.cpp src/core/common/instance.cpp src/core/common/notifier.cpp src/core/common/random_manager.cpp src/core/common/timer.hpp src/core/common/string.hpp src/core/common/time_ticker.cpp src/core/common/tasklet.cpp src/core/common/random.hpp src/core/common/time.hpp src/core/common/notifier.hpp src/core/common/pool.hpp src/core/common/locator.hpp src/core/common/string.cpp src/core/common/bit_vector.hpp src/core/common/tlvs.hpp src/core/common/crc16.cpp src/core/common/tasklet.hpp src/core/common/random_manager.hpp src/core/common/locator-getters.hpp src/core/common/equatable.hpp src/core/common/new.hpp src/core/common/time_ticker.hpp src/core/common/crc16.hpp src/core/common/code_utils.hpp src/core/common/non_copyable.hpp src/core/common/trickle_timer.hpp src/core/common/clearable.hpp src/core/api/thread_api.cpp src/core/api/link_api.cpp src/core/api/thread_ftd_api.cpp src/core/api/link_raw_api.cpp src/core/api/ip6_api.cpp src/core/api/coap_api.cpp src/core/api/message_api.cpp src/core/api/commissioner_api.cpp src/core/api/backbone_router_ftd_api.cpp src/core/api/coap_secure_api.cpp src/core/api/dataset_api.cpp src/core/api/udp_api.cpp src/core/api/border_router_api.cpp src/core/api/netdata_api.cpp src/core/api/channel_manager_api.cpp src/core/api/jam_detection_api.cpp src/core/api/instance_api.cpp src/core/api/network_time_api.cpp src/core/api/server_api.cpp src/core/api/joiner_api.cpp src/core/api/channel_monitor_api.cpp src/core/api/crypto_api.cpp src/core/api/random_noncrypto_api.cpp src/core/api/tasklet_api.cpp src/core/api/netdiag_api.cpp src/core/api/icmp6_api.cpp src/core/api/child_supervision_api.cpp src/core/api/heap_api.cpp src/core/api/dataset_ftd_api.cpp src/core/api/diags_api.cpp src/core/api/logging_api.cpp src/core/api/sntp_api.cpp src/core/api/link_metrics_api.cpp src/core/api/random_crypto_api.cpp src/core/api/backbone_router_api.cpp src/core/api/dns_api.cpp src/core/api/entropy_api.cpp src/core/utils/channel_manager.cpp src/core/utils/slaac_address.cpp src/core/utils/flash.cpp src/core/utils/jam_detector.cpp src/core/utils/heap.cpp src/core/utils/child_supervision.cpp src/core/utils/channel_monitor.cpp src/core/utils/otns.cpp src/core/utils/heap.hpp src/core/utils/flash.hpp src/core/utils/parse_cmdline.cpp src/core/utils/child_supervision.hpp src/core/utils/channel_manager.hpp src/core/utils/jam_detector.hpp src/core/utils/otns.hpp src/core/utils/channel_monitor.hpp src/core/utils/slaac_address.hpp src/core/coap/coap.cpp src/core/coap/coap_message.cpp src/core/coap/coap_secure.cpp src/core/coap/coap_message.hpp src/core/coap/coap_secure.hpp src/core/coap/coap.hpp src/core/backbone_router/bbr_local.cpp src/core/backbone_router/bbr_manager.cpp src/core/backbone_router/bbr_leader.cpp src/core/backbone_router/multicast_listeners_table.cpp src/core/backbone_router/ndproxy_table.cpp src/core/backbone_router/ndproxy_table.hpp src/core/backbone_router/multicast_listeners_table.hpp src/core/backbone_router/backbone_tmf.cpp src/core/backbone_router/bbr_local.hpp src/core/backbone_router/bbr_leader.hpp src/core/backbone_router/bbr_manager.hpp src/core/backbone_router/backbone_tmf.hpp src/core/diags/factory_diags.cpp src/core/diags/factory_diags.hpp src/core/crypto/aes_ccm.cpp src/core/crypto/pbkdf2_cmac.cpp src/core/crypto/mbedtls.cpp src/core/crypto/ecdsa.cpp src/core/crypto/hmac_sha256.cpp src/core/crypto/sha256.cpp src/core/crypto/aes_ecb.cpp src/core/crypto/aes_ccm.hpp src/core/radio/radio_platform.cpp src/core/radio/radio.hpp src/core/radio/radio_callbacks.cpp src/core/radio/radio.cpp src/cli/cli.cpp src/cli/cli_dataset.cpp src/cli/cli_coap.cpp src/cli/cli_coap_secure.cpp src/cli/cli_commissioner.cpp src/cli/cli_udp.cpp src/cli/cli_network_data.cpp src/cli/cli_uart.cpp src/cli/cli_joiner.cpp src/cli/cli_console.cpp src/cli/cli.hpp src/cli/cli_coap.hpp src/cli/cli_dataset.hpp src/cli/cli_joiner.hpp src/cli/cli_commissioner.hpp src/ncp/ncp_base_mtd.cpp src/ncp/ncp_base.cpp src/ncp/ncp_base_ftd.cpp src/ncp/ncp_base_radio.cpp src/ncp/ncp_uart.cpp src/ncp/changed_props_set.cpp src/ncp/ncp_base_dispatcher.cpp src/ncp/changed_props_set.hpp src/ncp/ncp_base.hpp src/lib/spinel/radio_spinel_impl.hpp src/lib/spinel/spinel.c src/lib/spinel/spinel_buffer.cpp src/lib/spinel/spinel_decoder.cpp src/lib/spinel/spinel_encoder.cpp src/lib/spinel/spinel_encoder.hpp src/lib/spinel/spinel_decoder.hpp src/lib/spinel/radio_spinel.hpp src/lib/spinel/spinel_buffer.hpp src/lib/hdlc/hdlc.cpp src/lib/hdlc/hdlc.hpp src/lib/url/url.cpp src/lib/url/url.hpp src/lib/platform/exit_code.c src/posix/platform/netif.cpp src/posix/platform/hdlc_interface.cpp src/posix/platform/settings.cpp src/posix/platform/udp.cpp src/posix/platform/radio.cpp src/posix/platform/uart.cpp src/posix/platform/system.cpp src/posix/platform/virtual_time.cpp src/posix/platform/alarm.cpp src/posix/platform/misc.cpp src/posix/platform/logging.cpp src/posix/platform/entropy.cpp src/posix/platform/max_power_table.hpp src/posix/platform/backbone.cpp src/posix/platform/radio_url.cpp src/posix/platform/hdlc_interface.hpp src/posix/main.c src/posix/client.cpp src/posix/console_cli.cpp tests/unit/test_lowpan.cpp tests/unit/test_spinel_buffer.cpp tests/unit/test_hdlc.cpp tests/unit/test_spinel_decoder.cpp tests/unit/test_timer.cpp tests/unit/test_mac_frame.cpp tests/unit/test_platform.cpp tests/unit/test_link_quality.cpp tests/unit/test_spinel_encoder.cpp tests/unit/test_priority_queue.cpp tests/unit/test_child_table.cpp tests/unit/test_child.cpp tests/unit/test_message_queue.cpp tests/unit/test_linked_list.cpp tests/unit/test_ip6_address.cpp tests/unit/test_netif.cpp tests/unit/test_checksum.cpp tests/unit/test_string.cpp tests/unit/test_multicast_listeners_table.cpp tests/unit/test_flash.cpp tests/unit/test_heap.cpp tests/unit/test_message.cpp tests/unit/test_steering_data.cpp tests/unit/test_aes.cpp tests/unit/test_toolchain.cpp tests/unit/test_network_data.cpp tests/unit/test_pool.cpp tests/unit/test_lowpan.hpp tests/unit/test_ndproxy_table.cpp tests/unit/test_pskc.cpp tests/unit/test_util.cpp tests/unit/test_hmac_sha256.cpp tests/unit/test_toolchain_c.c examples/platforms/simulation/radio.c examples/platforms/simulation/virtual_time/platform-sim.c examples/platforms/simulation/virtual_time/alarm-sim.c examples/platforms/simulation/uart.c examples/platforms/simulation/alarm.c examples/platforms/simulation/system.c examples/platforms/simulation/flash.c examples/platforms/simulation/misc.c examples/platforms/simulation/diag.c examples/platforms/simulation/entropy.c examples/platforms/utils/soft_source_match_table.c examples/platforms/utils/mac_frame.cpp examples/platforms/utils/logging_rtt.c examples/platforms/utils/debug_uart.c examples/platforms/utils/otns_utils.cpp examples/apps/cli/main.c examples/apps/ncp/main.c tools/spi-hdlc-adapter/spi-hdlc-adapter.c include/openthread/coap.h

No flags found

Use flags to group coverage reports by test type, project and/or folders.
Then setup custom commit statuses and notifications for each flag.

e.g., #unittest #integration

#production #enterprise

#frontend #backend

Learn more about Codecov Flags here.

Showing 18 of 36 files from the diff.

@@ -75,6 +75,9 @@
Loading
75 75
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
76 76
#include <openthread/backbone_router_ftd.h>
77 77
#endif
78 +
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
79 +
#include <openthread/link_metrics.h>
80 +
#endif
78 81
#endif
79 82
80 83
#include "cli_dataset.hpp"
@@ -1899,6 +1902,109 @@
Loading
1899 1902
}
1900 1903
#endif // OPENTHREAD_FTD
1901 1904
1905 +
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
1906 +
void Interpreter::HandleLinkMetricsReport(const otIp6Address *       aAddress,
1907 +
                                          const otLinkMetricsValues *aMetricsValues,
1908 +
                                          void *                     aContext)
1909 +
{
1910 +
    static_cast<Interpreter *>(aContext)->HandleLinkMetricsReport(aAddress, aMetricsValues);
1911 +
}
1912 +
1913 +
void Interpreter::HandleLinkMetricsReport(const otIp6Address *aAddress, const otLinkMetricsValues *aMetricsValues)
1914 +
{
1915 +
    const char kLinkMetricsTypeCount[]   = "(Count/Summation)";
1916 +
    const char kLinkMetricsTypeAverage[] = "(Exponential Moving Average)";
1917 +
1918 +
    OutputFormat("Received Link Metrics Report from: ");
1919 +
    OutputIp6Address(*aAddress);
1920 +
    OutputLine("");
1921 +
1922 +
    if (aMetricsValues->mMetrics.mPduCount)
1923 +
    {
1924 +
        OutputLine(" - PDU Counter: %d %s", aMetricsValues->mPduCountValue, kLinkMetricsTypeCount);
1925 +
    }
1926 +
1927 +
    if (aMetricsValues->mMetrics.mLqi)
1928 +
    {
1929 +
        OutputLine(" - LQI: %d %s", aMetricsValues->mLqiValue, kLinkMetricsTypeAverage);
1930 +
    }
1931 +
1932 +
    if (aMetricsValues->mMetrics.mLinkMargin)
1933 +
    {
1934 +
        OutputLine(" - Margin: %d (dB) %s", aMetricsValues->mLinkMarginValue, kLinkMetricsTypeAverage);
1935 +
    }
1936 +
1937 +
    if (aMetricsValues->mMetrics.mRssi)
1938 +
    {
1939 +
        OutputLine(" - RSSI: %d (dBm) %s", aMetricsValues->mRssiValue, kLinkMetricsTypeAverage);
1940 +
    }
1941 +
}
1942 +
1943 +
otError Interpreter::ProcessLinkMetrics(uint8_t aArgsLength, char *aArgs[])
1944 +
{
1945 +
    otError error = OT_ERROR_INVALID_COMMAND;
1946 +
1947 +
    VerifyOrExit(aArgsLength >= 1, OT_NOOP);
1948 +
1949 +
    if (strcmp(aArgs[0], "query") == 0)
1950 +
    {
1951 +
        error = ProcessLinkMetricsQuery(aArgsLength - 1, aArgs + 1);
1952 +
    }
1953 +
1954 +
exit:
1955 +
    return error;
1956 +
}
1957 +
1958 +
otError Interpreter::ProcessLinkMetricsQuery(uint8_t aArgsLength, char *aArgs[])
1959 +
{
1960 +
    otError       error = OT_ERROR_INVALID_ARGS;
1961 +
    otIp6Address  address;
1962 +
    otLinkMetrics linkMetrics;
1963 +
    long          seriesId = 0;
1964 +
1965 +
    VerifyOrExit(aArgsLength >= 2, OT_NOOP);
1966 +
1967 +
    SuccessOrExit(error = otIp6AddressFromString(aArgs[0], &address));
1968 +
1969 +
    memset(&linkMetrics, 0, sizeof(otLinkMetrics));
1970 +
1971 +
    if (strcmp(aArgs[1], "single") == 0)
1972 +
    {
1973 +
        VerifyOrExit(aArgsLength == 3, OT_NOOP);
1974 +
        for (char *arg = aArgs[2]; *arg != '\0'; arg++)
1975 +
        {
1976 +
            switch (*arg)
1977 +
            {
1978 +
            case 'p':
1979 +
                linkMetrics.mPduCount = 1;
1980 +
                break;
1981 +
1982 +
            case 'q':
1983 +
                linkMetrics.mLqi = 1;
1984 +
                break;
1985 +
1986 +
            case 'm':
1987 +
                linkMetrics.mLinkMargin = 1;
1988 +
                break;
1989 +
1990 +
            case 'r':
1991 +
                linkMetrics.mRssi = 1;
1992 +
                break;
1993 +
1994 +
            default:
1995 +
                ExitNow(error = OT_ERROR_INVALID_ARGS);
1996 +
            }
1997 +
        }
1998 +
        error = otLinkMetricsQuery(mInstance, &address, static_cast<uint8_t>(seriesId), &linkMetrics,
1999 +
                                   &Interpreter::HandleLinkMetricsReport, this);
2000 +
    }
2001 +
2002 +
exit:
2003 +
    return error;
2004 +
}
2005 +
2006 +
#endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
2007 +
1902 2008
#if OPENTHREAD_FTD
1903 2009
otError Interpreter::ProcessPskc(uint8_t aArgsLength, char *aArgs[])
1904 2010
{

@@ -0,0 +1,385 @@
Loading
1 +
/*
2 +
 *  Copyright (c) 2020, The OpenThread Authors.
3 +
 *  All rights reserved.
4 +
 *
5 +
 *  Redistribution and use in source and binary forms, with or without
6 +
 *  modification, are permitted provided that the following conditions are met:
7 +
 *  1. Redistributions of source code must retain the above copyright
8 +
 *     notice, this list of conditions and the following disclaimer.
9 +
 *  2. Redistributions in binary form must reproduce the above copyright
10 +
 *     notice, this list of conditions and the following disclaimer in the
11 +
 *     documentation and/or other materials provided with the distribution.
12 +
 *  3. Neither the name of the copyright holder nor the
13 +
 *     names of its contributors may be used to endorse or promote products
14 +
 *     derived from this software without specific prior written permission.
15 +
 *
16 +
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 +
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 +
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 +
 *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 +
 *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 +
 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 +
 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 +
 *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 +
 *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 +
 *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 +
 *  POSSIBILITY OF SUCH DAMAGE.
27 +
 */
28 +
29 +
/**
30 +
 * @file
31 +
 *   This file includes definitions for Thread Link Metrics.
32 +
 */
33 +
34 +
#include "link_metrics.hpp"
35 +
36 +
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
37 +
38 +
#include "common/code_utils.hpp"
39 +
#include "common/instance.hpp"
40 +
#include "common/locator-getters.hpp"
41 +
#include "common/logging.hpp"
42 +
43 +
#include "link_metrics_tlvs.hpp"
44 +
45 +
namespace ot {
46 +
47 +
LinkMetrics::LinkMetrics(Instance &aInstance)
48 +
    : InstanceLocator(aInstance)
49 +
    , mLinkMetricsReportCallback(nullptr)
50 +
    , mLinkMetricsReportCallbackContext(nullptr)
51 +
{
52 +
}
53 +
54 +
otError LinkMetrics::LinkMetricsQuery(const Ip6::Address & aDestination,
55 +
                                      uint8_t              aSeriesId,
56 +
                                      const otLinkMetrics &aLinkMetricsFlags)
57 +
{
58 +
    otError                error;
59 +
    LinkMetricsTypeIdFlags typeIdFlags[kMaxTypeIdFlags];
60 +
    uint8_t                typeIdFlagsCount = TypeIdFlagsFromLinkMetricsFlags(typeIdFlags, aLinkMetricsFlags);
61 +
62 +
    error = SendLinkMetricsQuery(aDestination, aSeriesId, typeIdFlags, typeIdFlagsCount);
63 +
64 +
    return error;
65 +
}
66 +
67 +
otError LinkMetrics::AppendLinkMetricsReport(Message &aMessage, const Message &aRequestMessage)
68 +
{
69 +
    otError       error = OT_ERROR_NONE;
70 +
    Tlv           tlv;
71 +
    uint8_t       queryId;
72 +
    bool          hasQueryId  = false;
73 +
    uint8_t       length      = 0;
74 +
    uint16_t      startOffset = aMessage.GetLength();
75 +
    uint16_t      offset;
76 +
    uint16_t      endOffset;
77 +
    otLinkMetrics linkMetrics;
78 +
79 +
    memset(&linkMetrics, 0, sizeof(linkMetrics));
80 +
81 +
    SuccessOrExit(error = Tlv::FindTlvValueOffset(aRequestMessage, Mle::Tlv::Type::kLinkMetricsQuery, offset,
82 +
                                                  endOffset)); // `endOffset` is used to store tlv length here
83 +
84 +
    endOffset = offset + endOffset;
85 +
86 +
    while (offset < endOffset)
87 +
    {
88 +
        VerifyOrExit(aRequestMessage.Read(offset, sizeof(tlv), &tlv) == sizeof(tlv), error = OT_ERROR_PARSE);
89 +
90 +
        switch (tlv.GetType())
91 +
        {
92 +
        case kLinkMetricsQueryId:
93 +
            SuccessOrExit(error = Tlv::ReadUint8Tlv(aRequestMessage, offset, queryId));
94 +
            hasQueryId = true;
95 +
            break;
96 +
97 +
        case kLinkMetricsQueryOptions:
98 +
            for (uint16_t index = offset + sizeof(tlv), endIndex = static_cast<uint16_t>(offset + tlv.GetSize());
99 +
                 index < endIndex; index += sizeof(LinkMetricsTypeIdFlags))
100 +
            {
101 +
                LinkMetricsTypeIdFlags typeIdFlags;
102 +
103 +
                VerifyOrExit(aRequestMessage.Read(index, sizeof(typeIdFlags), &typeIdFlags) == sizeof(typeIdFlags),
104 +
                             error = OT_ERROR_PARSE);
105 +
106 +
                switch (typeIdFlags.GetRawValue())
107 +
                {
108 +
                case kTypeIdFlagPdu:
109 +
                    VerifyOrExit(!linkMetrics.mPduCount, error = OT_ERROR_PARSE);
110 +
                    linkMetrics.mPduCount = true;
111 +
                    break;
112 +
113 +
                case kTypeIdFlagLqi:
114 +
                    VerifyOrExit(!linkMetrics.mLqi, error = OT_ERROR_PARSE);
115 +
                    linkMetrics.mLqi = true;
116 +
                    break;
117 +
118 +
                case kTypeIdFlagLinkMargin:
119 +
                    VerifyOrExit(!linkMetrics.mLinkMargin, error = OT_ERROR_PARSE);
120 +
                    linkMetrics.mLinkMargin = true;
121 +
                    break;
122 +
123 +
                case kTypeIdFlagRssi:
124 +
                    VerifyOrExit(!linkMetrics.mRssi, error = OT_ERROR_PARSE);
125 +
                    linkMetrics.mRssi = true;
126 +
                    break;
127 +
128 +
                default:
129 +
                    if (typeIdFlags.IsExtendedFlagSet())
130 +
                    {
131 +
                        index += sizeof(uint8_t); // Skip the additional second flags byte.
132 +
                    }
133 +
                    break;
134 +
                }
135 +
            }
136 +
            break;
137 +
138 +
        default:
139 +
            break;
140 +
        }
141 +
142 +
        offset += tlv.GetSize();
143 +
    }
144 +
145 +
    VerifyOrExit(hasQueryId, error = OT_ERROR_PARSE);
146 +
147 +
    // Link Metrics Report TLV
148 +
    tlv.SetType(Mle::Tlv::kLinkMetricsReport);
149 +
    SuccessOrExit(error = aMessage.Append(&tlv, sizeof(tlv)));
150 +
151 +
    if (queryId == 0)
152 +
    {
153 +
        SuccessOrExit(error = AppendSingleProbeLinkMetricsReport(aMessage, length, linkMetrics, aRequestMessage));
154 +
    }
155 +
    else
156 +
    {
157 +
        ExitNow(error = OT_ERROR_NOT_IMPLEMENTED);
158 +
    }
159 +
160 +
    tlv.SetLength(length);
161 +
    aMessage.Write(startOffset, sizeof(tlv), &tlv);
162 +
163 +
exit:
164 +
    otLogDebgMle("AppendLinkMetricsReport, error:%s", otThreadErrorToString(error));
165 +
    return error;
166 +
}
167 +
168 +
void LinkMetrics::HandleLinkMetricsReport(const Message &     aMessage,
169 +
                                          uint16_t            aOffset,
170 +
                                          uint16_t            aLength,
171 +
                                          const Ip6::Address &aAddress)
172 +
{
173 +
    otLinkMetricsValues    metricsValues;
174 +
    uint8_t                metricsRawValue;
175 +
    uint16_t               pos    = aOffset;
176 +
    uint16_t               endPos = aOffset + aLength;
177 +
    Tlv                    tlv;
178 +
    LinkMetricsTypeIdFlags typeIdFlags;
179 +
180 +
    VerifyOrExit(mLinkMetricsReportCallback != nullptr, OT_NOOP);
181 +
182 +
    memset(&metricsValues, 0, sizeof(metricsValues));
183 +
184 +
    otLogDebgMle("Received Link Metrics Report");
185 +
186 +
    while (pos < endPos)
187 +
    {
188 +
        VerifyOrExit(aMessage.Read(pos, sizeof(Tlv), &tlv) == sizeof(Tlv), OT_NOOP);
189 +
        VerifyOrExit(tlv.GetType() == kLinkMetricsReportSub, OT_NOOP);
190 +
        pos += sizeof(Tlv);
191 +
        VerifyOrExit(pos + tlv.GetLength() <= endPos, OT_NOOP);
192 +
193 +
        aMessage.Read(pos, sizeof(LinkMetricsTypeIdFlags), &typeIdFlags);
194 +
        if (typeIdFlags.IsExtendedFlagSet())
195 +
        {
196 +
            pos += tlv.GetLength(); // Skip the whole sub-TLV if `E` flag is set
197 +
            continue;
198 +
        }
199 +
        pos += sizeof(LinkMetricsTypeIdFlags);
200 +
201 +
        switch (typeIdFlags.GetRawValue())
202 +
        {
203 +
        case kTypeIdFlagPdu:
204 +
            metricsValues.mMetrics.mPduCount = true;
205 +
            aMessage.Read(pos, sizeof(uint32_t), &metricsValues.mPduCountValue);
206 +
            pos += sizeof(uint32_t);
207 +
            otLogDebgMle(" - PDU Counter: %d (Count/Summation)", metricsValues.mPduCountValue);
208 +
            break;
209 +
210 +
        case kTypeIdFlagLqi:
211 +
            metricsValues.mMetrics.mLqi = true;
212 +
            aMessage.Read(pos, sizeof(uint8_t), &metricsValues.mLqiValue);
213 +
            pos += sizeof(uint8_t);
214 +
            otLogDebgMle(" - LQI: %d (Exponential Moving Average)", metricsValues.mLqiValue);
215 +
            break;
216 +
217 +
        case kTypeIdFlagLinkMargin:
218 +
            metricsValues.mMetrics.mLinkMargin = true;
219 +
            aMessage.Read(pos, sizeof(uint8_t), &metricsRawValue);
220 +
            metricsValues.mLinkMarginValue =
221 +
                metricsRawValue * 130 / 255; // Reverse operation for linear scale, map from [0, 255] to [0, 130]
222 +
            pos += sizeof(uint8_t);
223 +
            otLogDebgMle(" - Margin: %d (dB) (Exponential Moving Average)", metricsValues.mLinkMarginValue);
224 +
            break;
225 +
226 +
        case kTypeIdFlagRssi:
227 +
            metricsValues.mMetrics.mRssi = true;
228 +
            aMessage.Read(pos, sizeof(uint8_t), &metricsRawValue);
229 +
            metricsValues.mRssiValue =
230 +
                metricsRawValue * 130 / 255 - 130; // Reverse operation for linear scale, map from [0, 255] to [-130, 0]
231 +
            pos += sizeof(uint8_t);
232 +
            otLogDebgMle(" - RSSI: %d (dBm) (Exponential Moving Average)", metricsValues.mRssiValue);
233 +
            break;
234 +
235 +
        default:
236 +
            break;
237 +
        }
238 +
    }
239 +
240 +
    mLinkMetricsReportCallback(&aAddress, &metricsValues, mLinkMetricsReportCallbackContext);
241 +
242 +
exit:
243 +
    return;
244 +
}
245 +
246 +
void LinkMetrics::SetLinkMetricsReportCallback(otLinkMetricsReportCallback aCallback, void *aCallbackContext)
247 +
{
248 +
    mLinkMetricsReportCallback        = aCallback;
249 +
    mLinkMetricsReportCallbackContext = aCallbackContext;
250 +
}
251 +
252 +
otError LinkMetrics::SendLinkMetricsQuery(const Ip6::Address &          aDestination,
253 +
                                          uint8_t                       aSeriesId,
254 +
                                          const LinkMetricsTypeIdFlags *aTypeIdFlags,
255 +
                                          uint8_t                       aTypeIdFlagsCount)
256 +
{
257 +
    otError                    error = OT_ERROR_NONE;
258 +
    LinkMetricsQueryOptionsTlv linkMetricsQueryOptionsTlv;
259 +
    uint8_t                    length = 0;
260 +
    static const uint8_t       tlvs[] = {Mle::Tlv::kLinkMetricsReport};
261 +
    uint8_t                    buf[sizeof(Tlv) * 3 + sizeof(uint8_t) +
262 +
                sizeof(LinkMetricsTypeIdFlags) *
263 +
                    kMaxTypeIdFlags]; // LinkMetricsQuery Tlv + LinkMetricsQueryId sub-TLV (value-length: 1 byte) +
264 +
                                      // LinkMetricsQueryOptions sub-TLV (value-length: `kMaxTypeIdFlags` bytes)
265 +
    Tlv *tlv = reinterpret_cast<Tlv *>(buf);
266 +
    Tlv  subTlv;
267 +
268 +
    // Link Metrics Query TLV
269 +
    tlv->SetType(Mle::Tlv::kLinkMetricsQuery);
270 +
    length += sizeof(Tlv);
271 +
272 +
    // Link Metrics Query ID sub-TLV
273 +
    subTlv.SetType(kLinkMetricsQueryId);
274 +
    subTlv.SetLength(sizeof(uint8_t));
275 +
    memcpy(buf + length, &subTlv, sizeof(subTlv));
276 +
    length += sizeof(subTlv);
277 +
    memcpy(buf + length, &aSeriesId, sizeof(aSeriesId));
278 +
    length += sizeof(aSeriesId);
279 +
280 +
    // Link Metrics Query Options sub-TLV
281 +
    if (aTypeIdFlagsCount > 0)
282 +
    {
283 +
        linkMetricsQueryOptionsTlv.Init();
284 +
        linkMetricsQueryOptionsTlv.SetLength(aTypeIdFlagsCount * sizeof(LinkMetricsTypeIdFlags));
285 +
286 +
        memcpy(buf + length, &linkMetricsQueryOptionsTlv, sizeof(linkMetricsQueryOptionsTlv));
287 +
        length += sizeof(linkMetricsQueryOptionsTlv);
288 +
        memcpy(buf + length, aTypeIdFlags, linkMetricsQueryOptionsTlv.GetLength());
289 +
        length += linkMetricsQueryOptionsTlv.GetLength();
290 +
    }
291 +
292 +
    // Set Length for Link Metrics Report TLV
293 +
    tlv->SetLength(length - sizeof(Tlv));
294 +
295 +
    SuccessOrExit(error = Get<Mle::MleRouter>().SendDataRequest(aDestination, tlvs, sizeof(tlvs), 0, buf, length));
296 +
297 +
exit:
298 +
    return error;
299 +
}
300 +
301 +
otError LinkMetrics::AppendSingleProbeLinkMetricsReport(Message &            aMessage,
302 +
                                                        uint8_t &            aLength,
303 +
                                                        const otLinkMetrics &aLinkMetrics,
304 +
                                                        const Message &      aRequestMessage)
305 +
{
306 +
    otError                 error = OT_ERROR_NONE;
307 +
    LinkMetricsReportSubTlv metric;
308 +
309 +
    aLength = 0;
310 +
311 +
    // Link Metrics Report sub-TLVs
312 +
    if (aLinkMetrics.mPduCount)
313 +
    {
314 +
        metric.Init();
315 +
        metric.SetMetricsTypeId(kTypeIdFlagPdu);
316 +
        metric.SetMetricsValue32(aRequestMessage.GetPsduCount());
317 +
        SuccessOrExit(error = aMessage.Append(&metric, metric.GetSize()));
318 +
        aLength += metric.GetSize();
319 +
    }
320 +
321 +
    if (aLinkMetrics.mLqi)
322 +
    {
323 +
        metric.Init();
324 +
        metric.SetMetricsTypeId(kTypeIdFlagLqi);
325 +
        metric.SetMetricsValue8(aRequestMessage.GetAverageLqi()); // IEEE 802.15.4 LQI is in scale 0-255
326 +
        SuccessOrExit(error = aMessage.Append(&metric, metric.GetSize()));
327 +
        aLength += metric.GetSize();
328 +
    }
329 +
330 +
    if (aLinkMetrics.mLinkMargin)
331 +
    {
332 +
        metric.Init();
333 +
        metric.SetMetricsTypeId(kTypeIdFlagLinkMargin);
334 +
        metric.SetMetricsValue8(
335 +
            LinkQualityInfo::ConvertRssToLinkMargin(Get<Mac::Mac>().GetNoiseFloor(), aRequestMessage.GetAverageRss()) *
336 +
            255 / 130); // Linear scale Link Margin from [0, 130] to [0, 255]
337 +
        SuccessOrExit(error = aMessage.Append(&metric, metric.GetSize()));
338 +
        aLength += metric.GetSize();
339 +
    }
340 +
341 +
    if (aLinkMetrics.mRssi)
342 +
    {
343 +
        metric.Init();
344 +
        metric.SetMetricsTypeId(kTypeIdFlagRssi);
345 +
        metric.SetMetricsValue8((aRequestMessage.GetAverageRss() + 130) * 255 /
346 +
                                130); // Linear scale rss from [-130, 0] to [0, 255]
347 +
        SuccessOrExit(error = aMessage.Append(&metric, metric.GetSize()));
348 +
        aLength += metric.GetSize();
349 +
    }
350 +
351 +
exit:
352 +
    return error;
353 +
}
354 +
355 +
uint8_t LinkMetrics::TypeIdFlagsFromLinkMetricsFlags(LinkMetricsTypeIdFlags *aTypeIdFlags,
356 +
                                                     const otLinkMetrics &   aLinkMetricsFlags)
357 +
{
358 +
    uint8_t count = 0;
359 +
360 +
    if (aLinkMetricsFlags.mPduCount)
361 +
    {
362 +
        aTypeIdFlags[count++].SetRawValue(kTypeIdFlagPdu);
363 +
    }
364 +
365 +
    if (aLinkMetricsFlags.mLqi)
366 +
    {
367 +
        aTypeIdFlags[count++].SetRawValue(kTypeIdFlagLqi);
368 +
    }
369 +
370 +
    if (aLinkMetricsFlags.mLinkMargin)
371 +
    {
372 +
        aTypeIdFlags[count++].SetRawValue(kTypeIdFlagLinkMargin);
373 +
    }
374 +
375 +
    if (aLinkMetricsFlags.mRssi)
376 +
    {
377 +
        aTypeIdFlags[count++].SetRawValue(kTypeIdFlagRssi);
378 +
    }
379 +
380 +
    return count;
381 +
}
382 +
383 +
} // namespace ot
384 +
385 +
#endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE

@@ -41,6 +41,7 @@
Loading
41 41
#include "common/tlvs.hpp"
42 42
#include "meshcop/timestamp.hpp"
43 43
#include "net/ip6_address.hpp"
44 +
#include "thread/link_metrics_tlvs.hpp"
44 45
#include "thread/mle_types.hpp"
45 46
46 47
namespace ot {
@@ -103,6 +104,8 @@
Loading
103 104
        kDiscovery           = 26, ///< Thread Discovery TLV
104 105
        kCslChannel          = 80, ///< CSL Channel TLV
105 106
        kCslTimeout          = 85, ///< CSL Timeout TLV
107 +
        kLinkMetricsQuery    = 87, ///< Link Metrics Query TLV
108 +
        kLinkMetricsReport   = 89, ///< Link Metrics Report TLV
106 109
107 110
        /**
108 111
         * Applicable/Required only when time synchronization service

@@ -84,6 +84,7 @@
Loading
84 84
#include "thread/discover_scanner.hpp"
85 85
#include "thread/energy_scan_server.hpp"
86 86
#include "thread/key_manager.hpp"
87 +
#include "thread/link_metrics.hpp"
87 88
#include "thread/mesh_forwarder.hpp"
88 89
#include "thread/mle.hpp"
89 90
#include "thread/mle_router.hpp"
@@ -266,6 +267,9 @@
Loading
266 267
#if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
267 268
    TimeSync mTimeSync;
268 269
#endif
270 +
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_ENABLE
271 +
    LinkMetrics mLinkMetrics;
272 +
#endif
269 273
};
270 274
271 275
/**

@@ -211,6 +211,55 @@
Loading
211 211
    uint16_t mCount : 5;    // Number of RSS values added to averager so far (limited to 2^kCoeffBitShift-1).
212 212
};
213 213
214 +
/**
215 +
 * This class implements a Link Quality Indicator (LQI) averager.
216 +
 *
217 +
 * It maintains the exponential moving average value of LQI.
218 +
 *
219 +
 */
220 +
class LqiAverager
221 +
{
222 +
public:
223 +
    /**
224 +
     * This method resets the averager and clears the average value.
225 +
     *
226 +
     */
227 +
    void Reset(void);
228 +
229 +
    /**
230 +
     * This method adds a link quality indicator (LQI) value to the average.
231 +
     *
232 +
     * @param[in] aLqi  Link Quality Indicator value to be added to the average.
233 +
     *
234 +
     */
235 +
    void Add(uint8_t aLqi);
236 +
237 +
    /**
238 +
     * This method returns the current average link quality value maintained by the averager.
239 +
     *
240 +
     * @returns The current average value.
241 +
     *
242 +
     */
243 +
    uint8_t GetAverage(void) const { return mAverage; }
244 +
245 +
    /**
246 +
     * This method returns the count of frames calculated so far.
247 +
     *
248 +
     * @returns The count of frames calculated.
249 +
     *
250 +
     */
251 +
    uint8_t GetCount(void) const { return mCount; }
252 +
253 +
private:
254 +
    enum
255 +
    {
256 +
        kCoeffBitShift = 3, ///< Coefficient used for exponentially weighted filter (1 << kCoeffBitShift).
257 +
    };
258 +
259 +
    uint8_t mAverage; ///< The average link quality indicator value.
260 +
    uint8_t mCount;   ///< Number of LQI values added to averager so far.
261 +
};
262 +
214 263
/**
215 264
 * This class encapsulates/stores all relevant information about quality of a link, including average received signal
216 265
 * strength (RSS), last RSS, link margin, and link quality.

Click to load this diff.
Loading diff...

Click to load this diff.
Loading diff...

Click to load this diff.
Loading diff...

Click to load this diff.
Loading diff...

Click to load this diff.
Loading diff...

Click to load this diff.
Loading diff...

Click to load this diff.
Loading diff...

Click to load this diff.
Loading diff...

Click to load this diff.
Loading diff...

Click to load this diff.
Loading diff...

Click to load this diff.
Loading diff...

Click to load this diff.
Loading diff...

Click to load this diff.
Loading diff...

Learn more Showing 21 files with coverage changes found.

Changes in src/posix/main.c
-3
+3
Loading file...
Changes in src/core/meshcop/meshcop_leader.cpp
-3
+3
Loading file...
Changes in src/posix/platform/alarm.cpp
-1
+1
Loading file...
Changes in src/lib/spinel/radio_spinel_impl.hpp
-11
+11
Loading file...
Changes in src/core/thread/network_data_local.cpp
-1
+1
Loading file...
Changes in examples/platforms/simulation/radio.c
-1
+1
Loading file...
Changes in src/ncp/ncp_base_mtd.cpp
-1
+1
Loading file...
Changes in src/core/thread/thread_netif.cpp
-2
Loading file...
Changes in tests/unit/test_ndproxy_table.cpp
-1
Loading file...
New file src/core/thread/link_metrics.cpp
New
Loading file...
New file src/core/thread/link_metrics_tlvs.hpp
New
Loading file...
New file src/core/api/link_metrics_api.cpp
New
Loading file...
Changes in src/core/thread/mle_router.cpp
-3
+2
Loading file...
Changes in src/core/thread/mle.cpp
-4
+4
Loading file...
Changes in src/core/thread/mesh_forwarder.hpp
+1
Loading file...
Changes in src/core/thread/router_table.cpp
-2
+2
Loading file...
Changes in src/core/thread/mesh_forwarder.cpp
-5
+5
Loading file...
Changes in src/core/thread/time_sync_service.cpp
-1
+1
Loading file...
Changes in src/core/common/message.hpp
-1
+1
Loading file...
Changes in src/core/thread/indirect_sender.cpp
-5
+5
Loading file...
Changes in src/core/mac/data_poll_handler.cpp
-7
+7
Loading file...

23 Commits

+3 Files
+68
+197
-129
-2 Files
+147
+109
+38
-3
-60
+57
+3 Files
+20
+244
-224
-3 Files
-72
-284
+212
-99
-26
-73
-2
+11
-13
Hiding 1 contexual commits
+23
-23
Hiding 13 contexual commits
+2 Files
+223
+58
+165
Pull Request Base Commit
Files Coverage
examples -0.08% 80.67%
src 0.08% 85.71%
tests/unit -<.01% 90.22%
include/openthread/coap.h 100.00%
tools/spi-hdlc-adapter/spi-hdlc-adapter.c 0.00%
Project Totals (371 files) 84.75%
Loading