diff --git a/.travis/script.sh b/.travis/script.sh index 0fe8d0cc9..4db6589bb 100755 --- a/.travis/script.sh +++ b/.travis/script.sh @@ -438,7 +438,8 @@ python --version || die --enable-channel-manager \ --enable-channel-monitor \ --disable-docs \ - --disable-tests || die + --disable-tests \ + --with-vendor-extension=./src/core/common/extension_example.cpp || die make -j 8 || die git checkout -- . || die diff --git a/configure.ac b/configure.ac index 80605301f..f796227d9 100644 --- a/configure.ac +++ b/configure.ac @@ -1067,6 +1067,36 @@ AC_SUBST(OPENTHREAD_ENABLE_DIAG) AM_CONDITIONAL([OPENTHREAD_ENABLE_DIAG], [test "${enable_diag}" = "yes"]) AC_DEFINE_UNQUOTED([OPENTHREAD_ENABLE_DIAG],[${OPENTHREAD_ENABLE_DIAG}],[Define to 1 if you want to use diagnostics module]) +# +# Vendor Extension - Specify a C++ source file which will be built as part of OpenThread core library. +# + +AC_ARG_WITH( + [vendor-extension], + [AS_HELP_STRING([--with-vendor-extension=],[Specify a C++ source file built as part of OpenThread core library. @<:@default=none@:>@.])], + [ + if test "${withval}" = "no" + then OPENTHREAD_ENABLE_VENDOR_EXTENSION=0 + elif test '!' -f "${withval}" + then AC_MSG_ERROR([Can't open ${withval} for --with-vendor-extension]) + else + OPENTHREAD_ENABLE_VENDOR_EXTENSION=1 + + # Get the absolute path. + OPENTHREAD_VENDOR_EXTENSION_SOURCE=$(cd `dirname ${withval}` && pwd)/$(basename ${withval}) + fi + ], + [ + OPENTHREAD_ENABLE_VENDOR_EXTENSION=0 + with_vendor_extension=none + ]) + +AC_MSG_CHECKING([for vendor extension]) +AC_MSG_RESULT(${OPENTHREAD_VENDOR_EXTENSION_SOURCE-none}) +AC_SUBST(OPENTHREAD_VENDOR_EXTENSION_SOURCE) +AC_DEFINE_UNQUOTED([OPENTHREAD_ENABLE_VENDOR_EXTENSION],[${OPENTHREAD_ENABLE_VENDOR_EXTENSION}],[Define to 1 if using vendor extension]) +AM_CONDITIONAL([OPENTHREAD_ENABLE_VENDOR_EXTENSION], [test "${OPENTHREAD_ENABLE_VENDOR_EXTENSION}" = "1"]) + # # Legacy Network # @@ -1833,6 +1863,7 @@ AC_MSG_NOTICE([ OpenThread NCP-BUS Configuration : ${with_ncp_bus} OpenThread NCP Vendor Hook Source : ${with_ncp_vendor_hook_source} OpenThread NCP Spinel Encrypter : ${with_ncp_spinel_encrypter_libs} + OpenThread Vendor Extension Source : ${with_vendor_extension} OpenThread Multiple Instances support : ${enable_multiple_instances} OpenThread MTD Network Diagnostic support : ${enable_mtd_network_diagnostic} OpenThread builtin mbedtls support : ${enable_builtin_mbedtls} diff --git a/src/core/Makefile.am b/src/core/Makefile.am index 77daed6c7..55e9a5d36 100644 --- a/src/core/Makefile.am +++ b/src/core/Makefile.am @@ -219,6 +219,10 @@ SOURCES_COMMON = \ utils/slaac_address.cpp \ $(NULL) +EXTRA_DIST = \ + common/extension_example.cpp \ + $(NULL) + libopenthread_radio_a_SOURCES = \ api/instance_api.cpp \ api/link_raw_api.cpp \ @@ -248,6 +252,28 @@ libopenthread_ftd_a_SOURCES = \ $(SOURCES_COMMON) \ $(NULL) +if OPENTHREAD_ENABLE_VENDOR_EXTENSION + +.INTERMEDIATE: vendor_extension_temp.cpp +vendor_extension_temp.cpp: ${OPENTHREAD_VENDOR_EXTENSION_SOURCE} + $(AM_V_GEN)cp $< $@ + +# "nodist_" prefix tells automake not to include in 'make dist' + +nodist_libopenthread_ftd_a_SOURCES = \ + vendor_extension_temp.cpp \ + $(NULL) + +nodist_libopenthread_mtd_a_SOURCES = \ + vendor_extension_temp.cpp \ + $(NULL) + +nodist_libopenthread_radio_a_SOURCES = \ + vendor_extension_temp.cpp \ + $(NULL) + +endif # OPENTHREAD_ENABLE_VENDOR_EXTENSION + HEADERS_COMMON = \ openthread-core-config-check.h \ openthread-core-config.h \ @@ -259,6 +285,7 @@ HEADERS_COMMON = \ common/crc16.hpp \ common/debug.hpp \ common/encoding.hpp \ + common/extension.hpp \ common/instance.hpp \ common/locator.hpp \ common/logging.hpp \ @@ -364,6 +391,7 @@ noinst_HEADERS = \ PRETTY_FILES = \ $(HEADERS_COMMON) \ $(SOURCES_COMMON) \ + $(EXTRA_DIST) \ $(NULL) if OPENTHREAD_BUILD_COVERAGE diff --git a/src/core/common/extension.hpp b/src/core/common/extension.hpp new file mode 100644 index 000000000..9e13f292d --- /dev/null +++ b/src/core/common/extension.hpp @@ -0,0 +1,124 @@ +/* + * Copyright (c) 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 OpenThread vendor extension hooks. + */ + +#ifndef EXTENSION_HPP_ +#define EXTENSION_HPP_ + +#include "openthread-core-config.h" + +#include "common/locator.hpp" + +#if OPENTHREAD_ENABLE_VENDOR_EXTENSION + +namespace ot { +namespace Ncp { +class NcpBase; +} +namespace Extension { + +/** + * @addtogroup core-extension + * + * @brief + * This module includes definitions for OpenThread vendor extension hooks. + * + * @{ + * + */ + +/** + * This class defines the base class for an OpenThread vendor Extension object. + * + * This class is used by OpenThread core to interact with the extension module. Methods in this class are expected + * to be implemented by the vendor extension module. + * + * Support for vendor extension can be enabled using `OPENTHREAD_ENABLE_VENDOR_EXTENSION` configuration option. + * + */ +class ExtensionBase : public InstanceLocator +{ +public: + /** + * This static method initializes and gets a vendor extension instance. + * + * @param[in] aInstance A reference to the OpenThread instance. + * + * @note When this method is called, the @p aInstance itself may not yet be fully initialized. The method + * `SignalInstanceInit()` is called when `aInstance` is fully initialized. + * + * @returns A reference to the object. + * + */ + static ExtensionBase &Init(Instance &aInstance); + + /** + * This method notifies the extension object that OpenThread instance has been initialized. + * + */ + void SignalInstanceInit(void); + + /** + * This method notifies the extension object that NCP instance has been initialized. + * + * @param[in] aNcpInstance A reference to the NCP object. + * + */ + void SignalNcpInit(Ncp::NcpBase &aNcpInsatnce); + +protected: + /** + * This constructor initializes the object. + * + * @param[in] aInstance A reference to the OpenThread instance. + * + */ + explicit ExtensionBase(Instance &aInstance) + : InstanceLocator(aInstance) + , mIsInitialized(true) + { + } + + bool mIsInitialized; +}; + +/** + * @} + * + */ + +} // namespace Extension +} // namespace ot + +#endif // #if OPENTHREAD_ENABLE_VENDOR_EXTENSION + +#endif // EXTENSION_HPP_ diff --git a/src/core/common/extension_example.cpp b/src/core/common/extension_example.cpp new file mode 100644 index 000000000..6f1824f95 --- /dev/null +++ b/src/core/common/extension_example.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (c) 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 provides an example on how to implement an OpenThread vendor extension. + */ + +#include "openthread-core-config.h" + +#include "common/code_utils.hpp" +#include "common/extension.hpp" +#include "common/new.hpp" +#include "utils/wrap_stdbool.h" +#include "utils/wrap_stdint.h" + +namespace ot { +namespace Extension { + +/** + * This class defines the vendor extension object. + * + */ +class Extension : public ExtensionBase +{ +public: + explicit Extension(Instance &aInstance) + : ExtensionBase(aInstance) + { + } + + // TODO: Add vendor extension code (add methods and/or member variables). +}; + +// ---------------------------------------------------------------------------- +// `ExtensionBase` API +// ---------------------------------------------------------------------------- + +static otDEFINE_ALIGNED_VAR(sExtensionRaw, sizeof(Extension), uint64_t); + +ExtensionBase &ExtensionBase::Init(Instance &aInstance) +{ + ExtensionBase *ext = reinterpret_cast(&sExtensionRaw); + + VerifyOrExit(!ext->mIsInitialized); + + ext = new (&sExtensionRaw) Extension(aInstance); + +exit: + return *ext; +} + +void ExtensionBase::SignalInstanceInit(void) +{ + // OpenThread instance is initialized and ready. + + // TODO: Implement vendor extension code here and start interaction with OpenThread instance. +} + +void ExtensionBase::SignalNcpInit(Ncp::NcpBase &aNcpBase) +{ + // NCP instance is initialized and ready. + + // TODO: Implement vendor extension code here and start interaction with NCP instance. + + OT_UNUSED_VARIABLE(aNcpBase); +} + +} // namespace Extension +} // namespace ot diff --git a/src/core/common/instance.cpp b/src/core/common/instance.cpp index eee4b2eda..3fe98c0c3 100644 --- a/src/core/common/instance.cpp +++ b/src/core/common/instance.cpp @@ -86,6 +86,9 @@ Instance::Instance(void) #endif // OPENTHREAD_RADIO || OPENTHREAD_ENABLE_RAW_LINK_API #if OPENTHREAD_CONFIG_ENABLE_DYNAMIC_LOG_LEVEL , mLogLevel(static_cast(OPENTHREAD_CONFIG_LOG_LEVEL)) +#endif +#if OPENTHREAD_ENABLE_VENDOR_EXTENSION + , mExtension(Extension::ExtensionBase::Init(*this)) #endif , mIsInitialized(false) { @@ -169,6 +172,10 @@ void Instance::AfterInit(void) #endif #endif // OPENTHREAD_MTD || OPENTHREAD_FTD + +#if OPENTHREAD_ENABLE_VENDOR_EXTENSION + GetExtension().SignalInstanceInit(); +#endif } void Instance::Finalize(void) diff --git a/src/core/common/instance.hpp b/src/core/common/instance.hpp index 939958a6e..568eafb6d 100644 --- a/src/core/common/instance.hpp +++ b/src/core/common/instance.hpp @@ -67,6 +67,9 @@ #include "utils/channel_monitor.hpp" #endif #endif // OPENTHREAD_FTD || OPENTHREAD_MTD +#if OPENTHREAD_ENABLE_VENDOR_EXTENSION +#include "common/extension.hpp" +#endif /** * @addtogroup core-instance @@ -376,6 +379,16 @@ public: */ MessagePool &GetMessagePool(void) { return mMessagePool; } +#if OPENTHREAD_ENABLE_VENDOR_EXTENSION + /** + * This method returns a reference to vendor extension object. + * + * @returns A reference to the vendor extension object. + * + */ + Extension::ExtensionBase &GetExtension(void) { return mExtension; } +#endif + #endif // OPENTHREAD_MTD || OPENTHREAD_FTD /** @@ -459,6 +472,9 @@ private: #endif // OPENTHREAD_RADIO || OPENTHREAD_ENABLE_RAW_LINK_API #if OPENTHREAD_CONFIG_ENABLE_DYNAMIC_LOG_LEVEL otLogLevel mLogLevel; +#endif +#if OPENTHREAD_ENABLE_VENDOR_EXTENSION + Extension::ExtensionBase &mExtension; #endif bool mIsInitialized; }; @@ -691,6 +707,13 @@ template <> inline TaskletScheduler &Instance::Get(void) return GetTaskletScheduler(); } +#if OPENTHREAD_ENABLE_VENDOR_EXTENSION +template <> inline Extension::ExtensionBase &Instance::Get(void) +{ + return GetExtension(); +} +#endif + /** * @} * diff --git a/src/ncp/ncp_base.cpp b/src/ncp/ncp_base.cpp index c3a659362..daff866c7 100644 --- a/src/ncp/ncp_base.cpp +++ b/src/ncp/ncp_base.cpp @@ -290,6 +290,10 @@ NcpBase::NcpBase(Instance *aInstance) #endif // OPENTHREAD_MTD || OPENTHREAD_FTD mChangedPropsSet.AddLastStatus(SPINEL_STATUS_RESET_UNKNOWN); mUpdateChangedPropsTask.Post(); + +#if OPENTHREAD_ENABLE_VENDOR_EXTENSION + aInstance->GetExtension().SignalNcpInit(*this); +#endif } NcpBase *NcpBase::GetNcpInstance(void)