[radio] send max power table to radio (#5867)

This change sends the max power table to the radio so that the radio
chip can manage the transmit power by self.
This commit is contained in:
Jiacheng Guo
2020-12-04 08:08:52 -08:00
committed by GitHub
parent 65fb7924df
commit f5a7dc2b9a
13 changed files with 199 additions and 70 deletions
+34 -3
View File
@@ -39,6 +39,7 @@
#include <openthread/platform/radio.h>
#include <openthread/platform/time.h>
#include "common/code_utils.hpp"
#include "utils/code_utils.h"
#include "utils/mac_frame.h"
#include "utils/soft_source_match_table.h"
@@ -113,6 +114,14 @@ static int8_t sTxPower = 0;
static int8_t sCcaEdThresh = -74;
static int8_t sLnaGain = 0;
enum
{
kMinChannel = 11,
kMaxChannel = 26,
};
static int8_t sChannelMaxTransmitPower[kMaxChannel - kMinChannel + 1];
static uint8_t sCurrentChannel = kMinChannel;
static bool sSrcMatchEnabled = false;
#if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
@@ -359,6 +368,11 @@ void platformRadioInit(void)
#else
sTransmitFrame.mInfo.mTxInfo.mIeInfo = NULL;
#endif
for (size_t i = 0; i <= kMaxChannel - kMinChannel; i++)
{
sChannelMaxTransmitPower[i] = OT_RADIO_POWER_INVALID;
}
}
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
@@ -433,6 +447,7 @@ otError otPlatRadioReceive(otInstance *aInstance, uint8_t aChannel)
sState = OT_RADIO_STATE_RECEIVE;
sTxWait = false;
sReceiveFrame.mChannel = aChannel;
sCurrentChannel = aChannel;
}
return error;
@@ -450,8 +465,9 @@ otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame)
if (sState == OT_RADIO_STATE_RECEIVE)
{
error = OT_ERROR_NONE;
sState = OT_RADIO_STATE_TRANSMIT;
error = OT_ERROR_NONE;
sState = OT_RADIO_STATE_TRANSMIT;
sCurrentChannel = aFrame->mChannel;
}
return error;
@@ -945,9 +961,11 @@ otError otPlatRadioGetTransmitPower(otInstance *aInstance, int8_t *aPower)
{
OT_UNUSED_VARIABLE(aInstance);
int8_t maxPower = sChannelMaxTransmitPower[sCurrentChannel - kMinChannel];
assert(aInstance != NULL);
*aPower = sTxPower;
*aPower = sTxPower < maxPower ? sTxPower : maxPower;
return OT_ERROR_NONE;
}
@@ -1155,3 +1173,16 @@ void otPlatRadioSetMacFrameCounter(otInstance *aInstance, uint32_t aMacFrameCoun
sMacFrameCounter = aMacFrameCounter;
}
otError otPlatRadioSetChannelMaxTransmitPower(otInstance *aInstance, uint8_t aChannel, int8_t aMaxPower)
{
OT_UNUSED_VARIABLE(aInstance);
otError error = OT_ERROR_NONE;
VerifyOrExit(aChannel >= kMinChannel && aChannel <= kMaxChannel, error = OT_ERROR_INVALID_ARGS);
sChannelMaxTransmitPower[aChannel - kMinChannel] = aMaxPower;
exit:
return error;
}
+1 -1
View File
@@ -53,7 +53,7 @@ extern "C" {
* @note This number versions both OpenThread platform and user APIs.
*
*/
#define OPENTHREAD_API_VERSION (52)
#define OPENTHREAD_API_VERSION (53)
/**
* @addtogroup api-instance
+19 -3
View File
@@ -72,9 +72,10 @@ enum
OT_RADIO_BIT_RATE = 250000, ///< 2.4 GHz IEEE 802.15.4 (bits per second)
OT_RADIO_BITS_PER_OCTET = 8, ///< Number of bits per octet
OT_RADIO_SYMBOL_TIME = ((OT_RADIO_BITS_PER_OCTET / OT_RADIO_SYMBOLS_PER_OCTET) * 1000000) / OT_RADIO_BIT_RATE,
OT_RADIO_LQI_NONE = 0, ///< LQI measurement not supported
OT_RADIO_RSSI_INVALID = 127, ///< Invalid or unknown RSSI value
OT_RADIO_SYMBOL_TIME = ((OT_RADIO_BITS_PER_OCTET / OT_RADIO_SYMBOLS_PER_OCTET) * 1000000) / OT_RADIO_BIT_RATE,
OT_RADIO_LQI_NONE = 0, ///< LQI measurement not supported
OT_RADIO_RSSI_INVALID = 127, ///< Invalid or unknown RSSI value
OT_RADIO_POWER_INVALID = 127, ///< Invalid or unknown power value
};
/**
@@ -946,6 +947,21 @@ otError otPlatRadioEnableCsl(otInstance *aInstance, uint32_t aCslPeriod, const o
*/
void otPlatRadioUpdateCslSampleTime(otInstance *aInstance, uint32_t aCslSampleTime);
/**
* Set the max transmit power for a specific channel.
*
* @param[in] aInstance The OpenThread instance structure.
* @param[in] aChannel The radio channel.
* @param[in] aMaxPower The max power in dBm, passing OT_RADIO_RSSI_INVALID will disable this channel.
*
* @retval OT_ERROR_NOT_IMPLEMENTED The feature is not implemented
* @retval OT_ERROR_INVALID_ARGS The specified channel is not valid.
* @retval OT_ERROR_FAILED Other platform specific errors.
* @retval OT_ERROR_NONE Successfully set max transmit poewr.
*
*/
otError otPlatRadioSetChannelMaxTransmitPower(otInstance *aInstance, uint8_t aChannel, int8_t aMaxPower);
/**
* @}
*
@@ -26,27 +26,27 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef OT_POSIX_PLATFORM_MAX_POWER_TABLE_HPP_
#define OT_POSIX_PLATFORM_MAX_POWER_TABLE_HPP_
#ifndef OT_CORE_RADIO_MAX_POWER_TABLE_HPP_
#define OT_CORE_RADIO_MAX_POWER_TABLE_HPP_
#include "core/radio/radio.hpp"
#include "openthread/platform/radio.h"
namespace ot {
namespace Posix {
class MaxPowerTable
{
public:
static const int8_t kPowerDefault = 30; ///< Default power 1 watt (30 dBm).
MaxPowerTable(void) { memset(mPowerTable, kPowerForbidden, sizeof(mPowerTable)); }
MaxPowerTable(void) { memset(mPowerTable, kPowerDefault, sizeof(mPowerTable)); }
/**
* This method gets the max allowed transmit power of channel @p aChannel.
*
* @params[in] aChannel The radio channel number.
*
* @returns The max allowed transmit power in dBm.
* @returns The max supported transmit power in dBm.
*
*/
int8_t GetTransmitPower(uint8_t aChannel) const { return mPowerTable[aChannel - Radio::kChannelMin]; }
@@ -55,24 +55,22 @@ public:
* This method sets the max allowed transmit power of channel @p aChannel.
*
* @params[in] aChannel The radio channel number.
* @params[in] aPower The max allowed transmit power in dBm.
* @params[in] aPower The max supported transmit power in dBm.
*
*/
void SetTransmitPower(uint8_t aChannel, int8_t aPower) { mPowerTable[aChannel - Radio::kChannelMin] = aPower; }
/**
* This method gets the allowed channel masks.
*
* All channels of max power value of 0x7f is considered forbidden.
* This method gets the supported channel masks.
*
*/
uint32_t GetAllowedChannelMask(void) const
uint32_t GetSupportedChannelMask(void) const
{
uint32_t channelMask = 0;
for (uint8_t i = Radio::kChannelMin; i <= Radio::kChannelMax; ++i)
{
if (mPowerTable[i - Radio::kChannelMin] != kPowerForbidden)
if (mPowerTable[i - Radio::kChannelMin] != OT_RADIO_POWER_INVALID)
{
channelMask |= (1 << i);
}
@@ -82,12 +80,9 @@ public:
}
private:
static const int8_t kPowerForbidden = 0x7f;
int8_t mPowerTable[Radio::kChannelMax - Radio::kChannelMin + 1];
};
} // namespace Posix
} // namespace ot
#endif // OT_POSIX_PLATFORM_MAX_POWER_TABLE_HPP_
#endif // OT_CORE_RADIO_MAX_POWER_TABLE_HPP_
+9
View File
@@ -181,3 +181,12 @@ OT_TOOL_WEAK otError otPlatRadioSetFemLnaGain(otInstance *aInstance, int8_t aGai
return OT_ERROR_NOT_IMPLEMENTED;
}
OT_TOOL_WEAK otError otPlatRadioSetChannelMaxTransmitPower(otInstance *aInstance, uint8_t aChannel, int8_t aMaxPower)
{
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aChannel);
OT_UNUSED_VARIABLE(aMaxPower);
return OT_ERROR_NOT_IMPLEMENTED;
}
+15
View File
@@ -39,6 +39,7 @@
#include "openthread-spinel-config.h"
#include "spinel.h"
#include "spinel_interface.hpp"
#include "core/radio/max_power_table.hpp"
#include "ncp/ncp_config.h"
namespace ot {
@@ -704,6 +705,18 @@ public:
*/
uint32_t GetBusSpeed(void) const;
/**
* This method sets the max transmit power.
*
* @param[in] aChannel The radio channel.
* @param[in] aPower The max transmit power in dBm.
*
* @retval OT_ERROR_NONE Succesfully set the max transmit power.
* @retval OT_ERROR_INVALID_ARGS Channel is not in valid range.
*
*/
otError SetChannelMaxTransmitPower(uint8_t aChannel, int8_t aPower);
private:
enum
{
@@ -968,6 +981,8 @@ private:
uint64_t mTxRadioEndUs;
uint64_t mRadioTimeRecalcStart; ///< When to recalculate RCP time offset.
int64_t mRadioTimeOffset; ///< Time difference with estimated RCP time minus host time.
MaxPowerTable mMaxPowerTable;
};
} // namespace Spinel
+31
View File
@@ -52,6 +52,7 @@
#include "lib/spinel/spinel_decoder.hpp"
#include "meshcop/dataset.hpp"
#include "meshcop/meshcop_tlvs.hpp"
#include "radio/radio.hpp"
#ifndef MS_PER_S
#define MS_PER_S 1000
@@ -2047,6 +2048,8 @@ uint32_t RadioSpinel<InterfaceType, ProcessContextType>::GetRadioChannelMask(boo
maskLength -= static_cast<spinel_size_t>(unpacked);
}
channelMask &= mMaxPowerTable.GetSupportedChannelMask();
exit:
LogIfFail("Get radio channel mask failed", error);
return channelMask;
@@ -2289,9 +2292,37 @@ void RadioSpinel<InterfaceType, ProcessContextType>::RestoreProperties(void)
SuccessOrDie(Set(SPINEL_PROP_PHY_FEM_LNA_GAIN, SPINEL_DATATYPE_INT8_S, mFemLnaGain));
}
for (uint8_t channel = Radio::kChannelMin; channel <= Radio::kChannelMax; channel++)
{
int8_t power = mMaxPowerTable.GetTransmitPower(channel);
if (power != OT_RADIO_POWER_INVALID)
{
// Some old RCPs doesn't support max transmit power
otError error = SetChannelMaxTransmitPower(channel, power);
if (error != OT_ERROR_NONE && error != OT_ERROR_NOT_FOUND)
{
DieNow(OT_EXIT_FAILURE);
}
}
}
CalcRcpTimeOffset();
}
#endif // OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
template <typename InterfaceType, typename ProcessContextType>
otError RadioSpinel<InterfaceType, ProcessContextType>::SetChannelMaxTransmitPower(uint8_t aChannel, int8_t aMaxPower)
{
otError error = OT_ERROR_NONE;
VerifyOrExit(aChannel >= Radio::kChannelMin && aChannel <= Radio::kChannelMax, error = OT_ERROR_INVALID_ARGS);
mMaxPowerTable.SetTransmitPower(aChannel, aMaxPower);
error = Set(SPINEL_PROP_PHY_CHAN_MAX_POWER, SPINEL_DATATYPE_UINT8_S SPINEL_DATATYPE_INT8_S, aChannel, aMaxPower);
exit:
return error;
}
} // namespace Spinel
} // namespace ot
+4
View File
@@ -1399,6 +1399,10 @@ const char *spinel_prop_key_to_cstr(spinel_prop_key_t prop_key)
ret = "PHY_CHAN_PREFERRED";
break;
case SPINEL_PROP_PHY_CHAN_MAX_POWER:
ret = "PHY_CHAN_MAX_POWER";
break;
case SPINEL_PROP_JAM_DETECT_ENABLE:
ret = "JAM_DETECT_ENABLE";
break;
+10 -2
View File
@@ -377,7 +377,7 @@
* Please see section "Spinel definition compatibility guideline" for more details.
*
*/
#define SPINEL_RCP_API_VERSION 1
#define SPINEL_RCP_API_VERSION 2
/**
* @def SPINEL_MIN_HOST_SUPPORTED_RCP_API_VERSION
@@ -1568,7 +1568,15 @@ enum
SPINEL_PROP_PHY_PCAP_ENABLED = SPINEL_PROP_PHY__BEGIN + 8, ///< [b]
SPINEL_PROP_PHY_CHAN_PREFERRED = SPINEL_PROP_PHY__BEGIN + 9, ///< [A(C)]
SPINEL_PROP_PHY_FEM_LNA_GAIN = SPINEL_PROP_PHY__BEGIN + 10, ///< dBm [c]
SPINEL_PROP_PHY__END = 0x30,
/// Signal the max power for a channel
/** Format: `Cc`
*
* First byte is the channel then the max transmit power, write-only.
*/
SPINEL_PROP_PHY_CHAN_MAX_POWER = SPINEL_PROP_PHY__BEGIN + 11,
SPINEL_PROP_PHY__END = 0x30,
SPINEL_PROP_PHY_EXT__BEGIN = 0x1200,
+14
View File
@@ -2238,6 +2238,20 @@ exit:
return error;
}
template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_PHY_CHAN_MAX_POWER>(void)
{
uint8_t channel;
int8_t maxPower;
otError error = OT_ERROR_NONE;
SuccessOrExit(error = mDecoder.ReadUint8(channel));
SuccessOrExit(error = mDecoder.ReadInt8(maxPower));
error = otPlatRadioSetChannelMaxTransmitPower(mInstance, channel, maxPower);
exit:
return error;
}
template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_DEBUG_TEST_ASSERT>(void)
{
#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+1
View File
@@ -368,6 +368,7 @@ NcpBase::PropertyHandler NcpBase::FindSetPropertyHandler(spinel_prop_key_t aKey)
OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_PHY_PCAP_ENABLED),
#endif
OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_PHY_FEM_LNA_GAIN),
OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_PHY_CHAN_MAX_POWER),
OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_MAC_SCAN_STATE),
OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_MAC_SCAN_MASK),
OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_MAC_SCAN_PERIOD),
+46 -46
View File
@@ -51,12 +51,6 @@ static ot::Spinel::RadioSpinel<ot::Posix::SpiInterface, RadioProcessContext> sRa
#error "OPENTHREAD_POSIX_CONFIG_RCP_BUS only allows OT_POSIX_RCP_BUS_UART and OT_POSIX_RCP_BUS_SPI!"
#endif
#if OPENTHREAD_POSIX_CONFIG_MAX_POWER_TABLE_ENABLE
#include "posix/platform/max_power_table.hpp"
static ot::Posix::MaxPowerTable sMaxPowerTable;
#endif
void otPlatRadioGetIeeeEui64(otInstance *aInstance, uint8_t *aIeeeEui64)
{
OT_UNUSED_VARIABLE(aInstance);
@@ -101,30 +95,7 @@ void platformRadioInit(otUrl *aRadioUrl)
bool restoreDataset = (radioUrl.GetValue("ncp-dataset") != nullptr);
const char * parameterValue;
#if OPENTHREAD_POSIX_CONFIG_MAX_POWER_TABLE_ENABLE
uint8_t channel = ot::Radio::kChannelMin;
int8_t power = ot::Posix::MaxPowerTable::kPowerDefault;
const char *maxPowerTable = radioUrl.GetValue("max-power-table");
if (maxPowerTable != nullptr)
{
const char *str = nullptr;
for (str = strtok(const_cast<char *>(maxPowerTable), ","); str != nullptr && channel <= ot::Radio::kChannelMax;
str = strtok(nullptr, ","))
{
power = static_cast<int8_t>(strtol(str, nullptr, 0));
sMaxPowerTable.SetTransmitPower(channel++, power);
}
VerifyOrDie(str == nullptr, OT_EXIT_INVALID_ARGUMENTS);
}
// Use the last power if omitted.
while (channel <= ot::Radio::kChannelMax)
{
sMaxPowerTable.SetTransmitPower(channel, power);
++channel;
}
const char *maxPowerTable;
#endif
SuccessOrDie(sRadioSpinel.GetSpinelInterface().Init(radioUrl));
@@ -147,6 +118,43 @@ void platformRadioInit(otUrl *aRadioUrl)
VerifyOrDie(INT8_MIN <= ccaThreshold && ccaThreshold <= INT8_MAX, OT_EXIT_INVALID_ARGUMENTS);
SuccessOrDie(sRadioSpinel.SetCcaEnergyDetectThreshold(static_cast<int8_t>(ccaThreshold)));
}
#if OPENTHREAD_POSIX_CONFIG_MAX_POWER_TABLE_ENABLE
maxPowerTable = radioUrl.GetValue("max-power-table");
if (maxPowerTable != nullptr)
{
constexpr int8_t kPowerDefault = 30; // Default power 1 watt (30 dBm).
const char * str = nullptr;
uint8_t channel = ot::Radio::kChannelMin;
int8_t power = kPowerDefault;
otError error;
for (str = strtok(const_cast<char *>(maxPowerTable), ","); str != nullptr && channel <= ot::Radio::kChannelMax;
str = strtok(nullptr, ","))
{
power = static_cast<int8_t>(strtol(str, nullptr, 0));
error = sRadioSpinel.SetChannelMaxTransmitPower(channel, power);
if (error != OT_ERROR_NONE && error != OT_ERROR_NOT_FOUND)
{
DieNow(OT_ERROR_FAILED);
}
++channel;
}
// Use the last power if omitted.
while (channel <= ot::Radio::kChannelMax)
{
error = sRadioSpinel.SetChannelMaxTransmitPower(channel, power);
if (error != OT_ERROR_NONE && error != OT_ERROR_NOT_FOUND)
{
DieNow(OT_ERROR_FAILED);
}
++channel;
}
VerifyOrDie(str == nullptr, OT_EXIT_INVALID_ARGUMENTS);
}
#endif // OPENTHREAD_POSIX_CONFIG_MAX_POWER_TABLE_ENABLE
}
void platformRadioDeinit(void)
@@ -183,12 +191,6 @@ otError otPlatRadioReceive(otInstance *aInstance, uint8_t aChannel)
otError error;
#if OPENTHREAD_POSIX_CONFIG_MAX_POWER_TABLE_ENABLE
if (sRadioSpinel.GetChannel() != aChannel)
{
SuccessOrExit(error = otPlatRadioSetTransmitPower(aInstance, sMaxPowerTable.GetTransmitPower(aChannel)));
}
#endif
SuccessOrExit(error = sRadioSpinel.Receive(aChannel));
exit:
@@ -495,21 +497,13 @@ void otPlatDiagAlarmCallback(otInstance *aInstance)
uint32_t otPlatRadioGetSupportedChannelMask(otInstance *aInstance)
{
OT_UNUSED_VARIABLE(aInstance);
return
#if OPENTHREAD_POSIX_CONFIG_MAX_POWER_TABLE_ENABLE
sMaxPowerTable.GetAllowedChannelMask() &
#endif
sRadioSpinel.GetRadioChannelMask(false);
return sRadioSpinel.GetRadioChannelMask(false);
}
uint32_t otPlatRadioGetPreferredChannelMask(otInstance *aInstance)
{
OT_UNUSED_VARIABLE(aInstance);
return
#if OPENTHREAD_POSIX_CONFIG_MAX_POWER_TABLE_ENABLE
sMaxPowerTable.GetAllowedChannelMask() &
#endif
sRadioSpinel.GetRadioChannelMask(true);
return sRadioSpinel.GetRadioChannelMask(true);
}
otRadioState otPlatRadioGetState(otInstance *aInstance)
@@ -546,3 +540,9 @@ uint32_t otPlatRadioGetBusSpeed(otInstance *aInstance)
OT_UNUSED_VARIABLE(aInstance);
return sRadioSpinel.GetBusSpeed();
}
otError otPlatRadioSetChannelMaxTransmitPower(otInstance *aInstance, uint8_t aChannel, int8_t aMaxPower)
{
OT_UNUSED_VARIABLE(aInstance);
return sRadioSpinel.SetChannelMaxTransmitPower(aChannel, aMaxPower);
}
@@ -37,6 +37,11 @@ expect "Done"
send "channel preferred\n"
expect "0x3fff800"
expect "Done"
send "txpower 20\n"
expect "Done"
send "txpower\n"
expect "11 dBm"
expect "Done"
send "\x04"
expect eof
# allows all channels by default