From e012df1bacb1f41de9957e640873d481e41a3567 Mon Sep 17 00:00:00 2001 From: Kaspar Schleiser Date: Sat, 9 Jul 2016 11:25:34 +0200 Subject: [PATCH] nrf52dk: add BLE/6lo support utilizing Nordic's SoftDevice --- Makefile.dep | 11 + boards/nrf52dk/Makefile.dep | 4 + boards/nrf52dk/Makefile.include | 7 + boards/nrf52dk/include/periph_conf.h | 10 +- cpu/nrf52/cpu.c | 24 +- cpu/nrf52/include/cpu_conf.h | 17 +- cpu/nrf52/ldscripts/nrf52xxaa_sd.ld | 27 ++ cpu/nrf52/vectors.c | 28 +- pkg/nordic_softdevice_ble/Makefile | 49 +++ pkg/nordic_softdevice_ble/Makefile.include | 32 ++ pkg/nordic_softdevice_ble/Makefile.module | 1 + .../README-BLE-6LoWPAN.md | 100 ++++++ pkg/nordic_softdevice_ble/README.md | 30 ++ pkg/nordic_softdevice_ble/src/Makefile | 2 + pkg/nordic_softdevice_ble/src/app_error.c | 9 + pkg/nordic_softdevice_ble/src/ble-core.c | 235 +++++++++++++ pkg/nordic_softdevice_ble/src/ble-core.h | 61 ++++ pkg/nordic_softdevice_ble/src/ble-mac.c | 305 +++++++++++++++++ pkg/nordic_softdevice_ble/src/ble-mac.h | 50 +++ .../src/gnrc_nordic_ble_6lowpan.c | 318 ++++++++++++++++++ .../src/gnrc_nordic_ble_6lowpan.h | 43 +++ sys/auto_init/auto_init.c | 5 + 22 files changed, 1355 insertions(+), 13 deletions(-) create mode 100644 cpu/nrf52/ldscripts/nrf52xxaa_sd.ld create mode 100644 pkg/nordic_softdevice_ble/Makefile create mode 100644 pkg/nordic_softdevice_ble/Makefile.include create mode 100644 pkg/nordic_softdevice_ble/Makefile.module create mode 100644 pkg/nordic_softdevice_ble/README-BLE-6LoWPAN.md create mode 100644 pkg/nordic_softdevice_ble/README.md create mode 100644 pkg/nordic_softdevice_ble/src/Makefile create mode 100644 pkg/nordic_softdevice_ble/src/app_error.c create mode 100644 pkg/nordic_softdevice_ble/src/ble-core.c create mode 100644 pkg/nordic_softdevice_ble/src/ble-core.h create mode 100644 pkg/nordic_softdevice_ble/src/ble-mac.c create mode 100644 pkg/nordic_softdevice_ble/src/ble-mac.h create mode 100644 pkg/nordic_softdevice_ble/src/gnrc_nordic_ble_6lowpan.c create mode 100644 pkg/nordic_softdevice_ble/src/gnrc_nordic_ble_6lowpan.h diff --git a/Makefile.dep b/Makefile.dep index 97650d319af4..6d14cf96e67c 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -31,6 +31,17 @@ ifneq (,$(filter gnrc_uhcpc,$(USEMODULE))) USEMODULE += fmt endif +ifneq (,$(filter nordic_softdevice_ble,$(USEPKG))) + USEMODULE += softdevice_handler + USEMODULE += ble_common + USEMODULE += ble_6lowpan + USEMODULE += gnrc_sixlowpan + USEMODULE += gnrc_sixlowpan_iphc + USEMODULE += gnrc_ipv6_default + USEMODULE += gnrc_netdev2 + USEMODULE += gnrc_ipv6_netif +endif + ifneq (,$(filter gnrc_%,$(filter-out gnrc_netapi gnrc_netreg gnrc_netif% gnrc_pktbuf,$(USEMODULE)))) USEMODULE += gnrc endif diff --git a/boards/nrf52dk/Makefile.dep b/boards/nrf52dk/Makefile.dep index 5472bf8b8d8f..27225b7b405a 100644 --- a/boards/nrf52dk/Makefile.dep +++ b/boards/nrf52dk/Makefile.dep @@ -1,3 +1,7 @@ ifneq (,$(filter saul_default,$(USEMODULE))) USEMODULE += saul_gpio endif + +ifneq (,$(filter gnrc_netdev_default,$(USEMODULE))) + USEPKG += nordic_softdevice_ble +endif diff --git a/boards/nrf52dk/Makefile.include b/boards/nrf52dk/Makefile.include index e16b064a4d57..b2404fafa3fd 100644 --- a/boards/nrf52dk/Makefile.include +++ b/boards/nrf52dk/Makefile.include @@ -11,6 +11,13 @@ include $(RIOTBOARD)/$(BOARD)/Makefile.dep # setup JLink for flashing export JLINK_DEVICE := nrf52 + +# special options when using SoftDevice +ifneq (,$(filter nordic_softdevice_ble,$(USEPKG))) +export JLINK_PRE_FLASH := loadfile $(BINDIR)/softdevice.hex +export JLINK_FLASH_ADDR := 0x1f000 +export LINKER_SCRIPT ?= $(RIOTCPU)/$(CPU)/ldscripts/$(CPU_MODEL)_sd.ld +endif include $(RIOTBOARD)/Makefile.include.jlink # setup serial terminal diff --git a/boards/nrf52dk/include/periph_conf.h b/boards/nrf52dk/include/periph_conf.h index 753d740749d4..2975d5968f1f 100644 --- a/boards/nrf52dk/include/periph_conf.h +++ b/boards/nrf52dk/include/periph_conf.h @@ -44,10 +44,10 @@ extern "C" { */ static const timer_conf_t timer_config[] = { /* dev, channels, width, IRQn */ - { NRF_TIMER0, 3, TIMER_BITMODE_BITMODE_32Bit, TIMER0_IRQn } + { NRF_TIMER1, 3, TIMER_BITMODE_BITMODE_32Bit, TIMER1_IRQn } }; -#define TIMER_0_ISR isr_timer0 +#define TIMER_0_ISR isr_timer1 #define TIMER_NUMOF (sizeof(timer_config) / sizeof(timer_config[0])) /** @} */ @@ -57,9 +57,9 @@ static const timer_conf_t timer_config[] = { * @{ */ #define RTT_NUMOF (1U) -#define RTT_DEV NRF_RTC0 -#define RTT_IRQ RTC0_IRQn -#define RTT_ISR isr_rtc0 +#define RTT_DEV NRF_RTC1 +#define RTT_IRQ RTC1_IRQn +#define RTT_ISR isr_rtc1 #define RTT_MAX_VALUE (0xffffff) #define RTT_FREQUENCY (10) /* in Hz */ #define RTT_PRESCALER (3275U) /* run with 10 Hz */ diff --git a/cpu/nrf52/cpu.c b/cpu/nrf52/cpu.c index 9e72b02264ae..173531915d3c 100644 --- a/cpu/nrf52/cpu.c +++ b/cpu/nrf52/cpu.c @@ -20,6 +20,8 @@ * @} */ +#define DONT_OVERRIDE_NVIC + #include "cpu.h" #include "periph_conf.h" @@ -28,14 +30,16 @@ static bool ftpan_32(void); static bool ftpan_37(void); static bool ftpan_36(void); +#ifdef SOFTDEVICE_PRESENT +#include "softdevice_handler.h" +uint8_t _ble_evt_buffer[BLE_STACK_EVT_MSG_BUF_SIZE]; +#endif + /** * @brief Initialize the CPU, set IRQ priorities */ void cpu_init(void) { - /* set pendSV interrupt to lowest possible priority */ - NVIC_SetPriority(PendSV_IRQn, 0xff); - /* Workaround for FTPAN-32 * "DIF: Debug session automatically enables TracePort pins." */ if (ftpan_32()) { @@ -64,6 +68,20 @@ void cpu_init(void) while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0); #endif + + /* softdevice needs to be enabled from ISR context */ +#ifdef SOFTDEVICE_PRESENT + softdevice_handler_init(NRF_CLOCK_LFCLKSRC_XTAL_20_PPM, &_ble_evt_buffer, + BLE_STACK_EVT_MSG_BUF_SIZE, NULL); +#endif + /* call cortexm default initialization */ + cortexm_init(); + +#ifdef SOFTDEVICE_PRESENT + /* fixup swi0 (used as softdevice PendSV trampoline) */ + NVIC_EnableIRQ(SWI0_EGU0_IRQn); + NVIC_SetPriority(SWI0_EGU0_IRQn, 6); +#endif } /** diff --git a/cpu/nrf52/include/cpu_conf.h b/cpu/nrf52/include/cpu_conf.h index 066b1cfbcac7..5a60cae047ab 100644 --- a/cpu/nrf52/include/cpu_conf.h +++ b/cpu/nrf52/include/cpu_conf.h @@ -32,11 +32,24 @@ extern "C" { * @brief ARM Cortex-M specific CPU configuration * @{ */ -#define CPU_DEFAULT_IRQ_PRIO (1U) -#define CPU_IRQ_NUMOF (38) +#define CPU_DEFAULT_IRQ_PRIO (2U) +#define CPU_IRQ_NUMOF (38U) #define CPU_FLASH_BASE (0x00000000) /** @} */ +/** + * @brief SoftDevice settings + * @{ + */ +#ifdef SOFTDEVICE_PRESENT +#ifndef DONT_OVERRIDE_NVIC +#include "nrf_soc.h" +#undef NVIC_SetPriority +#define NVIC_SetPriority sd_nvic_SetPriority +#endif /* DONT_OVERRIDE_NVIC */ +#endif /* SOFTDEVICE_PRESENT */ +/** @} */ + #ifdef __cplusplus } #endif diff --git a/cpu/nrf52/ldscripts/nrf52xxaa_sd.ld b/cpu/nrf52/ldscripts/nrf52xxaa_sd.ld new file mode 100644 index 000000000000..1b9f09172267 --- /dev/null +++ b/cpu/nrf52/ldscripts/nrf52xxaa_sd.ld @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2016 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @addtogroup cpu_nrf52 + * @{ + * + * @file + * @brief Memory definitions for the NRF52832XXAA + * + * @author Hauke Petersen + * + * @} + */ + +MEMORY +{ + rom (rx) : ORIGIN = 0x1f000, LENGTH = 0x61000 + ram (rwx) : ORIGIN = 0x20002800, LENGTH = 0xD800 +} + +INCLUDE cortexm_base.ld diff --git a/cpu/nrf52/vectors.c b/cpu/nrf52/vectors.c index 20e043de6791..0cb88e47e11b 100644 --- a/cpu/nrf52/vectors.c +++ b/cpu/nrf52/vectors.c @@ -58,7 +58,21 @@ WEAK_DEFAULT void isr_wdt(void); WEAK_DEFAULT void isr_rtc1(void); WEAK_DEFAULT void isr_qdec(void); WEAK_DEFAULT void isr_lpcomp(void); + +#ifndef SOFTDEVICE_PRESENT WEAK_DEFAULT void isr_swi0(void); +#else +/* For unknown reasons, setting PendSV pending within + * the softdevice ISRs leads to a crash. This workaround + * uses swi0 as trampoline. + */ +extern void thread_arch_yield(void); +void isr_swi0(void) +{ + thread_arch_yield(); +} +#endif + WEAK_DEFAULT void isr_swi1(void); WEAK_DEFAULT void isr_swi2(void); WEAK_DEFAULT void isr_swi3(void); @@ -76,6 +90,10 @@ WEAK_DEFAULT void isr_rtc2(void); WEAK_DEFAULT void isr_i2s(void); +#ifdef SOFTDEVICE_PRESENT +extern void SWI2_EGU2_IRQHandler(void); +#endif + /* interrupt vector table */ ISR_VECTORS const void *interrupt_vector[] = { /* Exception stack pointer */ @@ -121,10 +139,14 @@ ISR_VECTORS const void *interrupt_vector[] = { (void *) isr_lpcomp, /* lpcomp */ (void *) isr_swi0, /* swi0 */ (void *) isr_swi1, /* swi1 */ +#ifdef SOFTDEVICE_PRESENT + (void *) SWI2_EGU2_IRQHandler, /* softdevice swi handler */ +#else (void *) isr_swi2, /* swi2 */ - (void *) isr_swi3, /* swi3 */ - (void *) isr_swi4, /* swi4 */ - (void *) isr_swi5, /* swi5 */ +#endif + (void *) (0UL), /* swi3 */ + (void *) (0UL), /* swi4 */ + (void *) (0UL), /* swi5 */ (void *) isr_timer3, /* timer 3 */ (void *) isr_timer4, /* timer 4 */ (void *) isr_pwm0, /* pwm 0 */ diff --git a/pkg/nordic_softdevice_ble/Makefile b/pkg/nordic_softdevice_ble/Makefile new file mode 100644 index 000000000000..0e44c05d940f --- /dev/null +++ b/pkg/nordic_softdevice_ble/Makefile @@ -0,0 +1,49 @@ +PKG_NAME = nordic_softdevice_ble +PKG_VERSION = 3288530 +PKG_FILE = nrf5_iot_sdk_$(PKG_VERSION).zip +PKG_URL = https://developer.nordicsemi.com/nRF5_IoT_SDK/nRF5_IoT_SDK_v0.9.x/$(PKG_FILE) +PKG_DIR=$(CURDIR) +PKG_BUILDDIR=$(BINDIRBASE)/pkg/$(BOARD)/$(PKG_NAME) +PKG_SRCDIR=$(PKG_BUILDDIR)/src + +SOFTDEVICE := components/softdevice/s1xx_iot/s1xx-iot-prototype3_nrf52_softdevice.hex +BLE_6LOWPAN_LIB := components/iot/ble_6lowpan/lib/ble_6lowpan.a +MODULE_MAKEFILE := $(PKG_DIR)/Makefile.module + +.PHONY: all clean distclean + +all: $(BINDIR)/ble_6lowpan.a $(BINDIR)/softdevice.hex + +$(BINDIR)/ble_6lowpan.a: $(PKG_SRCDIR)/.extracted + cp $(PKG_SRCDIR)/$(BLE_6LOWPAN_LIB) $@ + +$(BINDIR)/softdevice.hex: $(PKG_SRCDIR)/.extracted + cp $(PKG_SRCDIR)/$(SOFTDEVICE) $@ + +$(PKG_SRCDIR)/.extracted: $(PKG_BUILDDIR)/$(PKG_FILE) + rm -rf $(@D) + mkdir -p $(@D) + $(AD)cd $(@D) && $(UNZIP_HERE) $(PKG_BUILDDIR)/$(PKG_FILE) + +# this file doesn't compile with RIOT, but is not needed either + rm $(PKG_BUILDDIR)/src/components/ble/common/ble_conn_params.c + +# setup RIOT module makefiles for nordic SDK components + cat $(MODULE_MAKEFILE) > $(PKG_SRCDIR)/components/softdevice/common/softdevice_handler/Makefile + + echo "MODULE=ble_common" > $(PKG_SRCDIR)/components/ble/common/Makefile + cat $(MODULE_MAKEFILE) >> $(PKG_SRCDIR)/components/ble/common/Makefile + + cat $(MODULE_MAKEFILE) > $(PKG_SRCDIR)/components/iot/ble_ipsp/Makefile + + touch $@ + +$(PKG_BUILDDIR)/$(PKG_FILE): + @mkdir -p $(@D) + $(AD)$(DOWNLOAD_TO_FILE) $@ $(PKG_URL) + +clean:: + rm -rf $(PKG_SRCDIR)/ + +distclean:: + rm -rf $(PKG_BUILDDIR)/ diff --git a/pkg/nordic_softdevice_ble/Makefile.include b/pkg/nordic_softdevice_ble/Makefile.include new file mode 100644 index 000000000000..138595464e1e --- /dev/null +++ b/pkg/nordic_softdevice_ble/Makefile.include @@ -0,0 +1,32 @@ +NORDIC_SRCS := $(BINDIRBASE)/pkg/$(BOARD)/nordic_softdevice_ble/src + +INCLUDES += \ + -I$(RIOTBASE)/pkg/nordic_softdevice_ble/src \ + -I$(NORDIC_SRCS)/components/ble/common \ + -I$(NORDIC_SRCS)/components/device \ + -I$(NORDIC_SRCS)/components/iot/ble_6lowpan \ + -I$(NORDIC_SRCS)/components/iot/ble_ipsp \ + -I$(NORDIC_SRCS)/components/iot/common \ + -I$(NORDIC_SRCS)/components/libraries/scheduler \ + -I$(NORDIC_SRCS)/components/libraries/util \ + -I$(NORDIC_SRCS)/components/softdevice/common/softdevice_handler \ + -I$(NORDIC_SRCS)/components/softdevice/s1xx_iot/headers \ + -I$(NORDIC_SRCS)/components/softdevice/s1xx_iot/headers/nrf52 \ + -I$(NORDIC_SRCS)/components/toolchain + +CFLAGS += -DNRF52 \ + -DBLE_STACK_SUPPORT_REQD \ + -DISR_STACKSIZE=8192 \ + -DSOFTDEVICE_PRESENT \ + -DS132 + +# Nordic's ble_6lowpan.a is compiled with hard-float +# so set this, otherwise linking fails +CFLAGS_FPU := -mfloat-abi=hard -mfpu=fpv4-sp-d16 + +DIRS += \ + $(RIOTBASE)/pkg/nordic_softdevice_ble/src \ + $(NORDIC_SRCS)/components/softdevice/common/softdevice_handler \ + $(NORDIC_SRCS)/components/ble/common \ + $(NORDIC_SRCS)/components/iot/ble_ipsp + diff --git a/pkg/nordic_softdevice_ble/Makefile.module b/pkg/nordic_softdevice_ble/Makefile.module new file mode 100644 index 000000000000..48422e909a47 --- /dev/null +++ b/pkg/nordic_softdevice_ble/Makefile.module @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/pkg/nordic_softdevice_ble/README-BLE-6LoWPAN.md b/pkg/nordic_softdevice_ble/README-BLE-6LoWPAN.md new file mode 100644 index 000000000000..3ac44423697d --- /dev/null +++ b/pkg/nordic_softdevice_ble/README-BLE-6LoWPAN.md @@ -0,0 +1,100 @@ +This README contains information how to establish an IPv6 connecton between +Linux BLE router and an IPSP enabled BLE device. + +Prerequisites +============= +In general, any device capable of running Linux operating system, can be used +as a BLE router provided the following conditions are met: + +* Linux Kernel >3.18 is used +* bluez, libcap-ng0, radvd tools are present. + +If a built-in Bluetooth device is not available then Bluetooth 4.0 compatible +USB dongle can be used. + +The following procedures have been tested on Ubuntu 15.10. + +Establishing an IPv6 connection +=============================== +Use the following procedure to establish a connection between an nRF52 device +and Linux router: + +First enable 6LoWPAN module. This is neccessary only once per session: + + # Log in as a root user. + sudo su + + # Mount debugfs file system. + mount -t debugfs none /sys/kernel/debug + + # Load 6LoWPAN module. + modprobe bluetooth_6lowpan + + # Enable the bluetooth 6lowpan module. + echo 1 > /sys/kernel/debug/bluetooth/6lowpan_enable + + # Look for available HCI devices. + hciconfig + + # Reset HCI device - for example hci0 device. + hciconfig hci0 reset + + # Read 00:AA:BB:XX:YY:ZZ address of the nRF5x device. + hcitool lescan + +If you see device name and address in lescan output then you can connect to the +device: + + echo "connect 00:AA:BB:XX:YY:ZZ 1" > /sys/kernel/debug/bluetooth/6lowpan_control + +If above is successful then LED1 will stop blinking and LED2 will switch on. +You can then check the connection using the following commands: + + # Check if bt0 interface is present and up + ifconfig + + # Try to ping the device using its link-local address, for example, on bt0 interface. + ping6 fe80::2aa:bbff:fexx:yyzz%bt0 + +If you'd like to learn more about the procedure please refer to +[Connecting devices to the router]. + +Distributing routable IPv6 prefix +================================= +In Linux, Router Advertisement Daemon (RADVD) can be used to distribute prefixes +in the network, hance configure routable IPv6 address. + +To configure RADVD create `/etc/radvd.conf` file and paste the following contents: + + interface bt0 + { + AdvSendAdvert on; + prefix 2001:db8::/64 + { + AdvOnLink off; + AdvAutonomous on; + AdvRouterAddr on; + }; + }; + +Next, start RADVD daemon: + + # Set IPv6 forwarding (must be present). + sudo echo 1 > /proc/sys/net/ipv6/conf/all/forwarding + # Run radvd daemon. + sudo service radvd restart + +If successfull then all devices connected to the host will receive +a routable `2001:db8` prefix. + +This can be verified by sending echo request to the full address: + + ping6 -I bt0 2001:db8::2aa:bbff:fexx:yyzz + +where `aa:bbff:fexx:yyzz` is device Bluetooth address. + +If you'd like to learn more about the procedure please refer to +[Distributing a global IPv6 prefix]. + +* [Connecting devices to the router]: http://developer.nordicsemi.com/nRF5_IoT_SDK/doc/0.9.0/html/a00089.html +* [Distributing a global IPv6 prefix]: http://developer.nordicsemi.com/nRF5_IoT_SDK/doc/0.9.0/html/a00090.html diff --git a/pkg/nordic_softdevice_ble/README.md b/pkg/nordic_softdevice_ble/README.md new file mode 100644 index 000000000000..3cb357d3635e --- /dev/null +++ b/pkg/nordic_softdevice_ble/README.md @@ -0,0 +1,30 @@ +# Overview + +This package provides necessary Makefiles and glue code to use the Nordic S132 +SoftDevice as Bluetooth BLE transport for RIOT's 6lowpan stack. + +# Usage + +"gnrc_netdev_default" has a dependency to "nordic_softdevice_ble", so all +examples automatically download the SDK and compile / link / flash all needed +code. + +If you want to manually set up included modules, add "USEPKG += +nordic_softdevice_ble" to your application's Makefile. + +See README-BLE-6LoWPAN.md for instructions on how to set up 6lowpan over BLE on +Linux. + +# Known issues + +- floating point ABI mismatch + +The Nordic binaries are compiled using hard float ABI, which RIOT currently +doesn't support (RIOT's context switching code doesn't preserve the floating +point registers). If the softdevice is compiled in, RIOT will be compiled with +hard float ABI in order for the linking to succeed. This works for some +application, but will lead to serious and hard-to-find bugs for code using +floating point instructions. + +Hopefully, either the RIOT community adds hard-float support, or Nordic +releases a soft-float version of the used binaries. diff --git a/pkg/nordic_softdevice_ble/src/Makefile b/pkg/nordic_softdevice_ble/src/Makefile new file mode 100644 index 000000000000..d8f0fd1b273a --- /dev/null +++ b/pkg/nordic_softdevice_ble/src/Makefile @@ -0,0 +1,2 @@ +MODULE = nordic_softdevice_ble +include $(RIOTBASE)/Makefile.base diff --git a/pkg/nordic_softdevice_ble/src/app_error.c b/pkg/nordic_softdevice_ble/src/app_error.c new file mode 100644 index 000000000000..cb3d92833483 --- /dev/null +++ b/pkg/nordic_softdevice_ble/src/app_error.c @@ -0,0 +1,9 @@ +#include "app_error.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +void app_error_handler(uint32_t error_code, uint32_t line_num, const uint8_t *p_file_name) +{ + puts("nordic softdevice app_error_handler()"); +} diff --git a/pkg/nordic_softdevice_ble/src/ble-core.c b/pkg/nordic_softdevice_ble/src/ble-core.c new file mode 100644 index 000000000000..7c02da95e5c8 --- /dev/null +++ b/pkg/nordic_softdevice_ble/src/ble-core.c @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2016, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ +/** + * @addtogroup cpu + * @{ + * + * @addtogroup nrf52832 + * @{ + * + * @addtogroup nrf52832-ble Bluetooth Low Energy drivers + * @{ + * + * @file + * Basic BLE functions. + * @author + * Wojciech Bober + * Kaspar Schleiser + * + */ +#include +#include + +//#include "boards.h" +//#include "nordic_common.h" +//#include "nrf_delay.h" +#include "nrf_sdm.h" +#include "ble_advdata.h" +#include "ble_srv_common.h" +#include "ble_ipsp.h" +#include "softdevice_handler.h" +#include "app_error.h" +#include "iot_defines.h" +#include "ble-core.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#define IS_SRVC_CHANGED_CHARACT_PRESENT 1 +#define APP_ADV_TIMEOUT 0 /**< Time for which the device must be advertising in non-connectable mode (in seconds). 0 disables timeout. */ +#define APP_ADV_ADV_INTERVAL MSEC_TO_UNITS(333, UNIT_0_625_MS) /**< The advertising interval. This value can vary between 100ms to 10.24s). */ + +static ble_gap_adv_params_t m_adv_params; /**< Parameters to be passed to the stack when starting advertising. */ + +static void +ble_evt_dispatch(ble_evt_t * p_ble_evt); +/*---------------------------------------------------------------------------*/ +/** + * @brief Initialize and enable the BLE stack. + */ +void +ble_stack_init(void) +{ + uint32_t err_code; + + // Enable BLE stack. + ble_enable_params_t ble_enable_params; + memset(&ble_enable_params, 0, sizeof(ble_enable_params)); + ble_enable_params.gatts_enable_params.attr_tab_size = + BLE_GATTS_ATTR_TAB_SIZE_DEFAULT; + ble_enable_params.gatts_enable_params.service_changed = + IS_SRVC_CHANGED_CHARACT_PRESENT; + err_code = sd_ble_enable(&ble_enable_params); + APP_ERROR_CHECK(err_code); + + // Register with the SoftDevice handler module for BLE events. + err_code = softdevice_ble_evt_handler_set(ble_evt_dispatch); + APP_ERROR_CHECK(err_code); + + // Setup address + ble_gap_addr_t ble_addr; + err_code = sd_ble_gap_address_get(&ble_addr); + APP_ERROR_CHECK(err_code); + + ble_addr.addr[5] = 0x00; + ble_addr.addr_type = BLE_GAP_ADDR_TYPE_PUBLIC; + + err_code = sd_ble_gap_address_set(BLE_GAP_ADDR_CYCLE_MODE_NONE, &ble_addr); + APP_ERROR_CHECK(err_code); +} +/*---------------------------------------------------------------------------*/ +/** + * @brief Return device EUI64 MAC address + * @param addr pointer to a buffer to store the address + */ +void +ble_get_mac(uint8_t addr[8]) +{ + uint32_t err_code; + ble_gap_addr_t ble_addr; + + err_code = sd_ble_gap_address_get(&ble_addr); + APP_ERROR_CHECK(err_code); + + IPV6_EUI64_CREATE_FROM_EUI48(addr, ble_addr.addr, ble_addr.addr_type); +} +/*---------------------------------------------------------------------------*/ +/** + * @brief Initialize BLE advertising data. + * @param name Human readable device name that will be advertised + */ +void +ble_advertising_init(const char *name) +{ + uint32_t err_code; + ble_advdata_t advdata; + uint8_t flags = BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED; + ble_gap_conn_sec_mode_t sec_mode; + + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode); + + err_code = sd_ble_gap_device_name_set(&sec_mode, (const uint8_t *)name, + strlen(name)); + APP_ERROR_CHECK(err_code); + + ble_uuid_t adv_uuids[] = {{BLE_UUID_IPSP_SERVICE, BLE_UUID_TYPE_BLE}}; + + // Build and set advertising data. + memset(&advdata, 0, sizeof(advdata)); + + advdata.name_type = BLE_ADVDATA_FULL_NAME; + advdata.flags = flags; + advdata.uuids_complete.uuid_cnt = sizeof(adv_uuids) / sizeof(adv_uuids[0]); + advdata.uuids_complete.p_uuids = adv_uuids; + + err_code = ble_advdata_set(&advdata, NULL); + APP_ERROR_CHECK(err_code); + + // Initialize advertising parameters (used when starting advertising). + memset(&m_adv_params, 0, sizeof(m_adv_params)); + + m_adv_params.type = BLE_GAP_ADV_TYPE_ADV_IND; + m_adv_params.p_peer_addr = NULL; // Undirected advertisement. + m_adv_params.fp = BLE_GAP_ADV_FP_ANY; + m_adv_params.interval = APP_ADV_ADV_INTERVAL; + m_adv_params.timeout = APP_ADV_TIMEOUT; +} +/*---------------------------------------------------------------------------*/ +/** + * @brief Start BLE advertising. + */ +void +ble_advertising_start(void) +{ + uint32_t err_code; + + err_code = sd_ble_gap_adv_start(&m_adv_params); + APP_ERROR_CHECK(err_code); + + DEBUG("ble-core: advertising started\n"); +} +/*---------------------------------------------------------------------------*/ +/** + * @brief Print GAP address. + * @param addr a pointer to address + */ +void +ble_gap_addr_print(const ble_gap_addr_t *addr) +{ + unsigned int i; + for(i = 0; i < sizeof(addr->addr); i++) { + if(i > 0) { + DEBUG(":"); + }DEBUG("%02x", addr->addr[i]); + }DEBUG(" (%d)", addr->addr_type); +} +/*---------------------------------------------------------------------------*/ +/** + * @brief Function for handling the Application's BLE Stack events. + * @param[in] p_ble_evt Bluetooth stack event. + */ +static void +on_ble_evt(ble_evt_t *p_ble_evt) +{ + switch(p_ble_evt->header.evt_id) { + case BLE_GAP_EVT_CONNECTED: + DEBUG("ble-core: connected [handle:%d, peer: ", p_ble_evt->evt.gap_evt.conn_handle); + ble_gap_addr_print(&(p_ble_evt->evt.gap_evt.params.connected.peer_addr)); + DEBUG("]\n"); + sd_ble_gap_rssi_start(p_ble_evt->evt.gap_evt.conn_handle, + BLE_GAP_RSSI_THRESHOLD_INVALID, + 0); + break; + + case BLE_GAP_EVT_DISCONNECTED: + DEBUG("ble-core: disconnected [handle:%d]\n", p_ble_evt->evt.gap_evt.conn_handle); + ble_advertising_start(); + break; + default: + break; + } +} +/*---------------------------------------------------------------------------*/ +/** + * @brief SoftDevice BLE event callback. + * @param[in] p_ble_evt Bluetooth stack event. + */ +static void +ble_evt_dispatch(ble_evt_t *p_ble_evt) +{ + ble_ipsp_evt_handler(p_ble_evt); + on_ble_evt(p_ble_evt); +} +/*---------------------------------------------------------------------------*/ +/** + * @} + * @} + * @} + */ diff --git a/pkg/nordic_softdevice_ble/src/ble-core.h b/pkg/nordic_softdevice_ble/src/ble-core.h new file mode 100644 index 000000000000..84c181d2eff4 --- /dev/null +++ b/pkg/nordic_softdevice_ble/src/ble-core.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ +/** + * \addtogroup cpu + * @{ + * + * \addtogroup nrf52832 + * @{ + * + * \addtogroup nrf52832-ble Bluetooth Low Energy drivers + * @{ + * + * \file + * Basic BLE functions. + * \author + * Wojciech Bober + */ +#ifndef DEV_BLE_H_ +#define DEV_BLE_H_ + +#include + +void ble_stack_init(void); +void ble_advertising_init(const char *name); +void ble_advertising_start(void); +void ble_get_mac(uint8_t addr[8]); + +#endif /* DEV_BLE_H_ */ + +/** + * @} + * @} + * @} + */ diff --git a/pkg/nordic_softdevice_ble/src/ble-mac.c b/pkg/nordic_softdevice_ble/src/ble-mac.c new file mode 100644 index 000000000000..e77d564ec9c2 --- /dev/null +++ b/pkg/nordic_softdevice_ble/src/ble-mac.c @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2016, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +#include + +#define DONT_OVERRIDE_NVIC + +#include "ble-core.h" +#include "ble_ipsp.h" +#include "ble_gap.h" + +#include "ble-mac.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#if defined(MODULE_OD) && ENABLE_DEBUG +#include "od.h" +#endif + +#ifndef BLE_MAC_MAX_INTERFACE_NUM +#define BLE_MAC_MAX_INTERFACE_NUM (1U) /**< Maximum number of interfaces, i.e., + connection to master devices */ +#endif + +typedef struct { + uint8_t peer_addr[8]; + ble_ipsp_handle_t handle; +} ble_mac_interface_t; + +static ble_mac_interface_t interfaces[BLE_MAC_MAX_INTERFACE_NUM]; + +volatile int ble_mac_busy_tx; +volatile int ble_mac_busy_rx; + +static ble_mac_inbuf_t inbuf; +static ble_mac_callback_t _callback; + +/** + * @brief Lookup interface by IPSP connection. + * + * @param[in] handle a pointer to IPSP handle. + * @return a pointer to interface structure + * @return NULL if no interface has been found for a given handle + */ +static ble_mac_interface_t *ble_mac_interface_lookup(ble_ipsp_handle_t *handle) +{ + for (int i = 0; i < BLE_MAC_MAX_INTERFACE_NUM; i++) { + if (interfaces[i].handle.conn_handle == handle->conn_handle && + interfaces[i].handle.cid == handle->cid) { + return &interfaces[i]; + } + } + return NULL; +} + +/** + * @brief Add IPSP connection to the interface table. + * + * This function binds IPSP connection with peer address. + * + * @param[in] peer a pointer to eui64 address + * @param[in] handle a pointer to IPSP handle + * + * @return a pointer to an interface structure on success + * @return NULL if interface table is full + */ +static ble_mac_interface_t *ble_mac_interface_add(uint8_t peer[8], + ble_ipsp_handle_t *handle) +{ + DEBUG("ble_mac_interface_add()"); + for (int i = 0; i < BLE_MAC_MAX_INTERFACE_NUM; i++) { + if (interfaces[i].handle.conn_handle == 0 && interfaces[i].handle.cid == 0) { + memcpy(&interfaces[i].handle, handle, sizeof(ble_ipsp_handle_t)); + memcpy(&interfaces[i].peer_addr, peer, 8); + + /* notify handler thread */ + /* msg_t m = { .type = BLE_IFACE_ADDED, .content.ptr = &interfaces[i] }; */ + /* msg_send(&m, gnrc_nordic_ble_6lowpan_pid); */ + + return &interfaces[i]; + } + } + return NULL; +} + +/** + * @brief Remove interface from the interface table. + * @param[in] interface a pointer to interface + */ +static void ble_mac_interface_delete(ble_mac_interface_t *interface) +{ + DEBUG("ble_mac_interface_delete()"); + memset(interface, 0, sizeof(ble_mac_interface_t)); +} + +/** + * @brief Lookup IPSP handle by peer address. + * + * @param[in] addr a pointer to eui64 address. + * @retval a pointer to IPSP handle on success + * @retval NULL if an IPSP handle for given address haven't been found + */ +static ble_ipsp_handle_t *_find_handle(const uint8_t *addr) +{ + for (int i = 0; i < BLE_MAC_MAX_INTERFACE_NUM; i++) { + if (memcmp(interfaces[i].peer_addr, addr, BLE_SIXLOWPAN_L2_ADDR_LEN) == 0) { + return &interfaces[i].handle; + } + } + return NULL; +} + +/** + * @brief Send packet on a given IPSP handle. + * + * @param[in] handle a pointer to IPSP handle. + * @return 1 on success, 0 otherwise + */ +static int _send_to_peer(ble_ipsp_handle_t *handle, void *data, size_t len) +{ + DEBUG("ble-mac: sending packet[GAP handle:%d CID:0x%04X]\n", + handle->conn_handle, handle->cid); + return ble_ipsp_send(handle, data, len); +} + +static int _is_broadcast(uint8_t dest[8]) +{ + uint32_t *_dest = (uint32_t*)dest; + for (int i = 0; i < 2; i++) { + if (_dest[i]) { + return 0; + } + } + return 1; +} + +int ble_mac_send(uint8_t dest[8], void *data, size_t len) +{ + DEBUG("ble_mac_send(): sending pkt with len %u\n", (unsigned)len); + +#if defined(MODULE_OD) && ENABLE_DEBUG + od_hex_dump(dest, 8, OD_WIDTH_DEFAULT); + od_hex_dump(data, len, OD_WIDTH_DEFAULT); +#endif + + int i; + ble_ipsp_handle_t *handle; + int ret = -1; + + if ((!dest) || _is_broadcast(dest)) { + DEBUG("broadcast\n"); + for (i = 0; i < BLE_MAC_MAX_INTERFACE_NUM; i++) { + if (interfaces[i].handle.cid != 0 && interfaces[i].handle.conn_handle != 0) { + ret = _send_to_peer(&interfaces[i].handle, data, len); + DEBUG("ret=%i\n", ret); + } + } + } + else if ((handle = _find_handle(dest)) != NULL) { + DEBUG("unicast\n"); + ret = _send_to_peer(handle, data, len); + } + else { + DEBUG("ble-mac: no connection found for peer\n"); + } + + if (ret == NRF_SUCCESS) { + ble_mac_busy_tx = 1; + return 0; + } + else { + DEBUG("ble-mac: send error: %i\n", ret); + return -1; + } +} + +static uint32_t ble_mac_ipsp_evt_handler_irq(ble_ipsp_handle_t *p_handle, ble_ipsp_evt_t *p_evt) +{ + uint32_t retval = NRF_SUCCESS; + + ble_mac_interface_t *p_instance = NULL; + + p_instance = ble_mac_interface_lookup(p_handle); + + if (p_handle) { + DEBUG("ble-mac: IPSP event [handle:%d CID 0x%04X]\n", p_handle->conn_handle, p_handle->cid); + } + + switch (p_evt->evt_id) { + case BLE_IPSP_EVT_CHANNEL_CONNECTED: { + uint8_t peer_addr[8]; + + DEBUG("ble-mac: channel connected\n"); + ble_eui64_from_eui48(peer_addr, p_evt->evt_param->params.ch_conn_request.peer_addr.addr, + p_evt->evt_param->params.ch_conn_request.peer_addr.addr_type == + BLE_GAP_ADDR_TYPE_PUBLIC); + + p_instance = ble_mac_interface_add(peer_addr, p_handle); + + if (p_instance != NULL) { + DEBUG("ble-mac: added new IPSP interface\n"); + } + else { + DEBUG("ble-mac: cannot add new interface. Table is full\n"); + ble_ipsp_disconnect(p_handle); + } + break; + } + + case BLE_IPSP_EVT_CHANNEL_DISCONNECTED: { + DEBUG("ble-mac: channel disconnected\n"); + if (p_instance != NULL) { + DEBUG("ble-mac: removed IPSP interface\n"); + ble_mac_interface_delete(p_instance); + } + break; + } + + case BLE_IPSP_EVT_CHANNEL_DATA_RX: { + DEBUG("ble-mac: data received\n"); + if (p_instance != NULL) { + if (ble_mac_busy_rx) { + DEBUG("ble-mac: packet dropped as input buffer is busy\n"); + break; + } + + if (p_evt->evt_param->params.ch_rx.len > BLE_SIXLOWPAN_MTU) { + DEBUG("ble-mac: packet buffer is too small!\n"); + break; + } + + ble_mac_busy_rx = 1; + + inbuf.len = p_evt->evt_param->params.ch_rx.len; + memcpy(inbuf.payload, p_evt->evt_param->params.ch_rx.p_data, inbuf.len); + memcpy(inbuf.src, p_instance->peer_addr, 8); + sd_ble_gap_rssi_get(p_handle->conn_handle, &inbuf.rssi); + + _callback(BLE_EVENT_RX_DONE, &inbuf); + } + else { + DEBUG("ble-mac: got data to unknown interface!\n"); + } + break; + } + + case BLE_IPSP_EVT_CHANNEL_DATA_TX_COMPLETE: { + DEBUG("ble-mac: data transmitted\n"); + ble_mac_busy_tx = 0; + //_callback(BLE_EVENT_TX_DONE, NULL); + break; + } + } + + if (sched_context_switch_request) { + NVIC_SetPendingIRQ( SWI0_EGU0_IRQn ); + } + + return retval; +} + +void ble_mac_init(ble_mac_callback_t callback) +{ + assert(callback); + + uint32_t res; + ble_ipsp_init_t ipsp_init_params = { + .evt_handler = ble_mac_ipsp_evt_handler_irq + }; + + _callback = callback; + + res = ble_ipsp_init(&ipsp_init_params); + DEBUG("ble_ipsp_init() res = %" PRIu32 "\n", res); + (void)res; +} diff --git a/pkg/nordic_softdevice_ble/src/ble-mac.h b/pkg/nordic_softdevice_ble/src/ble-mac.h new file mode 100644 index 000000000000..19eaefb03ab9 --- /dev/null +++ b/pkg/nordic_softdevice_ble/src/ble-mac.h @@ -0,0 +1,50 @@ +#ifndef BLE_MAC_H +#define BLE_MAC_H + +typedef enum { + BLE_EVENT_RX_DONE = 20000, +} ble_mac_event_enum_t; + +#define BLE_IFACE_ADDED (10000) + +#define BLE_SIXLOWPAN_MTU (1280U) +#define BLE_SIXLOWPAN_L2_ADDR_LEN (8) + +#define IPV6_IID_FLIP_VALUE (0x02) + +#include "net/eui64.h" + +static inline void ble_eui64_from_eui48(uint8_t eui64[8], uint8_t eui48[6], int _public) +{ + eui64[0] = eui48[5]; + eui64[1] = eui48[4]; + eui64[2] = eui48[3]; + eui64[3] = 0xFF; + eui64[4] = 0xFE; + eui64[5] = eui48[2]; + eui64[6] = eui48[1]; + eui64[7] = eui48[0]; + if (_public) { + eui64[0] &= ~(IPV6_IID_FLIP_VALUE); + } + else { + eui64[0] |= IPV6_IID_FLIP_VALUE; + } +} + +typedef struct { + uint8_t src[8]; + uint8_t payload[BLE_SIXLOWPAN_MTU]; + uint16_t len; + int8_t rssi; +} ble_mac_inbuf_t; + +typedef void (*ble_mac_callback_t)(ble_mac_event_enum_t event, void*arg); +void ble_mac_init(ble_mac_callback_t callback); +int ble_mac_send(uint8_t dest[8], void *data, size_t len); + +extern volatile int ble_mac_busy_tx; /**< Flag is set to 1 when the driver + is busy transmitting a packet. */ +extern volatile int ble_mac_busy_rx; /**< Flag is set to 1 when there is a + received packet pending. */ +#endif /* BLE_MAC_H */ diff --git a/pkg/nordic_softdevice_ble/src/gnrc_nordic_ble_6lowpan.c b/pkg/nordic_softdevice_ble/src/gnrc_nordic_ble_6lowpan.c new file mode 100644 index 000000000000..156c2289d0e6 --- /dev/null +++ b/pkg/nordic_softdevice_ble/src/gnrc_nordic_ble_6lowpan.c @@ -0,0 +1,318 @@ +/* + * Copyright (c) 2016, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +/** + * @{ + * @ingroup net + * @file + * @brief Glue for Nordic's SoftDevice BLE 6lowpan blob to netapi + * + * @author Kaspar Schleiser + * @} + */ + +#include +#include + +#include "msg.h" +#include "thread.h" + +#include "net/gnrc.h" +#include "net/gnrc/nettype.h" + +#include "ble-core.h" +#include "softdevice_handler.h" + +#include "ble-mac.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#if defined(MODULE_OD) && ENABLE_DEBUG +#include "od.h" +#endif + +#define BLE_NETAPI_MSG_QUEUE_SIZE (8U) +#define BLE_PRIO (THREAD_PRIORITY_MAIN - 1) + +kernel_pid_t gnrc_nordic_ble_6lowpan_pid; +static char _stack[(THREAD_STACKSIZE_DEFAULT + DEBUG_EXTRA_STACKSIZE)]; + +static uint8_t _own_mac_addr[BLE_SIXLOWPAN_L2_ADDR_LEN]; + +static uint8_t _sendbuf[BLE_SIXLOWPAN_MTU]; + +static void _ble_mac_callback(ble_mac_event_enum_t event, void* arg) +{ + msg_t m = { .type=event, .content.ptr=arg }; + + if (!msg_send_int(&m, gnrc_nordic_ble_6lowpan_pid)) { + puts("_ble_mac_callback(): possibly lost interrupt"); + } +} + +static void _handle_raw_sixlowpan(ble_mac_inbuf_t *inbuf) +{ + gnrc_pktsnip_t *pkt = NULL; + + pkt = gnrc_pktbuf_add(NULL, inbuf->payload, + inbuf->len, + GNRC_NETTYPE_SIXLOWPAN); + + if(!pkt) { + DEBUG("_handle_raw_sixlowpan(): no space left in packet buffer.\n"); + return; + } + + /* create netif header */ + gnrc_pktsnip_t *netif_hdr; + netif_hdr = gnrc_pktbuf_add(NULL, NULL, + sizeof(gnrc_netif_hdr_t) + (2 * sizeof(eui64_t)), + GNRC_NETTYPE_NETIF); + + if (netif_hdr == NULL) { + DEBUG("_handle_raw_sixlowpan(): no space left in packet buffer.\n"); + gnrc_pktbuf_release(pkt); + return; + } + + gnrc_netif_hdr_init(netif_hdr->data, BLE_SIXLOWPAN_L2_ADDR_LEN, BLE_SIXLOWPAN_L2_ADDR_LEN); + gnrc_netif_hdr_set_src_addr(netif_hdr->data, inbuf->src, BLE_SIXLOWPAN_L2_ADDR_LEN); + gnrc_netif_hdr_set_dst_addr(netif_hdr->data, _own_mac_addr, BLE_SIXLOWPAN_L2_ADDR_LEN); + ((gnrc_netif_hdr_t *)netif_hdr->data)->if_pid = gnrc_nordic_ble_6lowpan_pid; + + DEBUG("_handle_raw_sixlowpan(): received packet from %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x " + "of length %d\n", + inbuf->src[0], inbuf->src[1], inbuf->src[2], inbuf->src[3], inbuf->src[4], + inbuf->src[5], inbuf->src[6], inbuf->src[7], inbuf->len); +#if defined(MODULE_OD) && ENABLE_DEBUG + od_hex_dump(inbuf->payload, inbuf->len, OD_WIDTH_DEFAULT); +#endif + + LL_APPEND(pkt, netif_hdr); + + /* throw away packet if no one is interested */ + if (!gnrc_netapi_dispatch_receive(pkt->type, GNRC_NETREG_DEMUX_CTX_ALL, pkt)) { + DEBUG("_handle_raw_sixlowpan: unable to forward packet of type %i\n", pkt->type); + gnrc_pktbuf_release(pkt); + } +} + +static int _send(gnrc_pktsnip_t *pkt) +{ + gnrc_netif_hdr_t *netif_hdr; + gnrc_pktsnip_t *payload = pkt->next; + uint8_t *dst; + + if (ble_mac_busy_tx) { + DEBUG("_send(): ble_mac_busy_tx\n"); + return -EBUSY; + } + + uint8_t *buf = _sendbuf; + unsigned len = 0; + + if (pkt == NULL) { + DEBUG("_send_ble: pkt was NULL\n"); + return -EINVAL; + } + if (pkt->type != GNRC_NETTYPE_NETIF) { + DEBUG("_send_ble: first header is not generic netif header\n"); + return -EBADMSG; + } + + netif_hdr = pkt->data; + + /* prepare destination address */ + if (netif_hdr->flags & + (GNRC_NETIF_HDR_FLAGS_BROADCAST | GNRC_NETIF_HDR_FLAGS_MULTICAST)) { + dst = NULL; + } + else { + dst = gnrc_netif_hdr_get_dst_addr(netif_hdr); + } + + /* prepare packet for sending */ + while (payload) { + memcpy(buf, payload->data, payload->size); + len += payload->size; + buf += payload->size; + payload = payload->next; + } + + gnrc_pktbuf_release(pkt); + + if (ble_mac_send(dst, _sendbuf, len) == -1) { + return -EBADMSG; + } + + return 0; +} +static int _handle_get(gnrc_netapi_opt_t *_opt) +{ + int res = -ENOTSUP; + uint8_t *value = _opt->data; + + switch (_opt->opt) { + case NETOPT_ACK_REQ: + case NETOPT_CHANNEL: + case NETOPT_NID: + case NETOPT_ADDRESS: + /* -ENOTSUP */ + break; + case NETOPT_ADDRESS_LONG: + assert(_opt->data_len >= BLE_SIXLOWPAN_L2_ADDR_LEN); + memcpy(value, _own_mac_addr, BLE_SIXLOWPAN_L2_ADDR_LEN); + value[0] = IPV6_IID_FLIP_VALUE; + res = BLE_SIXLOWPAN_L2_ADDR_LEN; + break; + case NETOPT_ADDR_LEN: + case NETOPT_SRC_LEN: + assert(_opt->data_len == sizeof(uint16_t)); + *((uint16_t *)value) = BLE_SIXLOWPAN_L2_ADDR_LEN; + res = sizeof(uint16_t); + break; +#ifdef MODULE_GNRC + case NETOPT_PROTO: + assert(_opt->data_len == sizeof(gnrc_nettype_t)); + *((gnrc_nettype_t *)value) = GNRC_NETTYPE_SIXLOWPAN; + res = sizeof(gnrc_nettype_t); + break; +#endif +/* case NETOPT_DEVICE_TYPE: + assert(_opt->data_len == sizeof(uint16_t)); + *((uint16_t *)value) = NETDEV2_TYPE_IEEE802154; + res = sizeof(uint16_t); + break;*/ + case NETOPT_IPV6_IID: + memcpy(value, _own_mac_addr, BLE_SIXLOWPAN_L2_ADDR_LEN); + value[0] = IPV6_IID_FLIP_VALUE; + res = BLE_SIXLOWPAN_L2_ADDR_LEN; + break; + default: + break; + } + return res; +} + +/** + * @brief Startup code and event loop of the gnrc_nordic_ble_6lowpan layer + * + * @return never returns + */ +static void *_gnrc_nordic_ble_6lowpan_thread(void *args) +{ + (void)args; + + DEBUG("gnrc_nordic_ble_6lowpan: starting thread\n"); + + gnrc_nordic_ble_6lowpan_pid = thread_getpid(); + + gnrc_netapi_opt_t *opt; + int res; + msg_t msg, reply, msg_queue[BLE_NETAPI_MSG_QUEUE_SIZE]; + + /* setup the message queue */ + msg_init_queue(msg_queue, BLE_NETAPI_MSG_QUEUE_SIZE); + + /* initialize BLE stack */ + assert((unsigned)softdevice_handler_isEnabled()); + + ble_stack_init(); + ble_get_mac(_own_mac_addr); + + ble_mac_init(_ble_mac_callback); + + ble_advertising_init("RIOT BLE"); + ble_advertising_start(); + + /* register the device to the network stack*/ + gnrc_netif_add(thread_getpid()); + + /* start the event loop */ + while (1) { +// DEBUG("gnrc_nordic_ble_6lowpan: waiting for incoming messages\n"); + msg_receive(&msg); + /* dispatch NETDEV and NETAPI messages */ + switch (msg.type) { + case BLE_EVENT_RX_DONE: + { + DEBUG("ble rx:\n"); + _handle_raw_sixlowpan(msg.content.ptr); + ble_mac_busy_rx = 0; + break; + } + case GNRC_NETAPI_MSG_TYPE_SND: + DEBUG("gnrc_nordic_ble_6lowpan: GNRC_NETAPI_MSG_TYPE_SND received\n"); + _send(msg.content.ptr); + break; + case GNRC_NETAPI_MSG_TYPE_SET: + /* read incoming options */ + opt = msg.content.ptr; + DEBUG("gnrc_nordic_ble_6lowpan: GNRC_NETAPI_MSG_TYPE_SET received. opt=%s\n", + netopt2str(opt->opt)); + /* set option for device driver */ + res = ENOTSUP; + DEBUG("gnrc_nordic_ble_6lowpan: response of netdev->set: %i\n", res); + /* send reply to calling thread */ + reply.type = GNRC_NETAPI_MSG_TYPE_ACK; + reply.content.value = (uint32_t)res; + msg_reply(&msg, &reply); + break; + case GNRC_NETAPI_MSG_TYPE_GET: + /* read incoming options */ + opt = msg.content.ptr; + DEBUG("gnrc_nordic_ble_6lowpan: GNRC_NETAPI_MSG_TYPE_GET received. opt=%s\n", + netopt2str(opt->opt)); + res = _handle_get(opt); + DEBUG("gnrc_nordic_ble_6lowpan: response of netdev->get: %i\n", res); + /* send reply to calling thread */ + reply.type = GNRC_NETAPI_MSG_TYPE_ACK; + reply.content.value = (uint32_t)res; + msg_reply(&msg, &reply); + break; + default: + DEBUG("gnrc_nordic_ble_6lowpan: Unknown command %" PRIu16 "\n", msg.type); + break; + } + } + /* never reached */ + return NULL; +} + +void gnrc_nordic_ble_6lowpan_init(void) +{ + kernel_pid_t res = thread_create(_stack, sizeof(_stack), BLE_PRIO, + THREAD_CREATE_STACKTEST, + _gnrc_nordic_ble_6lowpan_thread, NULL, + "ble"); + assert(res > 0); + (void)res; +} diff --git a/pkg/nordic_softdevice_ble/src/gnrc_nordic_ble_6lowpan.h b/pkg/nordic_softdevice_ble/src/gnrc_nordic_ble_6lowpan.h new file mode 100644 index 000000000000..27dde2fd1a3c --- /dev/null +++ b/pkg/nordic_softdevice_ble/src/gnrc_nordic_ble_6lowpan.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2016, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ +#ifndef GNRC_NORDIC_BLE_6LOWPAN_H +#define GNRC_NORDIC_BLE_6LOWPAN_H + +#ifdef __cplusplus +extern "C" { +#endif + +void gnrc_nordic_ble_6lowpan_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* GNRC_NORDIC_BLE_6LOWPAN_H */ diff --git a/sys/auto_init/auto_init.c b/sys/auto_init/auto_init.c index 63c9e6ec0050..44f75bf3a8ff 100644 --- a/sys/auto_init/auto_init.c +++ b/sys/auto_init/auto_init.c @@ -225,6 +225,11 @@ void auto_init(void) auto_init_netdev2_tap(); #endif +#ifdef MODULE_NORDIC_SOFTDEVICE_BLE + extern void gnrc_nordic_ble_6lowpan_init(void); + gnrc_nordic_ble_6lowpan_init(); +#endif + #endif /* MODULE_AUTO_INIT_GNRC_NETIF */ #ifdef MODULE_GNRC_IPV6_NETIF