mirror of
https://github.com/espressif/openthread.git
synced 2026-10-26 17:24:00 +00:00
Allow setting per-channel target power via otPlatRadioSetChannelTargetPower() and SPINEL_PROP_PHY_CHAN_TARGET_POWER without requiring OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE.
251 lines
9.9 KiB
C++
251 lines
9.9 KiB
C++
/*
|
|
* Copyright (c) 2024, 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 OT_GTEST_FAKE_PLATFORM_HPP_
|
|
#define OT_GTEST_FAKE_PLATFORM_HPP_
|
|
|
|
#include "openthread-core-config.h"
|
|
|
|
#include <map>
|
|
#include <set>
|
|
#include <vector>
|
|
|
|
#include <inttypes.h>
|
|
|
|
#include <openthread/error.h>
|
|
#include <openthread/instance.h>
|
|
#include <openthread/platform/alarm-micro.h>
|
|
#include <openthread/platform/alarm-milli.h>
|
|
#include <openthread/platform/radio.h>
|
|
#include <openthread/platform/time.h>
|
|
|
|
bool operator<(const otExtAddress &aLeft, const otExtAddress &aRight);
|
|
|
|
namespace ot {
|
|
|
|
class FakePlatform
|
|
{
|
|
public:
|
|
FakePlatform();
|
|
virtual ~FakePlatform();
|
|
|
|
static FakePlatform &CurrentPlatform() { return *sPlatform; }
|
|
static otInstance *CurrentInstance() { return CurrentPlatform().mInstance; }
|
|
|
|
/**
|
|
* Run until something happened or timeout.
|
|
*
|
|
* @param aTimeout The timeout in us.
|
|
*
|
|
* @returns the remaining timeout.
|
|
*/
|
|
uint64_t Run(uint64_t aTimeoutInUs = 0);
|
|
|
|
void GoInUs(uint64_t aTimeoutInUs = 0);
|
|
|
|
void GoInMs(uint32_t aTimeoutInMs = 0) { GoInUs(aTimeoutInMs * OT_US_PER_MS); }
|
|
|
|
void UpdateRadioAvailability(otRadioTime64 aStartTime,
|
|
otRadioAvailabilitySlotDuration aSlotDuration,
|
|
const uint8_t *aAvailableSlots,
|
|
const uint8_t *aPreferredSlots,
|
|
uint8_t aNumSlots);
|
|
|
|
virtual otError GetRadioAvailability(otRadioAvailability &aAvailability) const;
|
|
|
|
virtual uint64_t GetNow() const { return mNow; }
|
|
|
|
virtual void StartMilliAlarm(uint32_t aT0, uint32_t aDt);
|
|
virtual void StopMilliAlarm();
|
|
#if OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE
|
|
virtual void StartMicroAlarm(uint32_t aT0, uint32_t aDt);
|
|
virtual void StopMicroAlarm();
|
|
#endif
|
|
|
|
uint8_t GetReceiveChannel(void) const { return mChannel; }
|
|
virtual otRadioFrame *GetTransmitBuffer() { return &mTransmitFrame; }
|
|
virtual otError Transmit(otRadioFrame *aFrame);
|
|
virtual otError ReceiveAt(uint8_t aChannel, uint32_t aStart, uint32_t aDuration)
|
|
{
|
|
mReceiveAtChannel = aChannel;
|
|
mReceiveAtStart = mNow + aStart;
|
|
mReceiveAtEnd = mReceiveAtStart + aDuration;
|
|
|
|
return OT_ERROR_NONE;
|
|
}
|
|
|
|
virtual otError Receive(uint8_t aChannel)
|
|
{
|
|
mChannel = aChannel;
|
|
return OT_ERROR_NONE;
|
|
}
|
|
|
|
virtual otError SettingsGet(uint16_t aKey, uint16_t aIndex, uint8_t *aValue, uint16_t *aValueLength) const;
|
|
virtual otError SettingsSet(uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength);
|
|
virtual otError SettingsAdd(uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength);
|
|
virtual otError SettingsDelete(uint16_t aKey, int aIndex);
|
|
virtual void SettingsWipe();
|
|
|
|
virtual void FlashInit();
|
|
virtual void FlashErase(uint8_t aSwapIndex);
|
|
virtual void FlashRead(uint8_t aSwapIndex, uint32_t aOffset, void *aData, uint32_t aSize) const;
|
|
virtual void FlashWrite(uint8_t aSwapIndex, uint32_t aOffset, const void *aData, uint32_t aSize);
|
|
virtual uint32_t FlashGetSwapSize() const { return kFlashSwapSize; }
|
|
|
|
virtual uint64_t GetEui64() const { return 0; }
|
|
|
|
virtual void SrcMatchEnable(bool aEnabled) { mSrcMatchEnabled = aEnabled; }
|
|
virtual bool SrcMatchIsEnabled() const { return mSrcMatchEnabled; }
|
|
virtual void SrcMatchAddShortEntry(uint16_t aShortAddr) { mSrcMatchShortAddrs.insert(aShortAddr); }
|
|
virtual void SrcMatchClearShortEntry(uint16_t aShortAddr) { mSrcMatchShortAddrs.erase(aShortAddr); }
|
|
virtual bool SrcMatchHasShortEntry(uint16_t aShortAddr) const { return mSrcMatchShortAddrs.count(aShortAddr) != 0; }
|
|
virtual void SrcMatchAddExtEntry(const otExtAddress &aExtAddr) { mSrcMatchExtAddrs.insert(aExtAddr); }
|
|
virtual void SrcMatchClearExtEntry(const otExtAddress &aExtAddr) { mSrcMatchExtAddrs.erase(aExtAddr); }
|
|
virtual bool SrcMatchHasExtEntry(const otExtAddress &aExtAddr) const
|
|
{
|
|
return mSrcMatchExtAddrs.count(aExtAddr) != 0;
|
|
}
|
|
virtual void SrcMatchClearShortEntries(void) { mSrcMatchShortAddrs.clear(); }
|
|
virtual size_t SrcMatchCountShortEntries(void) const { return mSrcMatchShortAddrs.size(); }
|
|
virtual void SrcMatchClearExtEntries(void) { mSrcMatchExtAddrs.clear(); }
|
|
virtual size_t SrcMatchCountExtEntries(void) const { return mSrcMatchExtAddrs.size(); }
|
|
|
|
// Records what the RCP was told, so a test can assert which channel got
|
|
// which power rather than only that something was sent.
|
|
static constexpr int8_t kNoMaxTxPower = INT8_MIN;
|
|
|
|
virtual otError ChannelMaxTxPowerSet(uint8_t aChannel, int8_t aPower)
|
|
{
|
|
otError error = mChannelMaxTxPowerError;
|
|
|
|
if (error == OT_ERROR_NONE)
|
|
{
|
|
mChannelMaxTxPower[aChannel] = aPower;
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
// Makes the fake RCP refuse the property, the way a firmware without
|
|
// `SPINEL_PROP_PHY_CHAN_MAX_POWER` does.
|
|
virtual void ChannelMaxTxPowerFailWith(otError aError) { mChannelMaxTxPowerError = aError; }
|
|
virtual int8_t ChannelMaxTxPowerGet(uint8_t aChannel) const
|
|
{
|
|
auto it = mChannelMaxTxPower.find(aChannel);
|
|
return (it == mChannelMaxTxPower.end()) ? kNoMaxTxPower : it->second;
|
|
}
|
|
virtual void ChannelMaxTxPowerClear(void) { mChannelMaxTxPower.clear(); }
|
|
virtual size_t ChannelMaxTxPowerCount(void) const { return mChannelMaxTxPower.size(); }
|
|
|
|
static constexpr int16_t kNoTargetPower = INT16_MIN;
|
|
|
|
virtual otError ChannelTargetPowerSet(uint8_t aChannel, int16_t aTargetPower)
|
|
{
|
|
otError error = mChannelTargetPowerError;
|
|
|
|
if (error == OT_ERROR_NONE)
|
|
{
|
|
mChannelTargetPower[aChannel] = aTargetPower;
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
virtual void ChannelTargetPowerFailWith(otError aError) { mChannelTargetPowerError = aError; }
|
|
virtual int16_t ChannelTargetPowerGet(uint8_t aChannel) const
|
|
{
|
|
auto it = mChannelTargetPower.find(aChannel);
|
|
return (it == mChannelTargetPower.end()) ? kNoTargetPower : it->second;
|
|
}
|
|
virtual void ChannelTargetPowerClear(void) { mChannelTargetPower.clear(); }
|
|
virtual size_t ChannelTargetPowerCount(void) const { return mChannelTargetPower.size(); }
|
|
|
|
protected:
|
|
void ProcessSchedules(uint64_t &aTimeout);
|
|
|
|
static constexpr uint64_t kAlarmStop = 0xffffffffffffffffUL;
|
|
|
|
static constexpr uint32_t kFlashSwapSize = 2048;
|
|
static constexpr uint32_t kFlashSwapNum = 2;
|
|
|
|
static FakePlatform *sPlatform;
|
|
|
|
otInstance *mInstance = nullptr;
|
|
|
|
uint64_t mNow = 0;
|
|
#if OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE
|
|
uint64_t mMicroAlarmStart = kAlarmStop;
|
|
#endif
|
|
uint64_t mMilliAlarmStart = kAlarmStop;
|
|
|
|
uint64_t mReceiveAtStart = kAlarmStop;
|
|
uint64_t mReceiveAtEnd = kAlarmStop;
|
|
|
|
template <uint64_t FakePlatform::*T> void HandleSchedule();
|
|
|
|
otRadioFrame mTransmitFrame{};
|
|
uint8_t mTransmitBuffer[OT_RADIO_FRAME_MAX_SIZE]{};
|
|
uint8_t mChannel = 0;
|
|
uint8_t mReceiveAtChannel = 0;
|
|
|
|
uint8_t mFlash[kFlashSwapSize * kFlashSwapNum];
|
|
|
|
std::map<uint32_t, std::vector<std::vector<uint8_t>>> mSettings;
|
|
|
|
bool mSrcMatchEnabled = false;
|
|
std::set<uint16_t> mSrcMatchShortAddrs;
|
|
std::set<otExtAddress> mSrcMatchExtAddrs;
|
|
std::map<uint8_t, int8_t> mChannelMaxTxPower;
|
|
otError mChannelMaxTxPowerError = OT_ERROR_NONE;
|
|
std::map<uint8_t, int16_t> mChannelTargetPower;
|
|
otError mChannelTargetPowerError = OT_ERROR_NONE;
|
|
|
|
bool mHasRadioAvailability = false;
|
|
otRadioTime64 mRadioAvailStartTime = 0;
|
|
otRadioAvailabilitySlotDuration mRadioAvailSlotDuration = OT_RADIO_AVAILABILITY_SLOT_DURATION_625_US;
|
|
uint8_t mRadioAvailNumSlots = 0;
|
|
std::vector<uint8_t> mRadioAvailAvailableSlots;
|
|
std::vector<uint8_t> mRadioAvailPreferredSlots;
|
|
};
|
|
|
|
template <> inline void FakePlatform::HandleSchedule<&FakePlatform::mMilliAlarmStart>()
|
|
{
|
|
otPlatAlarmMilliFired(mInstance);
|
|
}
|
|
|
|
#if OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE
|
|
template <> inline void FakePlatform::HandleSchedule<&FakePlatform::mMicroAlarmStart>()
|
|
{
|
|
otPlatAlarmMicroFired(mInstance);
|
|
}
|
|
#endif
|
|
|
|
} // namespace ot
|
|
|
|
#endif // OT_GTEST_FAKE_PLATFORM_HPP_
|