mirror of
https://github.com/espressif/openthread.git
synced 2026-08-04 01:47:47 +00:00
[link-raw] fix radio with multiple transmit buffers (#3239)
This commit is contained in:
@@ -244,4 +244,12 @@ void otSimSendEvent(const struct Event *aEvent);
|
||||
*/
|
||||
void otSimSendUartWriteEvent(const uint8_t *aData, uint16_t aLength);
|
||||
|
||||
/**
|
||||
* This function checks if radio transmitting is pending.
|
||||
*
|
||||
* @returns Whether radio transmitting is pending.
|
||||
*
|
||||
*/
|
||||
bool platformRadioIsTransmitPending(void);
|
||||
|
||||
#endif // PLATFORM_POSIX_H_
|
||||
|
||||
@@ -281,7 +281,7 @@ void otSysProcessDrivers(otInstance *aInstance)
|
||||
platformUartUpdateFdSet(&read_fds, &write_fds, &error_fds, &max_fd);
|
||||
#endif
|
||||
|
||||
if (!otTaskletsArePending(aInstance) && platformAlarmGetNext() > 0)
|
||||
if (!otTaskletsArePending(aInstance) && platformAlarmGetNext() > 0 && !platformRadioIsTransmitPending())
|
||||
{
|
||||
platformSendSleepEvent();
|
||||
|
||||
|
||||
@@ -540,9 +540,14 @@ void radioSendMessage(otInstance *aInstance)
|
||||
sAckWait = true;
|
||||
}
|
||||
|
||||
bool platformRadioIsTransmitPending(void)
|
||||
{
|
||||
return sState == OT_RADIO_STATE_TRANSMIT && !sAckWait;
|
||||
}
|
||||
|
||||
void platformRadioProcess(otInstance *aInstance)
|
||||
{
|
||||
if (sState == OT_RADIO_STATE_TRANSMIT && !sAckWait)
|
||||
if (platformRadioIsTransmitPending())
|
||||
{
|
||||
radioSendMessage(aInstance);
|
||||
}
|
||||
|
||||
@@ -177,14 +177,13 @@ typedef void (*otLinkRawTransmitDone)(otInstance * aInstance,
|
||||
* 2. Transmits the PSDU on the given channel and at the given transmit power.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
* @param[in] aFrame A pointer to the frame that was transmitted.
|
||||
* @param[in] aCallback A pointer to a function called on completion of the transmission.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully transitioned to Transmit.
|
||||
* @retval OT_ERROR_INVALID_STATE The radio was not in the Receive state.
|
||||
*
|
||||
*/
|
||||
otError otLinkRawTransmit(otInstance *aInstance, otRadioFrame *aFrame, otLinkRawTransmitDone aCallback);
|
||||
otError otLinkRawTransmit(otInstance *aInstance, otLinkRawTransmitDone aCallback);
|
||||
|
||||
/**
|
||||
* Get the most recent RSSI measurement.
|
||||
|
||||
@@ -105,20 +105,13 @@ otError otLinkRawReceive(otInstance *aInstance, otLinkRawReceiveDone aCallback)
|
||||
|
||||
otRadioFrame *otLinkRawGetTransmitBuffer(otInstance *aInstance)
|
||||
{
|
||||
otRadioFrame *buffer = NULL;
|
||||
|
||||
VerifyOrExit(static_cast<Instance *>(aInstance)->GetLinkRaw().IsEnabled());
|
||||
|
||||
buffer = otPlatRadioGetTransmitBuffer(aInstance);
|
||||
|
||||
exit:
|
||||
return buffer;
|
||||
return static_cast<Instance *>(aInstance)->GetLinkRaw().GetTransmitFrame();
|
||||
}
|
||||
|
||||
otError otLinkRawTransmit(otInstance *aInstance, otRadioFrame *aFrame, otLinkRawTransmitDone aCallback)
|
||||
otError otLinkRawTransmit(otInstance *aInstance, otLinkRawTransmitDone aCallback)
|
||||
{
|
||||
otLogInfoPlat("LinkRaw Transmit (%d bytes on channel %d)", aFrame->mLength, aFrame->mChannel);
|
||||
return static_cast<Instance *>(aInstance)->GetLinkRaw().Transmit(aFrame, aCallback);
|
||||
otLogInfoPlat("LinkRaw Transmit");
|
||||
return static_cast<Instance *>(aInstance)->GetLinkRaw().Transmit(aCallback);
|
||||
}
|
||||
|
||||
int8_t otLinkRawGetRssi(otInstance *aInstance)
|
||||
|
||||
@@ -407,7 +407,7 @@ public:
|
||||
* @returns A reference to the LinkRaw object.
|
||||
*
|
||||
*/
|
||||
LinkRaw &GetLinkRaw(void) { return mLinkRaw; }
|
||||
Mac::LinkRaw &GetLinkRaw(void) { return mLinkRaw; }
|
||||
#endif
|
||||
|
||||
private:
|
||||
@@ -460,7 +460,7 @@ private:
|
||||
MessagePool mMessagePool;
|
||||
#endif // OPENTHREAD_MTD || OPENTHREAD_FTD
|
||||
#if OPENTHREAD_RADIO || OPENTHREAD_ENABLE_RAW_LINK_API
|
||||
LinkRaw mLinkRaw;
|
||||
Mac::LinkRaw mLinkRaw;
|
||||
#endif // OPENTHREAD_RADIO || OPENTHREAD_ENABLE_RAW_LINK_API
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_DYNAMIC_LOG_LEVEL
|
||||
@@ -689,7 +689,7 @@ template <> inline AnnounceSender &Instance::Get(void)
|
||||
#endif // OPENTHREAD_MTD || OPENTHREAD_FTD
|
||||
|
||||
#if OPENTHREAD_RADIO || OPENTHREAD_ENABLE_RAW_LINK_API
|
||||
template <> inline LinkRaw &Instance::Get(void)
|
||||
template <> inline Mac::LinkRaw &Instance::Get(void)
|
||||
{
|
||||
return GetLinkRaw();
|
||||
}
|
||||
|
||||
+163
-143
@@ -49,8 +49,12 @@
|
||||
|
||||
namespace ot {
|
||||
|
||||
namespace Mac {
|
||||
|
||||
LinkRaw::LinkRaw(Instance &aInstance)
|
||||
: mInstance(aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
, mOperationTask(aInstance, &LinkRaw::HandleOperationTask, this)
|
||||
, mPendingTransmitData(false)
|
||||
#if OPENTHREAD_LINKRAW_TIMER_REQUIRED
|
||||
, mTimer(aInstance, &LinkRaw::HandleTimer, this)
|
||||
, mTimerReason(kTimerReasonNone)
|
||||
@@ -60,17 +64,33 @@ LinkRaw::LinkRaw(Instance &aInstance)
|
||||
, mEnergyScanTimer(aInstance, &LinkRaw::HandleTimer, this)
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_TIMER
|
||||
#endif // OPENTHREAD_LINKRAW_TIMER_REQUIRED
|
||||
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_CSMA_BACKOFF
|
||||
, mCsmaBackoffs(0)
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_CSMA_BACKOFF
|
||||
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT
|
||||
, mTransmitRetries(0)
|
||||
, mCsmaBackoffs(0)
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT
|
||||
, mReceiveChannel(OPENTHREAD_CONFIG_DEFAULT_CHANNEL)
|
||||
, mReceiveDoneCallback(NULL)
|
||||
, mTransmitDoneCallback(NULL)
|
||||
, mEnergyScanDoneCallback(NULL)
|
||||
, mTransmitFrame(static_cast<Frame *>(otPlatRadioGetTransmitBuffer(&aInstance)))
|
||||
, mRadioCaps(otPlatRadioGetCaps(&aInstance))
|
||||
{
|
||||
// Query the capabilities to check asserts
|
||||
(void)GetCaps();
|
||||
}
|
||||
|
||||
void LinkRaw::HandleOperationTask(Tasklet &aTasklet)
|
||||
{
|
||||
aTasklet.GetOwner<LinkRaw>().HandleOperationTask();
|
||||
}
|
||||
|
||||
void LinkRaw::HandleOperationTask(void)
|
||||
{
|
||||
if (mPendingTransmitData)
|
||||
{
|
||||
mPendingTransmitData = false;
|
||||
TransmitNow();
|
||||
}
|
||||
}
|
||||
|
||||
otError LinkRaw::SetEnabled(bool aEnabled)
|
||||
@@ -80,16 +100,16 @@ otError LinkRaw::SetEnabled(bool aEnabled)
|
||||
otLogInfoPlat("LinkRaw Enabled=%d", aEnabled ? 1 : 0);
|
||||
|
||||
#if OPENTHREAD_MTD || OPENTHREAD_FTD
|
||||
VerifyOrExit(!static_cast<Instance &>(mInstance).GetThreadNetif().IsUp(), error = OT_ERROR_INVALID_STATE);
|
||||
VerifyOrExit(!GetInstance().GetThreadNetif().IsUp(), error = OT_ERROR_INVALID_STATE);
|
||||
#endif // OPENTHREAD_MTD || OPENTHREAD_FTD
|
||||
|
||||
if (aEnabled)
|
||||
{
|
||||
otPlatRadioEnable(&mInstance);
|
||||
otPlatRadioEnable(&GetInstance());
|
||||
}
|
||||
else
|
||||
{
|
||||
otPlatRadioDisable(&mInstance);
|
||||
otPlatRadioDisable(&GetInstance());
|
||||
}
|
||||
|
||||
mEnabled = aEnabled;
|
||||
@@ -106,7 +126,7 @@ otError LinkRaw::SetPanId(uint16_t aPanId)
|
||||
|
||||
VerifyOrExit(IsEnabled(), error = OT_ERROR_INVALID_STATE);
|
||||
|
||||
otPlatRadioSetPanId(&mInstance, aPanId);
|
||||
otPlatRadioSetPanId(&GetInstance(), aPanId);
|
||||
mPanId = aPanId;
|
||||
|
||||
exit:
|
||||
@@ -137,7 +157,7 @@ otError LinkRaw::SetExtAddress(const otExtAddress &aExtAddress)
|
||||
addr.m8[i] = aExtAddress.m8[7 - i];
|
||||
}
|
||||
|
||||
otPlatRadioSetExtendedAddress(&mInstance, &addr);
|
||||
otPlatRadioSetExtendedAddress(&GetInstance(), &addr);
|
||||
mExtAddress = aExtAddress;
|
||||
|
||||
exit:
|
||||
@@ -150,7 +170,7 @@ otError LinkRaw::SetShortAddress(uint16_t aShortAddress)
|
||||
|
||||
VerifyOrExit(IsEnabled(), error = OT_ERROR_INVALID_STATE);
|
||||
|
||||
otPlatRadioSetShortAddress(&mInstance, aShortAddress);
|
||||
otPlatRadioSetShortAddress(&GetInstance(), aShortAddress);
|
||||
mShortAddress = aShortAddress;
|
||||
|
||||
exit:
|
||||
@@ -159,40 +179,25 @@ exit:
|
||||
|
||||
otRadioCaps LinkRaw::GetCaps(void) const
|
||||
{
|
||||
otRadioCaps RadioCaps = otPlatRadioGetCaps(&mInstance);
|
||||
|
||||
// The radio shouldn't support a capability if it is being compile
|
||||
// time included into the raw link-layer code.
|
||||
otRadioCaps radioCaps = mRadioCaps;
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ACK_TIMEOUT
|
||||
if ((RadioCaps & OT_RADIO_CAPS_ACK_TIMEOUT) == 0)
|
||||
{
|
||||
RadioCaps = static_cast<otRadioCaps>(RadioCaps | OT_RADIO_CAPS_ACK_TIMEOUT);
|
||||
}
|
||||
radioCaps |= OT_RADIO_CAPS_ACK_TIMEOUT;
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ACK_TIMEOUT
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT
|
||||
if ((RadioCaps & OT_RADIO_CAPS_TRANSMIT_RETRIES) == 0)
|
||||
{
|
||||
RadioCaps = static_cast<otRadioCaps>(RadioCaps | OT_RADIO_CAPS_TRANSMIT_RETRIES);
|
||||
}
|
||||
radioCaps |= OT_RADIO_CAPS_TRANSMIT_RETRIES;
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_CSMA_BACKOFF
|
||||
if ((RadioCaps & OT_RADIO_CAPS_CSMA_BACKOFF) == 0)
|
||||
{
|
||||
RadioCaps = static_cast<otRadioCaps>(RadioCaps | OT_RADIO_CAPS_CSMA_BACKOFF);
|
||||
}
|
||||
radioCaps |= OT_RADIO_CAPS_CSMA_BACKOFF;
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_CSMA_BACKOFF
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ENERGY_SCAN
|
||||
if ((RadioCaps & OT_RADIO_CAPS_ENERGY_SCAN) == 0)
|
||||
{
|
||||
RadioCaps = static_cast<otRadioCaps>(RadioCaps | OT_RADIO_CAPS_ENERGY_SCAN);
|
||||
}
|
||||
radioCaps |= OT_RADIO_CAPS_ENERGY_SCAN;
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ENERGY_SCAN
|
||||
|
||||
return RadioCaps;
|
||||
return radioCaps;
|
||||
}
|
||||
|
||||
otError LinkRaw::Receive(otLinkRawReceiveDone aCallback)
|
||||
@@ -202,7 +207,7 @@ otError LinkRaw::Receive(otLinkRawReceiveDone aCallback)
|
||||
if (mEnabled)
|
||||
{
|
||||
mReceiveDoneCallback = aCallback;
|
||||
error = otPlatRadioReceive(&mInstance, mReceiveChannel);
|
||||
error = otPlatRadioReceive(&GetInstance(), mReceiveChannel);
|
||||
}
|
||||
|
||||
return error;
|
||||
@@ -215,7 +220,7 @@ void LinkRaw::InvokeReceiveDone(otRadioFrame *aFrame, otError aError)
|
||||
if (aError == OT_ERROR_NONE)
|
||||
{
|
||||
otLogInfoPlat("LinkRaw Invoke Receive Done (%d bytes)", aFrame->mLength);
|
||||
mReceiveDoneCallback(&mInstance, aFrame, aError);
|
||||
mReceiveDoneCallback(&GetInstance(), aFrame, aError);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -224,117 +229,141 @@ void LinkRaw::InvokeReceiveDone(otRadioFrame *aFrame, otError aError)
|
||||
}
|
||||
}
|
||||
|
||||
otError LinkRaw::Transmit(otRadioFrame *aFrame, otLinkRawTransmitDone aCallback)
|
||||
void LinkRaw::StartTransmit(void)
|
||||
{
|
||||
otError error = OT_ERROR_INVALID_STATE;
|
||||
|
||||
if (mEnabled)
|
||||
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_CSMA_BACKOFF
|
||||
if ((mRadioCaps & OT_RADIO_CAPS_CSMA_BACKOFF) == 0 && mTransmitFrame->IsCsmaCaEnabled())
|
||||
{
|
||||
mTransmitDoneCallback = aCallback;
|
||||
StartCsmaBackoff();
|
||||
}
|
||||
else
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_CSMA_BACKOFF
|
||||
{
|
||||
mPendingTransmitData = true;
|
||||
mOperationTask.Post();
|
||||
}
|
||||
}
|
||||
|
||||
void LinkRaw::TransmitNow(void)
|
||||
{
|
||||
otError error = otPlatRadioTransmit(&GetInstance(), mTransmitFrame);
|
||||
|
||||
if (error != OT_ERROR_NONE)
|
||||
{
|
||||
InvokeTransmitDone(mTransmitFrame, NULL, error);
|
||||
}
|
||||
}
|
||||
|
||||
otError LinkRaw::Transmit(otLinkRawTransmitDone aCallback)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
VerifyOrExit(mEnabled, error = OT_ERROR_INVALID_STATE);
|
||||
|
||||
mTransmitDoneCallback = aCallback;
|
||||
|
||||
mTransmitFrame->SetCsmaCaEnabled(true);
|
||||
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_CSMA_BACKOFF
|
||||
if ((mRadioCaps & OT_RADIO_CAPS_TRANSMIT_RETRIES) == 0)
|
||||
{
|
||||
mCsmaBackoffs = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT
|
||||
if ((mRadioCaps & OT_RADIO_CAPS_TRANSMIT_RETRIES) == 0)
|
||||
{
|
||||
mTransmitRetries = 0;
|
||||
mCsmaBackoffs = 0;
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_CSMA_BACKOFF
|
||||
if (aFrame->mInfo.mTxInfo.mCsmaCaEnabled)
|
||||
{
|
||||
// Start the transmission backoff logic
|
||||
StartCsmaBackoff();
|
||||
error = OT_ERROR_NONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_CSMA_BACKOFF
|
||||
error = otPlatRadioTransmit(&mInstance, aFrame);
|
||||
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_CSMA_BACKOFF
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_CSMA_BACKOFF
|
||||
}
|
||||
StartTransmit();
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void LinkRaw::InvokeTransmitDone(otRadioFrame *aFrame, otRadioFrame *aAckFrame, otError aError)
|
||||
{
|
||||
otLogDebgPlat("LinkRaw Transmit Done (err=0x%x)", aError);
|
||||
assert(aFrame == mTransmitFrame);
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ACK_TIMEOUT
|
||||
mTimer.Stop();
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ACK_TIMEOUT
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT
|
||||
|
||||
if (aError == OT_ERROR_CHANNEL_ACCESS_FAILURE)
|
||||
if (aError == OT_ERROR_NONE)
|
||||
{
|
||||
mCsmaBackoffs++;
|
||||
|
||||
if (mCsmaBackoffs < aFrame->mInfo.mTxInfo.mMaxCsmaBackoffs)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_CSMA_BACKOFF
|
||||
StartCsmaBackoff();
|
||||
#else
|
||||
// Start the transmit now
|
||||
otError error = otPlatRadioTransmit(&mInstance, aFrame);
|
||||
|
||||
if (error != OT_ERROR_NONE)
|
||||
{
|
||||
InvokeTransmitDone(aFrame, NULL, error);
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_CSMA_BACKOFF
|
||||
ExitNow();
|
||||
}
|
||||
otLogDebgPlat("LinkRaw Transmit Done: %s", otThreadErrorToString(aError));
|
||||
}
|
||||
else
|
||||
{
|
||||
mCsmaBackoffs = 0;
|
||||
otLogWarnPlat("LinkRaw Transmit Done: %s", otThreadErrorToString(aError));
|
||||
}
|
||||
|
||||
if (aError != OT_ERROR_NONE)
|
||||
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ACK_TIMEOUT
|
||||
if ((mRadioCaps & OT_RADIO_CAPS_ACK_TIMEOUT) == 0)
|
||||
{
|
||||
if (mTransmitRetries < aFrame->mInfo.mTxInfo.mMaxFrameRetries)
|
||||
{
|
||||
mTransmitRetries++;
|
||||
mTimer.Stop();
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ACK_TIMEOUT
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_CSMA_BACKOFF
|
||||
StartCsmaBackoff();
|
||||
#else
|
||||
// Start the transmit now
|
||||
otError error = otPlatRadioTransmit(&mInstance, aFrame);
|
||||
|
||||
if (error != OT_ERROR_NONE)
|
||||
{
|
||||
InvokeTransmitDone(aFrame, NULL, error);
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_CSMA_BACKOFF
|
||||
ExitNow();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT
|
||||
|
||||
// Transition back to receive state on previous channel
|
||||
otPlatRadioReceive(&mInstance, mReceiveChannel);
|
||||
|
||||
if (mTransmitDoneCallback)
|
||||
if ((mRadioCaps & OT_RADIO_CAPS_CSMA_BACKOFF) == 0)
|
||||
{
|
||||
if (aError == OT_ERROR_NONE)
|
||||
if (aError == OT_ERROR_CHANNEL_ACCESS_FAILURE)
|
||||
{
|
||||
otLogInfoPlat("LinkRaw Invoke Transmit Done");
|
||||
mCsmaBackoffs++;
|
||||
|
||||
if (mCsmaBackoffs < aFrame->mInfo.mTxInfo.mMaxCsmaBackoffs)
|
||||
{
|
||||
ExitNow(StartTransmit());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
otLogWarnPlat("LinkRaw Invoke Transmit Failed (err=0x%x)", aError);
|
||||
mCsmaBackoffs = 0;
|
||||
}
|
||||
|
||||
mTransmitDoneCallback(&mInstance, aFrame, aAckFrame, aError);
|
||||
mTransmitDoneCallback = NULL;
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_CSMA_BACKOFF
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT
|
||||
if ((mRadioCaps & OT_RADIO_CAPS_TRANSMIT_RETRIES) == 0)
|
||||
{
|
||||
if (aError != OT_ERROR_NONE)
|
||||
{
|
||||
if (mTransmitRetries < aFrame->mInfo.mTxInfo.mMaxFrameRetries)
|
||||
{
|
||||
mTransmitRetries++;
|
||||
#if OPENTHREAD_CONFIG_DISABLE_CSMA_CA_ON_LAST_ATTEMPT
|
||||
if ((mTransmitFrame->GetMaxFrameRetries() > 0) &&
|
||||
(mTransmitFrame->GetMaxFrameRetries() <= mTransmitRetries))
|
||||
{
|
||||
mTransmitFrame->SetCsmaCaEnabled(false);
|
||||
}
|
||||
#endif
|
||||
ExitNow(StartTransmit());
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT
|
||||
|
||||
// Transition back to receive state on previous channel
|
||||
otPlatRadioReceive(&GetInstance(), mReceiveChannel);
|
||||
|
||||
VerifyOrExit(mTransmitDoneCallback != NULL);
|
||||
|
||||
switch (aError)
|
||||
{
|
||||
case OT_ERROR_NONE:
|
||||
case OT_ERROR_NO_ACK:
|
||||
case OT_ERROR_CHANNEL_ACCESS_FAILURE:
|
||||
case OT_ERROR_ABORT:
|
||||
break;
|
||||
default:
|
||||
aError = OT_ERROR_ABORT;
|
||||
break;
|
||||
}
|
||||
|
||||
mTransmitDoneCallback(&GetInstance(), aFrame, aAckFrame, aError);
|
||||
|
||||
exit:
|
||||
return;
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT
|
||||
}
|
||||
|
||||
otError LinkRaw::EnergyScan(uint8_t aScanChannel, uint16_t aScanDuration, otLinkRawEnergyScanDone aCallback)
|
||||
@@ -345,16 +374,16 @@ otError LinkRaw::EnergyScan(uint8_t aScanChannel, uint16_t aScanDuration, otLink
|
||||
{
|
||||
mEnergyScanDoneCallback = aCallback;
|
||||
|
||||
if (otPlatRadioGetCaps(&mInstance) & OT_RADIO_CAPS_ENERGY_SCAN)
|
||||
if (otPlatRadioGetCaps(&GetInstance()) & OT_RADIO_CAPS_ENERGY_SCAN)
|
||||
{
|
||||
// Do the HW offloaded energy scan
|
||||
error = otPlatRadioEnergyScan(&mInstance, aScanChannel, aScanDuration);
|
||||
error = otPlatRadioEnergyScan(&GetInstance(), aScanChannel, aScanDuration);
|
||||
}
|
||||
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ENERGY_SCAN
|
||||
else
|
||||
{
|
||||
// Start listening on the scan channel
|
||||
otPlatRadioReceive(&mInstance, aScanChannel);
|
||||
otPlatRadioReceive(&GetInstance(), aScanChannel);
|
||||
|
||||
// Reset the RSSI value and start scanning
|
||||
mEnergyScanRssi = kInvalidRssiValue;
|
||||
@@ -376,7 +405,7 @@ void LinkRaw::InvokeEnergyScanDone(int8_t aEnergyScanMaxRssi)
|
||||
{
|
||||
if (IsEnabled() && mEnergyScanDoneCallback)
|
||||
{
|
||||
mEnergyScanDoneCallback(&mInstance, aEnergyScanMaxRssi);
|
||||
mEnergyScanDoneCallback(&GetInstance(), aEnergyScanMaxRssi);
|
||||
mEnergyScanDoneCallback = NULL;
|
||||
}
|
||||
}
|
||||
@@ -384,17 +413,14 @@ void LinkRaw::InvokeEnergyScanDone(int8_t aEnergyScanMaxRssi)
|
||||
void LinkRaw::TransmitStarted(otRadioFrame *aFrame)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ACK_TIMEOUT
|
||||
|
||||
// If we are implementing the ACK timeout logic, start a timer here (if ACK request)
|
||||
// to fire if we don't get a transmit done callback in time.
|
||||
if (static_cast<Mac::Frame *>(aFrame)->GetAckRequest() &&
|
||||
!(otPlatRadioGetCaps(&mInstance) & OT_RADIO_CAPS_ACK_TIMEOUT))
|
||||
if ((mRadioCaps & OT_RADIO_CAPS_ACK_TIMEOUT) == 0 && static_cast<Frame *>(aFrame)->GetAckRequest())
|
||||
{
|
||||
otLogDebgPlat("LinkRaw Starting AckTimeout Timer");
|
||||
mTimerReason = kTimerReasonAckTimeout;
|
||||
mTimer.Start(Mac::kAckTimeout);
|
||||
mTimer.Start(kAckTimeout);
|
||||
}
|
||||
|
||||
#else
|
||||
OT_UNUSED_VARIABLE(aFrame);
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ACK_TIMEOUT
|
||||
@@ -431,10 +457,10 @@ void LinkRaw::HandleTimer(void)
|
||||
case kTimerReasonAckTimeout:
|
||||
{
|
||||
// Transition back to receive state on previous channel
|
||||
otPlatRadioReceive(&mInstance, mReceiveChannel);
|
||||
otPlatRadioReceive(&GetInstance(), mReceiveChannel);
|
||||
|
||||
// Invoke completion callback for transmit
|
||||
InvokeTransmitDone(otPlatRadioGetTransmitBuffer(&mInstance), NULL, OT_ERROR_NO_ACK);
|
||||
InvokeTransmitDone(mTransmitFrame, NULL, OT_ERROR_NO_ACK);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -444,16 +470,7 @@ void LinkRaw::HandleTimer(void)
|
||||
|
||||
case kTimerReasonCsmaBackoffComplete:
|
||||
{
|
||||
otRadioFrame *aFrame = otPlatRadioGetTransmitBuffer(&mInstance);
|
||||
|
||||
// Start the transmit now
|
||||
otError error = otPlatRadioTransmit(&mInstance, aFrame);
|
||||
|
||||
if (error != OT_ERROR_NONE)
|
||||
{
|
||||
InvokeTransmitDone(aFrame, NULL, error);
|
||||
}
|
||||
|
||||
TransmitNow();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -472,6 +489,7 @@ void LinkRaw::HandleTimer(void)
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -481,16 +499,16 @@ void LinkRaw::HandleTimer(void)
|
||||
|
||||
void LinkRaw::StartCsmaBackoff(void)
|
||||
{
|
||||
uint32_t backoffExponent = Mac::kMinBE + mTransmitRetries + mCsmaBackoffs;
|
||||
uint32_t backoffExponent = kMinBE + mTransmitRetries + mCsmaBackoffs;
|
||||
uint32_t backoff;
|
||||
|
||||
if (backoffExponent > Mac::kMaxBE)
|
||||
if (backoffExponent > kMaxBE)
|
||||
{
|
||||
backoffExponent = Mac::kMaxBE;
|
||||
backoffExponent = kMaxBE;
|
||||
}
|
||||
|
||||
backoff = Random::GetUint32InRange(0, 1U << backoffExponent);
|
||||
backoff *= (static_cast<uint32_t>(Mac::kUnitBackoffPeriod) * OT_RADIO_SYMBOL_TIME);
|
||||
backoff *= (static_cast<uint32_t>(kUnitBackoffPeriod) * OT_RADIO_SYMBOL_TIME);
|
||||
|
||||
otLogDebgPlat("LinkRaw Starting RetransmitTimeout Timer (%d ms)", backoff);
|
||||
mTimerReason = kTimerReasonCsmaBackoffComplete;
|
||||
@@ -511,7 +529,7 @@ void LinkRaw::HandleEnergyScanTimer(void)
|
||||
// Only process if we are still energy scanning
|
||||
if (mTimer.IsRunning() && mTimerReason == kTimerReasonEnergyScanComplete)
|
||||
{
|
||||
int8_t rssi = otPlatRadioGetRssi(&mInstance);
|
||||
int8_t rssi = otPlatRadioGetRssi(&GetInstance());
|
||||
|
||||
// Only apply the RSSI if it was a valid value
|
||||
if (rssi != kInvalidRssiValue)
|
||||
@@ -532,27 +550,31 @@ void LinkRaw::HandleEnergyScanTimer(void)
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ENERGY_SCAN
|
||||
|
||||
} // namespace Mac
|
||||
|
||||
} // namespace ot
|
||||
|
||||
#if OPENTHREAD_RADIO
|
||||
extern "C" void otPlatRadioReceiveDone(otInstance *aInstance, otRadioFrame *aFrame, otError aError)
|
||||
{
|
||||
static_cast<Instance *>(aInstance)->GetLinkRaw().InvokeReceiveDone(aFrame, aError);
|
||||
static_cast<ot::Instance *>(aInstance)->GetLinkRaw().InvokeReceiveDone(aFrame, aError);
|
||||
}
|
||||
|
||||
extern "C" void otPlatRadioTxDone(otInstance *aInstance, otRadioFrame *aFrame, otRadioFrame *aAckFrame, otError aError)
|
||||
{
|
||||
static_cast<Instance *>(aInstance)->GetLinkRaw().InvokeTransmitDone(aFrame, aAckFrame, aError);
|
||||
static_cast<ot::Instance *>(aInstance)->GetLinkRaw().InvokeTransmitDone(aFrame, aAckFrame, aError);
|
||||
}
|
||||
|
||||
extern "C" void otPlatRadioTxStarted(otInstance *aInstance, otRadioFrame *aFrame)
|
||||
{
|
||||
static_cast<Instance *>(aInstance)->GetLinkRaw().TransmitStarted(aFrame);
|
||||
static_cast<ot::Instance *>(aInstance)->GetLinkRaw().TransmitStarted(aFrame);
|
||||
}
|
||||
|
||||
extern "C" void otPlatRadioEnergyScanDone(otInstance *aInstance, int8_t aEnergyScanMaxRssi)
|
||||
{
|
||||
VerifyOrExit(otInstanceIsInitialized(aInstance));
|
||||
|
||||
static_cast<Instance *>(aInstance)->GetLinkRaw().InvokeEnergyScanDone(aEnergyScanMaxRssi);
|
||||
static_cast<ot::Instance *>(aInstance)->GetLinkRaw().InvokeEnergyScanDone(aEnergyScanMaxRssi);
|
||||
|
||||
exit:
|
||||
return;
|
||||
@@ -569,6 +591,4 @@ extern "C" void otPlatRadioFrameUpdated(otInstance *aInstance, otRadioFrame *aFr
|
||||
|
||||
#endif // OPENTHREAD_RADIO
|
||||
|
||||
} // namespace ot
|
||||
|
||||
#endif // OPENTHREAD_RADIO || OPENTHREAD_ENABLE_RAW_LINK_API
|
||||
|
||||
+33
-13
@@ -38,7 +38,9 @@
|
||||
|
||||
#include <openthread/link_raw.h>
|
||||
|
||||
#include "common/locator.hpp"
|
||||
#include "common/timer.hpp"
|
||||
#include "mac/mac_frame.hpp"
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ACK_TIMEOUT || OPENTHREAD_CONFIG_ENABLE_SOFTWARE_CSMA_BACKOFF || \
|
||||
OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ENERGY_SCAN
|
||||
@@ -49,7 +51,9 @@
|
||||
|
||||
namespace ot {
|
||||
|
||||
class LinkRaw
|
||||
namespace Mac {
|
||||
|
||||
class LinkRaw : public InstanceLocator
|
||||
{
|
||||
public:
|
||||
/**
|
||||
@@ -112,14 +116,15 @@ public:
|
||||
/**
|
||||
* This method starts a (single) Transmit on the link-layer.
|
||||
*
|
||||
* @param[in] aFrame A pointer to the frame that was transmitted.
|
||||
* @note The callback @p aCallback will not be called if this call does not return OT_ERROR_NONE.
|
||||
*
|
||||
* @param[in] aCallback A pointer to a function called on completion of the transmission.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully transitioned to Transmit.
|
||||
* @retval OT_ERROR_INVALID_STATE The radio was not in the Receive state.
|
||||
*
|
||||
*/
|
||||
otError Transmit(otRadioFrame *aFrame, otLinkRawTransmitDone aCallback);
|
||||
otError Transmit(otLinkRawTransmitDone aCallback);
|
||||
|
||||
/**
|
||||
* This method invokes the mTransmitDoneCallback, if set.
|
||||
@@ -237,10 +242,22 @@ public:
|
||||
*/
|
||||
otError SetExtAddress(const otExtAddress &aExtAddress);
|
||||
|
||||
private:
|
||||
otInstance &mInstance;
|
||||
/**
|
||||
* This method gets the transmit frame.
|
||||
*
|
||||
* @returns A pointer to the transmit frame.
|
||||
*
|
||||
*/
|
||||
otRadioFrame *GetTransmitFrame(void) { return mTransmitFrame; }
|
||||
|
||||
#if OPENTHREAD_LINKRAW_TIMER_REQUIRED
|
||||
private:
|
||||
void TransmitNow(void);
|
||||
void StartTransmit(void);
|
||||
static void HandleOperationTask(Tasklet &aTasklet);
|
||||
void HandleOperationTask(void);
|
||||
|
||||
Tasklet mOperationTask;
|
||||
bool mPendingTransmitData : 1;
|
||||
|
||||
enum TimerReason
|
||||
{
|
||||
@@ -250,6 +267,7 @@ private:
|
||||
kTimerReasonEnergyScanComplete,
|
||||
};
|
||||
|
||||
#if OPENTHREAD_LINKRAW_TIMER_REQUIRED
|
||||
TimerMilli mTimer;
|
||||
TimerReason mTimerReason;
|
||||
#if OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_TIMER
|
||||
@@ -263,19 +281,18 @@ private:
|
||||
|
||||
#endif // OPENTHREAD_LINKRAW_TIMER_REQUIRED
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_CSMA_BACKOFF
|
||||
void StartCsmaBackoff(void);
|
||||
|
||||
uint8_t mCsmaBackoffs;
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_CSMA_BACKOFF
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT
|
||||
|
||||
uint8_t mTransmitRetries;
|
||||
uint8_t mCsmaBackoffs;
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_CSMA_BACKOFF
|
||||
|
||||
void StartCsmaBackoff(void);
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_CSMA_BACKOFF
|
||||
|
||||
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ENERGY_SCAN
|
||||
|
||||
enum
|
||||
@@ -310,8 +327,11 @@ private:
|
||||
otLinkRawReceiveDone mReceiveDoneCallback;
|
||||
otLinkRawTransmitDone mTransmitDoneCallback;
|
||||
otLinkRawEnergyScanDone mEnergyScanDoneCallback;
|
||||
Frame * mTransmitFrame;
|
||||
otRadioCaps mRadioCaps;
|
||||
};
|
||||
|
||||
} // namespace Mac
|
||||
} // namespace ot
|
||||
|
||||
#endif // LINK_RAW_HPP_
|
||||
|
||||
@@ -1071,6 +1071,14 @@ public:
|
||||
*/
|
||||
void SetCsmaCaEnabled(bool aCsmaCaEnabled) { mInfo.mTxInfo.mCsmaCaEnabled = aCsmaCaEnabled; }
|
||||
|
||||
/**
|
||||
* This method gets the CSMA-CA enabled attribute.
|
||||
*
|
||||
* @returns TRUE if CSMA-CA must be enabled for this packet, FALSE otherwise.
|
||||
*
|
||||
*/
|
||||
bool IsCsmaCaEnabled(void) const { return mInfo.mTxInfo.mCsmaCaEnabled; }
|
||||
|
||||
/**
|
||||
* This method returns the key used for frame encryption and authentication (AES CCM).
|
||||
*
|
||||
|
||||
@@ -369,7 +369,7 @@ otError NcpBase::HandlePropertySet_SPINEL_PROP_STREAM_RAW(uint8_t aHeader)
|
||||
|
||||
// Pass frame to the radio layer. Note, this fails if we
|
||||
// haven't enabled raw stream or are already transmitting.
|
||||
error = otLinkRawTransmit(mInstance, frame, &NcpBase::LinkRawTransmitDone);
|
||||
error = otLinkRawTransmit(mInstance, &NcpBase::LinkRawTransmitDone);
|
||||
|
||||
exit:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user