diff --git a/boards/common/slwstk6000b/Makefile.dep b/boards/common/slwstk6000b/Makefile.dep index eb037e258785..a7e794bac29a 100644 --- a/boards/common/slwstk6000b/Makefile.dep +++ b/boards/common/slwstk6000b/Makefile.dep @@ -8,5 +8,11 @@ USEMODULE += boards_common_silabs USEMODULE += silabs_aem USEMODULE += silabs_bc +ifneq (,$(filter netdev_default,$(USEMODULE))) + ifeq (1,$(EFM32_RADIO)) + USEMODULE += rail + endif +endif + # include board common dependencies include $(RIOTBOARD)/common/silabs/Makefile.dep diff --git a/boards/ikea-tradfri/Makefile.dep b/boards/ikea-tradfri/Makefile.dep index 5472bf8b8d8f..48341b21bc4e 100644 --- a/boards/ikea-tradfri/Makefile.dep +++ b/boards/ikea-tradfri/Makefile.dep @@ -1,3 +1,8 @@ ifneq (,$(filter saul_default,$(USEMODULE))) USEMODULE += saul_gpio endif + +ifneq (,$(filter netdev_default,$(USEMODULE))) + USEMODULE += rail +endif + diff --git a/boards/ikea-tradfri/include/rail_radio.h b/boards/ikea-tradfri/include/rail_radio.h new file mode 100644 index 000000000000..13005a5f9c1d --- /dev/null +++ b/boards/ikea-tradfri/include/rail_radio.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2018 Hochschule RheinMain + * + * 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 boards_ikea-tradfri + * @{ + * + * @file + * @brief Board specific definitions for the radio transceiver of the + * Ikea Tradfi module + * + * @author Kai Beckmann + **/ + +#ifndef RAIL_RADIO_H +#define RAIL_RADIO_H + +#include "cpu.h" + +#include "periph_conf.h" +#include "periph/gpio.h" +#include "periph/spi.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Select radio frequency + * + * ikea tradfri supports only 2.4 GHz + */ +#define RAIL_RADIO_BAND (2400) + +/** + * @brief Setting for the radio PA voltage in mV + * + * voltage of the radio PA in mV + * + * The setting depends on the module. + * + * the tradfi modules embedded in lamps are + * connected to th external dc-dc, therefore 3.3V + */ +#define RAIL_RADIO_PA_VOLTAGE (3300) + +/** + * @brief Packet Trace Interface + * + * The Tradfri doesn't support PTI, + * so don't enable it. + */ +#ifndef RAIL_PTI_ENABLED +#define RAIL_PTI_ENABLED (0) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* RAIL_RADIO_H */ +/** @} */ diff --git a/boards/sltb001a/Makefile.dep b/boards/sltb001a/Makefile.dep index 24169dab9c91..18b2e0248b75 100644 --- a/boards/sltb001a/Makefile.dep +++ b/boards/sltb001a/Makefile.dep @@ -9,5 +9,9 @@ endif USEMODULE += boards_common_silabs USEMODULE += silabs_pic +ifneq (,$(filter netdev_default,$(USEMODULE))) + USEMODULE += rail +endif + # include board common dependencies include $(RIOTBOARD)/common/silabs/Makefile.dep diff --git a/boards/sltb001a/include/rail_radio.h b/boards/sltb001a/include/rail_radio.h new file mode 100644 index 000000000000..423bcadfbaef --- /dev/null +++ b/boards/sltb001a/include/rail_radio.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2018 Hochschule RheinMain + * + * 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 boards_sltb001a + * @{ + * + * @file + * @brief Board specific definitions for the radio transceiver of the + * SLTB001A starter kit + * + * @author Kai Beckmann + **/ + +#ifndef RAIL_RADIO_H +#define RAIL_RADIO_H + +#include "cpu.h" + +#include "periph_conf.h" +#include "periph/gpio.h" +#include "periph/spi.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Select radio frequency + * + * the SLTB001A supports only 2.4 GHz + */ +#define RAIL_RADIO_BAND (2400) + +/** + * @brief Setting for the radio PA voltage in mV + * + * voltage of the radio PA in mV + * + * The setting depends on the module. + * + * TODO what voltage has the SLTB001A? + */ +#define RAIL_RADIO_PA_VOLTAGE (1800) + +/** + * @brief Packet Trace Interface + * + * To enable the PTI set vaule to 1. + * In RAIL_PTI_CONFIG the correct pins + * have to be configured + * + * Enable only for the SLTB001a if external debugger is + * used. + */ +#ifndef RAIL_PTI_ENABLED +#define RAIL_PTI_ENABLED (0) +#endif + +/* c&p from gecko-sdk BSP for EFR32MG1_BRD4154A */ +/* should work for sltb001a as well */ +#if !defined(RAIL_PTI_CONFIG) +#define RAIL_PTI_CONFIG \ + { \ + RAIL_PTI_MODE_UART, /* Only supported output mode for the WSTK*/ \ + 1600000, /* Choose 1.6 MHz for best the WSTK */ \ + 6, /* WSTK uses location 6 for DOUT PB12 */ \ + gpioPortB, /* FRC_DOUT#6 is PB12 */ \ + 12, /* FRC_DOUT#6 is PB12 */ \ + 6, /* UNUSED IN UART MODE */ \ + gpioPortB, /* UNUSED IN UART MODE */ \ + 11, /* UNUSED IN UART MODE */ \ + 6, /* WSTK uses location 6 for DFRAME */ \ + gpioPortB, /* RC_DOUT#6 is PB13 */ \ + 13, /* RC_DOUT#6 is PB13 */ \ + } +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* RAIL_RADIO_H */ +/** @} */ diff --git a/boards/slwstk6000b-slwrb4150a/include/rail_radio.h b/boards/slwstk6000b-slwrb4150a/include/rail_radio.h new file mode 100644 index 000000000000..ee170591cc34 --- /dev/null +++ b/boards/slwstk6000b-slwrb4150a/include/rail_radio.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2017-2018 Hochschule RheinMain + * + * 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 boards_slwstk6000b Silicon Labs SLWSTK6000B starter kit + * @ingroup boards + * @brief Support for the Silicon Labs SLWRB4150a module + * @{ + * + * @file + * @brief Board specific definitions for the radio transceicer of the + * SLWRB4150a module + * + * @author Kai Beckmann + **/ + +#ifndef RAIL_RADIO_H +#define RAIL_RADIO_H + +#include "cpu.h" + +#include "periph_conf.h" +#include "periph/gpio.h" +#include "periph/spi.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Select radio frequency + * + * SLWRB4150a supports 2400, 868, 915 + * + */ +#ifndef RAIL_RADIO_BAND +#define RAIL_RADIO_BAND (868) +#endif + +/** + * @brief Setting for the radio PA voltage in mV + * + * voltage of the radio PA in mV + * + * The setting depends on the module. + * + * The silabs dev modules are connected to + * the internal dc/dc -> 1.8V + */ +#define RAIL_RADIO_PA_VOLTAGE (1800) + +/** + * @brief Packet Trace Interface + * + * To enable the PTI set vaule to 1. + * In RAIL_PTI_CONFIG the correct pins + * have to be configured + */ +#ifndef RAIL_PTI_ENABLED +#define RAIL_PTI_ENABLED (0) +#endif + +/** + * c&p from gecko-sdk BSP for EFR32MG1_BRD4154A + */ +#if !defined(RAIL_PTI_CONFIG) +#define RAIL_PTI_CONFIG \ + { \ + RAIL_PTI_MODE_UART, /* Only supported output mode for the WSTK*/ \ + 1600000, /* Choose 1.6 MHz for best the WSTK */ \ + 6, /* WSTK uses location 6 for DOUT PB12 */ \ + gpioPortB, /* FRC_DOUT#6 is PB12 */ \ + 12, /* FRC_DOUT#6 is PB12 */ \ + 6, /* UNUSED IN UART MODE */ \ + gpioPortB, /* UNUSED IN UART MODE */ \ + 11, /* UNUSED IN UART MODE */ \ + 6, /* WSTK uses location 6 for DFRAME */ \ + gpioPortB, /* RC_DOUT#6 is PB13 */ \ + 13, /* RC_DOUT#6 is PB13 */ \ + } +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* RAIL_RADIO_H */ +/** @} */ diff --git a/boards/slwstk6000b-slwrb4162a/include/rail_radio.h b/boards/slwstk6000b-slwrb4162a/include/rail_radio.h new file mode 100644 index 000000000000..2ca13f093e68 --- /dev/null +++ b/boards/slwstk6000b-slwrb4162a/include/rail_radio.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2017-2018 Hochschule RheinMain + * + * 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 boards_slwstk6000b Silicon Labs SLWSTK6000B starter kit + * @ingroup boards + * @brief Support for the Silicon Labs SLWRB4162a module + * @{ + * + * @file + * @brief Board specific definitions for the radio transceicer of the + * SLWRB4162a module + * + * @author Kai Beckmann + **/ + +#ifndef RAIL_RADIO_H +#define RAIL_RADIO_H + +#include "cpu.h" + +#include "periph_conf.h" +#include "periph/gpio.h" +#include "periph/spi.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Select radio frequency + * + * SLWRB4162a supports only 2.4 GHz + */ +#define RAIL_RADIO_BAND (2400) + +/** + * @brief Setting for the radio PA voltage in mV + * + * voltage of the radio PA in mV + * + * The setting depends on the module. + * + * The silabs dev modules are connected to + * the internal dc/dc -> 1.8V + */ +#define RAIL_RADIO_PA_VOLTAGE (1800) + +/** + * @brief Packet Trace Interface + * + * To enable the PTI set vaule to 1. + * In RAIL_PTI_CONFIG the correct pins + * have to be configured + */ +#ifndef RAIL_PTI_ENABLED +#define RAIL_PTI_ENABLED (0) +#endif + +/** + * c&p from gecko-sdk BSP for EFR32MG1_BRD4154A + */ +#if !defined(RAIL_PTI_CONFIG) +#define RAIL_PTI_CONFIG \ + { \ + RAIL_PTI_MODE_UART, /* Only supported output mode for the WSTK*/ \ + 1600000, /* Choose 1.6 MHz for best the WSTK */ \ + 6, /* WSTK uses location 6 for DOUT PB12 */ \ + gpioPortB, /* FRC_DOUT#6 is PB12 */ \ + 12, /* FRC_DOUT#6 is PB12 */ \ + 6, /* UNUSED IN UART MODE */ \ + gpioPortB, /* UNUSED IN UART MODE */ \ + 11, /* UNUSED IN UART MODE */ \ + 6, /* WSTK uses location 6 for DFRAME */ \ + gpioPortB, /* RC_DOUT#6 is PB13 */ \ + 13, /* RC_DOUT#6 is PB13 */ \ + } +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* RAIL_RADIO_H */ +/** @} */ diff --git a/drivers/Makefile.dep b/drivers/Makefile.dep index d5feed1f52b0..29ea8b205977 100644 --- a/drivers/Makefile.dep +++ b/drivers/Makefile.dep @@ -136,6 +136,18 @@ ifneq (,$(filter atwinc15x0,$(USEMODULE))) FEATURES_REQUIRED += periph_spi endif +ifneq (,$(filter rail,$(USEMODULE))) + USEPKG += gecko_sdk + USEMODULE += xtimer + USEMODULE += luid + USEMODULE += netif + USEMODULE += ieee802154 + USEMODULE += netdev_ieee802154 + USEMODULE += gecko_sdk_librail + USEMODULE += netopt + USEMODULE += core_thread_flags +endif + ifneq (,$(filter bh1750fvi,$(USEMODULE))) USEMODULE += xtimer FEATURES_REQUIRED += periph_i2c diff --git a/drivers/Makefile.include b/drivers/Makefile.include new file mode 100644 index 000000000000..05a9c65b7910 --- /dev/null +++ b/drivers/Makefile.include @@ -0,0 +1,437 @@ +# driver includes (in alphabetical order) + +ifneq (,$(filter ad7746,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/ad7746/include +endif + +ifneq (,$(filter adcxx1c,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/adcxx1c/include +endif + +ifneq (,$(filter ads101x,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/ads101x/include +endif + +ifneq (,$(filter adxl345,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/adxl345/include +endif + +ifneq (,$(filter apa102,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/apa102/include +endif + +ifneq (,$(filter apds99xx,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/apds99xx/include +endif + +ifneq (,$(filter at24cxxx,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/at24cxxx/include +endif + +ifneq (,$(filter at24mac,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/at24mac/include +endif + +ifneq (,$(filter at25xxx,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/at25xxx/include +endif + +ifneq (,$(filter at86rf2xx,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/at86rf2xx/include +endif + +ifneq (,$(filter at86rf215,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/at86rf215/include +endif + +ifneq (,$(filter ata8520e,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/ata8520e/include +endif + +ifneq (,$(filter atwinc15x0,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/atwinc15x0/include +endif + +ifneq (,$(filter bh1750fvi,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/bh1750fvi/include +endif + +ifneq (,$(filter bh1900nux,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/bh1900nux/include +endif + +ifneq (,$(filter bme680_%,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/bme680/include +endif + +ifneq (,$(filter bmp180,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/bmp180/include +endif + +ifneq (,$(filter bmx055,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/bmx055/include +endif + +ifneq (,$(filter bmx280,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/bmx280/include +endif + +ifneq (,$(filter rail,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/rail/include + include $(RIOTBASE)/drivers/rail/Makefile.include +endif +ifneq (,$(filter cc110x,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/cc110x/include +endif + +ifneq (,$(filter cc2420,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/cc2420/include +endif + +ifneq (,$(filter ccs811,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/ccs811/include +endif + +ifneq (,$(filter dcf77,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/dcf77/include +endif + +ifneq (,$(filter dfplayer,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/dfplayer/include + ifneq (,$(filter arch_avr8 arch_msp430,$(FEATURES_USED))) + # no strerror() on AVR and MSP430 + CFLAGS += -DDFPLAYER_NO_STRERROR + endif +endif + +ifneq (,$(filter dht,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/dht/include +endif + +ifneq (,$(filter ds1307,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/ds1307/include +endif + +ifneq (,$(filter ds18,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/ds18/include +endif + +ifneq (,$(filter ds3234,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/ds3234/include +endif + +ifneq (,$(filter ds75lx,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/ds75lx/include +endif + +ifneq (,$(filter dsp0401,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/dsp0401/include +endif + +ifneq (,$(filter dynamixel,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/dynamixel/include +endif + +ifneq (,$(filter enc28j60,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/enc28j60/include +endif + +ifneq (,$(filter encx24j600,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/encx24j600/include +endif + +ifneq (,$(filter dose,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/dose/include +endif + +ifneq (,$(filter feetech,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/feetech/include +endif + +ifneq (,$(filter fxos8700,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/fxos8700/include +endif + +ifneq (,$(filter grove_ledbar,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/grove_ledbar/include +endif + +ifneq (,$(filter hd44780,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/hd44780/include +endif + +ifneq (,$(filter hdc1000,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/hdc1000/include +endif + +ifneq (,$(filter hmc5883l,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/hmc5883l/include +endif + +ifneq (,$(filter hts221,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/hts221/include +endif + +ifneq (,$(filter ili9341,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/ili9341/include +endif + +ifneq (,$(filter ina2xx,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/ina2xx/include +endif + +ifneq (,$(filter ina3221,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/ina3221/include +endif + +ifneq (,$(filter io1_xplained,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/io1_xplained/include +endif + +ifneq (,$(filter isl29020,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/isl29020/include +endif + +ifneq (,$(filter isl29125,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/isl29125/include +endif + +ifneq (,$(filter itg320x,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/itg320x/include +endif + +ifneq (,$(filter jc42,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/jc42/include +endif + +ifneq (,$(filter kw2xrf,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/kw2xrf/include +endif + +ifneq (,$(filter kw41zrf,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/kw41zrf/include +endif + +ifneq (,$(filter l3g4200d,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/l3g4200d/include +endif + +ifneq (,$(filter lc709203f, $(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/lc709203f/include +endif + +ifneq (,$(filter lis2dh12,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/lis2dh12/include +endif + +ifneq (,$(filter lis3dh,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/lis3dh/include +endif + +ifneq (,$(filter lis3mdl,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/lis3mdl/include +endif + +ifneq (,$(filter lpd8808,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/lpd8808/include +endif + +ifneq (,$(filter lpsxxx,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/lpsxxx/include +endif + +ifneq (,$(filter lsm303dlhc,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/lsm303dlhc/include +endif + +ifneq (,$(filter lsm6dsl,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/lsm6dsl/include +endif + +ifneq (,$(filter ltc4150,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/ltc4150/include +endif + +ifneq (,$(filter mag3110,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/mag3110/include +endif + +ifneq (,$(filter mhz19,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/mhz19/include +endif + +ifneq (,$(filter mma7660,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/mma7660/include +endif + +ifneq (,$(filter mma8x5x,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/mma8x5x/include +endif + +ifneq (,$(filter mpl3115a2,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/mpl3115a2/include +endif + +ifneq (,$(filter mpu9x50,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/mpu9x50/include +endif + +ifneq (,$(filter mrf24j40,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/mrf24j40/include +endif + +ifneq (,$(filter my9221,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/my9221/include +endif + +ifneq (,$(filter nrf24l01p,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/nrf24l01p/include +endif + +ifneq (,$(filter opt3001,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/opt3001/include +endif + +ifneq (,$(filter pca9633,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/pca9633/include +endif + +ifneq (,$(filter pca9685,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/pca9685/include +endif + +ifneq (,$(filter pcd8544,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/pcd8544/include +endif + +ifneq (,$(filter ph_oem,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/ph_oem/include +endif + +ifneq (,$(filter pir,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/pir/include +endif + +ifneq (,$(filter pulse_counter,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/pulse_counter/include +endif + +ifneq (,$(filter qmc5883l,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/qmc5883l/include +endif + +ifneq (,$(filter rn2xx3,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/rn2xx3/include +endif + +ifneq (,$(filter sdcard_spi,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/sdcard_spi/include +endif + +ifneq (,$(filter sdp3x,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/sdp3x/include +endif + +ifneq (,$(filter sds011,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/sds011/include +endif + +ifneq (,$(filter sht1x,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/sht1x/include +endif + +ifneq (,$(filter sht2x,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/sht2x/include +endif + +ifneq (,$(filter sht3x,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/sht3x/include +endif + +ifneq (,$(filter shtc1,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/shtc1/include +endif + +ifneq (,$(filter si114x,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/si114x/include +endif + +ifneq (,$(filter si70xx,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/si70xx/include +endif + +ifneq (,$(filter slipdev,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/slipdev/include +endif + +ifneq (,$(filter soft_spi,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/soft_spi/include +endif + +ifneq (,$(filter soft_uart,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/soft_uart/include +endif + +ifneq (,$(filter sps30,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/sps30/include +endif + +ifneq (,$(filter srf04,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/srf04/include +endif + +ifneq (,$(filter srf08,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/srf08/include +endif + +ifneq (,$(filter stmpe811,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/stmpe811/include +endif + +ifneq (,$(filter sx127x,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/sx127x/include +endif + +ifneq (,$(filter tcs37727,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/tcs37727/include +endif + +ifneq (,$(filter tmp00x,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/tmp00x/include +endif + +ifneq (,$(filter tps6274x,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/tps6274x/include +endif + +ifneq (,$(filter tsl2561,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/tsl2561/include +endif + +ifneq (,$(filter tsl4531x,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/tsl4531x/include +endif + +ifneq (,$(filter uart_half_duplex,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/uart_half_duplex/include +endif + +ifneq (,$(filter vcnl40x0,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/vcnl40x0/include +endif + +ifneq (,$(filter veml6070,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/veml6070/include +endif + +ifneq (,$(filter w5100,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/w5100/include +endif + +ifneq (,$(filter ws281x,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/ws281x/include +endif + +ifneq (,$(filter xbee,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/xbee/include +endif diff --git a/drivers/include/rail_drv.h b/drivers/include/rail_drv.h new file mode 100644 index 000000000000..7ff4df360275 --- /dev/null +++ b/drivers/include/rail_drv.h @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2018 Hochschule RheinMain + * + * 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 drivers_rail Silabs EFR32 radio driver + * @ingroup drivers_netdev + * + * This module contains drivers for the embedded radio transceivers in + * Silabs EFR32 SoCs using the probritary librail API. + * The driver is aimed to work with all devices of this series. + * + * @{ + * + * @file + * @brief Interface definition for Silabs EFR32 based drivers + * + * @author Kai Beckmann + */ + +#ifndef RAIL_DRV_H +#define RAIL_DRV_H + +#include +#include + +#include "board.h" +#include "periph/spi.h" +#include "periph/gpio.h" +#include "net/netdev.h" +#include "net/netdev/ieee802154.h" +#include "net/gnrc/nettype.h" +#include "net/eui64.h" + +#include "ringbuffer.h" +#include "thread_flags.h" + +#include "rail.h" + +#include "rail_helper.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name Channel configuration + * @{ + */ +/* TODO replace with netdev_ieee802154 rework */ +#define RAIL_868MHZ_MIN_CHANNEL (IEEE802154_CHANNEL_MIN_SUBGHZ) +#define RAIL_868MHZ_MAX_CHANNEL (IEEE802154_CHANNEL_MIN_SUBGHZ) /* 868MHz has only ONE channel! */ +#define RAIL_868MHZ_DEFAULT_CHANNEL (IEEE802154_CHANNEL_MIN_SUBGHZ) +#define RAIL_912MHZ_MIN_CHANNEL (IEEE802154_CHANNEL_MIN_SUBGHZ) +#define RAIL_912MHZ_MAX_CHANNEL (IEEE802154_CHANNEL_MAX_SUBGHZ) +#define RAIL_912MHZ_DEFAULT_CHANNEL (IEEE802154_DEFAULT_SUBGHZ_CHANNEL) +/* Page 2 is O-QPSK 100 kbit/s (channel 0), or 250 kbit/s (channels 1-10) */ +#define RAIL_SUBGHZ_DEFAULT_PAGE (IEEE802154_DEFAULT_SUBGHZ_PAGE) +#define RAIL_2P4GH_MIN_CHANNEL (IEEE802154_CHANNEL_MIN) +#define RAIL_2P4GH_MAX_CHANNEL (IEEE802154_CHANNEL_MAX) +#define RAIL_2P4GH_DEFAULT_CHANNEL (IEEE802154_DEFAULT_CHANNEL) +/* Only page 0 is supported in the 2.4 GHz band */ + +/** @} */ + + + +#if (_SILICON_LABS_EFR32_RADIO_TYPE == _SILICON_LABS_EFR32_RADIO_SUBGHZ) +#define RAIL_RADIO_HAS_SUBGHZ +#endif +#if (_SILICON_LABS_EFR32_RADIO_TYPE == _SILICON_LABS_EFR32_RADIO_DUALBAND) +#define RAIL_RADIO_HAS_SUBGHZ +#define RAIL_RADIO_HAS_2G4HZ +#define RAIL_RADIO_HAS_SUBGHZ +#endif +#if (_SILICON_LABS_EFR32_RADIO_TYPE == _SILICON_LABS_EFR32_RADIO_2G4HZ) +#define RAIL_RADIO_HAS_2G4HZ +#endif + +#ifdef DOXYGEN +/** + * @brief Set if radio transceiver supports 2.4 GHz + * + */ +#define RAIL_RADIO_HAS_2G4HZ +/** + * @brief Set if radio transceiver supports sub GHz + * + */ +#define RAIL_RADIO_HAS_SUBGHZ + +#endif + +/** + * @name radio transceiver states + * @{ + */ +/* TODO + - use enum? + - use ! + */ +#define RAIL_TRANSCEIVER_STATE_UNINITIALIZED (0x00) +#define RAIL_TRANSCEIVER_STATE_IDLE (0x01) +#define RAIL_TRANSCEIVER_STATE_SLEEP (0x02) +#define RAIL_TRANSCEIVER_STATE_OFF (0x03) +#define RAIL_TRANSCEIVER_STATE_RX (0x04) +#define RAIL_TRANSCEIVER_STATE_TX (0x05) + +/** @} */ + +/** + * @brief default panid for rail + */ +#define RAIL_DEFAULT_PANID (CONFIG_IEEE802154_DEFAULT_PANID) + +/** + * @brief default tx power + */ +#define RAIL_DEFAULT_TXPOWER (CONFIG_IEEE802154_DEFAULT_TXPOWER) +/** + * @brief default CSMA retries + */ +#define RAIL_DEFAULT_CSMA_TRIES (5) + +/** + * @brief enum for the three supported radio bands + */ +enum rail_transceiver_config_frequency { + RAIL_TRANSCEIVER_FREQUENCY_2P4GHZ, /**< 2.4GHz */ + RAIL_TRANSCEIVER_FREQUENCY_868MHZ, /**< EU 868 MHz band */ + RAIL_TRANSCEIVER_FREQUENCY_912MHZ /** US 912 MHz band */ +}; + +/** + * @brief This is active while the netdev thread needs to handle events while + * blocking. Set this to a flag bit that is not used by the MAC implementation. + */ +#define RAIL_THREAD_FLAG_ISR (1u << 8) + +/** + * @brief struct holding all params needed for device initialization + */ +typedef struct rail_params { + enum rail_transceiver_config_frequency freq; /**< radio band to operate */ + /* TODO possible other options for future extension: */ + /* RAIL_RADIO_PA_VOLTAGE */ + /* RAIL_DEFAULT_TXPOWER */ + /* RAIL_DEFAULT_PANID */ + /* IEEE802154_DEFAULT_CHANNEL */ + /* isPanCoordinator */ + /* auto ack on / off */ + /* auto ack timeout */ + +} rail_params_t; + +/** + * @brief Device descriptor for Silabs EFR32 rail radio devices + * + * @extends netdev_ieee802154_t + */ +typedef struct { + netdev_ieee802154_t netdev; /**< inherited from netdev_ieee802154_t */ + rail_params_t params; /**< the params for the driver */ + + RAIL_Handle_t rhandle; /**< handle of the RAIL driver blob instance */ + RAIL_Config_t rconfig; /**< config of the RAIL driver blob */ + RAIL_CsmaConfig_t csma_config; /**< config for CSMA */ + + uint8_t state; /**< state of the radio transceiver */ + + rail_event_queue_t event_queue; /**< event queue for the netdev layer */ + + uint32_t event_count; /**< stat / debug info, how many rail events have occured */ + + bool promiscuousMode; /**< flag if set to promiscuous mode */ + +#if defined(RAIL_RADIO_HAS_SUBGHZ) || defined(DOXYGEN) + uint8_t channel_page; /**< current configured channel page */ +#endif + thread_t *thread; /**< Network driver thread, for providing feedback from IRQ handler */ + bool send_in_progress; /**< True while waiting for a TX to finish */ + uint8_t num_retrans; /**< Counter used internally by send implementation */ + uint8_t max_retrans; /**< Maximum number of frame retransmissions when no Ack frame is received */ +} rail_t; + +/** + * @brief Setup an Silabs EFR32 rail based device + * + * @param[out] dev device descriptor + * @param[in] params parameters for device initialization + */ +void rail_setup(rail_t *dev, const rail_params_t *params); + +/** + * @brief configures radio with default values + * + * @param[in,out] dev device to reset + */ +int rail_init(rail_t *dev); + +/** + * @brief set the radio into receive mode + * + * @param[in] dev device + */ +int rail_start_rx(rail_t *dev); + +/** + * @brief transmit a packet + * + * @param[in] dev radio device + * @param[in] data_ptr pointer to packet to transmit + * @param[in] data_length size of packet + */ +int rail_transmit_frame(rail_t *dev, uint8_t *data_ptr, size_t data_length); + +#ifdef __cplusplus +} +#endif + +#endif /* RAIL_DRV_H */ + +/** @} */ diff --git a/drivers/rail/Makefile b/drivers/rail/Makefile new file mode 100644 index 000000000000..48422e909a47 --- /dev/null +++ b/drivers/rail/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/drivers/rail/Makefile.include b/drivers/rail/Makefile.include new file mode 100644 index 000000000000..2ec823492734 --- /dev/null +++ b/drivers/rail/Makefile.include @@ -0,0 +1,20 @@ +USEMODULE_INCLUDES_rail := $(LAST_MAKEFILEDIR)/include + +#RAIL_SDK_DIR = $(RIOTBASE)/pkg/gecko-sdk/sdk/ +RAIL_SDK_SRCDIR = $(PKGDIRBASE)/gecko_sdk/dist/radio/rail_lib + +RAIL_INCLUDES += -I$(RAIL_SDK_SRCDIR)/common +RAIL_INCLUDES += -I$(RAIL_SDK_SRCDIR)/protocol +RAIL_INCLUDES += -I$(RAIL_SDK_SRCDIR)/chip/efr32/efr32xg1x +RAIL_INCLUDES += -I$(RAIL_SDK_SRCDIR)/plugin/pa-conversions + +#RAIL_INCLUDES += -I$(RAIL_SDK_DIR)/hardware/kit/common/bsp/ +# if thunderbird +#RAIL_INCLUDES += -I$(RAIL_SDK_DIR)/hardware/kit/EFR32MG1_BRD4160A/config/ + + +export INCLUDES += $(RAIL_INCLUDES) + +export RAIL_SDK_SRCDIR + +USEMODULE_INCLUDES += $(USEMODULE_INCLUDES_rail) diff --git a/drivers/rail/include/rail_802154_config.h b/drivers/rail/include/rail_802154_config.h new file mode 100644 index 000000000000..9a7e8a011ca9 --- /dev/null +++ b/drivers/rail/include/rail_802154_config.h @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2018 Hochschule RheinMain + * + * 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 drivers_rail + * @{ + * + * @file + * @brief low level radio configuration for IEEE 802.15.4 mode on 868 MHz + * + * @author Kai Beckmann + */ + +#ifndef RAIL_802154_CONFIG_H +#define RAIL_802154_CONFIG_H + +#include "rail_radio.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief RAIL Configuration + * + * @copyright Copyright 2016 Silicon Laboratories, Inc. http://www.silabs.com + * + * Adapted form mbed + * https://github.com/ARMmbed/mbed-os/blob/master/targets/TARGET_Silicon_Labs/TARGET_SL_RAIL/efr32-rf-driver/rail/TARGET_EFR32_1/ieee802154_subg_efr32xg1_configurator_out.c + * + * @{ + */ +#if (RAIL_RADIO_BAND == 868) || (RAIL_RADIO_BAND == 915) + +#if defined(MODULE_CPU_EFR32MG1P) +#ifndef RAIL_IEEE802154_CONFIG_868MHZ +#define RAIL_IEEE802154_CONFIG_868MHZ RAIL_IEEE802154_CONFIG_868MHZ_EFR32MG1P +#endif + +#ifndef RAIL_IEEE802154_CONFIG_915MHZ +#define RAIL_IEEE802154_CONFIG_915MHZ RAIL_IEEE802154_CONFIG_915MHZ_EFR32MG1P +#endif + +#else +#error "rail_802154_config.h: No radio config for subghz IEEE 802.15.4" +#endif + +#define RAIL_IEEE802154_CONFIG_868MHZ_EFR32MG1P { \ + 0x01010FF4UL, 0x00000000UL, \ + 0x01010FF8UL, 0x0003C000UL, \ + 0x01010FFCUL, 0x0003C008UL, \ + 0x00010004UL, 0x00157001UL, \ + 0x00010008UL, 0x0000007FUL, \ + 0x00010018UL, 0x00000000UL, \ + 0x0001001CUL, 0x00000000UL, \ + 0x00010028UL, 0x00000000UL, \ + 0x0001002CUL, 0x00000000UL, \ + 0x00010030UL, 0x00000000UL, \ + 0x00010034UL, 0x00000000UL, \ + 0x0001003CUL, 0x00000000UL, \ + 0x00010040UL, 0x000007A0UL, \ + 0x00010048UL, 0x00000000UL, \ + 0x00010054UL, 0x00000000UL, \ + 0x00010058UL, 0x00000000UL, \ + 0x000100A0UL, 0x00004000UL, \ + 0x000100A4UL, 0x00004CFFUL, \ + 0x000100A8UL, 0x00004100UL, \ + 0x000100ACUL, 0x00004DFFUL, \ + 0x00012000UL, 0x00000704UL, \ + 0x00012010UL, 0x00000000UL, \ + 0x00012018UL, 0x00008408UL, \ + 0x00013008UL, 0x0000AC3FUL, \ + 0x0001302CUL, 0x021EB000UL, \ + 0x00013030UL, 0x00108000UL, \ + 0x00013034UL, 0x00000003UL, \ + 0x0001303CUL, 0x00014000UL, \ + 0x00013040UL, 0x00000000UL, \ + 0x000140A0UL, 0x0F00277AUL, \ + 0x000140F4UL, 0x00001020UL, \ + 0x00014134UL, 0x00000880UL, \ + 0x00014138UL, 0x000087F6UL, \ + 0x00014140UL, 0x00880048UL, \ + 0x00014144UL, 0x1153E6C0UL, \ + 0x00016014UL, 0x00000010UL, \ + 0x00016018UL, 0x04127920UL, \ + 0x0001601CUL, 0x0051C007UL, \ + 0x00016020UL, 0x000000C2UL, \ + 0x00016024UL, 0x00000000UL, \ + 0x00016028UL, 0x03000000UL, \ + 0x0001602CUL, 0x00000000UL, \ + 0x00016030UL, 0x00FF0BF4UL, \ + 0x00016034UL, 0x00000C20UL, \ + 0x00016038UL, 0x0102000AUL, \ + 0x0001603CUL, 0x00080430UL, \ + 0x00016040UL, 0x000000A7UL, \ + 0x00016044UL, 0x00000000UL, \ + 0x00016048UL, 0x04602123UL, \ + 0x0001604CUL, 0x0000A47CUL, \ + 0x00016050UL, 0x00000018UL, \ + 0x00016054UL, 0x00000000UL, \ + 0x00016058UL, 0x00000000UL, \ + 0x0001605CUL, 0x30100101UL, \ + 0x00016060UL, 0x7F7F7050UL, \ + 0x00016064UL, 0x00000000UL, \ + 0x00017014UL, 0x000270F1UL, \ + 0x00017018UL, 0x00001700UL, \ + 0x0001701CUL, 0x82840000UL, \ + 0x00017028UL, 0x00000000UL, \ + 0x00017048UL, 0x0000383EUL, \ + 0x0001704CUL, 0x000025BCUL, \ + 0x00017070UL, 0x00010103UL, \ + 0x00017074UL, 0x00000442UL, \ + 0x00017078UL, 0x006D8480UL, \ + 0xFFFFFFFFUL, \ +} + +#define RAIL_IEEE802154_CONFIG_915MHZ_EFR32MG1P { \ + 0x01010FF4UL, 0x00000000UL, \ + 0x01010FF8UL, 0x0003C000UL, \ + 0x01010FFCUL, 0x0003C008UL, \ + 0x00010004UL, 0x00157001UL, \ + 0x00010008UL, 0x0000007FUL, \ + 0x00010018UL, 0x00000000UL, \ + 0x0001001CUL, 0x00000000UL, \ + 0x00010028UL, 0x00000000UL, \ + 0x0001002CUL, 0x00000000UL, \ + 0x00010030UL, 0x00000000UL, \ + 0x00010034UL, 0x00000000UL, \ + 0x0001003CUL, 0x00000000UL, \ + 0x00010040UL, 0x000007A0UL, \ + 0x00010048UL, 0x00000000UL, \ + 0x00010054UL, 0x00000000UL, \ + 0x00010058UL, 0x00000000UL, \ + 0x000100A0UL, 0x00004000UL, \ + 0x000100A4UL, 0x00004CFFUL, \ + 0x000100A8UL, 0x00004100UL, \ + 0x000100ACUL, 0x00004DFFUL, \ + 0x00012000UL, 0x00000704UL, \ + 0x00012010UL, 0x00000000UL, \ + 0x00012018UL, 0x00008408UL, \ + 0x00013008UL, 0x0000AC3FUL, \ + 0x0001302CUL, 0x02364000UL, \ + 0x00013030UL, 0x00108000UL, \ + 0x00013034UL, 0x00000003UL, \ + 0x0001303CUL, 0x00014000UL, \ + 0x00013040UL, 0x00000000UL, \ + 0x000140A0UL, 0x0F00277AUL, \ + 0x000140F4UL, 0x00001020UL, \ + 0x00014134UL, 0x00000880UL, \ + 0x00014138UL, 0x000087F6UL, \ + 0x00014140UL, 0x00880048UL, \ + 0x00014144UL, 0x1153E6C0UL, \ + 0x00016014UL, 0x00000010UL, \ + 0x00016018UL, 0x04127920UL, \ + 0x0001601CUL, 0x0051C007UL, \ + 0x00016020UL, 0x000000C2UL, \ + 0x00016024UL, 0x00000000UL, \ + 0x00016028UL, 0x03000000UL, \ + 0x0001602CUL, 0x00000000UL, \ + 0x00016030UL, 0x00FF04C8UL, \ + 0x00016034UL, 0x000008A2UL, \ + 0x00016038UL, 0x0100000AUL, \ + 0x0001603CUL, 0x00080430UL, \ + 0x00016040UL, 0x000000A7UL, \ + 0x00016044UL, 0x00000000UL, \ + 0x00016048UL, 0x0AC02123UL, \ + 0x0001604CUL, 0x0000A47CUL, \ + 0x00016050UL, 0x00000018UL, \ + 0x00016054UL, 0x00000000UL, \ + 0x00016058UL, 0x00000000UL, \ + 0x0001605CUL, 0x30100101UL, \ + 0x00016060UL, 0x7F7F7050UL, \ + 0x00016064UL, 0x00000000UL, \ + 0x00017014UL, 0x000270F1UL, \ + 0x00017018UL, 0x00001700UL, \ + 0x0001701CUL, 0x82840000UL, \ + 0x00017028UL, 0x00000000UL, \ + 0x00017048UL, 0x0000383EUL, \ + 0x0001704CUL, 0x000025BCUL, \ + 0x00017070UL, 0x00010103UL, \ + 0x00017074UL, 0x00000442UL, \ + 0x00017078UL, 0x006D8480UL, \ + 0xFFFFFFFFUL, \ +} + +#endif /* (RAIL_RADIO_BAND == 868) || (RAIL_RADIO_BAND == 915) */ +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* RAIL_802154_CONFIG_H */ +/** @} */ diff --git a/drivers/rail/include/rail_helper.h b/drivers/rail/include/rail_helper.h new file mode 100644 index 000000000000..358a12c1ba8a --- /dev/null +++ b/drivers/rail/include/rail_helper.h @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2018 Hochschule RheinMain + * + * 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 drivers_rail + * @{ + * + * @file + * @brief helper functions for EFR32 radio driver + * + * @author Kai Beckmann + */ + +#ifndef RAIL_HELPER_H +#define RAIL_HELPER_H + +#include +#include + +#include "rail.h" + +#include "byteorder.h" +#include "net/eui64.h" +#include "ringbuffer.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Reads and converts the EUI of the transceiver + * + * @return the EUI + */ +eui64_t rail_helper_get_hw_EUI(void); + +/** + * + * @brief Simple event queue based on a ringbuffer to pass rail events to the netdev layer + * @{ + * + * @author Kai Beckmann + */ + +/** + * @brief count of possible events to hold in queue + */ +#define RAIL_EVENT_MSG_COUNT 10 + +/** + * @brief Structure to store all relevant data for an rail event + * + */ +typedef struct { + + RAIL_Events_t event; /**< The rail event that occurred */ + RAIL_RxPacketHandle_t rx_packet; /**< if a packet was received, the rail handle to the packet */ + RAIL_RxPacketInfo_t rx_packet_info; /**< if a packet was received, the basic packet information + extracted in the rail event hanlder */ + uint16_t rx_packet_size; /**< size of the received packet */ + uint32_t event_count; /**< the number / count of this event since driver init */ + +} rail_event_msg_t; + +/** + * @brief Structure for a simple rail event queue. + * + * Structure for a simple event queue, to be used in @see rail_t + * The memory for the ring buffer is part of the structure, so every + * instance of the driver can have its seperate queue. + */ +typedef struct { + ringbuffer_t ring_buffer; /**< ring buffer for incomming events */ + uint8_t _buffer[sizeof(rail_event_msg_t) * RAIL_EVENT_MSG_COUNT]; /**< memory to hold the ringbuffer */ + +} rail_event_queue_t; + +/** + * @brief Initialise an event queue for rail events + * + * @param[in,out] queue event queue + * + */ +void rail_event_queue_init(rail_event_queue_t* queue); + +/** + * @brief Peek an event from queue without removing it + * + * @param[in,out] queue event queue + * @param[out] event_msg the event + * + * @return 0 on success + * @return -1 on failure + */ +int rail_event_queue_peek(rail_event_queue_t* queue, rail_event_msg_t* event_msg); + +/** + * @brief Polls an event from queue with removing it + * + * @param[in,out] queue event queue + * @param[out] event_msg the event, if NULL the first event is just removed + * + * @return 0 on success + * @return -1 on failure + */ +int rail_event_queue_poll(rail_event_queue_t* queue, rail_event_msg_t* event_msg); + +/** + * @brief Adds an event to the end of the queue + * + * @param[in,out] queue event queue + * @param[out] event_msg the event to add + * + * @return 0 on success + * @return -1 on failurePeek an event from queue without removing it + */ +int rail_event_queue_add(rail_event_queue_t* queue, rail_event_msg_t* event_msg); + +/** @} */ + +/** + * @brief maps librail error / status codes to strings + * + * @param[in] status error or status code + * + * @return String describing the status/error + */ +const char *rail_error2str(RAIL_Status_t status); + +/** + * @brief Debug / helper functions for mapping librail stati and + * events to strings + * Strings are only included with @see DEVELHELP set + * + * @{ + */ + +/** + * @brief map rx packet status to string expression + * + * @param[in] status status to map + * + * @return String + */ +const char *rail_packetStatus2str(RAIL_RxPacketStatus_t status); + +/** + * @brief map radio state to string expression + * + * @param[in] state status to map + * + * @return String + */ +const char *rail_radioState2str(RAIL_RadioState_t state); + +/** + * @brief map rail event to string expression + * + * @param[in] event event to map + * + * @return String + */ +const char *rail_event2str(RAIL_Events_t event); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* RAIL_HELPER_H */ +/** @} */ diff --git a/drivers/rail/include/rail_netdev.h b/drivers/rail/include/rail_netdev.h new file mode 100644 index 000000000000..22548b0c6565 --- /dev/null +++ b/drivers/rail/include/rail_netdev.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2018 Hochschule RheinMain + * + * 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 drivers_rail + * @{ + * + * @file + * @brief Netdev interface to Silabs EFR32 radio drivers + * + * @author Kai Beckmann + */ + +#ifndef RAIL_NETDEV_H +#define RAIL_NETDEV_H + +#include "net/netdev.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Reference to the netdev device driver struct + */ +extern const netdev_driver_t rail_driver; + +#ifdef __cplusplus +} +#endif + +#endif /* RAIL_NETDEV_H */ +/** @} */ diff --git a/drivers/rail/include/rail_params.h b/drivers/rail/include/rail_params.h new file mode 100644 index 000000000000..5d567aaef7a6 --- /dev/null +++ b/drivers/rail/include/rail_params.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2018 Hochschule RheinMain + * + * 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 drivers_rail + * @{ + * @file + * @brief Default configuration for the Silabs EFR32 radio driver + * + * @author Kai Beckmann + */ + +#ifndef RAIL_PARAMS_H +#define RAIL_PARAMS_H + +#include "board.h" +#include "rail_drv.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name Set default configuration parameters for the AT86RF2xx driver + * @{ + */ +#ifndef RAIL_PARAMS +#define RAIL_PARAMS { .freq = RAIL_TRANSCEIVER_FREQUENCY_2P4GHZ } +#endif +/**@}*/ + +/** + * @brief EFR32 rail configuration + */ +static const rail_params_t rail_params[] = { + RAIL_PARAMS +}; + +#ifdef __cplusplus +} +#endif + +#endif /* RAIL_PARAMS_H */ +/** @} */ diff --git a/drivers/rail/rail_drv.c b/drivers/rail/rail_drv.c new file mode 100644 index 000000000000..18a228aebdd8 --- /dev/null +++ b/drivers/rail/rail_drv.c @@ -0,0 +1,787 @@ +/* + * Copyright (C) 2018 Hochschule RheinMain + * + * 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. + */ + +#include +#include +#include + +#include "byteorder.h" + +#include "rail_radio.h" + +/* gecko sdk rail lib includes*/ +#include "em_core.h" +#include "rail.h" +#include "rail_chip_specific.h" +#include "pa_conversions_efr32.h" +#include "rail_assert_error_codes.h" +#include "ieee802154/rail_ieee802154.h" + +/* riot os rail driver includes*/ +#include "rail_drv.h" +#include "rail_netdev.h" +#include "rail_802154_config.h" + +#include "net/ieee802154.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#include "log.h" + +/* RADIO CONFIGURATION */ +/* channel config for sub GHz radio + */ +#if (RAIL_RADIO_BAND == 868) || (RAIL_RADIO_BAND == 915) + +#if (RAIL_RADIO_BAND == 868) +static RAIL_ChannelConfigEntryAttr_t radio_channel_entry_868; +#elif (RAIL_RADIO_BAND == 915) +static RAIL_ChannelConfigEntryAttr_t radio_channel_entry_915; +#endif + +static const RAIL_ChannelConfigEntry_t radio_channel_entry[] = { +#if (RAIL_RADIO_BAND == 868) + { .phyConfigDeltaAdd = NULL, /* Add this to default config for this entry */ + .baseFrequency = 868300000U, + .channelSpacing = 600000U, + .physicalChannelOffset = 0, + .channelNumberStart = 0, + .channelNumberEnd = 0, + .maxPower = RAIL_TX_POWER_MAX, + .attr = &radio_channel_entry_868 }, +#elif (RAIL_RADIO_BAND == 915) + { .phyConfigDeltaAdd = NULL, /* Add this to default config for this entry */ + .baseFrequency = 906000000U, + .channelSpacing = 2000000U, + .physicalChannelOffset = 1, + .channelNumberStart = 1, + .channelNumberEnd = 10, + .maxPower = RAIL_TX_POWER_MAX, + .attr = &radio_channel_entry_915 } +#endif +}; + +#endif + +/* IEEE 802.15.4 config for 868MHz and 912MHz */ +#if (RAIL_RADIO_BAND == 868) + +static const uint32_t ieee802154_config_863[] = RAIL_IEEE802154_CONFIG_868MHZ; +static const uint32_t ieee802154_config_863_min[] = { + 0xFFFFFFFFUL, +}; + +static const RAIL_ChannelConfig_t _rail_radio_channel_config = { + .phyConfigBase = ieee802154_config_863, + .phyConfigDeltaSubtract = ieee802154_config_863_min, + .configs = &radio_channel_entry[0], + .length = 1 +}; +#elif (RAIL_RADIO_BAND == 915) + +static const uint32_t ieee802154_config_863[] = RAIL_IEEE802154_CONFIG_915MHZ; +static const uint32_t ieee802154_config_915_min[] = { + 0xFFFFFFFFUL, +}; + +static const RAIL_ChannelConfig_t _rail_radio_channel_config = { + .phyConfigBase = ieee802154_config_915, + .phyConfigDeltaSubtract = ieee802154_config_915_min, + .configs = &radio_channel_entry[0], + .length = 1 +}; +#endif + +static const RAIL_IEEE802154_Config_t _rail_ieee802154_config = { + .addresses = NULL, + .ackConfig = { + .enable = true, /* Turn on auto ACK for IEEE 802.15.4 */ + .ackTimeout = 864, /* 54 symbols * 16 us/symbol = 864 us */ + .rxTransitions = { + .success = RAIL_RF_STATE_RX, /* after rx -> state rx */ + .error = RAIL_RF_STATE_RX /* ignored */ + }, + .txTransitions = { + .success = RAIL_RF_STATE_RX, /* after tx -> state rx */ + .error = RAIL_RF_STATE_RX /* ignored */ + } + }, + .timings = { .idleToRx = 100, + /* Make txToRx slightly lower than desired to make sure we get to + RX in time + */ + .txToRx = 192 - 10, + .idleToTx = 100, + .rxToTx = 192, + .rxSearchTimeout = 0, + .txToRxSearchTimeout = 0 }, + .framesMask = RAIL_IEEE802154_ACCEPT_STANDARD_FRAMES, + .promiscuousMode = false, + .isPanCoordinator = false +}; + +static const RAIL_CsmaConfig_t _rail_csma_default_config = RAIL_CSMA_CONFIG_802_15_4_2003_2p4_GHz_OQPSK_CSMA; + +/* TODO use define to restrict to supported freq */ +RAIL_DECLARE_TX_POWER_VBAT_CURVES(piecewiseSegments, curvesSg, curves24Hp, curves24Lp); + +/********************* BUFFER MANAGEMENT ***************************/ + +/* tx buffer */ +static uint8_t _transmit_buffer[IEEE802154_FRAME_LEN_MAX + 1]; + +/********************* LOKAL VARIABLES ******************************/ + +/* ref to rail_t/ netdev_t struct for this driver + TODO howto distinguish between multible netdevs? + necessary for multiprotocol support, multible instances of the driver etc. + Possible solution: map with an rhandle as key and netdev as value? + */ +static rail_t *_rail_dev = NULL; + +/************************ private functions *********************************/ + +/* callback handler for RAIL driver blob, get called to handle events. + The hw irqs are allready handled when called + */ +static void _rail_radio_event_handler(RAIL_Handle_t rhandle, RAIL_Events_t event); + +void rail_setup(rail_t *dev, const rail_params_t *params) +{ + + netdev_t *netdev = (netdev_t *)dev; + + /* register driver (defined in rail_netdev) */ + netdev->driver = &rail_driver; + + /* init dev with params */ + memcpy(&dev->params, params, sizeof(rail_params_t)); + + DEBUG("rail->setup called\n"); + + /* default, no promiscuous mode */ + dev->promiscuousMode = false; + + dev->state = RAIL_TRANSCEIVER_STATE_UNINITIALIZED; + + /* TODO config for 868/912MHz different? */ + dev->csma_config = _rail_csma_default_config; + +#ifdef RAIL_RADIO_HAS_SUBGHZ + /* set default channel page, only relevant if sub ghz channel is set */ + dev->channel_page = RAIL_SUBGHZ_DEFAULT_PAGE; +#endif + + dev->event_count = 0; +} + +/* init Packet Trace (PTI) functionality -> usefull for debugging */ +#if (RAIL_PTI_ENABLED == 1) +int _rail_PTI_init(rail_t *dev) +{ + + /* init gpio for trace output */ + + RAIL_PtiConfig_t pti_config = RAIL_PTI_CONFIG; + + RAIL_ConfigPti(dev->rhandle, &pti_config); + + RAIL_EnablePti(dev->rhandle, true); + + DEBUG("RADIO_PTI_Init done\n"); + + return 0; +} +#endif + +/* initialisation of the transceivers power amplifier + have to be called in init + TODO what about deep sleep? + */ +int _rail_PA_init(rail_t *dev) +{ + + /* Initialize the RAIL Tx power curves for all PAs on this chip */ + RAIL_TxPowerCurvesConfig_t tx_power_curves_config = { + curves24Hp, + curvesSg, + curves24Lp, + piecewiseSegments + }; + + RAIL_Status_t ret = RAIL_InitTxPowerCurves(&tx_power_curves_config); + + if (ret != RAIL_STATUS_NO_ERROR) { + LOG_ERROR("Error init PA (Tx power curves) for rail - error msg: %s\n", rail_error2str(ret)); + return -1; + } + + /* Power config, depends on chip etc ... */ + /* TODO + - multi freq, mult protocol + - there are SoCs with high and low power PAs, + how to determain which version has this SoC? + atm only 2.4GHZ HighPower is supported + */ + RAIL_TxPowerConfig_t tx_power_config = { +#if RAIL_RADIO_BAND == 2400 + RAIL_TX_POWER_MODE_2P4_HP, +#elif (RAIL_RADIO_BAND == 868) || (RAIL_RADIO_BAND == 915) + RAIL_TX_POWER_MODE_SUBGIG, +#endif + RAIL_RADIO_PA_VOLTAGE, /* voltage vPA for the DCDC connection */ + 10 + }; + + ret = RAIL_ConfigTxPower(dev->rhandle, &tx_power_config); + + if (ret != RAIL_STATUS_NO_ERROR) { + LOG_ERROR("Error init PA (config Tx power) for rail - error msg: %s\n", rail_error2str(ret)); + return -1; + } + + ret = RAIL_SetTxPowerDbm(dev->rhandle, ((RAIL_TxPower_t)RAIL_DEFAULT_TXPOWER) * 10); + + if (ret != RAIL_STATUS_NO_ERROR) { + LOG_ERROR("Error init PA (set tx power) for rail"); + return -1; + } + + DEBUG("RADIO_PA_Init done\n"); + + return 0; +} + +int rail_init(rail_t *dev) +{ + + RAIL_Status_t ret; + int r = 0; + + netdev_ieee802154_t *netdev = (netdev_ieee802154_t *)dev; + dev->thread = (thread_t *)thread_get(thread_getpid()); + + /* save ref for this driver, for global access (esp in rail event handler) */ + /* TODO multible instances? */ + _rail_dev = dev; + + DEBUG("rail_init called\n"); + + dev->state = RAIL_TRANSCEIVER_STATE_UNINITIALIZED; + + /* init the queue for the rail events */ + rail_event_queue_init(&(dev->event_queue)); + + /* start with long addr mode. */ + netdev->flags |= NETDEV_IEEE802154_SRC_MODE_LONG; + + /* get informations about the used raillib */ + /* TODO check if driver is compatible? */ + RAIL_Version_t rail_version; + RAIL_GetVersion(&rail_version, true); + + DEBUG("Using Silicon Labs RAIL Lib. Version %u.%u Rev: %u build: %u multiprotocol: %s \n", + rail_version.major, rail_version.minor, rail_version.rev, rail_version.build, + rail_version.multiprotocol ? "YES" : "NO"); + + /* init rail blob config + set to zero, because API manual request it + */ + memset(&(dev->rconfig), 0, sizeof(RAIL_Config_t)); + + dev->rconfig.eventsCallback = &_rail_radio_event_handler; + dev->rconfig.protocol = NULL; + dev->rconfig.scheduler = NULL; + + /* Init rail driver blob instance */ + dev->rhandle = RAIL_Init(&(dev->rconfig), NULL); + + if (dev->rhandle == NULL) { + LOG_ERROR("Can not init rail blob driver\n"); + return -1; + } + + /* config data management, easier version with packets */ + + static const RAIL_DataConfig_t rail_data_config = { + TX_PACKET_DATA, + RX_PACKET_DATA, + PACKET_MODE, + PACKET_MODE, + }; + + ret = RAIL_ConfigData(dev->rhandle, &rail_data_config); + + if (ret != RAIL_STATUS_NO_ERROR) { + LOG_ERROR("Can not init rail data config - error msg: %s\n", rail_error2str(ret)); + return -1; + } + + /* config transceiver calibration (freq depends on temperature etc) */ + + ret = RAIL_ConfigCal(dev->rhandle, RAIL_CAL_ALL); + + if (ret != RAIL_STATUS_NO_ERROR) { + LOG_ERROR("Can not init rail calibration - error msg: %s\n", rail_error2str(ret)); + return -1; + } + + /* configure the channels for 802.15.4 */ + +#if RAIL_RADIO_BAND == 2400 + /* for 2.4 GHz the RAIL API provides a std conform default config */ + DEBUG("using 2.4GHz radio band\n"); + ret = RAIL_IEEE802154_Config2p4GHzRadio(dev->rhandle); + +#elif (RAIL_RADIO_BAND == 868) || (RAIL_RADIO_BAND == 915) + /* from gecko sdk 2.4 there is a official config api for sub ghz radio + but it does not support channel 0 + + */ +#if (RAIL_RADIO_BAND == 868) + DEBUG("using 868MHz radio band\n"); + /*ret = RAIL_IEEE802154_ConfigGB863MHzRadio(dev->rhandle); */ + ret = RAIL_ConfigChannels(dev->rhandle, &_rail_radio_channel_config, NULL); +#elif (RAIL_RADIO_BAND == 915) + DEBUG("using 915MHz radio band\n"); + /*ret = RAIL_IEEE802154_ConfigGB915MHzRadio(dev->rhandle);*/ + ret = RAIL_ConfigChannels(dev->rhandle, &_rail_radio_channel_config, NULL); +#endif + +#endif /* (RAIL_RADIO_BAND == 868) || (RAIL_RADIO_BAND == 915) */ + + if (ret != RAIL_STATUS_NO_ERROR) { + LOG_ERROR("Can not init rail radio channels - error msg: %s\n", rail_error2str(ret)); + return -1; + } + + /* init IEEE802.15.4 acceleration features */ + + ret = RAIL_IEEE802154_Init(dev->rhandle, &_rail_ieee802154_config); + if (ret != RAIL_STATUS_NO_ERROR) { + LOG_ERROR("Can not init rail ieee 802.15.4 support - error msg: %s\n", rail_error2str(ret)); + return -1; + } + + /* activate auto ack in the layer above */ + static const netopt_enable_t enable = NETOPT_ENABLE; + netdev_ieee802154_set(&dev->netdev, NETOPT_ACK_REQ, + &enable, sizeof(enable)); + + /* init radio PA */ + r = _rail_PA_init(dev); + + if (r != 0) { + return r; + } + + /* setup transmitt buffer */ + uint16_t buf_size = RAIL_SetTxFifo(dev->rhandle, _transmit_buffer, 0, sizeof(_transmit_buffer)); + if (buf_size == 0) { + LOG_ERROR("Can not set TxFifo - error msg: %s\n", rail_error2str(ret)); + return -1; + } + + /* setup PTI */ +#if (RAIL_PTI_ENABLED == 1) + r = _rail_PTI_init(dev); + assert(r == 0); +#endif + + /* TODO + - how to figure out if this device is the PAN coord? + */ + + /* get mac addr from SoC */ + eui64_t eui = rail_helper_get_hw_EUI(); + + DEBUG("Node EUI: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", + eui.uint8[0], + eui.uint8[1], + eui.uint8[2], + eui.uint8[3], + eui.uint8[4], + eui.uint8[5], + eui.uint8[6], + eui.uint8[7]); + + /* TODO provide default PANID / NID by params? */ + DEBUG("Set PanID to 0x%04x\n", RAIL_DEFAULT_PANID); + + netdev->pan = RAIL_DEFAULT_PANID; + + ret = RAIL_IEEE802154_SetPanId(dev->rhandle, RAIL_DEFAULT_PANID, 0); + if (ret != RAIL_STATUS_NO_ERROR) { + DEBUG("Can not set PAN ID %d - error msg: %s\n", RAIL_DEFAULT_PANID, rail_error2str(ret)); + } + + /* set short addr */ + DEBUG("Set ShortAddr 0x%04x\n", ntohs(eui.uint16[3].u16)); + + /* yeah riot want it in big endian*/ + memcpy(netdev->short_addr, &eui.uint16[3].u16, 2); + + /* rail want it in little endian ...*/ + ret = RAIL_IEEE802154_SetShortAddress(dev->rhandle, byteorder_ntohs(eui.uint16[3]), 0); + if (ret != RAIL_STATUS_NO_ERROR) { + DEBUG("Can not set short addr - error msg: %s", rail_error2str(ret)); + } + + /* set long addr aka EUI */ + DEBUG("Set LongAddr 0x%08lx%08lx\n", ntohl(eui.uint64.u32[0]), ntohl(eui.uint64.u32[1])); + + memcpy(netdev->long_addr, &eui.uint8, IEEE802154_LONG_ADDRESS_LEN); + + /* and for the long address, it have to be little endian aka reversed order */ + uint64_t addr_rev = byteorder_ntohll(eui.uint64); + + ret = RAIL_IEEE802154_SetLongAddress(dev->rhandle, (uint8_t *)&addr_rev, 0); + if (ret != RAIL_STATUS_NO_ERROR) { + DEBUG("Can not set long addr - error msg: %s", rail_error2str(ret)); + } + + /* get transmitt power, TODO only for debug mode */ + + RAIL_TxPower_t power_tx_ddBm = RAIL_GetTxPowerDbm(dev->rhandle); + + DEBUG("TX Power set to %hd deci dBm\n", power_tx_ddBm); + + /* configure the RAIL driver blob events we want the receive + it is possible to get all events with RAIL_EVENTS_ALL + */ + + ret = RAIL_ConfigEvents(dev->rhandle, + RAIL_EVENTS_ALL, /* mask of events, which should be modified, here all */ + /* events to subscribe */ + RAIL_EVENT_RX_ACK_TIMEOUT | + RAIL_EVENT_RX_FRAME_ERROR | + RAIL_EVENT_RX_ADDRESS_FILTERED | + RAIL_EVENT_RX_PACKET_RECEIVED | + RAIL_EVENT_TX_PACKET_SENT | + RAIL_EVENT_TX_CHANNEL_BUSY | + RAIL_EVENT_TX_ABORTED | + RAIL_EVENT_TX_BLOCKED | + RAIL_EVENT_TX_UNDERFLOW | + RAIL_EVENT_IEEE802154_DATA_REQUEST_COMMAND | + RAIL_EVENT_CAL_NEEDED); + + if (ret != RAIL_STATUS_NO_ERROR) { + LOG_ERROR("Can not subsripe to rail events - error msg: %s", rail_error2str(ret)); + return -1; + } + + /* TODO use / set some state? */ + + DEBUG("rail_init done\n"); + LOG_INFO("rail radio driver initialised\n"); + + return 0; +} + +/* TODO + - docu + - rename to transmit_packet, frames are done a layer above + */ +int rail_transmit_frame(rail_t *dev, uint8_t *data_ptr, size_t data_length) +{ + DEBUG("[rail] rail_transmit_frame called\n"); + + /* force radio state to idle, aboard running ops, so we can transmitt + otherwise the transceiver might be receiving/transmitting and the new + transmit op fails. + TODO ensure there are no other running ops + */ + RAIL_Idle(dev->rhandle, RAIL_IDLE_ABORT, true); + + /* write packet payload in the buffer of the rail driver blob*/ + RAIL_WriteTxFifo(dev->rhandle, data_ptr, data_length, true); + + /* config tx options, here just the defaults*/ + RAIL_TxOptions_t tx_option = RAIL_TX_OPTIONS_DEFAULT; + + /* TODO internal state */ + dev->state = RAIL_TRANSCEIVER_STATE_TX; + + /* Check FCF field in the TX buffer to see if the ACK_REQ flag was set in + * the packet that is queued for transmission */ + uint8_t fcf = data_ptr[1]; + if ((fcf & IEEE802154_FCF_ACK_REQ) && + (dev->netdev.flags & NETDEV_IEEE802154_ACK_REQ)) { + tx_option |= RAIL_TX_OPTION_WAIT_FOR_ACK; + DEBUG("tx option auto ack\n"); + } + + DEBUG("[rail] transmit - radio state: %s\n", rail_radioState2str(RAIL_GetRadioState(dev->rhandle))); + + /* start tx with settings in csma_config + */ + RAIL_Status_t ret = RAIL_StartCcaCsmaTx(dev->rhandle, + dev->netdev.chan, + tx_option, + &dev->csma_config, + NULL); + + if (ret != RAIL_STATUS_NO_ERROR) { + LOG_ERROR("Can't start transmit - current state %s - error msg: %s \n", + rail_radioState2str(RAIL_GetRadioState(dev->rhandle)), + rail_error2str(ret)); + rail_start_rx(dev); + return -1; + } + DEBUG("Started transmit\n"); + + /* TODO + - if this should be asymmetric blocking call, we have to wait for the + tx done event by the callback + - or use while (RAIL_GetRadioState(dev->rhandle) & RAIL_RF_STATE_TX ); + */ + while (RAIL_GetRadioState(dev->rhandle) & RAIL_RF_STATE_TX) {} + + rail_start_rx(dev); + return 0; +} + +int rail_start_rx(rail_t *dev) +{ + + /* + TODO process: + check state + if uninit/init etc/ -> error; + if calibrate || error + -> tx error + if idle and rx + if waiting for ack + no timeout? error + timeout?, stats++, cont + */ + /* check if set? or just a global setting? */ + if (dev->promiscuousMode == true) { + RAIL_IEEE802154_SetPromiscuousMode(dev->rhandle, true); + } + else { + RAIL_IEEE802154_SetPromiscuousMode(dev->rhandle, false); + } + + /* set channel to listen to */ + RAIL_StartRx(dev->rhandle, dev->netdev.chan, NULL); + dev->state = RAIL_TRANSCEIVER_STATE_RX; + + DEBUG("[rail] recv - radio state: %s\n", rail_radioState2str(RAIL_GetRadioState(dev->rhandle))); + return 0; +} + +/* RAIL blob event handler */ +/* moved everything possible to netdev->isr() + */ +static void _rail_radio_event_handler(RAIL_Handle_t rhandle, RAIL_Events_t event) +{ + + /* TODO get the right netdev struct */ + rail_t *dev = _rail_dev; + + /* init event msg struct */ + rail_event_msg_t event_msg = { .event = RAIL_EVENTS_NONE, .rx_packet = RAIL_RX_PACKET_HANDLE_INVALID }; + + /* debug/stat purpose, store event count */ + dev->event_count++; + + event_msg.event_count = dev->event_count; + + /* rail events are a bitmask, therefore multible events within this call + are possible -> TODO + */ + + /* Indicates a Data Request is being received when using IEEE 802.15.4 + functionality. */ + if (event & RAIL_EVENT_IEEE802154_DATA_REQUEST_COMMAND) { + /* TODO what is source match? and why might it be necessary to filter + here the packet? + */ + DEBUG("Rail event ieee 802.15.4 data request command\n"); + + if (dev->netdev.flags & NETDEV_IEEE802154_FRAME_PEND) { + RAIL_IEEE802154_SetFramePending(rhandle); + } + + return; + } + + /* Occurs when the application needs to run a calibration.*/ + if (event & RAIL_EVENT_CAL_NEEDED) { + + DEBUG("Rail event calibration needed \n"); + LOG_INFO("Rail radio transceiver needs a calibration: executed\n"); + + RAIL_Status_t ret; + + ret = RAIL_Calibrate(rhandle, NULL, RAIL_CAL_ALL_PENDING); + + DEBUG("calibration done, ret: %d \n", ret); + + assert(ret == RAIL_STATUS_NO_ERROR); + + return; + } + + /* store the rail event */ + event_msg.event = event; + + /* Occurs whenever a packet is received + Can not moved to netdev->isr(), because packet is only accessable in + this handler + */ + if (event & RAIL_EVENT_RX_PACKET_RECEIVED) { + DEBUG("Rail event rx packet received\n"); + + /* check if packet is ok */ + + RAIL_RxPacketHandle_t rx_handle; + rx_handle = RAIL_GetRxPacketInfo(rhandle, + RAIL_RX_PACKET_HANDLE_NEWEST, + &(event_msg.rx_packet_info)); + + DEBUG("[rail] rx packet event - len p 0x%02x - len2 0x%02x\n", + event_msg.rx_packet_info.firstPortionData[0], + event_msg.rx_packet_info.packetBytes); + + if (event_msg.rx_packet_info.packetStatus != RAIL_RX_PACKET_READY_SUCCESS) { + /* error */ + + DEBUG("Got an packet with an error - packet status msg: %s \n", + rail_packetStatus2str(event_msg.rx_packet_info.packetStatus)); + + /* overwrite type, because we handle it as a frame error */ + event_msg.event = RAIL_EVENT_RX_FRAME_ERROR; + /* if the packet is broken, we can release the memory */ + RAIL_ReleaseRxPacket(rhandle, rx_handle); + } + else { + DEBUG("Rail event rx packet good packet \n"); + + /* hold packet so it can be received from netdev thread context */ + RAIL_HoldRxPacket(rhandle); + /* save the rx packet handle in the rail event msg */ + event_msg.rx_packet = rx_handle; + /* save the size of the packet */ + event_msg.rx_packet_size = event_msg.rx_packet_info.packetBytes; + } + } + + /* debug events */ + + if (event & RAIL_EVENT_TX_START_CCA) { + + DEBUG("RAIL_EVENT_TX_START_CCA\n"); + } + if (event & RAIL_EVENT_TX_CCA_RETRY) { + + DEBUG("RAIL_EVENT_TX_CCA_RETRY\n"); + } + if (event & RAIL_EVENT_TX_CHANNEL_BUSY) { + + DEBUG("RAIL_EVENT_TX_CHANNEL_BUSY\n"); + } + if (event & RAIL_EVENT_TX_CHANNEL_CLEAR) { + + DEBUG("RAIL_EVENT_TX_CHANNEL_CLEAR\n"); + } + if (event & RAIL_EVENT_TXACK_UNDERFLOW) { + + DEBUG("RAIL_EVENT_TXACK_UNDERFLOW\n"); + } + if (event & RAIL_EVENT_TX_UNDERFLOW) { + + DEBUG("RAIL_EVENT_TX_UNDERFLOW\n"); + } + if (event & RAIL_EVENT_TXACK_BLOCKED) { + + DEBUG("RAIL_EVENT_TXACK_BLOCKED\n"); + } + if (event & RAIL_EVENT_TX_BLOCKED) { + + DEBUG("RAIL_EVENT_TX_BLOCKED\n"); + } + if (event & RAIL_EVENT_TXACK_ABORTED) { + + DEBUG("RAIL_EVENT_TXACK_ABORTED\n"); + } + + if (event & RAIL_EVENT_TXACK_PACKET_SENT) { + + DEBUG("RAIL_EVENT_TXACK_PACKET_SENT\n"); + } + if (event & RAIL_EVENT_TX_PACKET_SENT) { + + DEBUG("RAIL_EVENT_TX_PACKET_SENT\n"); + } + if (event & RAIL_EVENT_TX_FIFO_ALMOST_EMPTY) { + + DEBUG("RAIL_EVENT_TX_FIFO_ALMOST_EMPTY\n"); + } + if (event & RAIL_EVENT_RX_TIMING_DETECT) { + + DEBUG("RAIL_EVENT_RX_TIMING_DETECT\n"); + } + if (event & RAIL_EVENT_RX_TIMING_LOST) { + + DEBUG("RAIL_EVENT_RX_TIMING_LOST\n"); + } + if (event & RAIL_EVENT_RX_FILTER_PASSED) { + + DEBUG("RAIL_EVENT_RX_FILTER_PASSED\n"); + } + if (event & RAIL_EVENT_RX_PACKET_ABORTED) { + + DEBUG("RAIL_EVENT_RX_PACKET_ABORTED\n"); + } + if (event & RAIL_EVENT_RX_SCHEDULED_RX_END) { + + DEBUG("RAIL_EVENT_RX_SCHEDULED_RX_END\n"); + } + if (event & RAIL_EVENT_RX_TIMEOUT) { + + DEBUG("RAIL_EVENT_RX_TIMEOUT\n"); + } + if (event & RAIL_EVENT_RX_ADDRESS_FILTERED) { + + DEBUG("RAIL_EVENT_RX_ADDRESS_FILTERED\n"); + } + if (event & RAIL_EVENT_RX_FRAME_ERROR) { + + DEBUG("RAIL_EVENT_RX_FRAME_ERROR\n"); + } + if (event & RAIL_EVENT_RX_SYNC2_DETECT) { + + DEBUG("RAIL_EVENT_RX_SYNC2_DETECT\n"); + } + if (event & RAIL_EVENT_RX_SYNC1_DETECT) { + + DEBUG("RAIL_EVENT_RX_SYNC1_DETECT\n"); + } + if (event & RAIL_EVENT_RX_PREAMBLE_DETECT) { + + DEBUG("RAIL_EVENT_RX_PREAMBLE_DETECT\n"); + } + if (event & RAIL_EVENT_RX_PREAMBLE_LOST) { + + DEBUG("RAIL_EVENT_RX_PREAMBLE_LOST\n"); + } + + /* add event to queue, for netdev to process */ + rail_event_queue_add(&(dev->event_queue), &event_msg); + + /* let the netdev->isr() handle the rest */ + dev->netdev.netdev.event_callback((netdev_t *)&dev->netdev, NETDEV_EVENT_ISR); + + /* Signal to the thread that an IRQ has arrived, if it is waiting */ + thread_flags_set(dev->thread, RAIL_THREAD_FLAG_ISR); + + cortexm_isr_end(); +} diff --git a/drivers/rail/rail_helper.c b/drivers/rail/rail_helper.c new file mode 100644 index 000000000000..3255d3f5a21d --- /dev/null +++ b/drivers/rail/rail_helper.c @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2018 Hochschule RheinMain + * + * 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. + */ + +#include +#include +#include + +#include "rail_helper.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#include "log.h" + +eui64_t rail_helper_get_hw_EUI(void) +{ + + /* this is a bit messy, because everthing has or what it in different + endianess + for convenience we read it once and save it in the netdev structure in + big endianess + */ + le_uint64_t tmp; + tmp.u32[0] = DEVINFO->UNIQUEL; + tmp.u32[1] = DEVINFO->UNIQUEH; + + eui64_t eui; + eui.uint64 = byteorder_ltobll(tmp); + + return eui; +} + +void rail_event_queue_init(rail_event_queue_t* queue) +{ + assert(queue != NULL); + + /* init the ringbuffer for the rail event queue */ + ringbuffer_init(&(queue->ring_buffer), (char *) queue->_buffer, sizeof(queue->_buffer)); +} + +int rail_event_queue_peek(rail_event_queue_t* queue, rail_event_msg_t* event_msg) +{ + assert(event_msg != NULL); + + if (ringbuffer_empty(&(queue->ring_buffer)) != 0) { + return -1; + } + + unsigned r = ringbuffer_peek(&(queue->ring_buffer), (char *) event_msg, sizeof(rail_event_msg_t)); + + if (r != sizeof(rail_event_msg_t)) { + return -1; + } + + return 0; +} + +int rail_event_queue_poll(rail_event_queue_t* queue, rail_event_msg_t* event_msg) +{ + + if (ringbuffer_empty(&(queue->ring_buffer)) != 0) { + return -1; + } + + if (event_msg != NULL) { + unsigned r = ringbuffer_get(&(queue->ring_buffer), (char *) event_msg, sizeof(rail_event_msg_t)); + + if (r != sizeof(rail_event_msg_t)) { + return -1; + } + } + else { + unsigned r = ringbuffer_remove(&(queue->ring_buffer), sizeof(rail_event_msg_t)); + + if (r != sizeof(rail_event_msg_t)) { + return -1; + } + } + + return 0; +} + +int rail_event_queue_add(rail_event_queue_t* queue, rail_event_msg_t* event_msg) +{ + if (ringbuffer_full(&(queue->ring_buffer)) != 0) { + LOG_ERROR("Rail event ring buffer is full\n"); + return -1; + } + + unsigned r = ringbuffer_add(&(queue->ring_buffer), (char *) event_msg, sizeof(rail_event_msg_t)); + + if (r != sizeof(rail_event_msg_t)) { + return -1; + } + + return 0; +} + +const char *rail_error2str(RAIL_Status_t status) +{ + + switch (status) { + case (RAIL_STATUS_NO_ERROR): + return "No error"; + case (RAIL_STATUS_INVALID_PARAMETER): + return "Invalid parameter"; + case (RAIL_STATUS_INVALID_STATE): + return "Invalid state"; + case (RAIL_STATUS_INVALID_CALL): + return "Invalid Call"; + case (RAIL_STATUS_SUSPENDED): + return "Status suspended"; + } + (void) status; + return "Error code unknown"; +} + +const char *rail_event2str(RAIL_Events_t event) +{ +#ifdef DEVELHELP + if (event & RAIL_EVENT_RX_PACKET_RECEIVED) { + return "RAIL_EVENT_RX_PACKET_RECEIVED"; + } + if (event & RAIL_EVENT_TX_PACKET_SENT) { + return "RAIL_EVENT_TX_PACKET_SENT"; + } + if (event & RAIL_EVENT_RX_PACKET_RECEIVED) { + return "RAIL_EVENT_RX_PACKET_RECEIVED"; + } + if (event & RAIL_EVENT_TX_PACKET_SENT) { + return "RAIL_EVENT_TX_PACKET_SENT"; + } + if (event & RAIL_EVENT_RX_ACK_TIMEOUT) { + return "RAIL_EVENT_RX_ACK_TIMEOUT"; + } + if (event & RAIL_EVENT_RX_FRAME_ERROR) { + return "RAIL_EVENT_RX_FRAME_ERROR"; + } + if (event & RAIL_EVENT_RX_ADDRESS_FILTERED) { + return "RAIL_EVENT_RX_ADDRESS_FILTERED"; + } + if (event & RAIL_EVENT_RX_PACKET_ABORTED) { + return "RAIL_EVENT_RX_PACKET_ABORTED"; + } + if (event & RAIL_EVENT_TXACK_PACKET_SENT) { + return "RAIL_EVENT_TXACK_PACKET_SENT"; + } + if (event & RAIL_EVENT_TX_CHANNEL_BUSY) { + return "RAIL_EVENT_TX_CHANNEL_BUSY"; + } + if (event & RAIL_EVENT_TX_ABORTED) { + return "RAIL_EVENT_TX_ABORTED"; + } + if (event & RAIL_EVENT_TXACK_ABORTED) { + return "RAIL_EVENT_TXACK_ABORTED"; + } + if (event & RAIL_EVENT_TX_BLOCKED) { + return "RAIL_EVENT_TX_BLOCKED"; + } + if (event & RAIL_EVENT_TXACK_BLOCKED) { + return "RAIL_EVENT_TXACK_BLOCKED"; + } + if (event & RAIL_EVENT_TX_UNDERFLOW) { + return "RAIL_EVENT_TX_UNDERFLOW"; + } + if (event & RAIL_EVENT_TXACK_UNDERFLOW) { + return "RAIL_EVENT_TXACK_UNDERFLOW"; + } + + return "RAIL EVENT: TODO"; +#else + (void) event; + return "enable DEVELHELP"; +#endif /* DEVELHELP */ +} + +const char *rail_packetStatus2str(RAIL_RxPacketStatus_t status) +{ +#ifdef DEVELHELP + switch (status) { + case (RAIL_RX_PACKET_NONE): + return "Radio is idle or searching for a packet."; + case (RAIL_RX_PACKET_ABORT_FORMAT): + return "Format/Length error."; + case (RAIL_RX_PACKET_ABORT_FILTERED): + return "Filtering error (address)."; + case (RAIL_RX_PACKET_ABORT_ABORTED): + return "Aborted error."; + case (RAIL_RX_PACKET_ABORT_OVERFLOW): + return "Receive overflowed buffer."; + case (RAIL_RX_PACKET_ABORT_CRC_ERROR): + return "CRC error aborted."; + case (RAIL_RX_PACKET_READY_CRC_ERROR): + return "CRC error accepted (details available)."; + case (RAIL_RX_PACKET_READY_SUCCESS): + return "Success (details available)."; + case (RAIL_RX_PACKET_RECEIVING): + return "Receiving in progress."; + default: + return "Unknown status"; + } +#else + (void) status; + return "enable DEVELHELP"; +#endif /* DEVELHELP */ +} + +const char *rail_radioState2str(RAIL_RadioState_t state) +{ +#ifdef DEVELHELP + switch (state) { + case (RAIL_RF_STATE_INACTIVE): + return "state inactive"; + case (RAIL_RF_STATE_ACTIVE): + return "state active / idle"; + case (RAIL_RF_STATE_RX): + return "state rx"; + case (RAIL_RF_STATE_TX): + return "state tx"; + default: + return "unknown state"; + } +#else + (void) state; + return "enable DEVELHELP"; +#endif /* DEVELHELP */ +} diff --git a/drivers/rail/rail_netdev.c b/drivers/rail/rail_netdev.c new file mode 100644 index 000000000000..ab6e12e6727e --- /dev/null +++ b/drivers/rail/rail_netdev.c @@ -0,0 +1,925 @@ +/* + * Copyright (C) 2018 Hochschule RheinMain + * + * 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. + */ + +#include + +#include "rail.h" +#include "em_core.h" + +#include "iolist.h" + +#include "net/netdev.h" +#include "net/netopt.h" + +#include "ps.h" +#include "xtimer.h" + +#include "mbox.h" + +#include "errno.h" + +#include "rail_radio.h" + +#include "rail_drv.h" +#include "rail_netdev.h" + +#include "log.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#include "rail.h" +#include "ieee802154/rail_ieee802154.h" + +#define _MAX_MHR_OVERHEAD (25) + +/* local declaration of driver methodes */ +static int _send(netdev_t *netdev, const iolist_t *iolist); +static int _recv(netdev_t *netdev, void *buf, size_t len, void *info); +static int _init(netdev_t *netdev); +static void _isr(netdev_t *netdev); +static int _get(netdev_t *netdev, netopt_t opt, void *val, size_t max_len); +static int _set(netdev_t *netdev, netopt_t opt, const void *val, size_t len); + +/* buffer for outgoing frame */ +static uint8_t frame[IEEE802154_FRAME_LEN_MAX + 1]; + +/* local helper functions */ +static netopt_state_t _get_state(rail_t *dev); +static int _set_state(rail_t *dev, netopt_state_t state); + +const netdev_driver_t rail_driver = { + .send = _send, + .recv = _recv, + .init = _init, + .isr = _isr, + .get = _get, + .set = _set, +}; + +static inline int rail_map_rail_status2errno(RAIL_Status_t code) +{ + switch (code) { + case (RAIL_STATUS_NO_ERROR): + return 0; + break; + case (RAIL_STATUS_INVALID_PARAMETER): + return -EINVAL; + break; + case (RAIL_STATUS_INVALID_STATE): + return -EPERM; + break; + case (RAIL_STATUS_INVALID_CALL): + return -EOPNOTSUPP; + break; + case (RAIL_STATUS_SUSPENDED): + break; + default: + break; + } +} + +static int _init(netdev_t *netdev) +{ + + rail_t *dev = (rail_t *)netdev; + + DEBUG("rail_netdev->init called\n"); + + /* set default channel */ +#if (RAIL_RADIO_BAND == 2400) + dev->netdev.chan = (CONFIG_IEEE802154_DEFAULT_CHANNEL); +#elif (RAIL_RADIO_BAND == 868) + dev->netdev.chan = 0; /* for 868MHz there is only one channel */ +#elif (RAIL_RADIO_BAND == 915) + dev->netdev.chan = 1; +#endif + +#ifdef MODULE_GNRC_SIXLOWPAN + dev->netdev.proto = GNRC_NETTYPE_SIXLOWPAN; +#elif MODULE_GNRC + dev->netdev.proto = GNRC_NETTYPE_UNDEF; +#endif + + netdev->driver = &rail_driver; + + int ret; + + ret = rail_init(dev); + + if (ret < 0) { + return ret; + } + + dev->max_retrans = 3; + + ret = rail_start_rx(dev); + if (ret < 0) { + return ret; + } + + return 0; +} + +void wait_for_send(netdev_t *netdev) +{ + rail_t *dev = (rail_t *)netdev; + + /* we exit this wait using an IRQ so we can't do it from IRQ */ + assert(!irq_is_in()); + + if (!dev->send_in_progress) { + return; + } + + while (1) { + /* TX in progress */ + /* Block until we get an IRQ */ + thread_flags_wait_any(RAIL_THREAD_FLAG_ISR); + /* Handle the IRQ */ + _isr(netdev); + + if (!dev->send_in_progress) { + break; + } + } +} + +static int _send(netdev_t *netdev, const iolist_t *iolist) +{ + DEBUG("rail_netdev->send called\n"); + + wait_for_send(netdev); + + rail_t *dev = (rail_t *)netdev; + uint8_t *pkt_buf = &(frame[1]); + size_t len = 0; + + /* + TODO check current state, make it depend what to do + if tx, return error + if init or so return error + if calibaration error + if idle or rx, send + if waiting for ack + no timeout return error + timeout update stat and continue + */ + + /* prepare frame, cpy header and payload */ + for (const iolist_t *iol = iolist; iol; iol = iol->iol_next) { + /* current packet data + FCS too long */ + if ((len + iol->iol_len + IEEE802154_FCS_LEN) > IEEE802154_FRAME_LEN_MAX) { + DEBUG("[rail] error: packet too large (len so far %u byte, combined %u) to be send\n", + (unsigned)len + IEEE802154_FCS_LEN, + (unsigned) len + IEEE802154_FCS_LEN + iol->iol_len); + return -EOVERFLOW; + } + + memcpy(pkt_buf + len, iol->iol_base, iol->iol_len); + len += iol->iol_len; + } + + /* frame length stored in first byte */ + frame[0] = len + IEEE802154_FCS_LEN; + + dev->num_retrans = 0; + dev->send_in_progress = true; + int ret = rail_transmit_frame(dev, frame, frame[0]); + + if (ret != 0) { + DEBUG("Can not send data\n"); + return ret; + } + + dev->netdev.netdev.event_callback((netdev_t *)&dev->netdev, + NETDEV_EVENT_TX_STARTED); + return (int)len; +} + +static int _recv(netdev_t *netdev, void *buf, size_t len, void *info) +{ + + DEBUG("rail_netdev->recv called\n"); + + rail_t *dev = (rail_t *)netdev; + + RAIL_Status_t ret; + + /* + TODO rewrite rationale ... + + the "receiving of a packet" becomes a bit ugly, since the riot driver api is + optimized for low level hardware interaction. Here, the silabs driver blob + already did the whole low level hw interaction. By the time this methode is + called the whole packet is already read and stored in memory. + Normally the packet have to be processed within the registered handler of + the driver blob. It is possible to hold packets, to process them later. + + If a packet is received the rail driver blob event callback stores the handle + for the packet and the basic meta data of the packet in an rail_event_msg_t and + adds it to a event queue contained in the netdev structure of this driver. + When the _recv methode is called several times to process the frame, it accesses + the last occured event. + After processing the packet it is removed from the queue and is released with + RAIL_ReleaseRxPacket(). + + TODO + - could there be a race condition when another event occures and send an new + event to the netdev layer? + - What if for whatever reason the upper layer does only call this methode + once for a packet? Than the event is not removed from the queue, the packet + is not released and the next call for a suppost new packet would yield the + packet before. + */ + + /* buf == NULL && len == 0 -> return packet size, no dropping */ + if (buf == NULL && len == 0) { + /* peek event_msg from queue */ + rail_event_msg_t event_msg; + rail_event_queue_peek(&(dev->event_queue), &event_msg); + + assert(event_msg.event == RAIL_EVENT_RX_PACKET_RECEIVED); + assert(event_msg.rx_packet != RAIL_RX_PACKET_HANDLE_INVALID); + + DEBUG("_recv: no dropping return packet size: 0x%02x\n", + event_msg.rx_packet_info.packetBytes); + + /* -1 because only payload length, without the packet length byte */ + return event_msg.rx_packet_info.packetBytes - 1; + } + + /* buf == NULL && len > 0 -> return packet size + drop it */ + if (buf == NULL && len > 0) { + /* get event from queue */ + rail_event_msg_t event_msg; + rail_event_queue_poll(&(dev->event_queue), &event_msg); + + assert(event_msg.event == RAIL_EVENT_RX_PACKET_RECEIVED); + assert(event_msg.rx_packet != RAIL_RX_PACKET_HANDLE_INVALID); + + /* and drop it */ + DEBUG("_recv: drop packet - return packet size: 0x%02x\n", + event_msg.rx_packet_info.packetBytes); + + RAIL_ReleaseRxPacket(dev->rhandle, event_msg.rx_packet); + + /* -1 because only payload length, without the packet length byte */ + return event_msg.rx_packet_info.packetBytes - 1; + } + + /* hurray, we are finally at the stage to move the payload to the upper + layer + */ + + /* get and remove the event from the event queue */ + rail_event_msg_t event_msg; + rail_event_queue_poll(&(dev->event_queue), &event_msg); + + /* not enough space in buf */ + /* len + 1, because packetBytes contains one byte for length */ + if ((len + 1) < event_msg.rx_packet_info.packetBytes) { + /* release packet */ + RAIL_ReleaseRxPacket(dev->rhandle, event_msg.rx_packet); + return -ENOBUFS; + } + + /* get more infos about the packet */ + RAIL_RxPacketDetails_t pack_details; + /* clear info struct */ + memset(&pack_details, 0, sizeof(RAIL_RxPacketDetails_t)); + + ret = RAIL_GetRxPacketDetails(dev->rhandle, event_msg.rx_packet, &pack_details); + + if (ret != RAIL_STATUS_NO_ERROR) { + LOG_ERROR("Error receiving new packet / frame - msg: %s\n", rail_error2str(ret)); + return -1; + } + + DEBUG("time received: %lu " + "crcStatus %s " + "isAck: %s " + "subPhy: %u " + "rssiLatch: %d dBm " + "lqi: %u " + "syncWordId: %u " + "antenna id: %u " + "payload size: %u \n", + pack_details.timeReceived.packetTime, + pack_details.crcPassed ? "Passed" : "Failed", + pack_details.isAck ? "Ack" : "Not a Ack", + pack_details.subPhyId, + pack_details.rssi, + pack_details.lqi, + pack_details.syncWordId, + pack_details.antennaId, + event_msg.rx_packet_info.packetBytes); + + /* TODO question: with length info in byte 0 or without? */ + /* - first try without, skip it (seams to work) */ + event_msg.rx_packet_info.firstPortionData++; + event_msg.rx_packet_info.firstPortionBytes--; + event_msg.rx_packet_info.packetBytes--; + + /* copy payload from packet to the provided buffer */ + RAIL_CopyRxPacket((uint8_t *)buf, &(event_msg.rx_packet_info)); + + /* + DEBUG("Print buf cpy size %d: ", cpy_size); + for (int i = 0; i < cpy_size; i++) { + if (i % 4 == 0) DEBUG("\n"); + DEBUG("0x%02x ", ((uint8_t*)buf)[i]); + } + DEBUG("\n"); + */ + + /* if requested, provide meta infos as well */ + /* TODO move RAIL_GetRxPacketDetails in this block as well? */ + if (info != NULL) { + netdev_ieee802154_rx_info_t *rx_info = info; + rx_info->rssi = pack_details.rssi; + rx_info->lqi = pack_details.lqi; + } + + /* free packet, set handle to null */ + RAIL_ReleaseRxPacket(dev->rhandle, event_msg.rx_packet); + + return event_msg.rx_packet_info.packetBytes; +} + +static void _isr(netdev_t *netdev) +{ + + rail_t *dev = (rail_t *) netdev; + + thread_flags_clear(RAIL_THREAD_FLAG_ISR); + + /* get event from ring buffer, but leave it there */ + rail_event_msg_t event_msg; + rail_event_queue_peek(&(dev->event_queue), &event_msg); + + RAIL_Events_t event = event_msg.event; + + DEBUG("[rail_netdev->isr] Rail event count %lu, id: 0x%lx - %s\n", event_msg.event_count, (uint32_t) event, rail_event2str(event)); + + /* this shouldn't happen, if it does there is a race condition */ + if (event == RAIL_EVENTS_NONE) { + LOG_INFO("[rail] netdev-isr called, but no event occurred -> " + "race condition, please file a bug report\n"); + return; + } + + /* the basic packet handling was done in the RAIL handler function. + Now only the upper layer have to be informed + */ + if (event & RAIL_EVENT_RX_PACKET_RECEIVED) { + netdev->event_callback(netdev, NETDEV_EVENT_RX_COMPLETE); + return; + } + + /* no need to keep the event_msg in the queue for the other possible events */ + rail_event_queue_poll(&(dev->event_queue), NULL); + + /* event description c&p from RAIL API docu */ + + /* rail events are a bitmask, therefore multible events within this call + possible + */ + + if (event & RAIL_EVENT_TX_CHANNEL_BUSY) { + DEBUG("Rail event Tx channel busy\n"); + dev->netdev.netdev.event_callback((netdev_t *)&dev->netdev, NETDEV_EVENT_TX_MEDIUM_BUSY); + return; + /* TODO set state? */ + } + + /* Notifies the application when searching for an ack packet has timed out */ + if (event & RAIL_EVENT_RX_ACK_TIMEOUT) { + DEBUG("Rail event RX ACK TIMEOUT\n"); + + if (dev->num_retrans < dev->max_retrans) { + /* Perform frame retransmission */ + ++dev->num_retrans; + DEBUG("[kw41zrf] TX retry %u\n", (unsigned)dev->num_retrans); + /* Resubmit the frame for transmission */ + rail_transmit_frame(dev, frame, frame[0]); + + } else { + dev->netdev.netdev.event_callback((netdev_t *)&dev->netdev, + NETDEV_EVENT_TX_NOACK); + } + return; + } + + /* Occurs when a packet was sent */ + if (event & (RAIL_EVENT_TX_PACKET_SENT | RAIL_EVENT_TXACK_PACKET_SENT)) { + DEBUG("Rail event Tx packet sent \n"); + + dev->send_in_progress = false; + dev->netdev.netdev.event_callback((netdev_t *)&dev->netdev, NETDEV_EVENT_TX_COMPLETE); + return; + /* TODO set state? */ + } + + /* Occurs when a packet being received has a frame error */ + if (event & RAIL_EVENT_RX_FRAME_ERROR) { + DEBUG("Rail event RX frame error\n"); + dev->netdev.netdev.event_callback((netdev_t *)&dev->netdev, NETDEV_EVENT_CRC_ERROR); + + /* TODO statistic? */ + } + + /* Occurs when a packet's address does not match the filtering settings */ + if (event & RAIL_EVENT_RX_ADDRESS_FILTERED) { + DEBUG("Rail event rx address filtered\n"); + } + + /* TODO RAIL_EVENT_RX_PACKET_ABORTED */ + /* Occurs when a packet is aborted, but a more specific reason (such as + RAIL_EVENT_RX_ADDRESS_FILTERED) isn't known. + */ + + /* TODO RAIL_EVENT_TXACK_PACKET_SENT */ + /* Occurs when an ack packet was sent. */ + + /* Occurs when a transmit is aborted by the user */ + if (event & RAIL_EVENT_TX_ABORTED) { + DEBUG("Rail event Tx aborted\n"); + + /* TODO set state? */ + } + + /* TODO RAIL_EVENT_TXACK_ABORTED */ + /* Occurs when a transmit is aborted by the user */ + + /* Occurs when a transmit is blocked from occurring due to having called + RAIL_EnableTxHoldOff(). + */ + if (event & RAIL_EVENT_TX_BLOCKED) { + DEBUG("Rail event Tx blocked\n"); + + /* TODO how to notify layer above? */ + /* TODO set state? */ + } + + /* TODO RAIL_EVENT_TXACK_BLOCKED */ + /* Occurs when an ack transmit is blocked from occurring due to having + called RAIL_EnableTxHoldOff(). + */ + + /* Occurs when the transmit buffer underflows. */ + if (event & RAIL_EVENT_TX_UNDERFLOW) { + LOG_INFO("Rail event Tx underflow - > should not happen: race condition" + " while transmitting new package, please file a bug report\n"); + /* should not happen as long as the packet is written as whole into the + RAIL driver blob buffer*/ + } + + /* TODO RAIL_EVENT_TXACK_UNDERFLOW */ + /* Occurs when the ack transmit buffer underflows.*/ +} + +static int _get(netdev_t *netdev, netopt_t opt, void *val, size_t max_len) +{ + + if (netdev == NULL) { + return -ENODEV; + } + + rail_t *dev = (rail_t *)netdev; + + /* TODO + - is it necessary to differencate if transceiver is active or not? + - NETOPT_BANDWIDTH could be calculated, but is it usefull? + - NETOPT_CHANNEL_FREQUENCY + - NETOPT_AUTOCCA + */ + int ret = -ENOTSUP; + + switch (opt) { + case (NETOPT_MAX_PACKET_SIZE): + assert(max_len >= sizeof(int16_t)); + *((uint16_t *)val) = IEEE802154_FRAME_LEN_MAX - _MAX_MHR_OVERHEAD; + ret = sizeof(uint16_t); + break; + case (NETOPT_CHANNEL_PAGE): + assert(max_len >= sizeof(uint16_t)); + ((uint8_t *)val)[1] = 0; +#ifdef RAIL_RADIO_HAS_SUBGHZ + ((uint8_t *)val)[0] = dev->channel_page; +#else + ((uint8_t *)val)[0] = 0; /* for only 2.4GHz there is only channel page 0 possible */ +#endif + return sizeof(uint16_t); + break; + case (NETOPT_STATE): + assert(max_len >= sizeof(netopt_state_t)); + *((netopt_state_t *)val) = _get_state(dev); + return sizeof(netopt_state_t); + break; + case (NETOPT_TX_POWER): + assert(max_len >= sizeof(int16_t)); + /* rail tx dbm has a factor of 10 -> loosing resolution here */ + /* get transmitt power with new RAIL helper function */ + RAIL_TxPower_t power_tx_ddBm = RAIL_GetTxPowerDbm(dev->rhandle); + *((uint16_t *)val) = (int16_t) (power_tx_ddBm / 10); + ret = sizeof(int16_t); + break; + case (NETOPT_RETRANS): + assert(max_len >= sizeof(int8_t)); + *((uint8_t *)val) = dev->max_retrans; + ret = sizeof(uint8_t); + break; + case (NETOPT_PROMISCUOUSMODE): + if (dev->promiscuousMode == true) { + *((netopt_enable_t *)val) = NETOPT_ENABLE; + } + else { + *((netopt_enable_t *)val) = NETOPT_DISABLE; + } + ret = sizeof(netopt_enable_t); + break; + case (NETOPT_AUTOACK): + if (RAIL_IsRxAutoAckPaused(dev->rhandle) == false) { + *((netopt_enable_t *)val) = NETOPT_ENABLE; + } + else { + *((netopt_enable_t *)val) = NETOPT_DISABLE; + } + ret = sizeof(netopt_enable_t); + break; + case (NETOPT_CSMA): + /* if tries == 0 -> CSMA is disabled, or rather the packet is send + immediately + */ + if (dev->csma_config.csmaTries == 0) { + *((netopt_enable_t *)val) = NETOPT_DISABLE; + } + else { + *((netopt_enable_t *)val) = NETOPT_ENABLE; + } + ret = sizeof(netopt_enable_t); + break; + case (NETOPT_CSMA_RETRIES): + assert(max_len >= sizeof(int8_t)); + *((uint8_t *)val) = dev->csma_config.csmaTries; + ret = sizeof(uint8_t); + break; + + case (NETOPT_BANDWIDTH): + /* + assert(max_len >= sizeof(int8_t)); + // bits/seconds + uint32_t bw = RAIL_BitRateGet(); + uint8_t bw_kb = bw/1000; + *((uint8_t *)val) = bw_kb; + ret = sizeof(uint8_t); + */ + break; + default: + /* DEBUG("not supported netopt code at rail drv %d str %s \n", opt, + netopt2str(opt)); */ + break; + } + if (ret != -ENOTSUP) { + return ret; + } + + ret = netdev_ieee802154_get((netdev_ieee802154_t *)netdev, opt, val, max_len); + + if (ret != -ENOTSUP) { + return ret; + } + + return ret; +} + +static int _set(netdev_t *netdev, netopt_t opt, const void *val, size_t len) +{ + + if (netdev == NULL) { + return -ENODEV; + } + + rail_t *dev = (rail_t *)netdev; + int res = -ENOTSUP; + RAIL_Status_t rail_ret; + uint16_t le_u16; + uint64_t le_u64; + + /* TODO wake up transceiver? necessary? or done automaticaly by RAIL driver + blob? + */ + + switch (opt) { + + case (NETOPT_CHANNEL): + /* since we have to provide the channel for each tx or rx, just + change the attribute in the netdev struct */ + + assert(len == sizeof(uint16_t)); + uint8_t chan = (((const uint16_t *)val)[0]) & UINT8_MAX; + + if (dev->params.freq == RAIL_TRANSCEIVER_FREQUENCY_2P4GHZ) { + if (chan < RAIL_2P4GH_MIN_CHANNEL || chan > RAIL_2P4GH_MAX_CHANNEL) { + res = -EINVAL; + break; + } + } + else if (dev->params.freq == RAIL_TRANSCEIVER_FREQUENCY_868MHZ) { + /* TODO for SUB GHZ -> support channel page != 0 */ + /* 868MHz has only one channel at channel page 0 -> channel 0! */ + if (chan != RAIL_868MHZ_DEFAULT_CHANNEL) { + res = -EINVAL; + break; + } + } + else if (dev->params.freq == RAIL_TRANSCEIVER_FREQUENCY_912MHZ) { + /* TODO for SUB GHZ -> support channel page != 0 */ + if (chan > RAIL_912MHZ_MAX_CHANNEL) { + res = -EINVAL; + break; + } + } + else { + res = -EINVAL; + DEBUG("Unknown radio frequency configured\n"); + assert(false); + break; + } + /* since we have to provide the channel for each tx or rx, just + change the attribute in the netdev struct */ + /* TODO if chan_old != chan_new -> interupt rx op? */ + /* don't set res to set netdev_ieee802154_t::chan */ + dev->netdev.chan = chan; + + break; + case (NETOPT_CHANNEL_PAGE): + assert(len == sizeof(uint16_t)); + uint8_t page = (((const uint16_t *)val)[0]) & UINT8_MAX; +#ifdef RAIL_RADIO_HAS_SUBGHZ + /* TODO support channel pages > 0 */ + if ((page != 0) ) { + res = -EINVAL; + } + else { + dev->channel_page = page; + res = sizeof(uint16_t); + } +#else + /* 2.4 GHz only supports page 0 */ + if (page != 0) { + res = -EINVAL; + } + else { + res = sizeof(uint16_t); + } +#endif + break; + case (NETOPT_ADDRESS): + assert(len <= sizeof(uint16_t)); + /* RIOT uses Big endian, RAIL driver blob little endian ... */ + + le_u16 = ntohs(*((const uint16_t *)val)); + + /* RAIL driver blob can manage upto RAIL_IEEE802154_MAX_ADDRESSES + TODO how does RIOT handle multible short addresses? + atm just at pos 0 + */ + rail_ret = RAIL_IEEE802154_SetShortAddress(dev->rhandle, le_u16, 0); + + if (rail_ret != RAIL_STATUS_NO_ERROR) { + DEBUG("[rail] error setting short address: msg: %s\n", + rail_error2str(rail_ret)); + res = -EFAULT; + break; + } + + /* don't set res to set netdev_ieee802154_t::short_addr */ + break; + case (NETOPT_ADDRESS_LONG): + assert(len <= sizeof(uint64_t)); + /* RAIL driver blob can manage upto RAIL_IEEE802154_MAX_ADDRESSES + TODO how does RIOT handle multible long addresses? + atm just at pos 0 + */ + /* now the long addr ... the RAIL API docu says it have to be in + "over the air byte order", therefore little endian again ... */ + le_u64 = byteorder_swapll(*((const uint64_t *)val)); + + rail_ret = RAIL_IEEE802154_SetLongAddress(dev->rhandle, (uint8_t *)&le_u64, 0); + + if (rail_ret != RAIL_STATUS_NO_ERROR) { + DEBUG("[rail] error setting long address: msg: %s\n", + rail_error2str(rail_ret)); + res = -EFAULT; + break; + } + /* don't set res to set netdev_ieee802154_t::long_addr */ + break; + case (NETOPT_NID): + assert(len <= sizeof(uint16_t)); + /* RIOT driver blob supports multible PAN IDs. Does RIOT as well? */ + + rail_ret = RAIL_IEEE802154_SetPanId(dev->rhandle, *((const uint16_t *)val), 0); + + if (rail_ret != RAIL_STATUS_NO_ERROR) { + DEBUG("[rail] error setting NIB/pan id: msg: %s\n", + rail_error2str(rail_ret)); + res = -EFAULT; + break; + } + + /* don't set res to set netdev_ieee802154_t::pan */ + break; + case (NETOPT_TX_POWER): + assert(len <= sizeof(int16_t)); + + /* RAIL driver blob supports deci-dBm, RIOT only dBm*/ + int16_t dBm = *((const int16_t *)val); + int16_t ddBm = dBm * 10; + + rail_ret = RAIL_SetTxPowerDbm(dev->rhandle, ddBm); + + if (rail_ret != RAIL_STATUS_NO_ERROR) { + DEBUG("[rail] error setting NIB/pan id: msg: %s\n", + rail_error2str(rail_ret)); + res = -EFAULT; + break; + } + res = sizeof(uint16_t); + break; + case (NETOPT_STATE): + assert(len <= sizeof(netopt_state_t)); + res = _set_state(dev, *((const netopt_state_t *)val)); + break; + case (NETOPT_AUTOACK): + assert(len <= sizeof(netopt_enable_t)); + bool state = !*(const bool *)val; + RAIL_PauseRxAutoAck(dev->rhandle, state); + res = sizeof(netopt_enable_t); + break; + case (NETOPT_RETRANS): + assert(len <= sizeof(uint8_t)); + dev->max_retrans = *((const uint8_t *)val); + res = sizeof(uint8_t); + break; + case (NETOPT_PROMISCUOUSMODE): + + /* we have to store this info, because we can not ask the RAIL + driver blob, if promiscuousMode is set + */ + dev->promiscuousMode = ((const bool *)val)[0]; + + rail_ret = RAIL_IEEE802154_SetPromiscuousMode(dev->rhandle, dev->promiscuousMode); + + if (rail_ret != RAIL_STATUS_NO_ERROR) { + DEBUG("[rail] error setting promiscuous mode: msg: %s\n", + rail_error2str(rail_ret)); + res = -EFAULT; + break; + } + res = sizeof(netopt_enable_t); + break; + case (NETOPT_CSMA): + /* deactivate CSMA */ + if (((const bool *)val)[0] == false) { + dev->csma_config.csmaTries = 0; + } + else { + /* TODO set it to the default value? */ + dev->csma_config.csmaTries = RAIL_DEFAULT_CSMA_TRIES; + } + res = sizeof(netopt_enable_t); + break; + case (NETOPT_CSMA_RETRIES): + assert(len <= sizeof(uint8_t)); + /* tries == 0 -> CSMA is disabled */ + if (dev->csma_config.csmaTries == 0 || + (*((uint8_t *)val) > RAIL_MAX_LBT_TRIES)) { + /* If CSMA is disabled, don't allow setting retries */ + res = -EINVAL; + } + else { + dev->csma_config.csmaTries = *((const uint8_t *)val); + res = sizeof(uint8_t); + } + break; + case (NETOPT_CCA_THRESHOLD): + assert(len <= sizeof(int8_t)); + + rail_ret = RAIL_SetCcaThreshold(dev->rhandle, *((const int8_t *)val)); + + if (rail_ret != RAIL_STATUS_NO_ERROR) { + DEBUG("[rail] error CCA threshold: msg: %s\n", + rail_error2str(rail_ret)); + res = -EFAULT; + break; + } + + res = sizeof(int8_t); + break; + case (NETOPT_ACK_PENDING): + if (((const bool *)val)[0] == true) { + dev->netdev.flags |= NETDEV_IEEE802154_FRAME_PEND; + + } else { + dev->netdev.flags &= ~NETDEV_IEEE802154_FRAME_PEND; + } + res = sizeof(netopt_enable_t); + break; + default: + break; + } + + if (res == -ENOTSUP) { + res = netdev_ieee802154_set((netdev_ieee802154_t *)netdev, opt, val, len); + } + + return res; + + /* TODO + + - NETOPT_PRELOADING ? + - NETOPT_RX_START_IRQ ? + - NETOPT_RX_END_IRQ ? + - NETOPT_TX_START_IRQ ? + - NETOPT_TX_END_IRQ ? + + - bool RAIL_IEEE802154_IsEnabled (void) ? + - void RAIL_EnableTxHoldOff (RAIL_Handle_t railHandle, bool enable) + - bool RAIL_IsTxHoldOffEnabled (RAIL_Handle_t railHandle) + + - No Option for pan coord? RAIL_Status_t + RAIL_IEEE802154_SetPanCoordinator (bool isPanCoordinator) + - NETOPT_IPV6_ADDR_REMOVE + - Set to 0x00 00 00 00 00 00 00 00 to disable for this index. + */ + + DEBUG("rail_netdev->set called opt %s val %p len %d \n", netopt2str(opt), val, len); + + return 0; +} + +/* impl local helper functions */ + +netopt_state_t _get_state(rail_t *dev) +{ + + /* check state that can not */ + switch (dev->state) { + case (RAIL_TRANSCEIVER_STATE_UNINITIALIZED): + return NETOPT_STATE_OFF; + case (RAIL_TRANSCEIVER_STATE_SLEEP): + return NETOPT_STATE_SLEEP; + case (RAIL_TRANSCEIVER_STATE_OFF): + return NETOPT_STATE_OFF; + } + + /* check state from RAIL */ + + RAIL_RadioState_t state = RAIL_GetRadioState(dev->rhandle); + + if (state & RAIL_RF_STATE_RX) { + return NETOPT_STATE_RX; + } + else if (state & RAIL_RF_STATE_TX) { + return NETOPT_STATE_TX; + } + else if (state == RAIL_RF_STATE_IDLE) { + return NETOPT_STATE_IDLE; + } + + return NETOPT_STATE_IDLE; +} + +static int _set_state(rail_t *dev, netopt_state_t state) +{ + (void) dev; + switch (state) { + case NETOPT_STATE_STANDBY: + RAIL_Idle(dev->rhandle, RAIL_IDLE_ABORT, true); + return sizeof(netopt_state_t); + break; + case NETOPT_STATE_SLEEP: + RAIL_Idle(dev->rhandle, RAIL_IDLE_ABORT, true); + return sizeof(netopt_state_t); + break; + case NETOPT_STATE_IDLE: + RAIL_StartRx(dev->rhandle, dev->netdev.chan, NULL); + return sizeof(netopt_state_t); + break; + case NETOPT_STATE_TX: + break; + case NETOPT_STATE_RESET: + break; + default: + return -ENOTSUP; + } + return -ENOTSUP; +} diff --git a/pkg/gecko_sdk/Makefile b/pkg/gecko_sdk/Makefile index 7c9807a69a0f..f391e1e47590 100644 --- a/pkg/gecko_sdk/Makefile +++ b/pkg/gecko_sdk/Makefile @@ -13,5 +13,7 @@ ifneq (llvm,$(TOOLCHAIN)) CFLAGS += -Wno-int-in-bool-context endif +export EFM32_FAMILY = $(CPU_FAM) + all: "$(MAKE)" -C $(PKG_SOURCE_DIR)/dist diff --git a/pkg/gecko_sdk/Makefile.include b/pkg/gecko_sdk/Makefile.include index 18fd768fd71f..d597eac86614 100644 --- a/pkg/gecko_sdk/Makefile.include +++ b/pkg/gecko_sdk/Makefile.include @@ -1,2 +1,8 @@ INCLUDES += -I$(PKGDIRBASE)/gecko_sdk/dist/emlib/inc INCLUDES += -I$(PKGDIRBASE)/gecko_sdk/dist/emlib-extra/inc + +ifneq (,$(filter gecko_sdk_librail,$(USEMODULE))) + CFLAGS_FPU = -mfloat-abi=softfp -mfpu=fpv4-sp-d16 + # Blacklisted for llvm because `CFLAGS_FPU` is used before its final value set here + TOOLCHAINS_BLACKLIST += llvm +endif diff --git a/sys/auto_init/auto_init.c b/sys/auto_init/auto_init.c index 7859c4f004c6..319285a12ff1 100644 --- a/sys/auto_init/auto_init.c +++ b/sys/auto_init/auto_init.c @@ -260,4 +260,5 @@ void auto_init(void) auto_init_dfplayer(); } } + } diff --git a/sys/net/gnrc/netif/init_devs/auto_init_rail.c b/sys/net/gnrc/netif/init_devs/auto_init_rail.c new file mode 100644 index 000000000000..e1cf68c19941 --- /dev/null +++ b/sys/net/gnrc/netif/init_devs/auto_init_rail.c @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2018 Hochschule RheinMain + * + * 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. + */ + + +#ifdef MODULE_RAIL + +#include + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#include "log.h" +#include "net/gnrc/netif/ieee802154.h" +#include "net/gnrc.h" + +#include "rail_drv.h" +#include "rail_params.h" + +#define RAIL_MAC_STACKSIZE (THREAD_STACKSIZE_DEFAULT) +#ifndef RAIL_MAC_PRIO +#define RAIL_MAC_PRIO (GNRC_NETIF_PRIO) +#endif + +#define RAIL_NUM (sizeof(rail_params) / sizeof(rail_params[0])) + +static rail_t rail_devs[RAIL_NUM]; +static gnrc_netif_t _netif[RAIL_NUM]; +static char _rail_stacks[RAIL_NUM][RAIL_MAC_STACKSIZE]; + + + +void auto_init_rail(void) +{ + for (unsigned i = 0; i < RAIL_NUM; i++) { + + LOG_DEBUG("[auto_init_netif] initializing rail #%u\n", i); + + rail_setup(&rail_devs[i], &rail_params[i]); + + /* init ieee802154 layer */ + gnrc_netif_ieee802154_create(&_netif[i], + _rail_stacks[i], + RAIL_MAC_STACKSIZE, + RAIL_MAC_PRIO, + "rail 802.15.4", + (netdev_t *)&rail_devs[i]); + } +} + +#else +typedef int dont_be_pedantic; + +#endif /* ----- #ifdef MODULE_RAIL_INC ----- */ diff --git a/sys/net/gnrc/netif/init_devs/init.c b/sys/net/gnrc/netif/init_devs/init.c index 765ef4b72727..31c5ac20b85f 100644 --- a/sys/net/gnrc/netif/init_devs/init.c +++ b/sys/net/gnrc/netif/init_devs/init.c @@ -163,4 +163,10 @@ void gnrc_netif_init_devs(void) extern void auto_init_nrf802154(void); auto_init_nrf802154(); } + + if (IS_USED(MODULE_RAIL)) { + extern void auto_init_rail(void); + auto_init_rail(); + } + }