mirror of
https://github.com/espressif/openthread.git
synced 2026-06-05 21:14:49 +00:00
[posix] add power calibration support (#8293)
The actual output power of the Thread device may be determined by both the Thread radio chip and the FEM. Consider the output power error of the Thread radio chip and the gain error of the FEM, the actual output power is inconsistent with the expected output power. To guarantee that the actual output power is accurate and meet the regulatory requirements, the output power should be calibrated in the factory if the output power is not accurate. This commit contains the following changes: - Adds a power calibration implementation - Adds a config file to configure the target power for different countries - Adds a tool for the factory to persist the power calibration data
This commit is contained in:
@@ -65,6 +65,10 @@ jobs:
|
||||
ulimit -c unlimited
|
||||
./script/test prepare_coredump_upload
|
||||
OT_OPTIONS='-DOT_READLINE=OFF -DOT_FULL_LOGS=ON -DOT_LOG_OUTPUT=PLATFORM_DEFINED' VIRTUAL_TIME=0 OT_NODE_TYPE=rcp ./script/test build expect
|
||||
- name: Run ot-fct
|
||||
run: |
|
||||
OT_CMAKE_NINJA_TARGET="ot-fct" script/cmake-build posix
|
||||
tests/scripts/expect/ot-fct.exp
|
||||
- name: Check Crash
|
||||
if: ${{ failure() }}
|
||||
run: |
|
||||
|
||||
+41
@@ -373,6 +373,7 @@ LOCAL_SRC_FILES := \
|
||||
src/core/utils/otns.cpp \
|
||||
src/core/utils/parse_cmdline.cpp \
|
||||
src/core/utils/ping_sender.cpp \
|
||||
src/core/utils/power_calibration.cpp \
|
||||
src/core/utils/slaac_address.cpp \
|
||||
src/core/utils/srp_client_buffers.cpp \
|
||||
src/lib/hdlc/hdlc.cpp \
|
||||
@@ -384,6 +385,7 @@ LOCAL_SRC_FILES := \
|
||||
src/posix/platform/alarm.cpp \
|
||||
src/posix/platform/backbone.cpp \
|
||||
src/posix/platform/backtrace.cpp \
|
||||
src/posix/platform/config_file.cpp \
|
||||
src/posix/platform/daemon.cpp \
|
||||
src/posix/platform/entropy.cpp \
|
||||
src/posix/platform/firewall.cpp \
|
||||
@@ -395,6 +397,8 @@ LOCAL_SRC_FILES := \
|
||||
src/posix/platform/misc.cpp \
|
||||
src/posix/platform/multicast_routing.cpp \
|
||||
src/posix/platform/netif.cpp \
|
||||
src/posix/platform/power.cpp \
|
||||
src/posix/platform/power_updater.cpp \
|
||||
src/posix/platform/radio.cpp \
|
||||
src/posix/platform/radio_url.cpp \
|
||||
src/posix/platform/settings.cpp \
|
||||
@@ -656,6 +660,43 @@ LOCAL_SRC_FILES := src/posix/client.cpp
|
||||
include $(BUILD_EXECUTABLE)
|
||||
endif # ($(USE_OTBR_DAEMON), 1)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := ot-fct
|
||||
LOCAL_MODULE_TAGS := eng
|
||||
|
||||
LOCAL_CPPFLAGS := \
|
||||
-std=c++11 \
|
||||
-pedantic-errors \
|
||||
$(NULL)
|
||||
|
||||
LOCAL_CFLAGS := \
|
||||
$(OPENTHREAD_PUBLIC_CFLAGS) \
|
||||
$(OPENTHREAD_PRIVATE_CFLAGS) \
|
||||
$(OPENTHREAD_PROJECT_CFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
LOCAL_C_INCLUDES := \
|
||||
$(OPENTHREAD_PROJECT_INCLUDES) \
|
||||
$(LOCAL_PATH)/include \
|
||||
$(LOCAL_PATH)/src/ \
|
||||
$(LOCAL_PATH)/src/core \
|
||||
$(LOCAL_PATH)/src/posix/platform \
|
||||
$(NULL)
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
src/core/common/string.cpp \
|
||||
src/core/utils/parse_cmdline.cpp \
|
||||
src/lib/platform/exit_code.c \
|
||||
src/posix/platform/config_file.cpp \
|
||||
src/posix/platform/power.cpp \
|
||||
tools/ot-fct/cli.cpp \
|
||||
tools/ot-fct/logging.cpp \
|
||||
tools/ot-fct/main.cpp \
|
||||
$(NULL)
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
ifneq ($(OPENTHREAD_PROJECT_ANDROID_MK),)
|
||||
include $(OPENTHREAD_PROJECT_ANDROID_MK)
|
||||
endif
|
||||
|
||||
@@ -209,6 +209,7 @@ if(OT_PLATFORM STREQUAL "simulation")
|
||||
endif()
|
||||
|
||||
add_subdirectory(tests)
|
||||
add_subdirectory(tools)
|
||||
|
||||
add_custom_target(print-ot-config ALL
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
|
||||
@@ -265,4 +265,24 @@
|
||||
#define OPENTHREAD_CONFIG_DETERMINISTIC_ECDSA_ENABLE 1
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_POWER_CALIBRATION_ENABLE
|
||||
*
|
||||
* Define as 1 to enable power calibration support.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_POWER_CALIBRATION_ENABLE
|
||||
#define OPENTHREAD_CONFIG_POWER_CALIBRATION_ENABLE 1
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
*
|
||||
* Define as 1 to enable platform power calibration support.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
#define OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE 1
|
||||
#endif
|
||||
|
||||
#endif // OPENTHREAD_CORE_SIMULATION_CONFIG_H_
|
||||
|
||||
@@ -53,7 +53,7 @@ extern "C" {
|
||||
* @note This number versions both OpenThread platform and user APIs.
|
||||
*
|
||||
*/
|
||||
#define OPENTHREAD_API_VERSION (270)
|
||||
#define OPENTHREAD_API_VERSION (271)
|
||||
|
||||
/**
|
||||
* @addtogroup api-instance
|
||||
|
||||
@@ -1144,6 +1144,100 @@ otError otPlatRadioConfigureEnhAckProbing(otInstance *aInstance,
|
||||
otShortAddress aShortAddress,
|
||||
const otExtAddress *aExtAddress);
|
||||
|
||||
/**
|
||||
* Add a calibrated power of the specified channel to the power calibration table.
|
||||
*
|
||||
* @note This API is an optional radio platform API. It's up to the platform layer to implement it.
|
||||
*
|
||||
* The @p aActualPower is the actual measured output power when the parameters of the radio hardware modules
|
||||
* are set to the @p aRawPowerSetting.
|
||||
*
|
||||
* The raw power setting is an opaque byte array. OpenThread doesn't define the format of the raw power setting.
|
||||
* Its format is radio hardware related and it should be defined by the developers in the platform radio driver.
|
||||
* For example, if the radio hardware contains both the radio chip and the FEM chip, the raw power setting can be
|
||||
* a combination of the radio power register and the FEM gain value.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance structure.
|
||||
* @param[in] aChannel The radio channel.
|
||||
* @param[in] aActualPower The actual power in 0.01dBm.
|
||||
* @param[in] aRawPowerSetting A pointer to the raw power setting byte array.
|
||||
* @param[in] aRawPowerSettingLength The length of the @p aRawPowerSetting.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully added the calibrated power to the power calibration table.
|
||||
* @retval OT_ERROR_NO_BUFS No available entry in the power calibration table.
|
||||
* @retval OT_ERROR_INVALID_ARGS The @p aChannel, @p aActualPower or @p aRawPowerSetting is invalid or the
|
||||
* @p aActualPower already exists in the power calibration table.
|
||||
* @retval OT_ERROR_NOT_IMPLEMENTED This feature is not implemented.
|
||||
*
|
||||
*/
|
||||
otError otPlatRadioAddCalibratedPower(otInstance *aInstance,
|
||||
uint8_t aChannel,
|
||||
int16_t aActualPower,
|
||||
const uint8_t *aRawPowerSetting,
|
||||
uint16_t aRawPowerSettingLength);
|
||||
|
||||
/**
|
||||
* Clear all calibrated powers from the power calibration table.
|
||||
*
|
||||
* @note This API is an optional radio platform API. It's up to the platform layer to implement it.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance structure.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully cleared all calibrated powers from the power calibration table.
|
||||
* @retval OT_ERROR_NOT_IMPLEMENTED This feature is not implemented.
|
||||
*
|
||||
*/
|
||||
otError otPlatRadioClearCalibratedPowers(otInstance *aInstance);
|
||||
|
||||
/**
|
||||
* Set the target power for the given channel.
|
||||
*
|
||||
* @note This API is an optional radio platform API. It's up to the platform layer to implement it.
|
||||
* If this API is implemented, the function `otPlatRadioSetTransmitPower()` should be disabled.
|
||||
*
|
||||
* The radio driver should set the actual output power to be less than or equal to the target power and as close
|
||||
* as possible to the target power.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance structure.
|
||||
* @param[in] aChannel The radio channel.
|
||||
* @param[in] aTargetPower The target power in 0.01dBm. Passing `INT16_MAX` will disable this channel to use the
|
||||
* target power.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully set the target power.
|
||||
* @retval OT_ERROR_INVALID_ARGS The @p aChannel or @p aTargetPower is invalid.
|
||||
* @retval OT_ERROR_NOT_IMPLEMENTED The feature is not implemented.
|
||||
*
|
||||
*/
|
||||
otError otPlatRadioSetChannelTargetPower(otInstance *aInstance, uint8_t aChannel, int16_t aTargetPower);
|
||||
|
||||
/**
|
||||
* Get the raw power setting for the given channel.
|
||||
*
|
||||
* @note OpenThread `src/core/utils` implements a default implementation of the API `otPlatRadioAddCalibratedPower()`,
|
||||
* `otPlatRadioClearCalibratedPowers()` and `otPlatRadioSetChannelTargetPower()`. This API is provided by
|
||||
* the default implementation to get the raw power setting for the given channel. If the platform doesn't
|
||||
* use the default implementation, it can ignore this API.
|
||||
*
|
||||
* Platform radio layer should parse the raw power setting based on the radio layer defined format and set the
|
||||
* parameters of each radio hardware module.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance structure.
|
||||
* @param[in] aChannel The radio channel.
|
||||
* @param[out] aRawPowerSetting A pointer to the raw power setting byte array.
|
||||
* @param[in,out] aRawPowerSettingLength On input, a pointer to the size of @p aRawPowerSetting.
|
||||
* On output, a pointer to the length of the raw power setting data.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully got the target power.
|
||||
* @retval OT_ERROR_INVALID_ARGS The @p aChannel is invalid, @p aRawPowerSetting or @p aRawPowerSettingLength is NULL
|
||||
* or @aRawPowerSettingLength is too short.
|
||||
* @retval OT_ERROR_NOT_FOUND The raw power setting for the @p aChannel was not found.
|
||||
*
|
||||
*/
|
||||
extern otError otPlatRadioGetRawPowerSetting(otInstance *aInstance,
|
||||
uint8_t aChannel,
|
||||
uint8_t *aRawPowerSetting,
|
||||
uint16_t *aRawPowerSettingLength);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
|
||||
@@ -706,6 +706,8 @@ openthread_core_files = [
|
||||
"utils/parse_cmdline.hpp",
|
||||
"utils/ping_sender.cpp",
|
||||
"utils/ping_sender.hpp",
|
||||
"utils/power_calibration.cpp",
|
||||
"utils/power_calibration.hpp",
|
||||
"utils/slaac_address.cpp",
|
||||
"utils/slaac_address.hpp",
|
||||
"utils/srp_client_buffers.cpp",
|
||||
@@ -745,6 +747,7 @@ openthread_radio_sources = [
|
||||
"radio/radio_platform.cpp",
|
||||
"thread/link_quality.cpp",
|
||||
"utils/parse_cmdline.cpp",
|
||||
"utils/power_calibration.cpp",
|
||||
]
|
||||
|
||||
header_pattern = [
|
||||
@@ -791,6 +794,7 @@ source_set("libopenthread_core_config") {
|
||||
"config/parent_search.h",
|
||||
"config/ping_sender.h",
|
||||
"config/platform.h",
|
||||
"config/power_calibration.h",
|
||||
"config/radio_link.h",
|
||||
"config/sntp_client.h",
|
||||
"config/srp_client.h",
|
||||
|
||||
@@ -240,6 +240,7 @@ set(COMMON_SOURCES
|
||||
utils/otns.cpp
|
||||
utils/parse_cmdline.cpp
|
||||
utils/ping_sender.cpp
|
||||
utils/power_calibration.cpp
|
||||
utils/slaac_address.cpp
|
||||
utils/srp_client_buffers.cpp
|
||||
)
|
||||
@@ -276,6 +277,7 @@ set(RADIO_COMMON_SOURCES
|
||||
radio/radio_platform.cpp
|
||||
thread/link_quality.cpp
|
||||
utils/parse_cmdline.cpp
|
||||
utils/power_calibration.cpp
|
||||
)
|
||||
|
||||
set(OT_VENDOR_EXTENSION "" CACHE STRING "specify a C++ source file built as part of OpenThread core library")
|
||||
|
||||
@@ -330,6 +330,7 @@ SOURCES_COMMON = \
|
||||
utils/otns.cpp \
|
||||
utils/parse_cmdline.cpp \
|
||||
utils/ping_sender.cpp \
|
||||
utils/power_calibration.cpp \
|
||||
utils/slaac_address.cpp \
|
||||
utils/srp_client_buffers.cpp \
|
||||
$(NULL)
|
||||
@@ -366,6 +367,7 @@ RADIO_SOURCES_COMMON = \
|
||||
radio/radio_platform.cpp \
|
||||
thread/link_quality.cpp \
|
||||
utils/parse_cmdline.cpp \
|
||||
utils/power_calibration.cpp \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DIST = \
|
||||
@@ -514,6 +516,7 @@ HEADERS_COMMON = \
|
||||
config/parent_search.h \
|
||||
config/ping_sender.h \
|
||||
config/platform.h \
|
||||
config/power_calibration.h \
|
||||
config/radio_link.h \
|
||||
config/sntp_client.h \
|
||||
config/srp_client.h \
|
||||
@@ -649,6 +652,7 @@ HEADERS_COMMON = \
|
||||
utils/otns.hpp \
|
||||
utils/parse_cmdline.hpp \
|
||||
utils/ping_sender.hpp \
|
||||
utils/power_calibration.hpp \
|
||||
utils/slaac_address.hpp \
|
||||
utils/srp_client_buffers.hpp \
|
||||
$(NULL)
|
||||
|
||||
@@ -236,6 +236,9 @@ Instance::Instance(void)
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_DIAG_ENABLE
|
||||
, mDiags(*this)
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_POWER_CALIBRATION_ENABLE && OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
, mPowerCalibration(*this)
|
||||
#endif
|
||||
, mIsInitialized(false)
|
||||
{
|
||||
|
||||
@@ -60,6 +60,7 @@
|
||||
#include "mac/link_raw.hpp"
|
||||
#include "radio/radio.hpp"
|
||||
#include "utils/otns.hpp"
|
||||
#include "utils/power_calibration.hpp"
|
||||
|
||||
#if OPENTHREAD_FTD || OPENTHREAD_MTD
|
||||
#include "backbone_router/backbone_tmf.hpp"
|
||||
@@ -618,6 +619,9 @@ private:
|
||||
#if OPENTHREAD_CONFIG_DIAG_ENABLE
|
||||
FactoryDiags::Diags mDiags;
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_POWER_CALIBRATION_ENABLE && OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
Utils::PowerCalibration mPowerCalibration;
|
||||
#endif
|
||||
|
||||
bool mIsInitialized;
|
||||
|
||||
@@ -960,6 +964,10 @@ template <> inline Extension::ExtensionBase &Instance::Get(void) { return mExten
|
||||
template <> inline FactoryDiags::Diags &Instance::Get(void) { return mDiags; }
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_POWER_CALIBRATION_ENABLE && OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
template <> inline Utils::PowerCalibration &Instance::Get(void) { return mPowerCalibration; }
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
|
||||
@@ -158,6 +158,16 @@
|
||||
#define OPENTHREAD_CONFIG_PLATFORM_MAC_KEYS_EXPORTABLE_ENABLE 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
*
|
||||
* Define as 1 to enable platform power calibration support.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
#define OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE 0
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_SUPPORT
|
||||
#if (!defined(OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_PAGE) || \
|
||||
!defined(OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_MIN) || \
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file includes compile-time configurations for power calibration module.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_POWER_CALIBRATION_H_
|
||||
#define CONFIG_POWER_CALIBRATION_H_
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_POWER_CALIBRATION_ENABLE
|
||||
*
|
||||
* Define as 1 to enable power calibration support.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_POWER_CALIBRATION_ENABLE
|
||||
#define OPENTHREAD_CONFIG_POWER_CALIBRATION_ENABLE 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_POWER_CALIBRATION_RAW_POWER_SETTING_SIZE
|
||||
*
|
||||
* The size of the raw power setting byte array.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_POWER_CALIBRATION_RAW_POWER_SETTING_SIZE
|
||||
#define OPENTHREAD_CONFIG_POWER_CALIBRATION_RAW_POWER_SETTING_SIZE 16
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_POWER_CALIBRATION_NUM_CALIBRATED_POWER_ENTRIES
|
||||
*
|
||||
* The number of the calibrated power entries for each channel.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_POWER_CALIBRATION_NUM_CALIBRATED_POWER_ENTRIES
|
||||
#define OPENTHREAD_CONFIG_POWER_CALIBRATION_NUM_CALIBRATED_POWER_ENTRIES 6
|
||||
#endif
|
||||
|
||||
#endif // CONFIG_POWER_CALIBRATION_H_
|
||||
@@ -89,6 +89,7 @@
|
||||
#include "config/parent_search.h"
|
||||
#include "config/ping_sender.h"
|
||||
#include "config/platform.h"
|
||||
#include "config/power_calibration.h"
|
||||
#include "config/radio_link.h"
|
||||
#include "config/sntp_client.h"
|
||||
#include "config/srp_client.h"
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Copyright (c) 2022, 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 "power_calibration.hpp"
|
||||
|
||||
#if OPENTHREAD_CONFIG_POWER_CALIBRATION_ENABLE && OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
|
||||
#include "common/as_core_type.hpp"
|
||||
#include "common/code_utils.hpp"
|
||||
#include "common/locator_getters.hpp"
|
||||
|
||||
namespace ot {
|
||||
namespace Utils {
|
||||
|
||||
PowerCalibration::PowerCalibration(Instance &aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
, mLastChannel(0)
|
||||
, mCalibratedPowerIndex(kInvalidIndex)
|
||||
{
|
||||
for (int16_t &targetPower : mTargetPowerTable)
|
||||
{
|
||||
targetPower = kInvalidPower;
|
||||
}
|
||||
}
|
||||
|
||||
void PowerCalibration::CalibratedPowerEntry::Init(int16_t aActualPower,
|
||||
const uint8_t *aRawPowerSetting,
|
||||
uint16_t aRawPowerSettingLength)
|
||||
{
|
||||
AssertPointerIsNotNull(aRawPowerSetting);
|
||||
OT_ASSERT(aRawPowerSettingLength <= kMaxRawPowerSettingSize);
|
||||
|
||||
mActualPower = aActualPower;
|
||||
mLength = aRawPowerSettingLength;
|
||||
memcpy(mSettings, aRawPowerSetting, aRawPowerSettingLength);
|
||||
}
|
||||
|
||||
Error PowerCalibration::CalibratedPowerEntry::GetRawPowerSetting(uint8_t *aRawPowerSetting,
|
||||
uint16_t *aRawPowerSettingLength)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
|
||||
AssertPointerIsNotNull(aRawPowerSetting);
|
||||
AssertPointerIsNotNull(aRawPowerSettingLength);
|
||||
VerifyOrExit(*aRawPowerSettingLength >= mLength, error = kErrorInvalidArgs);
|
||||
|
||||
memcpy(aRawPowerSetting, mSettings, mLength);
|
||||
*aRawPowerSettingLength = mLength;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
Error PowerCalibration::AddCalibratedPower(uint8_t aChannel,
|
||||
int16_t aActualPower,
|
||||
const uint8_t *aRawPowerSetting,
|
||||
uint16_t aRawPowerSettingLength)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
CalibratedPowerEntry entry;
|
||||
uint8_t chIndex;
|
||||
|
||||
AssertPointerIsNotNull(aRawPowerSetting);
|
||||
VerifyOrExit(IsChannelValid(aChannel) && aRawPowerSettingLength <= CalibratedPowerEntry::kMaxRawPowerSettingSize,
|
||||
error = kErrorInvalidArgs);
|
||||
|
||||
chIndex = aChannel - Radio::kChannelMin;
|
||||
VerifyOrExit(!mCalibratedPowerTables[chIndex].ContainsMatching(aActualPower), error = kErrorInvalidArgs);
|
||||
VerifyOrExit(!mCalibratedPowerTables[chIndex].IsFull(), error = kErrorNoBufs);
|
||||
|
||||
entry.Init(aActualPower, aRawPowerSetting, aRawPowerSettingLength);
|
||||
SuccessOrExit(error = mCalibratedPowerTables[chIndex].PushBack(entry));
|
||||
|
||||
if (aChannel == mLastChannel)
|
||||
{
|
||||
mCalibratedPowerIndex = kInvalidIndex;
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void PowerCalibration::ClearCalibratedPowers(void)
|
||||
{
|
||||
for (CalibratedPowerTable &table : mCalibratedPowerTables)
|
||||
{
|
||||
table.Clear();
|
||||
}
|
||||
|
||||
mCalibratedPowerIndex = kInvalidIndex;
|
||||
}
|
||||
|
||||
Error PowerCalibration::SetChannelTargetPower(uint8_t aChannel, int16_t aTargetPower)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
|
||||
VerifyOrExit(IsChannelValid(aChannel), error = kErrorInvalidArgs);
|
||||
mTargetPowerTable[aChannel - Radio::kChannelMin] = aTargetPower;
|
||||
|
||||
if (aChannel == mLastChannel)
|
||||
{
|
||||
mCalibratedPowerIndex = kInvalidIndex;
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
Error PowerCalibration::GetRawPowerSetting(uint8_t aChannel,
|
||||
uint8_t *aRawPowerSetting,
|
||||
uint16_t *aRawPowerSettingLength)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
uint8_t chIndex;
|
||||
uint8_t powerIndex = kInvalidIndex;
|
||||
int16_t foundPower = kInvalidPower;
|
||||
int16_t targetPower;
|
||||
int16_t actualPower;
|
||||
|
||||
VerifyOrExit(IsChannelValid(aChannel), error = kErrorInvalidArgs);
|
||||
VerifyOrExit((mLastChannel != aChannel) || IsPowerUpdated());
|
||||
|
||||
chIndex = aChannel - Radio::kChannelMin;
|
||||
targetPower = mTargetPowerTable[chIndex];
|
||||
VerifyOrExit(targetPower != kInvalidPower, error = kErrorNotFound);
|
||||
|
||||
for (uint8_t i = 0; i < mCalibratedPowerTables[chIndex].GetLength(); i++)
|
||||
{
|
||||
actualPower = mCalibratedPowerTables[chIndex][i].GetActualPower();
|
||||
|
||||
if ((actualPower <= targetPower) && ((foundPower == kInvalidPower) || (foundPower <= actualPower)))
|
||||
{
|
||||
foundPower = actualPower;
|
||||
powerIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
VerifyOrExit(powerIndex != kInvalidIndex, error = kErrorNotFound);
|
||||
|
||||
mCalibratedPowerIndex = powerIndex;
|
||||
mLastChannel = aChannel;
|
||||
|
||||
exit:
|
||||
if (error == kErrorNone)
|
||||
{
|
||||
error = mCalibratedPowerTables[mLastChannel - Radio::kChannelMin][mCalibratedPowerIndex].GetRawPowerSetting(
|
||||
aRawPowerSetting, aRawPowerSettingLength);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
} // namespace Utils
|
||||
} // namespace ot
|
||||
|
||||
using namespace ot;
|
||||
|
||||
otError otPlatRadioAddCalibratedPower(otInstance *aInstance,
|
||||
uint8_t aChannel,
|
||||
int16_t aActualPower,
|
||||
const uint8_t *aRawPowerSetting,
|
||||
uint16_t aRawPowerSettingLength)
|
||||
{
|
||||
return AsCoreType(aInstance).Get<Utils::PowerCalibration>().AddCalibratedPower(
|
||||
aChannel, aActualPower, aRawPowerSetting, aRawPowerSettingLength);
|
||||
}
|
||||
|
||||
otError otPlatRadioClearCalibratedPowers(otInstance *aInstance)
|
||||
{
|
||||
AsCoreType(aInstance).Get<Utils::PowerCalibration>().ClearCalibratedPowers();
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
otError otPlatRadioSetChannelTargetPower(otInstance *aInstance, uint8_t aChannel, int16_t aTargetPower)
|
||||
{
|
||||
return AsCoreType(aInstance).Get<Utils::PowerCalibration>().SetChannelTargetPower(aChannel, aTargetPower);
|
||||
}
|
||||
|
||||
otError otPlatRadioGetRawPowerSetting(otInstance *aInstance,
|
||||
uint8_t aChannel,
|
||||
uint8_t *aRawPowerSetting,
|
||||
uint16_t *aRawPowerSettingLength)
|
||||
{
|
||||
AssertPointerIsNotNull(aRawPowerSetting);
|
||||
AssertPointerIsNotNull(aRawPowerSettingLength);
|
||||
|
||||
return AsCoreType(aInstance).Get<Utils::PowerCalibration>().GetRawPowerSetting(aChannel, aRawPowerSetting,
|
||||
aRawPowerSettingLength);
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_POWER_CALIBRATION_ENABLE && OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief
|
||||
* This file includes definitions for the platform power calibration module.
|
||||
*
|
||||
*/
|
||||
#ifndef POWER_CALIBRATION_HPP_
|
||||
#define POWER_CALIBRATION_HPP_
|
||||
|
||||
#include "openthread-core-config.h"
|
||||
|
||||
#if OPENTHREAD_CONFIG_POWER_CALIBRATION_ENABLE && OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
|
||||
#include <openthread/platform/radio.h>
|
||||
|
||||
#include "common/array.hpp"
|
||||
#include "common/numeric_limits.hpp"
|
||||
#include "radio/radio.hpp"
|
||||
|
||||
namespace ot {
|
||||
namespace Utils {
|
||||
|
||||
/**
|
||||
* This class implements power calibration module.
|
||||
*
|
||||
* The power calibration module implements the radio platform power calibration APIs. It mainly stores the calibrated
|
||||
* power table and the target power table, provides an API for the platform to get the raw power setting of the
|
||||
* specified channel.
|
||||
*
|
||||
*/
|
||||
class PowerCalibration : public InstanceLocator, private NonCopyable
|
||||
{
|
||||
public:
|
||||
explicit PowerCalibration(Instance &aInstance);
|
||||
|
||||
/**
|
||||
* Add a calibrated power of the specificed channel to the power calibration table.
|
||||
*
|
||||
* @param[in] aChannel The radio channel.
|
||||
* @param[in] aActualPower The actual power in 0.01dBm.
|
||||
* @param[in] aRawPowerSetting A pointer to the raw power setting byte array.
|
||||
* @param[in] aRawPowerSettingLength The length of the @p aRawPowerSetting.
|
||||
*
|
||||
* @retval kErrorNone Successfully added the calibrated power to the power calibration table.
|
||||
* @retval kErrorNoBufs No available entry in the power calibration table.
|
||||
* @retval kErrorInvalidArgs The @p aChannel, @p aActualPower or @p aRawPowerSetting is invalid or the
|
||||
* @ aActualPower already exists in the power calibration table.
|
||||
*
|
||||
*/
|
||||
Error AddCalibratedPower(uint8_t aChannel,
|
||||
int16_t aActualPower,
|
||||
const uint8_t *aRawPowerSetting,
|
||||
uint16_t aRawPowerSettingLength);
|
||||
|
||||
/**
|
||||
* Clear all calibrated powers from the power calibration table.
|
||||
*
|
||||
*/
|
||||
void ClearCalibratedPowers(void);
|
||||
|
||||
/**
|
||||
* Set the target power for the given channel.
|
||||
*
|
||||
* @param[in] aChannel The radio channel.
|
||||
* @param[in] aTargetPower The target power in 0.01dBm. Passing `INT16_MAX` will disable this channel.
|
||||
*
|
||||
* @retval kErrorNone Successfully set the target power.
|
||||
* @retval kErrorInvalidArgs The @p aChannel or @p aTargetPower is invalid.
|
||||
*
|
||||
*/
|
||||
Error SetChannelTargetPower(uint8_t aChannel, int16_t aTargetPower);
|
||||
|
||||
/**
|
||||
* Get the raw power setting for the given channel.
|
||||
*
|
||||
* Platform radio layer should parse the raw power setting based on the radio layer defined format and set the
|
||||
* parameters of each radio hardware module.
|
||||
*
|
||||
* @param[in] aChannel The radio channel.
|
||||
* @param[out] aRawPowerSetting A pointer to the raw power setting byte array.
|
||||
* @param[in,out] aRawPowerSettingLength On input, a pointer to the size of @p aRawPowerSetting.
|
||||
* On output, a pointer to the length of the raw power setting data.
|
||||
*
|
||||
* @retval kErrorNone Successfully got the target power.
|
||||
* @retval kErrorInvalidArgs The @p aChannel is invalid or @p aRawPowerSetting is nullptr.
|
||||
* @retval kErrorNotFound The raw power setting for the @p aChannel was not found.
|
||||
*
|
||||
*/
|
||||
Error GetRawPowerSetting(uint8_t aChannel, uint8_t *aRawPowerSetting, uint16_t *aRawPowerSettingLength);
|
||||
|
||||
private:
|
||||
class CalibratedPowerEntry
|
||||
{
|
||||
public:
|
||||
static constexpr uint16_t kMaxRawPowerSettingSize = OPENTHREAD_CONFIG_POWER_CALIBRATION_RAW_POWER_SETTING_SIZE;
|
||||
|
||||
CalibratedPowerEntry(void)
|
||||
: mActualPower(kInvalidPower)
|
||||
, mLength(0)
|
||||
{
|
||||
}
|
||||
|
||||
void Init(int16_t aActualPower, const uint8_t *aRawPowerSetting, uint16_t aRawPowerSettingLength);
|
||||
Error GetRawPowerSetting(uint8_t *aRawPowerSetting, uint16_t *aRawPowerSettingLength);
|
||||
int16_t GetActualPower(void) const { return mActualPower; }
|
||||
bool Matches(int16_t aActualPower) const { return aActualPower == mActualPower; }
|
||||
|
||||
private:
|
||||
int16_t mActualPower;
|
||||
uint8_t mSettings[kMaxRawPowerSettingSize];
|
||||
uint16_t mLength;
|
||||
};
|
||||
|
||||
bool IsPowerUpdated(void) const { return mCalibratedPowerIndex == kInvalidIndex; }
|
||||
bool IsChannelValid(uint8_t aChannel) const
|
||||
{
|
||||
return ((aChannel >= Radio::kChannelMin) && (aChannel <= Radio::kChannelMax));
|
||||
}
|
||||
|
||||
static constexpr uint8_t kInvalidIndex = NumericLimits<uint8_t>::kMax;
|
||||
static constexpr uint16_t kInvalidPower = NumericLimits<int16_t>::kMax;
|
||||
static constexpr uint16_t kMaxNumCalibratedPowers =
|
||||
OPENTHREAD_CONFIG_POWER_CALIBRATION_NUM_CALIBRATED_POWER_ENTRIES;
|
||||
static constexpr uint16_t kNumChannels = Radio::kChannelMax - Radio::kChannelMin + 1;
|
||||
|
||||
static_assert(kMaxNumCalibratedPowers < NumericLimits<uint8_t>::kMax,
|
||||
"kMaxNumCalibratedPowers is larger than or equal to max");
|
||||
|
||||
typedef Array<CalibratedPowerEntry, kMaxNumCalibratedPowers> CalibratedPowerTable;
|
||||
|
||||
uint8_t mLastChannel;
|
||||
int16_t mTargetPowerTable[kNumChannels];
|
||||
uint8_t mCalibratedPowerIndex;
|
||||
CalibratedPowerTable mCalibratedPowerTables[kNumChannels];
|
||||
};
|
||||
} // namespace Utils
|
||||
} // namespace ot
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_POWER_CALIBRATION_ENABLE && OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
#endif // POWER_CALIBRATION_HPP_
|
||||
@@ -886,6 +886,55 @@ public:
|
||||
*/
|
||||
const otRadioSpinelMetrics *GetRadioSpinelMetrics(void) const { return &mRadioSpinelMetrics; }
|
||||
|
||||
#if OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
/**
|
||||
* Add a calibrated power of the specificed channel to the power calibration table.
|
||||
*
|
||||
* @param[in] aChannel The radio channel.
|
||||
* @param[in] aActualPower The actual power in 0.01dBm.
|
||||
* @param[in] aRawPowerSetting A pointer to the raw power setting byte array.
|
||||
* @param[in] aRawPowerSettingLength The length of the @p aRawPowerSetting.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully added the calibrated power to the power calibration table.
|
||||
* @retval OT_ERROR_NO_BUFS No available entry in the power calibration table.
|
||||
* @retval OT_ERROR_INVALID_ARGS The @p aChannel, @p aActualPower or @p aRawPowerSetting is invalid.
|
||||
* @retval OT_ERROR_NOT_IMPLEMENTED This feature is not implemented.
|
||||
* @retval OT_ERROR_BUSY Failed due to another operation is on going.
|
||||
* @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver.
|
||||
*
|
||||
*/
|
||||
otError AddCalibratedPower(uint8_t aChannel,
|
||||
int16_t aActualPower,
|
||||
const uint8_t *aRawPowerSetting,
|
||||
uint16_t aRawPowerSettingLength);
|
||||
|
||||
/**
|
||||
* Clear all calibrated powers from the power calibration table.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully cleared all calibrated powers from the power calibration table.
|
||||
* @retval OT_ERROR_NOT_IMPLEMENTED This feature is not implemented.
|
||||
* @retval OT_ERROR_BUSY Failed due to another operation is on going.
|
||||
* @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver.
|
||||
*
|
||||
*/
|
||||
otError ClearCalibratedPowers(void);
|
||||
|
||||
/**
|
||||
* Set the target power for the given channel.
|
||||
*
|
||||
* @param[in] aChannel The radio channel.
|
||||
* @param[in] aTargetPower The target power in 0.01dBm. Passing `INT16_MAX` will disable this channel.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully set the target power.
|
||||
* @retval OT_ERROR_INVALID_ARGS The @p aChannel or @p aTargetPower is invalid..
|
||||
* @retval OT_ERROR_NOT_IMPLEMENTED The feature is not implemented.
|
||||
* @retval OT_ERROR_BUSY Failed due to another operation is on going.
|
||||
* @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver.
|
||||
*
|
||||
*/
|
||||
otError SetChannelTargetPower(uint8_t aChannel, int16_t aTargetPower);
|
||||
#endif
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
|
||||
@@ -2516,6 +2516,43 @@ uint8_t RadioSpinel<InterfaceType, ProcessContextType>::GetCslUncertainty(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
template <typename InterfaceType, typename ProcessContextType>
|
||||
otError RadioSpinel<InterfaceType, ProcessContextType>::AddCalibratedPower(uint8_t aChannel,
|
||||
int16_t aActualPower,
|
||||
const uint8_t *aRawPowerSetting,
|
||||
uint16_t aRawPowerSettingLength)
|
||||
{
|
||||
otError error;
|
||||
|
||||
assert(aRawPowerSetting != nullptr);
|
||||
SuccessOrExit(error = Insert(SPINEL_PROP_PHY_CALIBRATED_POWER,
|
||||
SPINEL_DATATYPE_UINT8_S SPINEL_DATATYPE_INT16_S SPINEL_DATATYPE_DATA_WLEN_S, aChannel,
|
||||
aActualPower, aRawPowerSetting, aRawPowerSettingLength));
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
template <typename InterfaceType, typename ProcessContextType>
|
||||
otError RadioSpinel<InterfaceType, ProcessContextType>::ClearCalibratedPowers(void)
|
||||
{
|
||||
return Set(SPINEL_PROP_PHY_CALIBRATED_POWER, nullptr);
|
||||
}
|
||||
|
||||
template <typename InterfaceType, typename ProcessContextType>
|
||||
otError RadioSpinel<InterfaceType, ProcessContextType>::SetChannelTargetPower(uint8_t aChannel, int16_t aTargetPower)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
VerifyOrExit(aChannel >= Radio::kChannelMin && aChannel <= Radio::kChannelMax, error = OT_ERROR_INVALID_ARGS);
|
||||
error =
|
||||
Set(SPINEL_PROP_PHY_CHAN_TARGET_POWER, SPINEL_DATATYPE_UINT8_S SPINEL_DATATYPE_INT16_S, aChannel, aTargetPower);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
|
||||
template <typename InterfaceType, typename ProcessContextType>
|
||||
uint32_t RadioSpinel<InterfaceType, ProcessContextType>::Snprintf(char *aDest, uint32_t aSize, const char *aFormat, ...)
|
||||
{
|
||||
@@ -3090,6 +3127,42 @@ void RadioSpinel<InterfaceType, ProcessContextType>::LogSpinelFrame(const uint8_
|
||||
m8[2], m8[3], m8[4], m8[5], m8[6], m8[7], flags);
|
||||
}
|
||||
break;
|
||||
|
||||
case SPINEL_PROP_PHY_CALIBRATED_POWER:
|
||||
{
|
||||
if (cmd == SPINEL_CMD_PROP_VALUE_INSERT)
|
||||
{
|
||||
uint8_t channel;
|
||||
int16_t actualPower;
|
||||
uint8_t *rawPowerSetting;
|
||||
unsigned int rawPowerSettingLength;
|
||||
|
||||
unpacked = spinel_datatype_unpack(
|
||||
data, len, SPINEL_DATATYPE_UINT8_S SPINEL_DATATYPE_INT16_S SPINEL_DATATYPE_DATA_WLEN_S, &channel,
|
||||
&actualPower, &rawPowerSetting, &rawPowerSettingLength);
|
||||
VerifyOrExit(unpacked > 0, error = OT_ERROR_PARSE);
|
||||
|
||||
start += Snprintf(start, static_cast<uint32_t>(end - start),
|
||||
", ch:%u, actualPower:%d, rawPowerSetting:", channel, actualPower);
|
||||
for (uint16_t i = 0; i < rawPowerSettingLength; i++)
|
||||
{
|
||||
start += Snprintf(start, static_cast<uint32_t>(end - start), "%02x", rawPowerSetting[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SPINEL_PROP_PHY_CHAN_TARGET_POWER:
|
||||
{
|
||||
uint8_t channel;
|
||||
int16_t targetPower;
|
||||
|
||||
unpacked =
|
||||
spinel_datatype_unpack(data, len, SPINEL_DATATYPE_UINT8_S SPINEL_DATATYPE_INT16_S, &channel, &targetPower);
|
||||
VerifyOrExit(unpacked > 0, error = OT_ERROR_PARSE);
|
||||
start += Snprintf(start, static_cast<uint32_t>(end - start), ", ch:%u, targetPower:%d", channel, targetPower);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
exit:
|
||||
|
||||
@@ -1236,6 +1236,8 @@ const char *spinel_prop_key_to_cstr(spinel_prop_key_t prop_key)
|
||||
{SPINEL_PROP_PHY_CHAN_PREFERRED, "PHY_CHAN_PREFERRED"},
|
||||
{SPINEL_PROP_PHY_CHAN_MAX_POWER, "PHY_CHAN_MAX_POWER"},
|
||||
{SPINEL_PROP_PHY_REGION_CODE, "PHY_REGION_CODE"},
|
||||
{SPINEL_PROP_PHY_CALIBRATED_POWER, "PHY_CALIBRATED_POWER"},
|
||||
{SPINEL_PROP_PHY_CHAN_TARGET_POWER, "PHY_CHAN_TARGET_POWER"},
|
||||
{SPINEL_PROP_JAM_DETECT_ENABLE, "JAM_DETECT_ENABLE"},
|
||||
{SPINEL_PROP_JAM_DETECTED, "JAM_DETECTED"},
|
||||
{SPINEL_PROP_JAM_DETECT_RSSI_THRESHOLD, "JAM_DETECT_RSSI_THRESHOLD"},
|
||||
|
||||
+23
-1
@@ -417,7 +417,7 @@
|
||||
* Please see section "Spinel definition compatibility guideline" for more details.
|
||||
*
|
||||
*/
|
||||
#define SPINEL_RCP_API_VERSION 6
|
||||
#define SPINEL_RCP_API_VERSION 7
|
||||
|
||||
/**
|
||||
* @def SPINEL_MIN_HOST_SUPPORTED_RCP_API_VERSION
|
||||
@@ -1743,6 +1743,28 @@ enum
|
||||
*/
|
||||
SPINEL_PROP_PHY_REGION_CODE = SPINEL_PROP_PHY__BEGIN + 12,
|
||||
|
||||
/// Calibrated Power Table
|
||||
/** Format: `A(Csd)` - Insert/Set
|
||||
*
|
||||
* The `Insert` command on the property inserts a calibration power entry to the calibrated power table.
|
||||
* The `Set` command on the property with empty payload clears the calibrated power table.
|
||||
*
|
||||
* Structure Parameters:
|
||||
* `C`: Channel.
|
||||
* `s`: Actual power in 0.01 dBm.
|
||||
* `d`: Raw power setting.
|
||||
*/
|
||||
SPINEL_PROP_PHY_CALIBRATED_POWER = SPINEL_PROP_PHY__BEGIN + 13,
|
||||
|
||||
/// Target power for a channel
|
||||
/** Format: `t(Cs)` - Write only
|
||||
*
|
||||
* Structure Parameters:
|
||||
* `C`: Channel.
|
||||
* `s`: Target power in 0.01 dBm.
|
||||
*/
|
||||
SPINEL_PROP_PHY_CHAN_TARGET_POWER = SPINEL_PROP_PHY__BEGIN + 14,
|
||||
|
||||
SPINEL_PROP_PHY__END = 0x30,
|
||||
|
||||
SPINEL_PROP_PHY_EXT__BEGIN = 0x1200,
|
||||
|
||||
@@ -2566,6 +2566,44 @@ exit:
|
||||
}
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_PHY_CHAN_TARGET_POWER>(void)
|
||||
{
|
||||
otError error;
|
||||
uint8_t channel;
|
||||
int16_t targetPower;
|
||||
|
||||
SuccessOrExit(error = mDecoder.ReadUint8(channel));
|
||||
SuccessOrExit(error = mDecoder.ReadInt16(targetPower));
|
||||
error = otPlatRadioSetChannelTargetPower(mInstance, channel, targetPower);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
template <> otError NcpBase::HandlePropertyInsert<SPINEL_PROP_PHY_CALIBRATED_POWER>(void)
|
||||
{
|
||||
otError error;
|
||||
uint8_t channel;
|
||||
int16_t actualPower;
|
||||
const uint8_t *dataPtr;
|
||||
uint16_t dataLen;
|
||||
|
||||
SuccessOrExit(error = mDecoder.ReadUint8(channel));
|
||||
SuccessOrExit(error = mDecoder.ReadInt16(actualPower));
|
||||
SuccessOrExit(error = mDecoder.ReadDataWithLen(dataPtr, dataLen));
|
||||
error = otPlatRadioAddCalibratedPower(mInstance, channel, actualPower, dataPtr, dataLen);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_PHY_CALIBRATED_POWER>(void)
|
||||
{
|
||||
return otPlatRadioClearCalibratedPowers(mInstance);
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
|
||||
} // namespace Ncp
|
||||
} // namespace ot
|
||||
|
||||
|
||||
@@ -419,6 +419,10 @@ NcpBase::PropertyHandler NcpBase::FindSetPropertyHandler(spinel_prop_key_t aKey)
|
||||
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_PHY_REGION_CODE),
|
||||
#if OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_PHY_CALIBRATED_POWER),
|
||||
OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_PHY_CHAN_TARGET_POWER),
|
||||
#endif
|
||||
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),
|
||||
@@ -502,7 +506,6 @@ NcpBase::PropertyHandler NcpBase::FindSetPropertyHandler(spinel_prop_key_t aKey)
|
||||
#if OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE
|
||||
OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_RADIO_COEX_ENABLE),
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_MTD || OPENTHREAD_FTD
|
||||
#if OPENTHREAD_CONFIG_MAC_FILTER_ENABLE
|
||||
OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_MAC_ALLOWLIST),
|
||||
@@ -655,6 +658,9 @@ NcpBase::PropertyHandler NcpBase::FindInsertPropertyHandler(spinel_prop_key_t aK
|
||||
}
|
||||
|
||||
constexpr static HandlerEntry sHandlerEntries[] = {
|
||||
#if OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
OT_NCP_INSERT_HANDLER_ENTRY(SPINEL_PROP_PHY_CALIBRATED_POWER),
|
||||
#endif
|
||||
#if OPENTHREAD_MTD || OPENTHREAD_FTD
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
|
||||
OT_NCP_INSERT_HANDLER_ENTRY(SPINEL_PROP_THREAD_ON_MESH_NETS),
|
||||
|
||||
@@ -104,6 +104,7 @@ add_library(openthread-posix
|
||||
alarm.cpp
|
||||
backbone.cpp
|
||||
backtrace.cpp
|
||||
config_file.cpp
|
||||
daemon.cpp
|
||||
entropy.cpp
|
||||
firewall.cpp
|
||||
@@ -115,6 +116,8 @@ add_library(openthread-posix
|
||||
misc.cpp
|
||||
multicast_routing.cpp
|
||||
netif.cpp
|
||||
power.cpp
|
||||
power_updater.cpp
|
||||
radio.cpp
|
||||
radio_url.cpp
|
||||
settings.cpp
|
||||
|
||||
@@ -47,6 +47,7 @@ libopenthread_posix_a_SOURCES = \
|
||||
alarm.cpp \
|
||||
backbone.cpp \
|
||||
backtrace.cpp \
|
||||
config_file.cpp \
|
||||
daemon.cpp \
|
||||
entropy.cpp \
|
||||
firewall.cpp \
|
||||
@@ -58,6 +59,8 @@ libopenthread_posix_a_SOURCES = \
|
||||
misc.cpp \
|
||||
multicast_routing.cpp \
|
||||
netif.cpp \
|
||||
power.cpp \
|
||||
power_updater.cpp \
|
||||
radio.cpp \
|
||||
radio_url.cpp \
|
||||
settings.cpp \
|
||||
|
||||
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Copyright (c) 2022, 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 "config_file.hpp"
|
||||
|
||||
#include <libgen.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "utils.hpp"
|
||||
#include <openthread/logging.h>
|
||||
#include "common/code_utils.hpp"
|
||||
#include "lib/platform/exit_code.h"
|
||||
|
||||
namespace ot {
|
||||
namespace Posix {
|
||||
|
||||
ConfigFile::ConfigFile(const char *aFilePath)
|
||||
: mFilePath(aFilePath)
|
||||
{
|
||||
assert(mFilePath != nullptr);
|
||||
VerifyOrDie(strlen(mFilePath) + strlen(kSwapSuffix) < kFileNameMaxSize, OT_EXIT_FAILURE);
|
||||
}
|
||||
|
||||
otError ConfigFile::Get(const char *aKey, int &aIterator, char *aValue, int aValueLength)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
char line[kLineMaxSize + 1];
|
||||
FILE *fp = nullptr;
|
||||
char *ret;
|
||||
long int pos;
|
||||
|
||||
VerifyOrExit((aKey != nullptr) && (aValue != 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);
|
||||
|
||||
while ((ret = fgets(line, sizeof(line), fp)) != nullptr)
|
||||
{
|
||||
char *str;
|
||||
char *key;
|
||||
char *value;
|
||||
|
||||
// If the string exceeds the `sizeof(line) - 1`, the string will be truncated to `sizeof(line) - 1` bytes string
|
||||
// by the function `fgets()`.
|
||||
if (strlen(line) + 1 == sizeof(line))
|
||||
{
|
||||
// The line is too long.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Remove comments
|
||||
strtok(line, kCommentDelimiter);
|
||||
|
||||
if ((str = strstr(line, "=")) == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
*str = '\0';
|
||||
key = line;
|
||||
|
||||
Strip(key);
|
||||
|
||||
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';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
VerifyOrExit(ret != nullptr, error = OT_ERROR_NOT_FOUND);
|
||||
VerifyOrDie((pos = ftell(fp)) >= 0, OT_EXIT_ERROR_ERRNO);
|
||||
aIterator = static_cast<int>(pos);
|
||||
|
||||
exit:
|
||||
if (fp != nullptr)
|
||||
{
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
otError ConfigFile::Add(const char *aKey, const char *aValue)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
FILE *fp = nullptr;
|
||||
char *path = nullptr;
|
||||
char *dir;
|
||||
struct stat st;
|
||||
|
||||
VerifyOrExit((aKey != nullptr) && (aValue != nullptr), error = OT_ERROR_INVALID_ARGS);
|
||||
VerifyOrDie((path = strdup(mFilePath)) != nullptr, OT_EXIT_ERROR_ERRNO);
|
||||
dir = dirname(path);
|
||||
|
||||
if (stat(dir, &st) == -1)
|
||||
{
|
||||
VerifyOrDie(mkdir(dir, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) == 0, OT_EXIT_ERROR_ERRNO);
|
||||
}
|
||||
|
||||
VerifyOrDie((fp = fopen(mFilePath, "at")) != NULL, OT_EXIT_ERROR_ERRNO);
|
||||
VerifyOrDie(fprintf(fp, "%s=%s\n", aKey, aValue) > 0, OT_EXIT_ERROR_ERRNO);
|
||||
|
||||
exit:
|
||||
if (fp != nullptr)
|
||||
{
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
if (path != nullptr)
|
||||
{
|
||||
free(path);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
otError ConfigFile::Clear(const char *aKey)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
char swapFile[kFileNameMaxSize];
|
||||
char line[kLineMaxSize];
|
||||
FILE *fp = nullptr;
|
||||
FILE *fpSwap = nullptr;
|
||||
|
||||
VerifyOrExit(aKey != nullptr, error = OT_ERROR_INVALID_ARGS);
|
||||
VerifyOrDie((fp = fopen(mFilePath, "r")) != NULL, OT_EXIT_ERROR_ERRNO);
|
||||
snprintf(swapFile, sizeof(swapFile), "%s%s", mFilePath, kSwapSuffix);
|
||||
VerifyOrDie((fpSwap = fopen(swapFile, "w+")) != NULL, OT_EXIT_ERROR_ERRNO);
|
||||
|
||||
while (fgets(line, sizeof(line), fp) != nullptr)
|
||||
{
|
||||
bool containsKey;
|
||||
char *str1;
|
||||
char *str2;
|
||||
|
||||
str1 = strstr(line, kCommentDelimiter);
|
||||
str2 = strstr(line, aKey);
|
||||
|
||||
// If only the comment contains the key string, ignore it.
|
||||
containsKey = (str2 != nullptr) && (str1 == nullptr || str2 < str1);
|
||||
|
||||
if (!containsKey)
|
||||
{
|
||||
fputs(line, fpSwap);
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
if (fp != nullptr)
|
||||
{
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
if (fpSwap != nullptr)
|
||||
{
|
||||
fclose(fpSwap);
|
||||
}
|
||||
|
||||
if (error == OT_ERROR_NONE)
|
||||
{
|
||||
VerifyOrDie(rename(swapFile, mFilePath) == 0, OT_EXIT_ERROR_ERRNO);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void ConfigFile::Strip(char *aString)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
for (int i = 0; aString[i]; i++)
|
||||
{
|
||||
if (aString[i] != ' ' && aString[i] != '\r' && aString[i] != '\n')
|
||||
{
|
||||
aString[count++] = aString[i];
|
||||
}
|
||||
}
|
||||
|
||||
aString[count] = '\0';
|
||||
}
|
||||
} // namespace Posix
|
||||
} // namespace ot
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
#ifndef POSIX_PLATFORM_CONFIG_FILE_HPP_
|
||||
#define POSIX_PLATFORM_CONFIG_FILE_HPP_
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <openthread/error.h>
|
||||
|
||||
namespace ot {
|
||||
namespace Posix {
|
||||
|
||||
/**
|
||||
* This class provides read/write/clear methods for key/value configuration files.
|
||||
*
|
||||
*/
|
||||
class ConfigFile
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* This method initializes the configuration file path.
|
||||
*
|
||||
* @param[in] aFilePath A pointer to the null-terminated file path.
|
||||
*
|
||||
*/
|
||||
explicit ConfigFile(const char *aFilePath);
|
||||
|
||||
/**
|
||||
* This method gets a configuration from the configuration file.
|
||||
*
|
||||
* @param[in] aKey The key string associated with the requested configuration.
|
||||
* @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.
|
||||
* @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.
|
||||
*
|
||||
*/
|
||||
otError Get(const char *aKey, int &aIterator, char *aValue, int aValueLength);
|
||||
|
||||
/**
|
||||
* This method adds a configuration to the configuration file.
|
||||
*
|
||||
* @param[in] aKey The key string associated with the requested configuration.
|
||||
* @param[in] aValue A pointer to where the new value string of the configuration should be written.
|
||||
*
|
||||
* @retval OT_ERROR_NONE The given key was found and removed successfully.
|
||||
* @retval OT_ERROR_INVALID_ARGS If @p aKey or @p aValue was NULL.
|
||||
*
|
||||
*/
|
||||
otError Add(const char *aKey, const char *aValue);
|
||||
|
||||
/**
|
||||
* This function removes all configurations with the same key string from the configuration file.
|
||||
*
|
||||
* @param[in] aKey The key string associated with the requested configuration.
|
||||
*
|
||||
* @retval OT_ERROR_NONE The given key was found and removed successfully.
|
||||
* @retval OT_ERROR_INVALID_ARGS If @p aKey was NULL.
|
||||
*
|
||||
*/
|
||||
otError Clear(const char *aKey);
|
||||
|
||||
private:
|
||||
const char *kCommentDelimiter = "#";
|
||||
const char *kSwapSuffix = ".swap";
|
||||
static constexpr uint16_t kLineMaxSize = 512;
|
||||
static constexpr uint16_t kFileNameMaxSize = 255;
|
||||
|
||||
void Strip(char *aString);
|
||||
|
||||
const char *mFilePath;
|
||||
};
|
||||
|
||||
} // namespace Posix
|
||||
} // namespace ot
|
||||
|
||||
#endif // POSIX_PLATFORM_CONFIG_FILE_HPP_
|
||||
@@ -309,4 +309,14 @@
|
||||
#define OPENTHREAD_CONFIG_ASSERT_CHECK_API_POINTER_PARAM_FOR_NULL 1
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
*
|
||||
* Define as 1 to enable platform power calibration support.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
#define OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE 1
|
||||
#endif
|
||||
|
||||
#endif // OPENTHREAD_CORE_POSIX_CONFIG_H_
|
||||
|
||||
@@ -335,4 +335,27 @@
|
||||
#define OPENTHREAD_POSIX_CONFIG_INFRA_IF_ENABLE OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_POSIX_CONFIG_FACTORY_CONFIG_FILE
|
||||
*
|
||||
* Define the path of the factory config file.
|
||||
*
|
||||
* Note: The factory config file contains the persist data that configured by the factory. And it won't be changed
|
||||
* after a device firmware update OTA is done.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_POSIX_CONFIG_FACTORY_CONFIG_FILE
|
||||
#define OPENTHREAD_POSIX_CONFIG_FACTORY_CONFIG_FILE "src/posix/platform/openthread.conf.example"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_POSIX_CONFIG_PRODUCT_CONFIG_FILE
|
||||
*
|
||||
* Define the path of the product config file.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_POSIX_CONFIG_PRODUCT_CONFIG_FILE
|
||||
#define OPENTHREAD_POSIX_CONFIG_PRODUCT_CONFIG_FILE "src/posix/platform/openthread.conf.example"
|
||||
#endif
|
||||
|
||||
#endif // OPENTHREAD_PLATFORM_CONFIG_H_
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
#
|
||||
# Sample configuration file
|
||||
#
|
||||
# Modify this to use your own configurations!
|
||||
#
|
||||
|
||||
# Target power table entries.
|
||||
# target_power=<RegulatoryDomain>,<ChannelStart>,<ChannelEnd>,<TargetPower>
|
||||
target_power=ETSI,11,26,1000
|
||||
target_power=FCC,11,14,1700
|
||||
target_power=FCC,15,24,2000
|
||||
target_power=FCC,25,26,1600
|
||||
|
||||
# Region domain mapping table entries.
|
||||
# region_domain_mapping=<RegulatoryDomain>,<Region>,<Region>,...
|
||||
region_domain_mapping=FCC,AU,CA,CL,CO,IN,MX,PE,TW,US
|
||||
region_domain_mapping=ETSI,WW
|
||||
|
||||
# Power calibration table entries.
|
||||
# calibrated_power=<ChannelStart>,<ChannelEnd>,<ActualPower>,<RawPowerSetting>
|
||||
calibrated_power=11,25,1900,112233
|
||||
calibrated_power=11,25,1000,223344
|
||||
calibrated_power=26,26,1500,334455
|
||||
calibrated_power=26,26,700,445566
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright (c) 2022, 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 strain 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 "power.hpp"
|
||||
#include "common/code_utils.hpp"
|
||||
#include "utils/parse_cmdline.hpp"
|
||||
|
||||
namespace ot {
|
||||
namespace Power {
|
||||
|
||||
otError Domain::Set(const char *aDomain)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
uint16_t length = static_cast<uint16_t>(strlen(aDomain));
|
||||
|
||||
VerifyOrExit(length <= kDomainSize, error = OT_ERROR_INVALID_ARGS);
|
||||
memcpy(m8, aDomain, length);
|
||||
m8[length] = '\0';
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError TargetPower::FromString(char *aString)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
char *str;
|
||||
|
||||
VerifyOrExit((str = strtok(aString, ",")) != nullptr, error = OT_ERROR_PARSE);
|
||||
SuccessOrExit(error = Utils::CmdLineParser::ParseAsUint8(str, mChannelStart));
|
||||
|
||||
VerifyOrExit((str = strtok(nullptr, ",")) != nullptr, error = OT_ERROR_PARSE);
|
||||
SuccessOrExit(error = Utils::CmdLineParser::ParseAsUint8(str, mChannelEnd));
|
||||
|
||||
VerifyOrExit((str = strtok(nullptr, ",")) != nullptr, error = OT_ERROR_PARSE);
|
||||
SuccessOrExit(error = Utils::CmdLineParser::ParseAsInt16(str, mTargetPower));
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
TargetPower::InfoString TargetPower::ToString(void) const
|
||||
{
|
||||
InfoString string;
|
||||
|
||||
string.Append("%u,%u,%d", mChannelStart, mChannelEnd, mTargetPower);
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
otError RawPowerSetting::Set(const char *aRawPowerSetting)
|
||||
{
|
||||
otError error;
|
||||
uint16_t length = sizeof(mData);
|
||||
|
||||
SuccessOrExit(error = ot::Utils::CmdLineParser::ParseAsHexString(aRawPowerSetting, length, mData));
|
||||
mLength = static_cast<uint8_t>(length);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
RawPowerSetting::InfoString RawPowerSetting::ToString(void) const
|
||||
{
|
||||
InfoString string;
|
||||
|
||||
string.AppendHexBytes(mData, mLength);
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
otError CalibratedPower::FromString(char *aString)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
char *str;
|
||||
char *pSave;
|
||||
|
||||
VerifyOrExit((str = strtok_r(aString, ",", &pSave)) != nullptr, error = OT_ERROR_PARSE);
|
||||
SuccessOrExit(error = Utils::CmdLineParser::ParseAsUint8(str, mChannelStart));
|
||||
|
||||
VerifyOrExit((str = strtok_r(nullptr, ",", &pSave)) != nullptr, error = OT_ERROR_PARSE);
|
||||
SuccessOrExit(error = Utils::CmdLineParser::ParseAsUint8(str, mChannelEnd));
|
||||
|
||||
VerifyOrExit((str = strtok_r(nullptr, ",", &pSave)) != nullptr, error = OT_ERROR_PARSE);
|
||||
SuccessOrExit(error = Utils::CmdLineParser::ParseAsInt16(str, mActualPower));
|
||||
SuccessOrExit(error = mRawPowerSetting.Set(pSave));
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
CalibratedPower::InfoString CalibratedPower::ToString(void) const
|
||||
{
|
||||
InfoString string;
|
||||
|
||||
string.Append("%u,%u,%d,%s", mChannelStart, mChannelEnd, mActualPower, mRawPowerSetting.ToString().AsCString());
|
||||
|
||||
return string;
|
||||
}
|
||||
} // namespace Power
|
||||
} // namespace ot
|
||||
@@ -0,0 +1,289 @@
|
||||
/*
|
||||
* Copyright (c) 2022, 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 strain 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.
|
||||
*/
|
||||
|
||||
#ifndef POSIX_PLATFORM_POWER_H
|
||||
#define POSIX_PLATFORM_POWER_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openthread/error.h>
|
||||
#include <openthread/platform/radio.h>
|
||||
#include "common/string.hpp"
|
||||
|
||||
namespace ot {
|
||||
namespace Power {
|
||||
|
||||
class Domain
|
||||
{
|
||||
public:
|
||||
Domain(void) { m8[0] = '\0'; }
|
||||
|
||||
/**
|
||||
* This method sets the regulatory domain from a given null terminated C string.
|
||||
*
|
||||
* @param[in] aDomain A regulatory domain name C string.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully set the regulatory domain.
|
||||
* @retval OT_ERROR_INVALID_ARGS Given regulatory domain is too long.
|
||||
*
|
||||
*/
|
||||
otError Set(const char *aDomain);
|
||||
|
||||
/**
|
||||
* This method overloads operator `==` to evaluate whether or not two `Domain` instances are equal.
|
||||
*
|
||||
* @param[in] aOther The other `Domain` instance to compare with.
|
||||
*
|
||||
* @retval TRUE If the two `Domain` instances are equal.
|
||||
* @retval FALSE If the two `Domain` instances not equal.
|
||||
*
|
||||
*/
|
||||
bool operator==(const Domain &aOther) const { return strcmp(m8, aOther.m8) == 0; }
|
||||
|
||||
/**
|
||||
* This method overloads operator `!=` to evaluate whether or not the `Domain` is unequal to a given C string.
|
||||
*
|
||||
* @param[in] aCString A C string to compare with. Can be `nullptr` which then returns 'TRUE'.
|
||||
*
|
||||
* @retval TRUE If the two regulatory domains are not equal.
|
||||
* @retval FALSE If the two regulatory domains are equal.
|
||||
*
|
||||
*/
|
||||
bool operator!=(const char *aCString) const { return (aCString == nullptr) ? true : strcmp(m8, aCString) != 0; }
|
||||
|
||||
/**
|
||||
* This method gets the regulatory domain as a null terminated C string.
|
||||
*
|
||||
* @returns The regulatory domain as a null terminated C string array.
|
||||
*
|
||||
*/
|
||||
const char *AsCString(void) const { return m8; }
|
||||
|
||||
private:
|
||||
static constexpr uint8_t kDomainSize = 8;
|
||||
char m8[kDomainSize + 1];
|
||||
};
|
||||
|
||||
class TargetPower
|
||||
{
|
||||
public:
|
||||
static constexpr uint16_t kInfoStringSize = 12; ///< Recommended buffer size to use with `ToString()`.
|
||||
typedef String<kInfoStringSize> InfoString;
|
||||
|
||||
/**
|
||||
* This method parses an target power string.
|
||||
*
|
||||
* The string MUST follow the format: "<channel_start>,<channel_end>,<target_power>".
|
||||
* For example, "11,26,2000"
|
||||
*
|
||||
* @param[in] aString A pointer to the null-terminated string.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully parsed the target power string.
|
||||
* @retval OT_ERROR_PARSE Failed to parse the target power string.
|
||||
*
|
||||
*/
|
||||
otError FromString(char *aString);
|
||||
|
||||
/**
|
||||
* This method returns the start channel.
|
||||
*
|
||||
* @returns The channel.
|
||||
*
|
||||
*/
|
||||
uint8_t GetChannelStart(void) const { return mChannelStart; }
|
||||
|
||||
/**
|
||||
* This method returns the end channel.
|
||||
*
|
||||
* @returns The channel.
|
||||
*
|
||||
*/
|
||||
uint8_t GetChannelEnd(void) const { return mChannelEnd; }
|
||||
|
||||
/**
|
||||
* This method returns the target power.
|
||||
*
|
||||
* @returns The target power, in 0.01 dBm.
|
||||
*
|
||||
*/
|
||||
int16_t GetTargetPower(void) const { return mTargetPower; }
|
||||
|
||||
/**
|
||||
* This method converts the target power into a human-readable string.
|
||||
*
|
||||
* @returns An `InfoString` object representing the target power.
|
||||
*
|
||||
*/
|
||||
InfoString ToString(void) const;
|
||||
|
||||
private:
|
||||
uint8_t mChannelStart;
|
||||
uint8_t mChannelEnd;
|
||||
int16_t mTargetPower;
|
||||
};
|
||||
|
||||
class RawPowerSetting
|
||||
{
|
||||
public:
|
||||
// Recommended buffer size to use with `ToString()`.
|
||||
static constexpr uint16_t kInfoStringSize = OPENTHREAD_CONFIG_POWER_CALIBRATION_RAW_POWER_SETTING_SIZE * 2 + 1;
|
||||
typedef String<kInfoStringSize> InfoString;
|
||||
|
||||
/**
|
||||
* This method sets the raw power setting from a given null terminated hex C string.
|
||||
*
|
||||
* @param[in] aRawPowerSetting A raw power setting hex C string.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully set the raw power setting.
|
||||
* @retval OT_ERROR_INVALID_ARGS The given raw power setting is too long.
|
||||
*
|
||||
*/
|
||||
otError Set(const char *aRawPowerSetting);
|
||||
|
||||
/**
|
||||
* This method converts the raw power setting into a human-readable string.
|
||||
*
|
||||
* @returns An `InfoString` object representing the calibrated power.
|
||||
*
|
||||
*/
|
||||
InfoString ToString(void) const;
|
||||
|
||||
const uint8_t *GetData(void) const { return mData; }
|
||||
uint16_t GetLength(void) const { return mLength; }
|
||||
|
||||
private:
|
||||
static constexpr uint16_t kMaxRawPowerSettingSize = OPENTHREAD_CONFIG_POWER_CALIBRATION_RAW_POWER_SETTING_SIZE;
|
||||
|
||||
uint8_t mData[kMaxRawPowerSettingSize];
|
||||
uint16_t mLength;
|
||||
};
|
||||
|
||||
class CalibratedPower
|
||||
{
|
||||
public:
|
||||
// Recommended buffer size to use with `ToString()`.
|
||||
static constexpr uint16_t kInfoStringSize = 20 + RawPowerSetting::kInfoStringSize;
|
||||
typedef String<kInfoStringSize> InfoString;
|
||||
|
||||
/**
|
||||
* This method parses an calibrated power string.
|
||||
*
|
||||
* The string MUST follow the format: "<channel_start>,<channel_end>,<actual_power>,<raw_power_setting>".
|
||||
* For example, "11,26,2000,1122aabb"
|
||||
*
|
||||
* @param[in] aString A pointer to the null-terminated string.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully parsed the calibrated power string.
|
||||
* @retval OT_ERROR_PARSE Failed to parse the calibrated power string.
|
||||
*
|
||||
*/
|
||||
otError FromString(char *aString);
|
||||
|
||||
/**
|
||||
* This method returns the start channel.
|
||||
*
|
||||
* @returns The channel.
|
||||
*
|
||||
*/
|
||||
uint8_t GetChannelStart(void) const { return mChannelStart; }
|
||||
|
||||
/**
|
||||
* This method sets the start channel.
|
||||
*
|
||||
* @param[in] aChannelStart The start channel.
|
||||
*
|
||||
*/
|
||||
void SetChannelStart(uint8_t aChannelStart) { mChannelStart = aChannelStart; }
|
||||
|
||||
/**
|
||||
* This method returns the end channel.
|
||||
*
|
||||
* @returns The channel.
|
||||
*
|
||||
*/
|
||||
uint8_t GetChannelEnd(void) const { return mChannelEnd; }
|
||||
|
||||
/**
|
||||
* This method sets the end channel.
|
||||
*
|
||||
* @param[in] aChannelEnd The end channel.
|
||||
*
|
||||
*/
|
||||
void SetChannelEnd(uint8_t aChannelEnd) { mChannelEnd = aChannelEnd; }
|
||||
|
||||
/**
|
||||
* This method returns the actual power.
|
||||
*
|
||||
* @returns The actual measured power, in 0.01 dBm.
|
||||
*
|
||||
*/
|
||||
int16_t GetActualPower(void) const { return mActualPower; }
|
||||
|
||||
/**
|
||||
* This method sets the actual channel.
|
||||
*
|
||||
* @param[in] aActualPower The actual power in 0.01 dBm.
|
||||
*
|
||||
*/
|
||||
void SetActualPower(int16_t aActualPower) { mActualPower = aActualPower; }
|
||||
|
||||
/**
|
||||
* This method returns the raw power setting.
|
||||
*
|
||||
* @returns A reference to the raw power setting.
|
||||
*
|
||||
*/
|
||||
const RawPowerSetting &GetRawPowerSetting(void) const { return mRawPowerSetting; }
|
||||
|
||||
/**
|
||||
* This method sets the raw power setting.
|
||||
*
|
||||
* @param[in] aRawPowerSetting The raw power setting.
|
||||
*
|
||||
*/
|
||||
void SetRawPowerSetting(const RawPowerSetting &aRawPowerSetting) { mRawPowerSetting = aRawPowerSetting; }
|
||||
|
||||
/**
|
||||
* This method converts the calibrated power into a human-readable string.
|
||||
*
|
||||
* @returns An `InfoString` object representing the calibrated power.
|
||||
*
|
||||
*/
|
||||
InfoString ToString(void) const;
|
||||
|
||||
private:
|
||||
uint8_t mChannelStart;
|
||||
uint8_t mChannelEnd;
|
||||
int16_t mActualPower;
|
||||
RawPowerSetting mRawPowerSetting;
|
||||
};
|
||||
} // namespace Power
|
||||
} // namespace ot
|
||||
#endif // POSIX_PLATFORM_POWER_H
|
||||
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright (c) 2022, 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 strain 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 "power_updater.hpp"
|
||||
|
||||
#include "platform-posix.h"
|
||||
#include <openthread/platform/radio.h>
|
||||
#include "lib/platform/exit_code.h"
|
||||
|
||||
#if OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
|
||||
namespace ot {
|
||||
namespace Posix {
|
||||
|
||||
otError PowerUpdater::SetRegion(uint16_t aRegionCode)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
int iterator = 0;
|
||||
Power::Domain domain;
|
||||
Power::TargetPower targetPower;
|
||||
|
||||
if (GetDomain(aRegionCode, domain) != OT_ERROR_NONE)
|
||||
{
|
||||
// If failed to find the domain for the region, use the world wide region as the default region.
|
||||
VerifyOrExit(GetDomain(kRegionCodeWorldWide, domain) == OT_ERROR_NONE, error = OT_ERROR_FAILED);
|
||||
}
|
||||
|
||||
while (GetNextTargetPower(domain, iterator, targetPower) == OT_ERROR_NONE)
|
||||
{
|
||||
otLogInfoPlat("Update target power: %s\r\n", targetPower.ToString().AsCString());
|
||||
|
||||
for (uint8_t ch = targetPower.GetChannelStart(); ch <= targetPower.GetChannelEnd(); ch++)
|
||||
{
|
||||
SuccessOrExit(error = otPlatRadioSetChannelTargetPower(gInstance, ch, targetPower.GetTargetPower()));
|
||||
}
|
||||
}
|
||||
|
||||
SuccessOrExit(error = UpdateCalibratedPower());
|
||||
|
||||
mRegionCode = aRegionCode;
|
||||
|
||||
exit:
|
||||
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));
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
otError PowerUpdater::UpdateCalibratedPower(void)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
int iterator = 0;
|
||||
char value[kMaxValueSize];
|
||||
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.
|
||||
if (calibrationFile->Get(kKeyCalibratedPower, iterator, value, sizeof(value)) != OT_ERROR_NONE)
|
||||
{
|
||||
calibrationFile = &mProductConfigFile;
|
||||
}
|
||||
|
||||
iterator = 0;
|
||||
while (calibrationFile->Get(kKeyCalibratedPower, iterator, value, sizeof(value)) == OT_ERROR_NONE)
|
||||
{
|
||||
SuccessOrExit(error = calibratedPower.FromString(value));
|
||||
otLogInfoPlat("Update calibrated power: %s\r\n", calibratedPower.ToString().AsCString());
|
||||
|
||||
for (uint8_t ch = calibratedPower.GetChannelStart(); ch <= calibratedPower.GetChannelEnd(); ch++)
|
||||
{
|
||||
SuccessOrExit(error = otPlatRadioAddCalibratedPower(gInstance, ch, calibratedPower.GetActualPower(),
|
||||
calibratedPower.GetRawPowerSetting().GetData(),
|
||||
calibratedPower.GetRawPowerSetting().GetLength()));
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
if (error != OT_ERROR_NONE)
|
||||
{
|
||||
otLogCritPlat("Update calibrated power table failed, Error: %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 error = OT_ERROR_NOT_FOUND;
|
||||
char value[kMaxValueSize];
|
||||
char *domain;
|
||||
char *psave;
|
||||
|
||||
while (mProductConfigFile.Get(kKeyTargetPower, aIterator, value, sizeof(value)) == OT_ERROR_NONE)
|
||||
{
|
||||
if (((domain = strtok_r(value, kCommaDelimiter, &psave)) == nullptr) || (aDomain != domain))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((error = aTargetPower.FromString(psave)) != OT_ERROR_NONE)
|
||||
{
|
||||
otLogCritPlat("Read target power failed, Error: %s", otThreadErrorToString(error));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
} // namespace Posix
|
||||
} // namespace ot
|
||||
#endif // OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (c) 2022, 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 strain 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.
|
||||
*/
|
||||
|
||||
#ifndef POSIX_PLATFORM_POWER_UPDATER_HPP_
|
||||
#define POSIX_PLATFORM_POWER_UPDATER_HPP_
|
||||
|
||||
#include "openthread-posix-config.h"
|
||||
|
||||
#if OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openthread/error.h>
|
||||
#include <openthread/logging.h>
|
||||
#include <openthread/platform/radio.h>
|
||||
|
||||
#include "config_file.hpp"
|
||||
#include "power.hpp"
|
||||
#include "common/code_utils.hpp"
|
||||
|
||||
namespace ot {
|
||||
namespace Posix {
|
||||
|
||||
/**
|
||||
* This class updates the target power table and calibrated powe table to the RCP.
|
||||
*
|
||||
*/
|
||||
class PowerUpdater
|
||||
{
|
||||
public:
|
||||
PowerUpdater(void)
|
||||
: mFactoryConfigFile(kFactoryConfigFile)
|
||||
, mProductConfigFile(kProductConfigFile)
|
||||
, mRegionCode(0)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the region code.
|
||||
*
|
||||
* The radio region format is the 2-bytes ascii representation of the
|
||||
* ISO 3166 alpha-2 code.
|
||||
*
|
||||
* @param[in] aRegionCode The radio region.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully set region code.
|
||||
* @retval OT_ERROR_FAILED Failed to set the region code.
|
||||
*
|
||||
*/
|
||||
otError SetRegion(uint16_t aRegionCode);
|
||||
|
||||
/**
|
||||
* Get the region code.
|
||||
*
|
||||
* The radio region format is the 2-bytes ascii representation of the
|
||||
* ISO 3166 alpha-2 code.
|
||||
*
|
||||
* @returns The region code.
|
||||
*
|
||||
*/
|
||||
uint16_t GetRegion(void) const { return mRegionCode; }
|
||||
|
||||
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"
|
||||
|
||||
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 UpdateCalibratedPower(void);
|
||||
|
||||
ConfigFile mFactoryConfigFile;
|
||||
ConfigFile mProductConfigFile;
|
||||
uint16_t mRegionCode;
|
||||
};
|
||||
|
||||
} // namespace Posix
|
||||
} // namespace ot
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
#endif // POSIX_PLATFORM_POWER_UPDATER_HPP_
|
||||
@@ -63,6 +63,11 @@ static ot::Spinel::RadioSpinel<ot::Posix::VendorInterface, RadioProcessContext>
|
||||
"OT_POSIX_RCP_BUS_VENDOR!"
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
#include "power_updater.hpp"
|
||||
static ot::Posix::PowerUpdater sPowerUpdater;
|
||||
#endif
|
||||
|
||||
namespace ot {
|
||||
namespace Posix {
|
||||
|
||||
@@ -135,7 +140,7 @@ void Radio::Init(void)
|
||||
|
||||
VerifyOrDie(strnlen(region, 3) == 2, OT_EXIT_INVALID_ARGUMENTS);
|
||||
regionCode = static_cast<uint16_t>(static_cast<uint16_t>(region[0]) << 8) + static_cast<uint16_t>(region[1]);
|
||||
SuccessOrDie(sRadioSpinel.SetRadioRegion(regionCode));
|
||||
SuccessOrDie(otPlatRadioSetRegion(gInstance, regionCode));
|
||||
}
|
||||
|
||||
#if OPENTHREAD_POSIX_CONFIG_MAX_POWER_TABLE_ENABLE
|
||||
@@ -701,16 +706,49 @@ otError otPlatRadioSetChannelMaxTransmitPower(otInstance *aInstance, uint8_t aCh
|
||||
return sRadioSpinel.SetChannelMaxTransmitPower(aChannel, aMaxPower);
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
otError otPlatRadioAddCalibratedPower(otInstance *aInstance,
|
||||
uint8_t aChannel,
|
||||
int16_t aActualPower,
|
||||
const uint8_t *aRawPowerSetting,
|
||||
uint16_t aRawPowerSettingLength)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
return sRadioSpinel.AddCalibratedPower(aChannel, aActualPower, aRawPowerSetting, aRawPowerSettingLength);
|
||||
}
|
||||
|
||||
otError otPlatRadioClearCalibratedPowers(otInstance *aInstance)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
return sRadioSpinel.ClearCalibratedPowers();
|
||||
}
|
||||
|
||||
otError otPlatRadioSetChannelTargetPower(otInstance *aInstance, uint8_t aChannel, int16_t aTargetPower)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
return sRadioSpinel.SetChannelTargetPower(aChannel, aTargetPower);
|
||||
}
|
||||
#endif
|
||||
|
||||
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);
|
||||
#endif
|
||||
}
|
||||
|
||||
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);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
|
||||
|
||||
Executable
+48
@@ -0,0 +1,48 @@
|
||||
#!/usr/bin/expect -f
|
||||
#
|
||||
# Copyright (c) 2022, 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 build/posix/tools/ot-fct/ot-fct
|
||||
|
||||
send "targetpowertable\n"
|
||||
expect_line "Done"
|
||||
send "powercalibrationtable\n"
|
||||
expect_line "Done"
|
||||
send "powercalibrationtable add -b 11,25 -c 1900,112233/1000,223344 -b 26,26 -c 1500,334455/700,445566\n"
|
||||
expect_line "Done"
|
||||
send "powercalibrationtable clear\n"
|
||||
expect_line "Done"
|
||||
send "regiondomaintable\n"
|
||||
expect "Done"
|
||||
send "invalidcommand\n"
|
||||
expect "failed"
|
||||
expect "status 0x17"
|
||||
send "\x04"
|
||||
expect eof
|
||||
@@ -812,6 +812,27 @@ target_link_libraries(ot-test-pool
|
||||
|
||||
add_test(NAME ot-test-pool COMMAND ot-test-pool)
|
||||
|
||||
add_executable(ot-test-power-calibration
|
||||
test_power_calibration.cpp
|
||||
)
|
||||
|
||||
target_include_directories(ot-test-power-calibration
|
||||
PRIVATE
|
||||
${COMMON_INCLUDES}
|
||||
)
|
||||
|
||||
target_compile_options(ot-test-power-calibration
|
||||
PRIVATE
|
||||
${COMMON_COMPILE_OPTIONS}
|
||||
)
|
||||
|
||||
target_link_libraries(ot-test-power-calibration
|
||||
PRIVATE
|
||||
${COMMON_LIBS}
|
||||
)
|
||||
|
||||
add_test(NAME ot-test-power-calibration COMMAND ot-test-power-calibration)
|
||||
|
||||
add_executable(ot-test-priority-queue
|
||||
test_priority_queue.cpp
|
||||
)
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright (c) 2022, 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/platform/radio.h>
|
||||
|
||||
#include "test_platform.h"
|
||||
#include "test_util.h"
|
||||
|
||||
#if OPENTHREAD_CONFIG_POWER_CALIBRATION_ENABLE && OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
|
||||
namespace ot {
|
||||
|
||||
void TestPowerCalibration(void)
|
||||
{
|
||||
otInstance *instance;
|
||||
uint8_t rawPowerSetting[2];
|
||||
uint16_t rawPowerSettingLength;
|
||||
|
||||
struct CalibratedPowerEntry
|
||||
{
|
||||
uint8_t mChannel;
|
||||
int16_t mActualPower;
|
||||
uint8_t mRawPowerSetting[1];
|
||||
uint16_t mRawPowerSettingLength;
|
||||
};
|
||||
|
||||
constexpr CalibratedPowerEntry kCalibratedPowerTable[] = {
|
||||
{11, 15000, {0x02}, 1},
|
||||
{11, 5000, {0x00}, 1},
|
||||
{11, 10000, {0x01}, 1},
|
||||
};
|
||||
|
||||
instance = static_cast<otInstance *>(testInitInstance());
|
||||
VerifyOrQuit(instance != nullptr, "Null OpenThread instance");
|
||||
|
||||
for (const CalibratedPowerEntry &calibratedPower : kCalibratedPowerTable)
|
||||
{
|
||||
SuccessOrQuit(otPlatRadioAddCalibratedPower(instance, calibratedPower.mChannel, calibratedPower.mActualPower,
|
||||
calibratedPower.mRawPowerSetting,
|
||||
calibratedPower.mRawPowerSettingLength));
|
||||
}
|
||||
|
||||
SuccessOrQuit(otPlatRadioSetChannelTargetPower(instance, 11, 4999));
|
||||
rawPowerSettingLength = sizeof(rawPowerSetting);
|
||||
VerifyOrQuit(otPlatRadioGetRawPowerSetting(instance, 11, rawPowerSetting, &rawPowerSettingLength) ==
|
||||
OT_ERROR_NOT_FOUND);
|
||||
|
||||
SuccessOrQuit(otPlatRadioSetChannelTargetPower(instance, 11, 5000));
|
||||
rawPowerSettingLength = sizeof(rawPowerSetting);
|
||||
SuccessOrQuit(otPlatRadioGetRawPowerSetting(instance, 11, rawPowerSetting, &rawPowerSettingLength));
|
||||
VerifyOrQuit(rawPowerSettingLength == 1);
|
||||
VerifyOrQuit(rawPowerSetting[0] == 0x00);
|
||||
|
||||
SuccessOrQuit(otPlatRadioSetChannelTargetPower(instance, 11, 9999));
|
||||
rawPowerSettingLength = sizeof(rawPowerSetting);
|
||||
SuccessOrQuit(otPlatRadioGetRawPowerSetting(instance, 11, rawPowerSetting, &rawPowerSettingLength));
|
||||
VerifyOrQuit(rawPowerSettingLength == 1);
|
||||
VerifyOrQuit(rawPowerSetting[0] == 0x00);
|
||||
|
||||
SuccessOrQuit(otPlatRadioSetChannelTargetPower(instance, 11, 10000));
|
||||
rawPowerSettingLength = sizeof(rawPowerSetting);
|
||||
SuccessOrQuit(otPlatRadioGetRawPowerSetting(instance, 11, rawPowerSetting, &rawPowerSettingLength));
|
||||
VerifyOrQuit(rawPowerSettingLength == 1);
|
||||
VerifyOrQuit(rawPowerSetting[0] == 0x01);
|
||||
|
||||
SuccessOrQuit(otPlatRadioSetChannelTargetPower(instance, 11, 14999));
|
||||
rawPowerSettingLength = sizeof(rawPowerSetting);
|
||||
SuccessOrQuit(otPlatRadioGetRawPowerSetting(instance, 11, rawPowerSetting, &rawPowerSettingLength));
|
||||
VerifyOrQuit(rawPowerSettingLength == 1);
|
||||
VerifyOrQuit(rawPowerSetting[0] == 0x01);
|
||||
|
||||
SuccessOrQuit(otPlatRadioSetChannelTargetPower(instance, 11, 15000));
|
||||
rawPowerSettingLength = sizeof(rawPowerSetting);
|
||||
SuccessOrQuit(otPlatRadioGetRawPowerSetting(instance, 11, rawPowerSetting, &rawPowerSettingLength));
|
||||
VerifyOrQuit(rawPowerSettingLength == 1);
|
||||
VerifyOrQuit(rawPowerSetting[0] == 0x02);
|
||||
|
||||
SuccessOrQuit(otPlatRadioSetChannelTargetPower(instance, 11, 15001));
|
||||
rawPowerSettingLength = sizeof(rawPowerSetting);
|
||||
SuccessOrQuit(otPlatRadioGetRawPowerSetting(instance, 11, rawPowerSetting, &rawPowerSettingLength));
|
||||
VerifyOrQuit(rawPowerSettingLength == 1);
|
||||
VerifyOrQuit(rawPowerSetting[0] == 0x02);
|
||||
|
||||
rawPowerSettingLength = sizeof(rawPowerSetting);
|
||||
VerifyOrQuit(otPlatRadioGetRawPowerSetting(instance, 12, rawPowerSetting, &rawPowerSettingLength) ==
|
||||
OT_ERROR_NOT_FOUND);
|
||||
|
||||
SuccessOrQuit(otPlatRadioClearCalibratedPowers(instance));
|
||||
rawPowerSettingLength = sizeof(rawPowerSetting);
|
||||
VerifyOrQuit(otPlatRadioGetRawPowerSetting(instance, 11, rawPowerSetting, &rawPowerSettingLength) ==
|
||||
OT_ERROR_NOT_FOUND);
|
||||
|
||||
for (const CalibratedPowerEntry &calibratedPower : kCalibratedPowerTable)
|
||||
{
|
||||
SuccessOrQuit(otPlatRadioAddCalibratedPower(instance, calibratedPower.mChannel, calibratedPower.mActualPower,
|
||||
calibratedPower.mRawPowerSetting,
|
||||
calibratedPower.mRawPowerSettingLength));
|
||||
}
|
||||
|
||||
SuccessOrQuit(otPlatRadioSetChannelTargetPower(instance, 11, 15000));
|
||||
rawPowerSettingLength = sizeof(rawPowerSetting);
|
||||
SuccessOrQuit(otPlatRadioGetRawPowerSetting(instance, 11, rawPowerSetting, &rawPowerSettingLength));
|
||||
VerifyOrQuit(rawPowerSettingLength == 1);
|
||||
VerifyOrQuit(rawPowerSetting[0] == 0x02);
|
||||
|
||||
VerifyOrQuit(
|
||||
otPlatRadioAddCalibratedPower(instance, kCalibratedPowerTable[0].mChannel,
|
||||
kCalibratedPowerTable[0].mActualPower, kCalibratedPowerTable[0].mRawPowerSetting,
|
||||
kCalibratedPowerTable[0].mRawPowerSettingLength) == OT_ERROR_INVALID_ARGS);
|
||||
|
||||
testFreeInstance(instance);
|
||||
}
|
||||
} // namespace ot
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_POWER_CALIBRATION_ENABLE && OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
|
||||
int main(void)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_POWER_CALIBRATION_ENABLE && OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
ot::TestPowerCalibration();
|
||||
printf("All tests passed\n");
|
||||
#else // OPENTHREAD_CONFIG_POWER_CALIBRATION_ENABLE && OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
printf("Power calibration is not enabled\n");
|
||||
#endif // OPENTHREAD_CONFIG_POWER_CALIBRATION_ENABLE && OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
#
|
||||
# Copyright (c) 2022, 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.
|
||||
#
|
||||
|
||||
if(OT_PLATFORM STREQUAL "posix")
|
||||
add_subdirectory(ot-fct)
|
||||
endif()
|
||||
@@ -0,0 +1,49 @@
|
||||
#
|
||||
# Copyright (c) 2022, 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.
|
||||
#
|
||||
|
||||
project(ot-fct)
|
||||
|
||||
set(OPENTHREAD_DIR ${PROJECT_SOURCE_DIR}/../../)
|
||||
|
||||
include_directories(
|
||||
${OPENTHREAD_DIR}/include
|
||||
${OPENTHREAD_DIR}/src
|
||||
${OPENTHREAD_DIR}/src/core
|
||||
${OPENTHREAD_DIR}/src/posix/platform
|
||||
)
|
||||
|
||||
add_executable(ot-fct
|
||||
cli.cpp
|
||||
main.cpp
|
||||
logging.cpp
|
||||
${OPENTHREAD_DIR}/src/core/common/string.cpp
|
||||
${OPENTHREAD_DIR}/src/core/utils/parse_cmdline.cpp
|
||||
${OPENTHREAD_DIR}/src/lib/platform/exit_code.c
|
||||
${OPENTHREAD_DIR}/src/posix/platform/power.cpp
|
||||
${OPENTHREAD_DIR}/src/posix/platform/config_file.cpp
|
||||
)
|
||||
@@ -0,0 +1,75 @@
|
||||
# OpenThread Factory Tool Reference
|
||||
|
||||
## Overview
|
||||
|
||||
The ot-fct is used to store the power calibration table into the factory configuration file and show the power related tables.
|
||||
|
||||
## Command List
|
||||
|
||||
- [powercalibrationtable](#powercalibrationtable)
|
||||
- [regiondomaintable](#regiondomaintable)
|
||||
- [targetpowertable](#targetpowertable)
|
||||
|
||||
#### powercalibrationtable
|
||||
|
||||
Show the power calibration table.
|
||||
|
||||
```bash
|
||||
> powercalibrationtable
|
||||
| ChStart | ChEnd | ActualPower(0.01dBm) | RawPowerSetting |
|
||||
+---------+---------+----------------------+-----------------+
|
||||
| 11 | 25 | 1900 | 112233 |
|
||||
| 11 | 25 | 1000 | 223344 |
|
||||
| 26 | 26 | 1500 | 334455 |
|
||||
| 26 | 26 | 700 | 445566 |
|
||||
Done
|
||||
```
|
||||
|
||||
#### powercalibrationtable add -b \<channelstart\>,\<channelend\> -c \<actualpower\>,\<rawpowersetting\>/... ...
|
||||
|
||||
Add power calibration table entry.
|
||||
|
||||
- channelstart: Sub-band start channel.
|
||||
- channelend: Sub-band end channel.
|
||||
- actualpower: The actual power in 0.01 dBm.
|
||||
- rawpowersetting: The raw power setting hex string.
|
||||
|
||||
```bash
|
||||
> powercalibrationtable add -b 11,25 -c 1900,112233/1000,223344 -b 26,26 -c 1500,334455/700,445566
|
||||
Done
|
||||
```
|
||||
|
||||
#### powercalibrationtable clear
|
||||
|
||||
Clear the power calibration table.
|
||||
|
||||
```bash
|
||||
> powercalibrationtable clear
|
||||
Done
|
||||
```
|
||||
|
||||
#### regiondomaintable
|
||||
|
||||
Show the region and regulatory domain mapping table.
|
||||
|
||||
```bash
|
||||
> regiondomaintable
|
||||
FCC,AU,CA,CL,CO,IN,MX,PE,TW,US
|
||||
ETSI,WW
|
||||
Done
|
||||
```
|
||||
|
||||
#### targetpowertable
|
||||
|
||||
Show the target power table.
|
||||
|
||||
```bash
|
||||
> targetpowertable
|
||||
| Domain | ChStart | ChEnd | TargetPower(0.01dBm) |
|
||||
+----------+---------+---------+----------------------+
|
||||
| FCC | 11 | 14 | 1700 |
|
||||
| FCC | 15 | 24 | 2000 |
|
||||
| FCC | 25 | 26 | 1600 |
|
||||
| ETSI | 11 | 26 | 1000 |
|
||||
Done
|
||||
```
|
||||
@@ -0,0 +1,329 @@
|
||||
/*
|
||||
* Copyright (c) 2022, 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 strain 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 "cli.hpp"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "power.hpp"
|
||||
#include "common/code_utils.hpp"
|
||||
|
||||
namespace ot {
|
||||
namespace Fct {
|
||||
|
||||
const struct Cli::Command Cli::sCommands[] = {
|
||||
{"powercalibrationtable", &Cli::ProcessCalibrationTable},
|
||||
{"targetpowertable", &Cli::ProcessTargetPowerTable},
|
||||
{"regiondomaintable", &Cli::ProcessRegionDomainTable},
|
||||
};
|
||||
|
||||
otError Cli::GetNextTargetPower(const Power::Domain &aDomain, int &aIterator, Power::TargetPower &aTargetPower)
|
||||
{
|
||||
otError error = OT_ERROR_NOT_FOUND;
|
||||
char value[kMaxValueSize];
|
||||
char *domain;
|
||||
char *psave;
|
||||
|
||||
while (mProductConfigFile.Get(kKeyTargetPower, aIterator, value, sizeof(value)) == OT_ERROR_NONE)
|
||||
{
|
||||
if (((domain = strtok_r(value, kCommaDelimiter, &psave)) == nullptr) || (aDomain != domain))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
error = aTargetPower.FromString(psave);
|
||||
break;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
otError Cli::GetNextDomain(int &aIterator, Power::Domain &aDomain)
|
||||
{
|
||||
otError error = OT_ERROR_NOT_FOUND;
|
||||
char value[kMaxValueSize];
|
||||
char *str;
|
||||
|
||||
while (mProductConfigFile.Get(kKeyRegionDomainMapping, aIterator, value, sizeof(value)) == OT_ERROR_NONE)
|
||||
{
|
||||
if ((str = strtok(value, kCommaDelimiter)) == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
error = aDomain.Set(str);
|
||||
break;
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError Cli::ProcessTargetPowerTable(Utils::CmdLineParser::Arg aArgs[])
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
int iterator = 0;
|
||||
Power::Domain domain;
|
||||
|
||||
VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
printf("| Domain | ChStart | ChEnd | TargetPower(0.01dBm) |\r\n");
|
||||
printf("+----------+---------+---------+----------------------+\r\n");
|
||||
while (GetNextDomain(iterator, domain) == OT_ERROR_NONE)
|
||||
{
|
||||
int iter = 0;
|
||||
Power::TargetPower targetPower;
|
||||
|
||||
while (GetNextTargetPower(domain, iter, targetPower) == OT_ERROR_NONE)
|
||||
{
|
||||
printf("| %-8s | %-7d | %-7d | %-20d |\r\n", domain.AsCString(), targetPower.GetChannelStart(),
|
||||
targetPower.GetChannelEnd(), targetPower.GetTargetPower());
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError Cli::ProcessRegionDomainTable(Utils::CmdLineParser::Arg aArgs[])
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
int iterator = 0;
|
||||
char value[kMaxValueSize];
|
||||
char *domain;
|
||||
char *psave;
|
||||
|
||||
VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
while (mProductConfigFile.Get(kKeyRegionDomainMapping, iterator, value, sizeof(value)) == OT_ERROR_NONE)
|
||||
{
|
||||
printf("%s\r\n", value);
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError Cli::ParseNextCalibratedPower(char *aCalibratedPowerString,
|
||||
uint16_t aLength,
|
||||
uint16_t &aIterator,
|
||||
Power::CalibratedPower &aCalibratedPower)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
char *start = aCalibratedPowerString + aIterator;
|
||||
char *end;
|
||||
char *subString;
|
||||
int16_t actualPower;
|
||||
ot::Power::RawPowerSetting rawPowerSetting;
|
||||
|
||||
VerifyOrExit(aIterator < aLength, error = OT_ERROR_PARSE);
|
||||
|
||||
end = strstr(start, "/");
|
||||
if (end != nullptr)
|
||||
{
|
||||
aIterator = end - aCalibratedPowerString + 1; // +1 to skip '/'
|
||||
*end = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
aIterator = aLength;
|
||||
end = aCalibratedPowerString + aLength;
|
||||
}
|
||||
|
||||
subString = strstr(start, kCommaDelimiter);
|
||||
VerifyOrExit(subString != nullptr, error = OT_ERROR_PARSE);
|
||||
*subString = '\0';
|
||||
subString++;
|
||||
|
||||
SuccessOrExit(error = Utils::CmdLineParser::ParseAsInt16(start, actualPower));
|
||||
aCalibratedPower.SetActualPower(actualPower);
|
||||
|
||||
VerifyOrExit(subString < end, error = OT_ERROR_PARSE);
|
||||
SuccessOrExit(error = rawPowerSetting.Set(subString));
|
||||
aCalibratedPower.SetRawPowerSetting(rawPowerSetting);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError Cli::ProcessCalibrationTable(Utils::CmdLineParser::Arg aArgs[])
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
if (aArgs[0].IsEmpty())
|
||||
{
|
||||
int iterator = 0;
|
||||
char value[kMaxValueSize];
|
||||
|
||||
ot::Power::CalibratedPower calibratedPower;
|
||||
|
||||
printf("| ChStart | ChEnd | ActualPower(0.01dBm) | RawPowerSetting |\r\n");
|
||||
printf("+---------+---------+----------------------+-----------------+\r\n");
|
||||
|
||||
while (mFactoryConfigFile.Get(kKeyCalibratedPower, iterator, value, sizeof(value)) == OT_ERROR_NONE)
|
||||
{
|
||||
SuccessOrExit(error = calibratedPower.FromString(value));
|
||||
printf("| %-7d | %-7d | %-20d | %-15s |\r\n", calibratedPower.GetChannelStart(),
|
||||
calibratedPower.GetChannelEnd(), calibratedPower.GetActualPower(),
|
||||
calibratedPower.GetRawPowerSetting().ToString().AsCString());
|
||||
}
|
||||
}
|
||||
else if (aArgs[0] == "add")
|
||||
{
|
||||
constexpr uint16_t kStateSearchDomain = 0;
|
||||
constexpr uint16_t kStateSearchPower = 1;
|
||||
|
||||
uint8_t state = kStateSearchDomain;
|
||||
char *subString;
|
||||
uint8_t channel;
|
||||
Power::CalibratedPower calibratedPower;
|
||||
|
||||
for (Utils::CmdLineParser::Arg *arg = &aArgs[1]; !arg->IsEmpty(); arg++)
|
||||
{
|
||||
if ((state == kStateSearchDomain) && (*arg == "-b"))
|
||||
{
|
||||
arg++;
|
||||
VerifyOrExit(!arg->IsEmpty(), error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
subString = strtok(arg->GetCString(), kCommaDelimiter);
|
||||
VerifyOrExit(subString != nullptr, error = OT_ERROR_PARSE);
|
||||
SuccessOrExit(error = Utils::CmdLineParser::ParseAsUint8(subString, channel));
|
||||
calibratedPower.SetChannelStart(channel);
|
||||
|
||||
subString = strtok(NULL, kCommaDelimiter);
|
||||
VerifyOrExit(subString != nullptr, error = OT_ERROR_PARSE);
|
||||
SuccessOrExit(error = Utils::CmdLineParser::ParseAsUint8(subString, channel));
|
||||
calibratedPower.SetChannelEnd(channel);
|
||||
VerifyOrExit(calibratedPower.GetChannelStart() <= calibratedPower.GetChannelEnd(),
|
||||
error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
state = kStateSearchPower;
|
||||
}
|
||||
else if ((state == kStateSearchPower) && (*arg == "-c"))
|
||||
{
|
||||
uint16_t length;
|
||||
uint16_t iterator = 0;
|
||||
|
||||
arg++;
|
||||
VerifyOrExit(!arg->IsEmpty(), error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
length = strlen(arg->GetCString());
|
||||
while (ParseNextCalibratedPower(arg->GetCString(), length, iterator, calibratedPower) == OT_ERROR_NONE)
|
||||
{
|
||||
SuccessOrExit(
|
||||
error = mFactoryConfigFile.Add(kKeyCalibratedPower, calibratedPower.ToString().AsCString()));
|
||||
}
|
||||
|
||||
state = kStateSearchDomain;
|
||||
}
|
||||
else
|
||||
{
|
||||
error = OT_ERROR_INVALID_ARGS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (state == kStateSearchPower)
|
||||
{
|
||||
error = OT_ERROR_INVALID_ARGS;
|
||||
}
|
||||
}
|
||||
else if (aArgs[0] == "clear")
|
||||
{
|
||||
error = mFactoryConfigFile.Clear(kKeyCalibratedPower);
|
||||
}
|
||||
else
|
||||
{
|
||||
error = OT_ERROR_INVALID_ARGS;
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void Cli::ProcessCommand(Utils::CmdLineParser::Arg aArgs[])
|
||||
{
|
||||
otError error = OT_ERROR_NOT_FOUND;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < (sizeof(sCommands) / sizeof(sCommands[0])); i++)
|
||||
{
|
||||
if (strcmp(aArgs[0].GetCString(), sCommands[i].mName) == 0)
|
||||
{
|
||||
error = (this->*sCommands[i].mCommand)(aArgs + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
AppendErrorResult(error);
|
||||
}
|
||||
|
||||
void Cli::ProcessLine(char *aLine)
|
||||
{
|
||||
const int kMaxArgs = 20;
|
||||
Utils::CmdLineParser::Arg args[kMaxArgs + 1];
|
||||
|
||||
SuccessOrExit(ot::Utils::CmdLineParser::ParseCmd(aLine, args, kMaxArgs));
|
||||
VerifyOrExit(!args[0].IsEmpty());
|
||||
|
||||
ProcessCommand(args);
|
||||
|
||||
exit:
|
||||
OutputPrompt();
|
||||
}
|
||||
|
||||
void Cli::OutputPrompt(void)
|
||||
{
|
||||
printf("> ");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
void Cli::AppendErrorResult(otError aError)
|
||||
{
|
||||
if (aError != OT_ERROR_NONE)
|
||||
{
|
||||
printf("failed\r\nstatus %#x\r\n", aError);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Done\r\n");
|
||||
}
|
||||
|
||||
fflush(stdout);
|
||||
}
|
||||
} // namespace Fct
|
||||
} // namespace ot
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (c) 2022, 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 strain 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.
|
||||
*/
|
||||
|
||||
#ifndef CLI_H
|
||||
#define CLI_H
|
||||
|
||||
#include "openthread-posix-config.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "config_file.hpp"
|
||||
#include "power.hpp"
|
||||
#include "utils/parse_cmdline.hpp"
|
||||
|
||||
#include <openthread/error.h>
|
||||
#include <openthread/platform/radio.h>
|
||||
|
||||
namespace ot {
|
||||
namespace Fct {
|
||||
|
||||
class Cli;
|
||||
|
||||
/**
|
||||
* This class implements the factory CLI.
|
||||
*
|
||||
*/
|
||||
class Cli
|
||||
{
|
||||
public:
|
||||
Cli(void)
|
||||
: mFactoryConfigFile(OPENTHREAD_POSIX_CONFIG_FACTORY_CONFIG_FILE)
|
||||
, mProductConfigFile(OPENTHREAD_POSIX_CONFIG_PRODUCT_CONFIG_FILE)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* This method processes a factory command.
|
||||
*
|
||||
* @param[in] aArgs The arguments of command line.
|
||||
* @param[in] aArgsLength The number of args in @p aArgs.
|
||||
*
|
||||
*/
|
||||
void ProcessCommand(Utils::CmdLineParser::Arg aArgs[]);
|
||||
|
||||
/**
|
||||
* This method processes the command line.
|
||||
*
|
||||
* @param[in] aLine A pointer to a command line string.
|
||||
*
|
||||
*/
|
||||
void ProcessLine(char *aLine);
|
||||
|
||||
/**
|
||||
* This method outputs the prompt.
|
||||
*
|
||||
*/
|
||||
void OutputPrompt(void);
|
||||
|
||||
private:
|
||||
static constexpr uint16_t kMaxValueSize = 512;
|
||||
const char *kKeyCalibratedPower = "calibrated_power";
|
||||
const char *kKeyTargetPower = "target_power";
|
||||
const char *kKeyRegionDomainMapping = "region_domain_mapping";
|
||||
const char *kCommaDelimiter = ",";
|
||||
|
||||
struct Command
|
||||
{
|
||||
const char *mName;
|
||||
otError (Cli::*mCommand)(Utils::CmdLineParser::Arg aArgs[]);
|
||||
};
|
||||
|
||||
otError ParseNextCalibratedPower(char *aCalibratedPowerString,
|
||||
uint16_t aLength,
|
||||
uint16_t &aIterator,
|
||||
Power::CalibratedPower &aCalibratedPower);
|
||||
otError ProcessCalibrationTable(Utils::CmdLineParser::Arg aArgs[]);
|
||||
otError ProcessTargetPowerTable(Utils::CmdLineParser::Arg aArgs[]);
|
||||
otError ProcessRegionDomainTable(Utils::CmdLineParser::Arg aArgs[]);
|
||||
otError GetNextDomain(int &aIterator, Power::Domain &aDomain);
|
||||
otError GetNextTargetPower(const Power::Domain &aDomain, int &aIterator, Power::TargetPower &aTargetPower);
|
||||
|
||||
void AppendErrorResult(otError aError);
|
||||
|
||||
static const struct Command sCommands[];
|
||||
|
||||
ot::Posix::ConfigFile mFactoryConfigFile;
|
||||
ot::Posix::ConfigFile mProductConfigFile;
|
||||
};
|
||||
} // namespace Fct
|
||||
} // namespace ot
|
||||
#endif
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2022, 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 strain 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <openthread/logging.h>
|
||||
|
||||
void otLogCritPlat(const char *aFormat, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, aFormat);
|
||||
vprintf(aFormat, args);
|
||||
va_end(args);
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (c) 2022, 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 strain 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 <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/select.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "cli.hpp"
|
||||
|
||||
static ot::Fct::Cli sCli;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc >= 2)
|
||||
{
|
||||
const int kMaxArgs = 20;
|
||||
ot::Utils::CmdLineParser::Arg args[kMaxArgs + 1];
|
||||
|
||||
if (argc - 1 > kMaxArgs)
|
||||
{
|
||||
fprintf(stderr, "Too many arguments!\r\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
for (int i = 0; i < argc - 1; i++)
|
||||
{
|
||||
args[i].SetCString(argv[i + 1]);
|
||||
}
|
||||
args[argc - 1].Clear();
|
||||
|
||||
sCli.ProcessCommand(args);
|
||||
}
|
||||
else
|
||||
{
|
||||
fd_set rset;
|
||||
int maxFd;
|
||||
int ret;
|
||||
|
||||
sCli.OutputPrompt();
|
||||
|
||||
while (true)
|
||||
{
|
||||
FD_ZERO(&rset);
|
||||
FD_SET(STDIN_FILENO, &rset);
|
||||
maxFd = STDIN_FILENO + 1;
|
||||
|
||||
ret = select(maxFd, &rset, nullptr, nullptr, nullptr);
|
||||
|
||||
if ((ret == -1) && (errno != EINTR))
|
||||
{
|
||||
fprintf(stderr, "select: %s\n", strerror(errno));
|
||||
break;
|
||||
}
|
||||
else if (ret > 0)
|
||||
{
|
||||
if (FD_ISSET(STDIN_FILENO, &rset))
|
||||
{
|
||||
const int kBufferSize = 512;
|
||||
char buffer[kBufferSize];
|
||||
|
||||
if (fgets(buffer, sizeof(buffer), stdin) != nullptr)
|
||||
{
|
||||
sCli.ProcessLine(buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
Reference in New Issue
Block a user