diff --git a/pkg/openwsn/Makefile b/pkg/openwsn/Makefile new file mode 100644 index 0000000000..944bf419bd --- /dev/null +++ b/pkg/openwsn/Makefile @@ -0,0 +1,51 @@ +PKG_NAME=openwsn +PKG_URL=https://github.com/openwsn-berkeley/openwsn-fw.git +PKG_VERSION=cbcf622bd9369fcfc8455a5fb9349de2ed3c3a46 +PKG_LICENSE=BSD-3-Clause + +include $(RIOTBASE)/pkg/pkg.mk + +# openwsn_% RIOT Modules or PSEUDOMODULES that don't have custom rules +IGNORE_MODULES := openwsn_leds \ + openwsn_debugpins \ + openwsn_radio \ + openwsn_serial \ + openwsn_sctimer% \ + openwsn_cryptoengine \ + # + +OPENWSN_MODULES := $(filter-out $(IGNORE_MODULES),$(filter openwsn_%,$(USEMODULE))) + +.PHONY: openwsn_% + +OPENWSN_LOG_LEVEL ?= LOG_NONE + +CFLAGS += -Wno-array-bounds +CFLAGS += -Wno-implicit-fallthrough +CFLAGS += -Wno-implicit-function-declaration +CFLAGS += -Wno-incompatible-pointer-types +CFLAGS += -Wno-maybe-uninitialized +CFLAGS += -Wno-old-style-definition +CFLAGS += -Wno-return-type +CFLAGS += -Wno-sign-compare +CFLAGS += -Wno-unused-parameter +CFLAGS += -Wno-strict-prototypes +CFLAGS += -DLOG_LEVEL=$(OPENWSN_LOG_LEVEL) + +OPENWSN_PATH_openstack = openstack +OPENWSN_PATH_openapps = openapps +OPENWSN_PATH_drivers = drivers/common +OPENWSN_PATH_scheduler = kernel/openos +OPENWSN_PATH_cjoin = openapps/cjoin +OPENWSN_PATH_opencoap = openapps/opencoap +OPENWSN_PATH_mac_low = openstack/02a-MAClow +OPENWSN_PATH_mac_high = openstack/02b-MAChigh +OPENWSN_PATH_iphc = openstack/03a-IPHC +OPENWSN_PATH_ipv6 = openstack/03b-IPv6 +OPENWSN_PATH_transport = openstack/04-TRAN +OPENWSN_PATH_crosslayers = openstack/cross-layers + +all: $(OPENWSN_MODULES) + +openwsn_%: + "$(MAKE)" -C $(PKG_SOURCE_DIR)/$(OPENWSN_PATH_$*) -f $(RIOTBASE)/Makefile.base MODULE=$@ diff --git a/pkg/openwsn/Makefile.dep b/pkg/openwsn/Makefile.dep new file mode 100644 index 0000000000..9511b68e16 --- /dev/null +++ b/pkg/openwsn/Makefile.dep @@ -0,0 +1,71 @@ +ifneq (,$(filter openwsn_openstack,$(USEMODULE))) + USEMODULE += openwsn_cjoin + USEMODULE += openwsn_iphc + USEMODULE += openwsn_ipv6 + USEMODULE += openwsn_mac_low + USEMODULE += openwsn_mac_high + USEMODULE += openwsn_transport + USEMODULE += openwsn_crosslayers + + USEMODULE += openwsn_drivers + USEMODULE += openwsn_sctimer + USEMODULE += openwsn_radio + + DEFAULT_MODULE += auto_init_openwsn + + USEMODULE += luid + USEMODULE += netdev_default +endif + +ifneq (,$(filter openwsn_scheduler,$(USEMODULE))) + USEMODULE += core_thread_flags +endif + +ifneq (,$(filter openwsn_cjoin,$(USEMODULE))) + USEMODULE += openwsn_openapps + USEMODULE += openwsn_opencoap + + USEMODULE += openwsn_cryptoengine +endif + +ifneq (,$(filter openwsn_cryptoengine,$(USEMODULE))) + USEMODULE += crypto_3des + USEMODULE += cipher_modes +endif + +ifneq (,$(filter openwsn_sctimer,$(USEMODULE))) + ifeq (,$(filter openwsn_sctimer_ztimer,$(USEMODULE))) + USEMODULE += openwsn_sctimer_rtt + endif +endif + +ifneq (,$(filter openwsn_sctimer_ztimer,$(USEMODULE))) + USEMODULE += ztimer_usec + USEMODULE += ztimer_msec + FEATURES_OPTIONAL += periph_rtt + ifneq (,$(filter periph_rtt,$(FEATURES_USED))) + USEMODULE += ztimer_periph_rtt + endif +endif + +ifneq (,$(filter openwsn_sctimer_rtt,$(USEMODULE))) + FEATURES_REQUIRED += periph_rtt +endif + +ifneq (,$(filter openwsn_serial,$(USEMODULE))) + USEMODULE += openwsn_drivers + USEMODULE += ztimer_usec + FEATURES_REQUIRED += periph_uart + FEATURES_OPTIONAL += periph_uart_nonblocking +endif + +ifneq (,$(filter openwsn_leds openwsn_debugpins,$(USEMODULE))) + FEATURES_REQUIRED += periph_gpio +endif + +ifneq (,$(filter openwsn_debugpins,$(USEMODULE))) + FEATURES_REQUIRED += periph_gpio_irq +endif + +# This port currently requires setting ISR_STACKSIZE +FEATURES_BLACKLIST += arch_esp32 arch_esp8266 arch_riscv arch_avr8 diff --git a/pkg/openwsn/Makefile.include b/pkg/openwsn/Makefile.include new file mode 100644 index 0000000000..b3b66406f9 --- /dev/null +++ b/pkg/openwsn/Makefile.include @@ -0,0 +1,40 @@ +INCLUDES += -I$(PKGDIRBASE)/openwsn \ + -I$(PKGDIRBASE)/openwsn/kernel \ + -I$(PKGDIRBASE)/openwsn/inc \ + -I$(PKGDIRBASE)/openwsn/drivers/common \ + -I$(PKGDIRBASE)/openwsn/bsp/boards/ \ + -I$(PKGDIRBASE)/openwsn/openstack/ \ + -I$(PKGDIRBASE)/openwsn/openstack/02a-MAClow \ + -I$(PKGDIRBASE)/openwsn/openstack/02b-MAChigh \ + -I$(PKGDIRBASE)/openwsn/openstack/03a-IPHC \ + -I$(PKGDIRBASE)/openwsn/openstack/03b-IPv6 \ + -I$(PKGDIRBASE)/openwsn/openstack/04-TRAN \ + -I$(PKGDIRBASE)/openwsn/openstack/cross-layers \ + -I$(PKGDIRBASE)/openwsn/openapps \ + -I$(PKGDIRBASE)/openwsn/openapps/cjoin \ + -I$(PKGDIRBASE)/openwsn/openapps/opencoap \ + -I$(RIOTBASE)/pkg/openwsn/include \ + +DIRS += $(RIOTBASE)/pkg/openwsn/contrib + +PSEUDOMODULES += openwsn_serial +PSEUDOMODULES += openwsn_debugpins +PSEUDOMODULES += openwsn_leds +PSEUDOMODULES += openwsn_sctimer% +PSEUDOMODULES += openwsn_cryptoengine +PSEUDOMODULES += openwsn_radio + +# In OpenWSN the ISR stack is shared with the network stack. OpenWSN stack is +# 2Kb, this means that the ISR stack in OpenWSN might have up to 2Kb available. +# To keep the same marging increase the ISR stack to 2Kb as well. In practice +# 1Kb should be enough. +CFLAGS += -DISR_STACKSIZE=2048 + +# at86rf2xx state machine is in enhanced mode by default, OpenWSN requires +# basic mode. +ifneq (,$(filter at86rf2xx,$(USEMODULE))) + CFLAGS += -DAT86RF2XX_BASIC_MODE +endif + +# LLVM ARM shows issues with missing definitions fot stdatomic +TOOLCHAINS_BLACKLIST += llvm diff --git a/pkg/openwsn/contrib/Makefile b/pkg/openwsn/contrib/Makefile new file mode 100644 index 0000000000..07576b0a84 --- /dev/null +++ b/pkg/openwsn/contrib/Makefile @@ -0,0 +1,13 @@ +MODULE = openwsn + +SRC := $(filter-out sctimer_% ,$(wildcard *.c)) + +ifneq (,$(filter openwsn_sctimer_rtt,$(USEMODULE))) + SRC += sctimer_rtt.c +endif + +ifneq (,$(filter openwsn_sctimer_ztimer,$(USEMODULE))) + SRC += sctimer_ztimer.c +endif + +include $(RIOTBASE)/Makefile.base diff --git a/pkg/openwsn/contrib/board.c b/pkg/openwsn/contrib/board.c new file mode 100644 index 0000000000..1d57838ac8 --- /dev/null +++ b/pkg/openwsn/contrib/board.c @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2018 Hamburg University of Applied Sciences + * 2020 Inria + * + * 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. + */ + +/** + * @ingroup pkg_openwsn + * @{ + * + * @file + * @brief RIOT adaption of the "board" bsp module + * + * @author Thomas Watteyne , February 2012 + * @author Tengfei Chang , July 2012 + * @author Peter Kietzmann , July 2017 + * @author Francisco Molina + * + * @} + */ + +#include + +#include "sctimer.h" +#include "radio.h" + +#include "thread.h" +#include "periph/pm.h" + +#include "openwsn_board.h" +#include "openwsn_debugpins.h" +#include "openwsn_debugpins_params.h" +#include "openwsn_leds.h" +#include "openwsn_leds_params.h" +#include "openwsn_uart.h" + +#ifdef MODULE_PM_LAYERED +#include "pm_layered.h" +#endif + +#define LOG_LEVEL LOG_NONE +#include "log.h" + +void board_init_openwsn(void) +{ + LOG_DEBUG("[openwsn/board]: init\n"); + +#ifdef MODULE_PM_LAYERED + /* sleeping is currently not supported, block all sleep modes */ + for (uint8_t i = 0; i < PM_NUM_MODES; i++) { + pm_block(i); + } +#endif + + if (IS_USED(MODULE_OPENWSN_LEDS)) { + LOG_DEBUG("[openwsn/board]: leds init\n"); + ledpins_riot_init(openwsn_leds_params); + } + + if (IS_USED(MODULE_OPENWSN_DEBUGPINS)) { + LOG_DEBUG("[openwsn/board]: debugpins init\n"); + openwsn_debugpins_init(openwsn_debugpins_params); + } + + if (IS_USED(MODULE_OPENWSN_SCTIMER)) { + LOG_DEBUG("[openwsn/board]: sctimer init\n"); + sctimer_init(); + } + + if (IS_USED(MODULE_OPENWSN_SERIAL)) { + LOG_DEBUG("[openwsn/board]: uart init\n"); + uart_init_openwsn(); + } +} + +void board_sleep(void) +{ + /* sleep is handled by `pm_layered` */ +} + +void board_reset(void) +{ + LOG_DEBUG("[openwsn/board]: reset\n"); + pm_reboot(); +} diff --git a/pkg/openwsn/contrib/cryptoengine.c b/pkg/openwsn/contrib/cryptoengine.c new file mode 100644 index 0000000000..1ef8ffc6bf --- /dev/null +++ b/pkg/openwsn/contrib/cryptoengine.c @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2020 Inria + * + * 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. + */ + +/** + * @ingroup pkg_openwsn + * @{ + * + * @file + * @brief RIOT adaption definition of the "cryptoengine" module + * + * @author Francisco Molina + * + * @} + */ + +#include + +#include "opendefs.h" + +#include "crypto/ciphers.h" +#include "crypto/modes/ecb.h" +#include "crypto/modes/ccm.h" + +/* CCM does not restrict the input message size, but these function will + only be called with a message length of at most 125b in OpenWSN */ +#define MAX_MESSAGE_LEN (125U) + +owerror_t cryptoengine_aes_ccms_enc(uint8_t *a, uint8_t len_a, uint8_t *m, + uint8_t *len_m, uint8_t *nonce, uint8_t l, + uint8_t *key, uint8_t len_mac) +{ + cipher_t cipher; + int ret, len; + uint8_t tmp_buff[MAX_MESSAGE_LEN + CCM_MAC_MAX_LEN]; + + ret = cipher_init(&cipher, CIPHER_AES_128, key, CCM_BLOCK_SIZE); + + if (ret != 1) { + return E_FAIL; + } + + len = cipher_encrypt_ccm(&cipher, a, len_a, len_mac, l, + nonce, 15 - l, m, *len_m, tmp_buff); + if (len < 0) { + return E_FAIL; + } + + *len_m = len; + memcpy(m, tmp_buff, *len_m); + + return E_SUCCESS; +} + +owerror_t cryptoengine_aes_ccms_dec(uint8_t *a, uint8_t len_a, uint8_t *m, + uint8_t *len_m, uint8_t *nonce, uint8_t l, + uint8_t *key, uint8_t len_mac) +{ + cipher_t cipher; + int ret, len; + uint8_t tmp_buff[MAX_MESSAGE_LEN]; + + ret = cipher_init(&cipher, CIPHER_AES_128, key, CCM_BLOCK_SIZE); + + if (ret != 1) { + return E_FAIL; + } + + len = cipher_decrypt_ccm(&cipher, a, len_a, len_mac, l, nonce, 15 - l, m, + *len_m, tmp_buff); + + if (len < 0) { + return E_FAIL; + } + + *len_m = len; + memcpy(m, tmp_buff, *len_m); + + return E_SUCCESS; +} + +owerror_t cryptoengine_aes_ecb_enc(uint8_t *buffer, uint8_t *key) +{ + cipher_t cipher; + int ret, len; + + ret = cipher_init(&cipher, CIPHER_AES_128, key, CCM_BLOCK_SIZE); + + if (ret != 1) { + return E_FAIL; + } + + len = cipher_encrypt_ecb(&cipher, buffer, CCM_BLOCK_SIZE, buffer); + + if (len < 0) { + return E_FAIL; + } + + return E_SUCCESS; +} diff --git a/pkg/openwsn/contrib/debugpins.c b/pkg/openwsn/contrib/debugpins.c new file mode 100644 index 0000000000..b2f22f5cad --- /dev/null +++ b/pkg/openwsn/contrib/debugpins.c @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2017 Hamburg University of Applied Sciences + * + * 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. + */ + +/** + * @ingroup pkg_openwsn + * @{ + * + * @file + * @brief RIOT adaption of the "debugpins" bsp module + * + * @author Michael Frey + * @author Peter Kietzmann + * @author Francisco Molina + * + * @} + */ + +#include "debugpins.h" +#include "openwsn_debugpins.h" + +#include +#include + +/* holds the internal configuration for debugpins */ +static debugpins_config_t _configuration = { + GPIO_UNDEF, + GPIO_UNDEF, + GPIO_UNDEF, + GPIO_UNDEF, + GPIO_UNDEF, + GPIO_UNDEF +}; + +static void _set_checked(gpio_t pin) +{ + if (IS_USED(MODULE_OPENWSN_DEBUGPINS)) { + if (pin != GPIO_UNDEF){ + gpio_set(pin); + } + } +} + +static void _clear_checked(gpio_t pin) +{ + if (IS_USED(MODULE_OPENWSN_DEBUGPINS)) { + if (pin != GPIO_UNDEF){ + gpio_clear(pin); + } + } +} + +static void _toggle_checked(gpio_t pin) +{ + if (IS_USED(MODULE_OPENWSN_DEBUGPINS)) { + if (pin != GPIO_UNDEF){ + gpio_toggle(pin); + } + } +} + +static void _init_checked(gpio_t pin) +{ + if (IS_USED(MODULE_OPENWSN_DEBUGPINS)) { + if (pin != GPIO_UNDEF){ + gpio_init(pin, GPIO_OUT); + } + } +} + +void openwsn_debugpins_init(const debugpins_config_t *user_config) +{ + if (IS_USED(MODULE_OPENWSN_DEBUGPINS)) { + memset(&_configuration, GPIO_UNDEF, sizeof(debugpins_config_t)); + + if (user_config != NULL) { + memcpy(&_configuration, user_config, sizeof(debugpins_config_t)); + debugpins_init(); + } + } + else { + (void) user_config; + } +} + +void debugpins_init(void) +{ + _init_checked(_configuration.frame); + _init_checked(_configuration.slot); + _init_checked(_configuration.fsm); + _init_checked(_configuration.task); + _init_checked(_configuration.isr); + _init_checked(_configuration.radio); + + debugpins_frame_clr(); + debugpins_slot_clr(); + debugpins_fsm_clr(); + debugpins_task_clr(); + debugpins_isr_clr(); + debugpins_radio_clr(); +} + +void debugpins_frame_toggle(void) +{ + _toggle_checked(_configuration.frame); +} + +void debugpins_frame_clr(void) +{ + _clear_checked(_configuration.frame); +} + +void debugpins_frame_set(void) +{ + _set_checked(_configuration.frame); +} + +void debugpins_slot_toggle(void) +{ + _toggle_checked(_configuration.slot); +} + +void debugpins_slot_clr(void) +{ + _clear_checked(_configuration.slot); +} + +void debugpins_slot_set(void) +{ + _set_checked(_configuration.slot); +} + +void debugpins_fsm_toggle(void) +{ + _toggle_checked(_configuration.fsm); +} + +void debugpins_fsm_clr(void) +{ + _clear_checked(_configuration.fsm); +} + +void debugpins_fsm_set(void) +{ + _set_checked(_configuration.fsm); +} + +void debugpins_task_toggle(void) +{ + _toggle_checked(_configuration.task); +} + +void debugpins_task_clr(void) +{ + _clear_checked(_configuration.task); +} + +void debugpins_task_set(void) +{ + _set_checked(_configuration.task); +} + +void debugpins_isr_toggle(void) +{ + _toggle_checked(_configuration.isr); +} + +void debugpins_isr_clr(void) +{ + _clear_checked(_configuration.isr); +} + +void debugpins_isr_set(void) +{ + _set_checked(_configuration.isr); +} + +void debugpins_radio_toggle(void) +{ + _toggle_checked(_configuration.radio); +} + +void debugpins_radio_clr(void) +{ + _clear_checked(_configuration.radio); +} + +void debugpins_radio_set(void) +{ + _set_checked(_configuration.radio); +} diff --git a/pkg/openwsn/contrib/eui64.c b/pkg/openwsn/contrib/eui64.c new file mode 100644 index 0000000000..1b7221d780 --- /dev/null +++ b/pkg/openwsn/contrib/eui64.c @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2017 Hamburg University of Applied Sciences + * + * 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. + */ + +/** + * @ingroup pkg_openwsn + * @{ + * + * @file + * @brief RIOT adaption definition of the "eui64" bsp module + * + * @author Peter Kietzmann + * + * @} + */ + +#include "string.h" +#include "eui64.h" +#include "openwsn_radio.h" + +#include "luid.h" +#include "net/netdev.h" +#include "net/netopt.h" +#include "net/ieee802154.h" + +extern openwsn_radio_t openwsn_radio; + +void eui64_get(uint8_t *addressToWrite) +{ + eui64_t eui64; + + if (openwsn_radio.dev->driver->get(openwsn_radio.dev, NETOPT_ADDRESS_LONG, + &eui64, + sizeof(eui64_t)) == sizeof(eui64_t)) { + memcpy(addressToWrite, eui64.uint8, sizeof(eui64.uint8)); + } + else { + luid_get_eui64((eui64_t *) addressToWrite); + } +} diff --git a/pkg/openwsn/contrib/leds.c b/pkg/openwsn/contrib/leds.c new file mode 100644 index 0000000000..dc944be7ce --- /dev/null +++ b/pkg/openwsn/contrib/leds.c @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2017 Hamburg University of Applied Sciences + * 2020 Inria + * + * 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. + */ + +/** + * @ingroup pkg_openwsn + * @{ + * + * @file + * + * @author Michael Frey + * @author Peter Kietzmann + * @author Francisco Molina + * + * @} + */ + +#include "leds.h" +#include "openwsn_leds.h" + +#include "board.h" +#include "periph/gpio.h" + +#include +#include + +/** holds the internal configuration for debug pins */ +static leds_config_t _configuration = { + GPIO_UNDEF, + GPIO_UNDEF, + GPIO_UNDEF, + GPIO_UNDEF, + GPIO_LED_HIGH, +}; + +static void _toggle_checked(gpio_t pin) +{ + if (IS_USED(MODULE_OPENWSN_LEDS)) { + if (pin != GPIO_UNDEF) { + gpio_toggle(pin); + } + } +} + +static void _init_checked(gpio_t pin) +{ + if (IS_USED(MODULE_OPENWSN_LEDS)) { + if (pin != GPIO_UNDEF) { + gpio_init(pin, GPIO_OUT); + } + } +} + +static void _write_checked(gpio_t pin, uint8_t on_state) +{ + if (IS_USED(MODULE_OPENWSN_LEDS)) { + if (pin != GPIO_UNDEF) { + gpio_write(pin, on_state); + } + } +} + +static uint8_t _is_on_checked(gpio_t pin) +{ + if (IS_USED(MODULE_OPENWSN_LEDS)) { + uint8_t ret = 0; + + if (pin != GPIO_UNDEF) { + ret = gpio_read(pin); + } + return ret; + } + else { + return 0; + } +} + +static void _blink_checked(gpio_t pin) +{ + if (IS_USED(MODULE_OPENWSN_LEDS)) { + /* toggle for ~10s if ztimer is used */ + for (uint8_t i = 0; i < 100; i++) { + _toggle_checked(pin); + for (uint32_t i = 0; i < (CLOCK_CORECLOCK / 50); i++) { + /* Make sure for loop is not optimized out */ + __asm__ (""); + } + } + } +} + +void ledpins_riot_init(const leds_config_t *user_config) +{ + if (IS_USED(MODULE_OPENWSN_LEDS)) { + if (user_config != NULL) { + memcpy(&_configuration, user_config, sizeof(leds_config_t)); + leds_init(); + } + } + else { + (void)user_config; + } +} + +void leds_init(void) +{ + _init_checked(_configuration.error); + _init_checked(_configuration.sync); + _init_checked(_configuration.radio); + _init_checked(_configuration.debug); + leds_all_off(); +} + +void leds_error_on(void) +{ + _write_checked(_configuration.error, _configuration.led_on); +} + +void leds_error_off(void) +{ + _write_checked(_configuration.error, ~_configuration.led_on); +} + +void leds_error_toggle(void) +{ + _toggle_checked(_configuration.error); +} + +uint8_t leds_error_isOn(void) +{ + return _is_on_checked(_configuration.error); +} + +void leds_error_blink(void) +{ + _blink_checked(_configuration.error); +} + +void leds_radio_on(void) +{ + _write_checked(_configuration.radio, _configuration.led_on); +} + +void leds_radio_off(void) +{ + _write_checked(_configuration.radio, ~_configuration.led_on); +} + +void leds_radio_toggle(void) +{ + _toggle_checked(_configuration.radio); +} + +uint8_t leds_radio_isOn(void) +{ + return _is_on_checked(_configuration.radio); +} + +void leds_sync_on(void) +{ + _write_checked(_configuration.sync, _configuration.led_on); +} + +void leds_sync_off(void) +{ + _write_checked(_configuration.sync, ~_configuration.led_on); +} + +void leds_sync_toggle(void) +{ + _toggle_checked(_configuration.sync); +} + +uint8_t leds_sync_isOn(void) +{ + return _is_on_checked(_configuration.sync); +} + +void leds_debug_on(void) +{ + _write_checked(_configuration.debug, _configuration.led_on); +} + +void leds_debug_off(void) +{ + _write_checked(_configuration.debug, ~_configuration.led_on); +} + +void leds_debug_toggle(void) +{ + _toggle_checked(_configuration.debug); +} + +uint8_t leds_debug_isOn(void) +{ + return _is_on_checked(_configuration.debug); +} + +void leds_all_on(void) +{ + leds_error_on(); + leds_radio_on(); + leds_sync_on(); + leds_debug_on(); +} + +void leds_all_off(void) +{ + leds_error_off(); + leds_radio_off(); + leds_sync_off(); + leds_debug_off(); +} + +void leds_all_toggle(void) +{ + leds_error_toggle(); + leds_radio_toggle(); + leds_sync_toggle(); + leds_debug_toggle(); +} + +void leds_circular_shift(void) +{ + /** not implemented */ +} + +void leds_increment(void) +{ + /** not implemented */ +} diff --git a/pkg/openwsn/contrib/openwsn.c b/pkg/openwsn/contrib/openwsn.c new file mode 100644 index 0000000000..4f9c578b41 --- /dev/null +++ b/pkg/openwsn/contrib/openwsn.c @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2018 Hamburg University of Applied Sciences + * 2020 Inria + * + * 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. + */ + +/** + * @{ + * @file + * @brief OpenWSN bootstraping functions implementation + * + * @author Peter Kietzmann + * @author Francisco Molina + */ + +#include "scheduler.h" +#include "openstack.h" +#include "radio.h" +#include "idmanager.h" + +#include "openwsn.h" +#include "openwsn_board.h" +#include "openwsn_radio.h" + +#ifdef MODULE_AT86RF2XX +#include "at86rf2xx.h" +#include "at86rf2xx_params.h" +#endif + +#define LOG_LEVEL LOG_NONE +#include "log.h" + +#define OPENWSN_SCHED_NAME "openwsn" +#define OPENWSN_SCHED_PRIO (THREAD_PRIORITY_MAIN - 4) +#define OPENWSN_SCHED_STACKSIZE (2048) + +#ifdef MODULE_AT86RF2XX +static at86rf2xx_t at86rf2xx_dev; +#endif + +static char _stack[OPENWSN_SCHED_STACKSIZE]; + +static kernel_pid_t _pid = KERNEL_PID_UNDEF; + +static void *_event_loop(void *arg); + +kernel_pid_t openwsn_get_pid(void) +{ + return _pid; +} + +#ifdef MODULE_OPENWSN_RADIO +void openwsn_set_addr_16b(netdev_t* dev) +{ + uint8_t addr[IEEE802154_SHORT_ADDRESS_LEN]; + dev->driver->get(dev, NETOPT_ADDRESS, addr, IEEE802154_SHORT_ADDRESS_LEN); + open_addr_t id; + id.type = ADDR_16B; + memcpy(&id.addr_16b, addr, IEEE802154_SHORT_ADDRESS_LEN); + idmanager_setMyID(&id); +} +#endif + +int openwsn_bootstrap(void) +{ + LOG_DEBUG("[openwsn]: init RIOT board\n"); + board_init_openwsn(); + +#ifdef MODULE_AT86RF2XX + netdev_t *netdev = (netdev_t *)&at86rf2xx_dev.netdev.netdev; + at86rf2xx_setup(&at86rf2xx_dev, &at86rf2xx_params[0]); + (void) netdev; +#endif + +#ifdef MODULE_OPENWSN_RADIO + LOG_DEBUG("[openwsn]: init radio\n"); + if (openwsn_radio_init(netdev)) { + LOG_ERROR("[openwsn]: failed to init radio\n"); + return -1; + } +#endif + + /* Initiate Id manager here and not in `openstack_init` function to allow + overriding the short id address before additional stack components are + initiated */ + idmanager_init(); + +#ifdef MODULE_OPENWSN_RADIO + /* override 16b address to avoid short address collision */ + openwsn_set_addr_16b(netdev); +#endif + + LOG_DEBUG("[openwsn]: network thread\n"); + _pid = thread_create(_stack, OPENWSN_SCHED_STACKSIZE, OPENWSN_SCHED_PRIO, + THREAD_CREATE_STACKTEST, _event_loop, NULL, + OPENWSN_SCHED_NAME); + if (_pid <= 0) { + LOG_ERROR("[openwsn]: couldn't create thread\n"); + return -1; + } + + return _pid; +} + +static void *_event_loop(void *arg) +{ + (void)arg; + + LOG_DEBUG("[openwsn]: init scheduler\n"); + scheduler_init(); + LOG_DEBUG("[openwsn]: init openstack\n"); + /* Disable IRQ while scheduler is not ready to start */ + unsigned irq_state = irq_disable(); + openstack_init(); + LOG_DEBUG("[openwsn]: start scheduler loop\n"); + scheduler_start(irq_state); + + return NULL; +} diff --git a/pkg/openwsn/contrib/radio.c b/pkg/openwsn/contrib/radio.c new file mode 100644 index 0000000000..fad125de3a --- /dev/null +++ b/pkg/openwsn/contrib/radio.c @@ -0,0 +1,268 @@ +/* + * Copyright (C) 2018 Hamburg University of Applied Sciences + * 2020 Inria + * + * 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. + */ + +/** + * @ingroup pkg_openwsn + * @{ + * + * @file + * @brief RIOT adaption of the "radio" bsp module + * + * @author Peter Kietzmann + * @author Oliver Hahm + * @author Francisco Molina + * @} + */ +#include + +#include "leds.h" +#include "debugpins.h" +#include "sctimer.h" + +#include "net/netopt.h" +#include "net/ieee802154.h" +#include "net/netdev/ieee802154.h" + +#include "openwsn.h" +#include "openwsn_radio.h" + +#define LOG_LEVEL LOG_NONE +#include "log.h" + +openwsn_radio_t openwsn_radio; + +static void _event_cb(netdev_t *dev, netdev_event_t event); + +/* stores the NETDEV_EVENT_ISR capture time to tag the following NETDEV_EVENT */ +static PORT_TIMER_WIDTH _txrx_event_capture_time = 0; + +int openwsn_radio_init(netdev_t *netdev) +{ + assert(netdev); + + LOG_DEBUG("[openwsn/radio]: initialize riot-adaptation\n"); + openwsn_radio.dev = netdev; + + if (netdev->driver->init(netdev)) { + LOG_ERROR("[openwsn/radio]: unable to initialize device\n"); + return -1; + } + netdev->event_callback = _event_cb; + + LOG_DEBUG("[openwsn/radio]: put radio in standby\n"); + netopt_state_t state = NETOPT_STATE_STANDBY; + netdev->driver->set(netdev, NETOPT_STATE, &(state), sizeof(state)); + + LOG_DEBUG("[openwsn/radio]: set needed netdev options\n"); + netopt_enable_t enable; + /* Enable needed IRQs */ + enable = NETOPT_ENABLE; + netdev->driver->set(netdev, NETOPT_TX_START_IRQ, &(enable), sizeof(enable)); + enable = NETOPT_ENABLE; + netdev->driver->set(netdev, NETOPT_RX_START_IRQ, &(enable), sizeof(enable)); + enable = NETOPT_ENABLE; + netdev->driver->set(netdev, NETOPT_RX_END_IRQ, &(enable), sizeof(enable)); + enable = NETOPT_ENABLE; + netdev->driver->set(netdev, NETOPT_TX_END_IRQ, &(enable), sizeof(enable)); + enable = NETOPT_DISABLE; + /* Enable basic mode, no AUTOACK. no CSMA , no frame filtering */ + netdev->driver->set(netdev, NETOPT_AUTOACK, &(enable), sizeof(enable)); + enable = NETOPT_DISABLE; + netdev->driver->set(netdev, NETOPT_CSMA, &(enable), sizeof(enable)); + enable = NETOPT_ENABLE; + netdev->driver->set(netdev, NETOPT_RAWMODE, &(enable), sizeof(enable)); + uint8_t retrans = 0; + /* MAC layer will handle retransmissions */ + netdev->driver->set(netdev, NETOPT_RETRANS, &(retrans), sizeof(uint8_t)); + /* Enable TX with preloading */ + enable = NETOPT_ENABLE; + netdev->driver->set(netdev, NETOPT_PRELOADING, &(enable), sizeof(enable)); + /* Set default PANID */ + uint16_t panid = OPENWSN_PANID; + netdev->driver->set(netdev, NETOPT_NID, &(panid), sizeof(uint16_t)); + + return 0; +} + +void radio_setStartFrameCb(radio_capture_cbt cb) +{ + openwsn_radio.startFrame_cb = cb; +} + +void radio_setEndFrameCb(radio_capture_cbt cb) +{ + openwsn_radio.endFrame_cb = cb; +} + +void radio_reset(void) +{ + netopt_state_t state = NETOPT_STATE_RESET; + + openwsn_radio.dev->driver->set(openwsn_radio.dev, NETOPT_STATE, &(state), + sizeof(netopt_state_t)); + + state = NETOPT_STATE_STANDBY; + openwsn_radio.dev->driver->set(openwsn_radio.dev, NETOPT_STATE, &(state), + sizeof(netopt_state_t)); +} + +void radio_setFrequency(uint8_t frequency, radio_freq_t tx_or_rx) +{ + (void)tx_or_rx; + + uint16_t chan = frequency; + openwsn_radio.dev->driver->set(openwsn_radio.dev, NETOPT_CHANNEL, &(chan), + sizeof(chan)); +} + +void radio_rfOn(void) +{ + netopt_state_t state = NETOPT_STATE_IDLE; + + openwsn_radio.dev->driver->set(openwsn_radio.dev, NETOPT_STATE, &(state), + sizeof(netopt_state_t)); +} + +void radio_rfOff(void) +{ + netopt_state_t state = NETOPT_STATE_STANDBY; + + openwsn_radio.dev->driver->set(openwsn_radio.dev, NETOPT_STATE, &(state), + sizeof(netopt_state_t)); + + debugpins_radio_clr(); + leds_radio_off(); +} + +void radio_loadPacket(uint8_t *packet, uint16_t len) +{ + /* NETOPT_PRELOADING is enabled in radio_init so this will only load the + packet */ + /* OpenWSN `len` accounts for the FCS field which is set by default by + netdev, so remove from the actual packet `len` */ + iolist_t pkt = { + .iol_base = (void *)packet, + .iol_len = (size_t)(len - IEEE802154_FCS_LEN), + }; + + if (openwsn_radio.dev->driver->send(openwsn_radio.dev, &pkt) < 0) { + LOG_DEBUG("[openwsn/radio]: couldn't load pkt\n"); + } + LOG_DEBUG("[openwsn/radio]: loaded radio packet\n"); +} + +void radio_txEnable(void) +{ + debugpins_radio_set(); + leds_radio_on(); +} + +void radio_txNow(void) +{ + netopt_state_t state = NETOPT_STATE_TX; + + openwsn_radio.dev->driver->set(openwsn_radio.dev, NETOPT_STATE, &state, + sizeof(netopt_state_t)); +} + +void radio_rxEnable(void) +{ + debugpins_radio_set(); + leds_radio_on(); + netopt_state_t state = NETOPT_STATE_IDLE; + openwsn_radio.dev->driver->set(openwsn_radio.dev, NETOPT_STATE, &(state), + sizeof(state)); +} + +void radio_rxNow(void) +{ + /* nothing to do */ +} + +void radio_getReceivedFrame(uint8_t *bufRead, + uint8_t *lenRead, + uint8_t maxBufLen, + int8_t *rssi, + uint8_t *lqi, + bool *crc) +{ + /* OpenWSN packets are 130 bytes to hold all required data for an SPI + transaction since in some implementations it's used directly in the SPI + shift register: + - 1B spi address, 1B length, 125B data, 2B CRC, 1B LQI + In RIOT we don't do this so maxBufLen is irrelevant, packet size will + always be enough to hold IEEE802154_FRAME_LEN_MAX, but in practice only + 125B of data are copied into bufRead. + */ + (void)maxBufLen; + netdev_ieee802154_rx_info_t rx_info; + + int bytes_expected = openwsn_radio.dev->driver->recv(openwsn_radio.dev, + NULL, 0, + NULL); + + if (bytes_expected < (int)(IEEE802154_ACK_FRAME_LEN - IEEE802154_FCS_LEN)) { + /* drop invalid packet */ + openwsn_radio.dev->driver->recv(openwsn_radio.dev, NULL, bytes_expected, + NULL); + radio_rxEnable(); + return; + } + + int nread = openwsn_radio.dev->driver->recv(openwsn_radio.dev, bufRead, + bytes_expected, &rx_info); + + /* FCS is skipped by netdev in the returned length, but OpenWSN includes + IEEE802154_FCS_LEN in its length value */ + *lenRead = nread + IEEE802154_FCS_LEN; + + /* get rssi, lqi & crc */ + *rssi = rx_info.rssi; + *lqi = rx_info.lqi; + /* only valid crc frames are currently accepted */ + *crc = 1; + + radio_rxEnable(); +} + +static void _event_cb(netdev_t *dev, netdev_event_t event) +{ + (void)dev; + + if (event == NETDEV_EVENT_ISR) { + /* capture the time */ + debugpins_isr_set(); + _txrx_event_capture_time = sctimer_readCounter(); + openwsn_radio.dev->driver->isr(openwsn_radio.dev); + debugpins_isr_clr(); + } + else { + LOG_DEBUG("[openwsn/radio]: event triggered -> %i\n", event); + switch (event) { + case NETDEV_EVENT_RX_STARTED: + openwsn_radio.startFrame_cb(_txrx_event_capture_time); + LOG_DEBUG("[openwsn/radio]: NETDEV_EVENT_RX_STARTED\n"); + break; + case NETDEV_EVENT_TX_STARTED: + openwsn_radio.startFrame_cb(_txrx_event_capture_time); + LOG_DEBUG("[openwsn/radio]: NETDEV_EVENT_TX_STARTED\n"); + break; + case NETDEV_EVENT_RX_COMPLETE: + openwsn_radio.endFrame_cb(_txrx_event_capture_time); + LOG_DEBUG("[openwsn/radio]: NETDEV_EVENT_RX_COMPLETE\n"); + break; + case NETDEV_EVENT_TX_COMPLETE: + openwsn_radio.endFrame_cb(_txrx_event_capture_time); + LOG_DEBUG("[openwsn/radio]: NETDEV_EVENT_TX_COMPLETE\n"); + break; + default: + break; + } + } +} diff --git a/pkg/openwsn/contrib/sctimer_rtt.c b/pkg/openwsn/contrib/sctimer_rtt.c new file mode 100644 index 0000000000..1efdcd9781 --- /dev/null +++ b/pkg/openwsn/contrib/sctimer_rtt.c @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2017 Hamburg University of Applied Sciences + * 2020 Inria + * + * 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. + */ + +/** + * @ingroup pkg_openwsn + * @{ + * + * For details on the implementation check pkg/openwsn/doc.txt + * + * @file + * @brief RTT based adaptation of "sctimer" bsp module + * + * @author Tengfei Chang , July 2012 + * @author Peter Kietzmann , July 2017 + * @author Michel Rottleuthner , April 2019 + * @author Francisco Molina + * + * @} + */ +#include + +#include "sctimer.h" +#include "debugpins.h" + +#include "board.h" +#include "periph/rtt.h" + +#define LOG_LEVEL LOG_NONE +#include "log.h" + +/** + * @brief Maximum counter difference to not consider an ISR late, this + * should account for the largest timer interval OpenWSN + * scheduler might work with. When running only the stack this + * should not be more than SLOT_DURATION, but when using cjoin + * it is 65535ms + */ +#ifndef SCTIMER_LOOP_THRESHOLD +#define SCTIMER_LOOP_THRESHOLD (2 * PORT_TICS_PER_MS * 65535) +#endif + +/* OpenWSN needs at least 32 tics per ms,use time division to reach that + if needed */ +#ifdef RTT_FREQUENCY +#if RTT_FREQUENCY < 32768U +#define SCTIMER_TIME_DIVISION (1) +#if (SCTIMER_FREQUENCY % RTT_FREQUENCY) != 0 +#error "RTT_FREQUENCY not supported" +#endif +#endif +#endif + +#ifdef SCTIMER_TIME_DIVISION +#define SCTIMER_PRESCALER __builtin_ctz( \ + SCTIMER_FREQUENCY / RTT_FREQUENCY) +#define SCTIMER_TIME_DIVISION_MASK (RTT_MAX_VALUE >> SCTIMER_PRESCALER) +#define SCTIMER_PRESCALER_MASK (~SCTIMER_TIME_DIVISION_MASK) +#define SCTIMER_PRESCALER_SHIFT __builtin_ctz(SCTIMER_TIME_DIVISION_MASK) + +static uint32_t _prescaler; +static atomic_bool _enable; +#endif + +static sctimer_cbt sctimer_cb; + +static void sctimer_isr_internal(void *arg) +{ + (void)arg; + + if (sctimer_cb != NULL) { + debugpins_isr_set(); + sctimer_cb(); + debugpins_isr_clr(); + } +} + +void sctimer_init(void) +{ + rtt_init(); + sctimer_cb = NULL; +#ifdef SCTIMER_TIME_DIVISION + _prescaler = 0; + _enable = false; +#endif +} + +void sctimer_set_callback(sctimer_cbt cb) +{ + sctimer_cb = cb; +} + +#ifdef SCTIMER_TIME_DIVISION +uint32_t _update_val(uint32_t val, uint32_t now) +{ + now = now & SCTIMER_PRESCALER_MASK; + val = val >> SCTIMER_PRESCALER; + /* Check if next value would cause an overflow */ + if ((now - val) > SCTIMER_LOOP_THRESHOLD && _enable && now > val) { + _prescaler += (1 << SCTIMER_PRESCALER_SHIFT); + _enable = false; + } + /* Make sure it only updates the _prescaler once per overflow cycle */ + if (val > SCTIMER_LOOP_THRESHOLD && val < 2 * SCTIMER_LOOP_THRESHOLD) { + _enable = true; + } + val |= _prescaler; + + return val; +} +#endif + +void sctimer_setCompare(uint32_t val) +{ + unsigned state = irq_disable(); + + uint32_t now = rtt_get_counter(); + +#ifdef SCTIMER_TIME_DIVISION + val = _update_val(val, now); +#endif + + if ((int32_t)now - val < SCTIMER_LOOP_THRESHOLD && now > val) { + rtt_set_alarm((now + RTT_MIN_OFFSET) & RTT_MAX_VALUE, + sctimer_isr_internal, NULL); + } + else { + if ((int32_t)val - now < RTT_MIN_OFFSET) { + rtt_set_alarm((now + RTT_MIN_OFFSET) & RTT_MAX_VALUE, + sctimer_isr_internal, NULL); + } + else { + rtt_set_alarm(val & RTT_MAX_VALUE, sctimer_isr_internal, + NULL); + } + } + + irq_restore(state); + + LOG_DEBUG("[sctimer]: set cb to %" PRIu32 " at %" PRIu32 "\n", + (uint32_t) val, now); +} + +uint32_t sctimer_readCounter(void) +{ + uint32_t now = rtt_get_counter(); + +#ifdef SCTIMER_TIME_DIVISION + now &= SCTIMER_TIME_DIVISION_MASK; + now = (now << SCTIMER_PRESCALER); +#endif + LOG_DEBUG("[sctimer]: now %" PRIu32 "\n", now); + return now; +} + +void sctimer_enable(void) +{ + rtt_poweron(); +} + +void sctimer_disable(void) +{ + rtt_poweroff(); +} diff --git a/pkg/openwsn/contrib/sctimer_ztimer.c b/pkg/openwsn/contrib/sctimer_ztimer.c new file mode 100644 index 0000000000..e1ab32a632 --- /dev/null +++ b/pkg/openwsn/contrib/sctimer_ztimer.c @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2020 Inria + * + * 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. + */ + +/** + * @ingroup pkg_openwsn + * @{ + * + * @file + * @brief Ztimer based adaptation of "sctimer" bsp module + * + * For details on the implementation check pkg/openwsn/doc.txt + * + * @author Francisco Molina + * + * @} + */ +#include "sctimer.h" +#include "debugpins.h" + +#include "ztimer.h" +#include "ztimer/convert.h" +#include "ztimer/convert_frac.h" +#include "ztimer/convert_shift.h" +#include "ztimer/config.h" + +#include "periph_conf.h" + +#define LOG_LEVEL LOG_NONE +#include "log.h" + +/** + * @brief Maximum counter difference to not consider an ISR late, this + * should account for the largest timer interval OpenWSN + * scheduler might work with. When running only the stack this + * should not be more than SLOT_DURATION, but when using cjoin + * it is 65535ms + */ +#ifndef SCTIMER_LOOP_THRESHOLD +#define SCTIMER_LOOP_THRESHOLD (2 * PORT_TICS_PER_MS * 65535) +#endif + +#if CONFIG_ZTIMER_MSEC_BASE_FREQ > 32768U +static ztimer_convert_frac_t _ztimer_convert_frac_32768; +#define ZTIMER_32768_CONVERT_LOWER_FREQ CONFIG_ZTIMER_MSEC_BASE_FREQ +#define ZTIMER_32768_CONVERT_LOWER (ZTIMER_MSEC_BASE) +/* cppcheck-suppress preprocessorErrorDirective + * (reason: cppcheck fails to see that CONFIG_ZTIMER_MSEC_BASE_FREQ + * is set in ztimer/config.h to a non zero value */ +#elif (CONFIG_ZTIMER_MSEC_BASE_FREQ < 32768U) && \ + ((32768U % CONFIG_ZTIMER_MSEC_BASE_FREQ) == 0) +static ztimer_convert_shift_t _ztimer_convert_shift_32768; +#define ZTIMER_32768_CONVERT_HIGHER_FREQ CONFIG_ZTIMER_MSEC_BASE_FREQ +#define ZTIMER_32768_CONVERT_HIGHER (ZTIMER_MSEC_BASE) +#elif (CONFIG_ZTIMER_MSEC_BASE_FREQ < 32768U) && \ + ((32768U % CONFIG_ZTIMER_MSEC_BASE_FREQ) != 0) +#error No suitable ZTIMER_MSEC_BASE config. Maybe add USEMODULE += ztimer_usec? +#endif + +static sctimer_cbt _sctimer_cb; +static ztimer_t _ztimer_sctimer; +static ztimer_clock_t *ZTIMER_32768 = NULL; + +static void sctimer_isr_internal(void *arg) +{ + (void)arg; + + if (_sctimer_cb != NULL) { + debugpins_isr_set(); + _sctimer_cb(); + debugpins_isr_clr(); + } +} + +void sctimer_init(void) +{ +#if CONFIG_ZTIMER_MSEC_BASE_FREQ > 32768U + ZTIMER_32768 = &_ztimer_convert_frac_32768.super.super; +/* cppcheck-suppress preprocessorErrorDirective + * (reason: cppcheck fails to see that CONFIG_ZTIMER_MSEC_BASE_FREQ + * is set in ztimer/config.h to a non zero value */ +#elif (CONFIG_ZTIMER_MSEC_BASE_FREQ < 32768U) && \ + (32768U % CONFIG_ZTIMER_MSEC_BASE_FREQ == 0) + ZTIMER_32768 = &_ztimer_convert_shift_32768.super.super; +#elif CONFIG_ZTIMER_MSEC_BASE_FREQ == 32768U + ZTIMER_32768 = ZTIMER_MSEC_BASE; +#else +#error Invalid ZTIMER_MSEC_BASE_FREQ config. Maybe add USEMODULE += ztimer_usec? +#endif + +#if defined(ZTIMER_32768_CONVERT_LOWER) + LOG_DEBUG("[sctimer]: ZTIMER_32768 convert_frac from %lu to 32768\n", + (long unsigned)ZTIMER_32768_CONVERT_LOWER_FREQ); + ztimer_convert_frac_init(&_ztimer_convert_frac_32768, + ZTIMER_32768_CONVERT_LOWER, + SCTIMER_FREQUENCY, + ZTIMER_32768_CONVERT_LOWER_FREQ); +#elif defined(ZTIMER_32768_CONVERT_HIGHER) + LOG_DEBUG("[sctimer]: ZTIMER_32768 convert_shift %lu to 32768\n", + (long unsigned)ZTIMER_32768_CONVERT_HIGHER_FREQ); + ztimer_convert_shift_up_init(&_ztimer_convert_shift_32768, + ZTIMER_32768_CONVERT_HIGHER, + __builtin_ctz(SCTIMER_FREQUENCY / + CONFIG_ZTIMER_MSEC_BASE_FREQ)); +#endif + + _ztimer_sctimer.callback = sctimer_isr_internal; +} + +void sctimer_set_callback(sctimer_cbt cb) +{ + _sctimer_cb = cb; +} + +void sctimer_setCompare(uint32_t val) +{ + unsigned state = irq_disable(); + + uint32_t now = ztimer_now(ZTIMER_32768); + + /* if the next compare value (isr) to schedule is already later than + the required value, but close enough to think we have been slow + in scheduling it, trigger the ISR right away */ + if (now > val) { + if (now - val < SCTIMER_LOOP_THRESHOLD) { + ztimer_set(ZTIMER_32768, &_ztimer_sctimer, 0); + } + else { + ztimer_set(ZTIMER_32768, &_ztimer_sctimer, + UINT32_MAX - now + val); + } + } + else { + ztimer_set(ZTIMER_32768, &_ztimer_sctimer, val - now); + } + + irq_restore(state); + + LOG_DEBUG("[sctimer]: set cb to %" PRIu32 " at %" PRIu32 "\n", + val, now); +} + +uint32_t sctimer_readCounter(void) +{ + uint32_t now = ztimer_now(ZTIMER_32768); + + LOG_DEBUG("[sctimer]: now %" PRIu32 "\n", now); + return now; +} + +void sctimer_enable(void) +{ + /* not supported, sctimer does not control RTT or ztimer */ +} + +void sctimer_disable(void) +{ + /* not supported, sctimer does not control RTT or ztimer */ +} diff --git a/pkg/openwsn/contrib/uart.c b/pkg/openwsn/contrib/uart.c new file mode 100644 index 0000000000..83f22c3630 --- /dev/null +++ b/pkg/openwsn/contrib/uart.c @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2018 Hamburg University of Applied Sciences + * 2020 Inria + * + * 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. + */ + +/** + * @ingroup pkg_openwsn + * @{ + * + * @file + * @brief RIOT adaption of the OpenWSN "uart" bsp module. + * + * @author Peter Kietzmann + * @author Francisco Molina + * + * @} + */ + +#include + +#include "board.h" +#include "periph/uart.h" + +#ifdef MODULE_ZTIMER_USEC +#include "ztimer.h" +#endif + +#include "openwsn_uart.h" + +#define XOFF 0x13 +#define XON 0x11 +#define XONXOFF_ESCAPE 0x12 +#define XONXOFF_MASK 0x10 + +typedef struct { + uart_tx_cbt txCb; + uart_rx_cbt rxCb; + atomic_bool fXonXoffEscaping; + atomic_char xonXoffEscapedByte; +} uart_vars_t; + +static uart_vars_t _uart_vars; +static atomic_char _uart_rx_byte; + +#ifdef MODULE_ZTIMER_USEC +static ztimer_t _ztimer_tx_uart; +#endif + +static void _openwsn_uart_write(const uint8_t *data) +{ + if (IS_USED(MODULE_OPENWSN_SERIAL)) { + uart_write(OPENWSN_UART_DEV, data, 1); +#ifdef MODULE_ZTIMER_USEC + ztimer_set(ZTIMER_USEC, &_ztimer_tx_uart, 0); +#endif + } +} + +static void _riot_rx_cb(void *arg, uint8_t data) +{ + (void)arg; + if (IS_USED(MODULE_OPENWSN_SERIAL)) { + _uart_rx_byte = data; + if (_uart_vars.rxCb) { + _uart_vars.rxCb(); + } + } + else { + (void)data; + } +} + +static void _riot_tx_cb(void *arg) +{ + (void)arg; + + if (IS_USED(MODULE_OPENWSN_SERIAL)) { + if (_uart_vars.fXonXoffEscaping == 0x01) { + _uart_vars.fXonXoffEscaping = 0x00; + _uart_vars.xonXoffEscapedByte ^= XONXOFF_MASK; + _openwsn_uart_write((uint8_t *)&(_uart_vars.xonXoffEscapedByte)); + } + else { + if (_uart_vars.txCb) { + _uart_vars.txCb(); + } + } + } +} + +void uart_enableInterrupts(void) +{ + /* unused in RIOT */ +} + +void uart_disableInterrupts(void) +{ + /* unused in RIOT */ +} + +void uart_clearRxInterrupts(void) +{ + /* unused in RIOT */ +} + +void uart_clearTxInterrupts(void) +{ + /* unused in RIOT */ +} + +void uart_init_openwsn(void) +{ + if (IS_USED(MODULE_OPENWSN_SERIAL)) { + uart_init(OPENWSN_UART_DEV, OPENWSN_UART_BAUDRATE, \ + (uart_rx_cb_t)_riot_rx_cb, NULL); +#ifdef MODULE_ZTIMER_USEC + _ztimer_tx_uart.callback = &_riot_tx_cb; +#else + (void) _riot_tx_cb; +#endif + } +} + +void uart_setCallbacks(uart_tx_cbt txCb, uart_rx_cbt rxCb) +{ + if (IS_USED(MODULE_OPENWSN_SERIAL)) { + _uart_vars.txCb = txCb; + _uart_vars.rxCb = rxCb; + } + else { + (void)rxCb; + (void)txCb; + } +} + +void uart_setCTS(bool state) +{ + if (IS_USED(MODULE_OPENWSN_SERIAL)) { + uint8_t byte; + if (state == true) { + byte = XON; + } + else { + byte = XOFF; + } + _openwsn_uart_write(&byte); + } + else { + (void)state; + } +} + +void uart_writeByte(uint8_t byteToWrite) +{ + if (IS_USED(MODULE_OPENWSN_SERIAL)) { + if (byteToWrite == XON || byteToWrite == XOFF || \ + byteToWrite == XONXOFF_ESCAPE) { + uint8_t byte = XONXOFF_ESCAPE; + _uart_vars.fXonXoffEscaping = 0x01; + _uart_vars.xonXoffEscapedByte = byteToWrite; + _openwsn_uart_write(&byte); + } + else { + _openwsn_uart_write(&byteToWrite); + } + } + else { + (void)byteToWrite; + } +} + +inline uint8_t uart_readByte(void) +{ + if (IS_USED(MODULE_OPENWSN_SERIAL)) { + return _uart_rx_byte; + } + else { + return 0x00; + } +} diff --git a/pkg/openwsn/doc.txt b/pkg/openwsn/doc.txt new file mode 100644 index 0000000000..94d97326cb --- /dev/null +++ b/pkg/openwsn/doc.txt @@ -0,0 +1,420 @@ +/** + @defgroup pkg_openwsn OpenWSN network stack + @ingroup pkg + @ingroup net + @brief Provides a RIOT adaption of the OpenWSN network stack + @see https://github.com/openwsn-berkeley/openwsn-fw + @experimental + + # OpenWSN RIOT Port + + This implementation integrates the [OpenWSN](https://github.com/openwsn-berkeley/openwsn-fw) + full network stack (UDP, IPv6 (6LoWPAN), RPL, 6TiSCH) into RIOT. + + It can be used instead of GNRC on supported 802.15.4 radios, and compared to + GNRC, provides a full 6TiSCH implementation. It does not yet support RIOT's + sock API, so applications will have to be written against OpenWSN's API. + + This port provides a new RIOT "board" to the OpenWSN software. In this way + RIOT's hardware abstraction connects to OpenWSN's interfaces. + + The simple scheduling mechanism in OpenWSN is run in a RIOT thread with + second highest priority after the radio thread (THREAD_PRIORITY_MAIN - 4). + + The current port of OpenWSN currently needs a root node that works along an + external tool that performs routing and handles join procedure: + [Openvisualizer](https://github.com/openwsn-berkeley/openvisualizer) + + + ## Joining a network + + The first thing a new mote will need to do is to find a network. On boot it + will actively be listening for enhanced beacons. Once a beacon is received it + will adjust its timers drift and synchronize with the network. Re-synchronization + will be happening constantly to compensate for oscillator and timer drifts. + + Once synchronized the node will need to join the network. OpenWSN uses CoJP + [constrained join protocol](https://datatracker.ietf.org/doc/draft-ietf-6tisch-minimal-security/) + an the stack itself only handles Join Requests. The JRC (join registrar/coordinator, + a central entity) is not running on the root node, but alongside it, in the + `OpenVisualizer` external tool. + + Once joined the device has the required keys to start listening to DIS (DODAG + Information Solicitation) messages and to send DIO (DODAG Information Object) + requests. Once it knows about the topology of the network it is able to + send packets. + + OpenWSN uses source routing. This means that unless the recipient of a packet + is one of the parents in the RPL tree the packet will have to go up the tree + to the root node. But in OpenWSN RPL implementation the node does not know + how to route, instead it is `OpenVisualizer` which generates an SRH (Source + Routing Header), attaches to the incoming packet and sends it down the tree. + + ## Hardware abstraction implementation + + Following, details about the implementation of selected hardware modules. + + ### sctimer + + The `sctimer` ("single compare timer") in OpenWSN is the lowest timer + abstraction which is used by the higher layer timer module `opentimers`. In + the end it is responsible for scheduling on the MAC layer. To enable low power + energy modes, this timer usually uses the RTC (real time clock) or RTT (real + time timer) module. + + This port has two possible implementations or sctimer, one on top of + periph_rtt and another on top of ztimer, `sctimer_rtt` and `sctimer_ztimer` + respectively. If possible `ztimer` should be preferred, being a virtual + timer it will allow RIOT applications/modules to use the low level RTT timer. + But ztimer (any virtual timer) has some overhead which can be costly + depending on the different platforms used, specially when `openserial` + is required. More on this in openserial and Known Issues. + + #### sctimer_ztimer + + In order to get the most portable code, this implementation uses + ztimer and defines a new `ztimer_clock` (`ZTIMER_32768`) that operates + at 32768Khz to have a resolution of ~30usec/tick (same as OpenWSN). + + When available `ZTIMER_32768` will be built on top of `periph_rtt` to + get low power capabilities. If not it will be built on top of a + regular timer. In either case it will be shifted up if the base + frequency is lower than 32768Hz or frac if higher. + + When next interrupt to schedule is already late, current time, + implementations in OpenWSN directly trigger a hardware interrupt. + Until able to trigger sw isr directly a callback is set 0 ticks in + the future, which internally will be set to `now + RTT_MIN_OFFSET`. + + #### sctimer_rtt + + In order to reduce overhead this implementation uses bare RTT. It + expects a RTT running at 32768Hz to have a resolution of ~30usec/tick + (same as OpenWSN). If `RTT_FREQUENCY` is lower than 32768Hz then a + simple time-division mechanism will be used to speed up the clock. + This only works if `RTT_FREQUENCY` is 32768Hz/2. + + When next interrupt to schedule is already late, current time, + Implementations in OpenWSN directly trigger a hardware interrupt. + Until able to trigger sw isr directly a callback is set + `RTT_MIN_OFFSET` ticks in the future. + + ### radio + + The radio adaptation runs in its own thread with the highest priority + (`THREAD_PRIORITY_MAIN - 4`) and maps to RIOT's @ref netdev API. + + Hardware MAC layer features such as CSMA/CA, ACK handling and retransmissions + are handled by OpenWSN, so the radio driver must support disabling AUTOACK + and CSMA handling by the hardware. Frame filtering must as well be disabled. + + The radio adaptation preloads the buffer so `NETOPT_PRELOADING` must be + supported. + + OpenWSN needs to be notified when a frame reception/transmission starts and + when it ends. Therefore radio drivers need to support the following netdev + events: + + - `NETDEV_EVENT_RX_STARTED` + - `NETDEV_EVENT_TX_STARTED` + - `NETDEV_EVENT_RX_COMPLETE` + - `NETDEV_EVENT_TX_COMPLETE` + + OpenWSN expects to recover crc information on every received frame even if it + will simply drop frames with invalid crc. The stack can function correctly if + radio drivers automatically drop frames with an invalid crc (i.e. the stack + doesn't get notified about these frames). + + ### uart + + In RIOT, the first configured uart device is mapped to STDIO in most cases. + In OpenWSN however, the `openserial` tool uses uart to feed external software + running on a host computer such as + [Openvisualizer](https://github.com/openwsn-berkeley/openvisualizer). + To enable use of these tools, an uart adaptation is provided. + + This is provided through the `openwsn_serial` (`openserial`) module. It + will use the next available uart that is not used by STDIO + (checking STDIO_UART_DEV). When multiple uart are available STDIO and + `openserial` can be used in parallel. If `stdio_null` is used then `openserial` + will use `STDIO_UART_DEV`, otherwise it will use the next available uart. + e.g. If `STDIO_UART_DEV = UART_DEV(1)` `OPENWSN_UART_DEV = UART_DEV(0)` if + there are uarts. + + OpenWSN uart abstraction makes use of tx hardware interrupts to execute a + previously registered callback after every byte is sent out. These interrupts + are currently not defined in RIOT in a generic way, so instead a timer is set + to fire shortly after a byte is written. + + It uses `ztimer` to set the timer since it's already pulled in as a dependency. + + ### Openserial + + As was mentioned before any OpenWSN network will require a root node which is + connected to an `OpenVisualizer` instance running on a host computer. + Interaction between `OpenVisualizer` and the root-node is done over serial. As + OpenWSN uses source routing, this means that ultimately all network traffic + must go from the root node to `OpenVisualizer` and back. + + OpenSerial uses software flow control (XonXoff) to turn off serial activity + while time critical TSCH operation are ongoing. But software flow control + can cause issues since delays in the serial pipe (either because of a remote + connection, buffers, etc..) can lead to bytes being transmitted when one side + is not yet ready. + + Serial data is transmitted as High-Level Data Link Control (HDLC) frames. + Since network traffic is tunneled through the serial pipe, in order to + to have a stable connection these packets must not be lost. Packets can be + lost in multiple ways but at the end it reduces to bytes being overridden in + the uart reception buffer. + + 1. The last byte in an HDCL frame is received + 2. Serial pipe delays hindering XonXoff operation + 3. Interrupts are masked or higher/equal ISR are running + + 1. When the last byte of a frame is received some parsing and handling of the + frame occur. This takes some time and during that time OpenSerial can't + handle more incoming bytes. This in practice limits the baudrate depending + on the CPU's speed. + + 2. This can occur when a debugger/virtual-port might act as a + buffer between the mote and the host, or when there is a latency in the + connection (for example tcp connection to iotlab). + + 3. Since uart reception is interrupted based if the uart ISR is not serviced + for too long then bytes start overriding each other in the reception + buffer. In an application where only OpenWSN is running then there are 3 + functions/operations that run in ISR or with disabled ISR. + + (a) `opentimers_timer_callback` (OpenWSN timer abstraction callback) + (b) `sctimer_setCompare` and `sctimer_readCounter` + (c) `ztimer_handler` + + (a) and (b) are closely related since `opentimers_timer_callback` will + itself call `sctimer_setCompare` and `sctimer_readCounter`. And this itself + will depend on `ztimer_set` and `ztimer_now` or `rtt_get_counter` or + `rtt_set_alarm` execution time. + + (c) is also related to (a) (b) since `ztimer_handler` will also call + `opentimers_timer_callback` as well as the underlying `rtt` functions. + + Since a 115200 baudrate means ~1byte every 10us, none of the above can take + longer than that or bytes could be lost at that baudrate. + + Because of the above mentioned reasons, it is preferable to use `sctimer_rtt` + for the root node or "border router" on an OpenWSN network, since this reduces + the likeliness of packets being lost. For non root nodes, OpenSerial only + provides debugging information so no special care needs to be taken. + + It is also recommended that the root node should act as a border router + running only the OpenWSN stack to avoid other threads/ISR disrupting serial + reception. + + ## Tested Platforms and Pin configurations + + So far, this has been successfully tested on `iotlab-m3`,`nucleo-f103` and + `samr21-xpro`, all based on at86rf23x radios. + + ### Synchronization + + To join a network a node must first receive EB (enhanced beacons). Once an EB + is received the node will be synchronized with the network. Synchronization + times are not deterministic, they depend on the following: + + `SLOTFRAME_LENGTH*SLOTDURATION*P_CHANNEL*P_EB` + + `SLOTFRAME_LENGTH` in OpenWSN is 101, and this port uses 20ms as the slotOffset + duration. `P_EB` specifies the a probability for a node to transmit an EB. + By default it's 10%, that means that on average it will take 10 tries before an + EB is transmitted. `P_CHANNEL` is the probability for the transmitter's and + receiver channel to match. If channel hopping is disabled this means that the + average worst case scenario is `101*20ms*10 ~= 20s`, so 20s for synchronization + to take place. `EB_PORTION` can be changed to increase the likelihood of EB to be + sent. This can also be achieved by reducing `SLOTFRAME_LENGTH`, but the later can + have an impact on the MSF (Minimal Scheduling Function). If too few cells are + available this could increase the likelihood of collisions. + + On the other hand if channel hopping is enabled then the joining node picks a + random channel to start listening on. The transmitter also picks a random + channel to start transmitting on and then follows a channel hopping template. + This would take on average ~8 tries for it to hit the correct channel for the + first time, and then it would hit it every 16 hops, on average this could lead + synchronization times of around `320s`. + + If nodes are having trouble in staying synchronized increasing `P_EB` by + reducing the value of `EB_PORTION` can also be done. Note that `EB_PORTION` + and `SLOTFRAME_LENGTH` are not configurable by default so need to be overridden + with `CFLAGS`. + + ### Timing + + Timing is essential for OpenWSN to work properly. For optimal results most + parameters in `board_info.h` should be measured for the specific hardware used. + OpenWSN has done that for most of their boards. These values can not be taken + directly from OpenWSN since they do not necessarily use the same TIMER's or + clock speeds. + + For more details on those parameters refer to: + https://openwsn.atlassian.net/wiki/spaces/OW/pages/688251/State+Machine + + Since all these parameters are HW dependent, it also means that hybrid + networks (different type of underlying hardware) might desynchronize often, + or not manage to keep in sync at all. + + Print messages during TSCH operation should be avoided since these can disrupt + TSCH timings. + + ### ledpins & debugpins + + The OpenWSN software provides different hooks all over the stack to toggle + different LEDs as well as debug pins to examine state and scheduling of a node. + Default configuration files are provided for both. The LED configuration maps to + RIOTs `LEDX_PIN` definitions, if available. On Nucleo boards LED0 line is + shared SPI, so is not used. + + The default configuration can be overwritten by setting `OPENWSN_LEDS_DEFAULT` + in the form of `leds_config_t`. The debugpins work similarly by setting + `OPENWSN_DEBUGPINS_BOARD` in the form of `debugpins_config_t`. + + The default configuration maps to OpenWSN reference hardware `openmote-b`. + + ## Testing and debugging + + List of some items which are helpful to explore the functionality of OpenWSN: + + - LED pins and debug pins as mentioned above in combination with a logic analyzer. + The expected behavior is described in: + [OpenWSN wiki](https://openwsn.atlassian.net/wiki/spaces/OW/pages/688257/Schedules). + + - The provided test application provides a UDP client and server. If the UDP + server is able to receive packets, the mechanism is considered to work correctly. + You should also be able to ping the device from your host. See + `tests/pkg_openwsn/README.md` for more details. + + - To speed up synchronization and make sniffing easier you can disable channel + hopping by setting (`CFLAGS=-DIEEE802154E_SINGLE_CHANNEL=26`). + + - To sniff the packets either use a 802.15.4 capable board and follow at: + https://github.com/RIOT-OS/applications/blob/master/sniffer/tools/README.md. + Alternatively use a Raspberry Pi with an external radio such as Openlabs and + incorporate Linux WPAN tools. In addition to that, there's also other + hardware such as the ATUSB IEEE 802.15.4 USB Adapter which can directly be + used on your Linux computer with WPAN tools installed. If you conduct your + experiments on the IoT-LAB testbed you might want to use a: + [sniffer profile](https://www.iot-lab.info/tutorials/radio-sniffer). + + - To explore the channel hopping mechanism there are rather expensive + multi-channel sniffers such as the BeamLogic 802.15.4 Site Analyzer that can + sniff all channels simultaneously. Alternatively you can set up multiple + separate sniffer devices locally or make use of the `sniffer_aggregator` on + the IoT-LAB testbed. + + - To test Openserial on a given platform the target `make openv-serial` can + be used on a BOARD flashed with `tests/pkg_openwsn` (`USEMODULE=openwsn_serial`) + must be included as well. The following output should appear: + + ``` + Test Setup: + ------------------ + Iterations: 100 + Packet length: 100 + Echo timeout: 2 + + Test Progress: + + [####################################] 100% + + Test Statistics: + ------------------ + Pkts send: 100 + Echo success: 100 + Echo timeout: 0 + Echo corrupted: 0 + ``` + + The test should be considered passing if success rate is > 98%. + + ## Known Issues + + The following errors might be visible when using `openwsn_serial`: + + - `[OPENSERIAL] wrong CRC in input Buffer` + + Since a timer is set to simulate a uart transmit interrupt, it can happen that + the interrupt is missed if another interrupt occurs during that time, this + seems to lead to the input buffer missing a byte and so CRC fails. More details + where given in the `openserial` section. + + - `[IEEE802154E] wdDataDuration overflows while at state 19 in slotOffset 0` + + This error can show up when the radio starts receiving (receives the SFD) and + therefore triggers a `NETDEV_RX_STARTED` but then no `NETDEV_TX_STARTED` + event follows. This happens when packets with invalid CRC are received. + netdev currently silently drops these packets without notifying upper layers. + But this does not affect the stack operation, so they can be ignored. + + - `[IEEE802154E] large timeCorr.: -18 ticks (code loc. 0)` + + Most crystals used to clock the RTT will drift even those with a very similarly + drift (10-30ppm). It's is normal then for motes adjust their timerCorr as long + as it stays within the above mentioned margins and if motes are able to stay + synchronized over the long run. If there aren't then maybe board_info.h + parameters require tuning for the specific platform. + +- `[JRC:ERROR] Type-error in conversion of 5N=ex` + +This errors happen when a node tries to rejoin the network. This error is only +associated to a log print, so can be ignored. + +- `[coap:WARNING] coapRcBadRequest(reason=OSCOAP unprotect failed: oscoapError(reason=Replay protection failed))` + +The join procedure uses a replay window. If a node had already joined the network +and for some reason attempts to rejoin again, then the replay windows will need +to expire for it's join request to be accepted. + +The following errors are platform specific. + + - samr21-xpro issues: + - The serial debugger hinders Openserial operation, an ftdi device must + be used. + + - sam0 issues: + - sam0 requires 180us busy loops every time an alarm is set or the + counter is read. Because of the later only `sctimer_rtt` can be used + and the max. tested baudrate for openserial is of 19200 bauds. + + - iotlab-m3 issues: + - openserial does not work reliably over 57600 bauds or when using + sctimer_ztimer. + +Other errors: + +- missed characters over stdio + +TSCH state machine disable occurs in IRQ context and disables IRQ during time +critical sections. This can cause bytes sent over stdio to be missed. + + ## Todos + + - `sctimer` to trigger an ISR immediately using software interrupts. + - `RTT_FREQUENCY` is not configurable for most platforms, implementations + should be adapted to make this configurable to be able to set `RTT_FREQUENCY` + to 32768Hz or the closer possible value. + - The UART wrapper uses ztimer to fake an interrupt after one byte + has been sent. This should also be done with software interrupts. + + ## Future Steps + + The OpenWSN community is working on refactoring their code base. As + one of the outputs of this modules like `cjoin`, `udp`, `coap` will become + optional. Once this is upstream the support for this pkg should be adapted. + + With above mentioned re-works the extraction of the MAC layer might be favored. + + As more immediate future steps: + + - Follow up PR to add OpenWSN sock + - Complete support of OpenWSN default HW (`openmote-b`) + - Add support for other 802.15.4 network drivers + + */ diff --git a/pkg/openwsn/include/board_info.h b/pkg/openwsn/include/board_info.h new file mode 100644 index 0000000000..03a43f0db8 --- /dev/null +++ b/pkg/openwsn/include/board_info.h @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2017 Hamburg University of Applied Sciences + * 2020 Inria + * + * 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. + */ + +/** + * @ingroup pkg_openwsn + * @{ + * + * @file + * + * @author Thomas Watteyne , February 2012 + * @author Tengfei Chang , July 2012 + * @author Peter Kietzmann , July 2017 + * @author Francisco Molina + * + * @} + */ + +#ifndef BOARD_INFO_H +#define BOARD_INFO_H + +#include +#include + +#include "board.h" +#include "periph_conf.h" +#include "timex.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name OpenWSN interrupt handling wrappers + * @{ + */ +#define INTERRUPT_DECLARATION() unsigned irq_state; +#define DISABLE_INTERRUPTS() irq_state = irq_disable(); +#define ENABLE_INTERRUPTS() irq_restore(irq_state); +#define SCHEDULER_WAKEUP() /* unused by RIOT */ +#define SCHEDULER_ENABLE_INTERRUPT() /* unused by RIOT */ +/** @} */ + + +/** + * @name OpenWSN platform dependent definitions + * @{ + */ +/* Always 32bit when using ztimer */ +#if RTT_MAX_VALUE == UINT32_MAX || !((RTT_MAX_VALUE + 1) & (RTT_MAX_VALUE)) || \ + IS_USED(MODULE_OPENWSN_SCTIMER_ZTIMER) +#define PORT_TIMER_WIDTH uint32_t +#define PORT_RADIOTIMER_WIDTH uint32_t +#else +#error "RTT_MAX_VALUE not supported" +#endif + +#if __SIZEOF_POINTER__ == 2 +#define PORT_SIGNED_INT_WIDTH int16_t +#else +#define PORT_SIGNED_INT_WIDTH int32_t +#endif + +#define SCTIMER_FREQUENCY (32768U) + +/* 32 ticks @32768Hz */ +#define PORT_TICS_PER_MS (SCTIMER_FREQUENCY / MS_PER_SEC) +/* 30 us per tick @32768Hz */ +#define PORT_US_PER_TICK (US_PER_SEC / SCTIMER_FREQUENCY) +/** @} */ + +/** + * @name OpenWSN IEEE802154E timings + * @{ + * + * @note These parameters are BOARD and CPU specific. + Values can't be taken directly from OpenWSN since they do not necessarily use + the same BSP configuration (timers, clock speed, etc.) + For precise synchronization these values should be measured and tuned for + every BOARD. + To understand the relationship between these values and OpenWSN state machine + as well as how they can be measured refer to: + - https://openwsn.atlassian.net/wiki/spaces/OW/pages/688251/State+Machine + - https://openwsn.atlassian.net/wiki/spaces/OW/pages/688255/Timing+Constants + */ +/* standard slot duration is 10ms but code execution time for most OpenWSN + supported BOARDS takes longer than 10ms, so use the default 20ms upstream + slot */ +#ifndef SLOTDURATION +#define SLOTDURATION 20 /* in milliseconds */ +#endif + +#if SLOTDURATION == 20 +#ifndef PORT_TsSlotDuration /* 655 ticks at @32768Hz */ +#define PORT_TsSlotDuration ((SCTIMER_FREQUENCY * SLOTDURATION) / MS_PER_SEC) +#endif + +/* Execution speed related parameters */ +#ifndef PORT_maxTxDataPrepare +#define PORT_maxTxDataPrepare (3355 / PORT_US_PER_TICK ) /* ~110 ticks at @32768Hz */ +#endif +#ifndef PORT_maxRxAckPrepare +#define PORT_maxRxAckPrepare (610 / PORT_US_PER_TICK ) /* ~20 ticks at @32768Hz */ +#endif +#ifndef PORT_maxRxDataPrepare +#define PORT_maxRxDataPrepare (1000 / PORT_US_PER_TICK ) /* ~33 ticks at@32768Hz */ +#endif +#ifndef PORT_maxTxAckPrepare +#define PORT_maxTxAckPrepare (1525 / PORT_US_PER_TICK ) /* ~50 ticks at@32768Hz */ +#endif + +/* Radio speed related parameters */ +#ifndef PORT_delayTx +#define PORT_delayTx (300 / PORT_US_PER_TICK ) /* ~10 ticks at@32768Hz */ +#endif +#ifndef PORT_delayRx +#define PORT_delayRx (0 / PORT_US_PER_TICK ) /* ~0 ticks at@32768Hz */ +#endif +#else +#error "Only 20ms slot duration is currently supported" +#endif +/** @} */ /* SLOTDURATION == 20 */ + +/** + * @name Adaptive sync accuracy + * + * Used for synchronization in heterogeneous networks (different BOARDs) + * Not supported yet, dummy value needs to be provided. + * @{ + */ +#define SYNC_ACCURACY (1) /* ticks */ +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* BOARD_INFO_H */ diff --git a/pkg/openwsn/include/openwsn.h b/pkg/openwsn/include/openwsn.h new file mode 100644 index 0000000000..dbe18eda63 --- /dev/null +++ b/pkg/openwsn/include/openwsn.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2018 Hamburg University of Applied Sciences + * 2020 Inria + * + * 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. + */ + +/** + * @ingroup pkg_openwsn + * + * @{ + * + * @file + * + * @author Peter Kietzmann + * @author Francisco Molina + */ +#ifndef OPENWSN_H +#define OPENWSN_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "thread.h" + +/** + * @brief Default PANID for OpenWSN network + */ +#ifndef OPENWSN_PANID +#define OPENWSN_PANID (0xCAFE) +#endif + +/** + * @brief Initializes OpenWSN thread + * + * @return PID of OpenWSN thread + * @return -1 on initialization error + */ +int openwsn_bootstrap(void); + +/** + * @brief get PID of OpenWsn thread. + * + * @return PID of OpenWsn thread + */ +kernel_pid_t openwsn_get_pid(void); + +#ifdef __cplusplus +} +#endif + +#endif /* OPENWSN_H */ +/** @} */ diff --git a/pkg/openwsn/include/openwsn_board.h b/pkg/openwsn/include/openwsn_board.h new file mode 100644 index 0000000000..5814662dc7 --- /dev/null +++ b/pkg/openwsn/include/openwsn_board.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2017 Hamburg University of Applied Sciences + * 2020 Inria + * + * 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. + */ + +/** + * @ingroup pkg_openwsn + * @{ + * + * RIOT HAL is provided as a new "board", a "RIOT board" to OpenWSN hardware + * abstraction interfaces. + * + * @file + * @brief RIOT adaption-specific definition of the "uart" bsp module. + * + * @author Thomas Watteyne , February 2012 + * @author Peter Kietzmann , July 2017 + * @author Francisco Molina + * + * @} + */ + +#ifndef OPENWSN_BOARD_H +#define OPENWSN_BOARD_H + +#include "board_info.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief OpenWSN `board.h` enum definitions + */ +typedef enum { + DO_NOT_KICK_SCHEDULER, + KICK_SCHEDULER, +} kick_scheduler_t; + +/** + * @brief Initialize OpenWSN bsp board adaptation + * + * Most initialization functions are not needed since there are initialized by + * RIOT's `auto_init` module. Only OpenWSN specific interfaces will be initialized + * here: `sctimer`, `openwsn_leds`, `openwsn_debugpins` & `uart_ow`. + * + */ +void board_init_openwsn(void); + +/** + * @brief Resets the board + * + */ +void board_reset(void); + +/** + * @brief Function definitions that we do not use in RIOT but that need to be + * defined for OpenWSN. Sleep is handled by `pm_layered` if enabled for + * the platform. + */ +void board_sleep(void); + +#ifdef __cplusplus +} +#endif + +#endif /* OPENWSN_BOARD_H */ diff --git a/pkg/openwsn/include/openwsn_debugpins.h b/pkg/openwsn/include/openwsn_debugpins.h new file mode 100644 index 0000000000..32832a7d17 --- /dev/null +++ b/pkg/openwsn/include/openwsn_debugpins.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2017 Hamburg University of Applied Sciences + * + * 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. + */ + +/** + * @ingroup pkg_openwsn + * @{ + * + * @file + * @brief Provides an adaption of OpenWSN debug pin handling + * to RIOTs handling of GPIOs. + * + * @author Michael Frey + * @author Peter Kietzmann + * + * @} + */ + +#ifndef OPENWSN_DEBUGPINS_H +#define OPENWSN_DEBUGPINS_H + +#include "periph/gpio.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief struct holding configuration of OpenWSN debug pins + */ +typedef struct debugpins_config { + gpio_t frame; /**< debug pin for frames */ + gpio_t slot; /**< debug pin for slots */ + gpio_t fsm; /**< debug pin for fsm */ + gpio_t task; /**< debug pin for tasks */ + gpio_t isr; /**< debug pin for interrupt service routines */ + gpio_t radio; /**< debug pin for the radio */ +} debugpins_config_t; + +/** + * Sets the debug pins for a specific board for OpenWSN + * + * @param[in] user_config A configuration of GPIO pins used for debugging. + * Unused pins need to be defined as GPIO_UNDEF. + */ +void openwsn_debugpins_init(const debugpins_config_t *user_config); + +#ifdef __cplusplus +} +#endif + +#endif /* OPENWSN_DEBUGPINS_H */ diff --git a/pkg/openwsn/include/openwsn_debugpins_params.h b/pkg/openwsn/include/openwsn_debugpins_params.h new file mode 100644 index 0000000000..5ecc54f5f8 --- /dev/null +++ b/pkg/openwsn/include/openwsn_debugpins_params.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2017 Hamburg University of Applied Sciences + * + * 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. + */ + +/** + * @ingroup pkg_openwsn + * @{ + * + * @file + * @brief Default configuration for the OpenWSN debugpins + * + * @author Michael Frey + * @author Peter Kietzmann + * + * @} + */ + +#ifndef OPENWSN_DEBUGPINS_PARAMS_H +#define OPENWSN_DEBUGPINS_PARAMS_H + +#include "openwsn_debugpins.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name OpenWSN default debugpins configuration. + * + * Undefined by default. + * @{ + */ +#ifndef OPENWSN_DEBUGPIN_FRAME +#define OPENWSN_DEBUGPIN_FRAME GPIO_UNDEF +#endif +#ifndef OPENWSN_DEBUGPIN_SLOT +#define OPENWSN_DEBUGPIN_SLOT GPIO_UNDEF +#endif +#ifndef OPENWSN_DEBUGPIN_FSM +#define OPENWSN_DEBUGPIN_FSM GPIO_UNDEF +#endif +#ifndef OPENWSN_DEBUGPIN_TASK +#define OPENWSN_DEBUGPIN_TASK GPIO_UNDEF +#endif +#ifndef OPENWSN_DEBUGPIN_ISR +#define OPENWSN_DEBUGPIN_ISR GPIO_UNDEF +#endif +#ifndef OPENWSN_DEBUGPIN_RADIO +#define OPENWSN_DEBUGPIN_RADIO GPIO_UNDEF +#endif + +#define OPENWSN_DEBUGPINS_DEFAULT { .frame = OPENWSN_DEBUGPIN_FRAME, \ + .slot = OPENWSN_DEBUGPIN_SLOT, \ + .fsm = OPENWSN_DEBUGPIN_FSM, \ + .task = OPENWSN_DEBUGPIN_TASK, \ + .isr = OPENWSN_DEBUGPIN_ISR, \ + .radio = OPENWSN_DEBUGPIN_RADIO} +/**@}*/ + +/** + * @brief OpenWSN debugpins configuration + */ +static const debugpins_config_t openwsn_debugpins_params[] = +{ +#ifdef OPENWSN_DEBUGPINS_BOARD + OPENWSN_DEBUGPINS_BOARD, +#else + OPENWSN_DEBUGPINS_DEFAULT, +#endif +}; + +#ifdef __cplusplus +} +#endif + +#endif /* OPENWSN_DEBUGPINS_PARAMS_H */ diff --git a/pkg/openwsn/include/openwsn_leds.h b/pkg/openwsn/include/openwsn_leds.h new file mode 100644 index 0000000000..17774ede27 --- /dev/null +++ b/pkg/openwsn/include/openwsn_leds.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2017 Hamburg University of Applied Sciences + * 2020 Inria + * + * 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. + */ + +/** + * @ingroup pkg_openwsn + * @{ + * + * @file + * @brief Provides an adaption of OpenWSN led handling + * to RIOTs handling of LEDs and/or GPIOs + * + * @author Peter Kietzmann + * @author Francisco Molina + * + * @} + */ +#ifndef OPENWSN_LEDS_H +#define OPENWSN_LEDS_H + +#include "periph/gpio.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief OpenWSN leds pin configuration + * @{ + */ +typedef struct leds_config { + gpio_t error; /**< error led */ + gpio_t sync; /**< synchronization state led */ + gpio_t radio; /**< radio activity led */ + gpio_t debug; /**< debug led */ + uint8_t led_on; /**< GPIO set to turn led on */ +} leds_config_t; +/** @} */ + +/** + * @brief Led on state values + */ +enum { + GPIO_LED_LOW = 0, + GPIO_LED_HIGH +}; + +/** + * Sets the led pins for a specific board for OpenWSN + * + * @param[in] user_config A configuration of GPIO pins used for debugging. + * + * @note Unused pins need to be defined as GPIO_UNDEF + */ +void ledpins_riot_init(const leds_config_t *user_config); + +#ifdef __cplusplus +} +#endif + +#endif /* OPENWSN_LEDS_H */ diff --git a/pkg/openwsn/include/openwsn_leds_params.h b/pkg/openwsn/include/openwsn_leds_params.h new file mode 100644 index 0000000000..918df88095 --- /dev/null +++ b/pkg/openwsn/include/openwsn_leds_params.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2017 Hamburg University of Applied Sciences + * + * 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. + */ + +/** + * @ingroup pkg_openwsn + * @{ + * + * @file + * @brief Default configuration for the OpenWSN leds + * + * @author Peter Kietzmann + * + * @} + */ +#ifndef OPENWSN_LEDS_PARAMS_H +#define OPENWSN_LEDS_PARAMS_H + +#include "board.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name OpenWSN default leds pins configuration. + * + * Default settings match OpenWSN openmote-b configuration. + * + * @note On Nucleo boards the LED pin is shared with SPI -> don't use it! + * @{ + */ +#if defined (LED0_PIN) && !defined(MODULE_BOARDS_COMMON_NUCLEO) +#define OPENWSN_LEDPIN_ERROR LED0_PIN +#else +#define OPENWSN_LEDPIN_ERROR GPIO_UNDEF +#endif + +#ifdef LED1_PIN +#define OPENWSN_LEDPIN_SYNC LED1_PIN +#else +#define OPENWSN_LEDPIN_SYNC GPIO_UNDEF +#endif + +#ifdef LED2_PIN +#define OPENWSN_LEDPIN_RADIO LED2_PIN +#else +#define OPENWSN_LEDPIN_RADIO GPIO_UNDEF +#endif + +#ifdef LED3_PIN +#define OPENWSN_LEDPIN_DEBUG LED3_PIN +#else +#define OPENWSN_LEDPIN_DEBUG GPIO_UNDEF +#endif + +#ifndef OPENWSN_LED_ON_STATE +#define OPENWSN_LED_ON_STATE GPIO_LED_LOW +#endif + +#define OPENWSN_LEDS_DEFAULT { .error = OPENWSN_LEDPIN_ERROR, \ + .sync = OPENWSN_LEDPIN_SYNC, \ + .radio = OPENWSN_LEDPIN_RADIO, \ + .debug = OPENWSN_LEDPIN_DEBUG, \ + .led_on = OPENWSN_LED_ON_STATE } +/**@}*/ + +/** + * @brief OpenWSN leds configuration + */ +static const leds_config_t openwsn_leds_params[] = +{ +#ifdef OPENWSN_LEDS_BOARD + OPENWSN_LEDS_BOARD, +#else + OPENWSN_LEDS_DEFAULT, +#endif +}; + +#ifdef __cplusplus +} +#endif + +#endif /* OPENWSN_LEDS_PARAMS_H */ diff --git a/pkg/openwsn/include/openwsn_radio.h b/pkg/openwsn/include/openwsn_radio.h new file mode 100644 index 0000000000..a4788b3971 --- /dev/null +++ b/pkg/openwsn/include/openwsn_radio.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2019 Hamburg University of Applied Sciences + * 2020 Inria + * + * 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. + */ + +/** + * @ingroup pkg_openwsn + * @{ + * + * @file + * @brief RIOT adaption of the "radio" bsp module definitions + * + * The radio adaptation runs in an own thread with the highest priority + * (`THREAD_PRIORITY_MAIN - 4`) and maps to RIOT's `netdev` API. + * + * Hardware MAC layer features such as CSMA/CA, ACK handling and retransmissions + * are handled by OpenWSN, so the radio driver must support disabling AUTOACK + * and CSMA handling by the hardware. Frame filtering must as well be disabled. + * + * The radio adaptation preloads the buffer so `NETOPT_PRELOADING` must be + * supported. + * + * OpenWSN needs to be notified when a frame reception/transmission stats and + * when it ends. Therefore radio drivers need to support the following netdev + * events: + * + * - `NETDEV_EVENT_RX_STARTED` + * - `NETDEV_EVENT_TX_STARTED` + * - `NETDEV_EVENT_RX_COMPLETE` + * - `NETDEV_EVENT_TX_COMPLETE` + * + * OpenWSN expects to recover crc information on every received frame even if it + * will simply drop frames with invalid crc. The stack can function correctly if + * radio drivers automatically drop frames with an invalid crc (i.e. the stack + * doesn't get notified about these frames), but it might print the following + * error if using `openwsn_serial`: + * + * - `[IEEE802154E] wdDataDuration overflows while at state 19 in slotOffset 0` + * + * @author Peter Kietzmann , April 2019 + * @author Francisco Molina + * + * @} + */ + +#ifndef OPENWSN_RADIO_H +#define OPENWSN_RADIO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "net/netdev.h" +#include "radio.h" + +/** + * @brief Initialize OpenWSN radio + * + * @param[in] netdev pointer to a netdev interface + * + * @return PID of OpenWSN thread + * @return -1 on initialization error + */ +int openwsn_radio_init(netdev_t *netdev); + +/** + * @brief OpenWSN radio variables structure + */ +typedef struct { + radio_capture_cbt startFrame_cb; /**< start of frame capture callback */ + radio_capture_cbt endFrame_cb; /**< end of frame capture callback */ + netdev_t *dev; /**< netdev device */ +} openwsn_radio_t; + +#ifdef __cplusplus +} +#endif + +#endif /* OPENWSN_RADIO_H */ +/** @} */ diff --git a/pkg/openwsn/include/openwsn_uart.h b/pkg/openwsn/include/openwsn_uart.h new file mode 100644 index 0000000000..4c4e1cfc4a --- /dev/null +++ b/pkg/openwsn/include/openwsn_uart.h @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2018 Hamburg University of Applied Sciences + * 2020 Inria + * + * 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. + */ + +/** + * @ingroup pkg_openwsn + * @{ + * + * For details on the implementation check pkg/openwsn/doc.txt + * + * @file + * @brief RIOT adaption-specific definition of the "uart" bsp module. + * + * @author Thomas Watteyne , February 2012 + * @author Peter Kietzmann , July 2018 + * @author Francisco Molina + * + * @} + */ + +#ifndef OPENWSN_UART_H +#define OPENWSN_UART_H + +#include "stdint.h" +#include "board.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief UART device to use for STDIO + * + * Dont want to include the stdio header, so redefine the default value + * + */ +#ifndef STDIO_UART_DEV +#define STDIO_UART_DEV (UART_DEV(0)) +#endif +/** + * @brief OpenWSN default uart dev. + * + * @note If only one UART is available that uart might collide with + * STDIO_UART_DEV, otherwise the next available UART will be used. + * + */ +#ifndef OPENWSN_UART_DEV +#ifdef MODULE_STDIO_NULL +#define OPENWSN_UART_DEV (STDIO_UART_DEV) +#else +#define OPENWSN_UART_DEV ((STDIO_UART_DEV + 1) % UART_NUMOF) +#endif +#endif + +/** + * @brief OpenWSN uart baudrate + */ +#ifndef OPENWSN_UART_BAUDRATE +#ifndef STDIO_UART_BAUDRATE +#define OPENWSN_UART_BAUDRATE (115200U) +#else +#define OPENWSN_UART_BAUDRATE (STDIO_UART_BAUDRATE) +#endif +#endif + +/** + * @brief Initialize OpenWSN uart + * + * This will initialize a uart device at STDIO_UART_BAUDRATE/8N1. It will also + * initialize a timer to set sw tx_isr. + * + */ +void uart_init_openwsn(void); + +/** + * @brief OpenWSN uart tx callback type + */ +typedef void (*uart_tx_cbt)(void); + +/** + * @brief OpenWSN uart rx callback type + */ +typedef void (*uart_rx_cbt)(void); + +/** + * @brief OpenWSN uart tx callback type +*/ +void uart_setCallbacks(uart_tx_cbt txCb, uart_rx_cbt rxCb); + +/** + * @brief Sets software flow control CTS + * + * This function sends XON or XOFF bytes to "set" or "unset" CTS by sw. + * + * @param[in] state true sets CTS, false clears CTS + */ +void uart_setCTS(bool state); + +/** + * @brief Write a single byte to the configured OpenWSN uart + */ +void uart_writeByte(uint8_t byteToWrite); + +/** + * @brief Reads a single byte received through uart. + * + * OpenWSN will call this thrpugh uart_rx_cbt. + * + */ +uint8_t uart_readByte(void); + +/** + * @brief Unused in RIOT, needs to be defined for OpenWSN + */ +void uart_enableInterrupts(void); + +/** + * @brief Unused in RIOT, needs to be defined for OpenWSN + */ +void uart_disableInterrupts(void); + +/** + * @brief Unused in RIOT, needs to be defined for OpenWSN + */ +void uart_clearRxInterrupts(void); + +/** + * @brief Unused in RIOT, needs to be defined for OpenWSN + */ +void uart_clearTxInterrupts(void); + +#ifdef __cplusplus +} +#endif + +#endif /* OPENWSN_UART_H */ diff --git a/pkg/openwsn/patches/0001-bsp-kernel-include-RIOT-OpenWSN-board-definitions.patch b/pkg/openwsn/patches/0001-bsp-kernel-include-RIOT-OpenWSN-board-definitions.patch new file mode 100644 index 0000000000..023c6522f6 --- /dev/null +++ b/pkg/openwsn/patches/0001-bsp-kernel-include-RIOT-OpenWSN-board-definitions.patch @@ -0,0 +1,53 @@ +From 6f845cd8b8ea316307fd9ef6ab58127a26772f72 Mon Sep 17 00:00:00 2001 +From: PeterKietzmann +Date: Thu, 8 Feb 2018 10:23:00 +0100 +Subject: [PATCH 01/11] bsp-kernel: include RIOT-OpenWSN board definitions + +--- + bsp/boards/radio.h | 2 +- + bsp/boards/sctimer.h | 2 +- + kernel/openos/scheduler.c | 2 +- + 3 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/bsp/boards/radio.h b/bsp/boards/radio.h +index df4333e8..8435a951 100644 +--- a/bsp/boards/radio.h ++++ b/bsp/boards/radio.h +@@ -12,7 +12,7 @@ + \author Thomas Watteyne , February 2012. + */ + +-#include "board.h" ++#include "openwsn_board.h" + + //=========================== define ========================================== + +diff --git a/bsp/boards/sctimer.h b/bsp/boards/sctimer.h +index 668496cb..90978f89 100644 +--- a/bsp/boards/sctimer.h ++++ b/bsp/boards/sctimer.h +@@ -13,7 +13,7 @@ + */ + + #include "stdint.h" +-#include "board.h" ++#include "openwsn_board.h" + + //=========================== typedef ========================================= + +diff --git a/kernel/openos/scheduler.c b/kernel/openos/scheduler.c +index 35068796..1dad545e 100644 +--- a/kernel/openos/scheduler.c ++++ b/kernel/openos/scheduler.c +@@ -6,7 +6,7 @@ + + #include "opendefs.h" + #include "scheduler.h" +-#include "board.h" ++#include "openwsn_board.h" + #include "debugpins.h" + #include "leds.h" + +-- +2.27.0 + diff --git a/pkg/openwsn/patches/0002-drivers-common-openserial-rename-include-for-RIOT-Op.patch b/pkg/openwsn/patches/0002-drivers-common-openserial-rename-include-for-RIOT-Op.patch new file mode 100644 index 0000000000..007c29dec5 --- /dev/null +++ b/pkg/openwsn/patches/0002-drivers-common-openserial-rename-include-for-RIOT-Op.patch @@ -0,0 +1,26 @@ +From 6fff6e0e31dbed9a603e4e1eab434c45e8b43861 Mon Sep 17 00:00:00 2001 +From: Francisco Molina +Date: Mon, 10 Feb 2020 15:05:07 +0100 +Subject: [PATCH 02/11] drivers/common/openserial: rename include for + RIOT-OpenWSN uart + +--- + drivers/common/openserial.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/common/openserial.c b/drivers/common/openserial.c +index d39634c1..5c3c0003 100644 +--- a/drivers/common/openserial.c ++++ b/drivers/common/openserial.c +@@ -20,7 +20,7 @@ + #include "openbridge.h" + #include "leds.h" + #include "schedule.h" +-#include "uart.h" ++#include "openwsn_uart.h" + #include "opentimers.h" + #include "openhdlc.h" + #include "schedule.h" +-- +2.27.0 + diff --git a/pkg/openwsn/patches/0003-openapps-comment-out-unused-COAP-UDP-applications-in.patch b/pkg/openwsn/patches/0003-openapps-comment-out-unused-COAP-UDP-applications-in.patch new file mode 100644 index 0000000000..74336c6285 --- /dev/null +++ b/pkg/openwsn/patches/0003-openapps-comment-out-unused-COAP-UDP-applications-in.patch @@ -0,0 +1,60 @@ +From 1b9c54459e882a2beb4cedbdbafbb299b95be9e8 Mon Sep 17 00:00:00 2001 +From: Francisco Molina +Date: Fri, 27 Mar 2020 09:59:24 +0100 +Subject: [PATCH 03/11] openapps: comment out unused COAP&UDP applications + includes + +--- + openapps/openapps.c | 26 +++++++++++++------------- + 1 file changed, 13 insertions(+), 13 deletions(-) + +diff --git a/openapps/openapps.c b/openapps/openapps.c +index 3124d0c6..e30dcaec 100644 +--- a/openapps/openapps.c ++++ b/openapps/openapps.c +@@ -8,18 +8,18 @@ + + // CoAP + #include "opencoap.h" +-#include "c6t.h" +-#include "cinfo.h" +-#include "cleds.h" ++// #include "c6t.h" ++// #include "cinfo.h" ++// #include "cleds.h" + #include "cjoin.h" +-#include "cwellknown.h" +-#include "rrt.h" ++// #include "cwellknown.h" ++// #include "rrt.h" + // UDP +-#include "uecho.h" +-#include "uinject.h" +-#include "userialbridge.h" +-#include "uexpiration.h" +-#include "uexpiration_monitor.h" ++// #include "uecho.h" ++// #include "uinject.h" ++// #include "userialbridge.h" ++// #include "uexpiration.h" ++// #include "uexpiration_monitor.h" + + //=========================== variables ======================================= + +@@ -35,10 +35,10 @@ void openapps_init(void) { + + // CoAP + //c6t_init(); +- cinfo_init(); +- cleds__init(); ++ // cinfo_init(); ++ // cleds__init(); + cjoin_init(); +- cwellknown_init(); ++ // cwellknown_init(); + //rrt_init(); + + // UDP +-- +2.27.0 + diff --git a/pkg/openwsn/patches/0004-openstack-02b-MAChigh-neighbors.c-expose-neighbors_v.patch b/pkg/openwsn/patches/0004-openstack-02b-MAChigh-neighbors.c-expose-neighbors_v.patch new file mode 100644 index 0000000000..34b3e2c18e --- /dev/null +++ b/pkg/openwsn/patches/0004-openstack-02b-MAChigh-neighbors.c-expose-neighbors_v.patch @@ -0,0 +1,26 @@ +From a4a7bdb3504fe3e0f332170433e1e31f417f64fd Mon Sep 17 00:00:00 2001 +From: Francisco Molina +Date: Fri, 27 Mar 2020 10:15:43 +0100 +Subject: [PATCH 04/11] openstack/02b-MAChigh/neighbors.c: expose + neighbors_vars + +--- + openstack/02b-MAChigh/neighbors.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/openstack/02b-MAChigh/neighbors.c b/openstack/02b-MAChigh/neighbors.c +index a7de3394..4cfcf146 100644 +--- a/openstack/02b-MAChigh/neighbors.c ++++ b/openstack/02b-MAChigh/neighbors.c +@@ -10,7 +10,7 @@ + + //=========================== variables ======================================= + +-static neighbors_vars_t neighbors_vars; ++neighbors_vars_t neighbors_vars; + + //=========================== prototypes ====================================== + +-- +2.27.0 + diff --git a/pkg/openwsn/patches/0005-kernel-openos-scheduler-use-thread-flags-restore-irq.patch b/pkg/openwsn/patches/0005-kernel-openos-scheduler-use-thread-flags-restore-irq.patch new file mode 100644 index 0000000000..3a1d337536 --- /dev/null +++ b/pkg/openwsn/patches/0005-kernel-openos-scheduler-use-thread-flags-restore-irq.patch @@ -0,0 +1,77 @@ +From 626dbbed27b4a66bcf02fe061d5af1bff2d1accd Mon Sep 17 00:00:00 2001 +From: Francisco Molina +Date: Sun, 29 Mar 2020 12:11:53 +0200 +Subject: [PATCH 05/11] kernel/openos/scheduler: use thread flags, restore + irq_state + +Use thread_flags_wait_any to pause the scheduler. Set flag in +scheduler_push_task to trigger new task handling. + +squash! kernel/openos/scheduler: use thread flags +--- + kernel/openos/scheduler.c | 13 ++++++++++++- + kernel/scheduler.h | 2 +- + 2 files changed, 13 insertions(+), 2 deletions(-) + +diff --git a/kernel/openos/scheduler.c b/kernel/openos/scheduler.c +index 1dad545e..28bfe5c2 100644 +--- a/kernel/openos/scheduler.c ++++ b/kernel/openos/scheduler.c +@@ -10,6 +10,11 @@ + #include "debugpins.h" + #include "leds.h" + ++#include "openwsn.h" ++#include "thread.h" ++ ++#define OPENWSN_SCHEDULER_FLAG (1u << 8) ++ + //=========================== variables ======================================= + + scheduler_vars_t scheduler_vars; +@@ -31,8 +36,11 @@ void scheduler_init(void) { + SCHEDULER_ENABLE_INTERRUPT(); + } + +-void scheduler_start(void) { ++void scheduler_start(unsigned state) { + taskList_item_t* pThisTask; ++ ++ irq_restore(state); ++ + while (1) { + while(scheduler_vars.task_list!=NULL) { + // there is still at least one task in the linked-list of tasks +@@ -59,6 +67,7 @@ void scheduler_start(void) { + } + debugpins_task_clr(); + board_sleep(); ++ thread_flags_wait_any(OPENWSN_SCHEDULER_FLAG); + debugpins_task_set(); // IAR should halt here if nothing to do + } + } +@@ -105,6 +114,8 @@ void scheduler_push_task(task_cbt cb, task_prio_t prio) { + } + + ENABLE_INTERRUPTS(); ++ thread_t *thread = (thread_t*) thread_get(openwsn_get_pid()); ++ thread_flags_set(thread, OPENWSN_SCHEDULER_FLAG); + } + + //=========================== private ========================================= +diff --git a/kernel/scheduler.h b/kernel/scheduler.h +index bc49817e..f3f64570 100644 +--- a/kernel/scheduler.h ++++ b/kernel/scheduler.h +@@ -64,7 +64,7 @@ typedef struct { + //=========================== prototypes ====================================== + + void scheduler_init(void); +-void scheduler_start(void); ++void scheduler_start(unsigned state); + void scheduler_push_task(task_cbt task_cb, task_prio_t prio); + + /** +-- +2.27.0 + diff --git a/pkg/openwsn/patches/0006-bsp-boards-toolchain_defs.h-comment-out-conflict-ISR.patch b/pkg/openwsn/patches/0006-bsp-boards-toolchain_defs.h-comment-out-conflict-ISR.patch new file mode 100644 index 0000000000..842fb9a55e --- /dev/null +++ b/pkg/openwsn/patches/0006-bsp-boards-toolchain_defs.h-comment-out-conflict-ISR.patch @@ -0,0 +1,43 @@ +From 251802a8050d6b619d2e70c33c6ada5b6e57d549 Mon Sep 17 00:00:00 2001 +From: Francisco Molina +Date: Thu, 2 Apr 2020 16:04:29 +0200 +Subject: [PATCH 06/11] bsp/boards/toolchain_defs.h: comment out conflict ISR + definitions + +The ISR definition conflicts with AVR ISR definitions. +--- + bsp/boards/toolchain_defs.h | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/bsp/boards/toolchain_defs.h b/bsp/boards/toolchain_defs.h +index afcbcbf6..e288e52e 100644 +--- a/bsp/boards/toolchain_defs.h ++++ b/bsp/boards/toolchain_defs.h +@@ -16,15 +16,15 @@ + + //===== ISR and pragma + +-#if defined(__GNUC__) && (__GNUC__==4) && (__GNUC_MINOR__<=5) && defined(__MSP430__) +- // mspgcc <4.5.x +- #include +- #define ISR(v) interrupt (v ## _VECTOR) v ## _ISR(void) +-#else +- // other +- #define __PRAGMA__(x) _Pragma(#x) +- #define ISR(v) __PRAGMA__(vector=v ##_VECTOR) __interrupt void v ##_ISR(void) +-#endif ++// #if defined(__GNUC__) && (__GNUC__==4) && (__GNUC_MINOR__<=5) && defined(__MSP430__) ++// // mspgcc <4.5.x ++// #include ++// #define ISR(v) interrupt (v ## _VECTOR) v ## _ISR(void) ++// #else ++// // other ++// #define __PRAGMA__(x) _Pragma(#x) ++// #define ISR(v) __PRAGMA__(vector=v ##_VECTOR) __interrupt void v ##_ISR(void) ++// #endif + + //===== inline + +-- +2.27.0 + diff --git a/pkg/openwsn/patches/0007-openstack-openstack-dont-init-idmanager.patch b/pkg/openwsn/patches/0007-openstack-openstack-dont-init-idmanager.patch new file mode 100644 index 0000000000..cde7805227 --- /dev/null +++ b/pkg/openwsn/patches/0007-openstack-openstack-dont-init-idmanager.patch @@ -0,0 +1,27 @@ +From 6cf200f4f5fd73c065ac801328497bcfd073b382 Mon Sep 17 00:00:00 2001 +From: Francisco Molina +Date: Fri, 15 May 2020 13:45:02 +0200 +Subject: [PATCH 07/11] openstack/openstack: dont init idmanager + +Dont initiate idmanager in OpenWSN but in RIOT to allow overriding +default short address. +--- + openstack/openstack.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/openstack/openstack.c b/openstack/openstack.c +index 3b10eddb..886e853f 100644 +--- a/openstack/openstack.c ++++ b/openstack/openstack.c +@@ -57,7 +57,7 @@ void openstack_init(void) { + + //===== stack + //-- cross-layer +- idmanager_init(); // call first since initializes EUI64 and isDAGroot ++ // idmanager_init(); // call first since initializes EUI64 and isDAGroot + openqueue_init(); + openrandom_init(); + +-- +2.27.0 + diff --git a/pkg/openwsn/patches/0008-openstack-openapps-add-debugging.patch b/pkg/openwsn/patches/0008-openstack-openapps-add-debugging.patch new file mode 100644 index 0000000000..6a56d7a1da --- /dev/null +++ b/pkg/openwsn/patches/0008-openstack-openapps-add-debugging.patch @@ -0,0 +1,175 @@ +From ae6271246adb6fb97a8d23f4b09f78223dbb04f6 Mon Sep 17 00:00:00 2001 +From: Francisco Molina +Date: Fri, 27 Mar 2020 10:18:16 +0100 +Subject: [PATCH 08/11] openstack/openapps: add debugging + +Debugging info that can be also be obtained through ifconfig in +tests/openwsn. +--- + kernel/openos/scheduler.c | 3 ++- + openapps/cjoin/cjoin.c | 10 +++++++++- + openstack/02a-MAClow/IEEE802154E.c | 4 ++++ + openstack/02b-MAChigh/neighbors.c | 4 ++++ + openstack/03b-IPv6/icmpv6rpl.c | 4 ++++ + 5 files changed, 23 insertions(+), 2 deletions(-) + +diff --git a/kernel/openos/scheduler.c b/kernel/openos/scheduler.c +index 28bfe5c2..175d6309 100644 +--- a/kernel/openos/scheduler.c ++++ b/kernel/openos/scheduler.c +@@ -12,6 +12,7 @@ + + #include "openwsn.h" + #include "thread.h" ++#include "log.h" + + #define OPENWSN_SCHEDULER_FLAG (1u << 8) + +@@ -87,7 +88,7 @@ void scheduler_push_task(task_cbt cb, task_prio_t prio) { + } + if (taskContainer>&scheduler_vars.taskBuf[TASK_LIST_DEPTH-1]) { + // task list has overflown. This should never happpen! +- ++ LOG_ERROR("[openos/scheduler]: critical, task list overflow\n"); + // we can not print from within the kernel. Instead: + // blink the error LED + leds_error_blink(); +diff --git a/openapps/cjoin/cjoin.c b/openapps/cjoin/cjoin.c +index 2d87372f..74eca7b3 100644 +--- a/openapps/cjoin/cjoin.c ++++ b/openapps/cjoin/cjoin.c +@@ -18,6 +18,8 @@ + #include "eui64.h" + #include "neighbors.h" + ++#include "log.h" ++ + //=========================== defines ========================================= + + /// inter-packet period (in ms) +@@ -134,14 +136,18 @@ owerror_t cjoin_receive(OpenQueueEntry_t* msg, + owerror_t ret; + + if (coap_header->Code != COAP_CODE_RESP_CHANGED) { ++ LOG_DEBUG("[cjoin]:fail, replay protection\n"); + return E_FAIL; + } + + ret = cojp_cbor_decode_configuration_object(msg->payload, msg->length, &configuration); +- if (ret == E_FAIL) { return E_FAIL; } ++ if (ret == E_FAIL) { ++ LOG_DEBUG("[cjoin]: decode fail\n"); ++ return E_FAIL; } + + if (configuration.keyset.num_keys == 1 && + configuration.keyset.key[0].key_usage == COJP_KEY_USAGE_6TiSCH_K1K2_ENC_MIC32) { ++ LOG_DEBUG("[cjoin]: success\n"); + // set the L2 keys as per the parsed value + IEEE802154_security_setBeaconKey(configuration.keyset.key[0].key_index, configuration.keyset.key[0].key_value); + IEEE802154_security_setDataKey(configuration.keyset.key[0].key_index, configuration.keyset.key[0].key_value); +@@ -152,6 +158,7 @@ owerror_t cjoin_receive(OpenQueueEntry_t* msg, + // TODO not supported for now + } + ++ LOG_DEBUG("[cjoin]: failed\n"); + return E_FAIL; + } + +@@ -300,6 +307,7 @@ owerror_t cjoin_sendJoinRequest(open_addr_t* joinProxy) { + packetfunctions_reserveHeaderSize(pkt, payload_len); + memcpy(pkt->payload, tmp, payload_len); + // send ++ LOG_DEBUG("[cjoin]: send join request\n"); + outcome = opencoap_send( + pkt, + COAP_TYPE_NON, +diff --git a/openstack/02a-MAClow/IEEE802154E.c b/openstack/02a-MAClow/IEEE802154E.c +index 07921ae3..c1b532af 100644 +--- a/openstack/02a-MAClow/IEEE802154E.c ++++ b/openstack/02a-MAClow/IEEE802154E.c +@@ -18,6 +18,8 @@ + #include "openrandom.h" + #include "msf.h" + ++#include "log.h" ++ + //=========================== definition ====================================== + + //=========================== variables ======================================= +@@ -806,6 +808,7 @@ port_INLINE void activity_synchronize_endOfFrame(PORT_TIMER_WIDTH capturedTime) + synchronizePacket(ieee154e_vars.syncCapturedTime); + + // declare synchronized ++ LOG_DEBUG("[IEE20154E]: synchronized\n"); + changeIsSync(TRUE); + // log the info + openserial_printInfo(COMPONENT_IEEE802154E,ERR_SYNCHRONIZED, +@@ -890,6 +893,7 @@ port_INLINE void activity_ti1ORri1(void) { + ieee154e_vars.numOfSleepSlots = 1; + + // declare myself desynchronized ++ LOG_DEBUG("[IEE20154E]: desynchronized\n"); + changeIsSync(FALSE); + + // log the error +diff --git a/openstack/02b-MAChigh/neighbors.c b/openstack/02b-MAChigh/neighbors.c +index 4cfcf146..b5f064e9 100644 +--- a/openstack/02b-MAChigh/neighbors.c ++++ b/openstack/02b-MAChigh/neighbors.c +@@ -8,6 +8,8 @@ + #include "openrandom.h" + #include "msf.h" + ++#include "log.h" ++ + //=========================== variables ======================================= + + neighbors_vars_t neighbors_vars; +@@ -687,6 +689,7 @@ void registerNewNeighbor(open_addr_t* address, + i=0; + while(i +Date: Thu, 4 Jun 2020 15:39:07 +0200 +Subject: [PATCH 09/11] drivers/common/openserial: add flag to echo badcrc + frames + +--- + drivers/common/openserial.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/common/openserial.c b/drivers/common/openserial.c +index 5c3c0003..c6cdddf0 100644 +--- a/drivers/common/openserial.c ++++ b/drivers/common/openserial.c +@@ -981,9 +981,13 @@ port_INLINE void inputHdlcClose(void) { + openserial_vars.inputBufFillLevel -= 2; + } else { + // the CRC is incorrect +- ++#ifdef OPENSERIAL_ECHO_BADCRC ++ // Force echo on invalid crc ++ openserial_vars.inputBuf[0] = SERFRAME_PC2MOTE_TRIGGERSERIALECHO; ++#else + // drop the incoming frame + openserial_vars.inputBufFillLevel = 0; ++#endif + } + } + +-- +2.27.0 + diff --git a/pkg/openwsn/patches/0010-drivers-common-opentimers-enable-ISR-before-return.patch b/pkg/openwsn/patches/0010-drivers-common-opentimers-enable-ISR-before-return.patch new file mode 100644 index 0000000000..fc27caf560 --- /dev/null +++ b/pkg/openwsn/patches/0010-drivers-common-opentimers-enable-ISR-before-return.patch @@ -0,0 +1,32 @@ +From 02420eb4baf4229c66df5f99254f867d816b5e58 Mon Sep 17 00:00:00 2001 +From: Francisco Molina +Date: Thu, 25 Jun 2020 15:37:44 +0200 +Subject: [PATCH 10/11] drivers/common/opentimers: enable ISR before return + +--- + drivers/common/opentimers.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/common/opentimers.c b/drivers/common/opentimers.c +index 718b39a3..0c7c6683 100644 +--- a/drivers/common/opentimers.c ++++ b/drivers/common/opentimers.c +@@ -60,6 +60,7 @@ opentimers_id_t opentimers_create(uint8_t timer_id, uint8_t task_prio){ + opentimers_vars.timersBuf[timer_id].isUsed = TRUE; + // the TSCH timer and inhibit timer won't push a task, + // hence task_prio is not used ++ ENABLE_INTERRUPTS(); + return timer_id; + } + } +@@ -69,6 +70,7 @@ opentimers_id_t opentimers_create(uint8_t timer_id, uint8_t task_prio){ + if (opentimers_vars.timersBuf[id].isUsed == FALSE){ + opentimers_vars.timersBuf[id].isUsed = TRUE; + opentimers_vars.timersBuf[id].timer_task_prio = task_prio; ++ ENABLE_INTERRUPTS(); + return id; + } + } +-- +2.27.0 + diff --git a/pkg/openwsn/patches/0011-openstack-allow-to-set-EB_PORTION-SLOTFRAME_LENGTH.patch b/pkg/openwsn/patches/0011-openstack-allow-to-set-EB_PORTION-SLOTFRAME_LENGTH.patch new file mode 100644 index 0000000000..36e3fbda10 --- /dev/null +++ b/pkg/openwsn/patches/0011-openstack-allow-to-set-EB_PORTION-SLOTFRAME_LENGTH.patch @@ -0,0 +1,42 @@ +From d20020308e0728987dff1190273a7b7322926b64 Mon Sep 17 00:00:00 2001 +From: Francisco Molina +Date: Thu, 25 Jun 2020 17:50:24 +0200 +Subject: [PATCH 11/11] openstack: allow to set EB_PORTION, SLOTFRAME_LENGTH + +--- + openstack/02a-MAClow/IEEE802154E.h | 2 ++ + openstack/02b-MAChigh/schedule.h | 3 +++ + 2 files changed, 5 insertions(+) + +diff --git a/openstack/02a-MAClow/IEEE802154E.h b/openstack/02a-MAClow/IEEE802154E.h +index 117aa7f3..11d7ec10 100644 +--- a/openstack/02a-MAClow/IEEE802154E.h ++++ b/openstack/02a-MAClow/IEEE802154E.h +@@ -41,7 +41,9 @@ static const uint8_t ebIEsBytestream[] = { + #define TXRETRIES 15 // number of MAC retries before declaring failed + #define TX_POWER 31 // 1=-25dBm, 31=0dBm (max value) + #define RESYNCHRONIZATIONGUARD 5 // in 32kHz ticks. min distance to the end of the slot to successfully synchronize ++#ifndef EB_PORTION + #define EB_PORTION 10 // set EB on minimal cell for 1/EB_PORTION portion ++#endif + #define MAXKAPERIOD 1000 // in slots: 1500@20ms per slot -> ~30 seconds. Max value used by adaptive synchronization. + #define DESYNCTIMEOUT 1750 // in slots: 1750@20ms per slot -> ~35 seconds. A larger DESYNCTIMEOUT is needed if using a larger KATIMEOUT. + #define LIMITLARGETIMECORRECTION 5 // threshold number of ticks to declare a timeCorrection "large" +diff --git a/openstack/02b-MAChigh/schedule.h b/openstack/02b-MAChigh/schedule.h +index dc3b9f50..d64d6cf4 100644 +--- a/openstack/02b-MAChigh/schedule.h ++++ b/openstack/02b-MAChigh/schedule.h +@@ -17,7 +17,10 @@ + + The superframe reappears over time and can be arbitrarily long. + */ ++ ++#ifndef SLOTFRAME_LENGTH + #define SLOTFRAME_LENGTH 101 //should be 101 ++#endif + + //draft-ietf-6tisch-minimal-06 + #define SCHEDULE_MINIMAL_6TISCH_ACTIVE_CELLS 1 +-- +2.27.0 + diff --git a/sys/auto_init/auto_init.c b/sys/auto_init/auto_init.c index 628649afbd..a2bedb4165 100644 --- a/sys/auto_init/auto_init.c +++ b/sys/auto_init/auto_init.c @@ -108,6 +108,11 @@ void auto_init(void) extern void openthread_bootstrap(void); openthread_bootstrap(); } + if (IS_USED(MODULE_AUTO_INIT_OPENWSN)) { + LOG_DEBUG("Bootstrapping openwsn.\n"); + extern void openwsn_bootstrap(void); + openwsn_bootstrap(); + } if (IS_USED(MODULE_GCOAP) && !IS_ACTIVE(CONFIG_GCOAP_NO_AUTO_INIT)) { LOG_DEBUG("Auto init gcoap.\n");