mirror of
https://github.com/espressif/openthread.git
synced 2026-09-18 15:10:12 +00:00
[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:
committed by
Jonathan Hui
parent
5d6dccf35c
commit
8d12513591
@@ -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 \
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+78
-98
@@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user