mirror of
https://github.com/espressif/openthread.git
synced 2026-06-06 05:24:51 +00:00
[simulation] simulate energy scan (#7393)
This commit implements energy scan in simulation platform. Verified locally ```bash > ifconfig up Done > scan energy 100 | Ch | RSSI | +----+------+ | 11 | -98 | | 12 | -98 | | 13 | -98 | | 14 | -98 | | 15 | -30 | | 16 | -30 | | 17 | -98 | | 18 | -98 | | 19 | -30 | | 20 | -98 | | 21 | -98 | | 22 | -98 | | 23 | -30 | | 24 | -30 | | 25 | -30 | | 26 | -98 | Done ```
This commit is contained in:
@@ -163,10 +163,11 @@ void platformRadioReceive(otInstance *aInstance, uint8_t *aBuf, uint16_t aBufLen
|
||||
*
|
||||
* @param[in,out] aReadFdSet A pointer to the read file descriptors.
|
||||
* @param[in,out] aWriteFdSet A pointer to the write file descriptors.
|
||||
* @param[in,out] aTimeout A pointer to the timeout.
|
||||
* @param[in,out] aMaxFd A pointer to the max file descriptor.
|
||||
*
|
||||
*/
|
||||
void platformRadioUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, int *aMaxFd);
|
||||
void platformRadioUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, struct timeval *aTimeout, int *aMaxFd);
|
||||
|
||||
/**
|
||||
* This function performs radio driver processing.
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "platform-simulation.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <openthread/dataset.h>
|
||||
#include <openthread/link.h>
|
||||
@@ -47,6 +48,9 @@
|
||||
// The IPv4 group for receiving packets of radio simulation
|
||||
#define OT_RADIO_GROUP "224.0.0.116"
|
||||
|
||||
#define MS_PER_S 1000
|
||||
#define US_PER_MS 1000
|
||||
|
||||
enum
|
||||
{
|
||||
IEEE802154_ACK_LENGTH = 5,
|
||||
@@ -75,6 +79,10 @@ static uint16_t sPortOffset = 0;
|
||||
static uint16_t sPort = 0;
|
||||
#endif
|
||||
|
||||
static int8_t sEnergyScanResult = OT_RADIO_RSSI_INVALID;
|
||||
static bool sEnergyScanning = false;
|
||||
static uint32_t sEnergyScanEndTime = 0;
|
||||
|
||||
enum
|
||||
{
|
||||
SIM_RADIO_CHANNEL_MIN = OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MIN,
|
||||
@@ -156,6 +164,13 @@ static otMacKeyMaterial sCurrKey;
|
||||
static otMacKeyMaterial sNextKey;
|
||||
static otRadioKeyType sKeyType;
|
||||
|
||||
static int8_t GetRssi(uint16_t aChannel);
|
||||
|
||||
static bool IsTimeAfterOrEqual(uint32_t aTimeA, uint32_t aTimeB)
|
||||
{
|
||||
return (aTimeA - aTimeB) < (1U << 31);
|
||||
}
|
||||
|
||||
static void ReverseExtAddress(otExtAddress *aReversed, const otExtAddress *aOrigin)
|
||||
{
|
||||
for (size_t i = 0; i < sizeof(*aReversed); i++)
|
||||
@@ -493,20 +508,23 @@ otRadioFrame *otPlatRadioGetTransmitBuffer(otInstance *aInstance)
|
||||
int8_t otPlatRadioGetRssi(otInstance *aInstance)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
assert(aInstance != NULL);
|
||||
|
||||
int8_t rssi = SIM_LOW_RSSI_SAMPLE;
|
||||
uint8_t channel = sReceiveFrame.mChannel;
|
||||
return GetRssi(sReceiveFrame.mChannel);
|
||||
}
|
||||
|
||||
static int8_t GetRssi(uint16_t aChannel)
|
||||
{
|
||||
int8_t rssi = SIM_LOW_RSSI_SAMPLE;
|
||||
uint32_t probabilityThreshold;
|
||||
|
||||
otEXPECT((SIM_RADIO_CHANNEL_MIN <= channel) && channel <= (SIM_RADIO_CHANNEL_MAX));
|
||||
otEXPECT((SIM_RADIO_CHANNEL_MIN <= aChannel) && aChannel <= (SIM_RADIO_CHANNEL_MAX));
|
||||
|
||||
// To emulate a simple interference model, we return either a high or
|
||||
// a low RSSI value with a fixed probability per each channel. The
|
||||
// probability is increased per channel by a constant.
|
||||
|
||||
probabilityThreshold = (channel - SIM_RADIO_CHANNEL_MIN) * SIM_HIGH_RSSI_PROB_INC_PER_CHANNEL;
|
||||
probabilityThreshold = (aChannel - SIM_RADIO_CHANNEL_MIN) * SIM_HIGH_RSSI_PROB_INC_PER_CHANNEL;
|
||||
|
||||
if (otRandomNonCryptoGetUint16() < (probabilityThreshold * 0xffff / 100))
|
||||
{
|
||||
@@ -736,7 +754,7 @@ void platformRadioReceive(otInstance *aInstance, uint8_t *aBuf, uint16_t aBufLen
|
||||
radioReceive(aInstance);
|
||||
}
|
||||
#else
|
||||
void platformRadioUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, int *aMaxFd)
|
||||
void platformRadioUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, struct timeval *aTimeout, int *aMaxFd)
|
||||
{
|
||||
if (aReadFdSet != NULL && (sState != OT_RADIO_STATE_TRANSMIT || sTxWait))
|
||||
{
|
||||
@@ -757,6 +775,25 @@ void platformRadioUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, int *aMax
|
||||
*aMaxFd = sTxFd;
|
||||
}
|
||||
}
|
||||
|
||||
if (sEnergyScanning)
|
||||
{
|
||||
struct timeval tv = {0, 0};
|
||||
uint32_t now = otPlatAlarmMilliGetNow();
|
||||
|
||||
if (IsTimeAfterOrEqual(sEnergyScanEndTime, now))
|
||||
{
|
||||
uint32_t remaining = sEnergyScanEndTime - now;
|
||||
|
||||
tv.tv_sec = remaining / MS_PER_S;
|
||||
tv.tv_usec = (remaining % MS_PER_S) * US_PER_MS;
|
||||
}
|
||||
|
||||
if (timercmp(&tv, aTimeout, <))
|
||||
{
|
||||
*aTimeout = tv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no need to close in virtual time mode.
|
||||
@@ -811,11 +848,16 @@ void platformRadioProcess(otInstance *aInstance, const fd_set *aReadFdSet, const
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (platformRadioIsTransmitPending())
|
||||
{
|
||||
radioSendMessage(aInstance);
|
||||
}
|
||||
|
||||
if (sEnergyScanning && IsTimeAfterOrEqual(otPlatAlarmMilliGetNow(), sEnergyScanEndTime))
|
||||
{
|
||||
sEnergyScanning = false;
|
||||
otPlatRadioEnergyScanDone(aInstance, sEnergyScanResult);
|
||||
}
|
||||
}
|
||||
|
||||
void radioTransmit(struct RadioMessage *aMessage, const struct otRadioFrame *aFrame)
|
||||
@@ -982,13 +1024,22 @@ otError otPlatRadioEnergyScan(otInstance *aInstance, uint8_t aScanChannel, uint1
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
OT_UNUSED_VARIABLE(aScanChannel);
|
||||
OT_UNUSED_VARIABLE(aScanDuration);
|
||||
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
assert(aInstance != NULL);
|
||||
assert(aScanChannel >= SIM_RADIO_CHANNEL_MIN && aScanChannel <= SIM_RADIO_CHANNEL_MAX);
|
||||
assert(aScanDuration > 0);
|
||||
|
||||
return OT_ERROR_NOT_IMPLEMENTED;
|
||||
otEXPECT_ACTION((gRadioCaps & OT_RADIO_CAPS_ENERGY_SCAN), error = OT_ERROR_NOT_IMPLEMENTED);
|
||||
otEXPECT_ACTION(!sEnergyScanning, error = OT_ERROR_BUSY);
|
||||
|
||||
sEnergyScanResult = GetRssi(aScanChannel);
|
||||
sEnergyScanning = true;
|
||||
sEnergyScanEndTime = otPlatAlarmMilliGetNow() + aScanDuration;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError otPlatRadioGetTransmitPower(otInstance *aInstance, int8_t *aPower)
|
||||
|
||||
@@ -70,10 +70,11 @@ static void handleSignal(int aSignal)
|
||||
*/
|
||||
enum
|
||||
{
|
||||
OT_SIM_OPT_HELP = 'h',
|
||||
OT_SIM_OPT_SLEEP_TO_TX = 't',
|
||||
OT_SIM_OPT_TIME_SPEED = 's',
|
||||
OT_SIM_OPT_UNKNOWN = '?',
|
||||
OT_SIM_OPT_HELP = 'h',
|
||||
OT_SIM_OPT_ENABLE_ENERGY_SCAN = 'E',
|
||||
OT_SIM_OPT_SLEEP_TO_TX = 't',
|
||||
OT_SIM_OPT_TIME_SPEED = 's',
|
||||
OT_SIM_OPT_UNKNOWN = '?',
|
||||
};
|
||||
|
||||
static void PrintUsage(const char *aProgramName, int aExitCode)
|
||||
@@ -82,9 +83,10 @@ static void PrintUsage(const char *aProgramName, int aExitCode)
|
||||
"Syntax:\n"
|
||||
" %s [Options] NodeId\n"
|
||||
"Options:\n"
|
||||
" -h --help Display this usage information.\n"
|
||||
" -t --sleep-to-tx Let radio support direct transition from sleep to TX with CSMA.\n"
|
||||
" -s --time-speed=val Speed up the time in simulation.\n",
|
||||
" -h --help Display this usage information.\n"
|
||||
" -E --enable-energy-scan Enable energy scan capability.\n"
|
||||
" -t --sleep-to-tx Let radio support direct transition from sleep to TX with CSMA.\n"
|
||||
" -s --time-speed=val Speed up the time in simulation.\n",
|
||||
aProgramName);
|
||||
|
||||
exit(aExitCode);
|
||||
@@ -97,6 +99,7 @@ void otSysInit(int aArgCount, char *aArgVector[])
|
||||
|
||||
static const struct option long_options[] = {
|
||||
{"help", no_argument, 0, OT_SIM_OPT_HELP},
|
||||
{"enable-energy-scan", no_argument, 0, OT_SIM_OPT_SLEEP_TO_TX},
|
||||
{"sleep-to-tx", no_argument, 0, OT_SIM_OPT_SLEEP_TO_TX},
|
||||
{"time-speed", required_argument, 0, OT_SIM_OPT_TIME_SPEED},
|
||||
{0, 0, 0, 0},
|
||||
@@ -112,7 +115,7 @@ void otSysInit(int aArgCount, char *aArgVector[])
|
||||
|
||||
while (true)
|
||||
{
|
||||
int c = getopt_long(aArgCount, aArgVector, "hts:", long_options, NULL);
|
||||
int c = getopt_long(aArgCount, aArgVector, "Ehts:", long_options, NULL);
|
||||
|
||||
if (c == -1)
|
||||
{
|
||||
@@ -127,6 +130,9 @@ void otSysInit(int aArgCount, char *aArgVector[])
|
||||
case OT_SIM_OPT_HELP:
|
||||
PrintUsage(aArgVector[0], EXIT_SUCCESS);
|
||||
break;
|
||||
case OT_SIM_OPT_ENABLE_ENERGY_SCAN:
|
||||
gRadioCaps |= OT_RADIO_CAPS_ENERGY_SCAN;
|
||||
break;
|
||||
case OT_SIM_OPT_SLEEP_TO_TX:
|
||||
gRadioCaps |= OT_RADIO_CAPS_SLEEP_TO_TX;
|
||||
break;
|
||||
@@ -197,8 +203,8 @@ void otSysProcessDrivers(otInstance *aInstance)
|
||||
FD_ZERO(&error_fds);
|
||||
|
||||
platformUartUpdateFdSet(&read_fds, &write_fds, &error_fds, &max_fd);
|
||||
platformRadioUpdateFdSet(&read_fds, &write_fds, &max_fd);
|
||||
platformAlarmUpdateTimeout(&timeout);
|
||||
platformRadioUpdateFdSet(&read_fds, &write_fds, &timeout, &max_fd);
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
platformTrelUpdateFdSet(&read_fds, &write_fds, &timeout, &max_fd);
|
||||
#endif
|
||||
|
||||
@@ -53,7 +53,7 @@ extern "C" {
|
||||
* @note This number versions both OpenThread platform and user APIs.
|
||||
*
|
||||
*/
|
||||
#define OPENTHREAD_API_VERSION (208)
|
||||
#define OPENTHREAD_API_VERSION (209)
|
||||
|
||||
/**
|
||||
* @addtogroup api-instance
|
||||
|
||||
@@ -236,6 +236,7 @@ typedef void (*otLinkRawEnergyScanDone)(otInstance *aInstance, int8_t aEnergySca
|
||||
* @param[in] aCallback A pointer to a function called on completion of a scanned channel.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully started scanning the channel.
|
||||
* @retval OT_ERROR_BUSY The radio is performing enery scanning.
|
||||
* @retval OT_ERROR_NOT_IMPLEMENTED The radio doesn't support energy scanning.
|
||||
* @retval OT_ERROR_INVALID_STATE If the raw link-layer isn't enabled.
|
||||
*
|
||||
|
||||
@@ -857,6 +857,7 @@ int8_t otPlatRadioGetRssi(otInstance *aInstance);
|
||||
* @param[in] aScanDuration The duration, in milliseconds, for the channel to be scanned.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully started scanning the channel.
|
||||
* @retval OT_ERROR_BUSY The radio is performing enery scanning.
|
||||
* @retval OT_ERROR_NOT_IMPLEMENTED The radio doesn't support energy scanning.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -164,6 +164,7 @@ public:
|
||||
* @param[in] aCallback A pointer to a function called on completion of a scanned channel.
|
||||
*
|
||||
* @retval kErrorNone Successfully started scanning the channel.
|
||||
* @retval kErrorBusy The radio is performing energy scanning.
|
||||
* @retval kErrorNotImplemented The radio doesn't support energy scanning.
|
||||
* @retval kErrorInvalidState If the raw link-layer isn't enabled.
|
||||
*
|
||||
|
||||
@@ -572,6 +572,7 @@ public:
|
||||
* @param[in] aScanDuration The duration, in milliseconds, for the channel to be scanned.
|
||||
*
|
||||
* @retval kErrorNone Successfully started scanning the channel.
|
||||
* @retval kErrorBusy The radio is performing energy scanning.
|
||||
* @retval kErrorInvalidState The radio was disabled or transmitting.
|
||||
* @retval kErrorNotImplemented Energy scan is not supported by radio link.
|
||||
*
|
||||
|
||||
@@ -379,6 +379,7 @@ public:
|
||||
* @param[in] aScanDuration The duration, in milliseconds, for the channel to be scanned.
|
||||
*
|
||||
* @retval kErrorNone Successfully started scanning the channel.
|
||||
* @retval kErrorBusy The radio is performing energy scanning.
|
||||
* @retval kErrorInvalidState The radio was disabled or transmitting.
|
||||
* @retval kErrorNotImplemented Energy scan is not supported (applicable in link-raw/radio mode only).
|
||||
*
|
||||
|
||||
@@ -522,6 +522,7 @@ public:
|
||||
* @param[in] aScanDuration The duration, in milliseconds, for the channel to be scanned.
|
||||
*
|
||||
* @retval kErrorNone Successfully started scanning the channel.
|
||||
* @retval kErrorBusy The radio is performing energy scanning.
|
||||
* @retval kErrorNotImplemented The radio doesn't support energy scanning.
|
||||
*
|
||||
*/
|
||||
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
#!/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_node 1 "rcp" "spinel+hdlc+forkpty://$::env(OT_SIMULATION_APPS)/ncp/ot-rcp?forkpty-arg=1&forkpty-arg=-E&no-reset=1"
|
||||
|
||||
send "ifconfig up\n"
|
||||
expect_line "Done"
|
||||
# Actually returns last otPlatRadioGetRssi
|
||||
send "scan energy 0\n"
|
||||
expect_line "Done"
|
||||
# Actually performs energy scan on RCP
|
||||
send "scan energy 100\n"
|
||||
expect_line "Done"
|
||||
dispose_all
|
||||
Reference in New Issue
Block a user