1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

drivers: new driver for at86rf2xx family radios

This commit is contained in:
Hauke Petersen 2015-04-23 18:36:55 +02:00
parent f12f19917c
commit fefac35c1c
12 changed files with 2114 additions and 0 deletions

View File

@ -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

View File

@ -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%

View File

@ -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

View File

@ -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 <thomas.eichinger@fu-berlin.de>
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Kaspar Schleiser <kaspar@schleiser.de>
*/
#ifndef NG_AT86RF2XX_H_
#define NG_AT86RF2XX_H_
#include <stdint.h>
#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_ */
/** @} */

View File

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

View File

@ -0,0 +1,107 @@
/*
* Copyright (C) 2013 Alaeddine Weslati <alaeddine.weslati@inria.fr>
* 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 <alaeddine.weslati@inria.fr>
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*/
#ifndef NG_AT86RF2XX_INTERNAL_H_
#define NG_AT86RF2XX_INTERNAL_H_
#include <stdint.h>
#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_ */
/** @} */

View File

@ -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 <hauke.petersen@fu-berlin.de>
*/
#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_ */
/** @} */

View File

@ -0,0 +1,319 @@
/*
* Copyright (C) 2013 Alaeddine Weslati <alaeddine.weslati@inria.fr>
* 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 <alaeddine.weslati@inria.fr>
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Kaspar Schleiser <kaspar@schleiser.de>
*/
#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_ */
/** @} */

View File

@ -0,0 +1,256 @@
/*
* Copyright (C) 2013 Alaeddine Weslati <alaeddine.weslati@inria.fr>
* 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 <alaeddine.weslati@inria.fr>
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Kaspar Schleiser <kaspar@schleiser.de>
*
* @}
*/
#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
}

View File

@ -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 <thomas.eichinger@fu-berlin.de>
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*
* @}
*/
#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);
}
}

View File

@ -0,0 +1,106 @@
/*
* Copyright (C) 2013 Alaeddine Weslati <alaeddine.weslati@inria.fr>
* 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 <alaeddine.weslati@inria.fr>
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
* @author Joakim Gebart <joakim.gebart@eistec.se>
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*
* @}
*/
#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);
}

View File

@ -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 <thomas.eichinger@fu-berlin.de>
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*
* @}
*/
#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,
};