mirror of
https://github.com/espressif/openthread.git
synced 2026-08-16 23:57:46 +00:00
[radio] mechanism to switch to PAN channel more quickly on CSL tx (#8701)
This commit adds `mRxChannelAfterTxDone` in `otRadioFrame` which specifies the RX channel after frame TX is done (after all retries and ack received). This is intended for situations where they may be delay in interactions between OT stack and radio, as example this is used in RCP and host architecture to make sure RCP switches to PAN channel more quickly. In particular, this can help with CSL tx to a sleepy child, where the child may use a different channel for CSL than the PAN channel. After frame tx, we want the radio/RCP to go back to PAN channel quickly to ensure that parent does not miss any tx from child afterwards, e.g., child responding to the earlier CSL transmitted frame from parent using PAN channel while radio still staying on CSL channel. This commit adds support for the `mRxChannelAfterTxDone` parameter in spinel and posix host `RadioSpinel`. This is added in a backward compatible way, i.e., if RCP is using a newer version but host is older and does not provide the new parameter, RCP will use `frame.mChannel` as default value for this, and if host is using a newer version, older RCP will ignore it.
This commit is contained in:
@@ -53,7 +53,7 @@ extern "C" {
|
||||
* @note This number versions both OpenThread platform and user APIs.
|
||||
*
|
||||
*/
|
||||
#define OPENTHREAD_API_VERSION (295)
|
||||
#define OPENTHREAD_API_VERSION (296)
|
||||
|
||||
/**
|
||||
* @addtogroup api-instance
|
||||
|
||||
@@ -277,6 +277,27 @@ typedef struct otRadioFrame
|
||||
uint8_t mMaxCsmaBackoffs; ///< Maximum number of backoffs attempts before declaring CCA failure.
|
||||
uint8_t mMaxFrameRetries; ///< Maximum number of retries allowed after a transmission failure.
|
||||
|
||||
/**
|
||||
* The RX channel after frame TX is done (after all frame retries - ack received, or timeout, or abort).
|
||||
*
|
||||
* Radio platforms can choose to fully ignore this. OT stack will make sure to call `otPlatRadioReceive()`
|
||||
* with the desired RX channel after a frame TX is done and signaled in `otPlatRadioTxDone()` callback.
|
||||
* Radio platforms that don't provide `OT_RADIO_CAPS_TRANSMIT_RETRIES` must always ignore this.
|
||||
*
|
||||
* This is intended for situations where there may be delay in interactions between OT stack and radio, as
|
||||
* an example this is used in RCP/host architecture to make sure RCP switches to PAN channel more quickly.
|
||||
* In particular, this can help with CSL tx to a sleepy child, where the child may use a different channel
|
||||
* for CSL than the PAN channel. After frame tx, we want the radio/RCP to go back to the PAN channel
|
||||
* quickly to ensure that parent does not miss tx from child afterwards, e.g., child responding to the
|
||||
* earlier CSL transmitted frame from parent using PAN channel while radio still staying on CSL channel.
|
||||
*
|
||||
* The switch to the RX channel MUST happen after the frame TX is fully done, i.e., after all retries and
|
||||
* when ack is received (when "Ack Request" flag is set on the TX frame) or ack timeout. Note that ack is
|
||||
* expected on the same channel that frame is sent on.
|
||||
*
|
||||
*/
|
||||
uint8_t mRxChannelAfterTxDone;
|
||||
|
||||
/**
|
||||
* Indicates whether frame counter and CSL IEs are properly updated in the header.
|
||||
*
|
||||
|
||||
@@ -836,14 +836,6 @@ public:
|
||||
*/
|
||||
uint8_t GetChannel(void) const { return mChannel; }
|
||||
|
||||
/**
|
||||
* This method sets the IEEE 802.15.4 channel used for transmission or reception.
|
||||
*
|
||||
* @param[in] aChannel The IEEE 802.15.4 channel used for transmission or reception.
|
||||
*
|
||||
*/
|
||||
void SetChannel(uint8_t aChannel) { mChannel = aChannel; }
|
||||
|
||||
/**
|
||||
* This method returns the IEEE 802.15.4 PSDU length.
|
||||
*
|
||||
@@ -1262,6 +1254,36 @@ public:
|
||||
class TxFrame : public Frame
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* This method sets the channel on which to send the frame.
|
||||
*
|
||||
* It also sets the `RxChannelAfterTxDone` to the same channel.
|
||||
*
|
||||
* @param[in] aChannel The channel used for transmission.
|
||||
*
|
||||
*/
|
||||
void SetChannel(uint8_t aChannel)
|
||||
{
|
||||
mChannel = aChannel;
|
||||
SetRxChannelAfterTxDone(aChannel);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method gets the RX channel after frame TX is done.
|
||||
*
|
||||
* @returns The RX channel after frame TX is done.
|
||||
*
|
||||
*/
|
||||
uint8_t GetRxChannelAfterTxDone(void) const { return mInfo.mTxInfo.mRxChannelAfterTxDone; }
|
||||
|
||||
/**
|
||||
* This method sets the RX channel after frame TX is done.
|
||||
*
|
||||
* @param[in] aChannel The RX channel after frame TX is done.
|
||||
*
|
||||
*/
|
||||
void SetRxChannelAfterTxDone(uint8_t aChannel) { mInfo.mTxInfo.mRxChannelAfterTxDone = aChannel; }
|
||||
|
||||
/**
|
||||
* This method returns the maximum number of backoffs the CSMA-CA algorithm will attempt before declaring a channel
|
||||
* access failure.
|
||||
|
||||
@@ -619,6 +619,19 @@ void SubMac::HandleTransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, Error aErro
|
||||
|
||||
SetState(kStateReceive);
|
||||
|
||||
#if OPENTHREAD_RADIO
|
||||
if (aFrame.GetChannel() != aFrame.GetRxChannelAfterTxDone())
|
||||
{
|
||||
// On RCP build, we switch immediately to the specified RX
|
||||
// channel if it is different from the channel on which frame
|
||||
// was sent. On FTD or MTD builds we don't need to do
|
||||
// the same as the `Mac` will switch the channel from the
|
||||
// `mCallbacks.TransmitDone()`.
|
||||
|
||||
IgnoreError(Get<Radio>().Receive(aFrame.GetRxChannelAfterTxDone()));
|
||||
}
|
||||
#endif
|
||||
|
||||
mCallbacks.TransmitDone(aFrame, aAckFrame, aError);
|
||||
|
||||
exit:
|
||||
|
||||
@@ -214,6 +214,11 @@ Mac::TxFrame *CslTxScheduler::HandleFrameRequest(Mac::TxFrames &aTxFrames)
|
||||
frame->SetChannel(mCslTxChild->GetCslChannel() == 0 ? Get<Mac::Mac>().GetPanChannel()
|
||||
: mCslTxChild->GetCslChannel());
|
||||
|
||||
if (frame->GetChannel() != Get<Mac::Mac>().GetPanChannel())
|
||||
{
|
||||
frame->SetRxChannelAfterTxDone(Get<Mac::Mac>().GetPanChannel());
|
||||
}
|
||||
|
||||
delay = GetNextCslTransmissionDelay(*mCslTxChild, txDelay, /* aAheadUs */ 0);
|
||||
|
||||
// We make sure that delay is less than `mCslFrameRequestAheadUs`
|
||||
|
||||
@@ -871,6 +871,7 @@ start:
|
||||
{
|
||||
case Message::kSubTypeMleAnnounce:
|
||||
aFrame.SetChannel(aMessage.GetChannel());
|
||||
aFrame.SetRxChannelAfterTxDone(Get<Mac::Mac>().GetPanChannel());
|
||||
panIds.mDestination = Mac::kPanIdBroadcast;
|
||||
break;
|
||||
|
||||
|
||||
@@ -1980,21 +1980,23 @@ otError RadioSpinel<InterfaceType, ProcessContextType>::Transmit(otRadioFrame &a
|
||||
otPlatRadioTxStarted(mInstance, mTransmitFrame);
|
||||
|
||||
error = Request(SPINEL_CMD_PROP_VALUE_SET, SPINEL_PROP_STREAM_RAW,
|
||||
SPINEL_DATATYPE_DATA_WLEN_S // Frame data
|
||||
SPINEL_DATATYPE_UINT8_S // Channel
|
||||
SPINEL_DATATYPE_UINT8_S // MaxCsmaBackoffs
|
||||
SPINEL_DATATYPE_UINT8_S // MaxFrameRetries
|
||||
SPINEL_DATATYPE_BOOL_S // CsmaCaEnabled
|
||||
SPINEL_DATATYPE_BOOL_S // IsHeaderUpdated
|
||||
SPINEL_DATATYPE_BOOL_S // IsARetx
|
||||
SPINEL_DATATYPE_BOOL_S // SkipAes
|
||||
SPINEL_DATATYPE_UINT32_S // TxDelay
|
||||
SPINEL_DATATYPE_UINT32_S, // TxDelayBaseTime
|
||||
SPINEL_DATATYPE_DATA_WLEN_S // Frame data
|
||||
SPINEL_DATATYPE_UINT8_S // Channel
|
||||
SPINEL_DATATYPE_UINT8_S // MaxCsmaBackoffs
|
||||
SPINEL_DATATYPE_UINT8_S // MaxFrameRetries
|
||||
SPINEL_DATATYPE_BOOL_S // CsmaCaEnabled
|
||||
SPINEL_DATATYPE_BOOL_S // IsHeaderUpdated
|
||||
SPINEL_DATATYPE_BOOL_S // IsARetx
|
||||
SPINEL_DATATYPE_BOOL_S // IsSecurityProcessed
|
||||
SPINEL_DATATYPE_UINT32_S // TxDelay
|
||||
SPINEL_DATATYPE_UINT32_S // TxDelayBaseTime
|
||||
SPINEL_DATATYPE_UINT8_S, // RxChannelAfterTxDone
|
||||
mTransmitFrame->mPsdu, mTransmitFrame->mLength, mTransmitFrame->mChannel,
|
||||
mTransmitFrame->mInfo.mTxInfo.mMaxCsmaBackoffs, mTransmitFrame->mInfo.mTxInfo.mMaxFrameRetries,
|
||||
mTransmitFrame->mInfo.mTxInfo.mCsmaCaEnabled, mTransmitFrame->mInfo.mTxInfo.mIsHeaderUpdated,
|
||||
mTransmitFrame->mInfo.mTxInfo.mIsARetx, mTransmitFrame->mInfo.mTxInfo.mIsSecurityProcessed,
|
||||
mTransmitFrame->mInfo.mTxInfo.mTxDelay, mTransmitFrame->mInfo.mTxInfo.mTxDelayBaseTime);
|
||||
mTransmitFrame->mInfo.mTxInfo.mTxDelay, mTransmitFrame->mInfo.mTxInfo.mTxDelayBaseTime,
|
||||
mTransmitFrame->mInfo.mTxInfo.mRxChannelAfterTxDone);
|
||||
|
||||
if (error == OT_ERROR_NONE)
|
||||
{
|
||||
|
||||
+15
-7
@@ -420,7 +420,7 @@
|
||||
* Please see section "Spinel definition compatibility guideline" for more details.
|
||||
*
|
||||
*/
|
||||
#define SPINEL_RCP_API_VERSION 8
|
||||
#define SPINEL_RCP_API_VERSION 9
|
||||
|
||||
/**
|
||||
* @def SPINEL_MIN_HOST_SUPPORTED_RCP_API_VERSION
|
||||
@@ -3511,19 +3511,27 @@ enum
|
||||
* over the radio. This allows the caller to use the radio directly.
|
||||
*
|
||||
* The frame meta data for the `CMD_PROP_VALUE_SET` contains the following
|
||||
* optional fields. Default values are used for all unspecified fields.
|
||||
* fields. Default values are used for all unspecified fields.
|
||||
*
|
||||
* `C` : Channel (for frame tx)
|
||||
* `C` : Channel (for frame tx) - MUST be included.
|
||||
* `C` : Maximum number of backoffs attempts before declaring CCA failure
|
||||
* (use Thread stack default if not specified)
|
||||
* `C` : Maximum number of retries allowed after a transmission failure
|
||||
* (use Thread stack default if not specified)
|
||||
* `b` : Set to true to enable CSMA-CA for this packet, false otherwise.
|
||||
* (default true).
|
||||
* `b` : Set to true to indicate it is a retransmission packet, false otherwise.
|
||||
* (default false).
|
||||
* `b` : Set to true to indicate that SubMac should skip AES processing, false otherwise.
|
||||
* (default false).
|
||||
* `b` : Set to true to indicate if header is updated - related to
|
||||
* `mIsHeaderUpdated` in `otRadioFrame` (default false).
|
||||
* `b` : Set to true to indicate it is a retransmission - related to
|
||||
* `mIsARetx` in `otRadioFrame` (default false).
|
||||
* `b` : Set to true to indicate security was processed on tx frame
|
||||
* `mIsSecurityProcessed` in `otRadioFrame` (default false).
|
||||
* `L` : TX delay interval used for CSL - related to `mTxDelay` in
|
||||
* `otRadioFrame` (default zero).
|
||||
* `L` : TX delay based time used for CSL - related to `mTxDelayBaseTime`
|
||||
* in `otRadioFrame` (default zero).
|
||||
* `C` : RX channel after TX done (default assumed to be same as
|
||||
* channel in metadata)
|
||||
*
|
||||
*/
|
||||
SPINEL_PROP_STREAM_RAW = SPINEL_PROP_STREAM__BEGIN + 1,
|
||||
|
||||
@@ -408,14 +408,15 @@ otError NcpBase::DecodeStreamRawTxRequest(otRadioFrame &aFrame)
|
||||
SuccessOrExit(error = mDecoder.ReadUint8(aFrame.mChannel));
|
||||
|
||||
// Set the default value for all optional parameters.
|
||||
aFrame.mInfo.mTxInfo.mMaxCsmaBackoffs = OPENTHREAD_CONFIG_MAC_MAX_CSMA_BACKOFFS_DIRECT;
|
||||
aFrame.mInfo.mTxInfo.mMaxFrameRetries = OPENTHREAD_CONFIG_MAC_DEFAULT_MAX_FRAME_RETRIES_DIRECT;
|
||||
aFrame.mInfo.mTxInfo.mCsmaCaEnabled = true;
|
||||
aFrame.mInfo.mTxInfo.mIsHeaderUpdated = false;
|
||||
aFrame.mInfo.mTxInfo.mIsARetx = false;
|
||||
aFrame.mInfo.mTxInfo.mIsSecurityProcessed = false;
|
||||
aFrame.mInfo.mTxInfo.mTxDelay = 0;
|
||||
aFrame.mInfo.mTxInfo.mTxDelayBaseTime = 0;
|
||||
aFrame.mInfo.mTxInfo.mRxChannelAfterTxDone = aFrame.mChannel;
|
||||
aFrame.mInfo.mTxInfo.mMaxCsmaBackoffs = OPENTHREAD_CONFIG_MAC_MAX_CSMA_BACKOFFS_DIRECT;
|
||||
aFrame.mInfo.mTxInfo.mMaxFrameRetries = OPENTHREAD_CONFIG_MAC_DEFAULT_MAX_FRAME_RETRIES_DIRECT;
|
||||
aFrame.mInfo.mTxInfo.mCsmaCaEnabled = true;
|
||||
aFrame.mInfo.mTxInfo.mIsHeaderUpdated = false;
|
||||
aFrame.mInfo.mTxInfo.mIsARetx = false;
|
||||
aFrame.mInfo.mTxInfo.mIsSecurityProcessed = false;
|
||||
aFrame.mInfo.mTxInfo.mTxDelay = 0;
|
||||
aFrame.mInfo.mTxInfo.mTxDelayBaseTime = 0;
|
||||
|
||||
// All the next parameters are optional. Note that even if the
|
||||
// decoder fails to parse any of optional parameters we still want to
|
||||
@@ -430,6 +431,7 @@ otError NcpBase::DecodeStreamRawTxRequest(otRadioFrame &aFrame)
|
||||
SuccessOrExit(mDecoder.ReadBool(isSecurityProcessed));
|
||||
SuccessOrExit(mDecoder.ReadUint32(aFrame.mInfo.mTxInfo.mTxDelay));
|
||||
SuccessOrExit(mDecoder.ReadUint32(aFrame.mInfo.mTxInfo.mTxDelayBaseTime));
|
||||
SuccessOrExit(mDecoder.ReadUint8(aFrame.mInfo.mTxInfo.mRxChannelAfterTxDone));
|
||||
aFrame.mInfo.mTxInfo.mCsmaCaEnabled = csmaEnable;
|
||||
aFrame.mInfo.mTxInfo.mIsHeaderUpdated = isHeaderUpdated;
|
||||
aFrame.mInfo.mTxInfo.mIsARetx = isARetx;
|
||||
|
||||
Reference in New Issue
Block a user