mirror of
https://github.com/espressif/openthread.git
synced 2026-08-08 19:57:46 +00:00
[posix] add channel mask configurations to configuration file (#9391)
This commit allows developers to set the preferred channel mask and the supported channel mask in the configuration file. The posix platform selects channel masks from the configuration file based on the region code when the region code is updated.
This commit is contained in:
@@ -105,6 +105,7 @@ add_library(openthread-posix
|
||||
alarm.cpp
|
||||
backbone.cpp
|
||||
backtrace.cpp
|
||||
configuration.cpp
|
||||
config_file.cpp
|
||||
daemon.cpp
|
||||
entropy.cpp
|
||||
@@ -118,7 +119,6 @@ add_library(openthread-posix
|
||||
multicast_routing.cpp
|
||||
netif.cpp
|
||||
power.cpp
|
||||
power_updater.cpp
|
||||
radio.cpp
|
||||
radio_url.cpp
|
||||
resolver.cpp
|
||||
|
||||
@@ -50,15 +50,25 @@ ConfigFile::ConfigFile(const char *aFilePath)
|
||||
VerifyOrDie(strlen(mFilePath) + strlen(kSwapSuffix) < kFileNameMaxSize, OT_EXIT_FAILURE);
|
||||
}
|
||||
|
||||
otError ConfigFile::Get(const char *aKey, int &aIterator, char *aValue, int aValueLength)
|
||||
bool ConfigFile::HasKey(const char *aKey) const
|
||||
{
|
||||
int iterator = 0;
|
||||
|
||||
return (Get(aKey, iterator, nullptr, 0) == OT_ERROR_NONE);
|
||||
}
|
||||
|
||||
bool ConfigFile::DoesExist(void) const { return (access(mFilePath, 0) == 0); }
|
||||
|
||||
otError ConfigFile::Get(const char *aKey, int &aIterator, char *aValue, int aValueLength) const
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
char line[kLineMaxSize + 1];
|
||||
FILE *fp = nullptr;
|
||||
char *ret;
|
||||
char *psave;
|
||||
long int pos;
|
||||
|
||||
VerifyOrExit((aKey != nullptr) && (aValue != nullptr), error = OT_ERROR_INVALID_ARGS);
|
||||
VerifyOrExit(aKey != nullptr, error = OT_ERROR_INVALID_ARGS);
|
||||
VerifyOrExit((fp = fopen(mFilePath, "r")) != nullptr, error = OT_ERROR_NOT_FOUND);
|
||||
VerifyOrDie(fseek(fp, aIterator, SEEK_SET) == 0, OT_EXIT_ERROR_ERRNO);
|
||||
|
||||
@@ -77,7 +87,7 @@ otError ConfigFile::Get(const char *aKey, int &aIterator, char *aValue, int aVal
|
||||
}
|
||||
|
||||
// Remove comments
|
||||
strtok(line, kCommentDelimiter);
|
||||
strtok_r(line, kCommentDelimiter, &psave);
|
||||
|
||||
if ((str = strstr(line, "=")) == nullptr)
|
||||
{
|
||||
@@ -91,11 +101,14 @@ otError ConfigFile::Get(const char *aKey, int &aIterator, char *aValue, int aVal
|
||||
|
||||
if (strcmp(aKey, key) == 0)
|
||||
{
|
||||
value = str + 1;
|
||||
Strip(value);
|
||||
aValueLength = OT_MIN(static_cast<int>(strlen(value)), (aValueLength - 1));
|
||||
memcpy(aValue, value, static_cast<size_t>(aValueLength));
|
||||
aValue[aValueLength] = '\0';
|
||||
if (aValue != nullptr)
|
||||
{
|
||||
value = str + 1;
|
||||
Strip(value);
|
||||
aValueLength = OT_MIN(static_cast<int>(strlen(value)), (aValueLength - 1));
|
||||
memcpy(aValue, value, static_cast<size_t>(aValueLength));
|
||||
aValue[aValueLength] = '\0';
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -197,7 +210,7 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void ConfigFile::Strip(char *aString)
|
||||
void ConfigFile::Strip(char *aString) const
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
|
||||
@@ -58,14 +58,15 @@ public:
|
||||
* @param[in,out] aIterator A reference to an iterator. MUST be initialized to 0 or the behavior is undefined.
|
||||
* @param[out] aValue A pointer to where the new value string of the configuration should be read from.
|
||||
* The @p aValue string will be terminated with `\0` if this method returns success.
|
||||
* May be `nullptr` if performing a presence check.
|
||||
* @param[in] aValueLength The max length of the data pointed to by @p aValue.
|
||||
*
|
||||
* @retval OT_ERROR_NONE The given configuration was found and fetched successfully.
|
||||
* @retval OT_ERROR_NOT_FOUND The given key or iterator was not found in the configuration file.
|
||||
* @retval OT_ERROR_INVALID_ARGS If @p aKey or @p aValue was NULL.
|
||||
* @retval OT_ERROR_INVALID_ARGS If @p aKey was NULL.
|
||||
*
|
||||
*/
|
||||
otError Get(const char *aKey, int &aIterator, char *aValue, int aValueLength);
|
||||
otError Get(const char *aKey, int &aIterator, char *aValue, int aValueLength) const;
|
||||
|
||||
/**
|
||||
* Adds a configuration to the configuration file.
|
||||
@@ -90,13 +91,33 @@ public:
|
||||
*/
|
||||
otError Clear(const char *aKey);
|
||||
|
||||
/**
|
||||
* Indicates whether the given key exists.
|
||||
*
|
||||
* @param[in] aKey The key string associated with the requested configuration.
|
||||
*
|
||||
* @retval TRUE If the key exists in the configuration file.
|
||||
* @retval FALSE If the key does not exist in the configuration file.
|
||||
*
|
||||
*/
|
||||
bool HasKey(const char *aKey) const;
|
||||
|
||||
/**
|
||||
* Indicates whether the configuration file exists.
|
||||
*
|
||||
* @retval TRUE If the configuration file exists.
|
||||
* @retval FALSE If the configuration file does not exist.
|
||||
*
|
||||
*/
|
||||
bool DoesExist(void) const;
|
||||
|
||||
private:
|
||||
const char *kCommentDelimiter = "#";
|
||||
const char *kSwapSuffix = ".swap";
|
||||
static constexpr uint16_t kLineMaxSize = 512;
|
||||
static constexpr uint16_t kFileNameMaxSize = 255;
|
||||
|
||||
void Strip(char *aString);
|
||||
void Strip(char *aString) const;
|
||||
|
||||
const char *mFilePath;
|
||||
};
|
||||
|
||||
@@ -26,23 +26,27 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "power_updater.hpp"
|
||||
#include "configuration.hpp"
|
||||
|
||||
#include "platform-posix.h"
|
||||
#include <openthread/platform/radio.h>
|
||||
#include "lib/platform/exit_code.h"
|
||||
#include "utils/parse_cmdline.hpp"
|
||||
|
||||
#if OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
#if OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE && !OPENTHREAD_POSIX_CONFIG_CONFIGURATION_FILE_ENABLE
|
||||
#error \
|
||||
"OPENTHREAD_POSIX_CONFIG_CONFIGURATION_FILE_ENABLE is required for OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE"
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_POSIX_CONFIG_CONFIGURATION_FILE_ENABLE
|
||||
|
||||
namespace ot {
|
||||
namespace Posix {
|
||||
|
||||
otError PowerUpdater::SetRegion(uint16_t aRegionCode)
|
||||
otError Configuration::SetRegion(uint16_t aRegionCode)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
int iterator = 0;
|
||||
Power::Domain domain;
|
||||
Power::TargetPower targetPower;
|
||||
otError error = OT_ERROR_NONE;
|
||||
Power::Domain domain;
|
||||
|
||||
if (GetDomain(aRegionCode, domain) != OT_ERROR_NONE)
|
||||
{
|
||||
@@ -50,7 +54,124 @@ otError PowerUpdater::SetRegion(uint16_t aRegionCode)
|
||||
VerifyOrExit(GetDomain(kRegionCodeWorldWide, domain) == OT_ERROR_NONE, error = OT_ERROR_FAILED);
|
||||
}
|
||||
|
||||
while (GetNextTargetPower(domain, iterator, targetPower) == OT_ERROR_NONE)
|
||||
SuccessOrExit(error = UpdateChannelMasks(domain));
|
||||
#if OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
SuccessOrExit(error = UpdateTargetPower(domain));
|
||||
SuccessOrExit(error = UpdateCalibratedPower());
|
||||
#endif
|
||||
|
||||
mRegionCode = aRegionCode;
|
||||
|
||||
exit:
|
||||
if (error == OT_ERROR_NONE)
|
||||
{
|
||||
otLogInfoPlat("Successfully set region \"%c%c\"", (aRegionCode >> 8) & 0xff, (aRegionCode & 0xff));
|
||||
}
|
||||
else
|
||||
{
|
||||
otLogCritPlat("Failed to set region \"%c%c\": %s", (aRegionCode >> 8) & 0xff, (aRegionCode & 0xff),
|
||||
otThreadErrorToString(error));
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
otError Configuration::GetDomain(uint16_t aRegionCode, Power::Domain &aDomain)
|
||||
{
|
||||
otError error = OT_ERROR_NOT_FOUND;
|
||||
int iterator = 0;
|
||||
char value[kMaxValueSize];
|
||||
char *str;
|
||||
char *psave;
|
||||
|
||||
while (mProductConfigFile.Get(kKeyRegionDomainMapping, iterator, value, sizeof(value)) == OT_ERROR_NONE)
|
||||
{
|
||||
if ((str = strtok_r(value, kCommaDelimiter, &psave)) == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
while ((str = strtok_r(nullptr, kCommaDelimiter, &psave)) != nullptr)
|
||||
{
|
||||
if ((strlen(str) == 2) && (StringToRegionCode(str) == aRegionCode))
|
||||
{
|
||||
ExitNow(error = aDomain.Set(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
if (error != OT_ERROR_NONE)
|
||||
{
|
||||
otLogCritPlat("Failed to get power domain: %s", otThreadErrorToString(error));
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
otError Configuration::GetChannelMask(const char *aKey, const Power::Domain &aDomain, uint32_t &aChannelMask)
|
||||
{
|
||||
otError error = OT_ERROR_NOT_FOUND;
|
||||
int iterator = 0;
|
||||
char value[kMaxValueSize];
|
||||
char *str;
|
||||
Power::Domain domain;
|
||||
uint32_t channelMask;
|
||||
char *psave;
|
||||
|
||||
while (mProductConfigFile.Get(aKey, iterator, value, sizeof(value)) == OT_ERROR_NONE)
|
||||
{
|
||||
if (((str = strtok_r(value, kCommaDelimiter, &psave)) == nullptr) || (aDomain != str))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((str = strtok_r(nullptr, kCommaDelimiter, &psave)) != nullptr)
|
||||
{
|
||||
SuccessOrExit(error = Utils::CmdLineParser::ParseAsUint32(str, channelMask));
|
||||
aChannelMask = channelMask;
|
||||
error = OT_ERROR_NONE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError Configuration::UpdateChannelMasks(const Power::Domain &aDomain)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
if (mProductConfigFile.HasKey(kKeySupportedChannelMask))
|
||||
{
|
||||
SuccessOrExit(error = GetChannelMask(kKeySupportedChannelMask, aDomain, mSupportedChannelMask));
|
||||
}
|
||||
|
||||
if (mProductConfigFile.HasKey(kKeySupportedChannelMask))
|
||||
{
|
||||
SuccessOrExit(error = GetChannelMask(kKeyPreferredChannelMask, aDomain, mPreferredChannelMask));
|
||||
}
|
||||
|
||||
exit:
|
||||
if (error != OT_ERROR_NONE)
|
||||
{
|
||||
otLogCritPlat("Failed to update channel mask: %s", otThreadErrorToString(error));
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
otError Configuration::UpdateTargetPower(const Power::Domain &aDomain)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
int iterator = 0;
|
||||
Power::TargetPower targetPower;
|
||||
|
||||
VerifyOrExit(mProductConfigFile.HasKey(kKeyTargetPower));
|
||||
|
||||
while (GetNextTargetPower(aDomain, iterator, targetPower) == OT_ERROR_NONE)
|
||||
{
|
||||
otLogInfoPlat("Update target power: %s\r\n", targetPower.ToString().AsCString());
|
||||
|
||||
@@ -60,25 +181,16 @@ otError PowerUpdater::SetRegion(uint16_t aRegionCode)
|
||||
}
|
||||
}
|
||||
|
||||
SuccessOrExit(error = UpdateCalibratedPower());
|
||||
|
||||
mRegionCode = aRegionCode;
|
||||
|
||||
exit:
|
||||
if (error == OT_ERROR_NONE)
|
||||
if (error != OT_ERROR_NONE)
|
||||
{
|
||||
otLogInfoPlat("Set region \"%c%c\" successfully", (aRegionCode >> 8) & 0xff, (aRegionCode & 0xff));
|
||||
}
|
||||
else
|
||||
{
|
||||
otLogCritPlat("Set region \"%c%c\" failed, Error: %s", (aRegionCode >> 8) & 0xff, (aRegionCode & 0xff),
|
||||
otThreadErrorToString(error));
|
||||
otLogCritPlat("Failed to update target power: %s", otThreadErrorToString(error));
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
otError PowerUpdater::UpdateCalibratedPower(void)
|
||||
otError Configuration::UpdateCalibratedPower(void)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
int iterator = 0;
|
||||
@@ -86,8 +198,6 @@ otError PowerUpdater::UpdateCalibratedPower(void)
|
||||
Power::CalibratedPower calibratedPower;
|
||||
ConfigFile *calibrationFile = &mFactoryConfigFile;
|
||||
|
||||
SuccessOrExit(error = otPlatRadioClearCalibratedPowers(gInstance));
|
||||
|
||||
// If the distribution of output power is large, the factory needs to measure the power calibration data
|
||||
// for each device individually, and the power calibration data will be written to the factory config file.
|
||||
// Otherwise, the power calibration data can be pre-configured in the product config file.
|
||||
@@ -96,6 +206,9 @@ otError PowerUpdater::UpdateCalibratedPower(void)
|
||||
calibrationFile = &mProductConfigFile;
|
||||
}
|
||||
|
||||
VerifyOrExit(calibrationFile->HasKey(kKeyCalibratedPower));
|
||||
SuccessOrExit(error = otPlatRadioClearCalibratedPowers(gInstance));
|
||||
|
||||
iterator = 0;
|
||||
while (calibrationFile->Get(kKeyCalibratedPower, iterator, value, sizeof(value)) == OT_ERROR_NONE)
|
||||
{
|
||||
@@ -113,45 +226,15 @@ otError PowerUpdater::UpdateCalibratedPower(void)
|
||||
exit:
|
||||
if (error != OT_ERROR_NONE)
|
||||
{
|
||||
otLogCritPlat("Update calibrated power table failed, Error: %s", otThreadErrorToString(error));
|
||||
otLogCritPlat("Failed to update calibrated power table: %s", otThreadErrorToString(error));
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
otError PowerUpdater::GetDomain(uint16_t aRegionCode, Power::Domain &aDomain)
|
||||
{
|
||||
otError error = OT_ERROR_NOT_FOUND;
|
||||
int iterator = 0;
|
||||
char value[kMaxValueSize];
|
||||
char *str;
|
||||
|
||||
while (mProductConfigFile.Get(kKeyRegionDomainMapping, iterator, value, sizeof(value)) == OT_ERROR_NONE)
|
||||
{
|
||||
if ((str = strtok(value, kCommaDelimiter)) == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
while ((str = strtok(nullptr, kCommaDelimiter)) != nullptr)
|
||||
{
|
||||
if ((strlen(str) == 2) && (StringToRegionCode(str) == aRegionCode))
|
||||
{
|
||||
ExitNow(error = aDomain.Set(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
if (error != OT_ERROR_NONE)
|
||||
{
|
||||
otLogCritPlat("Get domain failed, Error: %s", otThreadErrorToString(error));
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
otError PowerUpdater::GetNextTargetPower(const Power::Domain &aDomain, int &aIterator, Power::TargetPower &aTargetPower)
|
||||
otError Configuration::GetNextTargetPower(const Power::Domain &aDomain,
|
||||
int &aIterator,
|
||||
Power::TargetPower &aTargetPower)
|
||||
{
|
||||
otError error = OT_ERROR_NOT_FOUND;
|
||||
char value[kMaxValueSize];
|
||||
@@ -167,14 +250,33 @@ otError PowerUpdater::GetNextTargetPower(const Power::Domain &aDomain, int &aIte
|
||||
|
||||
if ((error = aTargetPower.FromString(psave)) != OT_ERROR_NONE)
|
||||
{
|
||||
otLogCritPlat("Read target power failed, Error: %s", otThreadErrorToString(error));
|
||||
otLogCritPlat("Failed to read target power: %s", otThreadErrorToString(error));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
|
||||
bool Configuration::IsValid(void) const
|
||||
{
|
||||
bool ret;
|
||||
|
||||
VerifyOrExit(mProductConfigFile.DoesExist(), ret = false);
|
||||
|
||||
ret = mProductConfigFile.HasKey(kKeySupportedChannelMask) || mProductConfigFile.HasKey(kKeyPreferredChannelMask) ||
|
||||
mProductConfigFile.HasKey(kKeyRegionDomainMapping);
|
||||
VerifyOrExit(!ret);
|
||||
|
||||
#if OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
ret = (mProductConfigFile.HasKey(kKeyCalibratedPower) || mProductConfigFile.HasKey(kKeyTargetPower));
|
||||
#endif
|
||||
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace Posix
|
||||
} // namespace ot
|
||||
#endif // OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
#endif // OPENTHREAD_POSIX_CONFIG_CONFIGURATION_FILE_ENABLE
|
||||
@@ -26,12 +26,12 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef POSIX_PLATFORM_POWER_UPDATER_HPP_
|
||||
#define POSIX_PLATFORM_POWER_UPDATER_HPP_
|
||||
#ifndef POSIX_PLATFORM_CONFIGURATION_HPP_
|
||||
#define POSIX_PLATFORM_CONFIGURATION_HPP_
|
||||
|
||||
#include "openthread-posix-config.h"
|
||||
|
||||
#if OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
#if OPENTHREAD_POSIX_CONFIG_CONFIGURATION_FILE_ENABLE
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -51,13 +51,15 @@ namespace Posix {
|
||||
* Updates the target power table and calibrated power table to the RCP.
|
||||
*
|
||||
*/
|
||||
class PowerUpdater
|
||||
class Configuration
|
||||
{
|
||||
public:
|
||||
PowerUpdater(void)
|
||||
Configuration(void)
|
||||
: mFactoryConfigFile(kFactoryConfigFile)
|
||||
, mProductConfigFile(kProductConfigFile)
|
||||
, mRegionCode(0)
|
||||
, mSupportedChannelMask(kDefaultChannelMask)
|
||||
, mPreferredChannelMask(kDefaultChannelMask)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -86,31 +88,66 @@ public:
|
||||
*/
|
||||
uint16_t GetRegion(void) const { return mRegionCode; }
|
||||
|
||||
/**
|
||||
* Get the radio supported channel mask that the device is allowed to be on.
|
||||
*
|
||||
* @returns The radio supported channel mask.
|
||||
*
|
||||
*/
|
||||
uint32_t GetSupportedChannelMask(void) const { return mSupportedChannelMask; }
|
||||
|
||||
/**
|
||||
* Gets the radio preferred channel mask that the device prefers to form on.
|
||||
*
|
||||
* @returns The radio preferred channel mask.
|
||||
*
|
||||
*/
|
||||
uint32_t GetPreferredChannelMask(void) const { return mPreferredChannelMask; }
|
||||
|
||||
/**
|
||||
* Indicates whether the configuration file are valid.
|
||||
*
|
||||
* @retval TRUE If there are any valid configuration keys in the configuration file.
|
||||
* @retval FALSE If the configuration file doesn't exist or there is no key in the configuration file.
|
||||
*
|
||||
*/
|
||||
bool IsValid(void) const;
|
||||
|
||||
private:
|
||||
const char *kFactoryConfigFile = OPENTHREAD_POSIX_CONFIG_FACTORY_CONFIG_FILE;
|
||||
const char *kProductConfigFile = OPENTHREAD_POSIX_CONFIG_PRODUCT_CONFIG_FILE;
|
||||
const char *kKeyCalibratedPower = "calibrated_power";
|
||||
const char *kKeyTargetPower = "target_power";
|
||||
const char *kKeyRegionDomainMapping = "region_domain_mapping";
|
||||
const char *kCommaDelimiter = ",";
|
||||
static constexpr uint16_t kMaxValueSize = 512;
|
||||
static constexpr uint16_t kRegionCodeWorldWide = 0x5757; // Region Code: "WW"
|
||||
const char *kFactoryConfigFile = OPENTHREAD_POSIX_CONFIG_FACTORY_CONFIG_FILE;
|
||||
const char *kProductConfigFile = OPENTHREAD_POSIX_CONFIG_PRODUCT_CONFIG_FILE;
|
||||
const char *kKeyCalibratedPower = "calibrated_power";
|
||||
const char *kKeyTargetPower = "target_power";
|
||||
const char *kKeyRegionDomainMapping = "region_domain_mapping";
|
||||
const char *kKeySupportedChannelMask = "supported_channel_mask";
|
||||
const char *kKeyPreferredChannelMask = "preferred_channel_mask";
|
||||
const char *kCommaDelimiter = ",";
|
||||
static constexpr uint16_t kMaxValueSize = 512;
|
||||
static constexpr uint16_t kRegionCodeWorldWide = 0x5757; // Region Code: "WW"
|
||||
static constexpr uint32_t kDefaultChannelMask = 0x7fff800; // Channel 11 ~ 26
|
||||
|
||||
uint16_t StringToRegionCode(const char *aString) const
|
||||
{
|
||||
return static_cast<uint16_t>(((aString[0] & 0xFF) << 8) | ((aString[1] & 0xFF) << 0));
|
||||
}
|
||||
otError GetDomain(uint16_t aRegionCode, Power::Domain &aDomain);
|
||||
otError GetNextTargetPower(const Power::Domain &aDomain, int &aIterator, Power::TargetPower &aTargetPower);
|
||||
otError GetChannelMask(const char *aKey, const Power::Domain &aDomain, uint32_t &aChannelMask);
|
||||
otError UpdateChannelMasks(const Power::Domain &aDomain);
|
||||
#if OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
otError UpdateTargetPower(const Power::Domain &aDomain);
|
||||
otError UpdateCalibratedPower(void);
|
||||
otError GetNextTargetPower(const Power::Domain &aDomain, int &aIterator, Power::TargetPower &aTargetPower);
|
||||
#endif
|
||||
|
||||
ConfigFile mFactoryConfigFile;
|
||||
ConfigFile mProductConfigFile;
|
||||
uint16_t mRegionCode;
|
||||
uint32_t mSupportedChannelMask;
|
||||
uint32_t mPreferredChannelMask;
|
||||
};
|
||||
|
||||
} // namespace Posix
|
||||
} // namespace ot
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
#endif // POSIX_PLATFORM_POWER_UPDATER_HPP_
|
||||
#endif // OPENTHREAD_POSIX_CONFIG_CONFIGURATION_FILE_ENABLE
|
||||
#endif // POSIX_PLATFORM_CONFIGURATION_HPP_
|
||||
@@ -399,6 +399,16 @@
|
||||
#define OPENTHREAD_POSIX_CONFIG_PRODUCT_CONFIG_FILE "src/posix/platform/openthread.conf.example"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_POSIX_CONFIG_CONFIGURATION_FILE_ENABLE
|
||||
*
|
||||
* Define as 1 to enable the configuration file support.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_POSIX_CONFIG_CONFIGURATION_FILE_ENABLE
|
||||
#define OPENTHREAD_POSIX_CONFIG_CONFIGURATION_FILE_ENABLE 1
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_POSIX_CONFIG_RCP_TIME_SYNC_INTERVAL
|
||||
*
|
||||
|
||||
@@ -22,3 +22,14 @@ calibrated_power=11,25,1900,112233
|
||||
calibrated_power=11,25,1000,223344
|
||||
calibrated_power=26,26,1500,334455
|
||||
calibrated_power=26,26,700,445566
|
||||
|
||||
|
||||
# The radio supported channel mask that the device is allowed to be on.
|
||||
# supported_channel_mask=<RegulatoryDomain>,<ChannelMask>
|
||||
supported_channel_mask=ETSI,0x7fff800
|
||||
supported_channel_mask=FCC,0x7fff000
|
||||
|
||||
# The radio preferred channel mask that the device prefers to form on.
|
||||
# preferred_channel_mask=<RegulatoryDomain>,<ChannelMask>
|
||||
preferred_channel_mask=ETSI,0x7fff000
|
||||
preferred_channel_mask=FCC,0x7ff7000
|
||||
|
||||
@@ -50,14 +50,15 @@ otError TargetPower::FromString(char *aString)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
char *str;
|
||||
char *psave;
|
||||
|
||||
VerifyOrExit((str = strtok(aString, ",")) != nullptr, error = OT_ERROR_PARSE);
|
||||
VerifyOrExit((str = strtok_r(aString, ",", &psave)) != nullptr, error = OT_ERROR_PARSE);
|
||||
SuccessOrExit(error = Utils::CmdLineParser::ParseAsUint8(str, mChannelStart));
|
||||
|
||||
VerifyOrExit((str = strtok(nullptr, ",")) != nullptr, error = OT_ERROR_PARSE);
|
||||
VerifyOrExit((str = strtok_r(nullptr, ",", &psave)) != nullptr, error = OT_ERROR_PARSE);
|
||||
SuccessOrExit(error = Utils::CmdLineParser::ParseAsUint8(str, mChannelEnd));
|
||||
|
||||
VerifyOrExit((str = strtok(nullptr, ",")) != nullptr, error = OT_ERROR_PARSE);
|
||||
VerifyOrExit((str = strtok_r(nullptr, ",", &psave)) != nullptr, error = OT_ERROR_PARSE);
|
||||
SuccessOrExit(error = Utils::CmdLineParser::ParseAsInt16(str, mTargetPower));
|
||||
|
||||
exit:
|
||||
|
||||
@@ -60,9 +60,9 @@ static ot::Spinel::RadioSpinel<ot::Posix::VendorInterface> sRadioSpinel;
|
||||
"OT_POSIX_RCP_BUS_VENDOR!"
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
#include "power_updater.hpp"
|
||||
static ot::Posix::PowerUpdater sPowerUpdater;
|
||||
#if OPENTHREAD_POSIX_CONFIG_CONFIGURATION_FILE_ENABLE
|
||||
#include "configuration.hpp"
|
||||
static ot::Posix::Configuration sConfig;
|
||||
#endif
|
||||
|
||||
namespace ot {
|
||||
@@ -767,13 +767,41 @@ void otPlatDiagAlarmCallback(otInstance *aInstance) { OT_UNUSED_VARIABLE(aInstan
|
||||
uint32_t otPlatRadioGetSupportedChannelMask(otInstance *aInstance)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
return sRadioSpinel.GetRadioChannelMask(false);
|
||||
|
||||
uint32_t channelMask;
|
||||
|
||||
#if OPENTHREAD_POSIX_CONFIG_CONFIGURATION_FILE_ENABLE
|
||||
if (sConfig.IsValid())
|
||||
{
|
||||
channelMask = sConfig.GetSupportedChannelMask();
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
channelMask = sRadioSpinel.GetRadioChannelMask(false);
|
||||
}
|
||||
|
||||
return channelMask;
|
||||
}
|
||||
|
||||
uint32_t otPlatRadioGetPreferredChannelMask(otInstance *aInstance)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
return sRadioSpinel.GetRadioChannelMask(true);
|
||||
|
||||
uint32_t channelMask;
|
||||
|
||||
#if OPENTHREAD_POSIX_CONFIG_CONFIGURATION_FILE_ENABLE
|
||||
if (sConfig.IsValid())
|
||||
{
|
||||
channelMask = sConfig.GetPreferredChannelMask();
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
channelMask = sRadioSpinel.GetRadioChannelMask(true);
|
||||
}
|
||||
|
||||
return channelMask;
|
||||
}
|
||||
|
||||
otRadioState otPlatRadioGetState(otInstance *aInstance)
|
||||
@@ -870,22 +898,42 @@ otError otPlatRadioSetChannelTargetPower(otInstance *aInstance, uint8_t aChannel
|
||||
otError otPlatRadioSetRegion(otInstance *aInstance, uint16_t aRegionCode)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
#if OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
return sPowerUpdater.SetRegion(aRegionCode);
|
||||
#else
|
||||
return sRadioSpinel.SetRadioRegion(aRegionCode);
|
||||
|
||||
otError error;
|
||||
|
||||
#if OPENTHREAD_POSIX_CONFIG_CONFIGURATION_FILE_ENABLE
|
||||
if (sConfig.IsValid())
|
||||
{
|
||||
error = sConfig.SetRegion(aRegionCode);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
error = sRadioSpinel.SetRadioRegion(aRegionCode);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
otError otPlatRadioGetRegion(otInstance *aInstance, uint16_t *aRegionCode)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
#if OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
*aRegionCode = sPowerUpdater.GetRegion();
|
||||
return OT_ERROR_NONE;
|
||||
#else
|
||||
return sRadioSpinel.GetRadioRegion(aRegionCode);
|
||||
|
||||
otError error;
|
||||
|
||||
#if OPENTHREAD_POSIX_CONFIG_CONFIGURATION_FILE_ENABLE
|
||||
if (sConfig.IsValid())
|
||||
{
|
||||
*aRegionCode = sConfig.GetRegion();
|
||||
error = OT_ERROR_NONE;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
error = sRadioSpinel.GetRadioRegion(aRegionCode);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
|
||||
|
||||
@@ -86,6 +86,9 @@ proc spawn_node {id {type ""} {radio_url ""}} {
|
||||
|
||||
switch -regexp ${type} {
|
||||
{rcp|rcp-cli} {
|
||||
# Sleep 0.2 seconds to ensure that the ot-rcp in the previous test has exited to
|
||||
# avoid the error: "bind(sTxFd): Address already in use"
|
||||
sleep 0.2
|
||||
spawn /usr/bin/env GCOV_PREFIX=$gcov_prefix $::env(OT_POSIX_APPS)/ot-cli $radio_url
|
||||
send "factoryreset\n"
|
||||
wait_for "state" "disabled"
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
#!/usr/bin/expect -f
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
source "tests/scripts/expect/_common.exp"
|
||||
|
||||
spawn_node 1
|
||||
|
||||
send "channel supported\n"
|
||||
expect "0x7fff800"
|
||||
expect_line "Done"
|
||||
|
||||
send "channel preferred\n"
|
||||
expect "0x7fff800"
|
||||
expect_line "Done"
|
||||
|
||||
send "region US\n"
|
||||
expect_line "Done"
|
||||
|
||||
send "channel supported\n"
|
||||
expect "0x7fff000"
|
||||
expect_line "Done"
|
||||
|
||||
send "channel preferred\n"
|
||||
expect "0x7ff7000"
|
||||
expect_line "Done"
|
||||
|
||||
send "region WW\n"
|
||||
expect_line "Done"
|
||||
|
||||
send "channel supported\n"
|
||||
expect "0x7fff800"
|
||||
expect_line "Done"
|
||||
|
||||
send "channel preferred\n"
|
||||
expect "0x7fff000"
|
||||
expect_line "Done"
|
||||
|
||||
dispose_node 1
|
||||
@@ -29,6 +29,10 @@
|
||||
|
||||
source "tests/scripts/expect/_common.exp"
|
||||
|
||||
# backup the configuration file
|
||||
spawn mv src/posix/platform/openthread.conf.example src/posix/platform/openthread.conf.example.backup
|
||||
expect eof
|
||||
|
||||
# allows 11-25 and forbidden 26
|
||||
spawn_node 1 "rcp" "spinel+hdlc+uart://$env(OT_SIMULATION_APPS)/ncp/ot-rcp?max-power-table=11,12,13,14,15,16,17,18,19,20,21,22,23,24,-1,0x7f&forkpty-arg=1"
|
||||
send "channel supported\n"
|
||||
@@ -44,6 +48,11 @@ expect "11 dBm"
|
||||
expect_line "Done"
|
||||
send "\x04"
|
||||
expect eof
|
||||
|
||||
# restore the configuration file
|
||||
spawn mv src/posix/platform/openthread.conf.example.backup src/posix/platform/openthread.conf.example
|
||||
expect eof
|
||||
|
||||
# allows all channels by default
|
||||
spawn_node 1 "rcp" "spinel+hdlc+uart://$env(OT_SIMULATION_APPS)/ncp/ot-rcp?forkpty-arg=1"
|
||||
send "channel supported\n"
|
||||
|
||||
Reference in New Issue
Block a user