[mle] add otDeviceProperties to calculate local leader weight (#8670)

This commit adds `otDeviceProperties` which represents a set of device
properties which are used to calculate and set the local Leader
Weight on the device.

The device property set contains a `otPowerSupplyConfig` enum value
specifying the device power supply:
- Battery powered.
- Externally powered (mains-powered).
- Stable external power with a battery backup or UPS.
- Unstable external power (e.g., a light bulb powered via a switch).

It also indicates whether or not device is a border router, supports
CCM, and specifies a Leader Weight adjustment value.

The `otDeviceProperties` can be set through the newly added OT public API
`otThreadSetDeviceProperties()`. Its default value (upon OT stack start)
can also be configured using OT configs:
- Newly added `OPENTHREAD_CONFIG_DEVICE_POWER_SUPPLY` specifies the
  default power supply config to use. This config can also be set
  using the newly added CMake option `OT_POWER_SUPPLY`.
- Existing `OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE` will indicate
  if device is acting as a BR.

This commit also adds CLI command `deviceprops` for getting/setting
the device config. It also adds a unit test to validate the Leader
Weight calculation algorithm from a given device config.
This commit is contained in:
Abtin Keshavarzian
2023-03-21 22:51:49 -07:00
committed by GitHub
parent 07d69f30ce
commit b8335e0772
14 changed files with 631 additions and 3 deletions
+17
View File
@@ -157,6 +157,23 @@ if(OT_FULL_LOGS)
target_compile_definitions(ot-config INTERFACE "OPENTHREAD_CONFIG_LOG_PREPEND_LEVEL=1")
endif()
set(OT_POWER_SUPPLY "" CACHE STRING "set the device power supply config")
set(OT_POWER_SUPPLY_VALUES
""
"BATTERY"
"EXTERNAL"
"EXTERNAL_STABLE"
"EXTERNAL_UNSTABLE"
)
set_property(CACHE OT_POWER_SUPPLY PROPERTY STRINGS ${OT_POWER_SUPPLY_VALUES})
string(COMPARE EQUAL "${OT_POWER_SUPPLY}" "" is_empty)
if (is_empty)
message(STATUS "OT_POWER_SUPPLY=\"\"")
else()
message(STATUS "OT_POWER_SUPPLY=${OT_POWER_SUPPLY} --> OPENTHREAD_CONFIG_DEVICE_POWER_SUPPLY=OT_POWER_SUPPLY_${OT_POWER_SUPPLY}")
target_compile_definitions(ot-config INTERFACE "OPENTHREAD_CONFIG_DEVICE_POWER_SUPPLY=OT_POWER_SUPPLY_${OT_POWER_SUPPLY}")
endif()
set(OT_MLE_MAX_CHILDREN "" CACHE STRING "set maximum number of children")
if(OT_MLE_MAX_CHILDREN MATCHES "^[0-9]+$")
message(STATUS "OT_MLE_MAX_CHILDREN=${OT_MLE_MAX_CHILDREN}")
+1 -1
View File
@@ -53,7 +53,7 @@ extern "C" {
* @note This number versions both OpenThread platform and user APIs.
*
*/
#define OPENTHREAD_API_VERSION (302)
#define OPENTHREAD_API_VERSION (303)
/**
* @addtogroup api-instance
+57
View File
@@ -196,6 +196,59 @@ otError otThreadSetRouterEligible(otInstance *aInstance, bool aEligible);
*/
otError otThreadSetPreferredRouterId(otInstance *aInstance, uint8_t aRouterId);
/**
* This enumeration represents the power supply property on a device.
*
* This is used as a property in `otDeviceProperties` to calculate the leader weight.
*
*/
typedef enum
{
OT_POWER_SUPPLY_BATTERY = 0, ///< Battery powered.
OT_POWER_SUPPLY_EXTERNAL = 1, ///< Externally powered (mains-powered).
OT_POWER_SUPPLY_EXTERNAL_STABLE = 2, ///< Stable external power with a battery backup or UPS.
OT_POWER_SUPPLY_EXTERNAL_UNSTABLE = 3, ///< Potentially unstable ext power (e.g. light bulb powered via a switch).
} otPowerSupply;
/**
* This structure represents the device properties which are used for calculating the local leader weight on a
* device.
*
* The parameters are set based on device's capability, whether acting as border router, its power supply config, etc.
*
* `mIsUnstable` indicates operational stability of device and is determined via a vendor specific mechanism. It can
* include the following cases:
* - Device internally detects that it loses external power supply more often than usual. What is usual is
* determined by the vendor.
* - Device internally detects that it reboots more often than usual. What is usual is determined by the vendor.
*
*/
typedef struct otDeviceProperties
{
otPowerSupply mPowerSupply; ///< Power supply config.
bool mIsBorderRouter : 1; ///< Whether device is a border router.
bool mSupportsCcm : 1; ///< Whether device supports CCM (can act as a CCM border router).
bool mIsUnstable : 1; ///< Operational stability of device (vendor specific).
int8_t mLeaderWeightAdjustment; ///< Weight adjustment. Should be -16 to +16 (clamped otherwise).
} otDeviceProperties;
/**
* Get the current device properties.
*
* @returns The device properties `otDeviceProperties`.
*
*/
const otDeviceProperties *otThreadGetDeviceProperties(otInstance *aInstance);
/**
* Set the device properties which are then used to determine and set the Leader Weight.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aDeviceProperties The device properties.
*
*/
void otThreadSetDeviceProperties(otInstance *aInstance, const otDeviceProperties *aDeviceProperties);
/**
* Gets the Thread Leader Weight used when operating in the Leader role.
*
@@ -204,6 +257,7 @@ otError otThreadSetPreferredRouterId(otInstance *aInstance, uint8_t aRouterId);
* @returns The Thread Leader Weight value.
*
* @sa otThreadSetLeaderWeight
* @sa otThreadSetDeviceProperties
*
*/
uint8_t otThreadGetLocalLeaderWeight(otInstance *aInstance);
@@ -211,6 +265,9 @@ uint8_t otThreadGetLocalLeaderWeight(otInstance *aInstance);
/**
* Sets the Thread Leader Weight used when operating in the Leader role.
*
* This function directly sets the Leader Weight to the new value, replacing its previous value (which may have been
* determined from the current `otDeviceProperties`).
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aWeight The Thread Leader Weight value.
*
+39
View File
@@ -41,6 +41,7 @@ Done
- [csl](#csl)
- [dataset](README_DATASET.md)
- [delaytimermin](#delaytimermin)
- [deviceprops](#deviceprops)
- [diag](#diag)
- [discover](#discover-channel)
- [dns](#dns-config)
@@ -1056,6 +1057,44 @@ Set the minimal delay timer (in seconds).
Done
```
### deviceprops
Get the current device properties.
```bash
> deviceprops
PowerSupply : external
IsBorderRouter : yes
SupportsCcm : no
IsUnstable : no
WeightAdjustment : 0
Done
```
### deviceprops \<power-supply\> \<is-br\> \<supports-ccm\> \<is-unstable\> \<weight-adjustment\>
Set the device properties which are then used to determine and set the Leader Weight.
- power-supply: `battery`, `external`, `external-stable`, or `external-unstable`.
- weight-adjustment: Valid range is from -16 to +16. Clamped if not within the range.
```bash
> deviceprops battery 0 0 0 -5
Done
> deviceprops
PowerSupply : battery
IsBorderRouter : no
SupportsCcm : no
IsUnstable : no
WeightAdjustment : -5
Done
> leaderweight
51
Done
```
### discover \[channel\]
Perform an MLE Discovery operation.
+103
View File
@@ -4290,6 +4290,106 @@ template <> otError Interpreter::Process<Cmd("leaderweight")>(Arg aArgs[])
*/
return ProcessGetSet(aArgs, otThreadGetLocalLeaderWeight, otThreadSetLocalLeaderWeight);
}
template <> otError Interpreter::Process<Cmd("deviceprops")>(Arg aArgs[])
{
static const char *const kPowerSupplyStrings[4] = {
"battery", // (0) OT_POWER_SUPPLY_BATTERY
"external", // (1) OT_POWER_SUPPLY_EXTERNAL
"external-stable", // (2) OT_POWER_SUPPLY_EXTERNAL_STABLE
"external-unstable", // (3) OT_POWER_SUPPLY_EXTERNAL_UNSTABLE
};
static_assert(0 == OT_POWER_SUPPLY_BATTERY, "OT_POWER_SUPPLY_BATTERY value is incorrect");
static_assert(1 == OT_POWER_SUPPLY_EXTERNAL, "OT_POWER_SUPPLY_EXTERNAL value is incorrect");
static_assert(2 == OT_POWER_SUPPLY_EXTERNAL_STABLE, "OT_POWER_SUPPLY_EXTERNAL_STABLE value is incorrect");
static_assert(3 == OT_POWER_SUPPLY_EXTERNAL_UNSTABLE, "OT_POWER_SUPPLY_EXTERNAL_UNSTABLE value is incorrect");
otError error = OT_ERROR_NONE;
/**
* @cli deviceprops
* @code
* deviceprops
* PowerSupply : external
* IsBorderRouter : yes
* SupportsCcm : no
* IsUnstable : no
* WeightAdjustment : 0
* Done
* @endcode
* @par api_copy
* #otThreadGetDeviceProperties
*/
if (aArgs[0].IsEmpty())
{
const otDeviceProperties *props = otThreadGetDeviceProperties(GetInstancePtr());
OutputLine("PowerSupply : %s", Stringify(props->mPowerSupply, kPowerSupplyStrings));
OutputLine("IsBorderRouter : %s", props->mIsBorderRouter ? "yes" : "no");
OutputLine("SupportsCcm : %s", props->mSupportsCcm ? "yes" : "no");
OutputLine("IsUnstable : %s", props->mIsUnstable ? "yes" : "no");
OutputLine("WeightAdjustment : %d", props->mLeaderWeightAdjustment);
}
/**
* @cli deviceprops (set)
* @code
* deviceprops battery 0 0 0 -5
* Done
* @endcode
* @code
* deviceprops
* PowerSupply : battery
* IsBorderRouter : no
* SupportsCcm : no
* IsUnstable : no
* WeightAdjustment : -5
* Done
* @endcode
* @cparam deviceprops @ca{powerSupply} @ca{isBr} @ca{supportsCcm} @ca{isUnstable} @ca{weightAdjustment}
* `powerSupply`: should be 'battery', 'external', 'external-stable', 'external-unstable'.
* @par
* Sets the device properties.
* @csa{leaderweight}
* @csa{leaderweight (set)}
* @sa #otThreadSetDeviceProperties
*/
else
{
otDeviceProperties props;
bool value;
uint8_t index;
for (index = 0; index < OT_ARRAY_LENGTH(kPowerSupplyStrings); index++)
{
if (aArgs[0] == kPowerSupplyStrings[index])
{
props.mPowerSupply = static_cast<otPowerSupply>(index);
break;
}
}
VerifyOrExit(index < OT_ARRAY_LENGTH(kPowerSupplyStrings), error = OT_ERROR_INVALID_ARGS);
SuccessOrExit(error = aArgs[1].ParseAsBool(value));
props.mIsBorderRouter = value;
SuccessOrExit(error = aArgs[2].ParseAsBool(value));
props.mSupportsCcm = value;
SuccessOrExit(error = aArgs[3].ParseAsBool(value));
props.mIsUnstable = value;
SuccessOrExit(error = aArgs[4].ParseAsInt8(props.mLeaderWeightAdjustment));
VerifyOrExit(aArgs[5].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
otThreadSetDeviceProperties(GetInstancePtr(), &props);
}
exit:
return error;
}
#endif // OPENTHREAD_FTD
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE
@@ -8053,6 +8153,9 @@ otError Interpreter::ProcessCommand(Arg aArgs[])
#endif
CmdEntry("detach"),
#endif // OPENTHREAD_FTD || OPENTHREAD_MTD
#if OPENTHREAD_FTD
CmdEntry("deviceprops"),
#endif
#if OPENTHREAD_CONFIG_DIAG_ENABLE
CmdEntry("diag"),
#endif
+10
View File
@@ -79,6 +79,16 @@ otError otThreadSetPreferredRouterId(otInstance *aInstance, uint8_t aRouterId)
return AsCoreType(aInstance).Get<Mle::MleRouter>().SetPreferredRouterId(aRouterId);
}
const otDeviceProperties *otThreadGetDeviceProperties(otInstance *aInstance)
{
return &AsCoreType(aInstance).Get<Mle::MleRouter>().GetDeviceProperties();
}
void otThreadSetDeviceProperties(otInstance *aInstance, const otDeviceProperties *aDeviceProperties)
{
AsCoreType(aInstance).Get<Mle::MleRouter>().SetDeviceProperties(AsCoreType(aDeviceProperties));
}
uint8_t otThreadGetLocalLeaderWeight(otInstance *aInstance)
{
return AsCoreType(aInstance).Get<Mle::MleRouter>().GetLeaderWeight();
+13
View File
@@ -77,6 +77,19 @@
#define OPENTHREAD_CONFIG_STACK_VERSION_MINOR 1
#endif
/**
* @def OPENTHREAD_CONFIG_DEVICE_POWER_SUPPLY
*
* Specifies the default device power supply config. This config MUST use values from `otPowerSupply` enumeration.
*
* Device manufacturer can use this config to set the power supply config used by the device. This is then used as part
* of default `otDeviceProperties` to determine the Leader Weight used by the device.
*
*/
#ifndef OPENTHREAD_CONFIG_DEVICE_POWER_SUPPLY
#define OPENTHREAD_CONFIG_DEVICE_POWER_SUPPLY OT_POWER_SUPPLY_EXTERNAL
#endif
/**
* @def OPENTHREAD_CONFIG_ECDSA_ENABLE
*
+12
View File
@@ -88,6 +88,18 @@
#define OPENTHREAD_CONFIG_MLE_IP_ADDRS_TO_REGISTER (OPENTHREAD_CONFIG_MLE_IP_ADDRS_PER_CHILD)
#endif
/**
* @def OPENTHREAD_CONFIG_MLE_DEFAULT_LEADER_WEIGHT_ADJUSTMENT
*
* Specifies the default value for `mLeaderWeightAdjustment` in `otDeviceProperties`. MUST be from -16 up to +16.
*
* This value is used to adjust the calculated Leader Weight from `otDeviceProperties`.
*
*/
#ifndef OPENTHREAD_CONFIG_MLE_DEFAULT_LEADER_WEIGHT_ADJUSTMENT
#define OPENTHREAD_CONFIG_MLE_DEFAULT_LEADER_WEIGHT_ADJUSTMENT 0
#endif
/**
* @def OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE
*
+8 -1
View File
@@ -70,7 +70,6 @@ MleRouter::MleRouter(Instance &aInstance)
, mNetworkIdTimeout(kNetworkIdTimeout)
, mRouterUpgradeThreshold(kRouterUpgradeThreshold)
, mRouterDowngradeThreshold(kRouterDowngradeThreshold)
, mLeaderWeight(kLeaderWeight)
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
, mPreferredLeaderPartitionId(0)
, mCcmEnabled(false)
@@ -95,6 +94,7 @@ MleRouter::MleRouter(Instance &aInstance)
#endif
{
mDeviceMode.Set(mDeviceMode.Get() | DeviceMode::kModeFullThreadDevice | DeviceMode::kModeFullNetworkData);
mLeaderWeight = mDeviceProperties.CalculateLeaderWeight();
SetRouterId(kInvalidRouterId);
@@ -183,6 +183,13 @@ exit:
return error;
}
void MleRouter::SetDeviceProperties(const DeviceProperties &aDeviceProperties)
{
mDeviceProperties = aDeviceProperties;
mDeviceProperties.ClampWeightAdjustment();
SetLeaderWeight(mDeviceProperties.CalculateLeaderWeight());
}
Error MleRouter::BecomeRouter(ThreadStatusTlv::Status aStatus)
{
Error error = kErrorNone;
+21
View File
@@ -143,6 +143,22 @@ public:
*/
Error BecomeLeader(void);
/**
* This method gets the device properties which are used to determine the Leader Weight.
*
* @returns The current device properties.
*
*/
const DeviceProperties &GetDeviceProperties(void) const { return mDeviceProperties; }
/**
* This method sets the device properties which are then used to determine and set the Leader Weight.
*
* @param[in] aDeviceProperties The device properties.
*
*/
void SetDeviceProperties(const DeviceProperties &aDeviceProperties);
/**
* This method returns the Leader Weighting value for this Thread interface.
*
@@ -154,6 +170,9 @@ public:
/**
* This method sets the Leader Weighting value for this Thread interface.
*
* This method directly sets the Leader Weight to the new value replacing its previous value (which may have been
* determined from a previous call to `SetDeviceProperties()`).
*
* @param[in] aWeight The Leader Weighting value.
*
*/
@@ -636,6 +655,8 @@ private:
TrickleTimer mAdvertiseTrickleTimer;
DeviceProperties mDeviceProperties;
ChildTable mChildTable;
RouterTable mRouterTable;
+76
View File
@@ -39,6 +39,9 @@
namespace ot {
namespace Mle {
//---------------------------------------------------------------------------------------------------------------------
// DeviceMode
void DeviceMode::Get(ModeConfig &aModeConfig) const
{
aModeConfig.mRxOnWhenIdle = IsRxOnWhenIdle();
@@ -64,6 +67,77 @@ DeviceMode::InfoString DeviceMode::ToString(void) const
return string;
}
//---------------------------------------------------------------------------------------------------------------------
// DeviceProperties
#if OPENTHREAD_FTD
DeviceProperties::DeviceProperties(void)
{
Clear();
mPowerSupply = OPENTHREAD_CONFIG_DEVICE_POWER_SUPPLY;
mLeaderWeightAdjustment = kDefaultAdjustment;
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
mIsBorderRouter = true;
#endif
}
void DeviceProperties::ClampWeightAdjustment(void)
{
mLeaderWeightAdjustment = Clamp(mLeaderWeightAdjustment, kMinAdjustment, kMaxAdjustment);
}
uint8_t DeviceProperties::CalculateLeaderWeight(void) const
{
static const int8_t kPowerSupplyIncs[] = {
kPowerBatteryInc, // (0) kPowerSupplyBattery
kPowerExternalInc, // (1) kPowerSupplyExternal
kPowerExternalStableInc, // (2) kPowerSupplyExternalStable
kPowerExternalUnstableInc, // (3) kPowerSupplyExternalUnstable
};
static_assert(0 == kPowerSupplyBattery, "kPowerSupplyBattery value is incorrect");
static_assert(1 == kPowerSupplyExternal, "kPowerSupplyExternal value is incorrect");
static_assert(2 == kPowerSupplyExternalStable, "kPowerSupplyExternalStable value is incorrect");
static_assert(3 == kPowerSupplyExternalUnstable, "kPowerSupplyExternalUnstable value is incorrect");
uint8_t weight = kBaseWeight;
PowerSupply powerSupply = MapEnum(mPowerSupply);
if (mIsBorderRouter)
{
weight += (mSupportsCcm ? kCcmBorderRouterInc : kBorderRouterInc);
}
if (powerSupply < GetArrayLength(kPowerSupplyIncs))
{
weight += kPowerSupplyIncs[powerSupply];
}
if (mIsUnstable)
{
switch (powerSupply)
{
case kPowerSupplyBattery:
case kPowerSupplyExternalUnstable:
break;
default:
weight += kIsUnstableInc;
}
}
weight += mLeaderWeightAdjustment;
return weight;
}
#endif // OPENTHREAD_FTD
//---------------------------------------------------------------------------------------------------------------------
// RouterIdSet
uint8_t RouterIdSet::GetNumberOfAllocatedIds(void) const
{
uint8_t count = 0;
@@ -76,6 +150,8 @@ uint8_t RouterIdSet::GetNumberOfAllocatedIds(void) const
return count;
}
//---------------------------------------------------------------------------------------------------------------------
const char *RoleToString(DeviceRole aRole)
{
static const char *const kRoleStrings[] = {
+68 -1
View File
@@ -41,6 +41,9 @@
#include <string.h>
#include <openthread/thread.h>
#if OPENTHREAD_FTD
#include <openthread/thread_ftd.h>
#endif
#include "common/as_core_type.hpp"
#include "common/clearable.hpp"
@@ -181,7 +184,6 @@ constexpr uint32_t kMaxLeaderToRouterTimeout = 90; ///< (in sec)
constexpr uint32_t kReedAdvertiseInterval = 570; ///< (in sec)
constexpr uint32_t kReedAdvertiseJitter = 60; ///< (in sec)
constexpr uint8_t kLeaderWeight = 64; ///< Default leader weight
constexpr uint32_t kMleEndDeviceTimeout = OPENTHREAD_CONFIG_MLE_CHILD_TIMEOUT_DEFAULT; ///< (in sec)
constexpr uint8_t kMeshLocalPrefixContextId = 0; ///< 0 is reserved for Mesh Local Prefix
@@ -435,6 +437,67 @@ private:
uint8_t mMode;
};
#if OPENTHREAD_FTD
/**
* This class represents device properties.
*
* The device properties are used for calculating the local leader weight on the device.
*
*/
class DeviceProperties : public otDeviceProperties, public Clearable<DeviceProperties>
{
public:
/**
* This enumeration represents the device's power supply property.
*
*/
enum PowerSupply : uint8_t
{
kPowerSupplyBattery = OT_POWER_SUPPLY_BATTERY, ///< Battery powered.
kPowerSupplyExternal = OT_POWER_SUPPLY_EXTERNAL, ///< External powered.
kPowerSupplyExternalStable = OT_POWER_SUPPLY_EXTERNAL_STABLE, ///< Stable external power with backup.
kPowerSupplyExternalUnstable = OT_POWER_SUPPLY_EXTERNAL_UNSTABLE, ///< Unstable external power.
};
/**
* This constructor initializes `DeviceProperties` with default values.
*
*/
DeviceProperties(void);
/**
* This method clamps the `mLeaderWeightAdjustment` value to the valid range.
*
*/
void ClampWeightAdjustment(void);
/**
* This method calculates the leader weight based on the device properties.
*
* @returns The calculated leader weight.
*
*/
uint8_t CalculateLeaderWeight(void) const;
private:
static constexpr int8_t kDefaultAdjustment = OPENTHREAD_CONFIG_MLE_DEFAULT_LEADER_WEIGHT_ADJUSTMENT;
static constexpr uint8_t kBaseWeight = 64;
static constexpr int8_t kBorderRouterInc = +1;
static constexpr int8_t kCcmBorderRouterInc = +8;
static constexpr int8_t kIsUnstableInc = -4;
static constexpr int8_t kPowerBatteryInc = -8;
static constexpr int8_t kPowerExternalInc = 0;
static constexpr int8_t kPowerExternalStableInc = +4;
static constexpr int8_t kPowerExternalUnstableInc = -4;
static constexpr int8_t kMinAdjustment = -16;
static constexpr int8_t kMaxAdjustment = +16;
static_assert(kDefaultAdjustment >= kMinAdjustment, "Invalid default weight adjustment");
static_assert(kDefaultAdjustment <= kMaxAdjustment, "Invalid default weight adjustment");
};
#endif // OPENTHREAD_FTD
/**
* This class represents the Thread Leader Data.
*
@@ -693,6 +756,10 @@ const char *RoleToString(DeviceRole aRole);
DefineCoreType(otLeaderData, Mle::LeaderData);
DefineMapEnum(otDeviceRole, Mle::DeviceRole);
#if OPENTHREAD_FTD
DefineCoreType(otDeviceProperties, Mle::DeviceProperties);
DefineMapEnum(otPowerSupply, Mle::DeviceProperties::PowerSupply);
#endif
} // namespace ot
+21
View File
@@ -665,6 +665,27 @@ target_link_libraries(ot-test-message-queue
add_test(NAME ot-test-message-queue COMMAND ot-test-message-queue)
add_executable(ot-test-mle
test_mle.cpp
)
target_include_directories(ot-test-mle
PRIVATE
${COMMON_INCLUDES}
)
target_compile_options(ot-test-mle
PRIVATE
${COMMON_COMPILE_OPTIONS}
)
target_link_libraries(ot-test-mle
PRIVATE
${COMMON_LIBS}
)
add_test(NAME ot-test-mle COMMAND ot-test-mle)
add_executable(ot-test-multicast-listeners-table
test_multicast_listeners_table.cpp
)
+185
View File
@@ -0,0 +1,185 @@
/*
* Copyright (c) 2023, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <openthread/config.h>
#include "test_platform.h"
#include "test_util.hpp"
#include "common/num_utils.hpp"
#include "thread/mle_types.hpp"
namespace ot {
#if OPENTHREAD_FTD
void TestDefaultDeviceProperties(void)
{
Instance *instance;
const otDeviceProperties *props;
uint8_t weight;
instance = static_cast<Instance *>(testInitInstance());
VerifyOrQuit(instance != nullptr);
props = otThreadGetDeviceProperties(instance);
VerifyOrQuit(props->mPowerSupply == OPENTHREAD_CONFIG_DEVICE_POWER_SUPPLY);
VerifyOrQuit(!props->mSupportsCcm);
VerifyOrQuit(!props->mIsUnstable);
VerifyOrQuit(props->mLeaderWeightAdjustment == OPENTHREAD_CONFIG_MLE_DEFAULT_LEADER_WEIGHT_ADJUSTMENT);
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
VerifyOrQuit(props->mIsBorderRouter);
#else
VerifyOrQuit(!props->mIsBorderRouter);
#endif
weight = 64;
switch (props->mPowerSupply)
{
case OT_POWER_SUPPLY_BATTERY:
weight -= 8;
break;
case OT_POWER_SUPPLY_EXTERNAL:
break;
case OT_POWER_SUPPLY_EXTERNAL_STABLE:
weight += 4;
break;
case OT_POWER_SUPPLY_EXTERNAL_UNSTABLE:
weight -= 4;
break;
}
weight += props->mIsBorderRouter ? 1 : 0;
VerifyOrQuit(otThreadGetLocalLeaderWeight(instance) == weight);
printf("TestDefaultDeviceProperties passed\n");
}
void CompareDevicePropertiess(const otDeviceProperties &aFirst, const otDeviceProperties &aSecond)
{
static constexpr int8_t kMinAdjustment = -16;
static constexpr int8_t kMaxAdjustment = +16;
VerifyOrQuit(aFirst.mPowerSupply == aSecond.mPowerSupply);
VerifyOrQuit(aFirst.mIsBorderRouter == aSecond.mIsBorderRouter);
VerifyOrQuit(aFirst.mSupportsCcm == aSecond.mSupportsCcm);
VerifyOrQuit(aFirst.mIsUnstable == aSecond.mIsUnstable);
VerifyOrQuit(Clamp(aFirst.mLeaderWeightAdjustment, kMinAdjustment, kMaxAdjustment) ==
Clamp(aSecond.mLeaderWeightAdjustment, kMinAdjustment, kMaxAdjustment));
}
void TestLeaderWeightCalculation(void)
{
struct TestCase
{
otDeviceProperties mDeviceProperties;
uint8_t mExpectedLeaderWeight;
};
static const TestCase kTestCases[] = {
{{OT_POWER_SUPPLY_BATTERY, false, false, false, 0}, 56},
{{OT_POWER_SUPPLY_EXTERNAL, false, false, false, 0}, 64},
{{OT_POWER_SUPPLY_EXTERNAL_STABLE, false, false, false, 0}, 68},
{{OT_POWER_SUPPLY_EXTERNAL_UNSTABLE, false, false, false, 0}, 60},
{{OT_POWER_SUPPLY_BATTERY, true, false, false, 0}, 57},
{{OT_POWER_SUPPLY_EXTERNAL, true, false, false, 0}, 65},
{{OT_POWER_SUPPLY_EXTERNAL_STABLE, true, false, false, 0}, 69},
{{OT_POWER_SUPPLY_EXTERNAL_UNSTABLE, true, false, false, 0}, 61},
{{OT_POWER_SUPPLY_BATTERY, true, true, false, 0}, 64},
{{OT_POWER_SUPPLY_EXTERNAL, true, true, false, 0}, 72},
{{OT_POWER_SUPPLY_EXTERNAL_STABLE, true, true, false, 0}, 76},
{{OT_POWER_SUPPLY_EXTERNAL_UNSTABLE, true, true, false, 0}, 68},
// Check when `mIsUnstable` is set.
{{OT_POWER_SUPPLY_BATTERY, false, false, true, 0}, 56},
{{OT_POWER_SUPPLY_EXTERNAL, false, false, true, 0}, 60},
{{OT_POWER_SUPPLY_EXTERNAL_STABLE, false, false, true, 0}, 64},
{{OT_POWER_SUPPLY_EXTERNAL_UNSTABLE, false, false, true, 0}, 60},
{{OT_POWER_SUPPLY_BATTERY, true, false, true, 0}, 57},
{{OT_POWER_SUPPLY_EXTERNAL, true, false, true, 0}, 61},
{{OT_POWER_SUPPLY_EXTERNAL_STABLE, true, false, true, 0}, 65},
{{OT_POWER_SUPPLY_EXTERNAL_UNSTABLE, true, false, true, 0}, 61},
// Include non-zero `mLeaderWeightAdjustment`.
{{OT_POWER_SUPPLY_BATTERY, true, false, false, 10}, 67},
{{OT_POWER_SUPPLY_EXTERNAL, true, false, false, 10}, 75},
{{OT_POWER_SUPPLY_EXTERNAL_STABLE, true, false, false, 10}, 79},
{{OT_POWER_SUPPLY_EXTERNAL_UNSTABLE, true, false, false, 10}, 71},
{{OT_POWER_SUPPLY_BATTERY, false, false, false, -10}, 46},
{{OT_POWER_SUPPLY_EXTERNAL, false, false, false, -10}, 54},
{{OT_POWER_SUPPLY_EXTERNAL_STABLE, false, false, false, -10}, 58},
{{OT_POWER_SUPPLY_EXTERNAL_UNSTABLE, false, false, false, -10}, 50},
// Use `mLeaderWeightAdjustment` larger than valid range
// Make sure it clamps to -16 and +16.
{{OT_POWER_SUPPLY_BATTERY, false, false, false, 20}, 72},
{{OT_POWER_SUPPLY_EXTERNAL, false, false, false, 20}, 80},
{{OT_POWER_SUPPLY_EXTERNAL_STABLE, false, false, false, 20}, 84},
{{OT_POWER_SUPPLY_EXTERNAL_UNSTABLE, false, false, false, 20}, 76},
{{OT_POWER_SUPPLY_BATTERY, true, false, false, -20}, 41},
{{OT_POWER_SUPPLY_EXTERNAL, true, false, false, -20}, 49},
{{OT_POWER_SUPPLY_EXTERNAL_STABLE, true, false, false, -20}, 53},
{{OT_POWER_SUPPLY_EXTERNAL_UNSTABLE, true, false, false, -20}, 45},
};
Instance *instance;
instance = static_cast<Instance *>(testInitInstance());
VerifyOrQuit(instance != nullptr);
for (const TestCase &testCase : kTestCases)
{
otThreadSetDeviceProperties(instance, &testCase.mDeviceProperties);
CompareDevicePropertiess(testCase.mDeviceProperties, *otThreadGetDeviceProperties(instance));
VerifyOrQuit(otThreadGetLocalLeaderWeight(instance) == testCase.mExpectedLeaderWeight);
}
printf("TestLeaderWeightCalculation passed\n");
}
#endif // OPENTHREAD_FTD
} // namespace ot
int main(void)
{
#if OPENTHREAD_FTD
ot::TestDefaultDeviceProperties();
ot::TestLeaderWeightCalculation();
#endif
printf("All tests passed\n");
return 0;
}