diff --git a/Makefile.dep b/Makefile.dep index c2133a365f..549493a12d 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -201,3 +201,7 @@ ifneq (,$(filter oonf_common,$(USEMODULE))) USEPKG += oonf_api USEMODULE += socket_base endif + +ifneq (,$(filter ng_at86rf2%,$(USEMODULE))) + USEMODULE += ng_at86rf2xx +endif diff --git a/Makefile.pseudomodules b/Makefile.pseudomodules index 3536c4ab5e..e3f51876d9 100644 --- a/Makefile.pseudomodules +++ b/Makefile.pseudomodules @@ -3,3 +3,7 @@ PSEUDOMODULES += transport_layer PSEUDOMODULES += ng_ipv6_router PSEUDOMODULES += pktqueue PSEUDOMODULES += ng_netbase + +# include variants of the AT86RF2xx drivers as pseudo modules +PSEUDOMODULES += ng_at86rf23% +PSEUDOMODULES += ng_at86rf21% diff --git a/drivers/Makefile.include b/drivers/Makefile.include index 1075ca8593..08f9fccf56 100644 --- a/drivers/Makefile.include +++ b/drivers/Makefile.include @@ -13,6 +13,9 @@ endif ifneq (,$(filter at86rf231,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/drivers/at86rf231/include endif +ifneq (,$(filter ng_at86rf2xx,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/ng_at86rf2xx/include +endif ifneq (,$(filter isl29020,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/drivers/isl29020/include endif diff --git a/drivers/include/ng_at86rf2xx.h b/drivers/include/ng_at86rf2xx.h new file mode 100644 index 0000000000..b62e5edfa8 --- /dev/null +++ b/drivers/include/ng_at86rf2xx.h @@ -0,0 +1,366 @@ +/* + * Copyright (C) 2015 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License v2.1. See the file LICENSE in the top level directory for more + * details. + */ + +/** + * @defgroup drivers_ng_at86rf2xx AT86RF2xx based drivers + * @ingroup drivers + * + * This module contains drivers for radio devices in Atmel's AT86RF2xx series. + * The driver is aimed to work with all devices of this series. + * + * @{ + * + * @file + * @brief Interface definition for AT86RF2xx based drivers + * + * @author Thomas Eichinger + * @author Hauke Petersen + * @author Kaspar Schleiser + */ + +#ifndef NG_AT86RF2XX_H_ +#define NG_AT86RF2XX_H_ + +#include + +#include "board.h" +#include "periph/spi.h" +#include "periph/gpio.h" +#include "net/ng_netdev.h" +#include "ng_at86rf2xx.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Maximum possible packet size in byte + */ +#define NG_AT86RF2XX_MAX_PKT_LENGTH (127) + +/** + * @brief Default addresses used if the CPUID module is not present + * @{ + */ +#define NG_AT86RF2XX_DEFAULT_ADDR_SHORT (0x0230) +#define NG_AT86RF2XX_DEFAULT_ADDR_LONG (0x1222334455667788) +/** @} */ + +/** + * @brief Channel configuration + * @{ + */ +#ifdef MODULE_NG_AT86RF212B +/* the AT86RF212B has a sub-1GHz radio */ +#define NG_AT86RF2XX_MIN_CHANNEL (0) +#define NG_AT86RF2XX_MAX_CHANNEL (10) +#define NG_AT86RF2XX_DEFAULT_CHANNEL (5) +#else +#define NG_AT86RF2XX_MIN_CHANNEL (11U) +#define NG_AT86RF2XX_MAX_CHANNEL (26U) +#define NG_AT86RF2XX_DEFAULT_CHANNEL (17U) +#endif +/** @} */ + +/** + * @brief Default PAN ID + * + * TODO: Read some global network stack specific configuration value + */ +#define NG_AT86RF2XX_DEFAULT_PANID (0x0023) + +/** + * @brief Default TX power (0dBm) + */ +#define NG_AT86RF2XX_DEFAULT_TXPOWER (0U) + +/** + * @brief Flags for device internal states (see datasheet) + * @{ + */ +#define NG_AT86RF2XX_STATE_TRX_OFF (0x08) /**< idle */ +#define NG_AT86RF2XX_STATE_PLL_ON (0x09) /**< ready to transmit */ +#define NG_AT86RF2XX_STATE_SLEEP (0x0f) /**< sleep mode */ +#define NG_AT86RF2XX_STATE_BUSY_RX_AACK (0x11) /**< busy receiving data */ +#define NG_AT86RF2XX_STATE_BUSY_TX_ARET (0x12) /**< busy transmitting data */ +#define NG_AT86RF2XX_STATE_RX_AACK_ON (0x16) /**< wait for incoming data */ +#define NG_AT86RF2XX_STATE_TX_ARET_ON (0x19) /**< ready for sending data */ +#define NG_AT86RF2XX_STATE_IN_PROGRESS (0x1f) /**< ongoing state conversion */ +/** @} */ + +/** + * @brief Internal device option flags + * @{ + */ +#define NG_AT86RF2XX_OPT_AUTOACK (0x0001) /**< auto ACKs active */ +#define NG_AT86RF2XX_OPT_CSMA (0x0002) /**< CSMA active */ +#define NG_AT86RF2XX_OPT_PROMISCUOUS (0x0004) /**< promiscuous mode + * active */ +#define NG_AT86RF2XX_OPT_PRELOADING (0x0008) /**< preloading enabled */ +#define NG_AT86RF2XX_OPT_TELL_TX_START (0x0010) /**< notify MAC layer on TX + * start */ +#define NG_AT86RF2XX_OPT_TELL_TX_END (0x0020) /**< notify MAC layer on TX + * finished */ +#define NG_AT86RF2XX_OPT_TELL_RX_START (0x0040) /**< notify MAC layer on RX + * start */ +#define NG_AT86RF2XX_OPT_TELL_RX_END (0x0080) /**< notify MAC layer on RX + * finished */ +#define NG_AT86RF2XX_OPT_RAWDUMP (0x0100) /**< pass RAW frame data to + * upper layer */ +#define NG_AT86RF2XX_OPT_SRC_ADDR_LONG (0x0200) /**< send data using long + * source address */ +#define NG_AT86RF2XX_OPT_USE_SRC_PAN (0x0400) /**< do not compress source + * PAN ID */ +/** @} */ + +/** + * @brief Device descriptor for AT86RF2XX radio devices + */ +typedef struct { + /* netdev fields */ + const ng_netdev_driver_t *driver; /**< pointer to the devices interface */ + ng_netdev_event_cb_t event_cb; /**< netdev event callback */ + kernel_pid_t mac_pid; /**< the driver's thread's PID */ + /* device specific fields */ + spi_t spi; /**< used SPI device */ + gpio_t cs_pin; /**< chip select pin */ + gpio_t sleep_pin; /**< sleep pin */ + gpio_t reset_pin; /**< reset pin */ + gpio_t int_pin; /**< external interrupt pin */ + ng_nettype_t proto; /**< protocol the radio expects */ + uint8_t state; /**< current state of the radio */ + uint8_t seq_nr; /**< sequence number to use next */ + uint8_t frame_len; /**< length of the current TX frame */ + uint16_t pan; /**< currently used PAN ID */ + uint8_t addr_short[2]; /**< the radio's short address */ + uint8_t addr_long[8]; /**< the radio's long address */ + uint16_t options; /**< state of used options */ + uint8_t idle_state; /**< state to return to after sending */ +} ng_at86rf2xx_t; + + +/** + * @brief Initialize a given AT86RF2xx device + * + * @param[out] dev device descriptor + * @param[in] spi SPI bus the device is connected to + * @param[in] spi_speed SPI speed to use + * @param[in] cs_pin GPIO pin connected to chip select + * @param[in] int_pin GPIO pin connected to the interrupt pin + * @param[in] sleep_pin GPIO pin connected to the sleep pin + * @param[in] reset_pin GPIO pin connected to the reset pin + * + * @return 0 on success + * @return <0 on error + */ +int ng_at86rf2xx_init(ng_at86rf2xx_t *dev, spi_t spi, spi_speed_t spi_speed, + gpio_t cs_pin, gpio_t int_pin, + gpio_t sleep_pin, gpio_t reset_pin); + +/** + * @brief Trigger a hardware reset and configure radio with default values + * + * @param[in] dev device to reset + */ +void ng_at86rf2xx_reset(ng_at86rf2xx_t *dev); + +/** + * @brief Trigger a clear channel assessment + * + * @param[in] dev device to use + * + * @return true if channel is clear + * @return false if channel is busy + */ +bool ng_at86rf2xx_cca(ng_at86rf2xx_t *dev); + +/** + * @brief Get the short address of the given device + * + * @param[in] dev device to read from + * + * @return the currently set (2-byte) short address + */ +uint16_t ng_at86rf2xx_get_addr_short(ng_at86rf2xx_t *dev); + +/** + * @brief Set the short address of the given device + * + * @param[in] dev device to write to + * @param[in] addr (2-byte) short address to set + */ +void ng_at86rf2xx_set_addr_short(ng_at86rf2xx_t *dev, uint16_t addr); + +/** + * @brief Get the configured long address of the given device + * + * @param[in] dev device to read from + * + * @return the currently set (8-byte) long address + */ +uint64_t ng_at86rf2xx_get_addr_long(ng_at86rf2xx_t *dev); + +/** + * @brief Set the long address of the given device + * + * @param[in] dev device to write to + * @param[in] addr (8-byte) long address to set + */ +void ng_at86rf2xx_set_addr_long(ng_at86rf2xx_t *dev, uint64_t addr); + +/** + * @brief Get the configured channel of the given device + * + * @param[in] dev device to read from + * + * @return the currently set channel + */ +uint8_t ng_at86rf2xx_get_chan(ng_at86rf2xx_t *dev); + +/** + * @brief Set the channel of the given device + * + * @param[in] dev device to write to + * @param[in] chan channel to set + */ +void ng_at86rf2xx_set_chan(ng_at86rf2xx_t *dev, uint8_t chan); + +/** + * @brief Get the configured PAN ID of the given device + * + * @param[in] dev device to read from + * + * @return the currently set PAN ID + */ +uint16_t ng_at86rf2xx_get_pan(ng_at86rf2xx_t *dev); + +/** + * @brief Set the PAN ID of the given device + * + * @param[in] dev device to write to + * @param[in] pan PAN ID to set + */ +void ng_at86rf2xx_set_pan(ng_at86rf2xx_t *dev, uint16_t pan); + +/** + * @brief Get the configured transmission power of the given device [in dBm] + * + * @param[in] dev device to read from + * + * @return configured transmission power in dBm + */ +int16_t ng_at86rf2xx_get_txpower(ng_at86rf2xx_t *dev); + +/** + * @brief Set the transmission power of the given device [in dBm] + * + * If the device does not support the exact dBm value given, it will set a value + * as close as possible to the given value. If the given value is larger or + * lower then the maximal or minimal possible value, the min or max value is + * set, respectively. + * + * @param[in] dev device to write to + * @param[in] txpower transmission power in dBm + */ +void ng_at86rf2xx_set_txpower(ng_at86rf2xx_t *dev, int16_t txpower); + +/** + * @brief Enable or disable driver specific options + * + * @param[in] dev device to set/clear option flag for + * @param[in] option option to enable/disable + * @param[in] state true for enable, false for disable + */ +void ng_at86rf2xx_set_option(ng_at86rf2xx_t *dev, uint16_t option, bool state); + +/** + * @brief Get the given devices current internal state + * + * @param[in] dev device to get state of + * @return the current state of the given device + */ +uint8_t ng_at86rf2xx_get_state(ng_at86rf2xx_t *dev); + +/** + * @brief Set the state of the given device (trigger a state change) + * + * @param[in] dev device to change state of + * @param[in] state the targeted new state + */ +void ng_at86rf2xx_set_state(ng_at86rf2xx_t *dev, uint8_t state); + +/** + * @brief Convenience function for simply sending data + * + * @note This function ignores the PRELOADING option + * + * @param[in] dev device to use for sending + * @param[in] data data to send (must include IEEE802.15.4 header) + * @param[in] len length of @p data + * + * @return number of bytes that were actually send + * @return 0 on error + */ +size_t ng_at86rf2xx_send(ng_at86rf2xx_t *dev, uint8_t *data, size_t len); + +/** + * @brief Prepare for sending of data + * + * This function puts the given device into the TX state, so no receiving of + * data is possible after it was called. + * + * @param[in] dev device to prepare for sending + */ +void ng_at86rf2xx_tx_prepare(ng_at86rf2xx_t *dev); + +/** + * @brief Load chunks of data into the transmit buffer of the given device + * + * @param[in] dev device to write data to + * @param[in] data buffer containing the data to load + * @param[in] len number of bytes in @p buffer + * @param[in] offset offset used when writing data to internal buffer + * + * @return offset + number of bytes written + */ +size_t ng_at86rf2xx_tx_load(ng_at86rf2xx_t *dev, uint8_t *data, size_t len, + size_t offset); + +/** + * @brief Trigger sending of data previously loaded into transmit buffer + * + * @param[in] dev device to trigger + */ +void ng_at86rf2xx_tx_exec(ng_at86rf2xx_t *dev); + +/** + * @brief Read the length of a received packet + * + * @param dev device to read from + * + * @return overall length of a received packet in byte + */ +size_t ng_at86rf2xx_rx_len(ng_at86rf2xx_t *dev); + +/** + * @brief Read a chunk of data from the receive buffer of the given device + * + * @param[in] dev device to read from + * @param[out] data buffer to write data to + * @param[in] len number of bytes to read from device + * @param[in] offset offset in the receive buffer + */ +void ng_at86rf2xx_rx_read(ng_at86rf2xx_t *dev, uint8_t *data, size_t len, + size_t offset); + +#ifdef __cplusplus +} +#endif + +#endif /* NG_AT86RF2XX_H_ */ +/** @} */ diff --git a/drivers/ng_at86rf2xx/Makefile b/drivers/ng_at86rf2xx/Makefile new file mode 100644 index 0000000000..48422e909a --- /dev/null +++ b/drivers/ng_at86rf2xx/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/drivers/ng_at86rf2xx/include/ng_at86rf2xx_internal.h b/drivers/ng_at86rf2xx/include/ng_at86rf2xx_internal.h new file mode 100644 index 0000000000..c5e8ca424c --- /dev/null +++ b/drivers/ng_at86rf2xx/include/ng_at86rf2xx_internal.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2013 Alaeddine Weslati + * Copyright (C) 2015 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License v2.1. See the file LICENSE in the top level directory for more + * details. + */ + +/** + * @ingroup drivers_ng_at86rf2xx + * @{ + * + * @file + * @brief Internal interfaces for AT86RF2xx drivers + * + * @author Alaeddine Weslati + * @author Thomas Eichinger + * @author Hauke Petersen + */ + +#ifndef NG_AT86RF2XX_INTERNAL_H_ +#define NG_AT86RF2XX_INTERNAL_H_ + +#include + +#include "ng_at86rf2xx.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Read from a register at address `addr` from device `dev`. + * + * @param[in] dev device to read from + * @param[in] addr address of the register to read + * + * @return the value of the specified register + */ +uint8_t ng_at86rf2xx_reg_read(const ng_at86rf2xx_t *dev, const uint8_t addr); + +/** + * @brief Write to a register at address `addr` from device `dev`. + * + * @param[in] dev device to write to + * @param[in] addr address of the register to write + * @param[in] value value to write to the given register + */ +void ng_at86rf2xx_reg_write(const ng_at86rf2xx_t *dev, const uint8_t addr, + const uint8_t value); + +/** + * @brief Read a chunk of data from the SRAM of the given device + * + * @param[in] dev device to read from + * @param[in] offset starting address to read from [valid 0x00-0x7f] + * @param[out] data buffer to read data into + * @param[in] len number of bytes to read from SRAM + */ +void ng_at86rf2xx_sram_read(const ng_at86rf2xx_t *dev, + const uint8_t offset, + uint8_t *data, + const size_t len); + +/** + * @brief Write a chunk of data into the SRAM of the given device + * + * @param[in] dev device to write to + * @param[in] offset address in the SRAM to write to [valid 0x00-0x7f] + * @param[in] data data to copy into SRAM + * @param[in] len number of bytes to write to SRAM + */ +void ng_at86rf2xx_sram_write(const ng_at86rf2xx_t *dev, + const uint8_t offset, + const uint8_t *data, + const size_t len); + +/** + * @brief Read the internal frame buffer of the given device + * + * Reading the frame buffer returns some extra bytes that are not accessible + * through reading the RAM directly. + * + * @param[in] dev device to read from + * @param[out] data buffer to copy the data to + * @param[in] len number of bytes to read from the frame buffer + */ +void ng_at86rf2xx_fb_read(const ng_at86rf2xx_t *dev, + uint8_t *data, const size_t len); + +/** + * @brief Convenience function for reading the status of the given device + * + * @param[in] dev device to read the status from + * + * @return internal status of the given device + */ +uint8_t ng_at86rf2xx_get_status(const ng_at86rf2xx_t *dev); + +#ifdef __cplusplus +} +#endif + +#endif /* NG_AT86RF2XX_INTERNAL_H_ */ +/** @} */ diff --git a/drivers/ng_at86rf2xx/include/ng_at86rf2xx_netdev.h b/drivers/ng_at86rf2xx/include/ng_at86rf2xx_netdev.h new file mode 100644 index 0000000000..2085fb3e6e --- /dev/null +++ b/drivers/ng_at86rf2xx/include/ng_at86rf2xx_netdev.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2015 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_ng_at86rf2xx + * @{ + * + * @file + * @brief Netdev interface to AT86RF2xx drivers + * + * @author Hauke Petersen + */ + +#ifndef NG_AT86RF2XX_NETDEV_H_ +#define NG_AT86RF2XX_NETDEV_H_ + +#include "net/ng_netdev.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Reference to the netdev device driver struct + */ +extern const ng_netdev_driver_t ng_at86rf2xx_driver; + +#ifdef __cplusplus +} +#endif + +#endif /* NG_AT86RF2XX_NETDEV_H_ */ +/** @} */ diff --git a/drivers/ng_at86rf2xx/include/ng_at86rf2xx_registers.h b/drivers/ng_at86rf2xx/include/ng_at86rf2xx_registers.h new file mode 100644 index 0000000000..35c7429ced --- /dev/null +++ b/drivers/ng_at86rf2xx/include/ng_at86rf2xx_registers.h @@ -0,0 +1,319 @@ +/* + * Copyright (C) 2013 Alaeddine Weslati + * Copyright (C) 2015 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_ng_at86rf2xx + * @{ + * + * @file + * @brief Register and command definitions for AT86RF2xx devices + * + * @author Alaeddine Weslati + * @author Thomas Eichinger + * @author Hauke Petersen + * @author Kaspar Schleiser + */ + +#ifndef NG_AT86RF2XX_REGISTERS_H_ +#define NG_AT86RF2XX_REGISTERS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Constant part numbers of the AT86RF2xx device family + * @{ + */ +#define NG_AT86RF212B_PARTNUM (0x07) +#define NG_AT86RF231_PARTNUM (0x03) +#define NG_AT86RF232_PARTNUM (0x0a) +#define NG_AT86RF233_PARTNUM (0x0b) +/** @} */ + +/** + * @brief Assign the part number for the device we are building the driver for + * @{ + */ +#ifdef MODULE_NG_AT86RF212B +#define NG_AT86RF2XX_PARTNUM NG_AT86RF212B_PARTNUM +#elif MODULE_NG_AT86RF232 +#define NG_AT86RF2XX_PARTNUM NG_AT86RF232_PARTNUM +#elif MODULE_NG_AT86RF233 +#define NG_AT86RF2XX_PARTNUM NG_AT86RF233_PARTNUM +#else /* MODULE_NG_AT86RF231 as default device */ +#define NG_AT86RF2XX_PARTNUM NG_AT86RF231_PARTNUM +#endif +/** @} */ + +/** + * @brief SPI access specifiers + * @{ + */ +#define NG_AT86RF2XX_ACCESS_REG (0x80) +#define NG_AT86RF2XX_ACCESS_FB (0x20) +#define NG_AT86RF2XX_ACCESS_SRAM (0x00) +#define NG_AT86RF2XX_ACCESS_READ (0x00) +#define NG_AT86RF2XX_ACCESS_WRITE (0x40) +/** @} */ + +/** + * @brief Register addresses + * @{ + */ +#define NG_AT86RF2XX_REG__TRX_STATUS (0x01) +#define NG_AT86RF2XX_REG__TRX_STATE (0x02) +#define NG_AT86RF2XX_REG__TRX_CTRL_0 (0x03) +#define NG_AT86RF2XX_REG__TRX_CTRL_1 (0x04) +#define NG_AT86RF2XX_REG__PHY_TX_PWR (0x05) +#define NG_AT86RF2XX_REG__PHY_RSSI (0x06) +#define NG_AT86RF2XX_REG__PHY_ED_LEVEL (0x07) +#define NG_AT86RF2XX_REG__PHY_CC_CCA (0x08) +#define NG_AT86RF2XX_REG__CCA_THRES (0x09) +#define NG_AT86RF2XX_REG__RX_CTRL (0x0A) +#define NG_AT86RF2XX_REG__SFD_VALUE (0x0B) +#define NG_AT86RF2XX_REG__TRX_CTRL_2 (0x0C) +#define NG_AT86RF2XX_REG__ANT_DIV (0x0D) +#define NG_AT86RF2XX_REG__IRQ_MASK (0x0E) +#define NG_AT86RF2XX_REG__IRQ_STATUS (0x0F) +#define NG_AT86RF2XX_REG__VREG_CTRL (0x10) +#define NG_AT86RF2XX_REG__BATMON (0x11) +#define NG_AT86RF2XX_REG__XOSC_CTRL (0x12) +#define NG_AT86RF2XX_REG__CC_CTRL_1 (0x14) +#define NG_AT86RF2XX_REG__RX_SYN (0x15) +#define NG_AT86RF2XX_REG__XAH_CTRL_1 (0x17) +#define NG_AT86RF2XX_REG__FTN_CTRL (0x18) +#define NG_AT86RF2XX_REG__PLL_CF (0x1A) +#define NG_AT86RF2XX_REG__PLL_DCU (0x1B) +#define NG_AT86RF2XX_REG__PART_NUM (0x1C) +#define NG_AT86RF2XX_REG__VERSION_NUM (0x1D) +#define NG_AT86RF2XX_REG__MAN_ID_0 (0x1E) +#define NG_AT86RF2XX_REG__MAN_ID_1 (0x1F) +#define NG_AT86RF2XX_REG__SHORT_ADDR_0 (0x20) +#define NG_AT86RF2XX_REG__SHORT_ADDR_1 (0x21) +#define NG_AT86RF2XX_REG__PAN_ID_0 (0x22) +#define NG_AT86RF2XX_REG__PAN_ID_1 (0x23) +#define NG_AT86RF2XX_REG__IEEE_ADDR_0 (0x24) +#define NG_AT86RF2XX_REG__IEEE_ADDR_1 (0x25) +#define NG_AT86RF2XX_REG__IEEE_ADDR_2 (0x26) +#define NG_AT86RF2XX_REG__IEEE_ADDR_3 (0x27) +#define NG_AT86RF2XX_REG__IEEE_ADDR_4 (0x28) +#define NG_AT86RF2XX_REG__IEEE_ADDR_5 (0x29) +#define NG_AT86RF2XX_REG__IEEE_ADDR_6 (0x2A) +#define NG_AT86RF2XX_REG__IEEE_ADDR_7 (0x2B) +#define NG_AT86RF2XX_REG__XAH_CTRL_0 (0x2C) +#define NG_AT86RF2XX_REG__CSMA_SEED_0 (0x2D) +#define NG_AT86RF2XX_REG__CSMA_SEED_1 (0x2E) +#define NG_AT86RF2XX_REG__CSMA_BE (0x2F) +#define NG_AT86RF2XX_REG__TST_CTRL_DIGI (0x36) +/** @} */ + +/** + * @brief Bitfield definitions for the TRX_CTRL_0 register + * @{ + */ +#define NG_AT86RF2XX_TRX_CTRL_0_MASK__PAD_IO (0xC0) +#define NG_AT86RF2XX_TRX_CTRL_0_MASK__PAD_IO_CLKM (0x30) +#define NG_AT86RF2XX_TRX_CTRL_0_MASK__CLKM_SHA_SEL (0x08) +#define NG_AT86RF2XX_TRX_CTRL_0_MASK__CLKM_CTRL (0x07) + +#define NG_AT86RF2XX_TRX_CTRL_0_DEFAULT__PAD_IO (0x00) +#define NG_AT86RF2XX_TRX_CTRL_0_DEFAULT__PAD_IO_CLKM (0x10) +#define NG_AT86RF2XX_TRX_CTRL_0_DEFAULT__CLKM_SHA_SEL (0x08) +#define NG_AT86RF2XX_TRX_CTRL_0_DEFAULT__CLKM_CTRL (0x01) + +#define NG_AT86RF2XX_TRX_CTRL_0_CLKM_CTRL__OFF (0x00) +#define NG_AT86RF2XX_TRX_CTRL_0_CLKM_CTRL__1MHz (0x01) +#define NG_AT86RF2XX_TRX_CTRL_0_CLKM_CTRL__2MHz (0x02) +#define NG_AT86RF2XX_TRX_CTRL_0_CLKM_CTRL__4MHz (0x03) +#define NG_AT86RF2XX_TRX_CTRL_0_CLKM_CTRL__8MHz (0x04) +#define NG_AT86RF2XX_TRX_CTRL_0_CLKM_CTRL__16MHz (0x05) +#define NG_AT86RF2XX_TRX_CTRL_0_CLKM_CTRL__250kHz (0x06) +#define NG_AT86RF2XX_TRX_CTRL_0_CLKM_CTRL__62_5kHz (0x07) +/** @} */ + +/** + * @brief Bitfield definitions for the TRX_CTRL_1 register + * @{ + */ +#define NG_AT86RF2XX_TRX_CTRL_1_MASK__PA_EXT_EN (0x80) +#define NG_AT86RF2XX_TRX_CTRL_1_MASK__IRQ_2_EXT_EN (0x40) +#define NG_AT86RF2XX_TRX_CTRL_1_MASK__TX_AUTO_CRC_ON (0x20) +#define NG_AT86RF2XX_TRX_CTRL_1_MASK__RX_BL_CTRL (0x10) +#define NG_AT86RF2XX_TRX_CTRL_1_MASK__SPI_CMD_MODE (0x0C) +#define NG_AT86RF2XX_TRX_CTRL_1_MASK__IRQ_MASK_MODE (0x02) +#define NG_AT86RF2XX_TRX_CTRL_1_MASK__IRQ_POLARITY (0x01) +/** @} */ + +/** + * @brief Bitfield definitions for the TXR_CTRL_2 register + * @{ + */ +#define NG_AT86RF2XX_TRX_CTRL_2_MASK__RX_SAFE_MODE (0x80) +#define NG_AT86RF2XX_TRX_CTRL_2_MASK__SUB_MODE (0x4) +#define NG_AT86RF2XX_TRX_CTRL_2_MASK__OQPSK_DATA_RATE (0x03) +#define NG_AT86RF2XX_TRX_CTRL_2_MASK__OQPSK_SCRAM_EN (0x20) +/** @} */ + +/** + * @brief Bitfield definitions for the IRQ_STATUS register + * @{ + */ +#define NG_AT86RF2XX_IRQ_STATUS_MASK__BAT_LOW (0x80) +#define NG_AT86RF2XX_IRQ_STATUS_MASK__TRX_UR (0x40) +#define NG_AT86RF2XX_IRQ_STATUS_MASK__AMI (0x20) +#define NG_AT86RF2XX_IRQ_STATUS_MASK__CCA_ED_DONE (0x10) +#define NG_AT86RF2XX_IRQ_STATUS_MASK__TRX_END (0x08) +#define NG_AT86RF2XX_IRQ_STATUS_MASK__RX_START (0x04) +#define NG_AT86RF2XX_IRQ_STATUS_MASK__PLL_UNLOCK (0x02) +#define NG_AT86RF2XX_IRQ_STATUS_MASK__PLL_LOCK (0x01) +/** @} */ + +/** + * @brief Bitfield definitions for the TRX_STATUS register + * @{ + */ +#define NG_AT86RF2XX_TRX_STATUS_MASK__CCA_DONE (0x80) +#define NG_AT86RF2XX_TRX_STATUS_MASK__CCA_STATUS (0x40) +#define NG_AT86RF2XX_TRX_STATUS_MASK__TRX_STATUS (0x1F) + +#define NG_AT86RF2XX_TRX_STATUS__P_ON (0x00) +#define NG_AT86RF2XX_TRX_STATUS__BUSY_RX (0x01) +#define NG_AT86RF2XX_TRX_STATUS__BUSY_TX (0x02) +#define NG_AT86RF2XX_TRX_STATUS__RX_ON (0x06) +#define NG_AT86RF2XX_TRX_STATUS__TRX_OFF (0x08) +#define NG_AT86RF2XX_TRX_STATUS__PLL_ON (0x09) +#define NG_AT86RF2XX_TRX_STATUS__SLEEP (0x0F) +#define NG_AT86RF2XX_TRX_STATUS__BUSY_RX_AACK (0x11) +#define NG_AT86RF2XX_TRX_STATUS__BUSY_TX_ARET (0x12) +#define NG_AT86RF2XX_TRX_STATUS__RX_AACK_ON (0x16) +#define NG_AT86RF2XX_TRX_STATUS__TX_ARET_ON (0x19) +#define NG_AT86RF2XX_TRX_STATUS__RX_ON_NOCLK (0x1C) +#define NG_AT86RF2XX_TRX_STATUS__RX_AACK_ON_NOCLK (0x1D) +#define NG_AT86RF2XX_TRX_STATUS__BUSY_RX_AACK_NOCLK (0x1E) +#define NG_AT86RF2XX_TRX_STATUS__STATE_TRANSITION_IN_PROGRESS (0x1F) +/** @} */ + +/** + * @brief Bitfield definitions for the TRX_STATE register + * @{ + */ +#define NG_AT86RF2XX_TRX_STATE_MASK__TRAC (0xe0) + +#define NG_AT86RF2XX_TRX_STATE__NOP (0x00) +#define NG_AT86RF2XX_TRX_STATE__TX_START (0x02) +#define NG_AT86RF2XX_TRX_STATE__FORCE_TRX_OFF (0x03) +#define NG_AT86RF2XX_TRX_STATE__FORCE_PLL_ON (0x04) +#define NG_AT86RF2XX_TRX_STATE__RX_ON (0x06) +#define NG_AT86RF2XX_TRX_STATE__TRX_OFF (0x08) +#define NG_AT86RF2XX_TRX_STATE__PLL_ON (0x09) +#define NG_AT86RF2XX_TRX_STATE__RX_AACK_ON (0x16) +#define NG_AT86RF2XX_TRX_STATE__TX_ARET_ON (0x19) +#define NG_AT86RF2XX_TRX_STATE__TRAC_SUCCESS (0x00) +#define NG_AT86RF2XX_TRX_STATE__TRAC_SUCCESS_DATA_PENDING (0x20) +#define NG_AT86RF2XX_TRX_STATE__TRAC_SUCCESS_WAIT_FOR_ACK (0x40) +#define NG_AT86RF2XX_TRX_STATE__TRAC_CHANNEL_ACCESS_FAILURE (0x60) +#define NG_AT86RF2XX_TRX_STATE__TRAC_NO_ACK (0xa0) +#define NG_AT86RF2XX_TRX_STATE__TRAC_INVALID (0xe0) +/** @} */ + +/** + * @brief Bitfield definitions for the PHY_CCA register + * @{ + */ +#define NG_AT86RF2XX_PHY_CC_CCA_MASK__CCA_REQUEST (0x80) +#define NG_AT86RF2XX_PHY_CC_CCA_MASK__CCA_MODE (0x60) +#define NG_AT86RF2XX_PHY_CC_CCA_MASK__CHANNEL (0x1F) + +#define NG_AT86RF2XX_PHY_CC_CCA_DEFAULT__CCA_MODE (0x20) +/** @} */ + +/** + * @brief Bitfield definitions for the PHY_TX_PWR register + * @{ + */ +#define NG_AT86RF2XX_PHY_TX_PWR_MASK__PA_BUF_LT (0xC0) +#define NG_AT86RF2XX_PHY_TX_PWR_MASK__PA_LT (0x30) +#define NG_AT86RF2XX_PHY_TX_PWR_MASK__TX_PWR (0x0F) +#define NG_AT86RF2XX_PHY_TX_PWR_DEFAULT__PA_BUF_LT (0xC0) +#define NG_AT86RF2XX_PHY_TX_PWR_DEFAULT__PA_LT (0x00) +#define NG_AT86RF2XX_PHY_TX_PWR_DEFAULT__TX_PWR (0x00) +#define NG_AT86RF2XX_PHY_TX_PWR_TX_PWR_VALUE__3dBm (0x00) +#define NG_AT86RF2XX_PHY_TX_PWR_TX_PWR_VALUE__2_8dBm (0x01) +#define NG_AT86RF2XX_PHY_TX_PWR_TX_PWR_VALUE__2_3dBm (0x02) +#define NG_AT86RF2XX_PHY_TX_PWR_TX_PWR_VALUE__1_8dBm (0x03) +#define NG_AT86RF2XX_PHY_TX_PWR_TX_PWR_VALUE__1_3dBm (0x04) +#define NG_AT86RF2XX_PHY_TX_PWR_TX_PWR_VALUE__0_7dBm (0x05) +#define NG_AT86RF2XX_PHY_TX_PWR_TX_PWR_VALUE__0dBm (0x06) +#define NG_AT86RF2XX_PHY_TX_PWR_TX_PWR_VALUE__m1dBm (0x07) +#define NG_AT86RF2XX_PHY_TX_PWR_TX_PWR_VALUE__m2dBm (0x08) +#define NG_AT86RF2XX_PHY_TX_PWR_TX_PWR_VALUE__m3dBm (0x09) +#define NG_AT86RF2XX_PHY_TX_PWR_TX_PWR_VALUE__m4dBm (0x0A) +#define NG_AT86RF2XX_PHY_TX_PWR_TX_PWR_VALUE__m5dBm (0x0B) +#define NG_AT86RF2XX_PHY_TX_PWR_TX_PWR_VALUE__m7dBm (0x0C) +#define NG_AT86RF2XX_PHY_TX_PWR_TX_PWR_VALUE__m9dBm (0x0D) +#define NG_AT86RF2XX_PHY_TX_PWR_TX_PWR_VALUE__m12dBm (0x0E) +#define NG_AT86RF2XX_PHY_TX_PWR_TX_PWR_VALUE__m17dBm (0x0F) +/** @} */ + +/** + * @brief Bitfield definitions for the PHY_RSSI register + * @{ + */ +#define NG_AT86RF2XX_PHY_RSSI_MASK__RX_CRC_VALID (0x80) +#define NG_AT86RF2XX_PHY_RSSI_MASK__RND_VALUE (0x60) +#define NG_AT86RF2XX_PHY_RSSI_MASK__RSSI (0x1F) +/** @} */ + +/** + * @brief Bitfield definitions for the XOSC_CTRL register + * @{ + */ +#define NG_AT86RF2XX_XOSC_CTRL__XTAL_MODE_CRYSTAL (0xF0) +#define NG_AT86RF2XX_XOSC_CTRL__XTAL_MODE_EXTERNAL (0xF0) +/** @} */ + +/** + * @brief Timing values + * @{ + */ +#define NG_AT86RF2XX_TIMING__VCC_TO_P_ON (330) +#define NG_AT86RF2XX_TIMING__SLEEP_TO_TRX_OFF (380) +#define NG_AT86RF2XX_TIMING__TRX_OFF_TO_PLL_ON (110) +#define NG_AT86RF2XX_TIMING__TRX_OFF_TO_RX_ON (110) +#define NG_AT86RF2XX_TIMING__PLL_ON_TO_BUSY_TX (16) +#define NG_AT86RF2XX_TIMING__RESET (100) +#define NG_AT86RF2XX_TIMING__RESET_TO_TRX_OFF (37) +/** @} */ + +/** + * @brief Bitfield definitions for the XAH_CTRL_1 register + * @{ + */ +#define NG_AT86RF2XX_XAH_CTRL_1__AACK_FLTR_RES_FT (0x20) +#define NG_AT86RF2XX_XAH_CTRL_1__AACK_UPLD_RES_FT (0x10) +#define NG_AT86RF2XX_XAH_CTRL_1__AACK_ACK_TIME (0x04) +#define NG_AT86RF2XX_XAH_CTRL_1__AACK_PROM_MODE (0x02) +/** @} */ + +/** + * @brief Bitfield definitions for the CSMA_SEED_1 register + * @{ + */ +#define NG_AT86RF2XX_CSMA_SEED_1__AACK_SET_PD (0x20) +#define NG_AT86RF2XX_CSMA_SEED_1__AACK_DIS_ACK (0x10) +#define NG_AT86RF2XX_CSMA_SEED_1__AACK_I_AM_COORD (0x08) +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* NG_AT86RF2XX_REGISTERS_H_ */ +/** @} */ diff --git a/drivers/ng_at86rf2xx/ng_at86rf2xx.c b/drivers/ng_at86rf2xx/ng_at86rf2xx.c new file mode 100644 index 0000000000..7707fb69c0 --- /dev/null +++ b/drivers/ng_at86rf2xx/ng_at86rf2xx.c @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2013 Alaeddine Weslati + * Copyright (C) 2015 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_ng_at86rf2xx + * @{ + * + * @file + * @brief Implementation of public functions for AT86RF2xx drivers + * + * @author Alaeddine Weslati + * @author Thomas Eichinger + * @author Hauke Petersen + * @author Kaspar Schleiser + * + * @} + */ + +#include "hwtimer.h" +#include "periph/cpuid.h" +#include "net/ng_ieee802154.h" +#include "net/ng_netbase.h" +#include "ng_at86rf2xx_registers.h" +#include "ng_at86rf2xx_internal.h" +#include "ng_at86rf2xx_netdev.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + + +#define RESET_DELAY (0U) /* must be > 625ns */ + + +static void _irq_handler(void *arg) +{ + msg_t msg; + ng_at86rf2xx_t *dev = (ng_at86rf2xx_t *) arg; + + /* tell driver thread about the interrupt */ + msg.type = NG_NETDEV_MSG_TYPE_EVENT; + msg_send(&msg, dev->mac_pid); +} + +int ng_at86rf2xx_init(ng_at86rf2xx_t *dev, spi_t spi, spi_speed_t spi_speed, + gpio_t cs_pin, gpio_t int_pin, + gpio_t sleep_pin, gpio_t reset_pin) +{ + dev->driver = &ng_at86rf2xx_driver; + + /* initialize device descriptor */ + dev->spi = spi; + dev->cs_pin = cs_pin; + dev->int_pin = int_pin; + dev->sleep_pin = sleep_pin; + dev->reset_pin = reset_pin; + + /* initialise SPI */ + spi_init_master(dev->spi, SPI_CONF_FIRST_RISING, spi_speed); + /* initialise GPIOs */ + gpio_init_out(dev->cs_pin, GPIO_NOPULL); + gpio_set(dev->cs_pin); + gpio_init_out(dev->sleep_pin, GPIO_NOPULL); + gpio_clear(dev->sleep_pin); + gpio_init_out(dev->reset_pin, GPIO_NOPULL); + gpio_set(dev->reset_pin); + gpio_init_int(dev->int_pin, GPIO_NOPULL, GPIO_RISING, _irq_handler, dev); + + /* test if the SPI is set up correctly and the device is responding */ + if (ng_at86rf2xx_reg_read(dev, NG_AT86RF2XX_REG__PART_NUM) != + NG_AT86RF2XX_PARTNUM) { + DEBUG("[ng_at86rf2xx] error: unable to read correct part number\n"); + return -1; + } + + /* reset device to default values and put it into RX state */ + ng_at86rf2xx_reset(dev); + return 0; +} + +void ng_at86rf2xx_reset(ng_at86rf2xx_t *dev) +{ + uint8_t tmp; +#if CPUID_ID_LEN + uint8_t cpuid[CPUID_ID_LEN]; + uint16_t addr_short; + uint64_t addr_long; +#endif + + /* trigger hardware reset */ + gpio_clear(dev->reset_pin); + hwtimer_wait(HWTIMER_TICKS(RESET_DELAY)); + gpio_set(dev->reset_pin); + /* reset options and sequence number */ + dev->seq_nr = 0; + dev->options = 0; + /* set short and long address */ +#if CPUID_ID_LEN + cpuid_get(cpuid); +#if CPUID < 8 + /* in case CPUID_ID_LEN < 8, fill missing bytes with zeros */ + for (int i = CPUID_ID_LEN; i < 8; i++) { + cpuid[i] = 0; + } +#else + for (int i = 8; i < CPUID_ID_LEN; i++) { + cpuid[i & 0x07] ^= cpuid[i]; + } +#endif + /* make sure we mark the address as non-multicast and not globally unique */ + cpuid[0] &= ~(0x01); + cpuid[0] |= 0x02; + /* copy and set long address */ + memcpy(&addr_long, cpuid, 8); + ng_at86rf2xx_set_addr_long(dev, addr_long); + /* now compress the long addr to form the short address */ + for (int i = 2; i < 8; i++) { + cpuid[i & 0x01] ^= cpuid[i]; + } + memcpy(&addr_short, cpuid, 2); + ng_at86rf2xx_set_addr_short(dev, addr_short); +#else + ng_at86rf2xx_set_addr_long(dev, NG_AT86RF2XX_DEFAULT_ADDR_LONG); + ng_at86rf2xx_set_addr_short(dev, NG_AT86RF2XX_DEFAULT_ADDR_SHORT); +#endif + /* set default PAN id */ + ng_at86rf2xx_set_pan(dev, NG_AT86RF2XX_DEFAULT_PANID); + /* set default channel */ + ng_at86rf2xx_set_chan(dev, NG_AT86RF2XX_DEFAULT_CHANNEL); + /* set default TX power */ + ng_at86rf2xx_set_txpower(dev, NG_AT86RF2XX_DEFAULT_TXPOWER); + /* set default options */ + ng_at86rf2xx_set_option(dev, NG_AT86RF2XX_OPT_AUTOACK, true); + ng_at86rf2xx_set_option(dev, NG_AT86RF2XX_OPT_CSMA, true); + ng_at86rf2xx_set_option(dev, NG_AT86RF2XX_OPT_TELL_RX_END, true); + /* set default protocol */ +#ifdef MODULE_NG_SIXLOWPAN + dev->proto = NG_NETTYPE_SIXLOWPAN; +#else + dev->proto = NG_NETTYPE_UNDEF; +#endif + /* enable safe mode (protect RX FIFO until reading data starts) */ + tmp = NG_AT86RF2XX_TRX_CTRL_2_MASK__RX_SAFE_MODE; +#ifdef MODULE_NG_AT86RF212 + /* settings used by Linux 4.0rc at86rf212b driver */ + tmp |= (NG_AT86RF2XX_TRX_CTRL_2_MASK__SUB_MODE + | NG_AT86RF2XX_TRX_CTRL_2_MASK__OQPSK_SCRAM_EN); +#endif + ng_at86rf2xx_reg_write(dev, NG_AT86RF2XX_REG__TRX_CTRL_2, tmp); + /* enable interrupts */ + ng_at86rf2xx_reg_write(dev, NG_AT86RF2XX_REG__IRQ_MASK, + (NG_AT86RF2XX_IRQ_STATUS_MASK__RX_START | + NG_AT86RF2XX_IRQ_STATUS_MASK__TRX_END)); + /* go into RX state */ + ng_at86rf2xx_set_state(dev, NG_AT86RF2XX_STATE_RX_AACK_ON); + + DEBUG("ng_at86rf2xx_reset(): reset complete.\n"); +} + +bool ng_at86rf2xx_cca(ng_at86rf2xx_t *dev) +{ + uint8_t tmp; + uint8_t status; + + /* trigger CCA measurment */ + tmp = ng_at86rf2xx_reg_read(dev, NG_AT86RF2XX_REG__PHY_CC_CCA); + tmp &= NG_AT86RF2XX_PHY_CC_CCA_MASK__CCA_REQUEST; + ng_at86rf2xx_reg_write(dev, NG_AT86RF2XX_REG__PHY_CC_CCA, tmp); + /* wait for result to be ready */ + do { + status = ng_at86rf2xx_reg_read(dev, NG_AT86RF2XX_REG__TRX_STATUS); + } while (!(status & NG_AT86RF2XX_TRX_STATUS_MASK__CCA_DONE)); + /* return according to measurement */ + if (status & NG_AT86RF2XX_TRX_STATUS_MASK__CCA_STATUS) { + return true; + } + else { + return false; + } +} + +size_t ng_at86rf2xx_send(ng_at86rf2xx_t *dev, uint8_t *data, size_t len) +{ + /* check data length */ + if (len > NG_AT86RF2XX_MAX_PKT_LENGTH) { + DEBUG("[ng_at86rf2xx] Error: data to send exceeds max packet size\n"); + return 0; + } + ng_at86rf2xx_tx_prepare(dev); + ng_at86rf2xx_tx_load(dev, data, len, 0); + ng_at86rf2xx_tx_exec(dev); + return len; +} + +void ng_at86rf2xx_tx_prepare(ng_at86rf2xx_t *dev) +{ + uint8_t state; + + /* make sure ongoing transmissions are finished */ + do { + state = ng_at86rf2xx_get_state(dev); + } + while (state == NG_AT86RF2XX_STATE_BUSY_RX_AACK); + dev->idle_state = state; + ng_at86rf2xx_set_state(dev, NG_AT86RF2XX_STATE_TX_ARET_ON); + dev->frame_len = NG_IEEE802154_FCS_LEN; +} + +size_t ng_at86rf2xx_tx_load(ng_at86rf2xx_t *dev, uint8_t *data, + size_t len, size_t offset) +{ + dev->frame_len += (uint8_t)len; + ng_at86rf2xx_sram_write(dev, offset + 1, data, len); + return offset + len; +} + +void ng_at86rf2xx_tx_exec(ng_at86rf2xx_t *dev) +{ + /* write frame length field in FIFO */ + ng_at86rf2xx_sram_write(dev, 0, &(dev->frame_len), 1); + /* trigger sending of pre-loaded frame */ + ng_at86rf2xx_reg_write(dev, NG_AT86RF2XX_REG__TRX_STATE, + NG_AT86RF2XX_TRX_STATE__TX_START); + if (dev->event_cb && (dev->options & NG_AT86RF2XX_OPT_TELL_TX_START)) { + dev->event_cb(NETDEV_EVENT_TX_STARTED, NULL); + } +} + +size_t ng_at86rf2xx_rx_len(ng_at86rf2xx_t *dev) +{ + uint8_t res; + ng_at86rf2xx_fb_read(dev, &res, 1); + return (size_t)(res - 2); /* extract the PHR and LQI field */ +} + +void ng_at86rf2xx_rx_read(ng_at86rf2xx_t *dev, uint8_t *data, size_t len, + size_t offset) +{ + /* when reading from SRAM, the different chips from the AT86RF2xx family + * behave differently: the AT86F233, the AT86RF232 and the ATRF86212B return + * frame length field (PHR) at position 0 and the first data byte at + * position 1. + * The AT86RF231 does not return the PHR field and return + * the first data byte at position 0. + */ +#ifndef MODULE_NG_AT86RF231 + ng_at86rf2xx_sram_read(dev, offset + 1, data, len); +#else + ng_at86rf2xx_sram_read(dev, offset, data, len); +#endif +} diff --git a/drivers/ng_at86rf2xx/ng_at86rf2xx_getset.c b/drivers/ng_at86rf2xx/ng_at86rf2xx_getset.c new file mode 100644 index 0000000000..44e37b40af --- /dev/null +++ b/drivers/ng_at86rf2xx/ng_at86rf2xx_getset.c @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2015 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_ng_at86rf2xx + * @{ + * + * @file + * @brief Getter and setter functions for the AT86RF2xx drivers + * + * @author Thomas Eichinger + * @author Hauke Petersen + * + * @} + */ + +#include "ng_at86rf2xx.h" +#include "ng_at86rf2xx_internal.h" +#include "ng_at86rf2xx_registers.h" +#include "periph/spi.h" + +#define ENABLE_DEBUG (1) +#include "debug.h" + + +static const int16_t tx_pow_to_dbm[] = {3, 3, 2, 2, 1, 1, 0, + -1, -2, -3, -4, -5, -7, -9, -12, -17}; + +static const uint8_t dbm_to_tx_pow[] = {0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0d, 0x0d, 0x0c, 0x0c, 0x0b, + 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, + 0x05, 0x03, 0x00}; + +uint16_t ng_at86rf2xx_get_addr_short(ng_at86rf2xx_t *dev) +{ + return (dev->addr_short[0] << 8) | dev->addr_short[1]; +} + +void ng_at86rf2xx_set_addr_short(ng_at86rf2xx_t *dev, uint16_t addr) +{ + dev->addr_short[0] = addr >> 8; + dev->addr_short[1] = addr & 0xff; + ng_at86rf2xx_reg_write(dev, NG_AT86RF2XX_REG__SHORT_ADDR_0, + dev->addr_short[0]); + ng_at86rf2xx_reg_write(dev, NG_AT86RF2XX_REG__SHORT_ADDR_1, + dev->addr_short[1]); +} + +uint64_t ng_at86rf2xx_get_addr_long(ng_at86rf2xx_t *dev) +{ + uint64_t addr; + uint8_t *ap = (uint8_t *)(&addr); + for (int i = 0; i < 8; i++) { + ap[i] = dev->addr_long[7 - i]; + } + return addr; +} + +void ng_at86rf2xx_set_addr_long(ng_at86rf2xx_t *dev, uint64_t addr) +{ + for (int i = 0; i < 8; i++) { + dev->addr_long[i] = (addr >> ((7 - i) * 8)); + ng_at86rf2xx_reg_write(dev, (NG_AT86RF2XX_REG__IEEE_ADDR_0 + i), + dev->addr_long[i]); + } +} + +uint8_t ng_at86rf2xx_get_chan(ng_at86rf2xx_t *dev) +{ + uint8_t res = ng_at86rf2xx_reg_read(dev, NG_AT86RF2XX_REG__PHY_CC_CCA); + return (res & NG_AT86RF2XX_PHY_CC_CCA_MASK__CHANNEL); +} + +void ng_at86rf2xx_set_chan(ng_at86rf2xx_t *dev, uint8_t channel) +{ + uint8_t tmp; + + if (channel < NG_AT86RF2XX_MIN_CHANNEL + || channel > NG_AT86RF2XX_MAX_CHANNEL) { + return; + } + tmp = ng_at86rf2xx_reg_read(dev, NG_AT86RF2XX_REG__PHY_CC_CCA); + tmp &= ~(NG_AT86RF2XX_PHY_CC_CCA_MASK__CHANNEL); + tmp |= (channel & NG_AT86RF2XX_PHY_CC_CCA_MASK__CHANNEL); + ng_at86rf2xx_reg_write(dev, NG_AT86RF2XX_REG__PHY_CC_CCA, tmp); +} + +uint16_t ng_at86rf2xx_get_pan(ng_at86rf2xx_t *dev) +{ + return dev->pan; +} + +void ng_at86rf2xx_set_pan(ng_at86rf2xx_t *dev, uint16_t pan) +{ + dev->pan = pan; + DEBUG("pan0: %u, pan1: %u\n", (uint8_t)pan, pan >> 8); + ng_at86rf2xx_reg_write(dev, NG_AT86RF2XX_REG__PAN_ID_0, (uint8_t)pan); + ng_at86rf2xx_reg_write(dev, NG_AT86RF2XX_REG__PAN_ID_1, (pan >> 8)); +} + +int16_t ng_at86rf2xx_get_txpower(ng_at86rf2xx_t *dev) +{ + uint8_t txpower = ng_at86rf2xx_reg_read(dev, NG_AT86RF2XX_REG__PHY_TX_PWR) + & NG_AT86RF2XX_PHY_TX_PWR_MASK__TX_PWR; + return tx_pow_to_dbm[txpower]; +} + +void ng_at86rf2xx_set_txpower(ng_at86rf2xx_t *dev, int16_t txpower) +{ + txpower += 17; + if (txpower < 0) { + txpower = 0; + } else if (txpower > 20) { + txpower = 20; + } + ng_at86rf2xx_reg_write(dev, NG_AT86RF2XX_REG__PHY_TX_PWR, + dbm_to_tx_pow[txpower]); +} + +void ng_at86rf2xx_set_option(ng_at86rf2xx_t *dev, uint16_t option, bool state) +{ + uint8_t tmp; + + DEBUG("set option %i to %i\n", option, state); + + /* set option field */ + if (state) { + dev->options |= option; + /* trigger option specific actions */ + switch (option) { + case NG_AT86RF2XX_OPT_CSMA: + DEBUG("[ng_at86rf2xx] opt: enabling CSMA mode\n"); + /* TODO: en/disable csma */ + break; + case NG_AT86RF2XX_OPT_PROMISCUOUS: + DEBUG("[ng_at86rf2xx] opt: enabling PROMISCUOUS mode\n"); + /* disable auto ACKs in promiscuous mode */ + tmp = ng_at86rf2xx_reg_read(dev, NG_AT86RF2XX_REG__CSMA_SEED_1); + tmp |= NG_AT86RF2XX_CSMA_SEED_1__AACK_DIS_ACK; + ng_at86rf2xx_reg_write(dev, NG_AT86RF2XX_REG__CSMA_SEED_1, tmp); + /* enable promiscuous mode */ + tmp = ng_at86rf2xx_reg_read(dev, NG_AT86RF2XX_REG__XAH_CTRL_1); + tmp |= NG_AT86RF2XX_XAH_CTRL_1__AACK_PROM_MODE; + ng_at86rf2xx_reg_write(dev, NG_AT86RF2XX_REG__XAH_CTRL_1, tmp); + break; + case NG_AT86RF2XX_OPT_AUTOACK: + DEBUG("[ng_at86rf2xx] opt: enabling auto ACKs\n"); + tmp = ng_at86rf2xx_reg_read(dev, NG_AT86RF2XX_REG__CSMA_SEED_1); + tmp &= ~(NG_AT86RF2XX_CSMA_SEED_1__AACK_DIS_ACK); + ng_at86rf2xx_reg_write(dev, NG_AT86RF2XX_REG__CSMA_SEED_1, tmp); + break; + default: + /* do nothing */ + break; + } + } + else { + dev->options &= ~(option); + /* trigger option specific actions */ + switch (option) { + case NG_AT86RF2XX_OPT_CSMA: + /* TODO: en/disable csma */ + break; + case NG_AT86RF2XX_OPT_PROMISCUOUS: + /* disable promiscuous mode */ + tmp = ng_at86rf2xx_reg_read(dev, NG_AT86RF2XX_REG__XAH_CTRL_1); + tmp &= ~(NG_AT86RF2XX_XAH_CTRL_1__AACK_PROM_MODE); + ng_at86rf2xx_reg_write(dev, NG_AT86RF2XX_REG__XAH_CTRL_1, tmp); + /* re-enable AUTOACK only if the option is set */ + if (dev->options & NG_AT86RF2XX_OPT_AUTOACK) { + tmp = ng_at86rf2xx_reg_read(dev, + NG_AT86RF2XX_REG__CSMA_SEED_1); + tmp &= ~(NG_AT86RF2XX_CSMA_SEED_1__AACK_DIS_ACK); + ng_at86rf2xx_reg_write(dev, NG_AT86RF2XX_REG__CSMA_SEED_1, + tmp); + } + break; + case NG_AT86RF2XX_OPT_AUTOACK: + tmp = ng_at86rf2xx_reg_read(dev, NG_AT86RF2XX_REG__CSMA_SEED_1); + tmp |= NG_AT86RF2XX_CSMA_SEED_1__AACK_DIS_ACK; + ng_at86rf2xx_reg_write(dev, NG_AT86RF2XX_REG__CSMA_SEED_1, tmp); + break; + default: + /* do nothing */ + break; + } + } +} + +uint8_t ng_at86rf2xx_get_state(ng_at86rf2xx_t *dev) +{ + uint8_t status = ng_at86rf2xx_get_status(dev); + return (status & 0x1f); +} + +static inline void _set_state(ng_at86rf2xx_t *dev, uint8_t state) +{ + ng_at86rf2xx_reg_write(dev, NG_AT86RF2XX_REG__TRX_STATE, state); + while (ng_at86rf2xx_get_state(dev) != state); +} + +void ng_at86rf2xx_set_state(ng_at86rf2xx_t *dev, uint8_t state) +{ + uint8_t old_state = ng_at86rf2xx_get_state(dev); + + if (state == old_state) { + return; + } + /* make sure there is no ongoing transmission */ + while (old_state == NG_AT86RF2XX_STATE_BUSY_RX_AACK || + old_state == NG_AT86RF2XX_STATE_BUSY_TX_ARET) { + old_state = ng_at86rf2xx_get_state(dev); + } + /* check if we need to wake up from sleep mode */ + if (old_state == NG_AT86RF2XX_STATE_SLEEP) { + DEBUG("at86rf2xx: waking up from sleep mode\n"); + gpio_clear(dev->sleep_pin); + while (ng_at86rf2xx_get_state(dev) != NG_AT86RF2XX_STATE_TRX_OFF); + } + /* go to neutral TRX_OFF state */ + _set_state(dev, NG_AT86RF2XX_STATE_TRX_OFF); + if (state == NG_AT86RF2XX_STATE_RX_AACK_ON || + state == NG_AT86RF2XX_STATE_TX_ARET_ON) { + _set_state(dev, state); + } else if (state == NG_AT86RF2XX_STATE_SLEEP) { + gpio_set(dev->sleep_pin); + while (ng_at86rf2xx_get_state(dev) != NG_AT86RF2XX_STATE_SLEEP); + } +} diff --git a/drivers/ng_at86rf2xx/ng_at86rf2xx_internal.c b/drivers/ng_at86rf2xx/ng_at86rf2xx_internal.c new file mode 100644 index 0000000000..95511009a8 --- /dev/null +++ b/drivers/ng_at86rf2xx/ng_at86rf2xx_internal.c @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2013 Alaeddine Weslati + * Copyright (C) 2015 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_ng_at86rf2xx + * @{ + * + * @file + * @brief Implementation of driver internal functions + * + * @author Alaeddine Weslati + * @author Thomas Eichinger + * @author Joakim Gebart + * @author Hauke Petersen + * + * @} + */ + +#include "periph/spi.h" +#include "periph/gpio.h" +#include "ng_at86rf2xx_internal.h" +#include "ng_at86rf2xx_registers.h" + +void ng_at86rf2xx_reg_write(const ng_at86rf2xx_t *dev, + const uint8_t addr, + const uint8_t value) +{ + spi_acquire(dev->spi); + gpio_clear(dev->cs_pin); + spi_transfer_reg(dev->spi, + NG_AT86RF2XX_ACCESS_REG | NG_AT86RF2XX_ACCESS_WRITE | addr, + value, 0); + gpio_set(dev->cs_pin); + spi_release(dev->spi); +} + +uint8_t ng_at86rf2xx_reg_read(const ng_at86rf2xx_t *dev, const uint8_t addr) +{ + char value; + + spi_acquire(dev->spi); + gpio_clear(dev->cs_pin); + spi_transfer_reg(dev->spi, + NG_AT86RF2XX_ACCESS_REG | NG_AT86RF2XX_ACCESS_READ | addr, + 0, &value); + gpio_set(dev->cs_pin); + spi_release(dev->spi); + + return (uint8_t)value; +} + +void ng_at86rf2xx_sram_read(const ng_at86rf2xx_t *dev, + const uint8_t offset, + uint8_t *data, + const size_t len) +{ + spi_acquire(dev->spi); + gpio_clear(dev->cs_pin); + spi_transfer_reg(dev->spi, + NG_AT86RF2XX_ACCESS_SRAM | NG_AT86RF2XX_ACCESS_READ, + (char)offset, NULL); + spi_transfer_bytes(dev->spi, NULL, (char*)data, len); + gpio_set(dev->cs_pin); + spi_release(dev->spi); +} + +void ng_at86rf2xx_sram_write(const ng_at86rf2xx_t *dev, + const uint8_t offset, + const uint8_t *data, + const size_t len) +{ + spi_acquire(dev->spi); + gpio_clear(dev->cs_pin); + spi_transfer_reg(dev->spi, + NG_AT86RF2XX_ACCESS_SRAM | NG_AT86RF2XX_ACCESS_WRITE, + (char)offset, NULL); + spi_transfer_bytes(dev->spi, (char*)data, NULL, len); + gpio_set(dev->cs_pin); + spi_release(dev->spi); +} + +void ng_at86rf2xx_fb_read(const ng_at86rf2xx_t *dev, + uint8_t *data, + const size_t len) +{ + spi_acquire(dev->spi); + gpio_clear(dev->cs_pin); + spi_transfer_byte(dev->spi, + NG_AT86RF2XX_ACCESS_FB | NG_AT86RF2XX_ACCESS_READ, + NULL); + spi_transfer_bytes(dev->spi, NULL, (char *)data, len); + gpio_set(dev->cs_pin); + spi_release(dev->spi); +} + +uint8_t ng_at86rf2xx_get_status(const ng_at86rf2xx_t *dev) +{ + return (ng_at86rf2xx_reg_read(dev, NG_AT86RF2XX_REG__TRX_STATUS) + & NG_AT86RF2XX_TRX_STATUS_MASK__TRX_STATUS); +} diff --git a/drivers/ng_at86rf2xx/ng_at86rf2xx_netdev.c b/drivers/ng_at86rf2xx/ng_at86rf2xx_netdev.c new file mode 100644 index 0000000000..30c75194a5 --- /dev/null +++ b/drivers/ng_at86rf2xx/ng_at86rf2xx_netdev.c @@ -0,0 +1,676 @@ +/* + * Copyright (C) 2015 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_ng_at86rf2xx + * @{ + * + * @file + * @brief Netdev adaption for the AT86RF2xx drivers + * + * @author Thomas Eichinger + * @author Hauke Petersen + * + * @} + */ + +#include "net/ng_ieee802154.h" +#include "net/ng_netbase.h" +#include "ng_at86rf2xx.h" +#include "ng_at86rf2xx_netdev.h" +#include "ng_at86rf2xx_internal.h" +#include "ng_at86rf2xx_registers.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +/* TODO: generalize and move to ng_ieee802154 */ +static size_t _make_data_frame_hdr(ng_at86rf2xx_t *dev, uint8_t *buf, + ng_netif_hdr_t *hdr) +{ + int pos = 0; + + /* we are building a data frame here */ + buf[0] = NG_IEEE802154_FCF_TYPE_DATA; + buf[1] = 0x88; /* use short src and dst addresses as starting point */ + + /* if AUTOACK is enabled, then we also expect ACKs for this packet */ + if (dev->options & NG_AT86RF2XX_OPT_AUTOACK) { + buf[0] |= NG_IEEE802154_FCF_ACK_REQ; + } + + /* fill in destination PAN ID */ + pos = 3; + buf[pos++] = (uint8_t)((dev->pan) & 0xff); + buf[pos++] = (uint8_t)((dev->pan) >> 8); + + /* fill in destination address */ + if (hdr->flags & + (NG_NETIF_HDR_FLAGS_BROADCAST | NG_NETIF_HDR_FLAGS_MULTICAST)) { + buf[pos++] = 0xff; + buf[pos++] = 0xff; + } + else if (hdr->dst_l2addr_len == 2) { + uint8_t *dst_addr = ng_netif_hdr_get_dst_addr(hdr); + buf[pos++] = dst_addr[1]; + buf[pos++] = dst_addr[0]; + } + else if (hdr->dst_l2addr_len == 8) { + buf[1] |= 0x04; + uint8_t *dst_addr = ng_netif_hdr_get_dst_addr(hdr); + for (int i = 7; i >= 0; i--) { + buf[pos++] = dst_addr[i]; + } + } + else { + /* unsupported address length */ + return 0; + } + + /* fill in source PAN ID (if applicable */ + if (dev->options & NG_AT86RF2XX_OPT_USE_SRC_PAN) { + buf[pos++] = (uint8_t)((dev->pan) & 0xff); + buf[pos++] = (uint8_t)((dev->pan) >> 8); + } else { + buf[0] |= NG_IEEE802154_FCF_PAN_COMP; + } + + /* fill in source address */ + if (dev->options & NG_AT86RF2XX_OPT_SRC_ADDR_LONG) { + buf[1] |= 0x40; + memcpy(&(buf[pos]), dev->addr_long, 8); + pos += 8; + } + else { + buf[pos++] = dev->addr_short[0]; + buf[pos++] = dev->addr_short[1]; + } + + /* set sequence number */ + buf[2] = dev->seq_nr++; + /* return actual header length */ + return pos; +} + +/* TODO: generalize and move to ng_ieee802154 */ +/* TODO: include security header implications */ +static size_t _get_frame_hdr_len(uint8_t *mhr) +{ + uint8_t tmp; + size_t len = 3; + + /* figure out address sizes */ + tmp = (mhr[1] & NG_IEEE802154_FCF_DST_ADDR_MASK); + if (tmp == NG_IEEE802154_FCF_DST_ADDR_SHORT) { + len += 4; + } + else if (tmp == NG_IEEE802154_FCF_DST_ADDR_LONG) { + len += 10; + } + else if (tmp != NG_IEEE802154_FCF_DST_ADDR_VOID) { + return 0; + } + tmp = (mhr[1] & NG_IEEE802154_FCF_SRC_ADDR_MASK); + if (tmp == NG_IEEE802154_FCF_SRC_ADDR_VOID) { + return len; + } + else { + if (!(mhr[0] & NG_IEEE802154_FCF_PAN_COMP)) { + len += 2; + } + if (tmp == NG_IEEE802154_FCF_SRC_ADDR_SHORT) { + return (len + 2); + } + else if (tmp == NG_IEEE802154_FCF_SRC_ADDR_LONG) { + return (len + 8); + } + } + return 0; +} + +/* TODO: generalize and move to ng_ieee802154 */ +static ng_pktsnip_t *_make_netif_hdr(uint8_t *mhr) +{ + uint8_t tmp; + uint8_t *addr; + uint8_t src_len, dst_len; + ng_pktsnip_t *snip; + ng_netif_hdr_t *hdr; + + /* figure out address sizes */ + tmp = mhr[1] & NG_IEEE802154_FCF_SRC_ADDR_MASK; + if (tmp == NG_IEEE802154_FCF_SRC_ADDR_SHORT) { + src_len = 2; + } + else if (tmp == NG_IEEE802154_FCF_SRC_ADDR_LONG) { + src_len = 8; + } + else if (tmp == 0) { + src_len = 0; + } + else { + return NULL; + } + tmp = mhr[1] & NG_IEEE802154_FCF_DST_ADDR_MASK; + if (tmp == NG_IEEE802154_FCF_DST_ADDR_SHORT) { + dst_len = 2; + } + else if (tmp == NG_IEEE802154_FCF_DST_ADDR_LONG) { + dst_len = 8; + } + else if (tmp == 0) { + dst_len = 0; + } + else { + return NULL; + } + /* allocate space for header */ + snip = ng_pktbuf_add(NULL, NULL, sizeof(ng_netif_hdr_t) + src_len + dst_len, + NG_NETTYPE_NETIF); + if (snip == NULL) { + return NULL; + } + /* fill header */ + hdr = (ng_netif_hdr_t *)snip->data; + ng_netif_hdr_init(hdr, src_len, dst_len); + if (dst_len > 0) { + tmp = 5 + dst_len; + addr = ng_netif_hdr_get_dst_addr(hdr); + for (int i = 0; i < dst_len; i++) { + addr[i] = mhr[5 + (dst_len - i) - 1]; + } + } + else { + tmp = 3; + } + if (!(mhr[0] & NG_IEEE802154_FCF_PAN_COMP)) { + tmp += 2; + } + if (src_len > 0) { + addr = ng_netif_hdr_get_src_addr(hdr); + for (int i = 0; i < src_len; i++) { + addr[i] = mhr[tmp + (src_len - i) - 1]; + } + } + return snip; +} + + +static int _send(ng_netdev_t *netdev, ng_pktsnip_t *pkt) +{ + ng_at86rf2xx_t *dev = (ng_at86rf2xx_t *)netdev; + ng_pktsnip_t *snip; + uint8_t mhr[NG_IEEE802154_MAX_HDR_LEN]; + size_t len; + + if (pkt == NULL) { + return -ENOMSG; + } + if (dev == NULL) { + ng_pktbuf_release(pkt); + return -ENODEV; + } + + /* create 802.15.4 header */ + len = _make_data_frame_hdr(dev, mhr, (ng_netif_hdr_t *)pkt->data); + if (len == 0) { + DEBUG("[ng_at86rf2xx] error: unable to create 802.15.4 header\n"); + ng_pktbuf_release(pkt); + return -ENOMSG; + } + /* check if packet (header + payload + FCS) fits into FIFO */ + snip = pkt->next; + if ((ng_pkt_len(snip) + len + 2) > NG_AT86RF2XX_MAX_PKT_LENGTH) { + DEBUG("[ng_at86rf2xx] error: packet too large to be send\n"); + ng_pktbuf_release(pkt); + return -EOVERFLOW; + } + + ng_at86rf2xx_tx_prepare(dev); + /* put header into FIFO */ + len = ng_at86rf2xx_tx_load(dev, mhr, len, 0); + /* load packet data into FIFO */ + while (snip) { + len += ng_at86rf2xx_tx_load(dev, snip->data, snip->size, len); + snip = snip->next; + } + /* send data out directly if pre-loading id disabled */ + if (!(dev->options & NG_AT86RF2XX_OPT_PRELOADING)) { + ng_at86rf2xx_tx_exec(dev); + } + /* release packet */ + ng_pktbuf_release(pkt); + /* return the number of bytes that were actually send out */ + return (int)len; +} + +static void _receive_data(ng_at86rf2xx_t *dev) +{ + uint8_t mhr[NG_IEEE802154_MAX_HDR_LEN]; + size_t pkt_len, hdr_len; + ng_pktsnip_t *hdr, *payload = NULL; + ng_netif_hdr_t *netif; + + /* get the size of the received packet (unlocks frame buffer protection) */ + pkt_len = ng_at86rf2xx_rx_len(dev); + + /* abort here already if no event callback is registered */ + if (!dev->event_cb) { + return; + } + + /* in raw mode, just read the binary dump into the packet buffer */ + if (dev->options & NG_AT86RF2XX_OPT_RAWDUMP) { + payload = ng_pktbuf_add(NULL, NULL, pkt_len, NG_NETTYPE_UNDEF); + if (payload == NULL ) { + DEBUG("[ng_at86rf2xx] error: unable to allocate RAW data\n"); + return; + } + ng_at86rf2xx_rx_read(dev, payload->data, pkt_len, 0); + dev->event_cb(NETDEV_EVENT_RX_COMPLETE, payload); + return; + } + + /* get FCF field and compute 802.15.4 header length */ + ng_at86rf2xx_rx_read(dev, mhr, 2, 0); + hdr_len = _get_frame_hdr_len(mhr); + if (hdr_len == 0) { + DEBUG("[ng_at86rf2xx] error: unable parse incoming frame header\n"); + return; + } + /* read the rest of the header and parse the netif header from it */ + ng_at86rf2xx_rx_read(dev, &(mhr[2]), hdr_len - 2, 2); + hdr = _make_netif_hdr(mhr); + if (hdr == NULL) { + DEBUG("[ng_at86rf2xx] error: unable to allocate netif header\n"); + return; + } + /* fill missing fields in netif header */ + netif = (ng_netif_hdr_t *)hdr->data; + netif->if_pid = dev->mac_pid; + ng_at86rf2xx_rx_read(dev, &(netif->lqi), 1, pkt_len); + netif->rssi = ng_at86rf2xx_reg_read(dev, NG_AT86RF2XX_REG__PHY_ED_LEVEL); + + /* allocate payload */ + payload = ng_pktbuf_add(hdr, NULL, (pkt_len - hdr_len), dev->proto); + if (payload == NULL) { + DEBUG("[ng_at86rf2xx] error: unable to allocate incoming payload\n"); + ng_pktbuf_release(hdr); + return; + } + /* copy payload */ + ng_at86rf2xx_rx_read(dev, payload->data, payload->size, hdr_len); + /* finish up and send data to upper layers */ + dev->event_cb(NETDEV_EVENT_RX_COMPLETE, payload); +} + +static int _set_state(ng_at86rf2xx_t *dev, ng_netconf_state_t state) +{ + switch (state) { + case NETCONF_STATE_SLEEP: + ng_at86rf2xx_set_state(dev, NG_AT86RF2XX_STATE_TRX_OFF); + break; + case NETCONF_STATE_IDLE: + ng_at86rf2xx_set_state(dev, NG_AT86RF2XX_STATE_RX_AACK_ON); + break; + case NETCONF_STATE_TX: + if (dev->options & NG_AT86RF2XX_OPT_PRELOADING) { + ng_at86rf2xx_tx_exec(dev); + } + break; + case NETCONF_STATE_RESET: + ng_at86rf2xx_reset(dev); + break; + default: + return -ENOTSUP; + } + return sizeof(ng_netconf_state_t); +} + +ng_netconf_state_t _get_state(ng_at86rf2xx_t *dev) +{ + switch (ng_at86rf2xx_get_state(dev)) { + case NG_AT86RF2XX_STATE_SLEEP: + return NETCONF_STATE_SLEEP; + case NG_AT86RF2XX_STATE_BUSY_RX_AACK: + return NETCONF_STATE_RX; + case NG_AT86RF2XX_STATE_BUSY_TX_ARET: + case NG_AT86RF2XX_STATE_TX_ARET_ON: + return NETCONF_STATE_TX; + case NG_AT86RF2XX_STATE_RX_AACK_ON: + default: + return NETCONF_STATE_IDLE; + } +} + +static int _get(ng_netdev_t *device, ng_netconf_opt_t opt, + void *val, size_t max_len) +{ + if (device == NULL) { + return -ENODEV; + } + ng_at86rf2xx_t *dev = (ng_at86rf2xx_t *) device; + + switch (opt) { + + case NETCONF_OPT_ADDRESS: + if (max_len < sizeof(uint16_t)) { + return -EOVERFLOW; + } + *((uint16_t *)val) = ng_at86rf2xx_get_addr_short(dev); + return sizeof(uint16_t); + + case NETCONF_OPT_ADDRESS_LONG: + if (max_len < sizeof(uint64_t)) { + return -EOVERFLOW; + } + *((uint64_t *)val) = ng_at86rf2xx_get_addr_long(dev); + return sizeof(uint64_t); + + case NETCONF_OPT_ADDR_LEN: + if (max_len < sizeof(uint16_t)) { + return -EOVERFLOW; + } + *((uint16_t *)val) = 2; + return sizeof(uint16_t); + + case NETCONF_OPT_SRC_LEN: + if (max_len < sizeof(uint16_t)) { + return -EOVERFLOW; + } + if (dev->options & NG_AT86RF2XX_OPT_SRC_ADDR_LONG) { + *((uint16_t *)val) = 8; + } + else { + *((uint16_t *)val) = 2; + } + return sizeof(uint16_t); + + case NETCONF_OPT_NID: + if (max_len < sizeof(uint16_t)) { + return -EOVERFLOW; + } + *((uint16_t *)val) = dev->pan; + return sizeof(uint16_t); + + case NETCONF_OPT_CHANNEL: + if (max_len < sizeof(uint16_t)) { + return -EOVERFLOW; + } + ((uint8_t *)val)[1] = 0; + ((uint8_t *)val)[0] = ng_at86rf2xx_get_chan(dev); + return sizeof(uint16_t); + + case NETCONF_OPT_TX_POWER: + if (max_len < sizeof(int16_t)) { + return -EOVERFLOW; + } + *((uint16_t *)val) = ng_at86rf2xx_get_txpower(dev); + return sizeof(uint16_t); + + case NETCONF_OPT_MAX_PACKET_SIZE: + if (max_len < sizeof(int16_t)) { + return -EOVERFLOW; + } + *((uint16_t *)val) = NG_AT86RF2XX_MAX_PKT_LENGTH; + return sizeof(uint16_t); + + case NETCONF_OPT_STATE: + if (max_len < sizeof(ng_netconf_state_t)) { + return -EOVERFLOW; + } + *((ng_netconf_state_t*)val) = _get_state(dev); + break; + + case NETCONF_OPT_PRELOADING: + if (max_len < sizeof(ng_netconf_enable_t)) { + return -EOVERFLOW; + } + if (dev->options & NG_AT86RF2XX_OPT_PRELOADING) { + *((ng_netconf_enable_t *)val) = NETCONF_ENABLE; + } + else { + *((ng_netconf_enable_t *)val) = NETCONF_DISABLE; + } + return sizeof(ng_netconf_enable_t); + + case NETCONF_OPT_AUTOACK: + if (max_len < sizeof(ng_netconf_enable_t)) { + return -EOVERFLOW; + } + if (dev->options & NG_AT86RF2XX_OPT_AUTOACK) { + *((ng_netconf_enable_t *)val) = NETCONF_ENABLE; + } + else { + *((ng_netconf_enable_t *)val) = NETCONF_DISABLE; + } + return sizeof(ng_netconf_enable_t); + + case NETCONF_OPT_PROMISCUOUSMODE: + if (max_len < sizeof(ng_netconf_enable_t)) { + return -EOVERFLOW; + } + if (dev->options & NG_AT86RF2XX_OPT_PROMISCUOUS) { + *((ng_netconf_enable_t *)val) = NETCONF_ENABLE; + } + else { + *((ng_netconf_enable_t *)val) = NETCONF_DISABLE; + } + return sizeof(ng_netconf_enable_t); + + case NETCONF_OPT_RAWMODE: + if (max_len < sizeof(ng_netconf_enable_t)) { + return -EOVERFLOW; + } + if (dev->options & NG_AT86RF2XX_OPT_RAWDUMP) { + *((ng_netconf_enable_t *)val) = NETCONF_ENABLE; + } + else { + *((ng_netconf_enable_t *)val) = NETCONF_DISABLE; + } + return sizeof(ng_netconf_enable_t); + + case NETCONF_OPT_IS_CHANNEL_CLR: + if (max_len < sizeof(ng_netconf_enable_t)) { + return -EOVERFLOW; + } + if (ng_at86rf2xx_cca(dev)) { + *((ng_netconf_enable_t *)val) = NETCONF_ENABLE; + } + else { + *((ng_netconf_enable_t *)val) = NETCONF_DISABLE; + } + return sizeof(ng_netconf_enable_t); + + default: + return -ENOTSUP; + } + + return 0; +} + +static int _set(ng_netdev_t *device, ng_netconf_opt_t opt, + void *val, size_t len) +{ + ng_at86rf2xx_t *dev = (ng_at86rf2xx_t *) device; + + if (dev == NULL) { + return -ENODEV; + } + + switch (opt) { + case NETCONF_OPT_ADDRESS: + if (len > sizeof(uint16_t)) { + return -EOVERFLOW; + } + ng_at86rf2xx_set_addr_short(dev, *((uint16_t*)val)); + return sizeof(uint16_t); + + case NETCONF_OPT_ADDRESS_LONG: + if (len > sizeof(uint64_t)) { + return -EOVERFLOW; + } + ng_at86rf2xx_set_addr_long(dev, *((uint64_t*)val)); + return sizeof(uint64_t); + + case NETCONF_OPT_SRC_LEN: + if (len > sizeof(uint16_t)) { + return -EOVERFLOW; + } + if (*((uint16_t *)val) == 2) { + ng_at86rf2xx_set_option(dev, NG_AT86RF2XX_OPT_SRC_ADDR_LONG, + false); + } + else if (*((uint16_t *)val) == 8) { + ng_at86rf2xx_set_option(dev, NG_AT86RF2XX_OPT_SRC_ADDR_LONG, + true); + } + else { + return -ENOTSUP; + } + return sizeof(uint16_t); + + case NETCONF_OPT_NID: + if (len > sizeof(uint16_t)) { + return -EOVERFLOW; + } + ng_at86rf2xx_set_pan(dev, *((uint16_t *)val)); + return sizeof(uint16_t); + + case NETCONF_OPT_CHANNEL: + if (len != sizeof(uint16_t)) { + return -EINVAL; + } + uint8_t chan = ((uint8_t *)val)[0]; + if (chan < NG_AT86RF2XX_MIN_CHANNEL || + chan > NG_AT86RF2XX_MAX_CHANNEL) { + return -ENOTSUP; + } + ng_at86rf2xx_set_chan(dev, chan); + return sizeof(uint16_t); + + case NETCONF_OPT_TX_POWER: + if (len > sizeof(int16_t)) { + return -EOVERFLOW; + } + ng_at86rf2xx_set_txpower(dev, *((int16_t *)val)); + return sizeof(uint16_t); + + case NETCONF_OPT_STATE: + if (len > sizeof(ng_netconf_state_t)) { + return -EOVERFLOW; + } + return _set_state(dev, *((ng_netconf_state_t *)val)); + + case NETCONF_OPT_AUTOACK: + if (len > sizeof(ng_netconf_enable_t)) { + return -EOVERFLOW; + } + ng_at86rf2xx_set_option(dev, NG_AT86RF2XX_OPT_AUTOACK, + ((bool *)val)[0]); + return sizeof(ng_netconf_enable_t); + + case NETCONF_OPT_PRELOADING: + if (len > sizeof(ng_netconf_enable_t)) { + return -EOVERFLOW; + } + ng_at86rf2xx_set_option(dev, NG_AT86RF2XX_OPT_PRELOADING, + ((bool *)val)[0]); + return sizeof(ng_netconf_enable_t); + + case NETCONF_OPT_PROMISCUOUSMODE: + if (len > sizeof(ng_netconf_enable_t)) { + return -EOVERFLOW; + } + ng_at86rf2xx_set_option(dev, NG_AT86RF2XX_OPT_PROMISCUOUS, + ((bool *)val)[0]); + return sizeof(ng_netconf_enable_t); + + case NETCONF_OPT_RAWMODE: + if (len > sizeof(ng_netconf_enable_t)) { + return -EOVERFLOW; + } + ng_at86rf2xx_set_option(dev, NG_AT86RF2XX_OPT_RAWDUMP, + ((bool *)val)[0]); + return sizeof(ng_netconf_enable_t); + + default: + return -ENOTSUP; + } + + return 0; +} + +static int _add_event_cb(ng_netdev_t *dev, ng_netdev_event_cb_t cb) +{ + if (dev == NULL) { + return -ENODEV; + } + if (dev->event_cb) { + return -ENOBUFS; + } + + dev->event_cb = cb; + return 0; +} + +static int _rem_event_cb(ng_netdev_t *dev, ng_netdev_event_cb_t cb) +{ + if (dev == NULL) { + return -ENODEV; + } + if (dev->event_cb != cb) { + return -ENOENT; + } + + dev->event_cb = NULL; + return 0; +} + +static void _isr_event(ng_netdev_t *device, uint32_t event_type) +{ + ng_at86rf2xx_t *dev = (ng_at86rf2xx_t *) device; + uint8_t irq_mask; + uint8_t state; + + /* read (consume) device status */ + irq_mask = ng_at86rf2xx_reg_read(dev, NG_AT86RF2XX_REG__IRQ_STATUS); + state = ng_at86rf2xx_get_state(dev); + + if (irq_mask & NG_AT86RF2XX_IRQ_STATUS_MASK__RX_START) { + if (dev->event_cb && (dev->options & NG_AT86RF2XX_OPT_TELL_RX_START)) { + dev->event_cb(NETDEV_EVENT_RX_STARTED, NULL); + } + DEBUG("[ng_at86rf2xx] EVT - RX_START\n"); + } + if (irq_mask & NG_AT86RF2XX_IRQ_STATUS_MASK__TRX_END) { + if (state == NG_AT86RF2XX_STATE_RX_AACK_ON || state == NG_AT86RF2XX_STATE_BUSY_RX_AACK) { + DEBUG("[ng_at86rf2xx] EVT - RX_END\n"); + if (!(dev->options & NG_AT86RF2XX_OPT_TELL_RX_END)) { + return; + } + _receive_data(dev); + } + else if (state == NG_AT86RF2XX_STATE_TX_ARET_ON) { + if (dev->event_cb && (dev->options & NG_AT86RF2XX_OPT_TELL_TX_END)) { + dev->event_cb(NETDEV_EVENT_TX_COMPLETE, NULL); + } + DEBUG("[ng_at86rf2xx] EVT - TX_END\n"); + ng_at86rf2xx_set_state(dev, dev->idle_state); + } + } +} + +const ng_netdev_driver_t ng_at86rf2xx_driver = { + .send_data = _send, + .add_event_callback = _add_event_cb, + .rem_event_callback = _rem_event_cb, + .get = _get, + .set = _set, + .isr_event = _isr_event, +};