From 0e368353c9f142e36a58a09d1a6afc26132be774 Mon Sep 17 00:00:00 2001 From: Kamil Sroka Date: Mon, 15 Jan 2018 10:24:06 +0100 Subject: [PATCH 1/6] include: net: net_pkt: Use IEEE802154 instead of NET_L2_IEEE802154 Use CONFIG_IEEE802154 instead of CONFIG_NET_L2_IEEE802154 when adding RSSI and LQI members to net_pkt. CONFIG_IEEE802154 is more generic. Signed-off-by: Kamil Sroka --- include/net/net_pkt.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/net/net_pkt.h b/include/net/net_pkt.h index 5a6e77b5909c7c..af76d54ee626c1 100644 --- a/include/net/net_pkt.h +++ b/include/net/net_pkt.h @@ -124,7 +124,7 @@ struct net_pkt { #endif /* CONFIG_NET_IPV6_FRAGMENT */ #endif /* CONFIG_NET_IPV6 */ -#if defined(CONFIG_NET_L2_IEEE802154) || defined(CONFIG_IEEE802154_RAW_MODE) +#if defined(CONFIG_IEEE802154) || defined(CONFIG_IEEE802154_RAW_MODE) u8_t ieee802154_rssi; /* Received Signal Strength Indication */ u8_t ieee802154_lqi; /* Link Quality Indicator */ #endif @@ -426,7 +426,7 @@ static inline void net_pkt_ll_swap(struct net_pkt *pkt) net_pkt_ll_dst(pkt)->addr = addr; } -#if defined(CONFIG_NET_L2_IEEE802154) || defined(CONFIG_IEEE802154_RAW_MODE) +#if defined(CONFIG_IEEE802154) || defined(CONFIG_IEEE802154_RAW_MODE) static inline u8_t net_pkt_ieee802154_rssi(struct net_pkt *pkt) { return pkt->ieee802154_rssi; From eab8298cdfddc5f7b71067c985c1945521a4e09f Mon Sep 17 00:00:00 2001 From: Kamil Sroka Date: Mon, 15 Jan 2018 11:06:11 +0100 Subject: [PATCH 2/6] subsys: net: lib: Add OpenThread platform OpenThread requires platform definition with standarized API so we have to add wrappers to make it compatible with Zephyr. OpenThread is based on autoconf, this requires more specific CMakeLists.txt which allows to clone specific commit or point to local copy of openthread. Signed-off-by: Kamil Sroka --- subsys/net/lib/CMakeLists.txt | 1 + subsys/net/lib/openthread/CMakeLists.txt | 244 +++++++++++++ .../lib/openthread/platform/CMakeLists.txt | 17 + subsys/net/lib/openthread/platform/alarm.c | 71 ++++ subsys/net/lib/openthread/platform/diag.c | 66 ++++ subsys/net/lib/openthread/platform/flash.c | 108 ++++++ subsys/net/lib/openthread/platform/logging.c | 56 +++ subsys/net/lib/openthread/platform/misc.c | 27 ++ .../platform/openthread-core-zephyr-config.h | 98 +++++ .../lib/openthread/platform/platform-zephyr.h | 58 +++ subsys/net/lib/openthread/platform/platform.c | 33 ++ subsys/net/lib/openthread/platform/radio.c | 345 ++++++++++++++++++ subsys/net/lib/openthread/platform/random.c | 37 ++ subsys/net/lib/openthread/platform/shell.c | 79 ++++ subsys/net/lib/openthread/platform/spi.c | 49 +++ .../lib/openthread/zephyr-mbedtls-config.h | 12 + 16 files changed, 1301 insertions(+) create mode 100644 subsys/net/lib/openthread/CMakeLists.txt create mode 100644 subsys/net/lib/openthread/platform/CMakeLists.txt create mode 100644 subsys/net/lib/openthread/platform/alarm.c create mode 100644 subsys/net/lib/openthread/platform/diag.c create mode 100644 subsys/net/lib/openthread/platform/flash.c create mode 100644 subsys/net/lib/openthread/platform/logging.c create mode 100644 subsys/net/lib/openthread/platform/misc.c create mode 100644 subsys/net/lib/openthread/platform/openthread-core-zephyr-config.h create mode 100644 subsys/net/lib/openthread/platform/platform-zephyr.h create mode 100644 subsys/net/lib/openthread/platform/platform.c create mode 100644 subsys/net/lib/openthread/platform/radio.c create mode 100644 subsys/net/lib/openthread/platform/random.c create mode 100644 subsys/net/lib/openthread/platform/shell.c create mode 100644 subsys/net/lib/openthread/platform/spi.c create mode 100644 subsys/net/lib/openthread/zephyr-mbedtls-config.h diff --git a/subsys/net/lib/CMakeLists.txt b/subsys/net/lib/CMakeLists.txt index 9b5e9e01466da2..48990f18565086 100644 --- a/subsys/net/lib/CMakeLists.txt +++ b/subsys/net/lib/CMakeLists.txt @@ -12,3 +12,4 @@ if(CONFIG_HTTP_PARSER_URL add_subdirectory(http) endif() +add_subdirectory_ifdef(CONFIG_OPENTHREAD_PLAT openthread) diff --git a/subsys/net/lib/openthread/CMakeLists.txt b/subsys/net/lib/openthread/CMakeLists.txt new file mode 100644 index 00000000000000..68a9d18fad31df --- /dev/null +++ b/subsys/net/lib/openthread/CMakeLists.txt @@ -0,0 +1,244 @@ +# Invoke OpenThread's external autoconf-based build system. +include(ExternalProject) + +set(ep_base ${PROJECT_BINARY_DIR}/ext_proj) +set_property(DIRECTORY PROPERTY "EP_BASE" ${ep_base}) + +# Construct a list of commands to give to ExternalProject_Add() +# +# See https://cmake.org/cmake/help/latest/module/ExternalProject.html +# for documentation on ExternalProject_Add +set(cmd "") + +set(ot_name ot) +list(APPEND cmd + ${ot_name} + ) + +set(ot_STAMP_DIR ${ep_base}/Stamp/${ot_name}) +set(ot_INSTALL_DIR ${ep_base}/Install/${ot_name}) + +#--Download step-------------- +if(NOT EXTERNAL_PROJECT_PATH_OPENTHREAD) + # TODO: Point to a Zephyr fork + # Nov. 7 + set_ifndef(ot_GIT_REPOSITORY "https://github.com/openthread/openthread.git") + set_ifndef(ot_GIT_TAG e083fdfef42414cb1163d95b59f1d43a44fe0dbe) + set_ifndef(ot_GIT_PROGRESS 1) + + list(APPEND cmd + GIT_REPOSITORY ${ot_GIT_REPOSITORY} + GIT_TAG ${ot_GIT_TAG} + GIT_PROGRESS ${ot_GIT_PROGRESS} + ) +endif() + +#--Update/Patch step------------- + +# An update step is not necessary because we are using a commit hash +# as a tag, and the code behind a hash cannot change. + +# UPDATE_DISCONNECTED should be used when updates aren't needed, but +# for some reason we were not able to get this to work, so we use a +# dummy step to fake updating. This ensures that the git repo is not +# downloaded on every 'make' invocation. +list(APPEND cmd + UPDATE_COMMAND + ${CMAKE_COMMAND} -E touch ${ot_STAMP_DIR}/${ot_name}-update + ) + +#--Configure step------------- +if(EXTERNAL_PROJECT_PATH_OPENTHREAD) + set(ot_SOURCE_DIR ${EXTERNAL_PROJECT_PATH_OPENTHREAD}) + + list(APPEND cmd + SOURCE_DIR ${ot_SOURCE_DIR} + ) + +else() + set(ot_SOURCE_DIR ${ep_base}/Source/${ot_name}) # TODO: Download dir? + + # "If SOURCE_DIR is explicitly set to an existing directory the + # project will be built from it. Otherwise a download step must be + # specified using one of the DOWNLOAD_COMMAND, CVS_*, SVN_*, or URL + # options." -- CMake docs +endif() + +# TODO: Can we omit this, does OpenThread need to use install? +# TODO: Move this to host-tools? +find_program(INSTALL install) + +# It looks like OpenThread requires a *nix system to build for +# embedded. +# +# https://github.com/openthread/openthread/blob/master/examples/drivers/windows/README.md + +# TODO: Use different includes for C and CXX +zephyr_get_include_directories_for_lang_as_string( C includes) +zephyr_get_system_include_directories_for_lang_as_string(C system_includes) +zephyr_get_compile_definitions_for_lang_as_string( C definitions) + +zephyr_get_compile_options_for_lang_as_string(C c_options) +zephyr_get_compile_options_for_lang_as_string(CXX cxx_options) + +# TODO: What happens if a CFLAG is added after this build script has +# been run? + +# TODO: Does OpenThread need all flags, or just some? Should we +# whitelist, or blacklist flags? + + +# TODO: What is all this? $(dir $(realpath $(firstword $(MAKEFILE_LIST)))) + +set(exec_prefix zephyr) + +set(commoncflags "-DOPENTHREAD_CONFIG_LOG_LEVEL=${CONFIG_OPENTHREAD_LOG_LEVEL}") +set(commoncflags "${commoncflags} -DOPENTHREAD_PROJECT_CORE_CONFIG_FILE=\\\"openthread-core-zephyr-config.h\\\"") +set(commoncflags "${commoncflags} -I${CMAKE_CURRENT_LIST_DIR}/platform") + +set(configure_flags + "INSTALL=${INSTALL} -p" + "CPP=${CMAKE_C_COMPILER} -E" # TODO: Find CPP in toolchain-gcc.cmake and use that instead? + "CC=${CMAKE_C_COMPILER}" + "CXX=${CMAKE_CXX_COMPILER}" + OBJC="" # TODO: Omit this? + "OBJCXX=${OBJCXX}" # TODO: Omit this? + "AR=${CMAKE_AR}" + "RANLIB=${CMAKE_RANLILB}" + "NM=${CROSS_COMPILE}nm" # TODO: Find NM in toolchain-gcc.cmake and use that instead? + "STRIP=${CMAKE_STRIP}" + "CPPFLAGS=${definitions} ${commoncflags} ${includes} ${system_includes}" + "CFLAGS=${c_options} ${commoncflags} ${includes} ${system_includes}" + "CXXFLAGS=${cxx_options} ${commoncflags} ${includes} ${system_includes}" # TODO: Do we need includes here? + LDFLAGS="" # TODO: What does a networking stack need to use the linker for? + + --host=arm-none-eabi + --prefix=/ + --exec-prefix=/${exec_prefix} + --target=arm-none-eabi # TODO: Is Kconfig expressing that OT is ARM-only? + --enable-no-executables-hack + --disable-docs + --with-platform-info=zephyr +) + +# TODO: Simplify +set(ZEPHYR_MBEDTLS_CPPFLAGS "${ZEPHYR_MBEDTLS_CPPFLAGS} ") +set(ZEPHYR_MBEDTLS_CPPFLAGS "-DMBEDTLS_CONFIG_FILE='\"mbedtls-config.h\"'") +set(ZEPHYR_MBEDTLS_CPPFLAGS "${ZEPHYR_MBEDTLS_CPPFLAGS} -DMBEDTLS_USER_CONFIG_FILE='\"${CMAKE_CURRENT_SOURCE_DIR}/zephyr-mbedtls-config.h\"'") +set(ZEPHYR_MBEDTLS_CPPFLAGS "${ZEPHYR_MBEDTLS_CPPFLAGS} -I${ot_SOURCE_DIR}/third_party/mbedtls") +set(ZEPHYR_MBEDTLS_CPPFLAGS "${ZEPHYR_MBEDTLS_CPPFLAGS} -I${ot_SOURCE_DIR}/third_party/mbedtls/repo.patched/include") +set(ZEPHYR_MBEDTLS_CPPFLAGS "${ZEPHYR_MBEDTLS_CPPFLAGS} -I${ot_SOURCE_DIR}/third_party/mbedtls/repo.patched/include/mbedtls") + +list(APPEND configure_flags + "MBEDTLS_CPPFLAGS=${ZEPHYR_MBEDTLS_CPPFLAGS}" + ) + +if(CONFIG_OPENTHREAD_COMMISSIONER) + list(APPEND configure_flags + --enable-commissioner + ) +endif() + +if(CONFIG_OPENTHREAD_JAM_DETECTION) + list(APPEND configure_flags + --enable-jam-detection + ) +endif() + +if(CONFIG_OPENTHREAD_JOINER) + list(APPEND configure_flags + --enable-joiner + ) +endif() + +if(CONFIG_OPENTHREAD_SHELL) + list(APPEND configure_flags + --enable-cli-app=all + ) +endif() + +if(CONFIG_OPENTHREAD_DIAG) + list(APPEND configure_flags + --enable-diag + ) +endif() + +list(APPEND cmd + CONFIGURE_COMMAND ./configure ${configure_flags} +) + +#--Build step----------------- + +# Invoke OpenThread's build system from the root of it's source +# directory +# TODO: Support out-of-source builds +set(ot_BINARY_DIR ${ot_SOURCE_DIR}) +list(APPEND cmd + BINARY_DIR ${ot_BINARY_DIR} + INSTALL_DIR ${ot_INSTALL_DIR} + ) + +set(make_flags + -j99 # TODO: Why 99? + --no-print-directory + ) + +list(APPEND cmd + BUILD_COMMAND make ${make_flags} all + INSTALL_COMMAND make ${make_flags} DESTDIR=${ot_INSTALL_DIR} install + ) + +ExternalProject_Add(${cmd}) + +ExternalProject_Add_Step( + ${ot_name} bootstrap # Names of project and custom step + COMMAND ./bootstrap # Command line invoked by this step + COMMENT "bootstrapping..." # Text printed when step executes + DEPENDEES download # Steps on which this step depends + DEPENDERS configure # Steps that depend on this step + WORKING_DIRECTORY ${ot_SOURCE_DIR} + ) + +# TODO: Find out how to make this work. +set(ot_include_dir ${ot_SOURCE_DIR}/include) + +# TODO: Is this only needed by alarm.c? +zephyr_system_include_directories(${ot_include_dir}) + +# TODO: Why doesn't app get this path from the above function call? +target_include_directories(app SYSTEM PRIVATE ${ot_include_dir}) + +#set_target_properties(ot_lib PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${ot_include_dir}) +zephyr_include_directories(${ot_include_dir}) + +# Determine which libs should be linked in +set(ot_libs + openthread-platform-utils + mbedcrypto + ) +if(CONFIG_OPENTHREAD_FTD) + list(APPEND ot_libs openthread-ftd) + set(cli_lib openthread-cli-ftd) +elseif(CONFIG_OPENTHREAD_MTD) + list(APPEND ot_libs openthread-mtd) + set(cli_lib openthread-cli-ftd) +endif() + +if(CONFIG_OPENTHREAD_SHELL) + list(APPEND ot_libs ${cli_lib}) +endif() + +# Create wrapper CMake libraries +foreach(ot_lib ${ot_libs}) + add_library(${ot_lib} STATIC IMPORTED GLOBAL) + add_dependencies( # TODO: Necessary? + ${ot_lib} + ${ot_name} + ) + set_target_properties(${ot_lib} PROPERTIES IMPORTED_LOCATION + ${ot_INSTALL_DIR}/${exec_prefix}/lib/lib${ot_lib}.a + ) + zephyr_append_cmake_library(${ot_lib}) +endforeach() + +add_subdirectory(platform) diff --git a/subsys/net/lib/openthread/platform/CMakeLists.txt b/subsys/net/lib/openthread/platform/CMakeLists.txt new file mode 100644 index 00000000000000..3bbd711d457923 --- /dev/null +++ b/subsys/net/lib/openthread/platform/CMakeLists.txt @@ -0,0 +1,17 @@ +zephyr_library_named(openthread_platform) +zephyr_library_sources( + alarm.c + flash.c + logging.c + misc.c + platform.c + radio.c + random.c + spi.c + ) + +zephyr_library_sources_ifdef(CONFIG_OPENTHREAD_SHELL shell.c) + +# The source files here use header files from the OpenThread project +# target_link_libraries(app ot_lib) # Better? +add_dependencies(openthread_platform ot) diff --git a/subsys/net/lib/openthread/platform/alarm.c b/subsys/net/lib/openthread/platform/alarm.c new file mode 100644 index 00000000000000..f6d0c9ea20c600 --- /dev/null +++ b/subsys/net/lib/openthread/platform/alarm.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2018 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include +#include + +#define SYS_LOG_DOMAIN "openthread-plat" +#define SYS_LOG_LEVEL SYS_LOG_LEVEL_DEBUG +#include +#include + +#include "platform-zephyr.h" + +static bool timer_fired; + +static void ot_timer_fired(struct k_timer *timer) +{ + ARG_UNUSED(timer); + + timer_fired = true; + PlatformEventSignalPending(); +} + +K_TIMER_DEFINE(ot_timer, ot_timer_fired, NULL); + +void platformAlarmInit(void) +{ + /* Intentionally empty */ +} + +uint32_t otPlatAlarmMilliGetNow(void) +{ + return k_uptime_get_32(); +} + +void otPlatAlarmMilliStartAt(otInstance *aInstance, uint32_t t0, uint32_t dt) +{ + ARG_UNUSED(aInstance); + + s64_t reftime = (s64_t)t0 + (s64_t)dt; + s64_t delta = -k_uptime_delta(&reftime); + + if (delta > 0) { + k_timer_start(&ot_timer, K_MSEC(delta), 0); + } else { + ot_timer_fired(NULL); + } +} + +void otPlatAlarmMilliStop(otInstance *aInstance) +{ + ARG_UNUSED(aInstance); + + k_timer_stop(&ot_timer); +} + + +void platformAlarmProcess(otInstance *aInstance) +{ + if (timer_fired) { + timer_fired = false; + otPlatAlarmMilliFired(aInstance); + } +} diff --git a/subsys/net/lib/openthread/platform/diag.c b/subsys/net/lib/openthread/platform/diag.c new file mode 100644 index 00000000000000..d166f5941626f6 --- /dev/null +++ b/subsys/net/lib/openthread/platform/diag.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2018 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include "platform-zephyr.h" + +/** + * Diagnostics mode variables. + * + */ +static bool sDiagMode; + +void otPlatDiagProcess(otInstance *aInstance, + int argc, + char *argv[], + char *aOutput, + size_t aOutputMaxLen) +{ + ARG_UNUSED(argc); + ARG_UNUSED(aInstance); + + /* Add more plarform specific diagnostics features here. */ + snprintf(aOutput, aOutputMaxLen, + "diag feature '%s' is not supported\r\n", argv[0]); +} + +void otPlatDiagModeSet(bool aMode) +{ + sDiagMode = aMode; +} + +bool otPlatDiagModeGet(void) +{ + return sDiagMode; +} + +void otPlatDiagChannelSet(uint8_t aChannel) +{ + ARG_UNUSED(aChannel); +} + +void otPlatDiagTxPowerSet(int8_t aTxPower) +{ + ARG_UNUSED(aTxPower); +} + +void otPlatDiagRadioReceived(otInstance *aInstance, + RadioPacket *aFrame, + ThreadError aError) +{ + ARG_UNUSED(aInstance); + ARG_UNUSED(aFrame); + ARG_UNUSED(aError); +} + +void otPlatDiagAlarmCallback(otInstance *aInstance) +{ + ARG_UNUSED(aInstance); +} diff --git a/subsys/net/lib/openthread/platform/flash.c b/subsys/net/lib/openthread/platform/flash.c new file mode 100644 index 00000000000000..162277c7c6ad13 --- /dev/null +++ b/subsys/net/lib/openthread/platform/flash.c @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2018 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "platform-zephyr.h" + +static struct device *flash_dev; +static size_t ot_flash_size; +static size_t ot_flash_offset; + +static inline u32_t mapAddress(u32_t aAddress) +{ + return aAddress + ot_flash_offset; +} + +otError utilsFlashInit(void) +{ + int i; + struct flash_pages_info info; + size_t pages_count; + + flash_dev = device_get_binding( + CONFIG_OT_PLAT_FLASH_DEVICE_NAME); + + if (!flash_dev) { + return OT_ERROR_NOT_IMPLEMENTED; + } + + pages_count = flash_get_page_count(flash_dev); + + if (flash_get_page_info_by_idx(flash_dev, + pages_count - CONFIG_OT_PLAT_FLASH_PAGES_COUNT - 1, &info)) { + + return OT_ERROR_FAILED; + } + + ot_flash_offset = info.start_offset; + ot_flash_size = 0; + + for (i = 0; i < CONFIG_OT_PLAT_FLASH_PAGES_COUNT; i++) { + if (flash_get_page_info_by_idx(flash_dev, + pages_count - i - 1, &info)) { + + return OT_ERROR_FAILED; + } + ot_flash_size += info.size; + } + + return OT_ERROR_NONE; +} + +u32_t utilsFlashGetSize(void) +{ + return ot_flash_size; +} + +otError utilsFlashErasePage(u32_t aAddress) +{ + struct flash_pages_info info; + u32_t address; + + address = mapAddress(aAddress); + if (flash_get_page_info_by_offs(flash_dev, address, &info)) { + return OT_ERROR_FAILED; + } + + if (flash_erase(flash_dev, address, info.size)) { + return OT_ERROR_FAILED; + } + + return OT_ERROR_NONE; +} + +otError utilsFlashStatusWait(u32_t aTimeout) +{ + ARG_UNUSED(aTimeout); + + return OT_ERROR_NONE; +} + +u32_t utilsFlashWrite(u32_t aAddress, uint8_t *aData, u32_t aSize) +{ + u32_t index = 0; + + flash_write_protection_set(flash_dev, false); + if (!flash_write(flash_dev, mapAddress(aAddress), aData, aSize)) { + index = aSize; + } + flash_write_protection_set(flash_dev, true); + + return index; +} + +u32_t utilsFlashRead(u32_t aAddress, uint8_t *aData, u32_t aSize) +{ + u32_t index = 0; + + if (!flash_read(flash_dev, mapAddress(aAddress), aData, aSize)) { + index = aSize; + } + + return index; +} diff --git a/subsys/net/lib/openthread/platform/logging.c b/subsys/net/lib/openthread/platform/logging.c new file mode 100644 index 00000000000000..36abdddaff8ec1 --- /dev/null +++ b/subsys/net/lib/openthread/platform/logging.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2018 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include + +#define SYS_LOG_DOMAIN "openthread" +#define SYS_LOG_LEVEL 4 +#include + +#include "platform-zephyr.h" + +#define LOG_PARSE_BUFFER_SIZE 128 + +void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, + const char *aFormat, ...) +{ + ARG_UNUSED(aLogRegion); + + char logString[LOG_PARSE_BUFFER_SIZE + 1]; + u16_t length = 0; + + /* Parse user string. */ + va_list paramList; + + va_start(paramList, aFormat); + length += vsnprintf(&logString[length], + (LOG_PARSE_BUFFER_SIZE - length), + aFormat, paramList); + va_end(paramList); + + + switch (aLogLevel) { + case OT_LOG_LEVEL_CRIT: + SYS_LOG_ERR("%s", logString); + break; + case OT_LOG_LEVEL_WARN: + SYS_LOG_WRN("%s", logString); + break; + case OT_LOG_LEVEL_INFO: + SYS_LOG_INF("%s", logString); + break; + case OT_LOG_LEVEL_DEBG: + SYS_LOG_DBG("%s", logString); + break; + default: + break; + } +} + diff --git a/subsys/net/lib/openthread/platform/misc.c b/subsys/net/lib/openthread/platform/misc.c new file mode 100644 index 00000000000000..eee103f70c6372 --- /dev/null +++ b/subsys/net/lib/openthread/platform/misc.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2018 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include "platform-zephyr.h" + +void otPlatReset(otInstance *aInstance) +{ + ARG_UNUSED(aInstance); + + /* This function does nothing on the Posix platform. */ + sys_reboot(SYS_REBOOT_WARM); +} + +otPlatResetReason otPlatGetResetReason(otInstance *aInstance) +{ + ARG_UNUSED(aInstance); + + return OT_PLAT_RESET_REASON_POWER_ON; +} diff --git a/subsys/net/lib/openthread/platform/openthread-core-zephyr-config.h b/subsys/net/lib/openthread/platform/openthread-core-zephyr-config.h new file mode 100644 index 00000000000000..569fca3ebd1f2d --- /dev/null +++ b/subsys/net/lib/openthread/platform/openthread-core-zephyr-config.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2018 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * This file includes Zephyr compile-time configuration constants + * for OpenThread. + */ + +#ifndef OPENTHREAD_CORE_ZEPHYR_CONFIG_H_ +#define OPENTHREAD_CORE_ZEPHYR_CONFIG_H_ + +/** + * @def OPENTHREAD_CONFIG_NUM_MESSAGE_BUFFERS + * + * The number of message buffers in the buffer pool. + * + */ +#define OPENTHREAD_CONFIG_NUM_MESSAGE_BUFFERS 128 + +/** + * @def OPENTHREAD_CONFIG_MAX_STATECHANGE_HANDLERS + * + * The maximum number of state-changed callback handlers + * (set using `otSetStateChangedCallback()`). + * + */ +#define OPENTHREAD_CONFIG_MAX_STATECHANGE_HANDLERS 2 + +/** + * @def OPENTHREAD_CONFIG_ADDRESS_CACHE_ENTRIES + * + * The number of EID-to-RLOC cache entries. + * + */ +#define OPENTHREAD_CONFIG_ADDRESS_CACHE_ENTRIES 20 + +/** + * @def OPENTHREAD_CONFIG_LOG_PREPREND_LEVEL + * + * Define to prepend the log level to all log messages + * + */ +#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 + * + * The base address of settings. + * + */ +#define SETTINGS_CONFIG_BASE_ADDRESS 0 + +/** + * @def SETTINGS_CONFIG_PAGE_SIZE + * + * The page size of settings. + * + */ +#define SETTINGS_CONFIG_PAGE_SIZE 4096 + +/** + * @def SETTINGS_CONFIG_PAGE_NUM + * + * The page number of settings. + * + */ +#define SETTINGS_CONFIG_PAGE_NUM 4 + +/** + * @def OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_TIMER + * + * Define to 1 if you want to enable microsecond backoff timer + * implemented in platform. + * + */ +#define OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_TIMER 0 + +#endif /* OPENTHREAD_CORE_NRF52840_CONFIG_H_ */ diff --git a/subsys/net/lib/openthread/platform/platform-zephyr.h b/subsys/net/lib/openthread/platform/platform-zephyr.h new file mode 100644 index 00000000000000..1c90cecbff9a96 --- /dev/null +++ b/subsys/net/lib/openthread/platform/platform-zephyr.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2018 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief + * This file includes the Zephyr platform-specific initializers. + */ + +#ifndef PLATFORM_ZEPHYR_H_ +#define PLATFORM_ZEPHYR_H_ + +#include + +/** + * This function initializes the alarm service used by OpenThread. + * + */ +void platformAlarmInit(void); + +/** + * This function performs alarm driver processing. + * + * @param[in] aInstance The OpenThread instance structure. + * + */ +void platformAlarmProcess(otInstance *aInstance); + +/** + * This function initializes the radio service used by OpenThread. + * + */ +void platformRadioInit(void); + +/** + * This function performs radio driver processing. + * + * @param[in] aInstance The OpenThread instance structure. + * + */ +void platformRadioProcess(otInstance *aInstance); + +/** + * This function initializes the random number service used by OpenThread. + * + */ +void platformRandomInit(void); + + +/** + * Initialize platform Shell driver. + */ +void platformShellInit(otInstance *aInstance); + +#endif /* PLATFORM_POSIX_H_ */ diff --git a/subsys/net/lib/openthread/platform/platform.c b/subsys/net/lib/openthread/platform/platform.c new file mode 100644 index 00000000000000..47751c3318739b --- /dev/null +++ b/subsys/net/lib/openthread/platform/platform.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2018 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief + * This file includes the platform-specific initializers. + */ + +#include +#include +#include + +#include "platform-zephyr.h" + +void PlatformInit(int argc, char *argv[]) +{ + ARG_UNUSED(argc); + ARG_UNUSED(argv); + + platformAlarmInit(); + platformRadioInit(); +} + +void PlatformProcessDrivers(otInstance *aInstance) +{ + platformRadioProcess(aInstance); + platformAlarmProcess(aInstance); +} + diff --git a/subsys/net/lib/openthread/platform/radio.c b/subsys/net/lib/openthread/platform/radio.c new file mode 100644 index 00000000000000..6553e167dd01d5 --- /dev/null +++ b/subsys/net/lib/openthread/platform/radio.c @@ -0,0 +1,345 @@ +/* + * Copyright (c) 2018 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * This file implements the OpenThread platform abstraction + * for radio communication. + * + */ + +#include +#include +#include +#include + +#define SYS_LOG_LEVEL CONFIG_OPENTHREAD_LOG_LEVEL +#define SYS_LOG_DOMAIN "otPlat/radio" +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#define FCS_SIZE 2 + +static otRadioState sState = OT_RADIO_STATE_DISABLED; + +static otRadioFrame sTransmitFrame; + +static struct net_pkt *tx_pkt; +static struct net_buf *tx_payload; + +static struct device *radio_dev; +static struct ieee802154_radio_api *radio_api; + +static s8_t tx_power; + +static void dataInit(void) +{ + tx_pkt = net_pkt_get_reserve_tx(0, K_NO_WAIT); + __ASSERT_NO_MSG(tx_pkt != NULL); + + tx_payload = net_pkt_get_reserve_tx_data(0, K_NO_WAIT); + __ASSERT_NO_MSG(tx_payload != NULL); + + net_pkt_frag_insert(tx_pkt, tx_payload); + + sTransmitFrame.mPsdu = tx_payload->data; +} + +void platformRadioInit(void) +{ + dataInit(); + + radio_dev = device_get_binding(CONFIG_OT_PLAT_IEEE802154_RADIO_DEVICE_NAME); + __ASSERT_NO_MSG(radio_dev != NULL); + + radio_api = (struct ieee802154_radio_api *)radio_dev->driver_api; + + __ASSERT(radio_api->get_capabilities(radio_dev) + & IEEE802154_HW_TX_RX_ACK, + "Only radios with automatic ack handling " + "are currently supported"); +} + +void platformRadioProcess(otInstance *aInstance) +{ + if (sState == OT_RADIO_STATE_TRANSMIT) { + otError result = OT_ERROR_NONE; + + /* + * The payload is already in tx_payload->data, + * but we need to set the length field + * according to sTransmitFrame.length. + * We subtract the FCS size as radio driver + * adds CRC and increases frame length on its own. + */ + tx_payload->len = sTransmitFrame.mLength - FCS_SIZE; + + radio_api->set_channel(radio_dev, sTransmitFrame.mChannel); + radio_api->set_txpower(radio_dev, sTransmitFrame.mPower); + + if (radio_api->tx(radio_dev, tx_pkt, tx_payload)) { + result = OT_ERROR_CHANNEL_ACCESS_FAILURE; + } + + sState = OT_RADIO_STATE_RECEIVE; + +#if OPENTHREAD_ENABLE_DIAG + + if (otPlatDiagModeGet()) { + otPlatDiagRadioTransmitDone(aInstance, &sTransmitFrame, + result); + } else +#endif + { + if (sTransmitFrame.mPsdu[0] & 0x20) { + /* + * TODO: Get real ACK frame + * instead of making a spoofed one + */ + otRadioFrame ackFrame; + u8_t ackPsdu[] = {0x02, 0x00, 0x00, 0x00, 0x00}; + + ackPsdu[2] = sTransmitFrame.mPsdu[2]; + ackFrame.mPsdu = ackPsdu; + ackFrame.mLqi = 80; + ackFrame.mPower = -40; + ackFrame.mLength = 5; + + otPlatRadioTxDone(aInstance, &sTransmitFrame, + &ackFrame, result); + } else { + otPlatRadioTxDone(aInstance, &sTransmitFrame, + NULL, result); + } + } + } +} + +void otPlatRadioSetPanId(otInstance *aInstance, u16_t aPanId) +{ + ARG_UNUSED(aInstance); + + radio_api->set_filter(radio_dev, IEEE802154_FILTER_TYPE_PAN_ID, + (struct ieee802154_filter *) &aPanId); +} + +void otPlatRadioSetExtendedAddress(otInstance *aInstance, + const otExtAddress *aExtAddress) +{ + ARG_UNUSED(aInstance); + + radio_api->set_filter(radio_dev, IEEE802154_FILTER_TYPE_IEEE_ADDR, + (struct ieee802154_filter *) &aExtAddress); +} + +void otPlatRadioSetShortAddress(otInstance *aInstance, u16_t aShortAddress) +{ + ARG_UNUSED(aInstance); + + radio_api->set_filter(radio_dev, IEEE802154_FILTER_TYPE_SHORT_ADDR, + (struct ieee802154_filter *) &aShortAddress); +} + +bool otPlatRadioIsEnabled(otInstance *aInstance) +{ + ARG_UNUSED(aInstance); + + return (sState != OT_RADIO_STATE_DISABLED) ? true : false; +} + +otError otPlatRadioEnable(otInstance *aInstance) +{ + if (!otPlatRadioIsEnabled(aInstance)) { + sState = OT_RADIO_STATE_SLEEP; + } + + return OT_ERROR_NONE; +} + +otError otPlatRadioDisable(otInstance *aInstance) +{ + if (otPlatRadioIsEnabled(aInstance)) { + sState = OT_RADIO_STATE_DISABLED; + } + + return OT_ERROR_NONE; +} + +otError otPlatRadioSleep(otInstance *aInstance) +{ + ARG_UNUSED(aInstance); + + otError error = OT_ERROR_INVALID_STATE; + + if (sState == OT_RADIO_STATE_SLEEP || + sState == OT_RADIO_STATE_RECEIVE || + sState == OT_RADIO_STATE_TRANSMIT) { + error = OT_ERROR_NONE; + sState = OT_RADIO_STATE_SLEEP; + radio_api->stop(radio_dev); + } + + return error; +} + +otError otPlatRadioReceive(otInstance *aInstance, u8_t aChannel) +{ + ARG_UNUSED(aInstance); + + radio_api->set_channel(radio_dev, aChannel); + radio_api->set_txpower(radio_dev, tx_power); + radio_api->start(radio_dev); + sState = OT_RADIO_STATE_RECEIVE; + + return OT_ERROR_NONE; +} + +otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aPacket) +{ + otError error = OT_ERROR_INVALID_STATE; + + ARG_UNUSED(aInstance); + ARG_UNUSED(aPacket); + + __ASSERT_NO_MSG(aPacket == &sTransmitFrame); + + if (sState == OT_RADIO_STATE_RECEIVE) { + error = OT_ERROR_NONE; + sState = OT_RADIO_STATE_TRANSMIT; + PlatformEventSignalPending(); + } + + return error; +} + +otRadioFrame *otPlatRadioGetTransmitBuffer(otInstance *aInstance) +{ + ARG_UNUSED(aInstance); + + return &sTransmitFrame; +} + +int8_t otPlatRadioGetRssi(otInstance *aInstance) +{ + ARG_UNUSED(aInstance); + + /* TODO: No API in Zephyr to get the RSSI. */ + return 0; +} + +otRadioCaps otPlatRadioGetCaps(otInstance *aInstance) +{ + ARG_UNUSED(aInstance); + + return OT_RADIO_CAPS_NONE; +} + +bool otPlatRadioGetPromiscuous(otInstance *aInstance) +{ + ARG_UNUSED(aInstance); + + /* TODO: No API in Zephyr to get promiscuous mode. */ + bool result = false; + + SYS_LOG_DBG("PromiscuousMode=%d", result ? 1 : 0); + return result; +} + +void otPlatRadioSetPromiscuous(otInstance *aInstance, bool aEnable) +{ + ARG_UNUSED(aInstance); + ARG_UNUSED(aEnable); + + SYS_LOG_DBG("PromiscuousMode=%d", aEnable ? 1 : 0); + /* TODO: No API in Zephyr to set promiscuous mode. */ +} + +otError otPlatRadioEnergyScan(otInstance *aInstance, u8_t aScanChannel, + u16_t aScanDuration) +{ + ARG_UNUSED(aInstance); + ARG_UNUSED(aScanChannel); + ARG_UNUSED(aScanDuration); + + return OT_ERROR_NOT_IMPLEMENTED; +} + +void otPlatRadioEnableSrcMatch(otInstance *aInstance, bool aEnable) +{ + ARG_UNUSED(aInstance); + ARG_UNUSED(aEnable); +} + +otError otPlatRadioAddSrcMatchShortEntry(otInstance *aInstance, + const u16_t aShortAddress) +{ + ARG_UNUSED(aInstance); + ARG_UNUSED(aShortAddress); + + return OT_ERROR_NONE; +} + +otError otPlatRadioAddSrcMatchExtEntry(otInstance *aInstance, + const otExtAddress *aExtAddress) +{ + ARG_UNUSED(aInstance); + ARG_UNUSED(aExtAddress); + + return OT_ERROR_NONE; +} + +otError otPlatRadioClearSrcMatchShortEntry(otInstance *aInstance, + const u16_t aShortAddress) +{ + ARG_UNUSED(aInstance); + ARG_UNUSED(aShortAddress); + + return OT_ERROR_NONE; +} + +otError otPlatRadioClearSrcMatchExtEntry(otInstance *aInstance, + const otExtAddress *aExtAddress) +{ + ARG_UNUSED(aInstance); + ARG_UNUSED(aExtAddress); + + return OT_ERROR_NONE; +} + +void otPlatRadioClearSrcMatchShortEntries(otInstance *aInstance) +{ + ARG_UNUSED(aInstance); +} + +void otPlatRadioClearSrcMatchExtEntries(otInstance *aInstance) +{ + ARG_UNUSED(aInstance); +} + +int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance) +{ + ARG_UNUSED(aInstance); + + return -100; +} + +void otPlatRadioSetDefaultTxPower(otInstance *aInstance, int8_t aPower) +{ + ARG_UNUSED(aInstance); + + tx_power = aPower; +} diff --git a/subsys/net/lib/openthread/platform/random.c b/subsys/net/lib/openthread/platform/random.c new file mode 100644 index 00000000000000..563f9c0b092327 --- /dev/null +++ b/subsys/net/lib/openthread/platform/random.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2018 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include "platform-zephyr.h" + +uint32_t otPlatRandomGet(void) +{ + return sys_rand32_get(); +} + +otError otPlatRandomGetTrue(u8_t *aOutput, u16_t aOutputLength) +{ + int i; + u32_t random; + + if (!aOutput) { + return OT_ERROR_INVALID_ARGS; + } + + for (i = 0; i < (aOutputLength & 0xFFFC); i += 4) { + random = sys_rand32_get(); + memcpy(&aOutput[i], &random, sizeof(random)); + } + + random = sys_rand32_get(); + memcpy(&aOutput[i], &random, aOutputLength & 0x0003); + + return OT_ERROR_NONE; +} diff --git a/subsys/net/lib/openthread/platform/shell.c b/subsys/net/lib/openthread/platform/shell.c new file mode 100644 index 00000000000000..33e8e1cd0ba8e6 --- /dev/null +++ b/subsys/net/lib/openthread/platform/shell.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2018 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include "platform-zephyr.h" + +#define OT_SHELL_MODULE "ot" + +#define OT_SHELL_BUFFER_SIZE 256 + +static char rx_buffer[OT_SHELL_BUFFER_SIZE]; + +int otConsoleOutputCallback(const char *aBuf, uint16_t aBufLength, + void *aContext) +{ + ARG_UNUSED(aContext); + + printk("%s", aBuf); + + return aBufLength; +} + +static int ot_cmd(int argc, char *argv[]) +{ + char *buf_ptr = rx_buffer; + size_t buf_len = OT_SHELL_BUFFER_SIZE; + size_t arg_len = 0; + int i; + + if (argc < 2) { + return -1; + } + + for (i = 1; i < argc; i++) { + if (arg_len) { + buf_len -= arg_len + 1; + if (buf_len) { + buf_ptr[arg_len] = ' '; + } + buf_ptr += arg_len + 1; + } + + arg_len = snprintf(buf_ptr, buf_len, "%s", argv[i]); + + if (arg_len >= buf_len) { + printk("OT shell buffer full\n"); + return -1; + } + } + + if (i == argc) { + buf_len -= arg_len; + } + + otCliConsoleInputLine(rx_buffer, OT_SHELL_BUFFER_SIZE - buf_len); + + return 0; +} + +static struct shell_cmd ot_commands[] = { + { "cmd", ot_cmd, "OpenThread command" }, + {NULL, NULL, NULL} +}; + +void platformShellInit(otInstance *aInstance) +{ + SHELL_REGISTER(OT_SHELL_MODULE, ot_commands); + otCliConsoleInit(aInstance, otConsoleOutputCallback, NULL); +} + diff --git a/subsys/net/lib/openthread/platform/spi.c b/subsys/net/lib/openthread/platform/spi.c new file mode 100644 index 00000000000000..99bacfe72586f4 --- /dev/null +++ b/subsys/net/lib/openthread/platform/spi.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2018 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include "platform-zephyr.h" + +/* Spi-slave stubs */ + +otError otPlatSpiSlaveEnable( + otPlatSpiSlaveTransactionCompleteCallback aCompleteCallback, + otPlatSpiSlaveTransactionProcessCallback aProcessCallback, + void *aContext) +{ + ARG_UNUSED(aCompleteCallback); + ARG_UNUSED(aProcessCallback); + ARG_UNUSED(aContext); + + return OT_ERROR_NOT_IMPLEMENTED; +} + +void otPlatSpiSlaveDisable(void) +{ + /* Intentionally empty */ +} + +otError otPlatSpiSlavePrepareTransaction( + u8_t *anOutputBuf, + u16_t anOutputBufLen, + u8_t *anInputBuf, + u16_t anInputBufLen, + bool aRequestTransactionFlag +) +{ + ARG_UNUSED(anOutputBuf); + ARG_UNUSED(anOutputBufLen); + ARG_UNUSED(anInputBuf); + ARG_UNUSED(anInputBufLen); + ARG_UNUSED(aRequestTransactionFlag); + + return OT_ERROR_NOT_IMPLEMENTED; +} diff --git a/subsys/net/lib/openthread/zephyr-mbedtls-config.h b/subsys/net/lib/openthread/zephyr-mbedtls-config.h new file mode 100644 index 00000000000000..1fbbde5d4da26c --- /dev/null +++ b/subsys/net/lib/openthread/zephyr-mbedtls-config.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2018 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_MBEDTLS_CONFIG_H_ +#define ZEPHYR_MBEDTLS_CONFIG_H_ + +#define MBEDTLS_PLATFORM_EXIT_ALT + +#endif /* ZEPHYR_MBEDTLS_CONFIG_H_ */ From 44062ef0e3424efd5eeb09acab5c4ed9bda3dbf9 Mon Sep 17 00:00:00 2001 From: Kamil Sroka Date: Mon, 15 Jan 2018 11:38:21 +0100 Subject: [PATCH 3/6] include: net: net_l2: Add OpenThread L2 Add OpenThread L2 to L2 list. Signed-off-by: Kamil Sroka --- include/net/net_l2.h | 5 +++++ include/net/openthread.h | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 include/net/openthread.h diff --git a/include/net/net_l2.h b/include/net/net_l2.h index 3cf1bfab2161fa..761109fb5fd5a0 100644 --- a/include/net/net_l2.h +++ b/include/net/net_l2.h @@ -91,6 +91,11 @@ NET_L2_DECLARE_PUBLIC(BLUETOOTH_L2); NET_L2_DECLARE_PUBLIC(OFFLOAD_IP); #endif /* CONFIG_NET_OFFLOAD */ +#ifdef CONFIG_NET_L2_OPENTHREAD +#define OPENTHREAD_L2 OPENTHREAD +NET_L2_DECLARE_PUBLIC(OPENTHREAD_L2); +#endif /* CONFIG_NET_L2_OPENTHREAD */ + extern struct net_l2 __net_l2_end[]; #define NET_L2_INIT(_name, _recv_fn, _send_fn, _reserve_fn, _enable_fn) \ diff --git a/include/net/openthread.h b/include/net/openthread.h new file mode 100644 index 00000000000000..b48dfeb1e6a2af --- /dev/null +++ b/include/net/openthread.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2017 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __NET_OPENTHREAD_H_ +#define __NET_OPENTHREAD_H_ + +#include + +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct pkt_list_elem { + struct net_pkt *pkt; +}; + +struct openthread_context { + otInstance *instance; + struct net_if *iface; + u16_t pkt_list_in_idx; + u16_t pkt_list_out_idx; + u8_t pkt_list_full; + struct pkt_list_elem pkt_list[CONFIG_OPENTHREAD_PKT_LIST_SIZE]; +}; + +#define OPENTHREAD_L2_CTX_TYPE struct openthread_context + +#ifdef __cplusplus +} +#endif + +#endif /* __NET_OPENTHREAD_H_ */ From 806a8c391e69325b094bfe4e7ca19d92a7fc910b Mon Sep 17 00:00:00 2001 From: Kamil Sroka Date: Mon, 15 Jan 2018 11:39:54 +0100 Subject: [PATCH 4/6] drivers: 15.4: nrf5: Add OpenThread support to 802.15.4 driver Initially add support for OpenThread only for nRF 802.15.4 radio driver. Signed-off-by: Kamil Sroka --- drivers/ieee802154/CMakeLists.txt | 10 ++++++++++ drivers/ieee802154/Kconfig | 2 +- drivers/ieee802154/ieee802154_nrf5.c | 18 +++++++++++++++++- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/drivers/ieee802154/CMakeLists.txt b/drivers/ieee802154/CMakeLists.txt index e0af99c36a93c7..aef160192b5606 100644 --- a/drivers/ieee802154/CMakeLists.txt +++ b/drivers/ieee802154/CMakeLists.txt @@ -3,3 +3,13 @@ zephyr_sources_ifdef(CONFIG_IEEE802154_KW41Z ieee802154_kw41z.c) zephyr_sources_ifdef(CONFIG_IEEE802154_UPIPE ieee802154_uart_pipe.c) zephyr_sources_ifdef(CONFIG_IEEE802154_MCR20A ieee802154_mcr20a.c) zephyr_sources_ifdef(CONFIG_IEEE802154_NRF5 ieee802154_nrf5.c) +zephyr_sources_ifdef(CONFIG_IEEE802154_NRF5_RAW ieee802154_nrf5.c) + +if(CONFIG_NET_L2_OPENTHREAD) + # This driver calls DEVICE_INIT with the context of openthread. The + # context of openthread is defined in one of OpenThread's header + # files so we need express that this driver depends on OpenThread + # being downloaded to make sure that we don't build this driver + # before all of it's header file dependencies are met. + add_dependencies(${ZEPHYR_CURRENT_LIBRARY} ot) +endif() diff --git a/drivers/ieee802154/Kconfig b/drivers/ieee802154/Kconfig index e37069f44ed97b..e88c37f2670a80 100644 --- a/drivers/ieee802154/Kconfig +++ b/drivers/ieee802154/Kconfig @@ -12,7 +12,7 @@ menuconfig IEEE802154 bool "IEEE 802.15.4 drivers options" default n - default y if NET_L2_IEEE802154 + default y if NET_L2_IEEE802154 || NET_L2_OPENTHREAD if IEEE802154 diff --git a/drivers/ieee802154/ieee802154_nrf5.c b/drivers/ieee802154/ieee802154_nrf5.c index bb62918b20db70..251edea6eecae1 100644 --- a/drivers/ieee802154/ieee802154_nrf5.c +++ b/drivers/ieee802154/ieee802154_nrf5.c @@ -21,6 +21,10 @@ #include #include +#if defined(CONFIG_NET_L2_OPENTHREAD) +#include +#endif + #include #include #include @@ -90,7 +94,8 @@ static void nrf5_rx_thread(void *arg1, void *arg2, void *arg3) * The last 2 bytes contain LQI or FCS, depending if * automatic CRC handling is enabled or not, respectively. */ - if (IS_ENABLED(CONFIG_IEEE802154_RAW_MODE)) { + if (IS_ENABLED(CONFIG_IEEE802154_RAW_MODE) || + IS_ENABLED(CONFIG_NET_L2_OPENTHREAD)) { pkt_len = nrf5_radio->rx_psdu[0]; } else { pkt_len = nrf5_radio->rx_psdu[0] - NRF5_FCS_LENGTH; @@ -428,6 +433,17 @@ DEVICE_AND_API_INIT(nrf5_154_radio, CONFIG_IEEE802154_NRF5_DRV_NAME, nrf5_init, &nrf5_data, &nrf5_radio_cfg, POST_KERNEL, CONFIG_IEEE802154_NRF5_INIT_PRIO, &nrf5_radio_api); +#elif defined(CONFIG_NET_L2_OPENTHREAD) +NET_DEVICE_INIT(nrf5_154_radio, CONFIG_IEEE802154_NRF5_DRV_NAME, + nrf5_init, &nrf5_data, &nrf5_radio_cfg, + CONFIG_IEEE802154_NRF5_INIT_PRIO, + &nrf5_radio_api, OPENTHREAD_L2, + NET_L2_GET_CTX_TYPE(OPENTHREAD_L2), 1280); + +NET_STACK_INFO_ADDR(RX, nrf5_154_radio, + CONFIG_IEEE802154_NRF5_RX_STACK_SIZE, + CONFIG_IEEE802154_NRF5_RX_STACK_SIZE, + nrf5_data.rx_stack, 0); #else NET_DEVICE_INIT(nrf5_154_radio, CONFIG_IEEE802154_NRF5_DRV_NAME, nrf5_init, &nrf5_data, &nrf5_radio_cfg, From 4384396bc2570255040400195dd66bb776228d23 Mon Sep 17 00:00:00 2001 From: Kamil Sroka Date: Mon, 15 Jan 2018 11:42:28 +0100 Subject: [PATCH 5/6] subsys: net: ip: l2: Add OpenThread L2 Add OpenThread to Zephyrs net stack as data link layer. OpenThread requires to call process function when an event occurs. This process function is called from cooperative thread. Packet conversion and dispaching is implemented in openthread.c as well as addresses forwarding. Signed-off-by: Kamil Sroka --- subsys/net/ip/l2/CMakeLists.txt | 4 + subsys/net/ip/l2/Kconfig | 2 + subsys/net/ip/l2/openthread/CMakeLists.txt | 14 + subsys/net/ip/l2/openthread/Kconfig | 195 ++++++++++ subsys/net/ip/l2/openthread/openthread.c | 353 ++++++++++++++++++ .../net/ip/l2/openthread/openthread_utils.c | 247 ++++++++++++ .../net/ip/l2/openthread/openthread_utils.h | 42 +++ 7 files changed, 857 insertions(+) create mode 100644 subsys/net/ip/l2/openthread/CMakeLists.txt create mode 100644 subsys/net/ip/l2/openthread/Kconfig create mode 100644 subsys/net/ip/l2/openthread/openthread.c create mode 100644 subsys/net/ip/l2/openthread/openthread_utils.c create mode 100644 subsys/net/ip/l2/openthread/openthread_utils.h diff --git a/subsys/net/ip/l2/CMakeLists.txt b/subsys/net/ip/l2/CMakeLists.txt index 2a0cea04c3b510..abc7b3b912db1c 100644 --- a/subsys/net/ip/l2/CMakeLists.txt +++ b/subsys/net/ip/l2/CMakeLists.txt @@ -21,3 +21,7 @@ endif() if(CONFIG_NET_L2_IEEE802154) add_subdirectory(ieee802154) endif() + +if(CONFIG_NET_L2_OPENTHREAD) + add_subdirectory(openthread) +endif() diff --git a/subsys/net/ip/l2/Kconfig b/subsys/net/ip/l2/Kconfig index 6a090a04e2f8a1..f410c39423cedb 100644 --- a/subsys/net/ip/l2/Kconfig +++ b/subsys/net/ip/l2/Kconfig @@ -132,4 +132,6 @@ config NET_DEBUG_ARP help Enables core ARP code part to output debug messages +source "subsys/net/ip/l2/openthread/Kconfig" + endmenu diff --git a/subsys/net/ip/l2/openthread/CMakeLists.txt b/subsys/net/ip/l2/openthread/CMakeLists.txt new file mode 100644 index 00000000000000..e54529a9c98220 --- /dev/null +++ b/subsys/net/ip/l2/openthread/CMakeLists.txt @@ -0,0 +1,14 @@ +zephyr_library_named(subsys__net__ip__l2__openthread) +zephyr_library_include_directories(. ../..) +zephyr_library_compile_definitions_ifdef( + CONFIG_NEWLIB_LIBC __LINUX_ERRNO_EXTENSIONS__ + ) + +zephyr_library_sources( + openthread.c + openthread_utils.c + ) + +add_dependencies(subsys__net__ip__l2__openthread + ot + ) diff --git a/subsys/net/ip/l2/openthread/Kconfig b/subsys/net/ip/l2/openthread/Kconfig new file mode 100644 index 00000000000000..86c4ebad51e26c --- /dev/null +++ b/subsys/net/ip/l2/openthread/Kconfig @@ -0,0 +1,195 @@ +# Kconfig - OpenThread driver configuration options +# +# +# Copyright (c) 2018 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +# +# OpenThread options +# +menuconfig NET_L2_OPENTHREAD + bool + prompt "OpenThread L2" + depends on FLASH + depends on FLASH_PAGE_LAYOUT + depends on ENTROPY_GENERATOR + select OPENTHREAD_PLAT + +if NET_L2_OPENTHREAD + +config OPENTHREAD_PLAT +bool +depends on NET_L2_OPENTHREAD +default n +help +This option enables OpenThread platform + +if OPENTHREAD_PLAT + +menuconfig OPENTHREAD_DEBUG + bool + default n + prompt "OpenThread stack log support" + help + This option enables log support for OpenThread + +if OPENTHREAD_DEBUG + +choice + prompt "OpenThread stack log level" + help + This option selects log level for OpenThread stack. + +config OPENTHREAD_LOG_LEVEL_ERROR + bool "Error" +config OPENTHREAD_LOG_LEVEL_WARNING + bool "Warning" +config OPENTHREAD_LOG_LEVEL_INFO + bool "Info" +config OPENTHREAD_LOG_LEVEL_DEBUG + bool "Debug" +endchoice + +endif + +endif + +config OPENTHREAD_LOG_LEVEL + int + default 0 + default 1 if OPENTHREAD_LOG_LEVEL_ERROR + default 2 if OPENTHREAD_LOG_LEVEL_WARNING + default 3 if OPENTHREAD_LOG_LEVEL_INFO + default 4 if OPENTHREAD_LOG_LEVEL_DEBUG + +menuconfig OPENTHREAD_L2_DEBUG + bool + prompt "OpenThread L2 log support" + help + This option enables log support for OpenThread + +if OPENTHREAD_L2_DEBUG +choice + prompt "OpenThread L2 log level" + depends on OPENTHREAD_L2_DEBUG + help + This option selects log level for OpenThread driver. + +config OPENTHREAD_L2_LOG_LEVEL_ERROR + bool "Error" +config OPENTHREAD_L2_LOG_LEVEL_WARNING + bool "Warning" +config OPENTHREAD_L2_LOG_LEVEL_INFO + bool "Info" +config OPENTHREAD_L2_LOG_LEVEL_DEBUG + bool "Debug" +endchoice + +config OPENTHREAD_L2_DEBUG_DUMP_15_4 + bool + prompt "Dump 802.15.4 packets" + help + This option enables dumping of 802.15.4 packets + +config OPENTHREAD_L2_DEBUG_DUMP_IPV6 + bool + prompt "Dump IPv6 packets" + help + This option enables dumping of IPv6 packets + +endif + +config OPENTHREAD_L2_LOG_LEVEL + int + default 0 + default 1 if OPENTHREAD_L2_LOG_LEVEL_ERROR + default 2 if OPENTHREAD_L2_LOG_LEVEL_WARNING + default 3 if OPENTHREAD_L2_LOG_LEVEL_INFO + default 4 if OPENTHREAD_L2_LOG_LEVEL_DEBUG + +config OPENTHREAD_THREAD_PRIORITY + int + prompt "OpenThread thread priority" + default 8 + +config OPENTHREAD_THREAD_STACK_SIZE + int + prompt "OpenThread thread stack size" + default 3072 + +config OPENTHREAD_PKT_LIST_SIZE + int + prompt "List size for Ip6 packet buffering" + default 10 + +config OPENTHREAD_PANID + int + prompt "Default PAN ID" + default 43981 + +config OPENTHREAD_CHANNEL + int + prompt "Default Channel" + default 11 + +choice + prompt "OpenThread device type" + help + This option selects Thread network device type + +config OPENTHREAD_FTD + bool "FTD - Full Thread Device" +config OPENTHREAD_MTD + bool "MTD - Minimal Thread Device" +endchoice + +config OPENTHREAD_SHELL + bool + prompt "Enable OpenThread shell" + select CONSOLE_SHELL + default y + +config OPENTHREAD_DIAG + bool + prompt "Diagnostic functions support" + help + Enable OpenThread CLI diagnostic commands + +config OPENTHREAD_COMMISSIONER + bool + prompt "Commisioner functions support" + help + Enable commissioner capability in OpenThread stack + +config OPENTHREAD_JOINER + bool + prompt "Joiner functions support" + help + Enable joiner capability in OpenThread stack + +config OPENTHREAD_JAM_DETECTION + bool + prompt "Jam detection support" + help + Enable jam detection in OpenThread stack + +config OT_PLAT_FLASH_DEVICE_NAME + string + prompt "Flash device name" + default "NRF5_FLASH" + +config OT_PLAT_IEEE802154_RADIO_DEVICE_NAME + string + prompt "IEEE802.15.4 radio device name" + default "IEEE802154_nrf5" + +config OT_PLAT_FLASH_PAGES_COUNT + int + prompt "Flash pages count used by OpenThread platform" + default 4 + help + This option sets flash pages count used by OpenThread to store its settings. They are located at the end of flash. + +endif diff --git a/subsys/net/ip/l2/openthread/openthread.c b/subsys/net/ip/l2/openthread/openthread.c new file mode 100644 index 00000000000000..446b19cc1dd73c --- /dev/null +++ b/subsys/net/ip/l2/openthread/openthread.c @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2018 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define NET_SYS_LOG_LEVEL CONFIG_OPENTHREAD_L2_LOG_LEVEL + +#if defined(CONFIG_OPENTHREAD_L2_DEBUG) +#define NET_DOMAIN "net/openthread_l2" +#define NET_LOG_ENABLED 1 +#endif + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "openthread_utils.h" + +#define OT_STACK_SIZE (CONFIG_OPENTHREAD_THREAD_STACK_SIZE) +#define OT_PRIORITY K_PRIO_COOP(CONFIG_OPENTHREAD_THREAD_PRIORITY) + +extern void platformShellInit(otInstance *aInstance); + +K_SEM_DEFINE(ot_sem, 0, 1); + +K_THREAD_STACK_DEFINE(ot_stack_area, OT_STACK_SIZE); +static struct k_thread ot_thread_data; +static k_tid_t ot_tid; +static struct net_linkaddr *ll_addr; + +static struct net_mgmt_event_callback ip6_addr_cb; + +static void ipv6_addr_event_handler(struct net_mgmt_event_callback *cb, + u32_t mgmt_event, struct net_if *iface) +{ + struct openthread_context *ot_context = net_if_l2_data(iface); + + if (mgmt_event == NET_EVENT_IPV6_ADDR_ADD) { + add_ipv6_addr_to_ot(ot_context); + } else if (mgmt_event == NET_EVENT_IPV6_MADDR_ADD) { + add_ipv6_maddr_to_ot(ot_context); + } +} + +void otPlatRadioGetIeeeEui64(otInstance *instance, uint8_t *ieee_eui64) +{ + ARG_UNUSED(instance); + + memcpy(ieee_eui64, ll_addr->addr, ll_addr->len); +} + +void otTaskletsSignalPending(otInstance *instance) +{ + k_sem_give(&ot_sem); +} + +void PlatformEventSignalPending(void) +{ + k_sem_give(&ot_sem); +} + +void ot_state_changed_handler(u32_t flags, void *context) +{ + struct openthread_context *ot_context = context; + + NET_INFO("State changed! Flags: 0x%08x Current role: %d", + flags, otThreadGetDeviceRole(ot_context->instance)); + + if (flags & OT_CHANGED_IP6_ADDRESS_REMOVED) { + NET_DBG("Ipv6 address removed"); + rm_ipv6_addr_from_zephyr(ot_context); + rm_ipv6_maddr_from_zephyr(ot_context); + } + + if (flags & OT_CHANGED_IP6_ADDRESS_ADDED) { + NET_DBG("Ipv6 address added"); + add_ipv6_prefix_to_zephyr(ot_context); + add_ipv6_addr_to_zephyr(ot_context); + add_ipv6_maddr_to_zephyr(ot_context); + } + +} + +void ot_receive_handler(otMessage *aMessage, void *context) +{ + struct openthread_context *ot_context = context; + + u16_t offset = 0; + u16_t read_len; + struct net_pkt *pkt; + struct net_buf *prev_buf = NULL; + + pkt = net_pkt_get_reserve_rx(0, K_NO_WAIT); + if (!pkt) { + NET_ERR("Failed to reserve net pkt"); + goto out; + } + + while (1) { + struct net_buf *pkt_buf; + + pkt_buf = net_pkt_get_frag(pkt, K_NO_WAIT); + if (!pkt_buf) { + NET_ERR("Failed to get fragment buf"); + net_pkt_unref(pkt); + goto out; + } + + read_len = otMessageRead(aMessage, + offset, + pkt_buf->data, + net_buf_tailroom(pkt_buf)); + + if (!read_len) { + net_buf_unref(pkt_buf); + break; + } + + net_buf_add(pkt_buf, read_len); + + if (!prev_buf) { + net_pkt_frag_insert(pkt, pkt_buf); + } else { + net_buf_frag_insert(prev_buf, pkt_buf); + } + + prev_buf = pkt_buf; + + offset += read_len; + } + + NET_DBG("Injecting Ip6 packet to Zephyr net stack"); + +#if defined(CONFIG_OPENTHREAD_L2_DEBUG_DUMP_IPV6) + net_hexdump_frags("Received IPv6 packet", pkt, true); +#endif + + if (!pkt_list_is_full(ot_context)) { + if (net_recv_data(ot_context->iface, pkt) < 0) { + NET_ERR("net_recv_data failed"); + goto out; + } + + pkt_list_add(ot_context, pkt); + pkt = NULL; + } else { + NET_INFO("Pacet list is full"); + } +out: + if (pkt) { + net_pkt_unref(pkt); + } + + otMessageFree(aMessage); +} + +static void openthread_process(void *context, void *arg2, void *arg3) +{ + struct openthread_context *ot_context = context; + + while (1) { + while (otTaskletsArePending(ot_context->instance)) { + otTaskletsProcess(ot_context->instance); + } + + PlatformProcessDrivers(ot_context->instance); + + k_sem_take(&ot_sem, K_FOREVER); + } +} + +static enum net_verdict openthread_recv(struct net_if *iface, + struct net_pkt *pkt) +{ + struct openthread_context *ot_context = net_if_l2_data(iface); + + if (pkt_list_peek(ot_context) == pkt) { + pkt_list_remove_last(ot_context); + NET_DBG("Got injected Ip6 packet, " + "sending to upper layers"); +#if defined(CONFIG_OPENTHREAD_L2_DEBUG_DUMP_IPV6) + net_hexdump_frags("Injected IPv6 packet", pkt, true); +#endif + return NET_CONTINUE; + } + + NET_DBG("Got 802.15.4 packet, sending to OT"); + + otRadioFrame recv_frame; + + recv_frame.mPsdu = net_buf_frag_last(pkt->frags)->data; + /* Length inc. CRC. */ + recv_frame.mLength = net_buf_frags_len(pkt->frags); + /* TODO: get channel from packet */ + recv_frame.mChannel = CONFIG_OPENTHREAD_CHANNEL; + recv_frame.mLqi = net_pkt_ieee802154_lqi(pkt); + recv_frame.mPower = net_pkt_ieee802154_rssi(pkt); + +#if defined(CONFIG_OPENTHREAD_L2_DEBUG_DUMP_15_4) + net_hexdump_frags("Received 802.15.4 frame", pkt, true); +#endif + +#if OPENTHREAD_ENABLE_DIAG + if (otPlatDiagModeGet()) { + otPlatDiagRadioReceiveDone(ot_context->instance, + &recv_frame, OT_ERROR_NONE); + } else +#endif + { + otPlatRadioReceiveDone(ot_context->instance, + &recv_frame, OT_ERROR_NONE); + } + + net_pkt_unref(pkt); + + return NET_OK; +} + +enum net_verdict openthread_send(struct net_if *iface, struct net_pkt *pkt) +{ + struct openthread_context *ot_context = net_if_l2_data(iface); + enum net_verdict ret = NET_OK; + otMessage *message; + struct net_buf *frag; + + NET_DBG("Sending Ip6 packet to ot stack"); + + message = otIp6NewMessage(ot_context->instance, true); + if (message == NULL) { + goto exit; + } + + for (frag = pkt->frags; frag; frag = frag->frags) { + if (otMessageAppend(message, frag->data, + frag->len) != OT_ERROR_NONE) { + + NET_ERR("Error while appending to otMessage"); + otMessageFree(message); + goto exit; + } + } + + if (otIp6Send(ot_context->instance, message) != OT_ERROR_NONE) { + NET_ERR("Error while calling otIp6Send"); + goto exit; + } + +#if defined(CONFIG_OPENTHREAD_L2_DEBUG_DUMP_IPV6) + net_hexdump_frags("Sent IPv6 packet", pkt, true); +#endif + +exit: + + net_pkt_unref(pkt); + + return ret; +} + +static u16_t openthread_reserve(struct net_if *iface, void *arg) +{ + ARG_UNUSED(iface); + ARG_UNUSED(arg); + + return 0; +} + +enum net_verdict ieee802154_radio_handle_ack(struct net_if *iface, + struct net_buf *buf) +{ + ARG_UNUSED(iface); + ARG_UNUSED(buf); + NET_DBG(""); + + return NET_CONTINUE; +} + +static int openthread_init(struct net_if *iface) +{ + struct openthread_context *ot_context = net_if_l2_data(iface); + + NET_DBG("openthread_init"); + + PlatformInit(0, NULL); + + ot_context->instance = otInstanceInitSingle(); + ot_context->iface = iface; + + __ASSERT(ot_context->instance, "OT instance is NULL"); + +#if defined(CONFIG_OPENTHREAD_SHELL) + platformShellInit(ot_context->instance); +#endif + + NET_INFO("OpenThread version: %s", + otGetVersionString()); + NET_INFO("Network name: %s", + otThreadGetNetworkName(ot_context->instance)); + + otLinkSetChannel(ot_context->instance, CONFIG_OPENTHREAD_CHANNEL); + otLinkSetPanId(ot_context->instance, CONFIG_OPENTHREAD_PANID); + otIp6SetEnabled(ot_context->instance, true); + otThreadSetEnabled(ot_context->instance, true); + otIp6SetReceiveFilterEnabled(ot_context->instance, true); + otIp6SetReceiveCallback(ot_context->instance, + ot_receive_handler, ot_context); + otSetStateChangedCallback(ot_context->instance, + &ot_state_changed_handler, ot_context); + + ll_addr = net_if_get_link_addr(iface); + + net_mgmt_init_event_callback(&ip6_addr_cb, ipv6_addr_event_handler, + NET_EVENT_IPV6_ADDR_ADD | + NET_EVENT_IPV6_MADDR_ADD); + net_mgmt_add_event_callback(&ip6_addr_cb); + + ot_tid = k_thread_create(&ot_thread_data, ot_stack_area, + K_THREAD_STACK_SIZEOF(ot_stack_area), + openthread_process, + ot_context, NULL, NULL, + OT_PRIORITY, 0, K_NO_WAIT); + + return 0; +} + +void ieee802154_init(struct net_if *iface) +{ + openthread_init(iface); +} + +int ieee802154_radio_send(struct net_if *iface, struct net_pkt *pkt) +{ + ARG_UNUSED(iface); + ARG_UNUSED(pkt); + + /* Shouldnt be here */ + __ASSERT(false, "OpenThread L2 should never reach here"); + + return -EIO; +} + +NET_L2_INIT(OPENTHREAD_L2, openthread_recv, openthread_send, + openthread_reserve, NULL); diff --git a/subsys/net/ip/l2/openthread/openthread_utils.c b/subsys/net/ip/l2/openthread/openthread_utils.c new file mode 100644 index 00000000000000..5781cc4cbe47e8 --- /dev/null +++ b/subsys/net/ip/l2/openthread/openthread_utils.c @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2018 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define NET_SYS_LOG_LEVEL CONFIG_OPENTHREAD_L2_LOG_LEVEL + +#if defined(CONFIG_OPENTHREAD_L2_DEBUG) +#define NET_DOMAIN "net/openthread_l2" +#define NET_LOG_ENABLED 1 +#endif + +#include +#include +#include + +#include + +#include "openthread_utils.h" + +int pkt_list_add(struct openthread_context *context, struct net_pkt *pkt) +{ + u16_t i_idx = context->pkt_list_in_idx; + + if (context->pkt_list_full) { + return -ENOMEM; + } + + i_idx++; + if (i_idx == CONFIG_OPENTHREAD_PKT_LIST_SIZE) { + i_idx = 0; + } + + if (i_idx == context->pkt_list_out_idx) { + context->pkt_list_full = 1; + } + + context->pkt_list[context->pkt_list_in_idx].pkt = pkt; + context->pkt_list_in_idx = i_idx; + + return 0; +} + +struct net_pkt *pkt_list_peek(struct openthread_context *context) +{ + if ((context->pkt_list_in_idx == context->pkt_list_out_idx) && + (!context->pkt_list_full)) { + + return NULL; + } + return context->pkt_list[context->pkt_list_out_idx].pkt; +} + +void pkt_list_remove_last(struct openthread_context *context) +{ + if ((context->pkt_list_in_idx == context->pkt_list_out_idx) && + (!context->pkt_list_full)) { + + return; + } + + context->pkt_list_out_idx++; + if (context->pkt_list_out_idx == CONFIG_OPENTHREAD_PKT_LIST_SIZE) { + context->pkt_list_out_idx = 0; + } + + context->pkt_list_full = 0; +} + +void add_ipv6_addr_to_zephyr(struct openthread_context *context) +{ + const otNetifAddress *address; + + for (address = otIp6GetUnicastAddresses(context->instance); + address; address = address->mNext) { +#if CONFIG_OPENTHREAD_L2_LOG_LEVEL == SYS_LOG_LEVEL_DEBUG + char buf[NET_IPV6_ADDR_LEN]; + + NET_DBG("Adding %s", + net_addr_ntop(AF_INET6, + (struct in6_addr *)(&address->mAddress), + buf, sizeof(buf))); +#endif + net_if_ipv6_addr_add(context->iface, + (struct in6_addr *)(&address->mAddress), + NET_ADDR_ANY, 0); + } +} + +void add_ipv6_addr_to_ot(struct openthread_context *context) +{ + struct netif *iface = &context->iface; + struct otNetifAddress addr; + int i; + + memset(&addr, 0, sizeof(addr)); + + /* save the last added IP address for this interface */ + for (i = NET_IF_MAX_IPV6_ADDR - 1; i >= 0; i--) { + if (iface->ipv6.unicast[i].is_used) { + memcpy(&addr.mAddress, + &iface->ipv6.unicast[i].address.in6_addr, + sizeof(addr.mAddress)); + break; + } + } + + addr.mValid = true; + addr.mPreferred = true; + addr.mPrefixLength = 64; + + otIp6AddUnicastAddress(context->instance, &addr); + +#if CONFIG_OPENTHREAD_L2_LOG_LEVEL == SYS_LOG_LEVEL_DEBUG + char buf[NET_IPV6_ADDR_LEN]; + + NET_DBG("Added %s", net_addr_ntop(AF_INET6, + &laddr, buf, sizeof(buf))); +#endif +} + +void add_ipv6_maddr_to_ot(struct openthread_context *context) +{ + struct otIp6Address addr; + int i; + + /* save the last added IP address for this interface */ + for (i = NET_IF_MAX_IPV6_MADDR - 1; i >= 0; i--) { + if (context->iface->ipv6.mcast[i].is_used) { + memcpy(&addr, + &context->iface->ipv6.mcast[i].address.in6_addr, + sizeof(addr)); + break; + } + } + + otIp6SubscribeMulticastAddress(context->instance, &addr); + +#if CONFIG_OPENTHREAD_L2_LOG_LEVEL == SYS_LOG_LEVEL_DEBUG + char buf[NET_IPV6_ADDR_LEN]; + + NET_DBG("Added multicast %s", + net_addr_ntop(AF_INET6, &laddr, buf, sizeof(buf))); +#endif +} + +void add_ipv6_maddr_to_zephyr(struct openthread_context *context) +{ + const otNetifMulticastAddress *maddress; + + for (maddress = otIp6GetMulticastAddresses(context->instance); + maddress; maddress = maddress->mNext) { +#if CONFIG_OPENTHREAD_L2_LOG_LEVEL == SYS_LOG_LEVEL_DEBUG + char buf[NET_IPV6_ADDR_LEN]; + + NET_DBG("Adding multicast %s", + net_addr_ntop(AF_INET6, + (struct in6_addr *)(&maddress->mAddress), + buf, sizeof(buf))); +#endif + net_if_ipv6_maddr_add(context->iface, + (struct in6_addr *)(&maddress->mAddress)); + } +} + +void rm_ipv6_addr_from_zephyr(struct openthread_context *context) +{ + struct in6_addr *ot_addr; + struct net_if_addr *zephyr_addr; + int i; + + for (i = 0; i < NET_IF_MAX_IPV6_ADDR; i++) { + const otNetifAddress *address; + bool used = false; + + zephyr_addr = &context->iface->ipv6.unicast[i]; + if (!zephyr_addr->is_used) { + continue; + } + + for (address = otIp6GetUnicastAddresses(context->instance); + address; address = address->mNext) { + + ot_addr = (struct in6_addr *)(&address->mAddress); + if (net_ipv6_addr_cmp(ot_addr, + &zephyr_addr->address.in6_addr)) { + + used = true; + break; + } + } + if (!used) { +#if CONFIG_OPENTHREAD_L2_LOG_LEVEL == SYS_LOG_LEVEL_DEBUG + char buf[NET_IPV6_ADDR_LEN]; + + NET_DBG("Removing %s", + net_addr_ntop(AF_INET6, + &zephyr_addr->address.in6_addr, + buf, sizeof(buf))); +#endif + net_if_ipv6_addr_rm(context->iface, + &zephyr_addr->address.in6_addr); + } + } +} + +void rm_ipv6_maddr_from_zephyr(struct openthread_context *context) +{ + struct in6_addr *ot_addr; + struct net_if_mcast_addr *zephyr_addr; + int i; + + for (i = 0; i < NET_IF_MAX_IPV6_MADDR; i++) { + const otNetifMulticastAddress *maddress; + bool used = false; + + zephyr_addr = &context->iface->ipv6.mcast[i]; + if (!zephyr_addr->is_used) { + continue; + } + + for (maddress = otIp6GetMulticastAddresses(context->instance); + maddress; maddress = maddress->mNext) { + + ot_addr = (struct in6_addr *)(&maddress->mAddress); + if (net_ipv6_addr_cmp(ot_addr, + &zephyr_addr->address.in6_addr)) { + + used = true; + break; + } + } + if (!used) { +#if CONFIG_OPENTHREAD_L2_LOG_LEVEL == SYS_LOG_LEVEL_DEBUG + char buf[NET_IPV6_ADDR_LEN]; + + NET_DBG("Removing multicast %s", + net_addr_ntop(AF_INET6, + &zephyr_addr->address.in6_addr, + buf, sizeof(buf))); +#endif + net_if_ipv6_maddr_rm(context->iface, + &zephyr_addr->address.in6_addr); + } + } +} diff --git a/subsys/net/ip/l2/openthread/openthread_utils.h b/subsys/net/ip/l2/openthread/openthread_utils.h new file mode 100644 index 00000000000000..d5c48ff5315d32 --- /dev/null +++ b/subsys/net/ip/l2/openthread/openthread_utils.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2018 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __OPENTHREAD_UTILS_H__ +#define __OPENTHREAD_UTILS_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(CONFIG_OPENTHREAD_L2_DEBUG_DUMP_15_4) || \ + defined(CONFIG_OPENTHREAD_L2_DEBUG_DUMP_IPV6) + +void dump_pkt(const char *str, struct net_pkt *pkt); +#else +#define dump_pkt(...) +#endif + +void add_ipv6_addr_to_zephyr(struct openthread_context *context); +void add_ipv6_addr_to_ot(struct openthread_context *context); +void add_ipv6_maddr_to_ot(struct openthread_context *context); +void add_ipv6_maddr_to_zephyr(struct openthread_context *context); +void rm_ipv6_addr_from_zephyr(struct openthread_context *context); +void rm_ipv6_maddr_from_zephyr(struct openthread_context *context); + +int pkt_list_add(struct openthread_context *context, struct net_pkt *pkt); +struct net_pkt *pkt_list_peek(struct openthread_context *context); +void pkt_list_remove_last(struct openthread_context *context); + +inline int pkt_list_is_full(struct openthread_context *context) +{ + return context->pkt_list_full; +} + +#ifdef __cplusplus +} +#endif + +#endif /* __OPENTHREAD_UTILS_H__ */ From f7cd8dd05cad8e8566fc50556312ccc729a0cd5c Mon Sep 17 00:00:00 2001 From: Kamil Sroka Date: Mon, 15 Jan 2018 11:43:08 +0100 Subject: [PATCH 6/6] samples: net: Add config for OpenThread on nRF52840 Add samples config for nRF52840 with OpenThread for echo_client and echo_server. Signed-off-by: Kamil Sroka --- samples/net/echo_client/prj_nrf52840_ot.conf | 49 ++++++++++++++++++++ samples/net/echo_server/prj_nrf52840_ot.conf | 49 ++++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 samples/net/echo_client/prj_nrf52840_ot.conf create mode 100644 samples/net/echo_server/prj_nrf52840_ot.conf diff --git a/samples/net/echo_client/prj_nrf52840_ot.conf b/samples/net/echo_client/prj_nrf52840_ot.conf new file mode 100644 index 00000000000000..695c8545cb6295 --- /dev/null +++ b/samples/net/echo_client/prj_nrf52840_ot.conf @@ -0,0 +1,49 @@ +CONFIG_CPLUSPLUS=y + +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 + +CONFIG_BT=n + +CONFIG_NETWORKING=y +CONFIG_ENTROPY_GENERATOR=y +CONFIG_ENTROPY_NRF5_RNG=y + +CONFIG_NET_PKT_RX_COUNT=50 +CONFIG_NET_PKT_TX_COUNT=50 +CONFIG_NET_BUF_RX_COUNT=50 +CONFIG_NET_BUF_TX_COUNT=50 + +CONFIG_NET_TX_STACK_SIZE=2048 +CONFIG_NET_RX_STACK_SIZE=3072 + +CONFIG_NET_IPV4=n +CONFIG_NET_IPV6=y +CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=10 +CONFIG_NET_IPV6_NBR_CACHE=n +CONFIG_NET_IPV6_MLD=n + +CONFIG_REBOOT=y + +CONFIG_NET_LOG=y +CONFIG_SYS_LOG_SHOW_COLOR=y +CONFIG_PRINTK=y + +CONFIG_UART_INTERRUPT_DRIVEN=y + +CONFIG_FLASH=y +CONFIG_SOC_FLASH_NRF5=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_MPU_ALLOW_FLASH_WRITE=y + +CONFIG_NET_L2_OPENTHREAD=y +CONFIG_OPENTHREAD_L2_DEBUG=y +CONFIG_OPENTHREAD_L2_LOG_LEVEL_INFO=y +CONFIG_OPENTHREAD_CHANNEL=13 +CONFIG_IEEE802154_NRF5=y + +CONFIG_NET_APP=y +CONFIG_NET_APP_NEED_IPV6=y +CONFIG_NET_APP_CLIENT=y +CONFIG_NET_APP_SETTINGS=y +CONFIG_NET_APP_MY_IPV6_ADDR="fdde:ad00:beef::1" +CONFIG_NET_APP_PEER_IPV6_ADDR="fdde:ad00:beef::2" diff --git a/samples/net/echo_server/prj_nrf52840_ot.conf b/samples/net/echo_server/prj_nrf52840_ot.conf new file mode 100644 index 00000000000000..f78d26a8f1d20a --- /dev/null +++ b/samples/net/echo_server/prj_nrf52840_ot.conf @@ -0,0 +1,49 @@ +CONFIG_CPLUSPLUS=y + +CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000 + +CONFIG_BT=n + +CONFIG_NETWORKING=y +CONFIG_ENTROPY_GENERATOR=y +CONFIG_ENTROPY_NRF5_RNG=y + +CONFIG_NET_PKT_RX_COUNT=50 +CONFIG_NET_PKT_TX_COUNT=50 +CONFIG_NET_BUF_RX_COUNT=50 +CONFIG_NET_BUF_TX_COUNT=50 + +CONFIG_NET_TX_STACK_SIZE=2048 +CONFIG_NET_RX_STACK_SIZE=3072 + +CONFIG_NET_IPV4=n +CONFIG_NET_IPV6=y +CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=10 +CONFIG_NET_IPV6_NBR_CACHE=n +CONFIG_NET_IPV6_MLD=n + +CONFIG_REBOOT=y + +CONFIG_NET_LOG=y +CONFIG_SYS_LOG_SHOW_COLOR=y +CONFIG_PRINTK=y + +CONFIG_UART_INTERRUPT_DRIVEN=y + +CONFIG_FLASH=y +CONFIG_SOC_FLASH_NRF5=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_MPU_ALLOW_FLASH_WRITE=y + +CONFIG_IEEE802154_NRF5=y +CONFIG_NET_L2_OPENTHREAD=y +CONFIG_OPENTHREAD_L2_DEBUG=y +CONFIG_OPENTHREAD_L2_LOG_LEVEL_INFO=y +CONFIG_OPENTHREAD_CHANNEL=13 + +CONFIG_NET_APP=y +CONFIG_NET_APP_NEED_IPV6=y +CONFIG_NET_APP_SERVER=y +CONFIG_NET_APP_SETTINGS=y +CONFIG_NET_APP_MY_IPV6_ADDR="fdde:ad00:beef::2" +CONFIG_NET_APP_PEER_IPV6_ADDR="fdde:ad00:beef::1"