[mac] adding sub-MAC layer (#3262)

This commit introduces sub-MAC layer (class `Mac::SubMac`) in
OpenThread implementing a subset of IEEE802.15.4 MAC primitives which
are shared by both MAC layer (in FTD/MTD modes) and Raw Link (Radio
only mode).

The sub-MAC layer handles the following (if not provided by radio
platform):

  - Ack timeout for frame transmission,
  - CSMA backoff logic,
  - Frame re-transmissions,
  - Energy scan on a single channel and RSSI sampling.

It also act as the interface (to radio platform) for setting/getting
radio configurations such as short or extended addresses and PAN Id.

In addition, this commit contains following improvements in `Mac`:
- The implementation of `STAY_AWAKE_BETWEEN_FRAGMENTS` (delay sleep)
  feature is simplified by adding a new state variable tracking if
  sleep is being delayed and canceling sleep delay on start of any
  operation.
- Member variables in `Mac` class are re-ordered to avoid alignment
  gaps.
- `Mac` timers are combined into one which is used for Active Scan,
  Data Poll timeout, and delaying sleep.
This commit is contained in:
Abtin Keshavarzian
2018-11-28 10:09:35 -08:00
committed by Jonathan Hui
parent 5d6dccf35c
commit 8d12513591
18 changed files with 1892 additions and 1352 deletions
+2
View File
@@ -110,6 +110,8 @@ LOCAL_SRC_FILES := \
src/core/mac/mac.cpp \
src/core/mac/mac_filter.cpp \
src/core/mac/mac_frame.cpp \
src/core/mac/sub_mac.cpp \
src/core/mac/sub_mac_callbacks.cpp \
src/core/meshcop/announce_begin_client.cpp \
src/core/meshcop/border_agent.cpp \
src/core/meshcop/commissioner.cpp \
+3
View File
@@ -100,6 +100,8 @@
<ClCompile Include="..\..\src\core\mac\mac.cpp" />
<ClCompile Include="..\..\src\core\mac\mac_filter.cpp" />
<ClCompile Include="..\..\src\core\mac\mac_frame.cpp" />
<ClCompile Include="..\..\src\core\mac\sub_mac.cpp" />
<ClCompile Include="..\..\src\core\mac\sub_mac_callbacks.cpp" />
<ClCompile Include="..\..\src\core\meshcop\announce_begin_client.cpp" />
<ClCompile Include="..\..\src\core\meshcop\commissioner.cpp" />
<ClCompile Include="..\..\src\core\meshcop\dataset.cpp" />
@@ -189,6 +191,7 @@
<ClInclude Include="..\..\src\core\mac\mac.hpp" />
<ClInclude Include="..\..\src\core\mac\mac_filter.hpp" />
<ClInclude Include="..\..\src\core\mac\mac_frame.hpp" />
<ClInclude Include="..\..\src\core\mac\sub_mac.hpp" />
<ClInclude Include="..\..\src\core\meshcop\announce_begin_client.hpp" />
<ClInclude Include="..\..\src\core\meshcop\commissioner.hpp" />
<ClInclude Include="..\..\src\core\meshcop\dataset.hpp" />
@@ -183,6 +183,12 @@
<ClCompile Include="..\..\src\core\mac\mac_frame.cpp">
<Filter>Source Files\mac</Filter>
</ClCompile>
<ClCompile Include="..\..\src\core\mac\sub_mac.cpp">
<Filter>Source Files\mac</Filter>
</ClCompile>
<ClCompile Include="..\..\src\core\mac\sub_mac_callbacks.cpp">
<Filter>Source Files\mac</Filter>
</ClCompile>
<ClCompile Include="..\..\src\core\net\dhcp6_client.cpp">
<Filter>Source Files\net</Filter>
</ClCompile>
@@ -440,6 +446,9 @@
<ClInclude Include="..\..\src\core\mac\mac_frame.hpp">
<Filter>Header Files\mac</Filter>
</ClInclude>
<ClInclude Include="..\..\src\core\mac\sub_mac.hpp">
<Filter>Header Files\mac</Filter>
</ClInclude>
<ClInclude Include="..\..\src\core\net\dhcp6.hpp">
<Filter>Header Files\net</Filter>
</ClInclude>
@@ -107,6 +107,8 @@
<ClCompile Include="..\..\src\core\mac\mac.cpp" />
<ClCompile Include="..\..\src\core\mac\mac_filter.cpp" />
<ClCompile Include="..\..\src\core\mac\mac_frame.cpp" />
<ClCompile Include="..\..\src\core\mac\sub_mac.cpp" />
<ClCompile Include="..\..\src\core\mac\sub_mac_callbacks.cpp" />
<ClCompile Include="..\..\src\core\meshcop\commissioner.cpp" />
<ClCompile Include="..\..\src\core\meshcop\dataset.cpp" />
<ClCompile Include="..\..\src\core\meshcop\dataset_local.cpp" />
@@ -219,6 +221,7 @@
<ClInclude Include="..\..\src\core\mac\mac.hpp" />
<ClInclude Include="..\..\src\core\mac\mac_filter.hpp" />
<ClInclude Include="..\..\src\core\mac\mac_frame.hpp" />
<ClInclude Include="..\..\src\core\mac\sub_mac.hpp" />
<ClInclude Include="..\..\src\core\meshcop\announce_begin_client.hpp" />
<ClInclude Include="..\..\src\core\meshcop\commissioner.hpp" />
<ClInclude Include="..\..\src\core\meshcop\dataset.hpp" />
@@ -177,6 +177,12 @@
<ClCompile Include="..\..\src\core\mac\mac_frame.cpp">
<Filter>Source Files\mac</Filter>
</ClCompile>
<ClCompile Include="..\..\src\core\mac\sub_mac.cpp">
<Filter>Source Files\mac</Filter>
</ClCompile>
<ClCompile Include="..\..\src\core\mac\sub_mac_callbacks.cpp">
<Filter>Source Files\mac</Filter>
</ClCompile>
<ClCompile Include="..\..\src\core\net\dhcp6_client.cpp">
<Filter>Source Files\net</Filter>
</ClCompile>
@@ -434,6 +440,9 @@
<ClInclude Include="..\..\src\core\mac\mac_frame.hpp">
<Filter>Header Files\mac</Filter>
</ClInclude>
<ClInclude Include="..\..\src\core\mac\sub_mac.hpp">
<Filter>Header Files\mac</Filter>
</ClInclude>
<ClInclude Include="..\..\src\core\net\dhcp6.hpp">
<Filter>Header Files\net</Filter>
</ClInclude>
+5
View File
@@ -158,6 +158,8 @@ SOURCES_COMMON = \
mac/mac.cpp \
mac/mac_filter.cpp \
mac/mac_frame.cpp \
mac/sub_mac.cpp \
mac/sub_mac_callbacks.cpp \
meshcop/announce_begin_client.cpp \
meshcop/border_agent.cpp \
meshcop/commissioner.cpp \
@@ -243,6 +245,8 @@ libopenthread_radio_a_SOURCES = \
common/timer.cpp \
mac/link_raw.cpp \
mac/mac_frame.cpp \
mac/sub_mac.cpp \
mac/sub_mac_callbacks.cpp \
thread/link_quality.cpp \
utils/missing_strlcat.c \
utils/missing_strlcpy.c \
@@ -318,6 +322,7 @@ HEADERS_COMMON = \
mac/mac.hpp \
mac/mac_filter.hpp \
mac/mac_frame.hpp \
mac/sub_mac.hpp \
meshcop/announce_begin_client.hpp \
meshcop/border_agent.hpp \
meshcop/commissioner.hpp \
+3 -2
View File
@@ -105,7 +105,7 @@ otError otLinkRawReceive(otInstance *aInstance, otLinkRawReceiveDone aCallback)
otRadioFrame *otLinkRawGetTransmitBuffer(otInstance *aInstance)
{
return static_cast<Instance *>(aInstance)->GetLinkRaw().GetTransmitFrame();
return &static_cast<Instance *>(aInstance)->GetLinkRaw().GetTransmitFrame();
}
otError otLinkRawTransmit(otInstance *aInstance, otLinkRawTransmitDone aCallback)
@@ -263,7 +263,8 @@ const otExtAddress *otLinkGetExtendedAddress(otInstance *aInstance)
otError otLinkSetExtendedAddress(otInstance *aInstance, const otExtAddress *aExtAddress)
{
return static_cast<Instance *>(aInstance)->GetLinkRaw().SetExtAddress(*aExtAddress);
return static_cast<Instance *>(aInstance)->GetLinkRaw().SetExtAddress(
*static_cast<const Mac::ExtAddress *>(aExtAddress));
}
uint16_t otLinkGetShortAddress(otInstance *aInstance)
+23 -10
View File
@@ -383,6 +383,16 @@ public:
#endif // OPENTHREAD_MTD || OPENTHREAD_FTD
#if OPENTHREAD_RADIO || OPENTHREAD_ENABLE_RAW_LINK_API
/**
* This method returns a reference to LinkRaw object.
*
* @returns A reference to the LinkRaw object.
*
*/
Mac::LinkRaw &GetLinkRaw(void) { return mLinkRaw; }
#endif
/**
* This template method returns a reference to a given `Type` object belonging to the OpenThread instance.
*
@@ -400,16 +410,6 @@ public:
*/
template <typename Type> inline Type &Get(void);
#if OPENTHREAD_RADIO || OPENTHREAD_ENABLE_RAW_LINK_API
/**
* This method returns a reference to LinkRaw object.
*
* @returns A reference to the LinkRaw object.
*
*/
Mac::LinkRaw &GetLinkRaw(void) { return mLinkRaw; }
#endif
private:
Instance(void);
void AfterInit(void);
@@ -520,6 +520,11 @@ template <> inline Mac::Mac &Instance::Get(void)
return GetThreadNetif().GetMac();
}
template <> inline Mac::SubMac &Instance::Get(void)
{
return GetThreadNetif().GetMac().GetSubMac();
}
template <> inline KeyManager &Instance::Get(void)
{
return GetThreadNetif().GetKeyManager();
@@ -707,6 +712,14 @@ template <> inline Mac::LinkRaw &Instance::Get(void)
{
return GetLinkRaw();
}
#if OPENTHREAD_RADIO
template <> inline Mac::SubMac &Instance::Get(void)
{
return GetLinkRaw().GetSubMac();
}
#endif
#endif // OPENTHREAD_RADIO || OPENTHREAD_ENABLE_RAW_LINK_API
template <> inline TaskletScheduler &Instance::Get(void)
+16 -15
View File
@@ -223,6 +223,22 @@ class TimerScheduler : public InstanceLocator
{
friend class Timer;
public:
/**
* This static method compares two times and indicates if the first time is strictly before (earlier) than the
* second time.
*
* This method requires that the difference between the two given times to be smaller than kMaxDt.
*
* @param[in] aTimerA The first time for comparison.
* @param[in] aTimerB The second time for comparison.
*
* @returns TRUE if aTimeA is before aTimeB.
* @returns FALSE if aTimeA is same time or after aTimeB.
*
*/
static bool IsStrictlyBefore(uint32_t aTimeA, uint32_t aTimeB);
protected:
/**
* The Alarm APIs definition
@@ -281,21 +297,6 @@ protected:
*/
void SetAlarm(const AlarmApi &aAlarmApi);
/**
* This static method compares two times and indicates if the first time is strictly before (earlier) than the
* second time.
*
* This method requires that the difference between the two given times to be smaller than kMaxDt.
*
* @param[in] aTimerA The first time for comparison.
* @param[in] aTimerB The second time for comparison.
*
* @returns TRUE if aTimeA is before aTimeB.
* @returns FALSE if aTimeA is same time or after aTimeB.
*
*/
static bool IsStrictlyBefore(uint32_t aTimeA, uint32_t aTimeB);
Timer *mHead;
};
+42 -413
View File
@@ -40,59 +40,31 @@
#include "common/debug.hpp"
#include "common/instance.hpp"
#include "common/logging.hpp"
#include "common/owner-locator.hpp"
#include "common/random.hpp"
#include "mac/mac.hpp"
#include "utils/parse_cmdline.hpp"
#include "mac/mac_frame.hpp"
#if OPENTHREAD_RADIO || OPENTHREAD_ENABLE_RAW_LINK_API
namespace ot {
namespace Mac {
LinkRaw::LinkRaw(Instance &aInstance)
: InstanceLocator(aInstance)
, mOperationTask(aInstance, &LinkRaw::HandleOperationTask, this)
, mPendingTransmitData(false)
#if OPENTHREAD_LINKRAW_TIMER_REQUIRED
, mTimer(aInstance, &LinkRaw::HandleTimer, this)
, mTimerReason(kTimerReasonNone)
#if OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_TIMER
, mTimerMicro(aInstance, &LinkRaw::HandleTimer, this)
#else
, 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)
#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT
, mEnabled(false)
, mReceiveChannel(OPENTHREAD_CONFIG_DEFAULT_CHANNEL)
, mPanId(kPanIdBroadcast)
, mReceiveDoneCallback(NULL)
, mTransmitDoneCallback(NULL)
, mEnergyScanDoneCallback(NULL)
, mTransmitFrame(static_cast<Frame *>(otPlatRadioGetTransmitBuffer(&aInstance)))
, mRadioCaps(otPlatRadioGetCaps(&aInstance))
#if OPENTHREAD_RADIO
, mSubMac(aInstance, *this)
#elif OPENTHREAD_ENABLE_RAW_LINK_API
, mSubMac(aInstance.Get<SubMac>())
#endif
{
}
void LinkRaw::HandleOperationTask(Tasklet &aTasklet)
{
aTasklet.GetOwner<LinkRaw>().HandleOperationTask();
}
void LinkRaw::HandleOperationTask(void)
{
if (mPendingTransmitData)
{
mPendingTransmitData = false;
TransmitNow();
}
}
otError LinkRaw::SetEnabled(bool aEnabled)
{
otError error = OT_ERROR_NONE;
@@ -101,22 +73,20 @@ otError LinkRaw::SetEnabled(bool aEnabled)
#if OPENTHREAD_MTD || OPENTHREAD_FTD
VerifyOrExit(!GetInstance().GetThreadNetif().IsUp(), error = OT_ERROR_INVALID_STATE);
#endif // OPENTHREAD_MTD || OPENTHREAD_FTD
#endif
if (aEnabled)
{
otPlatRadioEnable(&GetInstance());
SuccessOrExit(error = mSubMac.Enable());
}
else
{
otPlatRadioDisable(&GetInstance());
mSubMac.Disable();
}
mEnabled = aEnabled;
#if OPENTHREAD_MTD || OPENTHREAD_FTD
exit:
#endif // OPENTHREAD_MTD || OPENTHREAD_FTD
return error;
}
@@ -125,8 +95,7 @@ otError LinkRaw::SetPanId(uint16_t aPanId)
otError error = OT_ERROR_NONE;
VerifyOrExit(IsEnabled(), error = OT_ERROR_INVALID_STATE);
otPlatRadioSetPanId(&GetInstance(), aPanId);
mSubMac.SetPanId(aPanId);
mPanId = aPanId;
exit:
@@ -138,82 +107,48 @@ otError LinkRaw::SetChannel(uint8_t aChannel)
otError error = OT_ERROR_NONE;
VerifyOrExit(IsEnabled(), error = OT_ERROR_INVALID_STATE);
mReceiveChannel = aChannel;
exit:
return error;
}
otError LinkRaw::SetExtAddress(const otExtAddress &aExtAddress)
otError LinkRaw::SetExtAddress(const ExtAddress &aExtAddress)
{
otExtAddress addr;
otError error = OT_ERROR_NONE;
otError error = OT_ERROR_NONE;
VerifyOrExit(IsEnabled(), error = OT_ERROR_INVALID_STATE);
for (size_t i = 0; i < sizeof(addr); i++)
{
addr.m8[i] = aExtAddress.m8[7 - i];
}
otPlatRadioSetExtendedAddress(&GetInstance(), &addr);
mExtAddress = aExtAddress;
mSubMac.SetExtAddress(aExtAddress);
exit:
return error;
}
otError LinkRaw::SetShortAddress(uint16_t aShortAddress)
otError LinkRaw::SetShortAddress(ShortAddress aShortAddress)
{
otError error = OT_ERROR_NONE;
VerifyOrExit(IsEnabled(), error = OT_ERROR_INVALID_STATE);
mSubMac.SetShortAddress(aShortAddress);
exit:
return error;
}
otError LinkRaw::Receive(otLinkRawReceiveDone aCallback)
{
otError error = OT_ERROR_NONE;
VerifyOrExit(IsEnabled(), error = OT_ERROR_INVALID_STATE);
otPlatRadioSetShortAddress(&GetInstance(), aShortAddress);
mShortAddress = aShortAddress;
SuccessOrExit(error = mSubMac.Receive(mReceiveChannel));
mReceiveDoneCallback = aCallback;
exit:
return error;
}
otRadioCaps LinkRaw::GetCaps(void) const
{
otRadioCaps radioCaps = mRadioCaps;
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ACK_TIMEOUT
radioCaps |= OT_RADIO_CAPS_ACK_TIMEOUT;
#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ACK_TIMEOUT
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT
radioCaps |= OT_RADIO_CAPS_TRANSMIT_RETRIES;
#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_CSMA_BACKOFF
radioCaps |= OT_RADIO_CAPS_CSMA_BACKOFF;
#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_CSMA_BACKOFF
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ENERGY_SCAN
radioCaps |= OT_RADIO_CAPS_ENERGY_SCAN;
#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ENERGY_SCAN
return radioCaps;
}
otError LinkRaw::Receive(otLinkRawReceiveDone aCallback)
{
otError error = OT_ERROR_INVALID_STATE;
if (mEnabled)
{
mReceiveDoneCallback = aCallback;
error = otPlatRadioReceive(&GetInstance(), mReceiveChannel);
}
return error;
}
void LinkRaw::InvokeReceiveDone(otRadioFrame *aFrame, otError aError)
void LinkRaw::InvokeReceiveDone(Frame *aFrame, otError aError)
{
if (mReceiveDoneCallback)
{
@@ -229,64 +164,21 @@ void LinkRaw::InvokeReceiveDone(otRadioFrame *aFrame, otError aError)
}
}
void LinkRaw::StartTransmit(void)
{
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_CSMA_BACKOFF
if ((mRadioCaps & OT_RADIO_CAPS_CSMA_BACKOFF) == 0 && mTransmitFrame->IsCsmaCaEnabled())
{
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);
VerifyOrExit(IsEnabled(), error = OT_ERROR_INVALID_STATE);
SuccessOrExit(error = mSubMac.Send());
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;
}
#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT
StartTransmit();
exit:
return error;
}
void LinkRaw::InvokeTransmitDone(otRadioFrame *aFrame, otRadioFrame *aAckFrame, otError aError)
void LinkRaw::InvokeTransmitDone(Frame &aFrame, Frame *aAckFrame, otError aError)
{
assert(aFrame == mTransmitFrame);
if (aError == OT_ERROR_NONE)
{
otLogDebgPlat("LinkRaw Transmit Done: %s", otThreadErrorToString(aError));
@@ -296,299 +188,36 @@ void LinkRaw::InvokeTransmitDone(otRadioFrame *aFrame, otRadioFrame *aAckFrame,
otLogWarnPlat("LinkRaw Transmit Done: %s", otThreadErrorToString(aError));
}
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ACK_TIMEOUT
if ((mRadioCaps & OT_RADIO_CAPS_ACK_TIMEOUT) == 0)
if (mTransmitDoneCallback)
{
mTimer.Stop();
mTransmitDoneCallback(&GetInstance(), &aFrame, aAckFrame, aError);
mTransmitDoneCallback = NULL;
}
#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ACK_TIMEOUT
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_CSMA_BACKOFF
if ((mRadioCaps & OT_RADIO_CAPS_CSMA_BACKOFF) == 0)
{
if (aError == OT_ERROR_CHANNEL_ACCESS_FAILURE)
{
mCsmaBackoffs++;
if (mCsmaBackoffs < aFrame->mInfo.mTxInfo.mMaxCsmaBackoffs)
{
ExitNow(StartTransmit());
}
}
else
{
mCsmaBackoffs = 0;
}
}
#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;
}
otError LinkRaw::EnergyScan(uint8_t aScanChannel, uint16_t aScanDuration, otLinkRawEnergyScanDone aCallback)
{
otError error = OT_ERROR_INVALID_STATE;
otError error = OT_ERROR_NONE;
if (mEnabled)
{
mEnergyScanDoneCallback = aCallback;
VerifyOrExit(IsEnabled(), error = OT_ERROR_INVALID_STATE);
if (otPlatRadioGetCaps(&GetInstance()) & OT_RADIO_CAPS_ENERGY_SCAN)
{
// Do the HW offloaded energy scan
error = otPlatRadioEnergyScan(&GetInstance(), aScanChannel, aScanDuration);
}
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ENERGY_SCAN
else
{
// Start listening on the scan channel
otPlatRadioReceive(&GetInstance(), aScanChannel);
// Reset the RSSI value and start scanning
mEnergyScanRssi = kInvalidRssiValue;
mTimerReason = kTimerReasonEnergyScanComplete;
#if OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_TIMER
mTimerMicro.Start(0);
#else
mEnergyScanTimer.Start(0);
#endif
mTimer.Start(aScanDuration);
}
#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ENERGY_SCAN
}
SuccessOrExit(error = mSubMac.EnergyScan(aScanChannel, aScanDuration));
mEnergyScanDoneCallback = aCallback;
exit:
return error;
}
void LinkRaw::InvokeEnergyScanDone(int8_t aEnergyScanMaxRssi)
{
if (IsEnabled() && mEnergyScanDoneCallback)
if (IsEnabled() && mEnergyScanDoneCallback != NULL)
{
mEnergyScanDoneCallback(&GetInstance(), aEnergyScanMaxRssi);
mEnergyScanDoneCallback = NULL;
}
}
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 ((mRadioCaps & OT_RADIO_CAPS_ACK_TIMEOUT) == 0 && static_cast<Frame *>(aFrame)->GetAckRequest())
{
otLogDebgPlat("LinkRaw Starting AckTimeout Timer");
mTimerReason = kTimerReasonAckTimeout;
mTimer.Start(kAckTimeout);
}
#else
OT_UNUSED_VARIABLE(aFrame);
#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ACK_TIMEOUT
}
#if OPENTHREAD_LINKRAW_TIMER_REQUIRED
void LinkRaw::HandleTimer(Timer &aTimer)
{
LinkRaw &linkRaw = aTimer.GetOwner<LinkRaw>();
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ENERGY_SCAN
// Energy scan uses a different timer for adding delay between RSSI samples.
if (&aTimer != &linkRaw.mTimer && linkRaw.mTimerReason == kTimerReasonEnergyScanComplete)
{
linkRaw.HandleEnergyScanTimer();
}
else
#endif
{
linkRaw.HandleTimer();
}
}
void LinkRaw::HandleTimer(void)
{
TimerReason timerReason = mTimerReason;
mTimerReason = kTimerReasonNone;
switch (timerReason)
{
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ACK_TIMEOUT
case kTimerReasonAckTimeout:
{
// Transition back to receive state on previous channel
otPlatRadioReceive(&GetInstance(), mReceiveChannel);
// Invoke completion callback for transmit
InvokeTransmitDone(mTransmitFrame, NULL, OT_ERROR_NO_ACK);
break;
}
#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ACK_TIMEOUT
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_CSMA_BACKOFF
case kTimerReasonCsmaBackoffComplete:
{
TransmitNow();
break;
}
#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_CSMA_BACKOFF
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ENERGY_SCAN
case kTimerReasonEnergyScanComplete:
{
// Invoke completion callback for the energy scan
InvokeEnergyScanDone(mEnergyScanRssi);
break;
}
#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ENERGY_SCAN
default:
assert(false);
break;
}
}
#endif // OPENTHREAD_LINKRAW_TIMER_REQUIRED
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_CSMA_BACKOFF
void LinkRaw::StartCsmaBackoff(void)
{
uint32_t backoffExponent = kMinBE + mTransmitRetries + mCsmaBackoffs;
uint32_t backoff;
if (backoffExponent > kMaxBE)
{
backoffExponent = kMaxBE;
}
backoff = Random::GetUint32InRange(0, 1U << backoffExponent);
backoff *= (static_cast<uint32_t>(kUnitBackoffPeriod) * OT_RADIO_SYMBOL_TIME);
otLogDebgPlat("LinkRaw Starting RetransmitTimeout Timer (%d ms)", backoff);
mTimerReason = kTimerReasonCsmaBackoffComplete;
#if OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_TIMER
mTimerMicro.Start(backoff);
#else // OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_TIMER
mTimer.Start(backoff / 1000UL);
#endif // OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_TIMER
}
#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_CSMA_BACKOFF
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ENERGY_SCAN
void LinkRaw::HandleEnergyScanTimer(void)
{
// Only process if we are still energy scanning
if (mTimer.IsRunning() && mTimerReason == kTimerReasonEnergyScanComplete)
{
int8_t rssi = otPlatRadioGetRssi(&GetInstance());
// Only apply the RSSI if it was a valid value
if (rssi != kInvalidRssiValue)
{
if ((mEnergyScanRssi == kInvalidRssiValue) || (rssi > mEnergyScanRssi))
{
mEnergyScanRssi = rssi;
}
}
#if OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_TIMER
mTimerMicro.Start(kEnergyScanRssiSampleInterval);
#else
mEnergyScanTimer.Start(kEnergyScanRssiSampleInterval);
#endif
}
}
#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<ot::Instance *>(aInstance)->GetLinkRaw().InvokeReceiveDone(aFrame, aError);
}
extern "C" void otPlatRadioTxDone(otInstance *aInstance, otRadioFrame *aFrame, otRadioFrame *aAckFrame, otError aError)
{
static_cast<ot::Instance *>(aInstance)->GetLinkRaw().InvokeTransmitDone(aFrame, aAckFrame, aError);
}
extern "C" void otPlatRadioTxStarted(otInstance *aInstance, otRadioFrame *aFrame)
{
static_cast<ot::Instance *>(aInstance)->GetLinkRaw().TransmitStarted(aFrame);
}
extern "C" void otPlatRadioEnergyScanDone(otInstance *aInstance, int8_t aEnergyScanMaxRssi)
{
VerifyOrExit(otInstanceIsInitialized(aInstance));
static_cast<ot::Instance *>(aInstance)->GetLinkRaw().InvokeEnergyScanDone(aEnergyScanMaxRssi);
exit:
return;
}
#if OPENTHREAD_CONFIG_HEADER_IE_SUPPORT
extern "C" void otPlatRadioFrameUpdated(otInstance *aInstance, otRadioFrame *aFrame)
{
// Note: For now this functionality is not supported in Radio Only mode.
OT_UNUSED_VARIABLE(aInstance);
OT_UNUSED_VARIABLE(aFrame);
}
#endif
#endif // OPENTHREAD_RADIO
#endif // OPENTHREAD_RADIO || OPENTHREAD_ENABLE_RAW_LINK_API
+57 -118
View File
@@ -39,21 +39,23 @@
#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
#define OPENTHREAD_LINKRAW_TIMER_REQUIRED 1
#else
#define OPENTHREAD_LINKRAW_TIMER_REQUIRED 0
#endif
#include "mac/sub_mac.hpp"
namespace ot {
namespace Mac {
#if OPENTHREAD_RADIO || OPENTHREAD_ENABLE_RAW_LINK_API
/**
* This class defines the raw link-layer object.
*
*/
class LinkRaw : public InstanceLocator
#if OPENTHREAD_RADIO
,
public SubMac::Callbacks
#endif
{
public:
/**
@@ -64,6 +66,14 @@ public:
*/
explicit LinkRaw(Instance &aInstance);
/**
* This method gets the associated `SubMac` object.
*
* @returns A reference to the `SubMac` object.
*
*/
SubMac &GetSubMac(void) { return mSubMac; }
/**
* This method returns true if the raw link-layer is enabled.
*
@@ -78,7 +88,8 @@ public:
* @param[in] aEnabled Whether enable raw link-layer.
*
* @retval OT_ERROR_INVALID_STATE Thread stack is enabled.
* @retval OT_ERROR_NONE Successfully enabled raw link.
* @retval OT_ERROR_FAILED The radio could not be enabled.
* @retval OT_ERROR_NONE Successfully enabled/disabled raw link.
*
*/
otError SetEnabled(bool aEnabled);
@@ -86,10 +97,10 @@ public:
/**
* This method returns the capabilities of the raw link-layer.
*
* @returns The radio capability bit vector. The stack enables or disables some functions based on this value.
* @returns The radio capability bit vector.
*
*/
otRadioCaps GetCaps(void) const;
otRadioCaps GetCaps(void) const { return mSubMac.GetCaps(); }
/**
* This method starts a (recurring) Receive on the link-layer.
@@ -106,12 +117,20 @@ public:
* This method invokes the mReceiveDoneCallback, if set.
*
* @param[in] aFrame A pointer to the received frame or NULL if the receive operation failed.
* @param[in] aError OT_ERROR_NONE when successfully received a frame, OT_ERROR_ABORT when reception
* was aborted and a frame was not received, OT_ERROR_NO_BUFS when a frame could not be
* received due to lack of rx buffer space.
* @param[in] aError OT_ERROR_NONE when successfully received a frame,
* OT_ERROR_ABORT when reception was aborted and a frame was not received,
* OT_ERROR_NO_BUFS when a frame could not be received due to lack of rx buffer space.
*
*/
void InvokeReceiveDone(otRadioFrame *aFrame, otError aError);
void InvokeReceiveDone(Frame *aFrame, otError aError);
/**
* This method gets the radio transmit frame.
*
* @returns The transmit frame.
*
*/
Frame &GetTransmitFrame(void) { return mSubMac.GetTransmitFrame(); }
/**
* This method starts a (single) Transmit on the link-layer.
@@ -129,18 +148,18 @@ public:
/**
* This method invokes the mTransmitDoneCallback, if set.
*
* @param[in] aFrame A pointer to the frame that was transmitted.
* @param[in] aFrame The transmitted frame.
* @param[in] aAckFrame A pointer to the ACK frame, NULL if no ACK was received.
* @param[in] aError OT_ERROR_NONE when the frame was transmitted, OT_ERROR_NO_ACK when the frame was
* transmitted but no ACK was received, OT_ERROR_CHANNEL_ACCESS_FAILURE when the transmission
* could not take place due to activity on the channel, OT_ERROR_ABORT when transmission was
* aborted for other reasons.
* @param[in] aError OT_ERROR_NONE when the frame was transmitted,
* OT_ERROR_NO_ACK when the frame was transmitted but no ACK was received,
* OT_ERROR_CHANNEL_ACCESS_FAILURE tx failed due to activity on the channel,
* OT_ERROR_ABORT when transmission was aborted for other reasons.
*
*/
void InvokeTransmitDone(otRadioFrame *aFrame, otRadioFrame *aAckFrame, otError aError);
void InvokeTransmitDone(Frame &aFrame, Frame *aAckFrame, otError aError);
/**
* This method starts a (single) Enery Scan on the link-layer.
* This method starts a (single) Energy Scan on the link-layer.
*
* @param[in] aScanChannel The channel to perform the energy scan on.
* @param[in] aScanDuration The duration, in milliseconds, for the channel to be scanned.
@@ -161,21 +180,13 @@ public:
*/
void InvokeEnergyScanDone(int8_t aEnergyScanMaxRssi);
/**
* This method is called when the transmission has started.
*
* @param[in] aFrame A pointer to the frame that is being transmitted.
*
*/
void TransmitStarted(otRadioFrame *aFrame);
/**
* This function returns the short address.
*
* @returns short address.
*
*/
uint16_t GetShortAddress(void) const { return mShortAddress; }
ShortAddress GetShortAddress(void) const { return mSubMac.GetShortAddress(); }
/**
* This method updates short address.
@@ -186,7 +197,7 @@ public:
* @retval OT_ERROR_INVALID_STATE If the raw link-layer isn't enabled.
*
*/
otError SetShortAddress(uint16_t aShortAddress);
otError SetShortAddress(ShortAddress aShortAddress);
/**
* This function returns PANID.
@@ -194,7 +205,7 @@ public:
* @returns PANID.
*
*/
uint16_t GetPanId(void) const { return mPanId; }
PanId GetPanId(void) const { return mPanId; }
/**
* This method updates PANID.
@@ -205,7 +216,7 @@ public:
* @retval OT_ERROR_INVALID_STATE If the raw link-layer isn't enabled.
*
*/
otError SetPanId(uint16_t aPanId);
otError SetPanId(PanId aPanId);
/**
* This method gets the current receiving channel.
@@ -229,7 +240,7 @@ public:
* @returns A reference to the extended address.
*
*/
const otExtAddress &GetExtAddress(void) const { return mExtAddress; }
const ExtAddress &GetExtAddress(void) const { return mSubMac.GetExtAddress(); }
/**
* This method updates extended address.
@@ -240,97 +251,25 @@ public:
* @retval OT_ERROR_INVALID_STATE If the raw link-layer isn't enabled.
*
*/
otError SetExtAddress(const otExtAddress &aExtAddress);
/**
* This method gets the transmit frame.
*
* @returns A pointer to the transmit frame.
*
*/
otRadioFrame *GetTransmitFrame(void) { return mTransmitFrame; }
otError SetExtAddress(const ExtAddress &aExtAddress);
private:
void TransmitNow(void);
void StartTransmit(void);
static void HandleOperationTask(Tasklet &aTasklet);
void HandleOperationTask(void);
Tasklet mOperationTask;
bool mPendingTransmitData : 1;
enum TimerReason
{
kTimerReasonNone,
kTimerReasonAckTimeout,
kTimerReasonCsmaBackoffComplete,
kTimerReasonEnergyScanComplete,
};
#if OPENTHREAD_LINKRAW_TIMER_REQUIRED
TimerMilli mTimer;
TimerReason mTimerReason;
#if OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_TIMER
TimerMicro mTimerMicro;
#else
TimerMilli mEnergyScanTimer;
#endif
static void HandleTimer(Timer &aTimer);
void HandleTimer(void);
#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;
#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ENERGY_SCAN
enum
{
kInvalidRssiValue = 127,
/**
* Interval between RSSI samples when performing Energy Scan.
*
* `mTimerMicro` or `mEnergyScanTimer` is used for adding delay between RSSI samples. If microsecond timer is
* supported, 128 usec time between samples is used, otherwise with the millisecond timer `mEnergyScanTimer` the
* minimum value of 1 msec is used.
*
*/
#if OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_TIMER
kEnergyScanRssiSampleInterval = 128,
#else
kEnergyScanRssiSampleInterval = 1,
#endif
};
int8_t mEnergyScanRssi;
void HandleEnergyScanTimer(void);
#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ENERGY_SCAN
otExtAddress mExtAddress;
uint16_t mPanId;
uint16_t mShortAddress;
bool mEnabled;
uint8_t mReceiveChannel;
PanId mPanId;
otLinkRawReceiveDone mReceiveDoneCallback;
otLinkRawTransmitDone mTransmitDoneCallback;
otLinkRawEnergyScanDone mEnergyScanDoneCallback;
Frame * mTransmitFrame;
otRadioCaps mRadioCaps;
#if OPENTHREAD_RADIO
SubMac mSubMac;
#elif OPENTHREAD_ENABLE_RAW_LINK_API
SubMac &mSubMac;
#endif
};
#endif // OPENTHREAD_RADIO || OPENTHREAD_ENABLE_RAW_LINK_API
} // namespace Mac
} // namespace ot
+276 -688
View File
File diff suppressed because it is too large Load Diff
+78 -98
View File
@@ -45,6 +45,7 @@
#include "mac/channel_mask.hpp"
#include "mac/mac_filter.hpp"
#include "mac/mac_frame.hpp"
#include "mac/sub_mac.hpp"
#include "thread/key_manager.hpp"
#include "thread/link_quality.hpp"
#include "thread/topology.hpp"
@@ -69,13 +70,6 @@ namespace Mac {
*/
enum
{
kMinBE = 3, ///< macMinBE (IEEE 802.15.4-2006).
kMaxBE = 5, ///< macMaxBE (IEEE 802.15.4-2006).
kUnitBackoffPeriod = 20, ///< Number of symbols (IEEE 802.15.4-2006).
kMinBackoff = 1, ///< Minimum backoff (milliseconds).
kAckTimeout = 16, ///< Timeout for waiting on an ACK (milliseconds).
kDataPollTimeout = 100, ///< Timeout for receiving Data Frame (milliseconds).
kSleepDelay = 300, ///< Max sleep delay when frame is pending (milliseconds).
kNonceSize = 13, ///< Size of IEEE 802.15.4 Nonce (bytes).
@@ -100,7 +94,7 @@ enum
* This class implements the IEEE 802.15.4 MAC.
*
*/
class Mac : public InstanceLocator
class Mac : public InstanceLocator, public SubMac::Callbacks
{
public:
/**
@@ -111,6 +105,14 @@ public:
*/
explicit Mac(Instance &aInstance);
/**
* This method gets the associated `SubMac` object.
*
* @returns A reference to the `SubMac` object.
*
*/
SubMac &GetSubMac(void) { return mSubMac; }
/**
* This function pointer is called on receiving an IEEE 802.15.4 Beacon during an Active Scan.
*
@@ -244,7 +246,7 @@ public:
* @returns A pointer to the IEEE 802.15.4 Extended Address.
*
*/
const ExtAddress &GetExtAddress(void) const { return mExtAddress; }
const ExtAddress &GetExtAddress(void) const { return mSubMac.GetExtAddress(); }
/**
* This method sets the IEEE 802.15.4 Extended Address.
@@ -252,7 +254,7 @@ public:
* @param[in] aExtAddress A reference to the IEEE 802.15.4 Extended Address.
*
*/
void SetExtAddress(const ExtAddress &aExtAddress);
void SetExtAddress(const ExtAddress &aExtAddress) { mSubMac.SetExtAddress(aExtAddress); }
/**
* This method returns the IEEE 802.15.4 Short Address.
@@ -260,7 +262,7 @@ public:
* @returns The IEEE 802.15.4 Short Address.
*
*/
ShortAddress GetShortAddress(void) const { return mShortAddress; }
ShortAddress GetShortAddress(void) const { return mSubMac.GetShortAddress(); }
/**
* This method sets the IEEE 802.15.4 Short Address.
@@ -386,7 +388,7 @@ public:
* @returns The IEEE 802.15.4 PAN ID.
*
*/
uint16_t GetPanId(void) const { return mPanId; }
PanId GetPanId(void) const { return mPanId; }
/**
* This method sets the IEEE 802.15.4 PAN ID.
@@ -396,7 +398,7 @@ public:
* @retval OT_ERROR_NONE Successfully set the IEEE 802.15.4 PAN ID.
*
*/
otError SetPanId(uint16_t aPanId);
otError SetPanId(PanId aPanId);
/**
* This method returns the IEEE 802.15.4 Extended PAN ID.
@@ -437,24 +439,49 @@ public:
void HandleReceivedFrame(Frame *aFrame, otError aError);
/**
* This method is called to handle transmission start events.
* This method records CCA status (success/failure) for a frame transmission attempt.
*
* @param[in] aCcaSuccess TRUE if the CCA succeeded, FALSE otherwise.
* @param[in] aChannel The channel on which CCA was performed.
*
* @param[in] aFrame A pointer to the frame that is transmitted.
*/
void HandleTransmitStarted(otRadioFrame *aFrame);
void RecordCcaStatus(bool aCcaSuccess, uint8_t aChannel);
/**
* This method records the status of a frame transmission attempt, updating MAC counters.
*
* Unlike `HandleTransmitDone` which is called after all transmission attempts of frame to indicate final status
* of a frame transmission request, this method is invoked on all frame transmission attempts.
*
* @param[in] aFrame The transmitted frame.
* @param[in] aAckFrame A pointer to the ACK frame, or NULL if no ACK was received.
* @param[in] aError OT_ERROR_NONE when the frame was transmitted successfully,
* OT_ERROR_NO_ACK when the frame was transmitted but no ACK was received,
* OT_ERROR_CHANNEL_ACCESS_FAILURE tx failed due to activity on the channel,
* OT_ERROR_ABORT when transmission was aborted for other reasons.
* @param[in] aRetryCount Indicates number of transmission retries for this frame.
* @param[in] aWillRetx Indicates whether frame will be retransmitted or not. This is applicable only
* when there was an error in transmission (i.e., `aError` is not NONE).
*
*/
void RecordFrameTransmitStatus(const Frame &aFrame,
const Frame *aAckFrame,
otError aError,
uint8_t aRetryCount,
bool aWillRetx);
/**
* This method is called to handle transmit events.
*
* @param[in] aFrame A pointer to the frame that was transmitted.
* @param[in] aFrame The frame that was transmitted.
* @param[in] aAckFrame A pointer to the ACK frame, NULL if no ACK was received.
* @param[in] aError OT_ERROR_NONE when the frame was transmitted,
* @param[in] aError OT_ERROR_NONE when the frame was transmitted successfully,
* OT_ERROR_NO_ACK when the frame was transmitted but no ACK was received,
* OT_ERROR_CHANNEL_ACCESS_FAILURE when the tx failed due to activity on the channel,
* OT_ERROR_ABORT when transmission was aborted for other reasons.
*
*/
void HandleTransmitDone(otRadioFrame *aFrame, otRadioFrame *aAckFrame, otError aError);
void HandleTransmitDone(Frame &aFrame, Frame *aAckFrame, otError aError);
/**
* This method returns if an active scan is in progress.
@@ -495,7 +522,7 @@ public:
* @retval false Promiscuous mode is not enabled.
*
*/
bool IsPromiscuous(void);
bool IsPromiscuous(void) const { return mPromiscuous; }
/**
* This method enables or disables the link layer promiscuous mode.
@@ -559,7 +586,7 @@ public:
uint16_t GetCcaFailureRate(void) const { return mCcaSuccessRateTracker.GetFailureRate(); }
/**
* This method Starts/Stops the Link layer. It may only be used when the Netif Interface is down
* This method Starts/Stops the Link layer. It may only be used when the Netif Interface is down.
*
* @param[in] aEnable The requested State for the MAC layer. true - Start, false - Stop.
*
@@ -590,22 +617,9 @@ public:
private:
enum
{
kInvalidRssiValue = 127,
kInvalidRssiValue = SubMac::kInvalidRssiValue,
kMaxCcaSampleCount = OPENTHREAD_CONFIG_CCA_FAILURE_RATE_AVERAGING_WINDOW,
kMaxAcquisitionId = 0xffff,
/**
* Interval between RSSI samples when performing Energy Scan.
*
* `mBackoffTimer` is used for adding delay between RSSI samples. If microsecond timer is supported, 128 usec
* time between samples is used, otherwise with a millisecond timer the minimum value of 1 msec is used.
*
*/
#if OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_TIMER
kEnergyScanRssiSampleInterval = 128,
#else
kEnergyScanRssiSampleInterval = 1,
#endif
};
enum Operation
@@ -645,35 +659,22 @@ private:
void SendBeaconRequest(Frame &aFrame);
void SendBeacon(Frame &aFrame);
bool ShouldSendBeacon(void) const;
void StartBackoff(void);
void BeginTransmit(void);
otError HandleMacCommand(Frame &aFrame);
Frame * GetOperationFrame(void);
static void HandleMacTimer(Timer &aTimer);
void HandleMacTimer(void);
static void HandleBackoffTimer(Timer &aTimer);
void HandleBackoffTimer(void);
static void HandleReceiveTimer(Timer &aTimer);
void HandleReceiveTimer(void);
static void HandleTimer(Timer &aTimer);
void HandleTimer(void);
static void HandleOperationTask(Tasklet &aTasklet);
void HandleOperationTask(void);
void StartCsmaBackoff(void);
void Scan(Operation aScanOperation, uint32_t aScanChannels, uint16_t aScanDuration, void *aContext);
otError UpdateScanChannel(void);
void PerformActiveScan(void);
void PerformEnergyScan(void);
void ReportEnergyScanResult(int8_t aRssi);
void SampleRssi(void);
otError RadioTransmit(Frame *aSendFrame);
otError RadioReceive(uint8_t aChannel);
otError RadioSleep(void);
void LogFrameRxFailure(const Frame *aFrame, otError aError) const;
void LogFrameTxFailure(const Frame &aFrame, otError aError) const;
void LogFrameTxFailure(const Frame &aFrame, otError aError, uint8_t aRetryCount) const;
void LogBeacon(const char *aActionText, const BeaconPayload &aBeaconPayload) const;
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
@@ -683,8 +684,7 @@ private:
static const char *OperationToString(Operation aOperation);
Operation mOperation;
bool mEnabled : 1;
bool mPendingActiveScan : 1;
bool mPendingEnergyScan : 1;
bool mPendingTransmitBeacon : 1;
@@ -692,66 +692,46 @@ private:
bool mPendingTransmitOobFrame : 1;
bool mPendingWaitingForData : 1;
bool mRxOnWhenIdle : 1;
bool mPromiscuous : 1;
bool mBeaconsEnabled : 1;
bool mTransmitAborted : 1;
#if OPENTHREAD_CONFIG_STAY_AWAKE_BETWEEN_FRAGMENTS
bool mDelaySleep : 1;
bool mShouldDelaySleep : 1;
bool mDelayingSleep : 1;
#endif
Tasklet mOperationTask;
TimerMilli mMacTimer;
#if OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_TIMER
TimerMicro mBackoffTimer;
#else
TimerMilli mBackoffTimer;
#endif
TimerMilli mReceiveTimer;
ExtAddress mExtAddress;
ShortAddress mShortAddress;
PanId mPanId;
uint8_t mPanChannel;
uint8_t mRadioChannel;
uint16_t mRadioChannelAcquisitionId;
ChannelMask mSupportedChannelMask;
otNetworkName mNetworkName;
Operation mOperation;
uint8_t mBeaconSequence;
uint8_t mDataSequence;
uint8_t mBroadcastTransmitCount;
PanId mPanId;
uint8_t mPanChannel;
uint8_t mRadioChannel;
uint16_t mRadioChannelAcquisitionId;
ChannelMask mSupportedChannelMask;
otExtendedPanId mExtendedPanId;
uint8_t mBeaconSequence;
uint8_t mDataSequence;
uint8_t mCsmaBackoffs;
uint8_t mTransmitRetries;
uint8_t mBroadcastTransmitCount;
ChannelMask mScanChannelMask;
uint16_t mScanDuration;
uint8_t mScanChannel;
int8_t mEnergyScanCurrentMaxRssi;
void * mScanContext;
otNetworkName mNetworkName;
uint8_t mScanChannel;
uint16_t mScanDuration;
ChannelMask mScanChannelMask;
void * mScanContext;
union
{
ActiveScanHandler mActiveScanHandler;
EnergyScanHandler mEnergyScanHandler;
};
otLinkPcapCallback mPcapCallback;
void * mPcapCallbackContext;
SubMac mSubMac;
Tasklet mOperationTask;
TimerMilli mTimer;
Frame * mOobFrame;
otMacCounters mCounters;
uint32_t mKeyIdMode2FrameCounter;
SuccessRateTracker mCcaSuccessRateTracker;
uint16_t mCcaSampleCount;
#if OPENTHREAD_ENABLE_MAC_FILTER
Filter mFilter;
#endif // OPENTHREAD_ENABLE_MAC_FILTER
Frame *mTxFrame;
Frame *mOobFrame;
otMacCounters mCounters;
uint32_t mKeyIdMode2FrameCounter;
SuccessRateTracker mCcaSuccessRateTracker;
uint16_t mCcaSampleCount;
bool mEnabled;
};
/**
+17
View File
@@ -1072,6 +1072,23 @@ exit:
}
#endif // OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
void Frame::CopyFrom(const Frame &aAnotherFrame)
{
uint8_t * psduBuffer = mPsdu;
otRadioIeInfo *ieInfoBuffer = mIeInfo;
memcpy(this, &aAnotherFrame, sizeof(Frame));
// Set the original buffer pointers back on the frame
// which were overwritten by above `memcpy()`.
mPsdu = psduBuffer;
mIeInfo = ieInfoBuffer;
memcpy(mPsdu, aAnotherFrame.mPsdu, aAnotherFrame.GetPsduLength());
memcpy(mIeInfo, aAnotherFrame.mIeInfo, sizeof(otRadioIeInfo));
}
Frame::InfoString Frame::ToInfoString(void) const
{
InfoString string;
+20 -8
View File
@@ -1063,6 +1063,15 @@ public:
*/
void SetDidTx(bool aDidTx) { mDidTx = aDidTx; }
/**
* This method indicates whether or not CSMA-CA is enabled.
*
* @retval TRUE CSMA-CA is enabled.
* @retval FALSE CSMA-CA is not enabled is not enabled.
*
*/
bool IsCsmaCaEnabled(void) const { return mInfo.mTxInfo.mCsmaCaEnabled; }
/**
* This method sets the CSMA-CA enabled attribute.
*
@@ -1071,14 +1080,6 @@ 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).
*
@@ -1257,6 +1258,17 @@ public:
uint8_t *GetHeaderIe(uint8_t aIeId) const;
#endif // OPENTHREAD_CONFIG_HEADER_IE_SUPPORT
/**
* This method copies the PSDU and all attributes from another frame.
*
* @note This method performs a deep copy meaning the content of PSDU buffer from the given frame is copied into
* the PSDU buffer of the current frame.
* @param[in] aFrame The frame to copy from.
*
*/
void CopyFrom(const Frame &aFrame);
/**
* This method returns information about the frame object as an `InfoString` object.
*
+667
View File
@@ -0,0 +1,667 @@
/*
* Copyright (c) 2016-2018, 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.
*/
/**
* @file
* This file implements the subset of IEEE 802.15.4 MAC primitives.
*/
#define WPP_NAME "sub_mac.tmh"
#include "sub_mac.hpp"
#include <stdio.h>
#include "common/code_utils.hpp"
#include "common/debug.hpp"
#include "common/instance.hpp"
#include "common/logging.hpp"
#include "common/owner-locator.hpp"
#include "common/random.hpp"
namespace ot {
namespace Mac {
SubMac::SubMac(Instance &aInstance, Callbacks &aCallbacks)
: InstanceLocator(aInstance)
, mRadioCaps(otPlatRadioGetCaps(&aInstance))
, mState(kStateDisabled)
, mCsmaBackoffs(0)
, mTransmitRetries(0)
, mShortAddress(kShortAddrInvalid)
, mRxOnWhenBackoff(true)
, mEnergyScanMaxRssi(kInvalidRssiValue)
, mEnergyScanEndTime(0)
, mTransmitFrame(*static_cast<Frame *>(otPlatRadioGetTransmitBuffer(&aInstance)))
, mCallbacks(aCallbacks)
, mPcapCallback(NULL)
, mPcapCallbackContext(NULL)
, mTimer(aInstance, &SubMac::HandleTimer, this)
{
memset(mExtAddress.m8, 0, sizeof(mExtAddress));
}
otRadioCaps SubMac::GetCaps(void) const
{
otRadioCaps caps = mRadioCaps;
#if OPENTHREAD_RADIO || OPENTHREAD_ENABLE_RAW_LINK_API
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ACK_TIMEOUT
caps |= OT_RADIO_CAPS_ACK_TIMEOUT;
#endif
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_CSMA_BACKOFF
caps |= OT_RADIO_CAPS_CSMA_BACKOFF;
#endif
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT
caps |= OT_RADIO_CAPS_TRANSMIT_RETRIES;
#endif
#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ENERGY_SCAN
caps |= OT_RADIO_CAPS_ENERGY_SCAN;
#endif
#else
caps = OT_RADIO_CAPS_ACK_TIMEOUT | OT_RADIO_CAPS_CSMA_BACKOFF | OT_RADIO_CAPS_TRANSMIT_RETRIES |
OT_RADIO_CAPS_ENERGY_SCAN;
#endif
return caps;
}
void SubMac::SetPanId(PanId aPanId)
{
otPlatRadioSetPanId(&GetInstance(), aPanId);
otLogDebgMac("RadioPanId: 0x%04x", aPanId);
}
void SubMac::SetShortAddress(ShortAddress aShortAddress)
{
mShortAddress = aShortAddress;
otPlatRadioSetShortAddress(&GetInstance(), mShortAddress);
otLogDebgMac("RadioShortAddress: 0x%04x", mShortAddress);
}
void SubMac::SetExtAddress(const ExtAddress &aExtAddress)
{
Address address;
mExtAddress = aExtAddress;
// Reverse the byte order before setting on radio.
address.SetExtended(aExtAddress.m8, /* aReverse */ true);
otPlatRadioSetExtendedAddress(&GetInstance(), &address.GetExtended());
otLogDebgMac("RadioExtAddress: %s", mExtAddress.ToString().AsCString());
}
void SubMac::SetPcapCallback(otLinkPcapCallback aPcapCallback, void *aCallbackContext)
{
mPcapCallback = aPcapCallback;
mPcapCallbackContext = aCallbackContext;
}
otError SubMac::Enable(void)
{
otError error = OT_ERROR_NONE;
VerifyOrExit(mState == kStateDisabled);
SuccessOrExit(error = otPlatRadioEnable(&GetInstance()));
error = otPlatRadioSleep(&GetInstance());
assert(error == OT_ERROR_NONE);
SetState(kStateSleep);
exit:
return error;
}
otError SubMac::Disable(void)
{
otError error;
mTimer.Stop();
error = otPlatRadioDisable(&GetInstance());
assert(error == OT_ERROR_NONE);
SetState(kStateDisabled);
return error;
}
otError SubMac::Sleep(void)
{
otError error = otPlatRadioSleep(&GetInstance());
if (error != OT_ERROR_NONE)
{
otLogWarnMac("otPlatRadioSleep() failed, error: %s", otThreadErrorToString(error));
ExitNow();
}
SetState(kStateSleep);
exit:
return error;
}
otError SubMac::Receive(uint8_t aChannel)
{
otError error = otPlatRadioReceive(&GetInstance(), aChannel);
if (error != OT_ERROR_NONE)
{
otLogWarnMac("otPlatRadioReceive() failed, error: %s", otThreadErrorToString(error));
ExitNow();
}
SetState(kStateReceive);
exit:
return error;
}
void SubMac::HandleReceiveDone(Frame *aFrame, otError aError)
{
if (mPcapCallback && (aFrame != NULL) && (aError == OT_ERROR_NONE))
{
aFrame->SetDidTx(false);
mPcapCallback(aFrame, mPcapCallbackContext);
}
mCallbacks.ReceiveDone(aFrame, aError);
}
otError SubMac::Send(void)
{
otError error = OT_ERROR_NONE;
switch (mState)
{
case kStateDisabled:
case kStateCsmaBackoff:
case kStateTransmit:
case kStateEnergyScan:
ExitNow(error = OT_ERROR_INVALID_STATE);
break;
case kStateSleep:
case kStateReceive:
break;
}
mCsmaBackoffs = 0;
mTransmitRetries = 0;
StartCsmaBackoff();
exit:
return error;
}
void SubMac::StartCsmaBackoff(void)
{
uint32_t backoff;
uint32_t backoffExponent = kMinBE + mTransmitRetries + mCsmaBackoffs;
SetState(kStateCsmaBackoff);
VerifyOrExit(ShouldHandleCsmaBackOff(), BeginTransmit());
#if OPENTHREAD_CONFIG_DISABLE_CSMA_CA_ON_LAST_ATTEMPT
if ((mTransmitRetries > 0) && (mTransmitRetries == mTransmitFrame.GetMaxFrameRetries()))
{
BeginTransmit();
ExitNow();
}
#endif
if (backoffExponent > kMaxBE)
{
backoffExponent = kMaxBE;
}
backoff = Random::GetUint32InRange(0, 1U << backoffExponent);
backoff *= (static_cast<uint32_t>(kUnitBackoffPeriod) * OT_RADIO_SYMBOL_TIME);
if (mRxOnWhenBackoff)
{
otPlatRadioReceive(&GetInstance(), mTransmitFrame.GetChannel());
}
else
{
otPlatRadioSleep(&GetInstance());
}
#if OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_TIMER
mTimer.Start(backoff);
#else
mTimer.Start(backoff / 1000UL);
#endif
exit:
return;
}
void SubMac::BeginTransmit(void)
{
otError error;
VerifyOrExit(mState == kStateCsmaBackoff);
#if OPENTHREAD_CONFIG_DISABLE_CSMA_CA_ON_LAST_ATTEMPT
if ((mTransmitRetries > 0) && (mTransmitRetries == mTransmitFrame.GetMaxFrameRetries()))
{
mTransmitFrame.SetCsmaCaEnabled(false);
}
else
#endif
{
mTransmitFrame.SetCsmaCaEnabled(true);
}
error = otPlatRadioReceive(&GetInstance(), mTransmitFrame.GetChannel());
assert(error == OT_ERROR_NONE);
error = otPlatRadioTransmit(&GetInstance(), &mTransmitFrame);
assert(error == OT_ERROR_NONE);
SetState(kStateTransmit);
if (mPcapCallback)
{
mTransmitFrame.SetDidTx(true);
mPcapCallback(&mTransmitFrame, mPcapCallbackContext);
}
exit:
return;
}
void SubMac::HandleTransmitStarted(Frame &aFrame)
{
if (ShouldHandleAckTimeout() && aFrame.GetAckRequest())
{
#if OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_TIMER
mTimer.Start(kAckTimeout * 1000UL);
#else
mTimer.Start(kAckTimeout);
#endif
}
}
void SubMac::HandleTransmitDone(Frame &aFrame, Frame *aAckFrame, otError aError)
{
bool ccaSuccess = true;
bool shouldRetx;
// Stop ack timeout timer.
mTimer.Stop();
// Record CCA success or failure status.
switch (aError)
{
case OT_ERROR_ABORT:
// Do not record CCA status in case of `ABORT` error
// since there may be no CCA check performed by radio.
break;
case OT_ERROR_CHANNEL_ACCESS_FAILURE:
ccaSuccess = false;
// fall through
case OT_ERROR_NONE:
case OT_ERROR_NO_ACK:
if (aFrame.IsCsmaCaEnabled())
{
mCallbacks.RecordCcaStatus(ccaSuccess, aFrame.GetChannel());
}
break;
default:
assert(false);
OT_UNREACHABLE_CODE(ExitNow());
}
// Determine whether a CSMA retry is required.
if (!ccaSuccess && ShouldHandleCsmaBackOff() && mCsmaBackoffs < aFrame.GetMaxCsmaBackoffs())
{
mCsmaBackoffs++;
StartCsmaBackoff();
ExitNow();
}
mCsmaBackoffs = 0;
// Determine whether to re-transmit the frame.
shouldRetx =
((aError != OT_ERROR_NONE) && ShouldHandleRetries() && (mTransmitRetries < aFrame.GetMaxFrameRetries()));
mCallbacks.RecordFrameTransmitStatus(aFrame, aAckFrame, aError, mTransmitRetries, shouldRetx);
if (shouldRetx)
{
mTransmitRetries++;
StartCsmaBackoff();
ExitNow();
}
mTransmitRetries = 0;
SetState(kStateReceive);
mCallbacks.TransmitDone(aFrame, aAckFrame, aError);
exit:
return;
}
int8_t SubMac::GetRssi(void) const
{
return otPlatRadioGetRssi(&GetInstance());
}
otError SubMac::EnergyScan(uint8_t aScanChannel, uint16_t aScanDuration)
{
otError error = OT_ERROR_NONE;
switch (mState)
{
case kStateDisabled:
case kStateCsmaBackoff:
case kStateTransmit:
case kStateEnergyScan:
ExitNow(error = OT_ERROR_INVALID_STATE);
case kStateReceive:
case kStateSleep:
break;
}
if (RadioSupportsEnergyScan())
{
otPlatRadioEnergyScan(&GetInstance(), aScanChannel, aScanDuration);
SetState(kStateEnergyScan);
}
else if (ShouldHandleEnergyScan())
{
error = otPlatRadioReceive(&GetInstance(), aScanChannel);
assert(error == OT_ERROR_NONE);
SetState(kStateEnergyScan);
mEnergyScanMaxRssi = kInvalidRssiValue;
mEnergyScanEndTime = TimerMilli::GetNow() + aScanDuration;
mTimer.Start(kEnergyScanRssiSampleInterval);
SampleRssi();
}
else
{
error = OT_ERROR_NOT_IMPLEMENTED;
}
exit:
return error;
}
void SubMac::SampleRssi(void)
{
int8_t rssi = GetRssi();
if (rssi != kInvalidRssiValue)
{
if ((mEnergyScanMaxRssi == kInvalidRssiValue) || (rssi > mEnergyScanMaxRssi))
{
mEnergyScanMaxRssi = rssi;
}
}
if (TimerMilliScheduler::IsStrictlyBefore(TimerMilli::GetNow(), mEnergyScanEndTime))
{
mTimer.StartAt(mTimer.GetFireTime(), kEnergyScanRssiSampleInterval);
}
else
{
HandleEnergyScanDone(mEnergyScanMaxRssi);
}
}
void SubMac::HandleEnergyScanDone(int8_t aMaxRssi)
{
SetState(kStateReceive);
mCallbacks.EnergyScanDone(aMaxRssi);
}
void SubMac::HandleTimer(Timer &aTimer)
{
aTimer.GetOwner<SubMac>().HandleTimer();
}
void SubMac::HandleTimer(void)
{
switch (mState)
{
case kStateCsmaBackoff:
BeginTransmit();
break;
case kStateTransmit:
otLogDebgMac("Ack timer timed out");
otPlatRadioReceive(&GetInstance(), mTransmitFrame.GetChannel());
HandleTransmitDone(mTransmitFrame, NULL, OT_ERROR_NO_ACK);
break;
case kStateEnergyScan:
SampleRssi();
break;
default:
break;
}
}
bool SubMac::ShouldHandleCsmaBackOff(void) const
{
bool swCsma = true;
VerifyOrExit(!RadioSupportsCsmaBackoff(), swCsma = false);
#if OPENTHREAD_ENABLE_RAW_LINK_API
VerifyOrExit(GetInstance().GetLinkRaw().IsEnabled());
#endif
#if OPENTHREAD_ENABLE_RAW_LINK_API || OPENTHREAD_RADIO
swCsma = OPENTHREAD_CONFIG_ENABLE_SOFTWARE_CSMA_BACKOFF;
#endif
exit:
return swCsma;
}
bool SubMac::ShouldHandleAckTimeout(void) const
{
bool swAckTimeout = true;
VerifyOrExit(!RadioSupportsAckTimeout(), swAckTimeout = false);
#if OPENTHREAD_ENABLE_RAW_LINK_API
VerifyOrExit(GetInstance().GetLinkRaw().IsEnabled());
#endif
#if OPENTHREAD_ENABLE_RAW_LINK_API || OPENTHREAD_RADIO
swAckTimeout = OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ACK_TIMEOUT;
#endif
exit:
return swAckTimeout;
}
bool SubMac::ShouldHandleRetries(void) const
{
bool swRetries = true;
VerifyOrExit(!RadioSupportsRetries(), swRetries = false);
#if OPENTHREAD_ENABLE_RAW_LINK_API
VerifyOrExit(GetInstance().GetLinkRaw().IsEnabled());
#endif
#if OPENTHREAD_ENABLE_RAW_LINK_API || OPENTHREAD_RADIO
swRetries = OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT;
#endif
exit:
return swRetries;
}
bool SubMac::ShouldHandleEnergyScan(void) const
{
bool swEnergyScan = true;
VerifyOrExit(!RadioSupportsEnergyScan(), swEnergyScan = false);
#if OPENTHREAD_ENABLE_RAW_LINK_API
VerifyOrExit(GetInstance().GetLinkRaw().IsEnabled());
#endif
#if OPENTHREAD_ENABLE_RAW_LINK_API || OPENTHREAD_RADIO
swEnergyScan = OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ENERGY_SCAN;
#endif
exit:
return swEnergyScan;
}
#if OPENTHREAD_CONFIG_HEADER_IE_SUPPORT
void SubMac::HandleFrameUpdated(Frame &aFrame)
{
mCallbacks.FrameUpdated(aFrame);
}
#endif
void SubMac::SetState(State aState)
{
if (mState != aState)
{
otLogDebgMac("RadioState: %s -> %s", StateToString(mState), StateToString(aState));
mState = aState;
}
}
const char *SubMac::StateToString(State aState)
{
const char *str = "Unknown";
switch (aState)
{
case kStateDisabled:
str = "Disabled";
break;
case kStateSleep:
str = "Sleep";
break;
case kStateReceive:
str = "Receive";
break;
case kStateCsmaBackoff:
str = "CsmaBackoff";
break;
case kStateTransmit:
str = "Transmit";
break;
case kStateEnergyScan:
str = "EnergyScan";
break;
}
return str;
}
//---------------------------------------------------------------------------------------------------------------------
// otPlatRadio callbacks
extern "C" void otPlatRadioReceiveDone(otInstance *aInstance, otRadioFrame *aFrame, otError aError)
{
Instance *instance = static_cast<Instance *>(aInstance);
if (instance->IsInitialized())
{
instance->Get<SubMac>().HandleReceiveDone(static_cast<Frame *>(aFrame), aError);
}
}
extern "C" void otPlatRadioTxStarted(otInstance *aInstance, otRadioFrame *aFrame)
{
Instance *instance = static_cast<Instance *>(aInstance);
if (instance->IsInitialized())
{
instance->Get<SubMac>().HandleTransmitStarted(*static_cast<Frame *>(aFrame));
}
}
extern "C" void otPlatRadioTxDone(otInstance *aInstance, otRadioFrame *aFrame, otRadioFrame *aAckFrame, otError aError)
{
Instance *instance = static_cast<Instance *>(aInstance);
if (instance->IsInitialized())
{
instance->Get<SubMac>().HandleTransmitDone(*static_cast<Frame *>(aFrame), static_cast<Frame *>(aAckFrame),
aError);
}
}
extern "C" void otPlatRadioEnergyScanDone(otInstance *aInstance, int8_t aEnergyScanMaxRssi)
{
Instance *instance = static_cast<Instance *>(aInstance);
if (instance->IsInitialized())
{
instance->Get<SubMac>().HandleEnergyScanDone(aEnergyScanMaxRssi);
}
}
#if OPENTHREAD_CONFIG_HEADER_IE_SUPPORT
extern "C" void otPlatRadioFrameUpdated(otInstance *aInstance, otRadioFrame *aFrame)
{
Instance *instance = static_cast<Instance *>(aInstance);
if (instance->IsInitialized())
{
instance->Get<SubMac>().HandleFrameUpdated(*static_cast<Frame *>(aFrame));
}
}
#endif
} // namespace Mac
} // namespace ot
+486
View File
@@ -0,0 +1,486 @@
/*
* Copyright (c) 2016-2018, 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.
*/
/**
* @file
* This file includes definitions for the IEEE 802.15.4 MAC layer (sub-MAC).
*/
#ifndef SUB_MAC_HPP_
#define SUB_MAC_HPP_
#include "openthread-core-config.h"
#include <openthread/link.h>
#include <openthread/platform/radio.h>
#include "common/locator.hpp"
#include "common/timer.hpp"
#include "mac/mac_frame.hpp"
namespace ot {
/**
* @addtogroup core-mac
*
* @brief
* This module includes definitions for the IEEE 802.15.4 MAC (sub-MAC).
*
* @{
*
*/
namespace Mac {
/**
* This class implements the IEEE 802.15.4 MAC (sub-MAC).
*
* Sub-MAC layer implements a subset of IEEE802.15.4 MAC primitives which are shared by both MAC layer (in FTD/MTD
* modes) and Raw Link (Radio only mode).
* The sub-MAC layer handles the following (if not provided by radio platform):
*
* - Ack timeout for frame transmission,
* - CSMA backoff logic,
* - Frame re-transmissions,
* - Energy scan on a single channel and RSSI sampling.
*
* It also act as the interface (to radio platform) for setting/getting radio configurations such as short or extended
* addresses and PAN Id.
*
*/
class SubMac : public InstanceLocator
{
public:
enum
{
kInvalidRssiValue = 127, ///< Invalid Received Signal Strength Indicator (RSSI) value.
};
/**
* This class defines the callbacks notifying `SubMac` user of changes and events.
*
*/
class Callbacks
{
friend class SubMac;
protected:
/**
* This method notifies user of `SubMac` of a received frame.
*
* @param[in] aFrame A pointer to the received frame or NULL if the receive operation failed.
* @param[in] aError OT_ERROR_NONE when successfully received a frame,
* OT_ERROR_ABORT when reception was aborted and a frame was not received,
* OT_ERROR_NO_BUFS when a frame could not be received due to lack of rx buffer space.
*
*/
void ReceiveDone(Frame *aFrame, otError aError);
/**
* This method notifies user of `SubMac` of CCA status (success/failure) for a frame transmission attempt.
*
* This is intended for updating counters, logging, and/or tracking CCA failure rate statistics.
*
* @param[in] aCcaSuccess TRUE if the CCA succeeded, FALSE otherwise.
* @param[in] aChannel The channel on which CCA was performed.
*
*/
void RecordCcaStatus(bool aCcaSuccess, uint8_t aChannel);
/**
* This method notifies user of `SubMac` of the status of a frame transmission attempt.
*
* This is intended for updating counters, logging, and/or collecting statistics.
*
* @note Unlike `TransmitDone` which is invoked after all re-transmission attempts to indicate the final status
* of a frame transmission, this method is invoked on all frame transmission attempts.
*
* @param[in] aFrame The transmitted frame.
* @param[in] aAckFrame A pointer to the ACK frame, or NULL if no ACK was received.
* @param[in] aError OT_ERROR_NONE when the frame was transmitted successfully,
* OT_ERROR_NO_ACK when the frame was transmitted but no ACK was received,
* OT_ERROR_CHANNEL_ACCESS_FAILURE tx failed due to activity on the channel,
* OT_ERROR_ABORT when transmission was aborted for other reasons.
* @param[in] aRetryCount Number of transmission retries for this frame.
* @param[in] aWillRetx Indicates whether frame will be retransmitted or not. This is applicable only
* when there was an error in current transmission attempt.
*
*/
void RecordFrameTransmitStatus(const Frame &aFrame,
const Frame *aAckFrame,
otError aError,
uint8_t aRetryCount,
bool aWillRetx);
/**
* The method notifies user of `SubMac` that the transmit operation has completed, providing, if applicable,
* the received ACK frame.
*
* @param[in] aFrame The transmitted frame.
* @param[in] aAckFrame A pointer to the ACK frame, NULL if no ACK was received.
* @param[in] aError OT_ERROR_NONE when the frame was transmitted,
* OT_ERROR_NO_ACK when the frame was transmitted but no ACK was received,
* OT_ERROR_CHANNEL_ACCESS_FAILURE tx failed due to activity on the channel,
* OT_ERROR_ABORT when transmission was aborted for other reasons.
*
*/
void TransmitDone(Frame &aFrame, Frame *aAckFrame, otError aError);
/**
* This method notifies user of `SubMac` that energy sfcan is complete.
*
* @param[in] aMaxRssi Maximum RSSI seen on the channel, or `SubMac::kInvalidRssiValue` if failed.
*
*/
void EnergyScanDone(int8_t aMaxRssi);
#if OPENTHREAD_CONFIG_HEADER_IE_SUPPORT
/**
* The method notifies user of `SubMac` to process transmit security for the frame, which happens when the
* frame includes Header IE(s) that were updated before transmission.
*
* @note This function can be called from interrupt context and it would only read/write data passed in
* via @p aFrame, but would not read/write any state within OpenThread.
*
* @param[in] aFrame The frame which needs to process transmit security.
*
*/
void FrameUpdated(Frame &aFrame);
#endif
/**
* This constructor initializes the `Callbacks` object.
*
*/
Callbacks(void) {}
};
/**
* This constructor initializes the `SubMac` object.
*
* @param[in] aInstance A reference to the OpenThread instance.
* @param[in] aCallbacks A reference to the `Callbacks` object.
*
*/
SubMac(Instance &aInstance, Callbacks &aCallbacks);
/**
* This method gets the capabilities provided by platform radio.
*
* @returns The capability bit vector (see `OT_RADIO_CAP_*` definitions).
*
*/
otRadioCaps GetRadioCaps(void) const { return mRadioCaps; }
/**
* This method gets the capabilities provided by `SubMac` layer.
*
* @returns The capability bit vector (see `OT_RADIO_CAP_*` definitions).
*
*/
otRadioCaps GetCaps(void) const;
/**
* This method sets the PAN ID.
*
* @param[in] aPanId The PAN ID.
*
*/
void SetPanId(PanId aPanId);
/**
* This method gets the short address.
*
* @returns The short address.
*
*/
ShortAddress GetShortAddress(void) const { return mShortAddress; }
/**
* This method sets the short address.
*
* @param[in] aShortAddress The short address.
*
*/
void SetShortAddress(ShortAddress aShortAddress);
/**
* This function gets the extended address.
*
* @returns A reference to the extended address.
*
*/
const ExtAddress &GetExtAddress(void) const { return mExtAddress; }
/**
* This method sets extended address.
*
* @param[in] aExtAddress The extended address.
*
*/
void SetExtAddress(const ExtAddress &aExtAddress);
/**
* This method registers a callback to provide received packet capture for IEEE 802.15.4 frames.
*
* @param[in] aPcapCallback A pointer to a function that is called when receiving an IEEE 802.15.4 link frame
* or NULL to disable the callback.
* @param[in] aCallbackContext A pointer to application-specific context.
*
*/
void SetPcapCallback(otLinkPcapCallback aPcapCallback, void *aCallbackContext);
/**
* This method indicates whether radio should stay in Receive or Sleep during CSMA backoff.
*
* @param[in] aRxOnWhenBackoff TRUE to keep radio in Receive, FALSE to put to Sleep during CSMA backoff.
*
*/
void SetRxOnWhenBackoff(bool aRxOnWhenBackoff) { mRxOnWhenBackoff = aRxOnWhenBackoff; }
/**
* This method enables the radio.
*
* @retval OT_ERROR_NONE Successfully enabled.
* @retval OT_ERROR_FAILED The radio could not be enabled.
*
*/
otError Enable(void);
/**
* This method disables the radio.
*
* @retval OT_ERROR_NONE Successfully disabled the radio.
*
*/
otError Disable(void);
/**
* This method transitions the radio to Sleep.
*
* @retval OT_ERROR_NONE Successfully transitioned to Sleep.
* @retval OT_ERROR_BUSY The radio was transmitting.
* @retval OT_ERROR_INVALID_STATE The radio was disabled.
*
*/
otError Sleep(void);
/**
* This method transitions the radio to Receive.
*
* @param[in] aChannel The channel to use for receiving.
*
* @retval OT_ERROR_NONE Successfully transitioned to Receive.
* @retval OT_ERROR_INVALID_STATE The radio was disabled or transmitting.
*
*/
otError Receive(uint8_t aChannel);
/**
* This method gets the radio transmit frame.
*
* @returns The transmit frame.
*
*/
Frame &GetTransmitFrame(void) { return mTransmitFrame; }
/**
* This method sends a prepared frame.
*
* The frame should be placed in `GetTransmitFrame()` frame.
*
* The `SubMac` layer handles Ack timeout, CSMA backoff, and frame retransmission.
*
* @retval OT_ERROR_NONE Successfully started the frame transmission
* @retval OT_ERROR_INVALID_STATE The radio was disabled or transmitting.
*
*/
otError Send(void);
/**
* This method gets the most recent RSSI measurement.
*
* @returns The RSSI in dBm when it is valid. `kInvalidRssiValue` when RSSI is invalid.
*
*/
int8_t GetRssi(void) const;
/**
* This method begins energy scan.
*
* @param[in] aScanChannel The channel to perform the energy scan on.
* @param[in] aScanDuration The duration, in milliseconds, for the channel to be scanned.
*
* @retval OT_ERROR_NONE Successfully started scanning the channel.
* @retval OT_ERROR_INVALID_STATE The radio was disabled or transmitting.
* @retval OT_ERROR_NOT_IMPLEMENTED Energy scan is not supported (applicable in link-raw/radio mode only).
*
*/
otError EnergyScan(uint8_t aScanChannel, uint16_t aScanDuration);
/**
* This method handles a "Receive Done" event from radio platform.
*
*
* @param[in] aFrame A pointer to the received frame or NULL if the receive operation failed.
* @param[in] aError OT_ERROR_NONE when successfully received a frame,
* OT_ERROR_ABORT when reception was aborted and a frame was not received,
* OT_ERROR_NO_BUFS when a frame could not be received due to lack of rx buffer space.
*
*/
void HandleReceiveDone(Frame *aFrame, otError aError);
/**
* This method handles a Transmit Started event from radio platform.
*
* @param[in] aFrame The frame that is being transmitted.
*
*/
void HandleTransmitStarted(Frame &aFrame);
/**
* This method handles a "Transmit Done" event from radio platform.
*
* @param[in] aFrame The frame that was transmitted.
* @param[in] aAckFrame A pointer to the ACK frame, NULL if no ACK was received.
* @param[in] aError OT_ERROR_NONE when the frame was transmitted,
* OT_ERROR_NO_ACK when the frame was transmitted but no ACK was received,
* OT_ERROR_CHANNEL_ACCESS_FAILURE tx could not take place due to activity on the channel,
* OT_ERROR_ABORT when transmission was aborted for other reasons.
*
*/
void HandleTransmitDone(Frame &aFrame, Frame *aAckFrame, otError aError);
/**
* This method handles "Energy Scan Done" event from radio platform.
*
* This method is used when radio provides OT_RADIO_CAPS_ENERGY_SCAN capability. It is called from
* `otPlatRadioEnergyScanDone()`.
*
* @param[in] aInstance The OpenThread instance structure.
* @param[in] aEnergyScanMaxRssi The maximum RSSI encountered on the scanned channel.
*
*/
void HandleEnergyScanDone(int8_t aMaxRssi);
#if OPENTHREAD_CONFIG_HEADER_IE_SUPPORT
/**
* This method handles a "Frame Updated" event from radio platform.
*
* This is called to notify OpenThread to process transmit security for the frame, this happens when the frame
* includes Header IE(s) that were updated before transmission. It is called from `otPlatRadioFrameUpdated()`.
*
* @note This method can be called from interrupt context and it would only read/write data passed in
* via @p aFrame, but would not read/write any state within OpenThread.
*
* @param[in] aFrame The frame which needs to process transmit security.
*
*/
void HandleFrameUpdated(Frame &aFrame);
#endif
private:
enum
{
kMinBE = 3, ///< macMinBE (IEEE 802.15.4-2006).
kMaxBE = 5, ///< macMaxBE (IEEE 802.15.4-2006).
kUnitBackoffPeriod = 20, ///< Number of symbols (IEEE 802.15.4-2006).
kMinBackoff = 1, ///< Minimum backoff (milliseconds).
kAckTimeout = 16, ///< Timeout for waiting on an ACK (milliseconds).
#if OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_TIMER
kEnergyScanRssiSampleInterval = 128, ///< RSSI sample interval during energy scan, 128 usec
#else
kEnergyScanRssiSampleInterval = 1, ///< RSSI sample interval during energy scan, 1 ms
#endif
};
enum State
{
kStateDisabled, ///< Radio is disabled.
kStateSleep, ///< Radio is in sleep.
kStateReceive, ///< Radio in in receive.
kStateCsmaBackoff, ///< CSMA backoff before transmission.
kStateTransmit, ///< Radio is transmitting.
kStateEnergyScan, ///< Energy scan.
};
bool RadioSupportsCsmaBackoff(void) const
{
return ((mRadioCaps & (OT_RADIO_CAPS_CSMA_BACKOFF | OT_RADIO_CAPS_TRANSMIT_RETRIES)) != 0);
}
bool RadioSupportsRetries(void) const { return ((mRadioCaps & OT_RADIO_CAPS_TRANSMIT_RETRIES) != 0); }
bool RadioSupportsAckTimeout(void) const { return ((mRadioCaps & OT_RADIO_CAPS_ACK_TIMEOUT) != 0); }
bool RadioSupportsEnergyScan(void) const { return ((mRadioCaps & OT_RADIO_CAPS_ENERGY_SCAN) != 0); }
bool ShouldHandleCsmaBackOff(void) const;
bool ShouldHandleAckTimeout(void) const;
bool ShouldHandleRetries(void) const;
bool ShouldHandleEnergyScan(void) const;
void StartCsmaBackoff(void);
void BeginTransmit(void);
void SampleRssi(void);
static void HandleTimer(Timer &aTimer);
void HandleTimer(void);
void SetState(State aState);
static const char *StateToString(State aState);
otRadioCaps mRadioCaps;
State mState;
uint8_t mCsmaBackoffs;
uint8_t mTransmitRetries;
ShortAddress mShortAddress;
ExtAddress mExtAddress;
bool mRxOnWhenBackoff;
int8_t mEnergyScanMaxRssi;
uint32_t mEnergyScanEndTime;
Frame & mTransmitFrame;
Callbacks & mCallbacks;
otLinkPcapCallback mPcapCallback;
void * mPcapCallbackContext;
#if OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_TIMER
TimerMicro mTimer;
#else
TimerMilli mTimer;
#endif
};
/**
* @}
*
*/
} // namespace Mac
} // namespace ot
#endif // SUB_MAC_HPP_
+176
View File
@@ -0,0 +1,176 @@
/*
* Copyright (c) 2016-2018, 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.
*/
/**
* @file
* This file implements the callbacks from `SubMac` layer into `Mac` or `LinkRaw`.
*/
#define WPP_NAME "sub_mac_callbacks.tmh"
#include "sub_mac.hpp"
#include "common/code_utils.hpp"
#include "common/instance.hpp"
#include "mac/mac.hpp"
namespace ot {
namespace Mac {
#if OPENTHREAD_FTD || OPENTHREAD_MTD
void SubMac::Callbacks::ReceiveDone(Frame *aFrame, otError aError)
{
Mac &mac = *static_cast<Mac *>(this);
#if OPENTHREAD_ENABLE_RAW_LINK_API
LinkRaw &linkRaw = mac.GetInstance().GetLinkRaw();
if (linkRaw.IsEnabled())
{
linkRaw.InvokeReceiveDone(aFrame, aError);
}
else
#endif
{
mac.HandleReceivedFrame(aFrame, aError);
}
}
void SubMac::Callbacks::RecordCcaStatus(bool aCcaSuccess, uint8_t aChannel)
{
static_cast<Mac *>(this)->RecordCcaStatus(aCcaSuccess, aChannel);
}
void SubMac::Callbacks::RecordFrameTransmitStatus(const Frame &aFrame,
const Frame *aAckFrame,
otError aError,
uint8_t aRetryCount,
bool aWillRetx)
{
static_cast<Mac *>(this)->RecordFrameTransmitStatus(aFrame, aAckFrame, aError, aRetryCount, aWillRetx);
}
void SubMac::Callbacks::TransmitDone(Frame &aFrame, Frame *aAckFrame, otError aError)
{
Mac &mac = *static_cast<Mac *>(this);
#if OPENTHREAD_ENABLE_RAW_LINK_API
LinkRaw &linkRaw = mac.GetInstance().GetLinkRaw();
if (linkRaw.IsEnabled())
{
linkRaw.InvokeTransmitDone(aFrame, aAckFrame, aError);
}
else
#endif
{
mac.HandleTransmitDone(aFrame, aAckFrame, aError);
}
}
void SubMac::Callbacks::EnergyScanDone(int8_t aMaxRssi)
{
Mac &mac = *static_cast<Mac *>(this);
#if OPENTHREAD_ENABLE_RAW_LINK_API
LinkRaw &linkRaw = mac.GetInstance().GetLinkRaw();
if (linkRaw.IsEnabled())
{
linkRaw.InvokeEnergyScanDone(aMaxRssi);
}
else
#endif
{
mac.EnergyScanDone(aMaxRssi);
}
}
#if OPENTHREAD_CONFIG_HEADER_IE_SUPPORT
void SubMac::Callbacks::FrameUpdated(Frame &aFrame)
{
/**
* This function will be called from interrupt context, it should only read/write data passed in
* via @p aFrame, but should not read/write any state within OpenThread.
*
*/
Mac &mac = *static_cast<Mac *>(this);
if (aFrame.GetSecurityEnabled())
{
const ExtAddress &extAddress = mac.GetExtAddress();
mac.ProcessTransmitAesCcm(aFrame, &extAddress);
}
}
#endif
#elif OPENTHREAD_RADIO
void SubMac::Callbacks::ReceiveDone(Frame *aFrame, otError aError)
{
static_cast<LinkRaw *>(this)->InvokeReceiveDone(aFrame, aError);
}
void SubMac::Callbacks::RecordCcaStatus(bool, uint8_t)
{
}
void SubMac::Callbacks::RecordFrameTransmitStatus(const Frame &, const Frame *, otError, uint8_t, bool)
{
}
void SubMac::Callbacks::TransmitDone(Frame &aFrame, Frame *aAckFrame, otError aError)
{
static_cast<LinkRaw *>(this)->InvokeTransmitDone(aFrame, aAckFrame, aError);
}
void SubMac::Callbacks::EnergyScanDone(int8_t aMaxRssi)
{
static_cast<LinkRaw *>(this)->InvokeEnergyScanDone(aMaxRssi);
}
#if OPENTHREAD_CONFIG_HEADER_IE_SUPPORT
void SubMac::Callbacks::FrameUpdated(Frame &)
{
/**
* This function will be called from interrupt context, it should only read/write data passed in
* via @p aFrame, but should not read/write any state within OpenThread.
*
*/
// For now this functionality is not supported in Radio Only mode.
}
#endif
#endif // OPENTHREAD_RADIO
} // namespace Mac
} // namespace ot