[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:
Abtin Keshavarzian
2023-03-07 13:09:34 -08:00
committed by GitHub
parent 130ef49cc4
commit a94fc44425
9 changed files with 109 additions and 35 deletions
+1 -1
View File
@@ -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
+21
View File
@@ -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.
*
+30 -8
View File
@@ -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.
+13
View File
@@ -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:
+5
View File
@@ -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`
+1
View File
@@ -871,6 +871,7 @@ start:
{
case Message::kSubTypeMleAnnounce:
aFrame.SetChannel(aMessage.GetChannel());
aFrame.SetRxChannelAfterTxDone(Get<Mac::Mac>().GetPanChannel());
panIds.mDestination = Mac::kPanIdBroadcast;
break;
+13 -11
View File
@@ -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
View File
@@ -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,
+10 -8
View File
@@ -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;