Compare commits

...

No commits in common. "master" and "7bf9fbc7a367501c602c64c84b1f503f7b2b4996" have entirely different histories.

138 changed files with 2782 additions and 593 deletions

View File

@ -1,7 +1,7 @@
#!/bin/sh
# uncomment and change this to limit builds, e.g.,
#export BOARDS="samr21-xpro native"
export BOARDS="samr21-xpro native"
# and / or
#export APPS="examples/hello-world tests/unittests"
@ -105,28 +105,18 @@ tests/ieee802154_hal
# As a rule of thumb, only add boards here if there are not differences in
# modules or packages.
# Eventually this list will be removed...
#
# msbiot and pyboard are on the list as kconfig tunes the pll due to different
# HSE values from the standard, this is not the case in makefile.
: ${TEST_KCONFIG_BOARD_BLOCKLIST:="
6lowpan-clicker
esp32-wrover-kit
esp8266-esp-12x
esp8266-olimex-mod
esp8266-sparkfun-thing
limifrog-v1
lora-e5-dev
msbiot
msb-430h
nucleo-l011k4
nucleo-wl55jc
omote
openmote-b
pic32-wifire
esp32-wrover-kit
esp8266-olimex-mod
msbiot
pyboard
remote-pa
samd10-xmini
stk3200
stm32f030f4-demo
stm32f3discovery
stm32mp157c-dk2
"}
# This list will force all boards that are not in the TEST_KCONFIG_BOARD_BLOCKLIST
@ -184,6 +174,20 @@ get_supported_kconfig_board_app() {
if is_in_list "${board}" "${TEST_KCONFIG_BOARD_BLOCKLIST}"; then
return 1
fi
# On nightlies run all possible kconfig tests on all boards
# Normally we don't want to do this as it adds quite a bit to build time
# and the subset of boards we are testing for are pretty good at catching
# any bugs...
# This will be over one day, I promise.
if [ ${NIGHTLY} -eq 1 ]; then
if is_in_list "${appdir}" "${TEST_KCONFIG_ENFORCE_APP_GROUPS}"; then
return 0
fi
if [ -f "${appdir}/app.config.test" ]; then
return 0
fi
fi
if is_in_list "${appdir}" "${TEST_KCONFIG_TEST_ALLOWLIST}"; then
return 0
fi
@ -382,7 +386,7 @@ get_compile_jobs() {
get_apps | \
maybe_filter_changed_apps | \
dwqc ${DWQ_ENV} -s \
dwqc ${DWQ_ENV} --queue default-first -s \
${DWQ_JOBID:+--subjob} \
"$0 get_app_board_toolchain_pairs \${1} $0 compile"
}

View File

@ -34,9 +34,13 @@ rsource "sys/Kconfig"
rsource "pkg/Kconfig"
menu "External Modules"
osource "$(KCONFIG_EXTERNAL_CONFIGS)"
osource "$(KCONFIG_EXTERNAL_MODULE_CONFIGS)"
endmenu # External Modules
menu "External Packages"
osource "$(KCONFIG_EXTERNAL_PKG_CONFIGS)"
endmenu # External Packages
comment "RIOT is in a migration phase."
comment "Some configuration options may not be here. Use CFLAGS instead."

View File

@ -10,7 +10,7 @@
# include external modules dependencies
# processed before RIOT ones to be evaluated before the 'default' rules.
-include $(EXTERNAL_MODULE_PATHS:%=%/Makefile.dep)
-include $(EXTERNAL_MODULE_PATHS:%=%Makefile.dep)
# pull dependencies from sys and drivers
include $(RIOTBASE)/sys/Makefile.dep

View File

@ -49,6 +49,7 @@ EXTERNAL_BOARD_DIRS ?=
RIOTMAKE ?= $(RIOTBASE)/makefiles
RIOTKCONFIG ?= $(RIOTBASE)/kconfigs
RIOTPKG ?= $(RIOTBASE)/pkg
EXTERNAL_PKG_DIRS ?=
RIOTTOOLS ?= $(RIOTBASE)/dist/tools
RIOTPROJECT ?= $(shell git rev-parse --show-toplevel 2>/dev/null || pwd)
BUILD_DIR ?= $(RIOTBASE)/build
@ -98,6 +99,9 @@ ifeq ($(INSIDE_DOCKER),0)
ifeq ($(origin EXTERNAL_MODULE_DIRS),command line)
$(error EXTERNAL_MODULE_DIRS must be passed as environment variable, and not as command line argument)
endif
ifeq ($(origin EXTERNAL_PKG_DIRS),command line)
$(error EXTERNAL_PKG_DIRS must be passed as environment variable, and not as command line argument)
endif
endif
# Deprecation of configuring 'RIOTBOARD'
@ -142,6 +146,9 @@ EXTERNAL_BOARD_DIRS := $(foreach dir,\
EXTERNAL_MODULE_DIRS := $(foreach dir,\
$(EXTERNAL_MODULE_DIRS),\
$(abspath $(dir)))
EXTERNAL_PKG_DIRS := $(foreach dir,\
$(EXTERNAL_PKG_DIRS),\
$(abspath $(dir)))
# Ensure that all directories are set and don't contain spaces.
ifneq (, $(filter-out 1, $(foreach v,$(__DIRECTORY_VARIABLES),$(words $($(v))))))
@ -428,9 +435,12 @@ ifeq (1,$(TEST_KCONFIG))
KCONFIG_PACKAGES := $(call lowercase,$(patsubst CONFIG_PACKAGE_%,%,$(filter CONFIG_PACKAGE_%,$(.VARIABLES))))
USEPKG := $(KCONFIG_PACKAGES)
# Locate used packages in $(RIOTPKG).
PKG_PATHS := $(sort $(foreach dir,$(RIOTPKG),\
# Locate used packages in $(RIOTPKG) or $(EXTERNAL_PKG_DIRS).
PKGDIRS := $(RIOTPKG) $(EXTERNAL_PKG_DIRS)
PKG_PATHS := $(sort $(foreach dir,$(PKGDIRS),\
$(foreach pkg,$(USEPKG),$(dir $(wildcard $(dir)/$(pkg)/Makefile)))))
EXTERNAL_MODULE_PATHS := $(dir $(EXTERNAL_MODULE_KCONFIGS))
else
# always select provided architecture features
FEATURES_REQUIRED += $(filter arch_%,$(FEATURES_PROVIDED))
@ -578,7 +588,7 @@ include $(RIOTBASE)/sys/Makefile.include
-include $(PKG_PATHS:%=%Makefile.include)
# include external modules configuration
-include $(EXTERNAL_MODULE_PATHS:%=%/Makefile.include)
-include $(EXTERNAL_MODULE_PATHS:%=%Makefile.include)
# Deduplicate includes without sorting them
# see https://stackoverflow.com/questions/16144115/makefile-remove-duplicate-words-without-sorting

View File

@ -40,7 +40,6 @@ static const mtd_spi_nor_params_t _samd51_nor_params = {
.cs = SAM0_QSPI_PIN_CS,
.wp = SAM0_QSPI_PIN_DATA_2,
.hold = SAM0_QSPI_PIN_DATA_3,
.addr_width = 3,
};
static mtd_spi_nor_t samd51_nor_dev = {

View File

@ -40,7 +40,6 @@ static const mtd_spi_nor_params_t _weact_nor_params = {
.cs = WEACT_4X1CX_NOR_SPI_CS,
.wp = GPIO_UNDEF,
.hold = GPIO_UNDEF,
.addr_width = 3,
};
static mtd_spi_nor_t weact_nor_dev = {

View File

@ -19,5 +19,5 @@ FEATURES_PROVIDED += arduino
# This configuration enables modules that are only available when using Kconfig
# module modelling
ifeq (1, $(TEST_KCONFIG))
KCONFIG_ADD_CONFIG += $(BOARDDIR)/esp32-wrover-kit.config
KCONFIG_BOARD_CONFIG += $(BOARDDIR)/esp32-wrover-kit.config
endif

View File

@ -59,9 +59,11 @@ extern "C" {
* @{
**/
#define SX127X_PARAM_SPI SPI_DEV(0)
#if defined(BOARD_FEATHER_M0_LORA)
#define SX127X_PARAM_SPI_NSS GPIO_PIN(PA, 6)
#define SX127X_PARAM_RESET GPIO_PIN(PA, 8)
#define SX127X_PARAM_DIO0 GPIO_PIN(PA, 9)
#endif
#define SX127X_PARAM_DIO1 GPIO_UNDEF
#define SX127X_PARAM_DIO2 GPIO_UNDEF
#define SX127X_PARAM_DIO3 GPIO_UNDEF

View File

@ -38,7 +38,6 @@ static const mtd_spi_nor_params_t _ikea_tradfri_nor_params = {
.cs = IKEA_TRADFRI_NOR_SPI_CS,
.wp = GPIO_UNDEF,
.hold = GPIO_UNDEF,
.addr_width = 3,
};
static mtd_spi_nor_t ikea_tradfri_nor_dev = {

View File

@ -40,7 +40,6 @@ static const mtd_spi_nor_params_t _mtd_nor_params = {
.cs = GPIO_PIN(PORT_A, 11),
.wp = GPIO_PIN(PORT_C, 6),
.hold = GPIO_PIN(PORT_C, 9),
.addr_width = 3,
};
static mtd_spi_nor_t mtd_nor_dev = {

View File

@ -19,4 +19,6 @@ config BOARD_LIMIFROG_V1
select HAS_PERIPH_TIMER
select HAS_PERIPH_UART
select HAVE_LIS3MDL
source "$(RIOTBOARD)/common/stm32/Kconfig"

View File

@ -25,6 +25,10 @@ config BOARD_LORA_E5_DEV
# Put other features for this board (in alphabetical order)
select HAS_RIOTBOOT
# Clock configuration
select BOARD_HAS_HSE
select BOARD_HAS_LSE
select HAVE_SAUL_GPIO
select HAVE_LM75A
@ -35,3 +39,5 @@ config LORA_E5_DEV_ENABLE_3P3V
config LORA_E5_DEV_ENABLE_5V
bool "LoRa-E5 Development Kit - Enable 5V output"
default y
source "$(RIOTBOARD)/common/stm32/Kconfig"

View File

@ -16,5 +16,6 @@ config BOARD_MSB_430H
select HAS_PERIPH_TIMER
select HAS_PERIPH_UART
select BOARD_COMMON_MSB_430
select HAVE_SHT11
source "$(RIOTBOARD)/common/msb-430/Kconfig"

View File

@ -27,4 +27,7 @@ config BOARD_MSBIOT
select BOARD_HAS_HSE
select BOARD_HAS_LSE
select HAVE_MPU9150
select HAVE_SAUL_GPIO
source "$(RIOTBOARD)/common/stm32/Kconfig"

View File

@ -56,7 +56,6 @@ static const mtd_spi_nor_params_t mulle_nor_params = {
.wait_32k_erase = 20LU * US_PER_MS,
.wait_chip_wake_up = 1LU * US_PER_MS,
.spi = MULLE_NOR_SPI_DEV,
.addr_width = 3,
.mode = SPI_MODE_3,
.cs = MULLE_NOR_SPI_CS,
.wp = GPIO_UNDEF,

View File

@ -40,7 +40,6 @@ static const mtd_spi_nor_params_t _nrf52840dk_nor_params = {
.cs = NRF52840DK_NOR_SPI_CS,
.wp = GPIO_UNDEF,
.hold = GPIO_UNDEF,
.addr_width = 3,
};
static mtd_spi_nor_t nrf52840dk_nor_dev = {

View File

@ -18,3 +18,7 @@ config BOARD_OMOTE
select HAS_PERIPH_TIMER
select HAS_PERIPH_UART
select HAS_RIOTBOOT
select HAVE_SAUL_GPIO
select HAVE_BMP180
select HAVE_ADXL345

View File

@ -18,3 +18,6 @@ config BOARD_OPENMOTE_B
select HAS_PERIPH_TIMER
select HAS_PERIPH_UART
select HAS_RIOTBOOT
select HAVE_SI7006
select HAVE_SAUL_GPIO

View File

@ -43,7 +43,6 @@ static const mtd_spi_nor_params_t _pinetime_nor_params = {
.cs = PINETIME_NOR_SPI_CS,
.wp = GPIO_UNDEF,
.hold = GPIO_UNDEF,
.addr_width = 3,
};
static mtd_spi_nor_t pinetime_nor_dev = {

View File

@ -43,7 +43,6 @@ static const mtd_spi_nor_params_t _mtd_nor_params = {
.cs = SPI_HWCS(0), /* GPIO(PORT_A, 3) is used for HWCS(0) on FC2 */
.wp = GPIO_UNDEF,
.hold = GPIO_UNDEF,
.addr_width = 3, /* 24-bit addresses */
};
static mtd_spi_nor_t mtd_nor_dev = {

View File

@ -11,5 +11,7 @@ config BOARD_REMOTE_PA
bool
default y
select BOARD_COMMON_REMOTE
select HAVE_SAUL_GPIO
select HAVE_SAUL_ADC
source "$(RIOTBOARD)/common/remote/Kconfig"

View File

@ -20,3 +20,9 @@ config BOARD_SAMD10_XMINI
select HAS_PERIPH_SPI
select HAS_PERIPH_TIMER
select HAS_PERIPH_UART
select HAVE_SAUL_GPIO
choice LIBC_IMPLEMENTATION
# Use Picolibc to reduce ROM usage
default MODULE_PICOLIBC
endchoice

View File

@ -24,7 +24,7 @@
#include "timex.h"
#ifdef MODULE_MTD
/* N25Q256A */
/* N25Q256A or SST26VF064B */
static const mtd_spi_nor_params_t _same54_nor_params = {
.opcode = &mtd_spi_nor_opcode_default,
.wait_chip_erase = 240 * US_PER_SEC,
@ -38,7 +38,6 @@ static const mtd_spi_nor_params_t _same54_nor_params = {
.cs = SAM0_QSPI_PIN_CS,
.wp = SAM0_QSPI_PIN_DATA_2,
.hold = SAM0_QSPI_PIN_DATA_3,
.addr_width = 4,
};
static mtd_spi_nor_t same54_nor_dev = {

View File

@ -41,7 +41,6 @@ static const mtd_spi_nor_params_t _serpente_nor_params = {
.cs = SERPENTE_NOR_SPI_CS,
.wp = GPIO_UNDEF,
.hold = GPIO_UNDEF,
.addr_width = 3,
};
static mtd_spi_nor_t serpente_nor_dev = {

View File

@ -3,9 +3,6 @@ ifneq (,$(filter saul_default,$(USEMODULE)))
USEMODULE += saul_gpio
endif
# limit the stack size so most tests and examples compile
CFLAGS += -DTHREAD_STACKSIZE_DEFAULT=512
# add board common drivers
USEMODULE += boards_common_silabs
USEMODULE += silabs_bc

View File

@ -1,5 +1,8 @@
# setup JLink for flashing
JLINK_PRE_FLASH = r
# limit the stack size so most tests and examples compile
CFLAGS += -DTHREAD_STACKSIZE_DEFAULT=512
# include board common
include $(RIOTBOARD)/common/silabs/Makefile.include

View File

@ -15,3 +15,9 @@ config BOARD_STM32MP157C_DK2
# Put defined MCU peripherals here (in alphabetical order)
select HAS_PERIPH_TIMER
select HAS_PERIPH_UART
# Clock configuration
select BOARD_HAS_HSE
select BOARD_HAS_LSE
source "$(RIOTBOARD)/common/stm32/Kconfig"

View File

@ -4,7 +4,3 @@ ifneq (,$(filter saul_default,$(USEMODULE)))
USEMODULE += saul_gpio
# USEMODULE += si7034 # TODO: add when si70xx driver is updated
endif
ifneq (,$(filter vfs,$(USEMODULE)))
USEMODULE += mtd_sdcard
endif

View File

@ -24,11 +24,6 @@
#define RMUTEX_H
#include <stdint.h>
#ifdef __cplusplus
#include "c11_atomics_compat.hpp"
#else
#include <stdatomic.h>
#endif
#include "mutex.h"
#include "sched.h"
@ -62,14 +57,14 @@ typedef struct rmutex_t {
* atomic_int_least16_t is used. Note @ref kernel_pid_t is an int16
* @internal
*/
atomic_int_least16_t owner;
kernel_pid_t owner;
} rmutex_t;
/**
* @brief Static initializer for rmutex_t.
* @details This initializer is preferable to rmutex_init().
*/
#define RMUTEX_INIT { MUTEX_INIT, 0, ATOMIC_VAR_INIT(KERNEL_PID_UNDEF) }
#define RMUTEX_INIT { MUTEX_INIT, 0, KERNEL_PID_UNDEF }
/**
* @brief Initializes a recursive mutex object.

View File

@ -24,9 +24,10 @@
#include <stdio.h>
#include <inttypes.h>
#include "assert.h"
#include "atomic_utils.h"
#include "rmutex.h"
#include "thread.h"
#include "assert.h"
#define ENABLE_DEBUG 0
#include "debug.h"
@ -78,7 +79,7 @@ static int _lock(rmutex_t *rmutex, int trylock)
*/
/* ensure that owner is read atomically, since I need a consistent value */
owner = atomic_load_explicit(&rmutex->owner, memory_order_relaxed);
owner = atomic_load_kernel_pid(&rmutex->owner);
DEBUG("rmutex %" PRIi16 " : mutex held by %" PRIi16 " \n",
thread_getpid(), owner);
@ -104,8 +105,7 @@ static int _lock(rmutex_t *rmutex, int trylock)
DEBUG("rmutex %" PRIi16 " : setting the owner\n", thread_getpid());
/* ensure that owner is written atomically, since others need a consistent value */
atomic_store_explicit(&rmutex->owner, thread_getpid(),
memory_order_relaxed);
atomic_store_kernel_pid(&rmutex->owner, thread_getpid());
DEBUG("rmutex %" PRIi16 " : increasing refs\n", thread_getpid());
@ -127,8 +127,8 @@ int rmutex_trylock(rmutex_t *rmutex)
void rmutex_unlock(rmutex_t *rmutex)
{
assert(atomic_load_explicit(&rmutex->owner,
memory_order_relaxed) == thread_getpid());
/* ensure that owner is read atomically, since I need a consistent value */
assert(atomic_load_kernel_pid(&rmutex->owner) == thread_getpid());
assert(rmutex->refcount > 0);
DEBUG("rmutex %" PRIi16 " : decrementing refs refs\n", thread_getpid());
@ -143,8 +143,7 @@ void rmutex_unlock(rmutex_t *rmutex)
DEBUG("rmutex %" PRIi16 " : resetting owner\n", thread_getpid());
/* ensure that owner is written only once */
atomic_store_explicit(&rmutex->owner, KERNEL_PID_UNDEF,
memory_order_relaxed);
atomic_store_kernel_pid(&rmutex->owner, KERNEL_PID_UNDEF);
DEBUG("rmutex %" PRIi16 " : releasing mutex\n", thread_getpid());

View File

@ -22,7 +22,7 @@ config USE_CLOCK_PLL
config USE_CLOCK_MSI
bool "Use direct multi-speed frequency internal oscillator (MSI)"
depends on CPU_FAM_L0 || CPU_FAM_L1 || CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB
depends on CPU_FAM_L0 || CPU_FAM_L1 || CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB || CPU_FAM_WL
config USE_CLOCK_HSE
bool "Direct High frequency external oscillator (HSE)"
@ -33,7 +33,7 @@ config USE_CLOCK_HSI
endchoice
if CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB
if CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB || CPU_FAM_WL
choice
bool "Source clock for PLL" if USE_CLOCK_PLL
default CLOCK_PLL_SRC_HSE if BOARD_HAS_HSE
@ -50,23 +50,23 @@ config CLOCK_PLL_SRC_HSI
bool "Use HSI16 source clock"
endchoice
endif # CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB
endif # CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB || CPU_FAM_WL
config CUSTOM_PLL_PARAMS
bool "Configure PLL parameters"
depends on USE_CLOCK_PLL
if CPU_FAM_F2 || CPU_FAM_F4 || CPU_FAM_F7 || CPU_FAM_G0 || CPU_FAM_G4 || CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB
if CPU_FAM_F2 || CPU_FAM_F4 || CPU_FAM_F7 || CPU_FAM_G0 || CPU_FAM_G4 || CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB || CPU_FAM_MP1
config CLOCK_PLL_M
int "M: PLLIN division factor" if CUSTOM_PLL_PARAMS
default 4 if CPU_FAM_F2 || CPU_FAM_F4 || CPU_FAM_F7
default 1 if CPU_FAM_G0
default 6 if CPU_FAM_G4 && BOARD_HAS_HSE
default 4 if CPU_FAM_G4
default 6 if (CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB) && CLOCK_PLL_SRC_MSI
default 4 if CPU_FAM_WB && CLOCK_PLL_SRC_HSE
default 2 if CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB
range 1 8 if CPU_FAM_G0 || CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB
default 6 if (CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB || CPU_FAM_WL) && CLOCK_PLL_SRC_MSI
default 4 if (CPU_FAM_WB || CPU_FAM_WL) && CLOCK_PLL_SRC_HSE
default 2 if CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB || CPU_FAM_WL || CPU_FAM_MP1
range 1 8 if CPU_FAM_G0 || CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB || CPU_FAM_WL
range 1 16 if CPU_FAM_G4
config CLOCK_PLL_N
@ -85,17 +85,21 @@ config CLOCK_PLL_N
default 90 if CPU_FAM_F4 && CLOCK_MAX_180MHZ
default 216 if CPU_FAM_F7 && BOARD_HAS_HSE
default 108 if CPU_FAM_F7
default 12 if CPU_FAM_WL
default 16 if CPU_FAM_WB
default 30 if CPU_LINE_STM32L4A6XX || CPU_LINE_STM32L4P5XX || CPU_LINE_STM32L4Q5XX || CPU_LINE_STM32L4R5XX || CPU_LINE_STM32L4R7XX || CPU_LINE_STM32L4R9XX || CPU_LINE_STM32L4S5XX || CPU_LINE_STM32L4S7XX || CPU_LINE_STM32L4S9XX
default 27 if CPU_FAM_L5
default 20 if CPU_FAM_G0 || CPU_FAM_L4
default 85 if CPU_FAM_G4
default 52 if CPU_FAM_MP1 && BOARD_HAS_HSE
default 78 if CPU_FAM_MP1
range 8 86 if CPU_FAM_G0 || CPU_FAM_L4 || CPU_FAM_L5
range 50 432 if CPU_FAM_F2 || CPU_FAM_F4 || CPU_FAM_F7
range 8 127 if CPU_FAM_G4
range 6 127 if CPU_FAM_WB
range 6 127 if CPU_FAM_WB || CPU_FAM_WL
range 4 512 if CPU_FAM_MP1
if CPU_FAM_F2 || CPU_FAM_F4 || CPU_FAM_F7
if CPU_FAM_F2 || CPU_FAM_F4 || CPU_FAM_F7 || CPU_FAM_MP1
choice
bool "Main PLL division factor (PLLP) for main system clock" if CUSTOM_PLL_PARAMS
default PLL_P_DIV_4 if CPU_FAM_F4 && CLOCK_MAX_84MHZ
@ -117,6 +121,7 @@ endchoice
config CLOCK_PLL_P
int
default 3 if CPU_FAM_MP1
default 2 if PLL_P_DIV_2
default 4 if PLL_P_DIV_4
default 6 if PLL_P_DIV_6
@ -129,18 +134,20 @@ config CLOCK_PLL_Q
default 4 if CPU_FAM_F4 && CLOCK_MAX_100MHZ
default 7 if CPU_FAM_F4 && CLOCK_MAX_180MHZ && (MODULE_PERIPH_USBDEV || USEMODULE_PERIPH_USBDEV)
default 9 if CPU_FAM_F7
default 13 if CPU_FAM_MP1
default 8
range 2 15
endif # CPU_FAM_F2 || CPU_FAM_F4 || CPU_FAM_F7
endif # CPU_FAM_F2 || CPU_FAM_F4 || CPU_FAM_F7 || CPU_FAM_MP1
if CPU_FAM_G0 || CPU_FAM_WB
if CPU_FAM_G0 || CPU_FAM_WB || CPU_FAM_WL || CPU_FAM_MP1
config CLOCK_PLL_R
int "Q: VCO division factor" if CUSTOM_PLL_PARAMS
default 2 if CPU_FAM_WB
default 2 if CPU_FAM_WB || CPU_FAM_WL
default 3 if CPU_FAM_MP1
default 6 if BOARD_HAS_HSE
default 5
range 2 8
endif # CPU_FAM_G0 || CPU_FAM_WB
endif # CPU_FAM_G0 || CPU_FAM_WB || CPU_FAM_WL || CPU_FAM_MP1
if CPU_FAM_G4 || CPU_FAM_L4 || CPU_FAM_L5
choice
@ -169,12 +176,12 @@ config CLOCK_PLL_R
default 8 if PLL_R_DIV_8
endif # CPU_FAM_G4 || CPU_FAM_L4 || CPU_FAM_L5
endif # CPU_FAM_F2 || CPU_FAM_F4 || CPU_FAM_F7 || CPU_FAM_G0 || CPU_FAM_G4 || CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB
endif # CPU_FAM_F2 || CPU_FAM_F4 || CPU_FAM_F7 || CPU_FAM_G0 || CPU_FAM_G4 || CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB || CPU_FAM_WL || CPU_FAM_MP1
if CPU_FAM_F0 || CPU_FAM_F1 || CPU_FAM_F3
config CLOCK_PLL_PREDIV
int "PLLIN division factor" if CUSTOM_PLL_PARAMS && !CPU_LINE_STM32F031X6 && !CPU_LINE_STM32F042X6 && !CPU_LINE_STM32F303X8
default 2 if CPU_LINE_STM32F031X6 || CPU_LINE_STM32F042X6 || CPU_LINE_STM32F303X8
default 2 if CPU_LINE_STM32F031X6 || CPU_LINE_STM32F042X6 || CPU_LINE_STM32F303X8 || CPU_LINE_STM32F303XC
default 1
range 1 16
@ -282,35 +289,35 @@ config CLOCK_HSISYS_DIV
default 128 if CLOCK_HSISYS_DIV_128
endif # CPU_FAM_G0
if CPU_FAM_L0 || CPU_FAM_L1 || CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB
if CPU_FAM_L0 || CPU_FAM_L1 || CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB || CPU_FAM_WL
choice
bool "Desired MSI clock frequency" if USE_CLOCK_MSI || (USE_CLOCK_PLL && CLOCK_PLL_SRC_MSI)
default CLOCK_MSI_48MHZ if CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB
default CLOCK_MSI_48MHZ if CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB || CPU_FAM_WL
default CLOCK_MSI_4MHZ
config CLOCK_MSI_65KHZ
bool "65.536kHz" if CPU_FAM_L0 || CPU_FAM_L1
config CLOCK_MSI_100KHZ
bool "100kHz" if CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB
bool "100kHz" if CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB || CPU_FAM_WL
config CLOCK_MSI_130KHZ
bool "131.072kHz" if CPU_FAM_L0 || CPU_FAM_L1
config CLOCK_MSI_200KHZ
bool "200kHz" if CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB
bool "200kHz" if CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB || CPU_FAM_WL
config CLOCK_MSI_260KHZ
bool "262.144kHz" if CPU_FAM_L0 || CPU_FAM_L1
config CLOCK_MSI_400KHZ
bool "400kHz" if CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB
bool "400kHz" if CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB || CPU_FAM_WL
config CLOCK_MSI_520KHZ
bool "524.288kHz" if CPU_FAM_L0 || CPU_FAM_L1
config CLOCK_MSI_800KHZ
bool "800kHz" if CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB
bool "800kHz" if CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB || CPU_FAM_WL
config CLOCK_MSI_1MHZ
bool
@ -325,19 +332,19 @@ config CLOCK_MSI_4MHZ
prompt "4MHz"
config CLOCK_MSI_8MHZ
bool "8MHz" if CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB
bool "8MHz" if CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB || CPU_FAM_WL
config CLOCK_MSI_16MHZ
bool "16MHz" if CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB
bool "16MHz" if CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB || CPU_FAM_WL
config CLOCK_MSI_24MHZ
bool "24MHz" if CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB
bool "24MHz" if CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB || CPU_FAM_WL
config CLOCK_MSI_32MHZ
bool "32MHz" if CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB
bool "32MHz" if CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB || CPU_FAM_WL
config CLOCK_MSI_48MHZ
bool "48MHz" if CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB
bool "48MHz" if CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB || CPU_FAM_WL
endchoice
@ -351,11 +358,11 @@ config CLOCK_MSI
default 200000 if CLOCK_MSI_200KHZ
default 400000 if CLOCK_MSI_400KHZ
default 800000 if CLOCK_MSI_800KHZ
default 1000000 if CLOCK_MSI_1MHZ && (CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB)
default 1000000 if CLOCK_MSI_1MHZ && (CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB || CPU_FAM_WL)
default 1048000 if CLOCK_MSI_1MHZ && (CPU_FAM_L0 || CPU_FAM_L1)
default 2000000 if CLOCK_MSI_2MHZ && (CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB)
default 2000000 if CLOCK_MSI_2MHZ && (CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB || CPU_FAM_WL)
default 2097000 if CLOCK_MSI_2MHZ && (CPU_FAM_L0 || CPU_FAM_L1)
default 4000000 if CLOCK_MSI_4MHZ && (CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB)
default 4000000 if CLOCK_MSI_4MHZ && (CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB || CPU_FAM_WL)
default 4194000 if CLOCK_MSI_4MHZ && (CPU_FAM_L0 || CPU_FAM_L1)
default 8000000 if CLOCK_MSI_8MHZ
default 16000000 if CLOCK_MSI_16MHZ
@ -363,12 +370,12 @@ config CLOCK_MSI
default 32000000 if CLOCK_MSI_32MHZ
default 48000000 if CLOCK_MSI_48MHZ
endif # CPU_FAM_L0 || CPU_FAM_L1 || CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB
endif # CPU_FAM_L0 || CPU_FAM_L1 || CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_WB || CPU_FAM_WL
choice
bool "APB1 prescaler (division factor of HCLK to produce PCLK1)"
default CLOCK_APB1_DIV_4 if CPU_FAM_F2 || (CPU_FAM_F4 && CLOCK_MAX_180MHZ) || CPU_FAM_F7 || CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_U5 || CPU_FAM_WB
default CLOCK_APB1_DIV_2 if CPU_FAM_F1 || CPU_FAM_F3 || CPU_FAM_F4
default CLOCK_APB1_DIV_4 if CPU_FAM_F2 || (CPU_FAM_F4 && CLOCK_MAX_180MHZ) || CPU_FAM_F7 || CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_U5 || CPU_FAM_WB || CPU_FAM_WL
default CLOCK_APB1_DIV_2 if CPU_FAM_F1 || CPU_FAM_F3 || CPU_FAM_F4 || CPU_FAM_MP1
default CLOCK_APB1_DIV_1
config CLOCK_APB1_DIV_1
@ -399,7 +406,7 @@ config CLOCK_APB1_DIV
choice
bool "APB2 prescaler (division factor of HCLK to produce PCLK2)"
depends on !CPU_FAM_G0 && !CPU_FAM_F0
default CLOCK_APB2_DIV_2 if CPU_FAM_F2 || (CPU_FAM_F4 && CLOCK_MAX_180MHZ) || CPU_FAM_F7 || CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_U5 || CPU_FAM_WB
default CLOCK_APB2_DIV_2 if CPU_FAM_F2 || (CPU_FAM_F4 && CLOCK_MAX_180MHZ) || CPU_FAM_F7 || CPU_FAM_L4 || CPU_FAM_L5 || CPU_FAM_U5 || CPU_FAM_WB || CPU_FAM_WL || CPU_FAM_MP1
default CLOCK_APB2_DIV_1
config CLOCK_APB2_DIV_1
@ -427,7 +434,7 @@ config CLOCK_APB2_DIV
default 8 if CLOCK_APB2_DIV_8
default 16 if CLOCK_APB2_DIV_16
if CPU_FAM_F0 || CPU_FAM_F1 || CPU_FAM_F3 || CPU_FAM_G0 || CPU_FAM_G4 || CPU_FAM_L0 || CPU_FAM_L1 || CPU_FAM_L4 || CPU_FAM_WB
if CPU_FAM_F0 || CPU_FAM_F1 || CPU_FAM_F3 || CPU_FAM_G0 || CPU_FAM_G4 || CPU_FAM_L0 || CPU_FAM_L1 || CPU_FAM_L4 || CPU_FAM_WB || CPU_FAM_WL
config CLOCK_ENABLE_MCO
bool "Enable MCU Clock Output (MCO) on PA8"
@ -447,15 +454,15 @@ config CLOCK_MCO_USE_HSI
config CLOCK_MCO_USE_LSE
bool "Use LSE as MCO source"
depends on CPU_FAM_G0 || CPU_FAM_G4 || CPU_FAM_L0 || CPU_FAM_L1 || CPU_FAM_L4 || CPU_FAM_WB
depends on CPU_FAM_G0 || CPU_FAM_G4 || CPU_FAM_L0 || CPU_FAM_L1 || CPU_FAM_L4 || CPU_FAM_WB || CPU_FAM_WL
config CLOCK_MCO_USE_LSI
bool "Use LSI as MCO source"
depends on CPU_FAM_G0 || CPU_FAM_G4 || CPU_FAM_L0 || CPU_FAM_L1 || CPU_FAM_L4 || CPU_FAM_WB
depends on CPU_FAM_G0 || CPU_FAM_G4 || CPU_FAM_L0 || CPU_FAM_L1 || CPU_FAM_L4 || CPU_FAM_WB || CPU_FAM_WL
config CLOCK_MCO_USE_MSI
bool "Use MSI as MCO source"
depends on CPU_FAM_L0 || CPU_FAM_L1 || CPU_FAM_L4 || CPU_FAM_WB
depends on CPU_FAM_L0 || CPU_FAM_L1 || CPU_FAM_L4 || CPU_FAM_WB || CPU_FAM_WL
config CLOCK_MCO_USE_SYSCLK
bool "Use SYSCLK as MCO source"
@ -484,15 +491,15 @@ config CLOCK_MCO_PRE_16
config CLOCK_MCO_PRE_32
bool "Divide MCO by 32"
depends on !CPU_FAM_G4 && !CPU_FAM_L0 && !CPU_FAM_L1 && !CPU_FAM_L4 && !CPU_FAM_WB
depends on !CPU_FAM_G4 && !CPU_FAM_L0 && !CPU_FAM_L1 && !CPU_FAM_L4 && !CPU_FAM_WB && !CPU_FAM_WL
config CLOCK_MCO_PRE_64
bool "Divide MCO by 64"
depends on !CPU_FAM_G4 && !CPU_FAM_L0 && !CPU_FAM_L1 && !CPU_FAM_L4 && !CPU_FAM_WB
depends on !CPU_FAM_G4 && !CPU_FAM_L0 && !CPU_FAM_L1 && !CPU_FAM_L4 && !CPU_FAM_WB && !CPU_FAM_WL
config CLOCK_MCO_PRE_128
bool "Divide MCO by 128"
depends on !CPU_FAM_G4 && !CPU_FAM_L0 && !CPU_FAM_L1 && !CPU_FAM_L4 && !CPU_FAM_WB
depends on !CPU_FAM_G4 && !CPU_FAM_L0 && !CPU_FAM_L1 && !CPU_FAM_L4 && !CPU_FAM_WB && !CPU_FAM_WL
endchoice
@ -507,6 +514,6 @@ config CLOCK_MCO_PRE
default 128 if CLOCK_MCO_PRE_128
default 1
endif # CPU_FAM_F0 || CPU_FAM_F1 || CPU_FAM_F3 || CPU_FAM_G0 || CPU_FAM_G4 || CPU_FAM_L0 || CPU_FAM_L1 || CPU_FAM_L4 || CPU_FAM_WB
endif # CPU_FAM_F0 || CPU_FAM_F1 || CPU_FAM_F3 || CPU_FAM_G0 || CPU_FAM_G4 || CPU_FAM_L0 || CPU_FAM_L1 || CPU_FAM_L4 || CPU_FAM_WB || CPU_FAM_WL
endmenu

View File

@ -39,7 +39,13 @@ TEST_INTERACTIVE_DELAY = int(os.environ.get('TEST_INTERACTIVE_DELAY') or 1)
# By default never reset after the terminal is open unless explicitly requested
# through an environment variable.
TESTRUNNER_RESET_AFTER_TERM = int(os.environ.get('TESTRUNNER_RESET_AFTER_TERM')
or '0')
or 0)
# When running e.g. tests/shell_ble we don't want to reset the board, because
# then ble-serial would terminate and the created virtual serial port would get
# lost. By default the board is reset before the test starts.
TESTRUNNER_RESET_BOARD_ON_STARTUP = \
int(os.environ.get('TESTRUNNER_RESET_BOARD_ON_STARTUP') or 1)
MAKE = os.environ.get('MAKE', 'make')
@ -70,7 +76,8 @@ def find_exc_origin(exc_info):
def setup_child(timeout=10, spawnclass=pexpect.spawnu, env=None, logfile=None):
# Some boards can't be reset after a terminal is open. Therefore reset
# before `cleanterm`.
_reset_board(env)
if TESTRUNNER_RESET_BOARD_ON_STARTUP:
_reset_board(env)
# on platforms exposing UART over USB, wait a little before connecting to
# the serial terminal. This gives time for stdio to be ready.

View File

@ -10,3 +10,9 @@ config MODULE_ADXL345
depends on HAS_PERIPH_I2C
depends on TEST_KCONFIG
select MODULE_PERIPH_I2C
config HAVE_ADXL345
bool
select MODULE_ADXL345 if MODULE_SAUL_DEFAULT
help
Indicates that a adxl345 sensor is present.

View File

@ -12,3 +12,9 @@ config MODULE_BMP180
select MODULE_PERIPH_I2C
select MODULE_ZTIMER
select MODULE_ZTIMER_MSEC
config HAVE_BMP180
bool
select MODULE_BMP180 if MODULE_SAUL_DEFAULT
help
Indicates that a bmp180 sensor is present.

View File

@ -21,6 +21,7 @@
#include <assert.h>
#include <string.h>
#include "board.h"
#include "dose.h"
#include "random.h"
#include "irq.h"
@ -33,6 +34,10 @@
#define ENABLE_DEBUG 0
#include "debug.h"
#if !defined(DOSE_TIMER_DEV) && IS_ACTIVE(MODULE_DOSE_WATCHDOG)
#error "DOSE_TIMER_DEV needs to be set by the board"
#endif
static uint16_t crc16_update(uint16_t crc, uint8_t octet);
static dose_signal_t state_transit_blocked(dose_t *ctx, dose_signal_t signal);
static dose_signal_t state_transit_idle(dose_t *ctx, dose_signal_t signal);

View File

@ -170,8 +170,6 @@ typedef enum {
*/
#if DOXYGEN
#define DOSE_TIMER_DEV TIMER_DEV(…)
#elif !defined(DOSE_TIMER_DEV) && IS_ACTIVE(MODULE_DOSE_WATCHDOG)
#error "DOSE_TIMER_DEV needs to be set by the board"
#endif
/**

View File

@ -113,7 +113,6 @@ typedef struct {
gpio_t cs; /**< CS pin GPIO handle */
gpio_t wp; /**< Write Protect pin GPIO handle */
gpio_t hold; /**< HOLD pin GPIO handle */
uint8_t addr_width; /**< Number of bytes in addresses, usually 3 for small devices */
} mtd_spi_nor_params_t;
/**
@ -150,6 +149,12 @@ typedef struct {
* Computed by mtd_spi_nor_init, no need to touch outside the driver.
*/
uint8_t sec_addr_shift;
/**
* @brief number of address bytes
*
* Computed by mtd_spi_nor_init, no need to touch outside the driver.
*/
uint8_t addr_width;
} mtd_spi_nor_t;
/**

View File

@ -5,30 +5,46 @@
# directory for more details.
#
if TEST_KCONFIG
choice
bool "MPU-9X50 accelerometer/magnetometer/gyroscope"
optional
depends on HAS_PERIPH_I2C
help
This driver supports both MPU9150 and MPU9250. Choose one model.
config MODULE_MPU9150
bool "MPU-9150"
select MODULE_MPU9X50
config MODULE_MPU9250
bool "MPU-9250"
select MODULE_MPU9X50
endchoice
config MODULE_MPU9X50
menuconfig MODULE_MPU9X50
bool
prompt "MPU-9X50 accelerometer/magnetometer/gyroscope" if !(MODULE_SAUL_DEFAULT && HAVE_MPU9X50)
default y if (MODULE_SAUL_DEFAULT && HAVE_MPU9X50)
depends on TEST_KCONFIG
depends on HAS_PERIPH_I2C
select MODULE_PERIPH_I2C
select MODULE_ZTIMER
select MODULE_ZTIMER_MSEC
endif # TEST_KCONFIG
choice
bool "Sensor variant"
default MODULE_MPU9150 if HAVE_MPU9150
default MODULE_MPU9250 if HAVE_MPU9250
depends on MODULE_MPU9X50
help
This driver supports both MPU9150 and MPU9250. Choose one model.
config MODULE_MPU9150
bool "MPU-9150"
config MODULE_MPU9250
bool "MPU-9250"
endchoice
config HAVE_MPU9150
bool
select HAVE_MPU9X50
help
Indicates that a mpu9150 sensor is present.
config HAVE_MPU9250
bool
select HAVE_MPU9X50
help
Indicates that a mpu9250 sensor is present.
config HAVE_MPU9X50
bool
help
Indicates that a mpu9X50 sensor is present.

View File

@ -45,6 +45,8 @@
#define SFLASH_CMD_4_BYTE_ADDR (0xB7) /**< enable 32 bit addressing */
#define SFLASH_CMD_3_BYTE_ADDR (0xE9) /**< enable 24 bit addressing */
#define SFLASH_CMD_ULBPR (0x98) /**< Global Block Protection Unlock */
#define MTD_64K (65536ul)
#define MTD_64K_ADDR_MASK (0xFFFF)
#define MTD_32K (32768ul)
@ -66,6 +68,7 @@
typedef enum {
SPI_NOR_JEDEC_ATMEL = 0x1F | JEDEC_BANK(1),
SPI_NOR_JEDEC_MICROCHIP = 0xBF | JEDEC_BANK(1),
} jedec_manuf_t;
/** @} */
@ -88,7 +91,7 @@ static void mtd_spi_release(const mtd_spi_nor_t *dev)
static inline uint8_t* _be_addr(const mtd_spi_nor_t *dev, uint32_t *addr)
{
*addr = htonl(*addr);
return &((uint8_t*)addr)[4 - dev->params->addr_width];
return &((uint8_t*)addr)[4 - dev->addr_width];
}
/**
@ -111,7 +114,7 @@ static void mtd_spi_cmd_addr_read(const mtd_spi_nor_t *dev, uint8_t opcode,
if (IS_ACTIVE(ENABLE_TRACE)) {
TRACE("mtd_spi_cmd_addr_read: addr:");
for (unsigned int i = 0; i < dev->params->addr_width; ++i) {
for (unsigned int i = 0; i < dev->addr_width; ++i) {
TRACE(" %02x", addr_buf[i]);
}
TRACE("\n");
@ -120,7 +123,7 @@ static void mtd_spi_cmd_addr_read(const mtd_spi_nor_t *dev, uint8_t opcode,
/* Send opcode followed by address */
spi_transfer_byte(_get_spi(dev), dev->params->cs, true, opcode);
spi_transfer_bytes(_get_spi(dev), dev->params->cs, true,
(char *)addr_buf, NULL, dev->params->addr_width);
(char *)addr_buf, NULL, dev->addr_width);
/* Read data */
spi_transfer_bytes(_get_spi(dev), dev->params->cs, false,
@ -147,7 +150,7 @@ static void mtd_spi_cmd_addr_write(const mtd_spi_nor_t *dev, uint8_t opcode,
if (IS_ACTIVE(ENABLE_TRACE)) {
TRACE("mtd_spi_cmd_addr_write: addr:");
for (unsigned int i = 0; i < dev->params->addr_width; ++i) {
for (unsigned int i = 0; i < dev->addr_width; ++i) {
TRACE(" %02x", addr_buf[i]);
}
TRACE("\n");
@ -159,7 +162,7 @@ static void mtd_spi_cmd_addr_write(const mtd_spi_nor_t *dev, uint8_t opcode,
/* only keep CS asserted when there is data that follows */
bool cont = (count > 0);
spi_transfer_bytes(_get_spi(dev), dev->params->cs, cont,
(char *)addr_buf, NULL, dev->params->addr_width);
(char *)addr_buf, NULL, dev->addr_width);
/* Write data */
if (cont) {
@ -303,6 +306,28 @@ static uint32_t mtd_spi_nor_get_size(const mtd_jedec_id_t *id)
(id->device[1] & ~0x3) == 0) {
return (0x1F & id->device[0]) * MBIT_AS_BYTES;
}
if (mtd_spi_manuf_match(id, SPI_NOR_JEDEC_MICROCHIP)) {
switch (id->device[1]) {
case 0x12: /* SST26VF020A */
case 0x8c: /* SST25VF020B */
return 2 * MBIT_AS_BYTES;
case 0x54: /* SST26WF040B */
case 0x8d: /* SST25VF040B */
return 4 * MBIT_AS_BYTES;
case 0x58: /* SST26WF080B */
case 0x8e: /* SST25VF080B */
return 8 * MBIT_AS_BYTES;
case 0x1: /* SST26VF016 */
case 0x41: /* SST26VF016B */
return 16 * MBIT_AS_BYTES;
case 0x2: /* SST26VF032 */
case 0x42: /* SST26VF032B */
return 32 * MBIT_AS_BYTES;
case 0x43: /* SST26VF064B */
case 0x53: /* SST26WF064C */
return 64 * MBIT_AS_BYTES;
}
}
/* everyone else seems to use device ID 2 for density */
return 1 << id->device[1];
@ -376,6 +401,12 @@ static void _init_pins(mtd_spi_nor_t *dev)
}
}
static void _enable_32bit_addr(mtd_spi_nor_t *dev)
{
mtd_spi_cmd(dev, dev->params->opcode->wren);
mtd_spi_cmd(dev, SFLASH_CMD_4_BYTE_ADDR);
}
static int mtd_spi_nor_power(mtd_dev_t *mtd, enum mtd_power_state power)
{
mtd_spi_nor_t *dev = (mtd_spi_nor_t *)mtd;
@ -399,9 +430,8 @@ static int mtd_spi_nor_power(mtd_dev_t *mtd, enum mtd_power_state power)
}
#endif
/* enable 32 bit address mode */
if (dev->params->addr_width == 4) {
mtd_spi_cmd(dev, dev->params->opcode->wren);
mtd_spi_cmd(dev, SFLASH_CMD_4_BYTE_ADDR);
if (dev->addr_width == 4) {
_enable_32bit_addr(dev);
}
break;
@ -414,6 +444,20 @@ static int mtd_spi_nor_power(mtd_dev_t *mtd, enum mtd_power_state power)
return 0;
}
static void _set_addr_width(mtd_dev_t *mtd)
{
mtd_spi_nor_t *dev = (mtd_spi_nor_t *)mtd;
uint32_t flash_size = mtd->pages_per_sector * mtd->page_size
* mtd->sector_count;
if (flash_size > 0xFFFFFF) {
dev->addr_width = 4;
} else {
dev->addr_width = 3;
}
}
static int mtd_spi_nor_init(mtd_dev_t *mtd)
{
DEBUG("mtd_spi_nor_init: %p\n", (void *)mtd);
@ -422,10 +466,6 @@ static int mtd_spi_nor_init(mtd_dev_t *mtd)
DEBUG("mtd_spi_nor_init: -> spi: %lx, cs: %lx, opcodes: %p\n",
(unsigned long)_get_spi(dev), (unsigned long)dev->params->cs, (void *)dev->params->opcode);
/* verify configuration */
assert(dev->params->addr_width > 0);
assert(dev->params->addr_width <= 4);
/* CS, WP, Hold */
_init_pins(dev);
@ -450,6 +490,7 @@ static int mtd_spi_nor_init(mtd_dev_t *mtd)
mtd->sector_count = mtd_spi_nor_get_size(&dev->jedec_id)
/ (mtd->pages_per_sector * mtd->page_size);
}
_set_addr_width(mtd);
DEBUG("mtd_spi_nor_init: %" PRIu32 " bytes "
"(%" PRIu32 " sectors, %" PRIu32 " bytes/sector, "
@ -459,14 +500,23 @@ static int mtd_spi_nor_init(mtd_dev_t *mtd)
mtd->sector_count, mtd->pages_per_sector * mtd->page_size,
mtd->pages_per_sector * mtd->sector_count,
mtd->pages_per_sector, mtd->page_size);
DEBUG("mtd_spi_nor_init: Using %u byte addresses\n", dev->params->addr_width);
DEBUG("mtd_spi_nor_init: Using %u byte addresses\n", dev->addr_width);
uint8_t status;
mtd_spi_cmd_read(dev, dev->params->opcode->rdsr, &status, sizeof(status));
mtd_spi_release(dev);
DEBUG("mtd_spi_nor_init: device status = 0x%02x\n", (unsigned int)status);
/* enable 32 bit address mode */
if (dev->addr_width == 4) {
_enable_32bit_addr(dev);
}
/* Global Block-Protection Unlock */
mtd_spi_cmd(dev, dev->params->opcode->wren);
mtd_spi_cmd(dev, SFLASH_CMD_ULBPR);
mtd_spi_release(dev);
/* check whether page size and sector size are powers of two (most chips' are)
* and compute the number of shifts needed to get the page and sector addresses
* from a byte address */

View File

@ -6,8 +6,9 @@
EXTERNAL_MODULE_PATHS := $(sort $(foreach dir,$(EXTERNAL_MODULE_DIRS),\
$(foreach mod,$(USEMODULE),$(dir $(wildcard $(dir)/$(mod)/Makefile)))))
# Locate used packages in $(RIOTPKG).
PKG_PATHS := $(sort $(foreach dir,$(RIOTPKG),\
# Locate used packages in $(RIOTPKG) or $(EXTERNAL_PKG_DIRS).
PKGDIRS := $(RIOTPKG) $(EXTERNAL_PKG_DIRS)
PKG_PATHS := $(sort $(foreach dir,$(PKGDIRS),\
$(foreach pkg,$(USEPKG),$(dir $(wildcard $(dir)/$(pkg)/Makefile)))))
# Back up current state to detect changes

View File

@ -27,7 +27,10 @@ export KCONFIG_AUTOHEADER_HEADER
export KCONFIG_GENERATED_DEPENDENCIES = $(GENERATED_DIR)/Kconfig.dep
# This file will contain external module configurations
export KCONFIG_EXTERNAL_CONFIGS = $(GENERATED_DIR)/Kconfig.external_modules
export KCONFIG_EXTERNAL_MODULE_CONFIGS = $(GENERATED_DIR)/Kconfig.external_modules
# This file will contain external package configurations
export KCONFIG_EXTERNAL_PKG_CONFIGS = $(GENERATED_DIR)/Kconfig.external_pkgs
# Add configurations that only work when running the Kconfig test so far,
# because they activate modules.
@ -179,12 +182,12 @@ $(KCONFIG_GENERATED_ENV_CONFIG): FORCE | $(GENERATED_DIR)
| $(LAZYSPONGE) $(LAZYSPONGE_FLAGS) $@
# All directories in EXTERNAL_MODULES_PATHS which have a Kconfig file
EXTERNAL_MODULE_KCONFIGS ?= $(sort $(foreach dir,$(EXTERNAL_MODULE_PATHS),\
$(wildcard $(dir)/Kconfig)))
EXTERNAL_MODULE_KCONFIGS ?= $(sort $(foreach dir,$(EXTERNAL_MODULE_DIRS),\
$(wildcard $(dir)/*/Kconfig)))
# Build a Kconfig file that source all external modules configuration
# files. Every EXTERNAL_MODULE_DIRS with a Kconfig file is written to
# KCONFIG_EXTERNAL_CONFIGS as 'osource dir/Kconfig'
$(KCONFIG_EXTERNAL_CONFIGS): FORCE | $(GENERATED_DIR)
# KCONFIG_EXTERNAL_MODULE_CONFIGS as 'osource dir/Kconfig'
$(KCONFIG_EXTERNAL_MODULE_CONFIGS): FORCE | $(GENERATED_DIR)
$(Q)\
if [ -n "$(EXTERNAL_MODULE_KCONFIGS)" ] ; then \
printf "%s\n" $(EXTERNAL_MODULE_KCONFIGS) \
@ -195,6 +198,24 @@ $(KCONFIG_EXTERNAL_CONFIGS): FORCE | $(GENERATED_DIR)
| $(LAZYSPONGE) $(LAZYSPONGE_FLAGS) $@ ; \
fi
# All directories in EXTERNAL_PKG_DIRS which have a subdirectory containing a
# Kconfig file.
EXTERNAL_PKG_KCONFIGS ?= $(sort $(foreach dir,$(EXTERNAL_PKG_DIRS),\
$(wildcard $(dir)/*/Kconfig)))
# Build a Kconfig file that sources all external packages configuration
# files. Every directory with a Kconfig file is written to KCONFIG_PKG_CONFIGS
# as 'osource dir/Kconfig'
$(KCONFIG_EXTERNAL_PKG_CONFIGS): FORCE | $(GENERATED_DIR)
$(Q)\
if [ -n "$(EXTERNAL_PKG_KCONFIGS)" ] ; then \
printf "%s\n" $(EXTERNAL_PKG_KCONFIGS) \
| awk '{ printf "osource \"%s\"\n", $$0 }' \
| $(LAZYSPONGE) $(LAZYSPONGE_FLAGS) $@ ; \
else \
printf "# no external packages" \
| $(LAZYSPONGE) $(LAZYSPONGE_FLAGS) $@ ; \
fi
# When the 'clean' target is called, the files inside GENERATED_DIR should be
# regenerated. For that, we conditionally change GENERATED_DIR from an 'order
# only' requisite to a normal one.
@ -211,7 +232,7 @@ GENERATED_DIR_DEP := $(if $(CLEAN),,|) $(GENERATED_DIR)
# Generates a .config file by merging multiple sources specified in
# MERGE_SOURCES. This will also generate KCONFIG_OUT_DEP with the list of used
# Kconfig files.
$(KCONFIG_OUT_CONFIG): $(KCONFIG_EXTERNAL_CONFIGS)
$(KCONFIG_OUT_CONFIG): $(KCONFIG_EXTERNAL_MODULE_CONFIGS) $(KCONFIG_EXTERNAL_PKG_CONFIGS)
$(KCONFIG_OUT_CONFIG): $(GENERATED_DEPENDENCIES_DEP) $(GENCONFIG) $(MERGE_SOURCES) $(GENERATED_DIR_DEP)
$(Q) $(GENCONFIG) \
--config-out=$(KCONFIG_OUT_CONFIG) \

View File

@ -154,8 +154,11 @@ PSEUDOMODULES += netstats_rpl
PSEUDOMODULES += nimble
PSEUDOMODULES += nimble_adv_ext
PSEUDOMODULES += nimble_autoconn_%
PSEUDOMODULES += nimble_netif_ext
PSEUDOMODULES += nimble_phy_coded
PSEUDOMODULES += nimble_phy_2mbit
PSEUDOMODULES += nimble_rpble_ext
PSEUDOMODULES += nimble_statconn_ext
PSEUDOMODULES += newlib
PSEUDOMODULES += newlib_gnu_source
PSEUDOMODULES += newlib_nano
@ -201,6 +204,7 @@ PSEUDOMODULES += stdin
PSEUDOMODULES += stdio_available
PSEUDOMODULES += stdio_cdc_acm
PSEUDOMODULES += stdio_ethos
PSEUDOMODULES += stdio_nimble_debug
PSEUDOMODULES += stdio_uart_rx
PSEUDOMODULES += stm32_eth
PSEUDOMODULES += stm32_eth_auto

View File

@ -2,6 +2,7 @@ STDIO_MODULES = \
slipdev_stdio \
stdio_cdc_acm \
stdio_ethos \
stdio_nimble \
stdio_null \
stdio_rtt \
stdio_semihosting \
@ -29,6 +30,18 @@ ifneq (,$(filter stdio_ethos,$(USEMODULE)))
USEMODULE += stdin
endif
ifneq (,$(filter stdio_nimble,$(USEMODULE)))
USEMODULE += stdio_available
USEPKG += nimble
USEMODULE += tsrb
USEMODULE += isrpipe
USEMODULE += nimble_svc_gap
USEMODULE += nimble_svc_gatt
ifneq (,$(filter stdio_nimble_debug,$(USEMODULE)))
FEATURES_REQUIRED += periph_uart
endif
endif
ifneq (,$(filter stdin,$(USEMODULE)))
ifneq (,$(filter stdio_uart,$(USEMODULE)))
USEMODULE += stdio_uart_rx

View File

@ -21,6 +21,7 @@ rsource "esp32_sdk/Kconfig"
rsource "esp32_sdk_libs/Kconfig"
rsource "esp8266_sdk/Kconfig"
rsource "fff/Kconfig"
rsource "fido2_tests/Kconfig"
rsource "gecko_sdk/Kconfig"
rsource "gemmlowp/Kconfig"
rsource "hacl/Kconfig"

View File

@ -72,5 +72,34 @@
* * commit your changes using `git commit`
* * create the patch files using `git format-patch -n riot-port`
* * move the resulting patch files to the patches directory of your package.
*
* Packages outside of RIOTPKG
* ---------------------------
* It can be beneficial to create packages outside of the RIOT tree. For example
* if one is working on new packages that aren't ready to be committed to
* upstream or if an application needs its own unique packages. For this, one
* can use the `EXTERNAL_PKG_DIRS` make variable. It works similar to the way
* [external modules](src/creating-modules.html#modules-outside-of-riotbase) are
* handled. In your application's Makefile, in addition to adding the package
* name to `USEPKG` as shown above, add the path to a folder that contains your
* external packages:
*
* ~~~~~~~~ {.mk}
* EXTERNAL_PKG_DIRS += <PATH_TO_FOLDER_CONTAINING_PACKAGES>
* ~~~~~~~~
*
* The path is allowed to be relative to the application's directory.
*
* ***NOTE:*** The name of an external package must be unique (both in regard to
* other external packages, as well to native RIOT packages). Additionally, the
* directory containing the packages must match the package name, e.g. package
* `foo`must be located in `<PATH_IN_EXTERNAL_PKG_DIRS>/foo`.
*
* An example can be found in
* [`tests/external_pkg_dirs`](https://github.com/RIOT-OS/RIOT/tree/master/tests/external_pkg_dirs)
*
* RIOT welcomes new and useful packages. If you'd like to share your work,
* consider [contributing](https://github.com/RIOT-OS/RIOT/tree/master/CONTRIBUTING.md).
*
* @}
*/

View File

@ -219,6 +219,19 @@ static ssize_t _write(vfs_file_t *filp, const void *src, size_t nbytes)
return (ssize_t)bw;
}
static int _fsync(vfs_file_t *filp)
{
fatfs_file_desc_t *fd = _get_fatfs_file_desc(filp);
FRESULT res = f_sync(&fd->file);
if (res != FR_OK) {
return fatfs_err_to_errno(res);
}
return 0;
}
static ssize_t _read(vfs_file_t *filp, void *dest, size_t nbytes)
{
fatfs_file_desc_t *fd = _get_fatfs_file_desc(filp);
@ -469,6 +482,7 @@ static const vfs_file_ops_t fatfs_file_ops = {
.write = _write,
.lseek = _lseek,
.fstat = _fstat,
.fsync = _fsync,
};
static const vfs_dir_ops_t fatfs_dir_ops = {

4
pkg/fido2_tests/Kconfig Normal file
View File

@ -0,0 +1,4 @@
config PACKAGE_FIDO2_TESTS
bool "FIDO2 tests"
help
Test suite for FIDO2, U2F, and other security key functions.

View File

@ -377,6 +377,22 @@ static off_t _lseek(vfs_file_t *filp, off_t off, int whence)
return littlefs_err_to_errno(ret);
}
static int _fsync(vfs_file_t *filp)
{
littlefs_desc_t *fs = filp->mp->private_data;
lfs_file_t *fp = _get_lfs_file(filp);
mutex_lock(&fs->lock);
DEBUG("littlefs: fsync: filp=%p, fp=%p\n",
(void *)filp, (void *)fp);
int ret = lfs_file_sync(&fs->fs, fp);
mutex_unlock(&fs->lock);
return littlefs_err_to_errno(ret);
}
static int _stat(vfs_mount_t *mountp, const char *restrict path, struct stat *restrict buf)
{
littlefs_desc_t *fs = mountp->private_data;
@ -519,6 +535,7 @@ static const vfs_file_ops_t littlefs_file_ops = {
.read = _read,
.write = _write,
.lseek = _lseek,
.fsync = _fsync,
};
static const vfs_dir_ops_t littlefs_dir_ops = {

View File

@ -383,6 +383,22 @@ static off_t _lseek(vfs_file_t *filp, off_t off, int whence)
return littlefs_err_to_errno(ret);
}
static int _fsync(vfs_file_t *filp)
{
littlefs2_desc_t *fs = filp->mp->private_data;
lfs_file_t *fp = _get_lfs_file(filp);
mutex_lock(&fs->lock);
DEBUG("littlefs: fsync: filp=%p, fp=%p\n",
(void *)filp, (void *)fp);
int ret = lfs_file_sync(&fs->fs, fp);
mutex_unlock(&fs->lock);
return littlefs_err_to_errno(ret);
}
static int _stat(vfs_mount_t *mountp, const char *restrict path, struct stat *restrict buf)
{
littlefs2_desc_t *fs = mountp->private_data;
@ -525,6 +541,7 @@ static const vfs_file_ops_t littlefs_file_ops = {
.read = _read,
.write = _write,
.lseek = _lseek,
.fsync = _fsync,
};
static const vfs_dir_ops_t littlefs_dir_ops = {

View File

@ -23,7 +23,7 @@ else
CFLAGS += -Wno-unused-but-set-variable
endif
IGNORE := nimble_autoconn_% nimble_phy_% nimble_adv_ext
IGNORE := nimble_autoconn_% nimble_phy_% nimble_%_ext
SUBMODS := $(filter-out $(IGNORE),$(filter nimble_%,$(USEMODULE)))
.PHONY: all

View File

@ -12,6 +12,15 @@ USEMODULE += nimble_riot_contrib
# RIOT port
USEMODULE += nimble_porting_nimble
# Pull in dependencies based on used features
ifneq (,$(filter ble_phy_coded,$(FEATURES_USED)))
USEMODULE += nimble_phy_coded
endif
ifneq (,$(filter ble_phy_2mbit,$(FEATURES_USED)))
USEMODULE += nimble_phy_2mbit
endif
# NOTE: this dependency depends on inclusion order, for it to work properly
# mynewt-core should be selected as nimble backend as early as possible,
# i.e. at the application level.
@ -56,6 +65,10 @@ ifneq (,$(filter nimble_autoadv,$(USEMODULE)))
USEMODULE += bluetil_ad
endif
ifneq (,$(filter nimble_autoconn_ext,$(USEMODULE)))
USEMODULE += nimble_netif_ext
endif
ifneq (,$(filter nimble_autoconn_%,$(USEMODULE)))
USEMODULE += nimble_autoconn
endif
@ -67,10 +80,6 @@ ifneq (,$(filter nimble_autoconn,$(USEMODULE)))
USEMODULE += bluetil_ad
endif
ifneq (,$(filter nimble_phy_%,$(USEMODULE)))
USEMODULE += nimble_adv_ext
endif
ifneq (,$(filter nimble_phy_2mbit,$(USEMODULE)))
FEATURES_REQUIRED += ble_phy_2mbit
endif
@ -79,6 +88,11 @@ ifneq (,$(filter nimble_phy_coded,$(USEMODULE)))
FEATURES_REQUIRED += ble_phy_coded
endif
ifneq (,$(filter nimble_rpble_ext,$(USEMODULE)))
USEMODULE += nimble_rpble
USEMODULE += nimble_netif_ext
endif
ifneq (,$(filter nimble_rpble,$(USEMODULE)))
USEMODULE += gnrc_rpl
USEMODULE += nimble_netif
@ -92,12 +106,22 @@ ifneq (,$(filter nimble_scanlist,$(USEMODULE)))
USEMODULE += ztimer_usec
endif
ifneq (,$(filter nimble_statconn_ext,$(USEMODULE)))
USEMODULE += nimble_statconn
USEMODULE += nimble_netif_ext
endif
ifneq (,$(filter nimble_statconn,$(USEMODULE)))
USEMODULE += random
USEMODULE += nimble_netif
USEMODULE += nimble_addr
endif
ifneq (,$(filter nimble_netif_ext,$(USEMODULE)))
USEMODULE += nimble_netif
USEMODULE += nimble_adv_ext
endif
ifneq (,$(filter nimble_netif,$(USEMODULE)))
FEATURES_REQUIRED += ble_nimble_netif
USEMODULE += random

View File

@ -26,6 +26,14 @@ ifneq (,$(filter nimble_controller,$(USEMODULE)))
ifneq (,$(filter nimble_drivers_nrf5x,$(USEMODULE)))
INCLUDES += $(NIMIBASE)/nimble/drivers/$(CPU_FAM)/include
endif
# Enable additional PHY modes if requested by the build
ifneq (,$(filter ble_phy_2mbit,$(FEATURES_USED)))
CFLAGS += -DMYNEWT_VAL_BLE_LL_CFG_FEAT_LE_2M_PHY=1
endif
ifneq (,$(filter ble_phy_coded,$(FEATURES_USED)))
CFLAGS += -DMYNEWT_VAL_BLE_LL_CFG_FEAT_LE_CODED_PHY=1
endif
endif
# include nimble host headers
@ -94,18 +102,6 @@ ifneq (,$(filter nimble_adv_ext,$(USEMODULE)))
endif
endif
ifneq (,$(filter nimble_phy_2mbit,$(USEMODULE)))
ifneq (,$(filter nimble_controller,$(USEMODULE)))
CFLAGS += -DMYNEWT_VAL_BLE_LL_CFG_FEAT_LE_2M_PHY=1
endif
endif
ifneq (,$(filter nimble_phy_coded,$(USEMODULE)))
ifneq (,$(filter nimble_controller,$(USEMODULE)))
CFLAGS += -DMYNEWT_VAL_BLE_LL_CFG_FEAT_LE_CODED_PHY=1
endif
endif
ifneq (,$(filter nimble_netif,$(USEMODULE)))
INCLUDES += -I$(RIOTPKG)/nimble/netif/include
@ -135,6 +131,17 @@ ifneq (,$(filter nimble_netif,$(USEMODULE)))
CFLAGS += -DMYNEWT_VAL_BLE_LL_CONN_INIT_SLOTS=1
CFLAGS += -DMYNEWT_VAL_BLE_LL_CFG_FEAT_DATA_LEN_EXT=1
endif
else
ifneq (,$(filter stdio_nimble,$(USEMODULE)))
# the maximum fragment size that we can receive. For maximum efficiency this
# should be equal to the maximum configured link layer packet size.
# WARNING: this value MUST never be larger than MYNEWT_VAL_BLE_LL_MAX_PKT_SIZE
CFLAGS += -DMYNEWT_VAL_BLE_L2CAP_COC_MPS=251
# in order to fit a 251 byte COC data segment into a single mbuf buffer, the
# used block size must be at least 297 byte (251 data + 48 overhead)
CFLAGS += -DMYNEWT_VAL_MSYS_1_BLOCK_SIZE="(MYNEWT_VAL_BLE_L2CAP_COC_MPS + 48)"
endif
endif
ifneq (,$(filter nimble_rpble,$(USEMODULE)))

View File

@ -131,29 +131,31 @@ enum {
*/
typedef struct {
/** amount of time spend in scanning mode [in ms] */
uint32_t period_scan;
uint32_t period_scan_ms;
/** amount of time spend in advertising mode [in ms] */
uint32_t period_adv;
uint32_t period_adv_ms;
/** a random value from 0 to this value is added to the duration of each
* scanning and advertising period [in ms] */
uint32_t period_jitter;
uint32_t period_jitter_ms;
/** advertising interval used when in advertising mode [in ms] */
uint32_t adv_itvl;
uint32_t adv_itvl_ms;
/** scan interval applied while in scanning state [in ms] */
uint32_t scan_itvl;
uint32_t scan_itvl_ms;
/** scan window applied while in scanning state [in ms] */
uint32_t scan_win;
uint32_t scan_win_ms;
/** opening a new connection is aborted after this time [in ms] */
uint32_t conn_timeout;
uint32_t conn_timeout_ms;
/** connection interval used when opening a new connection, lower bound.
* [in ms] */
uint32_t conn_itvl_min;
uint32_t conn_itvl_min_ms;
/** connection interval, upper bound [in ms] */
uint32_t conn_itvl_max;
/** slave latency used for new connections [in ms] */
uint32_t conn_itvl_max_ms;
/** slave latency used for new connections */
uint16_t conn_latency;
/** supervision timeout used for new connections [in ms] */
uint32_t conn_super_to;
uint32_t conn_super_to_ms;
/** BLE PHY mode to use */
nimble_phy_t phy_mode;
/** node ID included in the advertising data, may be NULL */
const char *node_id;
} nimble_autoconn_params_t;

View File

@ -64,24 +64,32 @@ extern "C" {
#define NIMBLE_AUTOCONN_CONN_SVTO_MS (2500U) /* 2.5s */
#endif
/**
* @brief Default BLE PHY mode used by autoconn
*/
#ifndef NIMBLE_AUTOCONN_PHY_MODE
#define NIMBLE_AUTOCONN_PHY_MODE NIMBLE_PHY_1M
#endif
#ifndef NIMBLE_AUTOCONN_NODE_ID
#define NIMBLE_AUTOCONN_NODE_ID "RIOT-autoconn"
#endif
#ifndef NIMBLE_AUTOCONN_PARAMS
#define NIMBLE_AUTOCONN_PARAMS \
{ .period_scan = NIMBLE_AUTOCONN_PERIOD_SCAN_MS, \
.period_adv = NIMBLE_AUTOCONN_PERIOD_ADV_MS, \
.period_jitter = NIMBLE_AUTOCONN_PERIOD_JITTER_MS, \
.adv_itvl = NIMBLE_AUTOCONN_ADV_ITVL_MS, \
.scan_itvl = NIMBLE_AUTOCONN_SCAN_ITVL_MS, \
.scan_win = NIMBLE_AUTOCONN_SCAN_WIN_MS, \
.conn_timeout = NIMBLE_AUTOCONN_CONN_TIMEOUT_MS, \
.conn_itvl_min = NIMBLE_AUTOCONN_CONN_ITVL_MIN_MS, \
.conn_itvl_max = NIMBLE_AUTOCONN_CONN_ITVL_MAX_MS, \
.conn_latency = NIMBLE_AUTOCONN_CONN_LATENCY, \
.conn_super_to = NIMBLE_AUTOCONN_CONN_SVTO_MS, \
.node_id = NIMBLE_AUTOCONN_NODE_ID, }
{ .period_scan_ms = NIMBLE_AUTOCONN_PERIOD_SCAN_MS, \
.period_adv_ms = NIMBLE_AUTOCONN_PERIOD_ADV_MS, \
.period_jitter_ms = NIMBLE_AUTOCONN_PERIOD_JITTER_MS, \
.adv_itvl_ms = NIMBLE_AUTOCONN_ADV_ITVL_MS, \
.scan_itvl_ms = NIMBLE_AUTOCONN_SCAN_ITVL_MS, \
.scan_win_ms = NIMBLE_AUTOCONN_SCAN_WIN_MS, \
.conn_timeout_ms = NIMBLE_AUTOCONN_CONN_TIMEOUT_MS, \
.conn_itvl_min_ms = NIMBLE_AUTOCONN_CONN_ITVL_MIN_MS, \
.conn_itvl_max_ms = NIMBLE_AUTOCONN_CONN_ITVL_MAX_MS, \
.conn_latency = NIMBLE_AUTOCONN_CONN_LATENCY, \
.conn_super_to_ms = NIMBLE_AUTOCONN_CONN_SVTO_MS, \
.phy_mode = NIMBLE_AUTOCONN_PHY_MODE, \
.node_id = NIMBLE_AUTOCONN_NODE_ID, }
#endif
/**@}*/

View File

@ -55,9 +55,8 @@ static volatile uint8_t _enabled = 0;
static bluetil_ad_t _ad;
static uint8_t _ad_buf[BLE_HS_ADV_MAX_SZ];
static struct ble_gap_adv_params _adv_params;
static struct ble_gap_conn_params _conn_params;
static uint32_t _conn_timeout;
static nimble_netif_accept_cfg_t _accept_params;
static nimble_netif_connect_cfg_t _conn_params;
static struct ble_npl_callout _state_evt;
static ble_npl_time_t _timeout_adv_period;
@ -77,7 +76,7 @@ static void _on_state_change(struct ble_npl_event *ev)
/* stop scanning */
nimble_scanner_stop();
/* start advertising/accepting */
int res = nimble_netif_accept(_ad.buf, _ad.pos, &_adv_params);
int res = nimble_netif_accept(_ad.buf, _ad.pos, &_accept_params);
assert((res == 0) || (res == -ENOMEM));
(void)res;
@ -137,11 +136,18 @@ static void _on_scan_evt(uint8_t type, const ble_addr_t *addr,
{
(void)info;
#if IS_USED(MODULE_NIMBLE_AUTOCONN_EXT)
if ((type != (NIMBLE_SCANNER_EXT_ADV | BLE_HCI_ADV_CONN_MASK)) ||
(info->status != BLE_GAP_EXT_ADV_DATA_STATUS_COMPLETE)) {
return;
}
#else
/* we are only interested in ADV_IND packets, the rest can be dropped right
* away */
if (type != BLE_HCI_ADV_RPT_EVTYPE_ADV_IND) {
return;
}
#endif
bluetil_ad_t ad = {
.buf = (uint8_t *)ad_buf,
@ -157,7 +163,7 @@ static void _on_scan_evt(uint8_t type, const ble_addr_t *addr,
nimble_scanner_stop();
DEBUG("[autoconn] SCAN success, initiating connection\n");
_state = STATE_CONN;
int res = nimble_netif_connect(addr, &_conn_params, _conn_timeout);
int res = nimble_netif_connect(addr, &_conn_params);
assert(res >= 0);
(void)res;
}
@ -271,47 +277,66 @@ int nimble_autoconn_update(const nimble_autoconn_params_t *params,
}
/* scan and advertising period configuration */
ble_npl_time_ms_to_ticks(params->period_adv, &_timeout_adv_period);
ble_npl_time_ms_to_ticks(params->period_scan, &_timeout_scan_period);
ble_npl_time_ms_to_ticks(params->period_jitter, &_period_jitter);
ble_npl_time_ms_to_ticks(params->period_adv_ms, &_timeout_adv_period);
ble_npl_time_ms_to_ticks(params->period_scan_ms, &_timeout_scan_period);
ble_npl_time_ms_to_ticks(params->period_jitter_ms, &_period_jitter);
/* populate the connection parameters */
_conn_params.scan_itvl = BLE_GAP_SCAN_ITVL_MS(params->scan_win);
_conn_params.scan_window = _conn_params.scan_itvl;
_conn_params.itvl_min = BLE_GAP_CONN_ITVL_MS(params->conn_itvl_min);
_conn_params.itvl_max = BLE_GAP_CONN_ITVL_MS(params->conn_itvl_max);
_conn_params.latency = 0;
_conn_params.supervision_timeout = BLE_GAP_SUPERVISION_TIMEOUT_MS(
params->conn_super_to);
_conn_params.min_ce_len = 0;
_conn_params.max_ce_len = 0;
_conn_timeout = params->conn_timeout;
memset(&_conn_params, 0, sizeof(_conn_params));
_conn_params.scan_itvl_ms = params->scan_itvl_ms;
_conn_params.scan_window_ms = params->scan_win_ms;
_conn_params.conn_itvl_min_ms = params->conn_itvl_min_ms;
_conn_params.conn_itvl_max_ms = params->conn_itvl_max_ms;
_conn_params.conn_supervision_timeout_ms = params->conn_super_to_ms;
_conn_params.conn_slave_latency = params->conn_latency;
_conn_params.timeout_ms = params->conn_timeout_ms;
#if IS_USED(MODULE_NIMBLE_AUTOCONN_EXT)
_conn_params.phy_mode = params->phy_mode;
#else
_conn_params.phy_mode = NIMBLE_PHY_1M;
#endif
_conn_params.own_addr_type = nimble_riot_own_addr_type;
/* we use the same values to updated existing connections */
struct ble_gap_upd_params conn_update_params;
conn_update_params.itvl_min = _conn_params.itvl_min;
conn_update_params.itvl_max = _conn_params.itvl_max;
conn_update_params.latency = _conn_params.latency;
conn_update_params.supervision_timeout = _conn_params.supervision_timeout;
conn_update_params.itvl_min = BLE_GAP_CONN_ITVL_MS(params->conn_itvl_min_ms);
conn_update_params.itvl_max = BLE_GAP_CONN_ITVL_MS(params->conn_itvl_max_ms);
conn_update_params.latency = params->conn_latency;
conn_update_params.supervision_timeout =
BLE_GAP_SUPERVISION_TIMEOUT_MS(params->conn_super_to_ms);
conn_update_params.min_ce_len = 0;
conn_update_params.max_ce_len = 0;
/* calculate the used scan parameters */
nimble_scanner_cfg_t scan_params;
scan_params.itvl_ms = params->scan_itvl;
scan_params.win_ms = params->scan_win;
scan_params.flags = NIMBLE_SCANNER_PASSIVE
| NIMBLE_SCANNER_FILTER_DUPS
| NIMBLE_SCANNER_PHY_1M;
scan_params.itvl_ms = params->scan_itvl_ms;
scan_params.win_ms = params->scan_win_ms;
scan_params.flags = (NIMBLE_SCANNER_PASSIVE | NIMBLE_SCANNER_FILTER_DUPS);
#if IS_USED(MODULE_NIMBLE_AUTOCONN_EXT) && IS_USED(MODULE_NIMBLE_PHY_CODED)
if (params->phy_mode == NIMBLE_PHY_CODED) {
scan_params.flags |= NIMBLE_SCANNER_PHY_CODED;
}
else {
scan_params.flags |= NIMBLE_SCANNER_PHY_1M;
}
#else
scan_params.flags |= NIMBLE_SCANNER_PHY_1M;
#endif
/* set the advertising parameters used */
_adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
_adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
_adv_params.itvl_min = BLE_GAP_ADV_ITVL_MS(params->adv_itvl);
_adv_params.itvl_max = _adv_params.itvl_min;
_adv_params.channel_map = 0;
_adv_params.filter_policy = 0;
_adv_params.high_duty_cycle = 0;
memset(&_accept_params, 0, sizeof(_accept_params));
#if IS_USED(MODULE_NIMBLE_AUTOCONN_EXT)
_accept_params.flags = 0;
_accept_params.primary_phy = params->phy_mode;
_accept_params.secondary_phy = params->phy_mode;
#else
_accept_params.flags = NIMBLE_NETIF_FLAG_LEGACY;
_accept_params.primary_phy = NIMBLE_PHY_1M;
_accept_params.secondary_phy = NIMBLE_PHY_1M;
#endif
_accept_params.adv_itvl_ms = params->adv_itvl_ms;
_accept_params.timeout_ms = BLE_HS_FOREVER;
_accept_params.own_addr_type = nimble_riot_own_addr_type;
/* initialize the advertising data that will be used */
if (adlen > 0) {

View File

@ -69,6 +69,20 @@ extern "C" {
#define NIMBLE_HOST_STACKSIZE (THREAD_STACKSIZE_DEFAULT)
#endif
/**
* @brief BLE PHY modes
*/
typedef enum {
NIMBLE_PHY_INVALID, /**< PHY mode invalid */
NIMBLE_PHY_1M, /**< legacy 1Mbit PHY mode (always supported) */
#if IS_USED(MODULE_NIMBLE_PHY_2MBIT)
NIMBLE_PHY_2M, /**< 2Mbit PHY mode */
#endif
#if IS_USED(MODULE_NIMBLE_PHY_CODED)
NIMBLE_PHY_CODED, /**< Coded (long range) PHY mode */
#endif
} nimble_phy_t;
/**
* @brief Export our own address type for later usage
*/

View File

@ -176,6 +176,13 @@ void nimble_riot_init(void)
nimble_autoconn_enable();
#endif
#ifdef MODULE_STDIO_NIMBLE
extern void stdio_nimble_init(void);
/* stdio_nimble_init() needs to be called after nimble stack initialization
* and before nimble_autoadv_init() */
stdio_nimble_init();
#endif
#ifdef MODULE_NIMBLE_AUTOADV
extern void nimble_autoadv_init(void);
nimble_autoadv_init();

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2019 Freie Universität Berlin
* Copyright (C) 2018-2021 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -70,6 +70,7 @@
#include <errno.h>
#include "net/ble.h"
#include "nimble_riot.h"
#include "host/ble_hs.h"
@ -103,6 +104,46 @@ extern "C" {
#define NIMBLE_NETIF_MTU (1280U)
#endif
/**
* @brief Flags for enabling legacy advertisement and high-duty cycle mode
* when accepting incoming connections
*/
enum {
NIMBLE_NETIF_FLAG_LEGACY = 0x01, /**< use legacy advertising mode */
NIMBLE_NETIF_FLAG_HD_MODE = 0x02, /**< use high duty cycle mode, only
* valid for direct advertising */
};
/**
* @brief Parameter set used to configure accepting connections (advertising)
*/
typedef struct {
uint8_t flags; /**< flags */
uint8_t channel_map; /**< specify custom channel map */
uint8_t own_addr_type; /**< specify our own address type to use */
int8_t tx_power; /**< specify TX power to be used */
uint32_t adv_itvl_ms; /**< advertising interval [ms] */
uint32_t timeout_ms; /**< stop accepting after this time [ms] */
nimble_phy_t primary_phy; /**< primary PHY mode */
nimble_phy_t secondary_phy; /**< secondary PHY mode */
} nimble_netif_accept_cfg_t;
/**
* @brief Parameter set used to configure connection initiation
*/
typedef struct {
uint16_t scan_itvl_ms; /**< scan interval [ms] */
uint16_t scan_window_ms; /**< scan window [ms] */
uint16_t conn_itvl_min_ms; /**< connection interval, lower bound [ms] */
uint16_t conn_itvl_max_ms; /**< connection interval, upper bound [ms] */
uint16_t conn_supervision_timeout_ms; /**< supervision timeout [ms] */
uint16_t conn_slave_latency;/**< slave latency */
uint32_t timeout_ms; /**< abort connection initiation after this time
* [ms] */
uint8_t phy_mode; /**< PHY mode used for the connection */
uint8_t own_addr_type; /**< specify our own address type to use */
} nimble_netif_connect_cfg_t;
/**
* @brief Set to > 0 to enforce different connection intervals for each of the
* nodes BLE connections
@ -197,19 +238,18 @@ void nimble_netif_eventcb(nimble_netif_eventcb_t cb);
*
* @param[in] addr address of the advertising BLE slave, in the NimBLE
* addr format (little endian)
* @param[in] conn_params connection (timing) parameters, set to NULL to use
* NimBLEs default parameters
* @param[in] timeout connect timeout [in ms]
* @param[in] cfg connection parameters
*
* @return the used connection handle on success
* @return -EBUSY if already connected to the given address or if
* a connection setup procedure is in progress
* @return -EBUSY if already connected to the given address or if a connection
* setup procedure is in progress
* @return -ENOMEM if no connection context memory is available
* @return -ECANCELED if unable to find valid connection interval
* @return -EINVAL if unable to apply given PHY mode
* @return -EIO on all other NimBLE errors
*/
int nimble_netif_connect(const ble_addr_t *addr,
struct ble_gap_conn_params *conn_params,
uint32_t timeout);
const nimble_netif_connect_cfg_t *cfg);
/**
* @brief Close the connection with the given handle
@ -219,6 +259,7 @@ int nimble_netif_connect(const ble_addr_t *addr,
* @return 0 on success
* @return -EINVAL if the handle is invalid
* @return -ENOTCONN if context for given handle is not connected
* @return -EIO on all other NimBLE errors
*/
int nimble_netif_close(int handle);
@ -227,36 +268,39 @@ int nimble_netif_close(int handle);
*
* @param[in] ad advertising data (in BLE AD format)
* @param[in] ad_len length of @p ad in bytes
* @param[in] adv_params advertising (timing) parameters to use
* @param[in] cfg advertising parameters to use
*
* @return 0 on success
* @return -EALREADY if already advertising
* @return -ENOMEM on insufficient connection memory
* @return -EINVAL on invalid configuration parameters
* @return -ECANCELED on other errors
*/
int nimble_netif_accept(const uint8_t *ad, size_t ad_len,
const struct ble_gap_adv_params *adv_params);
const nimble_netif_accept_cfg_t *cfg);
/**
* @brief Wait for an incoming connection from a specific peer, sending
* directed advertisements (IND_DIR)
* directed advertisements
*
* @param[in] addr BLE address of the target peer
* @param[in] timeout_ms stop advertising after this time (in ms), set to
* BLE_HS_FOREVER to disable timeout
* @param[in] adv_params advertising (timing) parameters to use
* @param[in] cfg advertising parameters to use
*
* @return 0 on success
* @return -EALREADY if already advertising
* @return -ENOMEM on insufficient connection memory
* @return -EINVAL on invalid configuration parameters
* @return -ECANCELED on other errors
*/
int nimble_netif_accept_direct(const ble_addr_t *addr, uint32_t timeout_ms,
const struct ble_gap_adv_params *adv_params);
int nimble_netif_accept_direct(const ble_addr_t *addr,
const nimble_netif_accept_cfg_t *cfg);
/**
* @brief Stop accepting incoming connections (stop advertising)
* *
* @return 0 on success
* @return -EALREADY if not currently advertising
* @return -EIO on other NimBLE errors
*/
int nimble_netif_accept_stop(void);

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018-2019 Freie Universität Berlin
* Copyright (C) 2018-2021 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -55,6 +55,8 @@
#define NIMBLE_NETIF_PRIO GNRC_NETIF_PRIO
#endif
#define EXT_ADV_INST 0
/* thread flag used for signaling transmit readiness */
#define FLAG_TX_UNSTALLED (1u << 13)
#define FLAG_TX_NOTCONN (1u << 12)
@ -543,10 +545,14 @@ static int _on_gap_slave_evt(struct ble_gap_event *event, void *arg)
/* nothing to do here */
break;
case BLE_GAP_EVENT_ADV_COMPLETE: {
uint8_t addr[BLE_ADDR_LEN];
nimble_netif_conn_free(handle, addr);
_notify(handle, NIMBLE_NETIF_ACCEPT_STOP, addr);
if (conn->state == NIMBLE_NETIF_ADV) {
uint8_t addr[BLE_ADDR_LEN];
nimble_netif_conn_free(handle, addr);
_notify(handle, NIMBLE_NETIF_ACCEPT_STOP, addr);
}
}
case BLE_GAP_EVENT_PHY_UPDATE_COMPLETE:
break;
default:
break;
}
@ -577,14 +583,10 @@ void nimble_netif_eventcb(nimble_netif_eventcb_t cb)
}
int nimble_netif_connect(const ble_addr_t *addr,
struct ble_gap_conn_params *conn_params,
uint32_t timeout)
const nimble_netif_connect_cfg_t *params)
{
assert(addr);
assert(_eventcb);
uint16_t itvl_min = 0;
uint16_t itvl_max = 0;
assert(params);
/* the netif_conn module expects addresses in network byte order */
uint8_t addrn[BLE_ADDR_LEN];
@ -602,33 +604,63 @@ int nimble_netif_connect(const ble_addr_t *addr,
return -ENOMEM;
}
if ((conn_params != NULL)
&& (conn_params->itvl_min != conn_params->itvl_max)) {
/* we need to save the min/max intervals in order to restore them
* later on */
itvl_min = conn_params->itvl_min;
itvl_max = conn_params->itvl_max;
uint16_t itvl = nimble_netif_conn_gen_itvl(itvl_min, itvl_max);
if (itvl == 0) {
return -ECANCELED;
}
conn_params->itvl_min = itvl;
conn_params->itvl_max = itvl;
/* generate connection interval */
uint16_t itvl = params->conn_itvl_min_ms;
if (params->conn_itvl_min_ms < params->conn_itvl_max_ms) {
itvl = nimble_netif_conn_gen_itvl(params->conn_itvl_min_ms,
params->conn_itvl_max_ms);
}
if (itvl == 0) {
nimble_netif_conn_free(handle, NULL);
return -ECANCELED;
}
int res = ble_gap_connect(nimble_riot_own_addr_type, addr, timeout,
conn_params, _on_gap_master_evt, (void *)handle);
assert(res == 0);
(void)res;
struct ble_gap_conn_params p = {
.scan_itvl = BLE_GAP_SCAN_ITVL_MS(params->scan_itvl_ms),
.scan_window = BLE_GAP_SCAN_WIN_MS(params->scan_window_ms),
.itvl_min = BLE_GAP_CONN_ITVL_MS(itvl),
.itvl_max = BLE_GAP_CONN_ITVL_MS(itvl),
.latency = params->conn_slave_latency,
.supervision_timeout = BLE_GAP_SUPERVISION_TIMEOUT_MS(
params->conn_supervision_timeout_ms),
.min_ce_len = 0,
.max_ce_len = 0,
};
if (itvl_min != itvl_max) {
conn_params->itvl_min = itvl_min;
conn_params->itvl_max = itvl_max;
#if MYNEWT_VAL_BLE_EXT_ADV
uint8_t phy_mask;
if (params->phy_mode == NIMBLE_PHY_1M) {
phy_mask = BLE_GAP_LE_PHY_1M_MASK;
}
#if IS_USED(MODULE_NIMBLE_PHY_2MBIT)
else if (params->phy_mode == NIMBLE_PHY_2M) {
phy_mask = (BLE_GAP_LE_PHY_1M_MASK | BLE_GAP_LE_PHY_2M_MASK);
}
#endif
#if IS_USED(MODULE_NIMBLE_PHY_CODED)
else if (params->phy_mode == NIMBLE_PHY_CODED) {
phy_mask = BLE_GAP_LE_PHY_CODED_MASK;
}
#endif
else {
return -EINVAL;
}
int res = ble_gap_ext_connect(params->own_addr_type, addr,
params->timeout_ms, phy_mask, &p, &p, &p,
_on_gap_master_evt, (void *)handle);
#else
uint32_t timeout = (params->timeout_ms == 0) ? BLE_HS_FOREVER
: params->timeout_ms;
int res = ble_gap_connect(params->own_addr_type, addr,
timeout, &p,
_on_gap_master_evt, (void *)handle);
#endif
if (res != 0) {
return -EIO;
}
_notify(handle, NIMBLE_NETIF_INIT_MASTER, addrn);
return handle;
}
@ -642,63 +674,168 @@ int nimble_netif_close(int handle)
return -ENOTCONN;
}
int res = ble_gap_terminate(ble_l2cap_get_conn_handle(conn->coc),
BLE_ERR_REM_USER_CONN_TERM);
assert(res == 0);
(void)res;
int res = ble_gap_terminate(conn->gaphandle, BLE_ERR_REM_USER_CONN_TERM);
if (res != 0) {
return -EIO;
}
return 0;
}
static int _accept(const uint8_t *ad, size_t ad_len, const ble_addr_t *addr,
uint32_t timeout,
const struct ble_gap_adv_params *adv_params)
#if MYNEWT_VAL_BLE_EXT_ADV
static int _get_phy_hci(uint8_t mode)
{
assert(adv_params);
switch (mode) {
case NIMBLE_PHY_1M:
return BLE_HCI_LE_PHY_1M;
#if IS_USED(MODULE_NIMBLE_PHY_2MBIT)
case NIMBLE_PHY_2M:
return BLE_HCI_LE_PHY_2M;
#endif
#if IS_USED(MODULE_NIMBLE_PHY_CODED)
case NIMBLE_PHY_CODED:
return BLE_HCI_LE_PHY_CODED;
#endif
default:
return -1;
}
}
#endif
static int _accept(const uint8_t *ad, size_t ad_len, const ble_addr_t *addr,
const nimble_netif_accept_cfg_t *params)
{
int handle;
int res;
(void)res;
assert(params);
/* allocate a connection context for incoming connections */
handle = nimble_netif_conn_start_adv();
if (handle < 0) {
return handle;
}
/* set advertisement data */
if (ad != NULL) {
res = ble_gap_adv_set_data(ad, (int)ad_len);
assert(res == 0);
}
/* remember address if applicable */
if (addr) {
nimble_netif_conn_t *conn = nimble_netif_conn_get(handle);
bluetil_addr_swapped_cp(addr->val, conn->addr);
}
/* remember context and start advertising */
res = ble_gap_adv_start(nimble_riot_own_addr_type, addr, timeout,
adv_params, _on_gap_slave_evt, (void *)handle);
assert(res == 0);
#if MYNEWT_VAL_BLE_EXT_ADV
struct ble_gap_ext_adv_params p;
memset(&p, 0, sizeof(p));
/* figure out PHY modes */
int phy_pri = _get_phy_hci(params->primary_phy);
int phy_sec = _get_phy_hci(params->secondary_phy);
if ((phy_pri < 0) || (phy_sec < 0)) {
nimble_netif_conn_free(handle, NULL);
return -EINVAL;
}
/* the 2M PHY is not allowed as primary phy, we need to used the 1M PHY
* instead. This is for convenience so uses may define 2M as primary PHY */
if (phy_pri == BLE_HCI_LE_PHY_2M) {
phy_pri = BLE_HCI_LE_PHY_1M;
}
if (addr != NULL) {
p.directed = 1;
memcpy(&p.peer, addr, sizeof(p.peer));
if (params->flags & NIMBLE_NETIF_FLAG_HD_MODE) {
p.high_duty_directed = 1;
}
}
else {
p.connectable = 1;
}
if (params->flags & NIMBLE_NETIF_FLAG_LEGACY) {
p.legacy_pdu = 1;
/* legacy connectable PDUs are always scannable */
p.scannable = 1;
}
p.itvl_min = BLE_GAP_ADV_ITVL_MS(params->adv_itvl_ms);
p.itvl_max = BLE_GAP_ADV_ITVL_MS(params->adv_itvl_ms);
p.channel_map = params->channel_map;
p.own_addr_type = params->own_addr_type;
p.primary_phy = (uint8_t)phy_pri;
p.secondary_phy = (uint8_t)phy_sec;
p.tx_power = params->tx_power;
res = ble_gap_ext_adv_configure(EXT_ADV_INST, &p, NULL,
_on_gap_slave_evt, (void *)handle);
if (res != 0) {
nimble_netif_conn_free(handle, NULL);
return -EINVAL;
}
if (ad != NULL) {
struct os_mbuf *data = os_msys_get_pkthdr(ad_len, 0);
if (data == NULL) {
nimble_netif_conn_free(handle, NULL);
return -ENOMEM;
}
res = os_mbuf_append(data, ad, ad_len);
if (res != 0) {
os_mbuf_free_chain(data);
nimble_netif_conn_free(handle, NULL);
return -ENOMEM;
}
res = ble_gap_ext_adv_set_data(EXT_ADV_INST, data);
assert(res == 0);
}
res = ble_gap_ext_adv_start(EXT_ADV_INST, params->timeout_ms / 10, 0);
#else
uint8_t mode = (addr != NULL) ? BLE_GAP_CONN_MODE_DIR
: BLE_GAP_CONN_MODE_UND;
struct ble_gap_adv_params p = {
.conn_mode = mode,
.disc_mode = BLE_GAP_DISC_MODE_GEN,
.itvl_min = BLE_GAP_ADV_ITVL_MS(params->adv_itvl_ms),
.itvl_max = BLE_GAP_ADV_ITVL_MS(params->adv_itvl_ms),
.channel_map = params->channel_map,
.filter_policy = 0,
.high_duty_cycle = (params->flags & NIMBLE_NETIF_FLAG_HD_MODE) ? 1 : 0,
};
/* set advertisement data, if applicable */
if (ad != NULL) {
res = ble_gap_adv_set_data(ad, (int)ad_len);
if (res != 0) {
nimble_netif_conn_free(handle, NULL);
return -EINVAL;
}
}
/* start advertising */
uint32_t timeout = (params->timeout_ms == 0) ? BLE_HS_FOREVER
: params->timeout_ms;
res = ble_gap_adv_start(params->own_addr_type, addr, timeout,
&p, _on_gap_slave_evt, (void *)handle);
#endif
if (res != 0) {
nimble_netif_conn_free(handle, NULL);
return -ECANCELED;
}
_notify(handle, NIMBLE_NETIF_ACCEPTING, _netif.l2addr);
return 0;
}
int nimble_netif_accept(const uint8_t *ad, size_t ad_len,
const struct ble_gap_adv_params *adv_params)
const nimble_netif_accept_cfg_t *params)
{
assert(ad != NULL);
assert(ad_len > 0);
return _accept(ad, ad_len, NULL, BLE_HS_FOREVER, adv_params);
return _accept(ad, ad_len, NULL, params);
}
int nimble_netif_accept_direct(const ble_addr_t *addr, uint32_t timeout,
const struct ble_gap_adv_params *adv_params)
int nimble_netif_accept_direct(const ble_addr_t *addr,
const nimble_netif_accept_cfg_t *params)
{
return _accept(NULL, 0, addr, timeout, adv_params);
assert(addr);
return _accept(NULL, 0, addr, params);
}
int nimble_netif_accept_stop(void)
@ -708,9 +845,15 @@ int nimble_netif_accept_stop(void)
return -EALREADY;
}
int res = ble_gap_adv_stop();
assert(res == 0);
(void)res;
int res;
#if MYNEWT_VAL_BLE_EXT_ADV
res = ble_gap_ext_adv_stop(EXT_ADV_INST);
#else
res = ble_gap_adv_stop();
#endif
if (res != 0) {
return -EIO;
}
nimble_netif_conn_free(handle, NULL);
_notify(handle, NIMBLE_NETIF_ACCEPT_STOP, _netif.l2addr);

View File

@ -113,6 +113,7 @@ typedef struct {
uint16_t conn_latency; /**< used slave latency for parent connection */
uint32_t conn_super_to_ms; /**< used supervision timeout for parent
* connection, in ms */
nimble_phy_t phy_mode; /**< BLE PHY mode to use */
uint32_t eval_itvl_min_ms; /**< amount of time a node searches for
* potential parents, lower bound in ms */
uint32_t eval_itvl_max_ms; /**< amount of time a node searches for

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 Freie Universität Berlin
* Copyright (C) 2019-2021 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -69,6 +69,13 @@ extern "C" {
#define NIMBLE_RPBLE_EVAL_ITVL_MAX_MS 13000U
#endif
/**
* @brief Default BLE PHY mode used by rpble
*/
#ifndef NIMBLE_RPBLE_PHY_MODE
#define NIMBLE_RPBLE_PHY_MODE NIMBLE_PHY_1M
#endif
#ifndef NIMBLE_RPBLE_PARAMS
#define NIMBLE_RPBLE_PARAMS \
{ .scan_itvl_ms = NIMBLE_RPBLE_SCAN_ITVL_MS, \
@ -81,6 +88,7 @@ extern "C" {
.conn_itvl_max_ms = NIMBLE_RPBLE_CONN_ITVL_MAX_MS, \
.conn_latency = NIMBLE_RPBLE_CONN_LATENCY, \
.conn_super_to_ms = NIMBLE_RPBLE_CONN_SUPER_TO_MS, \
.phy_mode = NIMBLE_RPBLE_PHY_MODE, \
.eval_itvl_min_ms = NIMBLE_RPBLE_EVAL_ITVL_MIN_MS, \
.eval_itvl_max_ms = NIMBLE_RPBLE_EVAL_ITVL_MAX_MS }
#endif

View File

@ -50,9 +50,8 @@
#define POS_FREE_SLOTS 22
/* keep the timing parameters for connections and advertisements */
static struct ble_gap_adv_params _adv_params = { 0 };
static struct ble_gap_conn_params _conn_params = { 0 };
static uint32_t _conn_scan_to; /* in ms */
static nimble_netif_accept_cfg_t _accept_params;
static nimble_netif_connect_cfg_t _conn_params;
/* local RPL context */
static nimble_rpble_ctx_t _local_rpl_ctx;
@ -107,7 +106,7 @@ static void _children_accept(void)
assert(res == BLUETIL_AD_OK);
/* start advertising this node */
res = nimble_netif_accept(ad.buf, ad.pos, &_adv_params);
res = nimble_netif_accept(ad.buf, ad.pos, &_accept_params);
assert(res == 0);
}
@ -118,10 +117,17 @@ static void _on_scan_evt(uint8_t type, const ble_addr_t *addr,
int res;
(void)info;
#if IS_USED(MODULE_NIMBLE_RPBLE_EXT)
if ((type != (NIMBLE_SCANNER_EXT_ADV | BLE_HCI_ADV_CONN_MASK)) ||
(info->status != BLE_GAP_EXT_ADV_DATA_STATUS_COMPLETE)) {
return;
}
#else
/* filter out all non-connectible advertisements */
if (type != BLE_HCI_ADV_RPT_EVTYPE_ADV_IND) {
return;
}
#endif
/* check if scanned node does actually speak rpble */
bluetil_ad_data_t sd_field;
@ -199,7 +205,7 @@ static void _parent_connect(struct ble_npl_event *ev)
}
/* try to connect to parent */
int res = nimble_netif_connect(&_psel.addr, &_conn_params, _conn_scan_to);
int res = nimble_netif_connect(&_psel.addr, &_conn_params);
if (res < 0) {
_parent_find();
return;
@ -283,19 +289,36 @@ int nimble_rpble_param_update(const nimble_rpble_cfg_t *cfg)
cfg->eval_itvl_max_ms);
ble_npl_time_ms_to_ticks(itvl, &_eval_itvl);
_adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
_adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
_adv_params.itvl_min = BLE_GAP_ADV_ITVL_MS(cfg->adv_itvl_ms);
_adv_params.itvl_max = _adv_params.itvl_min;
/* accept parameter extraction */
memset(&_accept_params, 0, sizeof(_accept_params));
#if IS_USED(MODULE_NIMBLE_RPBLE_EXT)
_accept_params.flags = 0;
_accept_params.primary_phy = cfg->phy_mode;
_accept_params.secondary_phy = cfg->phy_mode;
#else
_accept_params.flags = NIMBLE_NETIF_FLAG_LEGACY;
_accept_params.primary_phy = NIMBLE_PHY_1M;
_accept_params.secondary_phy = NIMBLE_PHY_1M;
#endif
_accept_params.adv_itvl_ms = cfg->adv_itvl_ms;
_accept_params.timeout_ms = BLE_HS_FOREVER;
_accept_params.own_addr_type = nimble_riot_own_addr_type;
_conn_params.scan_itvl = BLE_GAP_SCAN_ITVL_MS(cfg->conn_scan_itvl_ms);
_conn_params.scan_window = BLE_GAP_SCAN_WIN_MS(cfg->conn_scan_win_ms);
_conn_params.latency = cfg->conn_latency;
_conn_params.supervision_timeout =
BLE_GAP_SUPERVISION_TIMEOUT_MS(cfg->conn_super_to_ms);
_conn_params.itvl_min = BLE_GAP_CONN_ITVL_MS(cfg->conn_itvl_min_ms);
_conn_params.itvl_max = BLE_GAP_CONN_ITVL_MS(cfg->conn_itvl_max_ms);
_conn_scan_to = cfg->conn_scan_to_ms;
/* connection parameter extraction */
memset(&_conn_params, 0, sizeof(_conn_params));
_conn_params.scan_itvl_ms = cfg->conn_scan_itvl_ms;
_conn_params.scan_window_ms = cfg->conn_scan_win_ms;
_conn_params.conn_itvl_min_ms = cfg->conn_itvl_min_ms;
_conn_params.conn_itvl_max_ms = cfg->conn_itvl_max_ms;
_conn_params.conn_supervision_timeout_ms = cfg->conn_super_to_ms;
_conn_params.conn_slave_latency = cfg->conn_latency;
_conn_params.timeout_ms = cfg->conn_scan_to_ms;
#if IS_USED(MODULE_NIMBLE_RPBLE_EXT)
_conn_params.phy_mode = cfg->phy_mode;
#else
_conn_params.phy_mode = NIMBLE_PHY_1M;
#endif
_conn_params.own_addr_type = nimble_riot_own_addr_type;
/* register event callback */
nimble_netif_eventcb(_on_netif_evt);
@ -304,9 +327,18 @@ int nimble_rpble_param_update(const nimble_rpble_cfg_t *cfg)
nimble_scanner_cfg_t scan_params = { 0 };
scan_params.itvl_ms = cfg->scan_itvl_ms;
scan_params.win_ms = cfg->scan_win_ms;
scan_params.flags = NIMBLE_SCANNER_PASSIVE
| NIMBLE_SCANNER_FILTER_DUPS
| NIMBLE_SCANNER_PHY_1M;
scan_params.flags = (NIMBLE_SCANNER_PASSIVE | NIMBLE_SCANNER_FILTER_DUPS);
#if IS_USED(MODULE_NIMBLE_RPBLE_EXT) && IS_USED(MODULE_NIMBLE_PHY_CODED)
if (cfg->phy_mode == NIMBLE_PHY_CODED) {
scan_params.flags |= NIMBLE_SCANNER_PHY_CODED;
}
else {
scan_params.flags |= NIMBLE_SCANNER_PHY_1M;
}
#else
scan_params.flags |= NIMBLE_SCANNER_PHY_1M;
#endif
nimble_scanner_init(&scan_params, _on_scan_evt);
/* start to look for parents */

View File

@ -44,7 +44,9 @@ enum {
NIMBLE_SCANNER_LIMITED = 0x02, /**< do limited discovery */
NIMBLE_SCANNER_FILTER_DUPS = 0x04, /**< filter duplicates */
NIMBLE_SCANNER_PHY_1M = 0x10, /**< scan on 1Mbit PHY */
#if IS_USED(MODULE_NIMBLE_PHY_CODED)
NIMBLE_SCANNER_PHY_CODED = 0x20, /**< scan on CODED PHY */
#endif
};
/**

View File

@ -100,9 +100,12 @@ int nimble_scanner_start(void)
uint8_t limited = (_scan_flags & NIMBLE_SCANNER_LIMITED) ? 1 : 0;
const struct ble_gap_ext_disc_params *uncoded =
(_scan_flags & NIMBLE_SCANNER_PHY_1M) ? &_scan_params : NULL;
#if IS_USED(MODULE_NIMBLE_PHY_CODED)
const struct ble_gap_ext_disc_params *coded =
(_scan_flags & NIMBLE_SCANNER_PHY_CODED) ? &_scan_params : NULL;
#else
const struct ble_gap_ext_disc_params *coded = NULL;
#endif
int32_t dur = (_scan_duration == BLE_HS_FOREVER) ? 0
: _scan_duration / 10;

View File

@ -113,6 +113,21 @@ extern "C" {
#define NIMBLE_STATCONN_CONN_SUPERTO_MS (2500U)
#endif
/**
* @brief BLE PHY mode used by statconn. This value is only used if statconn
* is used in its extended mode (module `nimble_statconn_ext`)
*/
#ifndef NIMBLE_STATCONN_PHY_MODE
#define NIMBLE_STATCONN_PHY_MODE NIMBLE_PHY_1M
#endif
/**
* @brief Statconn connection parameters
*/
typedef struct {
nimble_phy_t phy_mode; /**< BLE PHY mode used for the connection */
} nimble_statconn_cfg_t;
/**
* @brief Initialize the statconn module
*
@ -138,23 +153,31 @@ void nimble_statconn_eventcb(nimble_netif_eventcb_t cb);
* connection by that master.
*
* @param[in] addr BLE address of the peer
* @param[in] cfg additional connection parameters, set to NULL to apply
* default values
*
* @return 0 if peer was successfully added
* @return -EALREADY if the peer address is already in use
* @return -ENOMEM if no empty connection slot is available
* @return -EINVAL if invalid configuration parameters are given
*/
int nimble_statconn_add_master(const uint8_t *addr);
int nimble_statconn_add_master(const uint8_t *addr,
const nimble_statconn_cfg_t *cfg);
/**
* @brief Connect to a peer (slave) with a given address as master
*
* @param[in] addr BLE address of the peer
* @param[in] cfg additional connection parameters, set to NULL to apply
* default values
*
* @return 0 if peer was successfully added
* @return -EALREADY if the peer address is already in use
* @return -ENOMEM if no empty connection slot is available
* @return -EINVAL if invalid configuration parameters are given
*/
int nimble_statconn_add_slave(const uint8_t *addr);
int nimble_statconn_add_slave(const uint8_t *addr,
const nimble_statconn_cfg_t *cfg);
/**
* @brief Remove the connection to the given peer

View File

@ -44,6 +44,9 @@
typedef struct {
uint8_t addr[BLE_ADDR_LEN]; /**< peer addr, network byte order */
uint8_t state; /**< internal state */
#if IS_USED(MODULE_NIMBLE_STATCONN_EXT)
nimble_phy_t phy_mode; /**< PHY mode used by this slot */
#endif
} slot_t;
static const uint8_t _ad[2] = { BLE_GAP_AD_FLAGS, BLUETIL_AD_FLAGS_DEFAULT };
@ -51,9 +54,8 @@ static const uint8_t _ad[2] = { BLE_GAP_AD_FLAGS, BLUETIL_AD_FLAGS_DEFAULT };
static mutex_t _lock = MUTEX_INIT;
static slot_t _slots[NIMBLE_NETIF_MAX_CONN];
static struct ble_gap_adv_params _adv_params;
static struct ble_gap_conn_params _conn_params;
static uint32_t _conn_timeout;
static nimble_netif_accept_cfg_t _accept_params;
static nimble_netif_connect_cfg_t _conn_params;
static nimble_netif_eventcb_t _eventcb = NULL;
@ -87,10 +89,17 @@ static void _activate(uint8_t role)
peer.type = BLE_ADDR_RANDOM;
bluetil_addr_swapped_cp(slot->addr, peer.val);
/* try to (re)open the connection */
nimble_netif_connect(&peer, &_conn_params, _conn_timeout);
#if IS_USED(MODULE_NIMBLE_STATCONN_EXT)
_conn_params.phy_mode = slot->phy_mode;
#endif
nimble_netif_connect(&peer, &_conn_params);
}
else if (slot && (role == ROLE_S)) {
nimble_netif_accept(_ad, sizeof(_ad), &_adv_params);
#if IS_USED(MODULE_NIMBLE_STATCONN_EXT)
_accept_params.primary_phy = slot->phy_mode;
_accept_params.secondary_phy = slot->phy_mode;
#endif
nimble_netif_accept(_ad, sizeof(_ad), &_accept_params);
}
mutex_unlock(&_lock);
}
@ -153,7 +162,8 @@ static void _on_netif_evt(int handle, nimble_netif_event_t event,
}
}
static int _be(uint8_t role, const uint8_t *addr)
static int _be(uint8_t role, const uint8_t *addr,
const nimble_statconn_cfg_t *cfg)
{
mutex_lock(&_lock);
slot_t *s = _get_addr(addr);
@ -170,6 +180,18 @@ static int _be(uint8_t role, const uint8_t *addr)
s->state = (role | PENDING);
memcpy(s->addr, addr, BLE_ADDR_LEN);
mutex_unlock(&_lock);
#if IS_USED(MODULE_NIMBLE_STATCONN_EXT)
if (cfg != NULL) {
s->phy_mode = cfg->phy_mode;
}
else {
s->phy_mode = NIMBLE_STATCONN_PHY_MODE;
}
#else
(void)cfg;
#endif
_activate(role);
return 0;
}
@ -179,27 +201,31 @@ void nimble_statconn_init(void)
memset(_slots, 0, sizeof(_slots));
/* set the advertising parameters used */
_adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
_adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
_adv_params.itvl_min = BLE_GAP_ADV_ITVL_MS(NIMBLE_STATCONN_ADV_ITVL_MS);
_adv_params.itvl_max = _adv_params.itvl_min;
_adv_params.channel_map = 0;
_adv_params.filter_policy = 0;
_adv_params.high_duty_cycle = 0;
memset(&_accept_params, 0, sizeof(_accept_params));
#if IS_USED(MODULE_NIMBLE_STATCONN_EXT)
_accept_params.flags = 0;
#else
_accept_params.flags = NIMBLE_NETIF_FLAG_LEGACY;
_accept_params.primary_phy = NIMBLE_PHY_1M;
_accept_params.secondary_phy = NIMBLE_PHY_1M;
#endif
_accept_params.adv_itvl_ms = NIMBLE_STATCONN_ADV_ITVL_MS;
_accept_params.timeout_ms = BLE_HS_FOREVER;
_accept_params.own_addr_type = nimble_riot_own_addr_type;
/* set connection parameters */
_conn_params.scan_itvl = BLE_GAP_SCAN_ITVL_MS(NIMBLE_STATCONN_CONN_WIN_MS);
_conn_params.scan_window = _conn_params.scan_itvl;
_conn_params.latency = NIMBLE_STATCONN_CONN_LATENCY;
_conn_params.supervision_timeout = BLE_GAP_SUPERVISION_TIMEOUT_MS(
NIMBLE_STATCONN_CONN_SUPERTO_MS);
_conn_params.itvl_min = BLE_GAP_CONN_ITVL_MS(
NIMBLE_STATCONN_CONN_ITVL_MIN_MS);
_conn_params.itvl_max = BLE_GAP_CONN_ITVL_MS(
NIMBLE_STATCONN_CONN_ITVL_MAX_MS);
_conn_params.min_ce_len = 0;
_conn_params.max_ce_len = 0;
_conn_timeout = NIMBLE_STATCONN_CONN_TIMEOUT_MS;
memset(&_conn_params, 0, sizeof(_conn_params));
#if !IS_USED(MODULE_NIMBLE_AUTOCONN_EXT)
_conn_params.phy_mode = NIMBLE_PHY_1M;
#endif
_conn_params.scan_itvl_ms = NIMBLE_STATCONN_CONN_WIN_MS;
_conn_params.scan_window_ms = NIMBLE_STATCONN_CONN_WIN_MS;
_conn_params.conn_itvl_min_ms = NIMBLE_STATCONN_CONN_ITVL_MIN_MS;
_conn_params.conn_itvl_max_ms = NIMBLE_STATCONN_CONN_ITVL_MAX_MS;
_conn_params.conn_supervision_timeout_ms = NIMBLE_STATCONN_CONN_SUPERTO_MS;
_conn_params.conn_slave_latency = NIMBLE_STATCONN_CONN_LATENCY;
_conn_params.timeout_ms = NIMBLE_STATCONN_CONN_TIMEOUT_MS;
_conn_params.own_addr_type = nimble_riot_own_addr_type;
/* register our event callback */
nimble_netif_eventcb(_on_netif_evt);
@ -210,14 +236,16 @@ void nimble_statconn_eventcb(nimble_netif_eventcb_t cb)
_eventcb = cb;
}
int nimble_statconn_add_master(const uint8_t *addr)
int nimble_statconn_add_master(const uint8_t *addr,
const nimble_statconn_cfg_t *cfg)
{
return _be(ROLE_S, addr);
return _be(ROLE_S, addr, cfg);
}
int nimble_statconn_add_slave(const uint8_t *addr)
int nimble_statconn_add_slave(const uint8_t *addr,
const nimble_statconn_cfg_t *cfg)
{
return _be(ROLE_M, addr);
return _be(ROLE_M, addr, cfg);
}
int nimble_statconn_rm(const uint8_t *addr)

View File

@ -115,7 +115,7 @@ $(PKG_PATCHED): $(PKG_PATCHED_PREREQUISITES)
$(call gen_dependency_files,$@.d,$(PKG_PATCHED_PREREQUISITES))
$(Q)$(GIT_IN_PKG) clean $(GIT_QUIET) -xdff '**' -e $(PKG_STATE:$(PKG_SOURCE_DIR)/%='%*')
$(Q)$(GIT_IN_PKG) checkout $(GIT_QUIET) -f $(PKG_VERSION)
$(Q)$(GIT_IN_PKG) $(GITFLAGS) am $(GITAMFLAGS) $(PKG_PATCHES) </dev/null
$(Q) test -n "$(PKG_PATCHES)" && $(GIT_IN_PKG) $(GITFLAGS) am $(GITAMFLAGS) $(PKG_PATCHES) </dev/null
@touch $@
$(PKG_DOWNLOADED): $(MAKEFILE_LIST) | $(PKG_SOURCE_DIR)/.git

View File

@ -332,6 +332,15 @@ static off_t _lseek(vfs_file_t *filp, off_t off, int whence)
return spiffs_err_to_errno(SPIFFS_lseek(&fs_desc->fs, filp->private_data.value, off, s_whence));
}
static int _fsync(vfs_file_t *filp)
{
spiffs_desc_t *fs_desc = filp->mp->private_data;
int ret = SPIFFS_fflush(&fs_desc->fs, filp->private_data.value);
return spiffs_err_to_errno(ret);
}
static int _fstat(vfs_file_t *filp, struct stat *buf)
{
spiffs_desc_t *fs_desc = filp->mp->private_data;
@ -514,6 +523,7 @@ static const vfs_file_ops_t spiffs_file_ops = {
.write = _write,
.lseek = _lseek,
.fstat = _fstat,
.fsync = _fsync,
};
static const vfs_dir_ops_t spiffs_dir_ops = {

View File

@ -1,7 +1,7 @@
PKG_NAME=tinycbor
PKG_URL=https://github.com/intel/tinycbor
# Tinycbor v0.5.3
PKG_VERSION=755f9ef932f9830a63a712fd2ac971d838b131f1
# Tinycbor v0.6.0
PKG_VERSION=d393c16f3eb30d0c47e6f9d92db62272f0ec4dc7
PKG_LICENSE=MIT
include $(RIOTBASE)/pkg/pkg.mk

View File

@ -843,7 +843,6 @@ ifneq (,$(filter fido2_ctap,$(USEMODULE)))
USEMODULE += ztimer_msec
USEMODULE += event
USEMODULE += event_timeout
USEMODULE += prng_sha256prng
USEMODULE += cipher_modes
USEMODULE += crypto_aes_256
USEMODULE += hashes

View File

@ -4,4 +4,17 @@
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
menuconfig MODULE_FIDO2
bool "FIDO2"
help
FIDO2 is an authentication standard that seeks to solve the password
problem by enabling passwordless authentication. FIDO2 consists of the
W3C Web Authentication specification (WebAuthn) and the Client to
Authenticator Protocol (CTAP). For more information visit
https://fidoalliance.org/fido2.
if MODULE_FIDO2
rsource "ctap/Kconfig"
endif # MODULE_FIDO2

View File

@ -4,13 +4,37 @@
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
menuconfig KCONFIG_USEMODULE_FIDO2_CTAP
menuconfig MODULE_FIDO2_CTAP
bool "FIDO2 CTAP"
depends on USEMODULE_FIDO2_CTAP
depends on HAS_PERIPH_FLASHPAGE
depends on HAS_PERIPH_GPIO
depends on HAS_PERIPH_GPIO_IRQ
depends on MODULE_FIDO2
depends on TEST_KCONFIG
select PACKAGE_TINYCBOR
select PACKAGE_MICRO-ECC
select PACKAGE_TINY-ASN1
select MODULE_PERIPH_GPIO
select MODULE_PERIPH_GPIO_IRQ
select MODULE_EVENT
select MODULE_EVENT_TIMEOUT
select MODULE_ZTIMER
select MODULE_ZTIMER_MSEC
select MODULE_MTD
select MODULE_MTD_FLASHPAGE
select MODULE_MTD_WRITE_PAGE
select MODULE_RANDOM
select MODULE_CRYPTO_AES_256
select MODULE_CIPHER_MODES
select MODULE_HASHES
help
Configure a FIDO2 CTAP authenticator via KConfig.
Y to enable CTAP protocol support. The Client-to-Authenticator
Protocol (CTAP) is an application layer protocol for the communication
between an authenticator and a host. CTAP is part of the FIDO2 Project.
For more information visit https://fidoalliance.org/fido2.
if KCONFIG_USEMODULE_FIDO2_CTAP
if MODULE_FIDO2_CTAP
config FIDO2_CTAP_STACK_SIZE
int "CTAP thread stack size"
@ -93,4 +117,4 @@ config FIDO2_CTAP_FLASH_START_PAGE
rsource "transport/Kconfig"
endif # KCONFIG_USEMODULE_FIDO2_CTAP
endif # MODULE_FIDO2_CTAP

View File

@ -4,4 +4,9 @@
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
menuconfig MODULE_FIDO2_CTAP_TRANSPORT
bool "FIDO2 CTAP transport"
depends on MODULE_FIDO2_CTAP
depends on TEST_KCONFIG
rsource "hid/Kconfig"

View File

@ -4,13 +4,16 @@
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
menuconfig KCONFIG_USEMODULE_FIDO2_CTAP_TRANSPORT_HID
bool "FIDO2 CTAP TRANSPORT HID"
depends on USEMODULE_FIDO2_CTAP_TRANSPORT_HID
menuconfig MODULE_FIDO2_CTAP_TRANSPORT_HID
bool "FIDO2 CTAP transport HID"
depends on MODULE_FIDO2_CTAP_TRANSPORT
depends on TEST_KCONFIG
select MODULE_ISRPIPE
select MODULE_USBUS_HID
help
Configure a FIDO2 CTAP authenticator via KConfig.
if KCONFIG_USEMODULE_FIDO2_CTAP_TRANSPORT_HID
if MODULE_FIDO2_CTAP_TRANSPORT_HID
config FIDO2_CTAP_TRANSPORT_HID_TRANSACTION_TIMEOUT
int "CTAPHID Transaction timeout in milliseconds"
@ -20,4 +23,4 @@ config FIDO2_CTAP_TRANSPORT_HID_TRANSACTION_TIMEOUT
of time to prevent the authenticator from being locked by a
stalling application.
endif # KCONFIG_USEMODULE_FIDO2_CTAP_TRANSPORT_HID
endif # MODULE_FIDO2_CTAP_TRANSPORT_HID

View File

@ -139,6 +139,8 @@
#include <stdint.h>
#include "irq.h"
#include "sched.h"
#include "atomic_utils_arch.h"
#ifdef __cplusplus
@ -263,6 +265,16 @@ static inline uintptr_t atomic_load_uintptr(const volatile uintptr_t *var) {
static inline void * atomic_load_ptr(void **ptr_addr) {
return (void *)atomic_load_uintptr((const volatile uintptr_t *)ptr_addr);
}
/**
* @brief Load an `kernel_pid_t` atomically
*
* @param[in] var Variable to load atomically
* @return The value stored in @p var
*/
static inline kernel_pid_t atomic_load_kernel_pid(const volatile kernel_pid_t *var)
{
return atomic_load_u16((const volatile uint16_t *)var);
}
/** @} */
/**
@ -321,6 +333,17 @@ static inline void atomic_store_uintptr(volatile uintptr_t *dest, uintptr_t val)
static inline void atomic_store_ptr(void **dest, const void *val) {
atomic_store_uintptr((volatile uintptr_t *)dest, (uintptr_t)val);
}
/**
* @brief Store an `kernel_pid_t` atomically
*
* @param[out] dest Location to atomically write the new value to
* @param[in] val Value to write
*/
static inline void atomic_store_kernel_pid(volatile kernel_pid_t *dest,
kernel_pid_t val)
{
atomic_store_u16((volatile uint16_t *)dest, (uint16_t)val);
}
/** @} */
/**

View File

@ -0,0 +1,69 @@
/*
* Copyright (C) 2019 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @defgroup sys_stdio_nimble STDIO over NimBLE
* @ingroup sys
*
* @experimental This feature is experimental as some use-cases, such as examples/twr_aloha, show
* unexpected behaviour.
*
* @brief Standard input/output backend using NimBLE.
*
* @note 'stdio_read' blocks until at least one character was read.
*
* @note 'stdio_write' is considered non-blocking even though it uses a mutex to protect the
* write buffer since only 'stdio_write' uses this mutex. Characters will be written
* in FIFO mode. Characters that do not fit in the buffer will be dropped.
*
* @{
* @file
*
* @author Hendrik van Essen <hendrik.ve@fu-berlin.de>
*/
#ifndef STDIO_NIMBLE_H
#define STDIO_NIMBLE_H
#include "stdio_base.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Whether to clear the buffers when establishing a new connection or
* not. Defaults to true.
*/
#ifndef CONFIG_STDIO_NIMBLE_CLEAR_BUFFER_ON_CONNECT
#define CONFIG_STDIO_NIMBLE_CLEAR_BUFFER_ON_CONNECT 1
#endif
/**
* @brief Size of buffer for stdin in bytes
*
* @note Must be a power of two!
*/
#ifndef CONFIG_STDIO_NIMBLE_STDIN_BUFSIZE
#define CONFIG_STDIO_NIMBLE_STDIN_BUFSIZE 1024
#endif
/**
* @brief Size of buffer for stdout in bytes
*
* @note Must be a power of two!
*/
#ifndef CONFIG_STDIO_NIMBLE_STDOUT_BUFSIZE
#define CONFIG_STDIO_NIMBLE_STDOUT_BUFSIZE 2048
#endif
#ifdef __cplusplus
}
#endif
/** @} */
#endif /* STDIO_NIMBLE_H */

View File

@ -440,6 +440,17 @@ struct vfs_file_ops {
* @return <0 on error
*/
ssize_t (*write) (vfs_file_t *filp, const void *src, size_t nbytes);
/**
* @brief Synchronize a file on storage
* Any pending writes are written out to storage.
*
* @param[in] filp pointer to open file
*
* @return 0 on success
* @return <0 on error
*/
int (*fsync) (vfs_file_t *filp);
};
/**
@ -739,6 +750,17 @@ ssize_t vfs_read(int fd, void *dest, size_t count);
*/
ssize_t vfs_write(int fd, const void *src, size_t count);
/**
* @brief Synchronize a file on storage
* Any pending writes are written out to storage.
*
* @param[in] fd fd number obtained from vfs_open
*
* @return 0 on success
* @return <0 on error
*/
int vfs_fsync(int fd);
/**
* @brief Open a directory for reading with readdir
*

View File

@ -21,6 +21,7 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "fmt.h"
#include "ztimer.h"
@ -30,17 +31,37 @@
#include "net/bluetil/ad.h"
#include "net/bluetil/addr.h"
#if !IS_USED(MODULE_NIMBLE_AUTOCONN) && !IS_USED(MODULE_NIMBLE_STATCONN)
#define FULL_CONTROL !IS_USED(MODULE_NIMBLE_AUTOCONN) && \
!IS_USED(MODULE_NIMBLE_STATCONN) && \
!IS_USED(MODULE_NIMBLE_RPBLE)
#if FULL_CONTROL
#include "nimble_scanlist.h"
#include "nimble_scanner.h"
#endif
#define DEFAULT_NODE_NAME "bleRIOT"
#define DEFAULT_SCAN_DURATION (500U) /* 500ms */
#define DEFAULT_CONN_TIMEOUT (500U) /* 500ms */
#define DEFAULT_SCAN_DURATION_MS 500U
#define DEFAULT_CONN_TIMEOUT_MS 500U
#define DEFAULT_SCAN_ITVL_MS 100U
#define DEFAULT_CONN_ITVL_MS 75U
#define DEFAULT_TX_POWER 0 /* 0dBm */
#define DEFAULT_ADV_ITVL_MS 75U
#if !IS_USED(MODULE_NIMBLE_AUTOCONN) && !IS_USED(MODULE_NIMBLE_STATCONN)
static const char *_phystr[] = { "N/A", "1M", "2M", "CODED" };
#if FULL_CONTROL
static const char *_name_to_connect = NULL;
static nimble_netif_connect_cfg_t _connect_params = {
.scan_itvl_ms = DEFAULT_SCAN_ITVL_MS,
.scan_window_ms = DEFAULT_SCAN_ITVL_MS,
.conn_itvl_min_ms = DEFAULT_CONN_ITVL_MS,
.conn_itvl_max_ms = DEFAULT_CONN_ITVL_MS,
.conn_supervision_timeout_ms = DEFAULT_CONN_ITVL_MS * 20,
.conn_slave_latency = 0,
.timeout_ms = 0, /* will be filled later */
.phy_mode = 0, /* will be filled later */
.own_addr_type = 0 /* will be filled later */,
};
static void _scan_for_name(uint8_t type, const ble_addr_t *addr,
const nimble_scanner_info_t *info,
@ -56,7 +77,7 @@ static void _scan_for_name(uint8_t type, const ble_addr_t *addr,
_name_to_connect, strlen(_name_to_connect));
if (res) {
nimble_scanner_stop();
nimble_netif_connect(addr, NULL, DEFAULT_CONN_TIMEOUT);
nimble_netif_connect(addr, &_connect_params);
}
}
@ -90,12 +111,34 @@ static void _on_ble_evt(int handle, nimble_netif_event_t event,
case NIMBLE_NETIF_ABORT_SLAVE:
_print_evt("CONNECTION ABORT", handle, addr);
break;
case NIMBLE_NETIF_ACCEPT_STOP:
_print_evt("ACCEPT STOP", handle, addr);
case NIMBLE_NETIF_CONN_UPDATED:
default:
/* do nothing */
break;
}
}
static uint8_t _parsephy(const char *phy_str)
{
if (memcmp(phy_str, "1M", 2) == 0) {
return NIMBLE_PHY_1M;
}
#if IS_ACTIVE(MODULE_NIMBLE_PHY_2MBIT)
else if (memcmp(phy_str, "2M", 2) == 0) {
return NIMBLE_PHY_2M;
}
#endif
#if IS_ACTIVE(MODULE_NIMBLE_PHY_CODED)
else if (memcmp(phy_str, "CODED", 5) == 0) {
return NIMBLE_PHY_CODED;
}
#endif
else {
return NIMBLE_PHY_INVALID;
}
}
#endif
static int _conn_dump(nimble_netif_conn_t *conn, int handle, void *arg)
@ -117,8 +160,20 @@ static int _conn_dump(nimble_netif_conn_t *conn, int handle, void *arg)
printf(" ");
bluetil_addr_ipv6_l2ll_print(conn->addr);
#endif
printf(" (%c,%ums,%ums,%i)", role, itvl, sto, (int)desc.conn_latency);
puts("");
#if IS_USED(MODULE_NIMBLE_NETIF_EXT)
uint8_t phy_rx, phy_tx;
(void)phy_tx;
res = ble_gap_read_le_phy(conn->gaphandle, &phy_tx, &phy_rx);
if (res != 0) {
phy_rx = 1;
}
#else
/* when not using extended advertisements we always use the 1M phy mode */
uint8_t phy_rx = 1;
#endif
printf(" (%c,%ums,%ums,%i,%s)\n",
role, itvl, sto, (int)desc.conn_latency, _phystr[phy_rx]);
return 0;
}
@ -159,7 +214,7 @@ static void _conn_list(void)
if (active > 0) {
nimble_netif_conn_foreach(NIMBLE_NETIF_L2CAP_CONNECTED,
_conn_dump, NULL);
puts(" (role, conn itvl, superv. timeout, slave latency)");
puts(" (role, conn itvl, superv. timeout, slave latency, PHY)");
}
}
@ -179,6 +234,15 @@ static void _cmd_info(void)
#endif
puts("");
printf("Supported PHY modes: 1M");
#if IS_USED(MODULE_NIMBLE_PHY_2MBIT)
printf(" 2M");
#endif
#if IS_USED(MODULE_NIMBLE_PHY_CODED)
printf(" CODED");
#endif
puts("");
printf(" Free slots: %u/%u\n", free, NIMBLE_NETIF_MAX_CONN);
printf("Advertising: ");
if (nimble_netif_conn_get_adv() != NIMBLE_NETIF_CONN_INVALID) {
@ -196,99 +260,107 @@ static void _cmd_info(void)
puts("");
}
#if !IS_USED(MODULE_NIMBLE_AUTOCONN) && !IS_USED(MODULE_NIMBLE_STATCONN)
static void _cmd_adv(const char *name)
#if FULL_CONTROL
static int _cmd_adv(int argc, char **argv, bool legacy)
{
int res;
(void)res;
uint8_t buf[BLE_HS_ADV_MAX_SZ];
bluetil_ad_t ad;
const struct ble_gap_adv_params _adv_params = {
.conn_mode = BLE_GAP_CONN_MODE_UND,
.disc_mode = BLE_GAP_DISC_MODE_LTD,
.itvl_min = BLE_GAP_ADV_FAST_INTERVAL2_MIN,
.itvl_max = BLE_GAP_ADV_FAST_INTERVAL2_MAX,
};
const char *name = NULL;
uint8_t addrn[BLE_ADDR_LEN];
ble_addr_t addr = { .type = nimble_riot_own_addr_type };
/* stop sub-command: stop advertising */
if (memcmp(argv[2], "stop", 4) == 0) {
res = nimble_netif_accept_stop();
if (res == 0) {
puts("advertising stopped");
}
else if (res == -EALREADY) {
puts("no advertising in progress");
}
return 0;
}
/* make sure no advertising is in progress */
if (nimble_netif_conn_is_adv()) {
puts("err: advertising already in progress");
return;
return 1;
}
/* build advertising data */
res = bluetil_ad_init_with_flags(&ad, buf, BLE_HS_ADV_MAX_SZ,
BLUETIL_AD_FLAGS_DEFAULT);
assert(res == BLUETIL_AD_OK);
uint16_t ipss = BLE_GATT_SVC_IPSS;
res = bluetil_ad_add(&ad, BLE_GAP_AD_UUID16_INCOMP, &ipss, sizeof(ipss));
assert(res == BLUETIL_AD_OK);
if (name == NULL) {
name = DEFAULT_NODE_NAME;
/* try if first parameter is a BLE address, if so, use directed
* advertisement */
if (bluetil_addr_from_str(addrn, argv[2]) != NULL) {
/* NimBLE expects address in little endian, so swap */
bluetil_addr_swapped_cp(addrn, addr.val);
puts("Found BLE address: sending directed advertisements");
}
res = bluetil_ad_add(&ad, BLE_GAP_AD_NAME, name, strlen(name));
if (res != BLUETIL_AD_OK) {
puts("err: the given name is too long");
return;
else {
name = argv[2];
}
uint32_t timeout = 0;
if (argc >= 4) {
timeout = (uint32_t)atoi(argv[3]);
}
uint8_t phy_sec = BLE_GAP_LE_PHY_1M;
if (argc >= 5) {
phy_sec = _parsephy(argv[4]);
if (phy_sec == 0) {
puts("err: PHY mode not supported\n");
return 1;
}
}
uint8_t phy_pri = (phy_sec == BLE_HCI_LE_PHY_2M) ? BLE_HCI_LE_PHY_1M
: phy_sec;
nimble_netif_accept_cfg_t p = {
.flags = (legacy) ? NIMBLE_NETIF_FLAG_LEGACY : 0,
.adv_itvl_ms = DEFAULT_ADV_ITVL_MS,
.primary_phy = phy_pri,
.secondary_phy = phy_sec,
.tx_power = DEFAULT_TX_POWER,
.channel_map = 0,
.timeout_ms = timeout,
.own_addr_type = nimble_riot_own_addr_type,
};
if (name != NULL) {
uint8_t buf[BLE_HS_ADV_MAX_SZ];
bluetil_ad_t ad;
/* build advertising data */
res = bluetil_ad_init_with_flags(&ad, buf, BLE_HS_ADV_MAX_SZ,
BLUETIL_AD_FLAGS_DEFAULT);
assert(res == BLUETIL_AD_OK);
uint16_t ipss = BLE_GATT_SVC_IPSS;
res = bluetil_ad_add(&ad, BLE_GAP_AD_UUID16_INCOMP, &ipss, sizeof(ipss));
assert(res == BLUETIL_AD_OK);
res = bluetil_ad_add(&ad, BLE_GAP_AD_NAME, name, strlen(name));
if (res != BLUETIL_AD_OK) {
puts("err: the given name is too long");
return 1;
}
res = nimble_netif_accept(ad.buf, ad.pos, &p);
}
else {
res = nimble_netif_accept_direct(&addr, &p);
}
/* start listening for incoming connections */
res = nimble_netif_accept(ad.buf, ad.pos, &_adv_params);
if (res != 0) {
printf("err: unable to start advertising (%i)\n", res);
}
else {
printf("success: advertising this node as '%s'\n", name);
}
}
static void _cmd_adv_direct(const char *addr_str)
{
int res;
(void)res;
uint8_t addrn[BLE_ADDR_LEN];
ble_addr_t addr;
const struct ble_gap_adv_params _adv_params = {
.conn_mode = BLE_GAP_CONN_MODE_DIR,
.disc_mode = BLE_GAP_DISC_MODE_GEN,
.itvl_min = BLE_GAP_ADV_FAST_INTERVAL2_MIN,
.itvl_max = BLE_GAP_ADV_FAST_INTERVAL2_MAX,
};
/* make sure no advertising is in progress */
if (nimble_netif_conn_is_adv()) {
puts("err: advertising already in progress");
return;
}
/* parse and convert address -> RIOT uses big endian notation, NimBLE
* expects little endian... */
if (bluetil_addr_from_str(addrn, addr_str) == NULL) {
puts("err: unable to parse BLE address");
return;
}
addr.type = nimble_riot_own_addr_type;
bluetil_addr_swapped_cp(addrn, addr.val);
/* start advertising directed advertising with the given BLE address */
res = nimble_netif_accept_direct(&addr, BLE_HS_FOREVER, &_adv_params);
if (res != 0) {
printf("err: unable to start directed advertising (%i)\n", res);
}
else {
puts("success: started to send directed advertisements");
}
}
static void _cmd_adv_stop(void)
{
int res = nimble_netif_accept_stop();
if (res == 0) {
puts("canceled advertising");
}
else {
puts("no advertising in progress");
if (name != NULL) {
printf("success: advertising this node as '%s'\n", name);
}
else {
printf("success: sending direct advertisements to ");
bluetil_addr_print(addrn);
puts("");
}
}
return 0;
}
static void _do_scan(nimble_scanner_cb cb, unsigned duration)
@ -301,7 +373,19 @@ static void _do_scan(nimble_scanner_cb cb, unsigned duration)
printf("err: scanner already active\n");
return;
}
nimble_scanner_init(NULL, cb);
nimble_scanner_cfg_t p = {
.itvl_ms = DEFAULT_SCAN_ITVL_MS,
.win_ms = DEFAULT_SCAN_ITVL_MS,
#if IS_USED(MODULE_NIMBLE_PHY_CODED)
.flags = (NIMBLE_SCANNER_PASSIVE | NIMBLE_SCANNER_PHY_1M |
NIMBLE_SCANNER_PHY_CODED),
#else
.flags = (NIMBLE_SCANNER_PASSIVE | NIMBLE_SCANNER_PHY_1M),
#endif
};
nimble_scanner_init(&p, cb);
nimble_scanlist_clear();
nimble_scanner_start();
ztimer_sleep(ZTIMER_MSEC, duration);
@ -316,58 +400,73 @@ static void _cmd_scan(unsigned duration)
nimble_scanlist_print();
}
static void _cmd_connect_addr(ble_addr_t *addr)
static void _cmd_connect(int argc, char **argv)
{
/* simply use NimBLEs default connection parameters */
int res = nimble_netif_connect(addr, NULL, DEFAULT_CONN_TIMEOUT);
if (res < 0) {
printf("err: unable to trigger connection sequence (%i)\n", res);
return;
}
ble_addr_t addr;
int proceed = 0;
printf("initiated connection procedure with ");
/* populate connection parameters */
_connect_params.timeout_ms = DEFAULT_CONN_TIMEOUT_MS;
if (argc >= 4) {
_connect_params.timeout_ms = (uint32_t)atoi(argv[3]);
}
_connect_params.phy_mode = NIMBLE_PHY_1M;
if (argc >= 5) {
_connect_params.phy_mode = _parsephy(argv[4]);
if (_connect_params.phy_mode == 0) {
puts("err: PHY mode not supported\n");
return;
}
}
_connect_params.own_addr_type = nimble_riot_own_addr_type;
/* try to parse address directly */
uint8_t addrn[BLE_ADDR_LEN];
bluetil_addr_swapped_cp(addr->val, addrn);
bluetil_addr_print(addrn);
puts("");
}
static void _cmd_connect_addr_raw(const uint8_t *addr_in)
{
/* RANDOM is the most common type, has no noticeable effect when connecting
anyhow... */
ble_addr_t addr = { .type = BLE_ADDR_RANDOM };
/* NimBLE expects address in little endian, so swap */
bluetil_addr_swapped_cp(addr_in, addr.val);
_cmd_connect_addr(&addr);
}
static void _cmd_connect_name(const char *name, unsigned duration)
{
if (_name_to_connect != NULL) {
printf("err: already trying to connect to '%s'\n", _name_to_connect);
if (bluetil_addr_from_str(addrn, argv[2]) != NULL) {
addr.type = nimble_riot_own_addr_type;
/* NimBLE expects address in little endian, so swap */
bluetil_addr_swapped_cp(addrn, addr.val);
proceed = 1;
}
/* try if param is a number, if so use it as scanlist entry number */
else if (fmt_is_number(argv[2])) {
unsigned pos = atoi(argv[2]);
nimble_scanlist_entry_t *sle = nimble_scanlist_get_by_pos(pos);
if (sle == NULL) {
puts("err: unable to find given entry in scanlist");
return;
}
_connect_params.phy_mode = sle->phy_sec;
memcpy(&addr, &sle->addr, sizeof(addr));
proceed = 1;
}
/* else interpret value as name and search for that peer */
else {
unsigned duration = DEFAULT_SCAN_DURATION_MS;
if (argc > 3) {
duration = atoi(argv[3]);
}
_name_to_connect = argv[2];
printf("trying to find and connect to a node with name '%s'\n", argv[2]);
_do_scan(_scan_for_name, duration);
if (_name_to_connect != NULL) {
printf("fail: unable to connect to '%s'\n", _name_to_connect);
_name_to_connect = NULL;
}
return;
}
_name_to_connect = name;
printf("trying to find and connect to a node with name '%s'\n", name);
_do_scan(_scan_for_name, duration);
if (_name_to_connect != NULL) {
printf("fail: unable to connect to '%s'\n", _name_to_connect);
_name_to_connect = NULL;
}
}
static void _cmd_connect_scanlist(unsigned pos)
{
nimble_scanlist_entry_t *sle = nimble_scanlist_get_by_pos(pos);
if (sle == NULL) {
puts("err: unable to find given entry in scanlist");
return;
if (proceed == 1) {
int res = nimble_netif_connect(&addr, &_connect_params);
if (res == 0) {
puts("Successfully connected 123");
}
else {
puts("err: unable to connect");
}
}
_cmd_connect_addr(&sle->addr);
}
#endif /* MODULE_NIMBLE_AUTOCONN */
#endif
static void _cmd_close(int handle)
{
@ -406,7 +505,7 @@ static int _ishelp(char *argv)
void sc_nimble_netif_init(void)
{
#if !IS_USED(MODULE_NIMBLE_AUTOCONN) && !IS_USED(MODULE_NIMBLE_STATCONN)
#if FULL_CONTROL
/* setup the scanning environment */
nimble_scanlist_init();
@ -418,8 +517,9 @@ void sc_nimble_netif_init(void)
int _nimble_netif_handler(int argc, char **argv)
{
if ((argc == 1) || _ishelp(argv[1])) {
#if !IS_USED(MODULE_NIMBLE_AUTOCONN) && !IS_USED(MODULE_NIMBLE_STATCONN)
printf("usage: %s [help|info|adv|scan|connect|close|update|chanmap]\n", argv[0]);
#if FULL_CONTROL
printf("usage: %s [help|info|adv|adv_ext|adv_dir|"
"scan|connect|close|update|chanmap]\n", argv[0]);
#else
printf("usage: %s [help|info|close|update|chanmap]\n", argv[0]);
#endif
@ -429,34 +529,26 @@ int _nimble_netif_handler(int argc, char **argv)
_cmd_info();
}
#if !IS_USED(MODULE_NIMBLE_AUTOCONN) && !IS_USED(MODULE_NIMBLE_STATCONN)
else if (memcmp(argv[1], "adv", 3) == 0) {
char *name = NULL;
if (argc > 2) {
if (_ishelp(argv[2])) {
printf("usage: %s adv [help|stop|direct <addr>|<name>]\n",
argv[0]);
return 0;
}
if (memcmp(argv[2], "stop", 4) == 0) {
_cmd_adv_stop();
return 0;
}
if (memcmp(argv[2], "direct", 6) == 0) {
puts("DBG: direct adv");
if (argc < 4) {
printf("error, no BLE address given\n");
return 0;
}
_cmd_adv_direct(argv[3]);
return 0;
}
name = argv[2];
#if FULL_CONTROL
else if (memcmp(argv[1], "adv_ext", 7) == 0) {
if (argc <= 2 || _ishelp(argv[2])) {
printf("usage: %s adv_ext <help|stop|addr|name> [timeout] [phy mode]\n"
" timeout in ms, 0 for no timeout\n"
" phy mode: [1M|2M|CODED]\n", argv[0]);
return 0;
}
_cmd_adv(name);
return _cmd_adv(argc, argv, false);
}
else if (memcmp(argv[1], "adv", 3) == 0) {
if (argc <= 2 || _ishelp(argv[2])) {
printf("usage: %s adv <help|stop|addr|name> [timeout]\n"
" timeout in ms, 0 for no timeout\n", argv[0]);
return 0;
}
return _cmd_adv(argc, argv, true);
}
else if (memcmp(argv[1], "scan", 4) == 0) {
uint32_t duration = DEFAULT_SCAN_DURATION;
uint32_t duration = DEFAULT_SCAN_DURATION_MS;
if (argc > 2) {
if (_ishelp(argv[2])) {
printf("usage: %s scan [help|list|[duration in ms]]\n", argv[0]);
@ -472,32 +564,16 @@ int _nimble_netif_handler(int argc, char **argv)
}
else if (memcmp(argv[1], "connect", 7) == 0) {
if ((argc < 3) || _ishelp(argv[2])) {
printf("usage: %s connect [help|list|<scanlist entry #>|<BLE addr>|<name>]\n",
argv[0]);
printf("usage: %s %s [help|list|<scanlist #>|<BLE addr>|<name>] "
"[timeout ms] [phy mode]\n"
" phy mode: [1M|2M|CODED]\n", argv[0], argv[1]);
return 0;
}
if (memcmp(argv[2], "list", 4) == 0) {
_conn_list();
return 0;
}
/* try if param is an BLE address */
uint8_t addr[BLE_ADDR_LEN];
if (bluetil_addr_from_str(addr, argv[2]) != NULL) {
_cmd_connect_addr_raw(addr);
return 0;
}
/* try if param is a name (contains non-number chars) */
if (!fmt_is_number(argv[2])) {
unsigned duration = DEFAULT_SCAN_DURATION;
if (argc > 3) {
duration = atoi(argv[3]);
}
_cmd_connect_name(argv[2], duration);
return 0;
}
unsigned pos = atoi(argv[2]);
_cmd_connect_scanlist(pos);
_cmd_connect(argc, argv);
}
#endif
else if (memcmp(argv[1], "close", 5) == 0) {

View File

@ -24,13 +24,48 @@
#include "net/bluetil/addr.h"
#include "nimble_statconn.h"
static uint8_t _parsephy(const char *phy_str)
{
if (memcmp(phy_str, "1M", 2) == 0) {
return NIMBLE_PHY_1M;
}
#if IS_ACTIVE(MODULE_NIMBLE_PHY_2MBIT)
else if (memcmp(phy_str, "2M", 2) == 0) {
return NIMBLE_PHY_2M;
}
#endif
#if IS_ACTIVE(MODULE_NIMBLE_PHY_CODED)
else if (memcmp(phy_str, "CODED", 5) == 0) {
return NIMBLE_PHY_CODED;
}
#endif
else {
return NIMBLE_PHY_INVALID;
}
}
int _nimble_statconn_handler(int argc, char **argv)
{
nimble_statconn_cfg_t cfg;
if ((argc < 3)) {
printf("usage: %s <addm|adds|rm> <BLE addr>\n", argv[0]);
printf("usage: %s <addm|adds|rm> <BLE addr> [phy mode]\n"
" phy_mode := [1M, 2M, CODED]\n", argv[0]);
return 0;
}
if (argc >= 4) {
cfg.phy_mode = _parsephy(argv[3]);
if (cfg.phy_mode == NIMBLE_PHY_INVALID) {
puts("err: PHY mode not supported");
return 1;
}
}
else {
cfg.phy_mode = NIMBLE_STATCONN_PHY_MODE;
}
/* parse address */
uint8_t addr[BLE_ADDR_LEN];
if (bluetil_addr_from_str(addr, argv[2]) == NULL) {
@ -39,7 +74,7 @@ int _nimble_statconn_handler(int argc, char **argv)
}
if (strncmp(argv[1], "addm", 4) == 0) {
if (nimble_statconn_add_master(addr) == 0) {
if (nimble_statconn_add_master(addr, &cfg) == 0) {
puts("success: connecting to peer as slave");
}
else {
@ -47,7 +82,7 @@ int _nimble_statconn_handler(int argc, char **argv)
}
}
else if (strncmp(argv[1], "adds", 4) == 0) {
if (nimble_statconn_add_slave(addr) == 0) {
if (nimble_statconn_add_slave(addr, &cfg) == 0) {
puts("success: connecting to peer as master");
}
else {

View File

@ -0,0 +1 @@
include $(RIOTBASE)/Makefile.base

110
sys/stdio_nimble/README.md Normal file
View File

@ -0,0 +1,110 @@
# STDIO NimBLE
This module uses NimBLE for stdio. The bluetooth characteristic for
stdin is writable and the characteristic for stdout uses the indicate
mechanism to publish the system's output to a connected device. Data will be
sent out asynchronously via callout functions.
To use this module, add
```
USEMODULE += stdio_nimble
```
to your makefile.
You can change the default buffer sizes by adding
```
CFLAGS += -DCONFIG_STDIO_NIMBLE_STDIN_BUFSIZE=1024
CFLAGS += -DCONFIG_STDIO_NIMBLE_STDOUT_BUFSIZE=2048
```
to your makefile. \
**NOTE:** These values must be a power of two!
By default, stdin and stdout buffers are cleared on a connect event. To keep the
content add the following to your makefile:
```
CFLAGS += -DCONFIG_STDIO_NIMBLE_CLEAR_BUFFER_ON_CONNECT=0
```
For automatic bluetooth advertising a module is provided: *nimble_autoadv*.
It will take care of enabling advertising on disconnect events and
disabling advertising on connect events. It can be enabled by adding
```
USEMODULE += nimble_autoadv
```
to your makefile.
The advertised device name can then optionally be configured with
```
CFLAGS += -DNIMBLE_AUTOADV_DEVICE_NAME='"Riot OS device"'
```
Otherwise the device will appear as "*RIOT OS device*".
## Instructions to connect to the bluetooth shell via ble-serial
- Configure and compile shell app for nrf52840dongle target in `tests/shell`.\
Add following to Makefile:
```
BOARD = nrf52840dongle
USEMODULE += nimble_autoadv
USEMODULE += stdio_nimble
```
**NOTE:** You can also have a look at `tests/shell_ble`.
- Flash
`$ make -C tests/shell -j clean all flash`
- Install the ble-serial tool
`$ pip install ble-serial`
- Scan for your device (device name `Riot OS device`) and note its BLE address.\
When you get `ble-scan: command not found` you can also run
`python -m ble_serial.scan` instead.
```
$ ble-scan
Started BLE scan
6BE8174C-A0F8-4479-AFA6-9828372CAFE9 (RSSI=-40): Riot OS device
A2862DCB-D382-4C0B-95BF-FA9A961F8D88 (RSSI=-48): Unknown
F2C75C08-7DD7-4F43-BEF0-151C92068FE5 (RSSI=-66): Unknown
69400683-FBE5-4B45-8CFE-98594076E5F4 (RSSI=-89): Unknown
```
- Discover characteristics (check the one advertised by the gatt server stdin/stdout)
```
$ ble-scan -d 6BE8174C-A0F8-4479-AFA6-9828372CAFE9
Started deep scan of 6BE8174C-A0F8-4479-AFA6-9828372CAFE9
SERVICE e6d54866-0292-4779-b8f8-c52bbec91e71 (Handle: 10): Unknown
CHARACTERISTIC 35f28386-3070-4f3b-ba38-27507e991762 (Handle: 11): Unknown ['indicate']
DESCRIPTOR 00002902-0000-1000-8000-00805f9b34fb (Handle: 13): Client Characteristic Configuration
CHARACTERISTIC ccdd113f-40d5-4d68-86ac-a728dd82f4aa (Handle: 14): Unknown ['write']
Completed deep scan of 6BE8174C-A0F8-4479-AFA6-9828372CAFE9
```
- Create a virtual port and mount it on /tmp/dev_riot_ble
```
$ ble-serial -d 6BE8174C-A0F8-4479-AFA6-9828372CAFE9 -p /tmp/dev_riot_ble --write-uuid ccdd113f-40d5-4d68-86ac-a728dd82f4aa --read-uuid 35f28386-3070-4f3b-ba38-27507e991762
17:44:18.765 | INFO | linux_pty.py: Slave created on /tmp/dev_riot_ble -> /dev/ttys006
17:44:18.766 | INFO | ble_interface.py: Receiver set up
17:44:18.766 | INFO | ble_interface.py: Trying to connect with 6BE8174C-A0F8-4479-AFA6-9828372CAFE9
17:44:19.861 | INFO | ble_interface.py: Device 6BE8174C-A0F8-4479-AFA6-9828372CAFE9 connected
17:44:19.862 | INFO | ble_interface.py: Found write characteristic ccdd113f-40d5-4d68-86ac-a728dd82f4aa (H. 14)
17:44:19.862 | INFO | ble_interface.py: Found notify characteristic 35f28386-3070-4f3b-ba38-27507e991762 (H. 11)
17:44:19.883 | INFO | main.py: Running main loop!
```
- Open the virtual com port (the port name is from the logs in previous steps)
```
$ picocom -q -b 115200 --imap lfcrlf /tmp/dev_riot_ble
ps
pid | state Q | pri
1 | running Q | 7
2 | bl anyfl _ | 5
3 | bl anyfl _ | 0
>
```

View File

@ -0,0 +1,387 @@
/*
* Copyright (C) 2019 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup sys
* @{
*
* @file
* @brief STDIO over NimBLE implementation
*
*
* @author Hendrik van Essen <hendrik.ve@fu-berlin.de>
* @author Francisco Molina <francois-xavier.molina@inria.fr>
*
* @}
*/
#include <errno.h>
#include <stdlib.h>
#include "nimble_riot.h"
#include "nimble/nimble_port.h"
#include "net/bluetil/ad.h"
#include "host/ble_hs.h"
#include "host/util/util.h"
#include "host/ble_gatt.h"
#include "services/gap/ble_svc_gap.h"
#include "services/gatt/ble_svc_gatt.h"
#if IS_USED(MODULE_STDIO_NIMBLE_DEBUG)
#include <stdarg.h>
#include "stdio_uart.h"
#include "periph/uart.h"
#endif /* IS_USED(MODULE_STDIO_NIMBLE_DEBUG) */
#if IS_USED(MODULE_VFS)
#include "vfs.h"
#endif
#include "tsrb.h"
#include "isrpipe.h"
#include "stdio_nimble.h"
#define NIMBLE_MAX_PAYLOAD MYNEWT_VAL(BLE_LL_MAX_PKT_SIZE)
/* Nimble uses ZTIMER_MSEC => 1 tick equals 1 ms */
#define CALLOUT_TICKS_MS 1
enum {
STDIO_NIMBLE_DISCONNECTED,
STDIO_NIMBLE_CONNECTED,
STDIO_NIMBLE_SUBSCRIBED,
STDIO_NIMBLE_SENDING,
};
/* isrpipe for stdin */
static uint8_t _isrpipe_stdin_mem[CONFIG_STDIO_NIMBLE_STDIN_BUFSIZE];
static isrpipe_t _isrpipe_stdin = ISRPIPE_INIT(_isrpipe_stdin_mem);
/* tsrb for stdout */
static uint8_t _tsrb_stdout_mem[CONFIG_STDIO_NIMBLE_STDOUT_BUFSIZE];
static tsrb_t _tsrb_stdout = TSRB_INIT(_tsrb_stdout_mem);
/* intermediate buffer to transfer data between tsrb and nimble functions,
* which are all based on os_mbuf implementation */
static uint8_t _stdin_read_buf[NIMBLE_MAX_PAYLOAD];
static uint8_t _stdout_write_buf[NIMBLE_MAX_PAYLOAD];
/* information about bluetooth connection */
static uint16_t _conn_handle;
static uint16_t _val_handle_stdout;
static volatile uint8_t _status = STDIO_NIMBLE_DISCONNECTED;
/* nimble related structs */
static struct ble_npl_callout _send_stdout_callout;
static struct ble_gap_event_listener _gap_event_listener;
#if IS_USED(MODULE_STDIO_NIMBLE_DEBUG)
#define DEBUG_PRINTF_BUFSIZE 512
#define PREFIX_STDIN "\nSTDIN: "
#define PREFIX_STDOUT "STDOUT: "
static char _debug_printf_buf[DEBUG_PRINTF_BUFSIZE];
#endif /* IS_USED(MODULE_STDIO_NIMBLE_DEBUG) */
static int _debug_printf(const char *format, ...)
{
#if IS_USED(MODULE_STDIO_NIMBLE_DEBUG)
unsigned state = irq_disable();
va_list va;
va_start(va, format);
int rc = vsnprintf(_debug_printf_buf, DEBUG_PRINTF_BUFSIZE, format, va);
va_end(va);
uart_write(STDIO_UART_DEV, (const uint8_t *)_debug_printf_buf, rc);
irq_restore(state);
return rc;
#else
(void)format;
return 0;
#endif
}
/**
* @brief UUID for stdio service (value: e6d54866-0292-4779-b8f8-c52bbec91e71)
*/
static const ble_uuid128_t gatt_svr_svc_stdio_uuid
= BLE_UUID128_INIT(0x71, 0x1e, 0xc9, 0xbe, 0x2b, 0xc5, 0xf8, 0xb8,
0x79, 0x47, 0x92, 0x02, 0x66, 0x48, 0xd5, 0xe6);
/**
* @brief UUID for stdout characteristic (value: 35f28386-3070-4f3b-ba38-27507e991762)
*/
static const ble_uuid128_t gatt_svr_chr_stdout_uuid
= BLE_UUID128_INIT(0x62, 0x17, 0x99, 0x7e, 0x50, 0x27, 0x38, 0xba,
0x3b, 0x4f, 0x70, 0x30, 0x86, 0x83, 0xf2, 0x35);
/**
* @brief UUID for stdin characteristic (value: ccdd113f-40d5-4d68-86ac-a728dd82f4aa)
*/
static const ble_uuid128_t gatt_svr_chr_stdin_uuid
= BLE_UUID128_INIT(0xaa, 0xf4, 0x82, 0xdd, 0x28, 0xa7, 0xac, 0x86,
0x68, 0x4d, 0xd5, 0x40, 0x3f, 0x11, 0xdd, 0xcc);
/**
* @brief Nimble access callback for stdin characteristic
*/
static int gatt_svr_chr_access_stdin(
uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg);
/**
* @brief Dummy access callback, because nimble requires one
*/
static int gatt_svr_chr_access_noop(
uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg)
{
(void)conn_handle;
(void)attr_handle;
(void)ctxt;
(void)arg;
return 0;
}
/**
* @brief Struct to define the stdio bluetooth service with its characteristics
*/
static const struct ble_gatt_svc_def _gatt_svr_svcs[] =
{
/*
* access_cb defines a callback for read and write access events on
* given characteristics
*/
{
/* Service: stdio */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = (ble_uuid_t *)&gatt_svr_svc_stdio_uuid.u,
.characteristics = (struct ble_gatt_chr_def[]) { {
/* Characteristic: stdout */
.uuid = (ble_uuid_t *)&gatt_svr_chr_stdout_uuid.u,
.access_cb = gatt_svr_chr_access_noop,
.val_handle = &_val_handle_stdout,
.flags = BLE_GATT_CHR_F_INDICATE,
}, {
/* Characteristic: stdin */
.uuid = (ble_uuid_t *)&gatt_svr_chr_stdin_uuid.u,
.access_cb = gatt_svr_chr_access_stdin,
.flags = BLE_GATT_CHR_F_WRITE,
}, {
0, /* No more characteristics in this service */
}, }
},
{
0, /* No more services */
},
};
static void _purge_buffer(void)
{
tsrb_clear(&_isrpipe_stdin.tsrb);
#if IS_USED(MODULE_SHELL)
/* send Ctrl-C to the shell to reset the input */
isrpipe_write_one(&_isrpipe_stdin, '\x03');
#endif
tsrb_clear(&_tsrb_stdout);
}
static void _send_stdout(struct ble_npl_event *ev)
{
(void)ev;
/* rearm callout */
ble_npl_callout_reset(&_send_stdout_callout, CALLOUT_TICKS_MS);
if (_status == STDIO_NIMBLE_SUBSCRIBED) {
_status = STDIO_NIMBLE_SENDING;
int to_send = tsrb_peek(&_tsrb_stdout, _stdout_write_buf, NIMBLE_MAX_PAYLOAD);
if (to_send > 0) {
struct os_mbuf *om = ble_hs_mbuf_from_flat(_stdout_write_buf, to_send);
if (om != NULL) {
int rc = ble_gattc_indicate_custom(_conn_handle, _val_handle_stdout, om);
if (rc == 0) {
/* bytes were successfully sent, so drop them from the buffer */
tsrb_drop(&_tsrb_stdout, to_send);
_debug_printf("%d bytes sent successfully\n", to_send);
}
else {
_status = STDIO_NIMBLE_SUBSCRIBED;
}
}
else {
_status = STDIO_NIMBLE_SUBSCRIBED;
}
}
else {
_status = STDIO_NIMBLE_SUBSCRIBED;
}
}
}
static int _gap_event_cb(struct ble_gap_event *event, void *arg)
{
(void)arg;
switch (event->type) {
case BLE_GAP_EVENT_CONNECT:
_debug_printf("BLE_GAP_EVENT_CONNECT\n");
if (event->connect.status == 0) {
_status = STDIO_NIMBLE_CONNECTED;
if (CONFIG_STDIO_NIMBLE_CLEAR_BUFFER_ON_CONNECT) {
_purge_buffer();
}
_conn_handle = event->connect.conn_handle;
}
else {
_status = STDIO_NIMBLE_DISCONNECTED;
}
break;
case BLE_GAP_EVENT_DISCONNECT:
_debug_printf("BLE_GAP_EVENT_DISCONNECT\n");
_status = STDIO_NIMBLE_DISCONNECTED;
break;
case BLE_GAP_EVENT_SUBSCRIBE:
_debug_printf("BLE_GAP_EVENT_SUBSCRIBE\n");
if (event->subscribe.attr_handle == _val_handle_stdout) {
if (event->subscribe.cur_indicate == 1) {
_status = STDIO_NIMBLE_SUBSCRIBED;
}
else {
_status = STDIO_NIMBLE_CONNECTED;
}
}
break;
case BLE_GAP_EVENT_NOTIFY_TX:
_debug_printf("BLE_GAP_EVENT_NOTIFY_TX\n");
if (event->notify_tx.indication == 1) {
if (event->notify_tx.status == BLE_HS_EDONE) {
_status = STDIO_NIMBLE_SUBSCRIBED;
}
else if (event->notify_tx.status != 0) {
_status = STDIO_NIMBLE_SUBSCRIBED;
}
}
break;
case BLE_GAP_EVENT_MTU:
_debug_printf("BLE_GAP_EVENT_MTU: mtu = %d\n", event->mtu.value);
break;
}
return 0;
}
static int gatt_svr_chr_access_stdin(
uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg)
{
(void)conn_handle;
(void)attr_handle;
(void)arg;
uint16_t om_len = OS_MBUF_PKTLEN(ctxt->om);
/* read sent data */
int rc = ble_hs_mbuf_to_flat(ctxt->om, _stdin_read_buf, sizeof(_stdin_read_buf), &om_len);
isrpipe_write(&_isrpipe_stdin, _stdin_read_buf, om_len);
return rc;
}
void stdio_init(void)
{
#if IS_USED(MODULE_VFS)
vfs_bind_stdio();
#endif
#if IS_USED(MODULE_STDIO_NIMBLE_DEBUG)
uart_init(STDIO_UART_DEV, STDIO_UART_BAUDRATE, NULL, NULL);
#endif
ble_npl_callout_init(&_send_stdout_callout, nimble_port_get_dflt_eventq(),
_send_stdout, NULL);
}
#if IS_USED(MODULE_STDIO_AVAILABLE)
int stdio_available(void)
{
return tsrb_avail(&_isrpipe_stdin.tsrb);
}
#endif
ssize_t stdio_read(void *buffer, size_t count)
{
/* blocks until at least one character was read */
ssize_t res = isrpipe_read(&_isrpipe_stdin, buffer, count);
#if IS_USED(MODULE_STDIO_NIMBLE_DEBUG)
unsigned state = irq_disable();
uart_write(STDIO_UART_DEV, (const uint8_t *)PREFIX_STDIN, strlen(PREFIX_STDIN));
uart_write(STDIO_UART_DEV, (const uint8_t *)buffer, res);
uart_write(STDIO_UART_DEV, (const uint8_t *)"\n", 1);
irq_restore(state);
#endif
return res;
}
ssize_t stdio_write(const void *buffer, size_t len)
{
unsigned state = irq_disable();
#if IS_USED(MODULE_STDIO_NIMBLE_DEBUG)
uart_write(STDIO_UART_DEV, (const uint8_t *)PREFIX_STDOUT, strlen(PREFIX_STDOUT));
uart_write(STDIO_UART_DEV, (const uint8_t *)buffer, len);
uart_write(STDIO_UART_DEV, (const uint8_t *)"\n", 1);
#endif
irq_restore(state);
unsigned int consumed = tsrb_add(&_tsrb_stdout, buffer, len);
if (!ble_npl_callout_is_active(&_send_stdout_callout)) {
/* bootstrap callout */
ble_npl_callout_reset(&_send_stdout_callout, CALLOUT_TICKS_MS);
}
return consumed;
}
/* is going to be called by auto_init */
void stdio_nimble_init(void)
{
int rc = 0;
/* verify and add our custom services */
rc = ble_gatts_count_cfg(_gatt_svr_svcs);
assert(rc == 0);
rc = ble_gatts_add_svcs(_gatt_svr_svcs);
assert(rc == 0);
/* reload the GATT server to link our added services */
ble_gatts_start();
/* register gap event listener */
rc = ble_gap_event_listener_register(&_gap_event_listener, _gap_event_cb, NULL);
assert(rc == 0);
/* fix compilation error when using DEVELHELP=0 */
(void)rc;
}

View File

@ -333,6 +333,25 @@ ssize_t vfs_write(int fd, const void *src, size_t count)
return filp->f_op->write(filp, src, count);
}
int vfs_fsync(int fd)
{
DEBUG_NOT_STDOUT(fd, "vfs_fsync: %d\n", fd);
int res = _fd_is_valid(fd);
if (res < 0) {
return res;
}
vfs_file_t *filp = &_vfs_open_files[fd];
if (((filp->flags & O_ACCMODE) != O_WRONLY) & ((filp->flags & O_ACCMODE) != O_RDWR)) {
/* File not open for writing */
return -EBADF;
}
if (filp->f_op->fsync == NULL) {
/* driver does not implement fsync() */
return -EINVAL;
}
return filp->f_op->fsync(filp);
}
int vfs_opendir(vfs_DIR *dirp, const char *dirname)
{
DEBUG("vfs_opendir: %p, \"%s\"\n", (void *)dirp, dirname);

View File

@ -23,6 +23,7 @@
#include <string.h>
#include "xtimer.h"
#include "atomic_utils.h"
#include "msg.h"
#include "mutex.h"
#include "rmutex.h"
@ -224,8 +225,7 @@ int xtimer_rmutex_lock_timeout(rmutex_t *rmutex, uint64_t timeout)
return 0;
}
if (xtimer_mutex_lock_timeout(&rmutex->mutex, timeout) == 0) {
atomic_store_explicit(&rmutex->owner,
thread_getpid(), memory_order_relaxed);
atomic_store_kernel_pid(&rmutex->owner, thread_getpid());
rmutex->refcount++;
return 0;
}

View File

@ -23,6 +23,7 @@
#include <assert.h>
#include <errno.h>
#include "atomic_utils.h"
#include "irq.h"
#include "mutex.h"
#include "rmutex.h"
@ -190,8 +191,7 @@ int ztimer_rmutex_lock_timeout(ztimer_clock_t *clock, rmutex_t *rmutex,
return 0;
}
if (ztimer_mutex_lock_timeout(clock, &rmutex->mutex, timeout) == 0) {
atomic_store_explicit(&rmutex->owner,
thread_getpid(), memory_order_relaxed);
atomic_store_kernel_pid(&rmutex->owner, thread_getpid());
rmutex->refcount++;
return 0;
}

View File

@ -23,6 +23,7 @@
#include <assert.h>
#include <errno.h>
#include "atomic_utils.h"
#include "irq.h"
#include "mutex.h"
#include "rmutex.h"
@ -183,8 +184,7 @@ int ztimer64_rmutex_lock_until(ztimer64_clock_t *clock, rmutex_t *rmutex,
return 0;
}
if (ztimer64_mutex_lock_until(clock, &rmutex->mutex, target) == 0) {
atomic_store_explicit(&rmutex->owner,
thread_getpid(), memory_order_relaxed);
atomic_store_kernel_pid(&rmutex->owner, thread_getpid());
rmutex->refcount++;
return 0;
}

View File

@ -2,6 +2,6 @@
This is a test application for the ON Semiconductor lc709203F Battery Fuel Gauge
# Usage
Just enter the `make BOARD=??? flash` command in the `tests/driver_lc709203F/` folder.
Make sure the `LC709203F_INT_PIN` is set in your boards periph_conf.h
Make sure the `LC709203F_PARAMS_ALARM_PIN` is set in your boards `board.h`
# Results
The sensor will first test the low RSOC interrupt by setting the threshold limit to 100%. Therefore a low RSOC interrupt should be triggered and the message "ALARM low RSOC" should be printed to the terminal. After that all major measurements will be printed and refreshed every 5s.

View File

@ -1,5 +1,5 @@
# this file enables modules defined in Kconfig. Do not use this file for
# application configuration. This is only needed during migration.
CONFIG_MODULE_MPU9150=y
CONFIG_MODULE_MPU9X50=y
CONFIG_MODULE_ZTIMER=y
CONFIG_MODULE_ZTIMER_MSEC=y

View File

@ -0,0 +1,6 @@
include ../Makefile.tests_common
EXTERNAL_PKG_DIRS += external_pkgs
USEPKG += external_pkg
include $(RIOTBASE)/Makefile.include

View File

@ -0,0 +1,16 @@
external_pkg_dirs
=================
Test application for the EXTERNAL_PKG_DIRS feature of the buildsystem.
Two external packages are provided in `external_pkgs/`: `external_pkg` and
`external_pkg_not_used`. If the first package is not properly included, a define
from `CFLAGS` is missing and a precompiler error is triggered. If the second
package somehow ends up included it triggers a makefile error.
Usage
=====
Set `EXTERNAL_PKG_DIRS` inside Makefile to point to other paths where the
buildsystem can look for packages. Similar functionality to `EXTERNAL_PKG_DIRS`.
Be careful to not name these externally provided packages the same as existing
packages in `$(RIOTBASE)/pkg/`.

View File

@ -0,0 +1 @@
CONFIG_PACKAGE_EXTERNAL_PKG=y

View File

@ -0,0 +1,9 @@
# Copyright (c) 2022 Niklaus Leuenberger
#
# 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.
config PACKAGE_EXTERNAL_PKG
bool "external_pkg package"
depends on TEST_KCONFIG

View File

@ -0,0 +1,16 @@
PKG_NAME = external_pkg
include $(RIOTBASE)/Makefile.base
.PHONY: all prepare clean distclean
all: prepare
prepare:
@:
clean::
rm -rf $(BINDIR)/pkg/$(PKG_NAME)
distclean::
rm -rf $(BINDIR)/pkg/$(PKG_NAME)

View File

@ -0,0 +1 @@
CFLAGS += -DTEST_EXTERNAL_PKG

View File

@ -0,0 +1,9 @@
# Copyright (c) 2022 Niklaus Leuenberger
#
# 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.
config PACKAGE_EXTERNAL_PKG_NOT_USED
bool "external_pkg_not_used package"
depends on TEST_KCONFIG

View File

@ -0,0 +1,19 @@
PKG_NAME = external_pkg_not_used
include $(RIOTBASE)/Makefile.base
.PHONY: all prepare clean distclean
all:
$(error target all for external_pkg_not_used executed)
prepare:
$(error target prepare for external_pkg_not_used executed)
clean::
rm -rf $(BINDIR)/pkg/$(PKG_NAME)
$(error target clean for external_pkg_not_used executed)
distclean::
rm -rf $(BINDIR)/pkg/$(PKG_NAME)
$(error target distclean for external_pkg_not_used executed)

View File

@ -0,0 +1 @@
CFLAGS += -DTEST_EXTERNAL_PKG_NOT_USED

View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 2021 Niklaus Leuenberger
*
* 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 tests
* @{
*
* @file
* @brief This is a test for the EXTERNAL_PKG_DIRS variable.
*
* @author Niklaus Leuenberger <niklaus.leuenb@gmail.com>
*
* @}
*/
#include <stdio.h>
#ifndef TEST_EXTERNAL_PKG
#error "Required external package not included."
#endif
#ifdef TEST_EXTERNAL_PKG_NOT_USED
#error "External package included that shouldn't be."
#endif
int main(void)
{
puts("If it compiles, it works!");
return 0;
}

View File

@ -4,4 +4,12 @@ USEMODULE += external_module_1
USEMODULE += external_module_2
EXTERNAL_MODULE_DIRS += external_modules
USEPKG += external_pkg_1
USEPKG += external_pkg_2
EXTERNAL_PKG_DIRS += external_pkgs
ifeq (1, $(TEST_KCONFIG))
KCONFIG_ADD_CONFIG += $(APPDIR)/app.config
endif
include $(RIOTBASE)/Makefile.include

View File

@ -9,3 +9,7 @@ CONFIG_APP_MSG_2=y
# enable configuration of external modules via kconfig
CONFIG_KCONFIG_EXTERNAL_MODULE_1=y
CONFIG_KCONFIG_EXTERNAL_MODULE_2=y
# enable configuration of external packages via kconfig
CONFIG_KCONFIG_EXTERNAL_PKG_1=y
CONFIG_KCONFIG_EXTERNAL_PKG_2=y

Some files were not shown because too many files have changed in this diff Show More