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, 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/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; 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_ */ 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" 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__ */ 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_ */