mirror of
https://github.com/espressif/openthread.git
synced 2026-08-25 03:39:52 +00:00
[spinel] add SPINEL_PROP_MAC_RX_AT (#10921)
This commit adds receive at functionality for spinel for host to schedule reception on RCP.
This commit is contained in:
@@ -1727,6 +1727,20 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError RadioSpinel::ReceiveAt(uint64_t aWhen, uint32_t aDuration, uint8_t aChannel)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
EXPECT(mState != kStateDisabled, error = OT_ERROR_INVALID_STATE);
|
||||
|
||||
error = Set(SPINEL_PROP_MAC_RX_AT, SPINEL_DATATYPE_UINT64_S SPINEL_DATATYPE_UINT32_S SPINEL_DATATYPE_UINT8_S, aWhen,
|
||||
aDuration, aChannel);
|
||||
EXPECT_NO_ERROR(error);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError RadioSpinel::Sleep(void)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
@@ -569,6 +569,22 @@ public:
|
||||
*/
|
||||
otError Receive(uint8_t aChannel);
|
||||
|
||||
/**
|
||||
* Schedule a radio reception window at a specific time and duration.
|
||||
*
|
||||
* @param[in] aWhen The receive window start time in the local
|
||||
* radio clock, see `otPlatRadioGetNow`. The radio
|
||||
* receiver SHALL be on and ready to receive the first
|
||||
* symbol of a frame's SHR at the window start time.
|
||||
* @param[in] aDuration The receive window duration, in microseconds, as
|
||||
* measured by the local radio clock.
|
||||
* @param[in] aChannel The channel to use for receiving.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully scheduled the reception.
|
||||
* @retval OT_ERROR_INVALID_STATE The radio was disabled.
|
||||
*/
|
||||
otError ReceiveAt(uint64_t aWhen, uint32_t aDuration, uint8_t aChannel);
|
||||
|
||||
/**
|
||||
* Switches the radio state from Receive to Sleep.
|
||||
*
|
||||
|
||||
@@ -2101,6 +2101,17 @@ enum
|
||||
*/
|
||||
SPINEL_PROP_MAC_15_4_ALT_SADDR = SPINEL_PROP_MAC__BEGIN + 12,
|
||||
|
||||
/// MAC Receive At
|
||||
/** Format: `XLC`
|
||||
*
|
||||
* Schedule a radio reception window at a specific time and duration.
|
||||
*
|
||||
* `X`: The receive window start time.
|
||||
* `L`: The receive window duration.
|
||||
* `C`: The receive channel.
|
||||
*/
|
||||
SPINEL_PROP_MAC_RX_AT = SPINEL_PROP_MAC__BEGIN + 13,
|
||||
|
||||
SPINEL_PROP_MAC__END = 0x40,
|
||||
|
||||
SPINEL_PROP_MAC_EXT__BEGIN = 0x1300,
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
|
||||
#include "common/code_utils.hpp"
|
||||
#include "common/debug.hpp"
|
||||
#include "lib/spinel/spinel.h"
|
||||
#include "radio/radio.hpp"
|
||||
|
||||
namespace ot {
|
||||
@@ -1685,6 +1686,31 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_MAC_RX_AT>(void)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
uint64_t when;
|
||||
uint32_t duration;
|
||||
uint8_t channel;
|
||||
|
||||
SuccessOrExit(error = mDecoder.ReadUint64(when));
|
||||
SuccessOrExit(error = mDecoder.ReadUint32(duration));
|
||||
SuccessOrExit(error = mDecoder.ReadUint8(channel));
|
||||
|
||||
{
|
||||
uint64_t now = otPlatRadioGetNow(mInstance);
|
||||
uint32_t start;
|
||||
|
||||
VerifyOrExit(when > now && (when - now) < UINT32_MAX, error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
start = when - now;
|
||||
error = otPlatRadioReceiveAt(mInstance, channel, start, duration);
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
|
||||
template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_RCP_CSL_ACCURACY>(void)
|
||||
{
|
||||
|
||||
@@ -451,6 +451,7 @@ NcpBase::PropertyHandler NcpBase::FindSetPropertyHandler(spinel_prop_key_t aKey)
|
||||
#if OPENTHREAD_RADIO || OPENTHREAD_CONFIG_LINK_RAW_ENABLE
|
||||
OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_MAC_15_4_ALT_SADDR),
|
||||
#endif
|
||||
OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_MAC_RX_AT),
|
||||
#if OPENTHREAD_MTD || OPENTHREAD_FTD
|
||||
OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_NET_IF_UP),
|
||||
OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_NET_STACK_UP),
|
||||
|
||||
@@ -39,8 +39,6 @@
|
||||
#include <openthread/instance.h>
|
||||
#include <openthread/tasklet.h>
|
||||
#include <openthread/tcat.h>
|
||||
#include <openthread/platform/alarm-micro.h>
|
||||
#include <openthread/platform/alarm-milli.h>
|
||||
#include <openthread/platform/ble.h>
|
||||
#include <openthread/platform/diag.h>
|
||||
#include <openthread/platform/dso_transport.h>
|
||||
@@ -124,11 +122,15 @@ void FakePlatform::StartMilliAlarm(uint32_t aT0, uint32_t aDt)
|
||||
|
||||
void FakePlatform::StopMilliAlarm() { mMilliAlarmStart = kAlarmStop; }
|
||||
|
||||
void FakePlatform::ProcessAlarm(uint64_t &aTimeout)
|
||||
{
|
||||
uint64_t end = mNow + aTimeout;
|
||||
template <> void FakePlatform::HandleSchedule<&FakePlatform::mReceiveAtStart>() { mChannel = mReceiveAtChannel; }
|
||||
|
||||
uint64_t *alarm = &end;
|
||||
template <> void FakePlatform::HandleSchedule<&FakePlatform::mReceiveAtEnd>() { mChannel = 0; }
|
||||
|
||||
void FakePlatform::ProcessSchedules(uint64_t &aTimeout)
|
||||
{
|
||||
uint64_t guard = mNow + aTimeout;
|
||||
|
||||
uint64_t *alarm = &guard;
|
||||
#if OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE
|
||||
if (mMicroAlarmStart < *alarm)
|
||||
{
|
||||
@@ -139,6 +141,14 @@ void FakePlatform::ProcessAlarm(uint64_t &aTimeout)
|
||||
{
|
||||
alarm = &mMilliAlarmStart;
|
||||
}
|
||||
if (mReceiveAtStart < *alarm)
|
||||
{
|
||||
alarm = &mReceiveAtStart;
|
||||
}
|
||||
else if (mReceiveAtEnd < *alarm)
|
||||
{
|
||||
alarm = &mReceiveAtEnd;
|
||||
}
|
||||
|
||||
if (mNow < *alarm)
|
||||
{
|
||||
@@ -146,17 +156,29 @@ void FakePlatform::ProcessAlarm(uint64_t &aTimeout)
|
||||
mNow = *alarm;
|
||||
}
|
||||
*alarm = kAlarmStop;
|
||||
|
||||
if (alarm == &guard)
|
||||
{
|
||||
// nonthing scheduled within this period.
|
||||
}
|
||||
else if (alarm == &mReceiveAtEnd)
|
||||
{
|
||||
FakePlatform::HandleSchedule<&FakePlatform::mReceiveAtEnd>();
|
||||
}
|
||||
else if (alarm == &mReceiveAtStart)
|
||||
{
|
||||
FakePlatform::HandleSchedule<&FakePlatform::mReceiveAtStart>();
|
||||
}
|
||||
else if (alarm == &mMilliAlarmStart)
|
||||
{
|
||||
FakePlatform::HandleSchedule<&FakePlatform::mMilliAlarmStart>();
|
||||
}
|
||||
#if OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE
|
||||
if (alarm == &mMicroAlarmStart)
|
||||
else if (alarm == &mMicroAlarmStart)
|
||||
{
|
||||
otPlatAlarmMicroFired(mInstance);
|
||||
FakePlatform::HandleSchedule<&FakePlatform::mMicroAlarmStart>();
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (alarm == &mMilliAlarmStart)
|
||||
{
|
||||
otPlatAlarmMilliFired(mInstance);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t FakePlatform::Run(uint64_t aTimeoutInUs)
|
||||
@@ -167,7 +189,7 @@ uint64_t FakePlatform::Run(uint64_t aTimeoutInUs)
|
||||
}
|
||||
else
|
||||
{
|
||||
ProcessAlarm(aTimeoutInUs);
|
||||
ProcessSchedules(aTimeoutInUs);
|
||||
}
|
||||
|
||||
return aTimeoutInUs;
|
||||
@@ -356,6 +378,11 @@ otError otPlatRadioSleep(otInstance *) { return OT_ERROR_NONE; }
|
||||
|
||||
otError otPlatRadioReceive(otInstance *, uint8_t aChannel) { return FakePlatform::CurrentPlatform().Receive(aChannel); }
|
||||
|
||||
otError otPlatRadioReceiveAt(otInstance *, uint8_t aChannel, uint32_t aStart, uint32_t aDuration)
|
||||
{
|
||||
return FakePlatform::CurrentPlatform().ReceiveAt(aChannel, aStart, aDuration);
|
||||
}
|
||||
|
||||
otError otPlatRadioTransmit(otInstance *, otRadioFrame *aFrame)
|
||||
{
|
||||
return FakePlatform::CurrentPlatform().Transmit(aFrame);
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
|
||||
#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>
|
||||
|
||||
@@ -77,7 +79,16 @@ public:
|
||||
uint8_t GetReceiveChannel(void) const { return mChannel; }
|
||||
virtual otRadioFrame *GetTransmitBuffer() { return &mTransmitFrame; }
|
||||
virtual otError Transmit(otRadioFrame *aFrame);
|
||||
virtual otError Receive(uint8_t aChannel)
|
||||
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;
|
||||
@@ -98,7 +109,7 @@ public:
|
||||
virtual uint64_t GetEui64() const { return 0; }
|
||||
|
||||
protected:
|
||||
void ProcessAlarm(uint64_t &aTimeout);
|
||||
void ProcessSchedules(uint64_t &aTimeout);
|
||||
|
||||
static constexpr uint64_t kAlarmStop = 0xffffffffffffffffUL;
|
||||
|
||||
@@ -115,15 +126,33 @@ protected:
|
||||
#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 mChannel = 0;
|
||||
uint8_t mReceiveAtChannel = 0;
|
||||
|
||||
uint8_t mFlash[kFlashSwapSize * kFlashSwapNum];
|
||||
|
||||
std::map<uint32_t, std::vector<std::vector<uint8_t>>> mSettings;
|
||||
};
|
||||
|
||||
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_
|
||||
|
||||
@@ -285,3 +285,31 @@ TEST(RadioSpinelTransmit, shouldNotCauseSwitchingToRxAfterTxDoneIfNotRxOnWhenIdl
|
||||
platform.GoInMs(1000);
|
||||
EXPECT_EQ(platform.GetReceiveChannel(), 11);
|
||||
}
|
||||
|
||||
TEST(RadioSpinelReceiveAt, shouldReceiveAtGiveRadioTime)
|
||||
{
|
||||
class MockPlatform : public FakeCoprocessorPlatform
|
||||
{
|
||||
public:
|
||||
MOCK_METHOD(otError, ReceiveAt, (uint8_t aChannel, uint32_t aStart, uint32_t aDuration), (override));
|
||||
};
|
||||
|
||||
MockPlatform platform;
|
||||
|
||||
ON_CALL(platform, ReceiveAt)
|
||||
.WillByDefault([&platform](uint8_t aChannel, uint32_t aStart, uint32_t aDuration) -> otError {
|
||||
return platform.FakePlatform::ReceiveAt(aChannel, aStart, aDuration);
|
||||
});
|
||||
|
||||
EXPECT_CALL(platform, ReceiveAt).Times(1);
|
||||
|
||||
ASSERT_EQ(platform.mRadioSpinel.Enable(FakePlatform::CurrentInstance()), kErrorNone);
|
||||
ASSERT_EQ(platform.mRadioSpinel.SetRxOnWhenIdle(false), kErrorNone);
|
||||
ASSERT_EQ(platform.mRadioSpinel.ReceiveAt(100000, 10000, 11), kErrorNone);
|
||||
platform.GoInUs(100000);
|
||||
EXPECT_EQ(platform.GetReceiveChannel(), 0);
|
||||
platform.GoInUs(1);
|
||||
EXPECT_EQ(platform.GetReceiveChannel(), 11);
|
||||
platform.GoInUs(10000);
|
||||
EXPECT_EQ(platform.GetReceiveChannel(), 0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user