diff --git a/examples/Makefile-cc2538 b/examples/Makefile-cc2538 index 61de9df0e..22571d2e4 100644 --- a/examples/Makefile-cc2538 +++ b/examples/Makefile-cc2538 @@ -70,11 +70,19 @@ ifeq ($(DHCP6_CLIENT),1) configure_OPTIONS += --enable-dhcp6-client endif +TopSourceDir := $(dir $(shell readlink $(firstword $(MAKEFILE_LIST)))).. +AbsTopSourceDir := $(dir $(realpath $(firstword $(MAKEFILE_LIST)))).. + +CONFIG_FILE = OPENTHREAD_PROJECT_CORE_CONFIG_FILE='\"openthread-core-cc2538-config.h\"' +CONFIG_FILE_PATH = $(AbsTopSourceDir)/examples/platforms/cc2538/ + COMMONCFLAGS := \ -fdata-sections \ -ffunction-sections \ -Os \ -g \ + -D$(CONFIG_FILE) \ + -I$(CONFIG_FILE_PATH) \ $(NULL) CPPFLAGS += \ @@ -113,9 +121,6 @@ RM_F := rm -f INSTALL := /usr/bin/install INSTALLFLAGS := -p -TopSourceDir := $(dir $(shell readlink $(firstword $(MAKEFILE_LIST)))).. -AbsTopSourceDir := $(dir $(realpath $(firstword $(MAKEFILE_LIST)))).. - BuildPath = build TopBuildDir = $(BuildPath) AbsTopBuildDir = $(PWD)/$(TopBuildDir) diff --git a/examples/Makefile-da15000 b/examples/Makefile-da15000 index 7dc660f20..2ccbb95ca 100644 --- a/examples/Makefile-da15000 +++ b/examples/Makefile-da15000 @@ -69,11 +69,19 @@ ifeq ($(DHCP6_CLIENT),1) configure_OPTIONS += --enable-dhcp6-client endif +TopSourceDir := $(dir $(shell readlink $(firstword $(MAKEFILE_LIST)))).. +AbsTopSourceDir := $(dir $(realpath $(firstword $(MAKEFILE_LIST)))).. + +CONFIG_FILE = OPENTHREAD_PROJECT_CORE_CONFIG_FILE='\"openthread-core-da15000-config.h\"' +CONFIG_FILE_PATH = $(AbsTopSourceDir)/examples/platforms/da15000/ + COMMONCFLAGS := \ -fdata-sections \ -ffunction-sections \ -Os \ -g \ + -D$(CONFIG_FILE) \ + -I$(CONFIG_FILE_PATH) \ $(NULL) CPPFLAGS += \ @@ -112,9 +120,6 @@ RM_F := rm -f INSTALL := /usr/bin/install INSTALLFLAGS := -p -TopSourceDir := $(dir $(shell readlink $(firstword $(MAKEFILE_LIST)))).. -AbsTopSourceDir := $(dir $(realpath $(firstword $(MAKEFILE_LIST)))).. - BuildPath = build TopBuildDir = $(BuildPath) AbsTopBuildDir = $(PWD)/$(TopBuildDir) diff --git a/examples/Makefile-posix b/examples/Makefile-posix index 109544bb4..f148bc33e 100644 --- a/examples/Makefile-posix +++ b/examples/Makefile-posix @@ -85,6 +85,7 @@ configure_OPTIONS = \ --enable-cli \ --enable-ncp \ --enable-diag \ + --enable-raw-link-api=no \ --with-examples=posix \ --with-platform-info=POSIX \ --enable-commissioner \ diff --git a/examples/platforms/cc2538/openthread-core-cc2538-config.h b/examples/platforms/cc2538/openthread-core-cc2538-config.h new file mode 100644 index 000000000..0ad985ce7 --- /dev/null +++ b/examples/platforms/cc2538/openthread-core-cc2538-config.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2016, 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 cc2538 compile-time configuration constants for OpenThread. + */ + +#ifndef OPENTHREAD_CORE_CC2538_CONFIG_H_ +#define OPENTHREAD_CORE_CC2538_CONFIG_H_ + + /** + * @def OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ACK_TIMEOUT + * + * Define to 1 if you want to enable software ACK timeout logic. + * + */ +#define OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ACK_TIMEOUT 1 + + /** + * @def OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT + * + * Define to 1 if you want to enable software retransmission logic. + * + */ +#define OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT 1 + + /** + * @def OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ENERGY_SCAN + * + * Define to 1 if you want to enable software energy scanning logic. + * + */ +#define OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ENERGY_SCAN 1 + +#endif // OPENTHREAD_CORE_CC2538_CONFIG_H_ diff --git a/examples/platforms/da15000/openthread-core-da15000-config.h b/examples/platforms/da15000/openthread-core-da15000-config.h new file mode 100644 index 000000000..8aa8ca69d --- /dev/null +++ b/examples/platforms/da15000/openthread-core-da15000-config.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2016, 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 DA15000 compile-time configuration constants for OpenThread. + */ + +#ifndef OPENTHREAD_CORE_DA15000_CONFIG_H_ +#define OPENTHREAD_CORE_DA15000_CONFIG_H_ + + /** + * @def OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ACK_TIMEOUT + * + * Define to 1 if you want to enable software ACK timeout logic. + * + */ +#define OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ACK_TIMEOUT 1 + + /** + * @def OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT + * + * Define to 1 if you want to enable software retransmission logic. + * + */ +#define OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT 1 + + /** + * @def OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ENERGY_SCAN + * + * Define to 1 if you want to enable software energy scanning logic. + * + */ +#define OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ENERGY_SCAN 1 + +#endif // OPENTHREAD_CORE_DA15000_CONFIG_H_ diff --git a/examples/platforms/nrf52840/openthread-core-nrf52840-config.h b/examples/platforms/nrf52840/openthread-core-nrf52840-config.h index c60d21463..8986ac122 100644 --- a/examples/platforms/nrf52840/openthread-core-nrf52840-config.h +++ b/examples/platforms/nrf52840/openthread-core-nrf52840-config.h @@ -67,6 +67,22 @@ */ #define OPENTHREAD_CONFIG_LOG_PREPEND_LEVEL 0 + /** + * @def OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ACK_TIMEOUT + * + * Define to 1 if you want to enable software ACK timeout logic. + * + */ +#define OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ACK_TIMEOUT 1 + + /** + * @def OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT + * + * Define to 1 if you want to enable software retransmission logic. + * + */ +#define OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT 1 + /** * @def SETTINGS_CONFIG_BASE_ADDRESS * @@ -91,4 +107,4 @@ */ #define SETTINGS_CONFIG_PAGE_NUM 4 -#endif // OPENTHREAD_CORE_WINDOWS_CONFIG_H_ +#endif // OPENTHREAD_CORE_NRF52840_CONFIG_H_ diff --git a/src/core/Makefile.am b/src/core/Makefile.am index 456cab8a8..eb8ab0590 100644 --- a/src/core/Makefile.am +++ b/src/core/Makefile.am @@ -167,6 +167,7 @@ noinst_HEADERS = \ openthread-core-config.h \ openthread-core-default-config.h \ openthread-instance.h \ + api/link_raw.hpp \ coap/coap_base.hpp \ coap/coap_client.hpp \ coap/coap_header.hpp \ diff --git a/src/core/api/link_raw.hpp b/src/core/api/link_raw.hpp new file mode 100644 index 000000000..bcebed663 --- /dev/null +++ b/src/core/api/link_raw.hpp @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2016, 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 Raw Link-Layer class. + */ + +#ifndef LINK_RAW_HPP_ +#define LINK_RAW_HPP_ + +#include +#include "openthread/link_raw.h" + +#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ACK_TIMEOUT || OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT || OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ENERGY_SCAN +#define OPENTHREAD_LINKRAW_TIMER_REQUIRED 1 +#else +#define OPENTHREAD_LINKRAW_TIMER_REQUIRED 0 +#endif + +namespace Thread { + +class LinkRaw +{ +public: + /** + * This constructor initializes the object. + * + */ + LinkRaw(otInstance &aInstance); + + /** + * This method returns true if the raw link-layer is enabled. + * + */ + bool IsEnabled() { return mEnabled; } + + /** + * This method enables/disables the raw link-layer. + * + */ + void SetEnabled(bool aEnabled) { mEnabled = aEnabled; } + + /** + * This method returns the capabilities of the raw link-layer. + * + */ + otRadioCaps GetCaps(); + + /** + * This method starts a (recurring) Receive on the link-layer. + * + */ + ThreadError Receive(uint8_t aChannel, otLinkRawReceiveDone aCallback); + + /** + * This method invokes the mReceiveDoneCallback, if set. + * + */ + void InvokeReceiveDone(RadioPacket *aPacket, ThreadError aError); + + /** + * This method starts a (single) Transmit on the link-layer. + * + */ + ThreadError Transmit(RadioPacket *aPacket, otLinkRawTransmitDone aCallback); + + /** + * This method invokes the mTransmitDoneCallback, if set. + * + */ + void InvokeTransmitDone(RadioPacket *aPacket, bool aFramePending, ThreadError aError); + + /** + * This method starts a (single) Enery Scan on the link-layer. + * + */ + ThreadError EnergyScan(uint8_t aScanChannel, uint16_t aScanDuration, otLinkRawEnergyScanDone aCallback); + + /** + * This method invokes the mEnergyScanDoneCallback, if set. + * + */ + void InvokeEnergyScanDone(int8_t aEnergyScanMaxRssi); + +private: + + otInstance &mInstance; + bool mEnabled; + otLinkRawReceiveDone mReceiveDoneCallback; + otLinkRawTransmitDone mTransmitDoneCallback; + otLinkRawEnergyScanDone mEnergyScanDoneCallback; + + ThreadError DoTransmit(RadioPacket *aPacket); + +#if OPENTHREAD_LINKRAW_TIMER_REQUIRED + + enum TimerReason + { + kTimerReasonNone, + kTimerReasonAckTimeout, + kTimerReasonRetransmitTimeout, + kTimerReasonEnergyScanComplete, + }; + + Timer mTimer; + TimerReason mTimerReason; + uint8_t mReceiveChannel; + + static void HandleTimer(void *aContext); + void HandleTimer(void); + +#endif // OPENTHREAD_LINKRAW_TIMER_REQUIRED + +#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT + + uint8_t mTransmitAttempts; + uint8_t mCsmaAttempts; + + void StartCsmaBackoff(void); + +#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT + +#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ENERGY_SCAN + + enum + { + kInvalidRssiValue = 127 + }; + + Tasklet mEnergyScanTask; + int8_t mEnergyScanRssi; + + static void HandleEnergyScanTask(void *aContext); + void HandleEnergyScanTask(void); + +#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ENERGY_SCAN +}; + +} // namespace Thread + +#endif // LINK_RAW_HPP_ diff --git a/src/core/api/link_raw_api.cpp b/src/core/api/link_raw_api.cpp index abd58bdbc..8b87b81fd 100644 --- a/src/core/api/link_raw_api.cpp +++ b/src/core/api/link_raw_api.cpp @@ -31,6 +31,8 @@ * This file implements blacklist IEEE 802.15.4 frame filtering based on MAC address. */ +#include +#include #include "openthread-instance.h" #ifdef __cplusplus @@ -43,7 +45,7 @@ ThreadError otLinkRawSetEnable(otInstance *aInstance, bool aEnabled) VerifyOrExit(!aInstance->mThreadNetif.IsUp(), error = kThreadError_InvalidState); - aInstance->mLinkRawEnabled = aEnabled; + aInstance->mLinkRaw.SetEnabled(aEnabled); exit: return error; @@ -51,14 +53,14 @@ exit: bool otLinkRawIsEnabled(otInstance *aInstance) { - return aInstance->mLinkRawEnabled; + return aInstance->mLinkRaw.IsEnabled(); } ThreadError otLinkRawSetPanId(otInstance *aInstance, uint16_t aPanId) { ThreadError error = kThreadError_None; - VerifyOrExit(aInstance->mLinkRawEnabled, error = kThreadError_InvalidState); + VerifyOrExit(aInstance->mLinkRaw.IsEnabled(), error = kThreadError_InvalidState); otPlatRadioSetPanId(aInstance, aPanId); @@ -71,7 +73,7 @@ ThreadError otLinkRawSetExtendedAddress(otInstance *aInstance, const otExtAddres ThreadError error = kThreadError_None; uint8_t buf[sizeof(otExtAddress)]; - VerifyOrExit(aInstance->mLinkRawEnabled, error = kThreadError_InvalidState); + VerifyOrExit(aInstance->mLinkRaw.IsEnabled(), error = kThreadError_InvalidState); for (size_t i = 0; i < sizeof(buf); i++) { @@ -88,7 +90,7 @@ ThreadError otLinkRawSetShortAddress(otInstance *aInstance, uint16_t aShortAddre { ThreadError error = kThreadError_None; - VerifyOrExit(aInstance->mLinkRawEnabled, error = kThreadError_InvalidState); + VerifyOrExit(aInstance->mLinkRaw.IsEnabled(), error = kThreadError_InvalidState); otPlatRadioSetShortAddress(aInstance, aShortAddress); @@ -105,7 +107,7 @@ ThreadError otLinkRawSetPromiscuous(otInstance *aInstance, bool aEnable) { ThreadError error = kThreadError_None; - VerifyOrExit(aInstance->mLinkRawEnabled, error = kThreadError_InvalidState); + VerifyOrExit(aInstance->mLinkRaw.IsEnabled(), error = kThreadError_InvalidState); otPlatRadioSetPromiscuous(aInstance, aEnable); @@ -117,7 +119,7 @@ ThreadError otLinkRawSleep(otInstance *aInstance) { ThreadError error = kThreadError_None; - VerifyOrExit(aInstance->mLinkRawEnabled, error = kThreadError_InvalidState); + VerifyOrExit(aInstance->mLinkRaw.IsEnabled(), error = kThreadError_InvalidState); error = otPlatRadioSleep(aInstance); @@ -127,23 +129,14 @@ exit: ThreadError otLinkRawReceive(otInstance *aInstance, uint8_t aChannel, otLinkRawReceiveDone aCallback) { - ThreadError error = kThreadError_None; - - VerifyOrExit(aInstance->mLinkRawEnabled, error = kThreadError_InvalidState); - - aInstance->mLinkRawReceiveDoneCallback = aCallback; - - error = otPlatRadioReceive(aInstance, aChannel); - -exit: - return error; + return aInstance->mLinkRaw.Receive(aChannel, aCallback); } RadioPacket *otLinkRawGetTransmitBuffer(otInstance *aInstance) { RadioPacket *buffer = NULL; - VerifyOrExit(aInstance->mLinkRawEnabled,); + VerifyOrExit(aInstance->mLinkRaw.IsEnabled(),); buffer = otPlatRadioGetTransmitBuffer(aInstance); @@ -153,16 +146,7 @@ exit: ThreadError otLinkRawTransmit(otInstance *aInstance, RadioPacket *aPacket, otLinkRawTransmitDone aCallback) { - ThreadError error = kThreadError_None; - - VerifyOrExit(aInstance->mLinkRawEnabled, error = kThreadError_InvalidState); - - aInstance->mLinkRawTransmitDoneCallback = aCallback; - - error = otPlatRadioTransmit(aInstance, aPacket); - -exit: - return error; + return aInstance->mLinkRaw.Transmit(aPacket, aCallback); } int8_t otLinkRawGetRssi(otInstance *aInstance) @@ -172,29 +156,20 @@ int8_t otLinkRawGetRssi(otInstance *aInstance) otRadioCaps otLinkRawGetCaps(otInstance *aInstance) { - return otPlatRadioGetCaps(aInstance); + return aInstance->mLinkRaw.GetCaps(); } ThreadError otLinkRawEnergyScan(otInstance *aInstance, uint8_t aScanChannel, uint16_t aScanDuration, otLinkRawEnergyScanDone aCallback) { - ThreadError error = kThreadError_None; - - VerifyOrExit(aInstance->mLinkRawEnabled, error = kThreadError_InvalidState); - - aInstance->mLinkRawEnergyScanDoneCallback = aCallback; - - error = otPlatRadioEnergyScan(aInstance, aScanChannel, aScanDuration); - -exit: - return error; + return aInstance->mLinkRaw.EnergyScan(aScanChannel, aScanDuration, aCallback); } ThreadError otLinkRawSrcMatchEnable(otInstance *aInstance, bool aEnable) { ThreadError error = kThreadError_None; - VerifyOrExit(aInstance->mLinkRawEnabled, error = kThreadError_InvalidState); + VerifyOrExit(aInstance->mLinkRaw.IsEnabled(), error = kThreadError_InvalidState); otPlatRadioEnableSrcMatch(aInstance, aEnable); @@ -206,7 +181,7 @@ ThreadError otLinkRawSrcMatchAddShortEntry(otInstance *aInstance, const uint16_t { ThreadError error = kThreadError_None; - VerifyOrExit(aInstance->mLinkRawEnabled, error = kThreadError_InvalidState); + VerifyOrExit(aInstance->mLinkRaw.IsEnabled(), error = kThreadError_InvalidState); error = otPlatRadioAddSrcMatchShortEntry(aInstance, aShortAddress); @@ -218,7 +193,7 @@ ThreadError otLinkRawSrcMatchAddExtEntry(otInstance *aInstance, const uint8_t *a { ThreadError error = kThreadError_None; - VerifyOrExit(aInstance->mLinkRawEnabled, error = kThreadError_InvalidState); + VerifyOrExit(aInstance->mLinkRaw.IsEnabled(), error = kThreadError_InvalidState); error = otPlatRadioAddSrcMatchExtEntry(aInstance, aExtAddress); @@ -230,7 +205,7 @@ ThreadError otLinkRawSrcMatchClearShortEntry(otInstance *aInstance, const uint16 { ThreadError error = kThreadError_None; - VerifyOrExit(aInstance->mLinkRawEnabled, error = kThreadError_InvalidState); + VerifyOrExit(aInstance->mLinkRaw.IsEnabled(), error = kThreadError_InvalidState); error = otPlatRadioClearSrcMatchShortEntry(aInstance, aShortAddress); @@ -242,7 +217,7 @@ ThreadError otLinkRawSrcMatchClearExtEntry(otInstance *aInstance, const uint8_t { ThreadError error = kThreadError_None; - VerifyOrExit(aInstance->mLinkRawEnabled, error = kThreadError_InvalidState); + VerifyOrExit(aInstance->mLinkRaw.IsEnabled(), error = kThreadError_InvalidState); error = otPlatRadioClearSrcMatchExtEntry(aInstance, aExtAddress); @@ -254,7 +229,7 @@ ThreadError otLinkRawSrcMatchClearShortEntries(otInstance *aInstance) { ThreadError error = kThreadError_None; - VerifyOrExit(aInstance->mLinkRawEnabled, error = kThreadError_InvalidState); + VerifyOrExit(aInstance->mLinkRaw.IsEnabled(), error = kThreadError_InvalidState); otPlatRadioClearSrcMatchShortEntries(aInstance); @@ -266,7 +241,7 @@ ThreadError otLinkRawSrcMatchClearExtEntries(otInstance *aInstance) { ThreadError error = kThreadError_None; - VerifyOrExit(aInstance->mLinkRawEnabled, error = kThreadError_InvalidState); + VerifyOrExit(aInstance->mLinkRaw.IsEnabled(), error = kThreadError_InvalidState); otPlatRadioClearSrcMatchExtEntries(aInstance); @@ -277,3 +252,316 @@ exit: #ifdef __cplusplus } // extern "C" #endif + +namespace Thread { + +LinkRaw::LinkRaw(otInstance &aInstance): + mInstance(aInstance), + mEnabled(false), + mReceiveDoneCallback(NULL), + mTransmitDoneCallback(NULL), + mEnergyScanDoneCallback(NULL) +#if OPENTHREAD_LINKRAW_TIMER_REQUIRED + , mTimer(aInstance.mIp6.mTimerScheduler, &LinkRaw::HandleTimer, this) + , mTimerReason(kTimerReasonNone) + , mReceiveChannel(OPENTHREAD_CONFIG_DEFAULT_CHANNEL) +#endif // OPENTHREAD_LINKRAW_TIMER_REQUIRED +#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ENERGY_SCAN + , mEnergyScanTask(aInstance.mIp6.mTaskletScheduler, &LinkRaw::HandleEnergyScanTask, this) +#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ENERGY_SCAN +{ + // Query the capabilities to check asserts + (void)GetCaps(); +} + +otRadioCaps LinkRaw::GetCaps() +{ + otRadioCaps RadioCaps = otPlatRadioGetCaps(&mInstance); + + // The radio shouldn't support a capability if it is being compile + // time included into the raw link-layer code. + +#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ACK_TIMEOUT + assert((RadioCaps & kRadioCapsAckTimeout) == 0); + RadioCaps = (otRadioCaps)(RadioCaps | kRadioCapsAckTimeout); +#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ACK_TIMEOUT + +#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT + assert((RadioCaps & kRadioCapsTransmitRetries) == 0); + RadioCaps = (otRadioCaps)(RadioCaps | kRadioCapsTransmitRetries); +#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT + +#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ENERGY_SCAN + assert((RadioCaps & kRadioCapsEnergyScan) == 0); + RadioCaps = (otRadioCaps)(RadioCaps | kRadioCapsEnergyScan); +#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ENERGY_SCAN + + return RadioCaps; +} + +ThreadError LinkRaw::Receive(uint8_t aChannel, otLinkRawReceiveDone aCallback) +{ + ThreadError error = kThreadError_InvalidState; + + if (mEnabled) + { +#if OPENTHREAD_LINKRAW_TIMER_REQUIRED + // Only need to cache if we implement timer logic that might + // revert the channel on completion. + mReceiveChannel = aChannel; +#endif + + mReceiveDoneCallback = aCallback; + error = otPlatRadioReceive(&mInstance, aChannel); + } + + return error; +} + +void LinkRaw::InvokeReceiveDone(RadioPacket *aPacket, ThreadError aError) +{ + if (mReceiveDoneCallback) + { + mReceiveDoneCallback(&mInstance, aPacket, aError); + } +} + +ThreadError LinkRaw::Transmit(RadioPacket *aPacket, otLinkRawTransmitDone aCallback) +{ + ThreadError error = kThreadError_InvalidState; + + if (mEnabled) + { + mTransmitDoneCallback = aCallback; + +#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT + (void)aPacket; + mTransmitAttempts = 0; + mCsmaAttempts = 0; + + // Start the transmission backlog logic + StartCsmaBackoff(); + error = kThreadError_None; +#else + // Let the hardware do the transmission logic + error = DoTransmit(aPacket); +#endif + } + + return error; +} + +ThreadError LinkRaw::DoTransmit(RadioPacket *aPacket) +{ + ThreadError error = otPlatRadioTransmit(&mInstance, aPacket); + +#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ACK_TIMEOUT + + // If we are implementing the ACK timeout logic, start a timer here (if ACK request) + // to fire if we don't get a transmit done callback in time. + if (static_cast(aPacket)->GetAckRequest()) + { + mTimerReason = kTimerReasonAckTimeout; + mTimer.Start(kAckTimeout); + } + +#endif + + return error; +} + +void LinkRaw::InvokeTransmitDone(RadioPacket *aPacket, bool aFramePending, ThreadError aError) +{ +#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ACK_TIMEOUT + mTimer.Stop(); +#endif + +#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT + + if (aError == kThreadError_ChannelAccessFailure) + { + if (mCsmaAttempts < Mac::kMaxCSMABackoffs) + { + mCsmaAttempts++; + StartCsmaBackoff(); + goto exit; + } + } + else + { + mCsmaAttempts = 0; + } + + if (aError == kThreadError_NoAck) + { + if (mTransmitAttempts < Mac::kMaxFrameAttempts) + { + mTransmitAttempts++; + StartCsmaBackoff(); + goto exit; + } + } + +#endif + + if (mTransmitDoneCallback) + { + mTransmitDoneCallback(&mInstance, aPacket, aFramePending, aError); + mTransmitDoneCallback = NULL; + } + +#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT +exit: + return; +#endif +} + +ThreadError LinkRaw::EnergyScan(uint8_t aScanChannel, uint16_t aScanDuration, otLinkRawEnergyScanDone aCallback) +{ + ThreadError error = kThreadError_InvalidState; + + if (mEnabled) + { + mEnergyScanDoneCallback = aCallback; + +#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ENERGY_SCAN + // Start listening on the scan channel + otPlatRadioReceive(&mInstance, aScanChannel); + + // Reset the RSSI value and start scanning + mEnergyScanRssi = kInvalidRssiValue; + mTimerReason = kTimerReasonEnergyScanComplete; + mTimer.Start(aScanDuration); + mEnergyScanTask.Post(); +#else + // Do the HW offloaded energy scan + error = otPlatRadioEnergyScan(&mInstance, aScanChannel, aScanDuration); +#endif + } + + return error; +} + +void LinkRaw::InvokeEnergyScanDone(int8_t aEnergyScanMaxRssi) +{ + if (mEnergyScanDoneCallback) + { + mEnergyScanDoneCallback(&mInstance, aEnergyScanMaxRssi); + mEnergyScanDoneCallback = NULL; + } +} + +#if OPENTHREAD_LINKRAW_TIMER_REQUIRED + +void LinkRaw::HandleTimer(void *aContext) +{ + static_cast(aContext)->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(&mInstance, mReceiveChannel); + + // Invoke completion callback for transmit + InvokeTransmitDone(otPlatRadioGetTransmitBuffer(&mInstance), false, kThreadError_NoAck); + } + +#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ACK_TIMEOUT + +#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT + + case kTimerReasonRetransmitTimeout: + { + RadioPacket *aPacket = otPlatRadioGetTransmitBuffer(&mInstance); + + // Start the transmit now + ThreadError error = DoTransmit(aPacket); + + if (error != kThreadError_None) + { + InvokeTransmitDone(aPacket, false, error); + } + } + +#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT + +#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ENERGY_SCAN + + case kTimerReasonEnergyScanComplete: + { + // Invoke completion callback for the energy scan + InvokeEnergyScanDone(mEnergyScanRssi); + } + +#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ENERGY_SCAN + + default: + assert(false); + } +} + +#endif // OPENTHREAD_LINKRAW_TIMER_REQUIRED + +#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT + +void LinkRaw::StartCsmaBackoff(void) +{ + uint32_t backoffExponent = Mac::kMinBE + mTransmitAttempts + mCsmaAttempts; + uint32_t backoff; + + if (backoffExponent > Mac::kMaxBE) + { + backoffExponent = Mac::kMaxBE; + } + + backoff = Mac::kMinBackoff + (Mac::kUnitBackoffPeriod * kPhyUsPerSymbol * (1 << backoffExponent)) / 1000; + backoff = (otPlatRandomGet() % backoff); + + mTimerReason = kTimerReasonRetransmitTimeout; + mTimer.Start(backoff); +} + +#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT + +#if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ENERGY_SCAN + +void LinkRaw::HandleEnergyScanTask(void *aContext) +{ + static_cast(aContext)->HandleEnergyScanTask(); +} + +void LinkRaw::HandleEnergyScanTask(void) +{ + // Only process task if we are still energy scanning + if (mTimerReason == kTimerReasonEnergyScanComplete) + { + int8_t rssi = otPlatRadioGetRssi(&mInstance); + + // Only apply the RSSI if it was a valid value + if (rssi != kInvalidRssiValue) + { + if ((mEnergyScanRssi == kInvalidRssiValue) || (rssi > mEnergyScanRssi)) + { + mEnergyScanRssi = rssi; + } + } + + // Post another instance of tha task, since we are + // still doing the energy scan. + mEnergyScanTask.Post(); + } +} + +#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ENERGY_SCAN + +} // namespace Thread diff --git a/src/core/mac/mac.cpp b/src/core/mac/mac.cpp index a32d19171..17b6e124d 100644 --- a/src/core/mac/mac.cpp +++ b/src/core/mac/mac.cpp @@ -266,13 +266,9 @@ extern "C" void otPlatRadioEnergyScanDone(otInstance *aInstance, int8_t aEnergyS { #if OPENTHREAD_ENABLE_RAW_LINK_API - if (aInstance->mLinkRawEnabled) + if (aInstance->mLinkRaw.IsEnabled()) { - if (aInstance->mLinkRawEnergyScanDoneCallback) - { - aInstance->mLinkRawEnergyScanDoneCallback(aInstance, aEnergyScanMaxRssi); - aInstance->mLinkRawEnergyScanDoneCallback = NULL; - } + aInstance->mLinkRaw.InvokeEnergyScanDone(aEnergyScanMaxRssi); } else #endif // OPENTHREAD_ENABLE_RAW_LINK_API @@ -807,13 +803,9 @@ extern "C" void otPlatRadioTransmitDone(otInstance *aInstance, RadioPacket *aPac #if OPENTHREAD_ENABLE_RAW_LINK_API - if (aInstance->mLinkRawEnabled) + if (aInstance->mLinkRaw.IsEnabled()) { - if (aInstance->mLinkRawTransmitDoneCallback) - { - aInstance->mLinkRawTransmitDoneCallback(aInstance, aPacket, aRxPending, aError); - aInstance->mLinkRawTransmitDoneCallback = NULL; - } + aInstance->mLinkRaw.InvokeTransmitDone(aPacket, aRxPending, aError); } else #endif // OPENTHREAD_ENABLE_RAW_LINK_API @@ -1200,12 +1192,9 @@ extern "C" void otPlatRadioReceiveDone(otInstance *aInstance, RadioPacket *aFram #if OPENTHREAD_ENABLE_RAW_LINK_API - if (aInstance->mLinkRawEnabled) + if (aInstance->mLinkRaw.IsEnabled()) { - if (aInstance->mLinkRawReceiveDoneCallback) - { - aInstance->mLinkRawReceiveDoneCallback(aInstance, aFrame, aError); - } + aInstance->mLinkRaw.InvokeReceiveDone(aFrame, aError); } else #endif // OPENTHREAD_ENABLE_RAW_LINK_API diff --git a/src/core/openthread-core-default-config.h b/src/core/openthread-core-default-config.h index 0496f5c0d..afd79186e 100644 --- a/src/core/openthread-core-default-config.h +++ b/src/core/openthread-core-default-config.h @@ -559,4 +559,34 @@ #define OPENTHREAD_CONFIG_PLATFORM_ASSERT_MANAGEMENT 0 #endif +/** + * @def OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ACK_TIMEOUT + * + * Define to 1 if you want to enable software ACK timeout logic. + * + */ +#ifndef OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ACK_TIMEOUT +#define OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ACK_TIMEOUT 0 +#endif + +/** + * @def OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT + * + * Define to 1 if you want to enable software retransmission logic. + * + */ +#ifndef OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT +#define OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT 0 +#endif + +/** + * @def OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ENERGY_SCAN + * + * Define to 1 if you want to enable software energy scanning logic. + * + */ +#ifndef OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ENERGY_SCAN +#define OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ENERGY_SCAN 0 +#endif + #endif // OPENTHREAD_CORE_DEFAULT_CONFIG_H_ diff --git a/src/core/openthread-instance.h b/src/core/openthread-instance.h index ef833b22b..88b14868d 100644 --- a/src/core/openthread-instance.h +++ b/src/core/openthread-instance.h @@ -44,7 +44,9 @@ #include #include #include -#include "openthread/link_raw.h" +#if OPENTHREAD_ENABLE_RAW_LINK_API +#include +#endif /** * This type represents all the static / global variables used by OpenThread allocated in one place. @@ -66,13 +68,6 @@ typedef struct otInstance otHandleEnergyScanResult mEnergyScanCallback; void *mEnergyScanCallbackContext; -#if OPENTHREAD_ENABLE_RAW_LINK_API - bool mLinkRawEnabled; - otLinkRawReceiveDone mLinkRawReceiveDoneCallback; - otLinkRawTransmitDone mLinkRawTransmitDoneCallback; - otLinkRawEnergyScanDone mLinkRawEnergyScanDoneCallback; -#endif // OPENTHREAD_ENABLE_RAW_LINK_API - // // State // @@ -83,6 +78,10 @@ typedef struct otInstance Thread::Ip6::Ip6 mIp6; Thread::ThreadNetif mThreadNetif; +#if OPENTHREAD_ENABLE_RAW_LINK_API + Thread::LinkRaw mLinkRaw; +#endif // OPENTHREAD_ENABLE_RAW_LINK_API + #if OPENTHREAD_ENABLE_APPLICATION_COAP Thread::Coap::Server mApplicationCoapServer; #endif // OPENTHREAD_ENABLE_APPLICATION_COAP diff --git a/src/core/openthread.cpp b/src/core/openthread.cpp index a08dc0017..72d014390 100644 --- a/src/core/openthread.cpp +++ b/src/core/openthread.cpp @@ -81,13 +81,10 @@ otInstance::otInstance(void) : mActiveScanCallbackContext(NULL), mEnergyScanCallback(NULL), mEnergyScanCallbackContext(NULL), -#if OPENTHREAD_ENABLE_RAW_LINK_API - mLinkRawEnabled(false), - mLinkRawReceiveDoneCallback(NULL), - mLinkRawTransmitDoneCallback(NULL), - mLinkRawEnergyScanDoneCallback(NULL), -#endif // OPENTHREAD_ENABLE_RAW_LINK_API mThreadNetif(mIp6) +#if OPENTHREAD_ENABLE_RAW_LINK_API + , mLinkRaw(*this) +#endif // OPENTHREAD_ENABLE_RAW_LINK_API #if OPENTHREAD_ENABLE_APPLICATION_COAP , mApplicationCoapServer(mIp6.mUdp, OT_DEFAULT_COAP_PORT) #endif // OPENTHREAD_ENABLE_APPLICATION_COAP @@ -1259,7 +1256,7 @@ ThreadError otInterfaceUp(otInstance *aInstance) otLogFuncEntry(); #if OPENTHREAD_ENABLE_RAW_LINK_API - VerifyOrExit(!aInstance->mLinkRawEnabled, error = kThreadError_InvalidState); + VerifyOrExit(!aInstance->mLinkRaw.IsEnabled(), error = kThreadError_InvalidState); #endif // OPENTHREAD_ENABLE_RAW_LINK_API error = aInstance->mThreadNetif.Up(); @@ -1278,7 +1275,7 @@ ThreadError otInterfaceDown(otInstance *aInstance) otLogFuncEntry(); #if OPENTHREAD_ENABLE_RAW_LINK_API - VerifyOrExit(!aInstance->mLinkRawEnabled, error = kThreadError_InvalidState); + VerifyOrExit(!aInstance->mLinkRaw.IsEnabled(), error = kThreadError_InvalidState); #endif // OPENTHREAD_ENABLE_RAW_LINK_API error = aInstance->mThreadNetif.Down();