2015-04-23 18:36:55 +02:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
2015-08-09 21:24:55 +02:00
|
|
|
* @ingroup drivers_at86rf2xx
|
2015-04-23 18:36:55 +02:00
|
|
|
* @{
|
|
|
|
*
|
|
|
|
* @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>
|
2015-05-10 21:50:41 +02:00
|
|
|
* @author Oliver Hahm <oliver.hahm@inria.fr>
|
2015-04-23 18:36:55 +02:00
|
|
|
*
|
|
|
|
* @}
|
|
|
|
*/
|
|
|
|
|
2015-07-30 10:20:06 +02:00
|
|
|
#include "xtimer.h"
|
2015-04-23 18:36:55 +02:00
|
|
|
#include "periph/cpuid.h"
|
2015-05-10 21:50:41 +02:00
|
|
|
#include "byteorder.h"
|
2015-08-07 14:36:04 +02:00
|
|
|
#include "net/ieee802154.h"
|
2015-08-10 02:41:08 +02:00
|
|
|
#include "net/gnrc.h"
|
2015-08-09 21:24:55 +02:00
|
|
|
#include "at86rf2xx_registers.h"
|
|
|
|
#include "at86rf2xx_internal.h"
|
|
|
|
#include "at86rf2xx_netdev.h"
|
2015-04-23 18:36:55 +02:00
|
|
|
|
|
|
|
#define ENABLE_DEBUG (0)
|
|
|
|
#include "debug.h"
|
|
|
|
|
|
|
|
|
2015-05-19 15:08:44 +02:00
|
|
|
#define RESET_DELAY (1U) /* must be > 625ns */
|
2015-04-23 18:36:55 +02:00
|
|
|
|
|
|
|
|
|
|
|
static void _irq_handler(void *arg)
|
|
|
|
{
|
|
|
|
msg_t msg;
|
2015-08-09 21:24:55 +02:00
|
|
|
at86rf2xx_t *dev = (at86rf2xx_t *) arg;
|
2015-04-23 18:36:55 +02:00
|
|
|
|
|
|
|
/* tell driver thread about the interrupt */
|
2015-08-17 15:41:29 +02:00
|
|
|
msg.type = GNRC_NETDEV_MSG_TYPE_EVENT;
|
2015-04-23 18:36:55 +02:00
|
|
|
msg_send(&msg, dev->mac_pid);
|
|
|
|
}
|
|
|
|
|
2015-08-09 21:24:55 +02:00
|
|
|
int at86rf2xx_init(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)
|
2015-04-23 18:36:55 +02:00
|
|
|
{
|
2015-08-09 21:24:55 +02:00
|
|
|
dev->driver = &at86rf2xx_driver;
|
2015-04-23 18:36:55 +02:00
|
|
|
|
|
|
|
/* 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;
|
2015-08-09 21:24:55 +02:00
|
|
|
dev->idle_state = AT86RF2XX_STATE_TRX_OFF;
|
2015-04-23 18:36:55 +02:00
|
|
|
|
|
|
|
/* initialise SPI */
|
|
|
|
spi_init_master(dev->spi, SPI_CONF_FIRST_RISING, spi_speed);
|
|
|
|
/* initialise GPIOs */
|
2015-06-12 19:10:29 +02:00
|
|
|
gpio_init(dev->cs_pin, GPIO_DIR_OUT, GPIO_NOPULL);
|
2015-04-23 18:36:55 +02:00
|
|
|
gpio_set(dev->cs_pin);
|
2015-06-12 19:10:29 +02:00
|
|
|
gpio_init(dev->sleep_pin, GPIO_DIR_OUT, GPIO_NOPULL);
|
2015-04-23 18:36:55 +02:00
|
|
|
gpio_clear(dev->sleep_pin);
|
2015-06-12 19:10:29 +02:00
|
|
|
gpio_init(dev->reset_pin, GPIO_DIR_OUT, GPIO_NOPULL);
|
2015-04-23 18:36:55 +02:00
|
|
|
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 */
|
2015-08-09 21:24:55 +02:00
|
|
|
if (at86rf2xx_reg_read(dev, AT86RF2XX_REG__PART_NUM) !=
|
|
|
|
AT86RF2XX_PARTNUM) {
|
|
|
|
DEBUG("[at86rf2xx] error: unable to read correct part number\n");
|
2015-04-23 18:36:55 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* reset device to default values and put it into RX state */
|
2015-08-09 21:24:55 +02:00
|
|
|
at86rf2xx_reset(dev);
|
2015-04-23 18:36:55 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-08-09 21:24:55 +02:00
|
|
|
void at86rf2xx_reset(at86rf2xx_t *dev)
|
2015-04-23 18:36:55 +02:00
|
|
|
{
|
|
|
|
#if CPUID_ID_LEN
|
|
|
|
uint8_t cpuid[CPUID_ID_LEN];
|
2015-05-10 21:50:41 +02:00
|
|
|
eui64_t addr_long;
|
2015-04-23 18:36:55 +02:00
|
|
|
#endif
|
|
|
|
|
2015-07-16 20:54:50 +02:00
|
|
|
/* wake from sleep in case radio is sleeping */
|
|
|
|
gpio_clear(dev->sleep_pin);
|
2015-04-23 18:36:55 +02:00
|
|
|
/* trigger hardware reset */
|
|
|
|
gpio_clear(dev->reset_pin);
|
2015-07-30 10:20:06 +02:00
|
|
|
xtimer_usleep(RESET_DELAY);
|
2015-04-23 18:36:55 +02:00
|
|
|
gpio_set(dev->reset_pin);
|
2015-07-16 20:54:50 +02:00
|
|
|
|
|
|
|
/* Reset state machine to ensure a known state */
|
2015-08-09 21:24:55 +02:00
|
|
|
at86rf2xx_reset_state_machine(dev);
|
2015-07-16 20:54:50 +02:00
|
|
|
|
2015-04-23 18:36:55 +02:00
|
|
|
/* reset options and sequence number */
|
|
|
|
dev->seq_nr = 0;
|
|
|
|
dev->options = 0;
|
|
|
|
/* set short and long address */
|
|
|
|
#if CPUID_ID_LEN
|
|
|
|
cpuid_get(cpuid);
|
2015-05-10 21:50:41 +02:00
|
|
|
|
2015-05-10 21:50:07 +02:00
|
|
|
#if CPUID_ID_LEN < 8
|
2015-04-23 18:36:55 +02:00
|
|
|
/* 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);
|
2015-08-09 21:24:55 +02:00
|
|
|
at86rf2xx_set_addr_long(dev, NTOHLL(addr_long.uint64.u64));
|
|
|
|
at86rf2xx_set_addr_short(dev, NTOHS(addr_long.uint16[0].u16));
|
2015-04-23 18:36:55 +02:00
|
|
|
#else
|
2015-08-09 21:24:55 +02:00
|
|
|
at86rf2xx_set_addr_long(dev, AT86RF2XX_DEFAULT_ADDR_LONG);
|
|
|
|
at86rf2xx_set_addr_short(dev, AT86RF2XX_DEFAULT_ADDR_SHORT);
|
2015-04-23 18:36:55 +02:00
|
|
|
#endif
|
|
|
|
/* set default PAN id */
|
2015-08-09 21:24:55 +02:00
|
|
|
at86rf2xx_set_pan(dev, AT86RF2XX_DEFAULT_PANID);
|
2015-04-23 18:36:55 +02:00
|
|
|
/* set default channel */
|
2015-08-09 21:24:55 +02:00
|
|
|
at86rf2xx_set_chan(dev, AT86RF2XX_DEFAULT_CHANNEL);
|
2015-04-23 18:36:55 +02:00
|
|
|
/* set default TX power */
|
2015-08-09 21:24:55 +02:00
|
|
|
at86rf2xx_set_txpower(dev, AT86RF2XX_DEFAULT_TXPOWER);
|
2015-04-23 18:36:55 +02:00
|
|
|
/* set default options */
|
2015-08-09 21:24:55 +02:00
|
|
|
at86rf2xx_set_option(dev, AT86RF2XX_OPT_AUTOACK, true);
|
|
|
|
at86rf2xx_set_option(dev, AT86RF2XX_OPT_CSMA, true);
|
|
|
|
at86rf2xx_set_option(dev, AT86RF2XX_OPT_TELL_RX_START, false);
|
|
|
|
at86rf2xx_set_option(dev, AT86RF2XX_OPT_TELL_RX_END, true);
|
2015-04-23 18:36:55 +02:00
|
|
|
/* set default protocol */
|
2015-08-17 15:41:29 +02:00
|
|
|
#ifdef MODULE_GNRC_SIXLOWPAN
|
|
|
|
dev->proto = GNRC_NETTYPE_SIXLOWPAN;
|
2015-04-23 18:36:55 +02:00
|
|
|
#else
|
2015-08-17 15:41:29 +02:00
|
|
|
dev->proto = GNRC_NETTYPE_UNDEF;
|
2015-04-23 18:36:55 +02:00
|
|
|
#endif
|
|
|
|
/* enable safe mode (protect RX FIFO until reading data starts) */
|
2015-08-09 21:24:55 +02:00
|
|
|
at86rf2xx_reg_write(dev, AT86RF2XX_REG__TRX_CTRL_2,
|
|
|
|
AT86RF2XX_TRX_CTRL_2_MASK__RX_SAFE_MODE);
|
2015-08-12 17:08:42 +02:00
|
|
|
#ifdef MODULE_AT86RF212B
|
2015-08-09 21:24:55 +02:00
|
|
|
at86rf2xx_set_freq(dev, AT86RF2XX_FREQ_915MHZ);
|
2015-04-23 18:36:55 +02:00
|
|
|
#endif
|
2015-07-01 16:35:19 +02:00
|
|
|
|
|
|
|
/* don't populate masked interrupt flags to IRQ_STATUS register */
|
2015-08-09 21:24:55 +02:00
|
|
|
uint8_t tmp = at86rf2xx_reg_read(dev, AT86RF2XX_REG__TRX_CTRL_1);
|
|
|
|
tmp &= ~(AT86RF2XX_TRX_CTRL_1_MASK__IRQ_MASK_MODE);
|
|
|
|
at86rf2xx_reg_write(dev, AT86RF2XX_REG__TRX_CTRL_1, tmp);
|
2015-07-01 16:35:19 +02:00
|
|
|
|
2015-04-23 18:36:55 +02:00
|
|
|
/* enable interrupts */
|
2015-08-09 21:24:55 +02:00
|
|
|
at86rf2xx_reg_write(dev, AT86RF2XX_REG__IRQ_MASK,
|
|
|
|
AT86RF2XX_IRQ_STATUS_MASK__TRX_END);
|
2015-07-01 16:35:19 +02:00
|
|
|
/* clear interrupt flags */
|
2015-08-09 21:24:55 +02:00
|
|
|
at86rf2xx_reg_read(dev, AT86RF2XX_REG__IRQ_STATUS);
|
2015-07-01 16:35:19 +02:00
|
|
|
|
2015-04-23 18:36:55 +02:00
|
|
|
/* go into RX state */
|
2015-08-09 21:24:55 +02:00
|
|
|
at86rf2xx_set_state(dev, AT86RF2XX_STATE_RX_AACK_ON);
|
2015-04-23 18:36:55 +02:00
|
|
|
|
2015-08-09 21:24:55 +02:00
|
|
|
DEBUG("at86rf2xx_reset(): reset complete.\n");
|
2015-04-23 18:36:55 +02:00
|
|
|
}
|
|
|
|
|
2015-08-09 21:24:55 +02:00
|
|
|
bool at86rf2xx_cca(at86rf2xx_t *dev)
|
2015-04-23 18:36:55 +02:00
|
|
|
{
|
|
|
|
uint8_t tmp;
|
|
|
|
uint8_t status;
|
|
|
|
|
|
|
|
/* trigger CCA measurment */
|
2015-08-09 21:24:55 +02:00
|
|
|
tmp = at86rf2xx_reg_read(dev, AT86RF2XX_REG__PHY_CC_CCA);
|
|
|
|
tmp &= AT86RF2XX_PHY_CC_CCA_MASK__CCA_REQUEST;
|
|
|
|
at86rf2xx_reg_write(dev, AT86RF2XX_REG__PHY_CC_CCA, tmp);
|
2015-04-23 18:36:55 +02:00
|
|
|
/* wait for result to be ready */
|
|
|
|
do {
|
2015-08-09 21:24:55 +02:00
|
|
|
status = at86rf2xx_reg_read(dev, AT86RF2XX_REG__TRX_STATUS);
|
|
|
|
} while (!(status & AT86RF2XX_TRX_STATUS_MASK__CCA_DONE));
|
2015-04-23 18:36:55 +02:00
|
|
|
/* return according to measurement */
|
2015-08-09 21:24:55 +02:00
|
|
|
if (status & AT86RF2XX_TRX_STATUS_MASK__CCA_STATUS) {
|
2015-04-23 18:36:55 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-09 21:24:55 +02:00
|
|
|
size_t at86rf2xx_send(at86rf2xx_t *dev, uint8_t *data, size_t len)
|
2015-04-23 18:36:55 +02:00
|
|
|
{
|
|
|
|
/* check data length */
|
2015-08-09 21:24:55 +02:00
|
|
|
if (len > AT86RF2XX_MAX_PKT_LENGTH) {
|
|
|
|
DEBUG("[at86rf2xx] Error: data to send exceeds max packet size\n");
|
2015-04-23 18:36:55 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2015-08-09 21:24:55 +02:00
|
|
|
at86rf2xx_tx_prepare(dev);
|
|
|
|
at86rf2xx_tx_load(dev, data, len, 0);
|
|
|
|
at86rf2xx_tx_exec(dev);
|
2015-04-23 18:36:55 +02:00
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2015-08-09 21:24:55 +02:00
|
|
|
void at86rf2xx_tx_prepare(at86rf2xx_t *dev)
|
2015-04-23 18:36:55 +02:00
|
|
|
{
|
|
|
|
uint8_t state;
|
|
|
|
|
|
|
|
/* make sure ongoing transmissions are finished */
|
|
|
|
do {
|
2015-08-09 21:24:55 +02:00
|
|
|
state = at86rf2xx_get_status(dev);
|
2015-04-23 18:36:55 +02:00
|
|
|
}
|
2015-08-09 21:24:55 +02:00
|
|
|
while (state == AT86RF2XX_STATE_BUSY_RX_AACK ||
|
|
|
|
state == AT86RF2XX_STATE_BUSY_TX_ARET);
|
|
|
|
if (state != AT86RF2XX_STATE_TX_ARET_ON) {
|
2015-07-20 11:46:07 +02:00
|
|
|
dev->idle_state = state;
|
|
|
|
}
|
2015-08-09 21:24:55 +02:00
|
|
|
at86rf2xx_set_state(dev, AT86RF2XX_STATE_TX_ARET_ON);
|
2015-08-07 14:36:04 +02:00
|
|
|
dev->frame_len = IEEE802154_FCS_LEN;
|
2015-04-23 18:36:55 +02:00
|
|
|
}
|
|
|
|
|
2015-08-09 21:24:55 +02:00
|
|
|
size_t at86rf2xx_tx_load(at86rf2xx_t *dev, uint8_t *data,
|
|
|
|
size_t len, size_t offset)
|
2015-04-23 18:36:55 +02:00
|
|
|
{
|
|
|
|
dev->frame_len += (uint8_t)len;
|
2015-08-09 21:24:55 +02:00
|
|
|
at86rf2xx_sram_write(dev, offset + 1, data, len);
|
2015-04-23 18:36:55 +02:00
|
|
|
return offset + len;
|
|
|
|
}
|
|
|
|
|
2015-08-09 21:24:55 +02:00
|
|
|
void at86rf2xx_tx_exec(at86rf2xx_t *dev)
|
2015-04-23 18:36:55 +02:00
|
|
|
{
|
|
|
|
/* write frame length field in FIFO */
|
2015-08-09 21:24:55 +02:00
|
|
|
at86rf2xx_sram_write(dev, 0, &(dev->frame_len), 1);
|
2015-04-23 18:36:55 +02:00
|
|
|
/* trigger sending of pre-loaded frame */
|
2015-08-09 21:24:55 +02:00
|
|
|
at86rf2xx_reg_write(dev, AT86RF2XX_REG__TRX_STATE,
|
|
|
|
AT86RF2XX_TRX_STATE__TX_START);
|
|
|
|
if (dev->event_cb && (dev->options & AT86RF2XX_OPT_TELL_TX_START)) {
|
2015-04-23 18:36:55 +02:00
|
|
|
dev->event_cb(NETDEV_EVENT_TX_STARTED, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-09 21:24:55 +02:00
|
|
|
size_t at86rf2xx_rx_len(at86rf2xx_t *dev)
|
2015-04-23 18:36:55 +02:00
|
|
|
{
|
|
|
|
uint8_t res;
|
2015-08-09 21:24:55 +02:00
|
|
|
at86rf2xx_fb_read(dev, &res, 1);
|
2015-04-23 18:36:55 +02:00
|
|
|
return (size_t)(res - 2); /* extract the PHR and LQI field */
|
|
|
|
}
|
|
|
|
|
2015-08-09 21:24:55 +02:00
|
|
|
void at86rf2xx_rx_read(at86rf2xx_t *dev, uint8_t *data, size_t len,
|
|
|
|
size_t offset)
|
2015-04-23 18:36:55 +02:00
|
|
|
{
|
|
|
|
/* 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.
|
|
|
|
*/
|
2015-08-12 17:08:42 +02:00
|
|
|
#ifndef MODULE_AT86RF231
|
2015-08-09 21:24:55 +02:00
|
|
|
at86rf2xx_sram_read(dev, offset + 1, data, len);
|
2015-04-23 18:36:55 +02:00
|
|
|
#else
|
2015-08-09 21:24:55 +02:00
|
|
|
at86rf2xx_sram_read(dev, offset, data, len);
|
2015-04-23 18:36:55 +02:00
|
|
|
#endif
|
|
|
|
}
|