1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/drivers/at86rf231/at86rf231.c
Ludwig Ortmann 6391235ff2 drivers/at86rf231: fix break condition
The break condition could not be fulfilled because the counter was always
reset.
2015-03-24 14:50:46 +01:00

757 lines
22 KiB
C

/*
* Copyright (C) 2013 Alaeddine Weslati <alaeddine.weslati@inria.fr>
*
* 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_at86rf231
* @{
*
* @file
* @brief Driver implementation of the AT86RF231 device driver
*
* @author Alaeddine Weslati <alaeddine.weslati@inria.fr>
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
*
* @}
*/
#include "at86rf231.h"
#include "at86rf231_spi.h"
#include "board.h"
#include "periph/gpio.h"
#include "periph/spi.h"
#include "kernel_types.h"
#include "transceiver.h"
#include "hwtimer.h"
#include "config.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#ifndef AT86RF231_SPI_SPEED
#define SPI_SPEED SPI_SPEED_5MHZ
#else
#define SPI_SPEED AT86RF231_SPI_SPEED
#endif
#define _MAX_RETRIES (100)
static uint16_t radio_pan;
static uint8_t radio_channel;
static uint16_t radio_address;
static uint64_t radio_address_long;
netdev_802154_raw_packet_cb_t at86rf231_raw_packet_cb;
netdev_rcv_data_cb_t at86rf231_data_packet_cb;
/* default source address length for sending in number of byte */
static size_t _default_src_addr_len = 2;
uint8_t driver_state;
void at86rf231_gpio_spi_interrupts_init(void);
void at86rf231_reset(void);
#ifdef MODULE_TRANSCEIVER
void at86rf231_init(kernel_pid_t tpid)
{
transceiver_pid = tpid;
at86rf231_initialize(NULL);
}
#endif
int at86rf231_initialize(netdev_t *dev)
{
at86rf231_gpio_spi_interrupts_init();
at86rf231_reset();
at86rf231_on();
/* TODO :
* and configure security, power
*/
#ifdef MODULE_CONFIG
at86rf231_set_pan(sysconfig.radio_pan_id);
#else
at86rf231_set_pan(0x0001);
#endif
radio_channel = at86rf231_reg_read(AT86RF231_REG__PHY_CC_CCA) & AT86RF231_PHY_CC_CCA_MASK__CHANNEL;
radio_address = 0x00FF & (uint16_t)at86rf231_reg_read(AT86RF231_REG__SHORT_ADDR_0);
radio_address |= at86rf231_reg_read(AT86RF231_REG__SHORT_ADDR_1) << 8;
radio_address_long = 0x00000000000000FF & (uint64_t)at86rf231_reg_read(AT86RF231_REG__IEEE_ADDR_0);
radio_address_long |= ((uint64_t)at86rf231_reg_read(AT86RF231_REG__IEEE_ADDR_1)) << 8;
radio_address_long |= ((uint64_t)at86rf231_reg_read(AT86RF231_REG__IEEE_ADDR_1)) << 16;
radio_address_long |= ((uint64_t)at86rf231_reg_read(AT86RF231_REG__IEEE_ADDR_1)) << 24;
radio_address_long |= ((uint64_t)at86rf231_reg_read(AT86RF231_REG__IEEE_ADDR_1)) << 32;
radio_address_long |= ((uint64_t)at86rf231_reg_read(AT86RF231_REG__IEEE_ADDR_1)) << 40;
radio_address_long |= ((uint64_t)at86rf231_reg_read(AT86RF231_REG__IEEE_ADDR_1)) << 48;
radio_address_long |= ((uint64_t)at86rf231_reg_read(AT86RF231_REG__IEEE_ADDR_1)) << 56;
return 0;
}
int at86rf231_on(void)
{
/* Send a FORCE TRX OFF command */
at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__FORCE_TRX_OFF);
/* busy wait for TRX_OFF state */
int delay = _MAX_RETRIES;
do {
if (!--delay) {
DEBUG("at86rf231 : ERROR : could not enter TRX_OFF mode\n");
return 0;
}
} while (at86rf231_get_status() != AT86RF231_TRX_STATUS__TRX_OFF);
at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__RX_ON);
/* change into basic reception mode to initialise CSMA seed by RNG */
delay = _MAX_RETRIES;
do {
if (!--delay) {
DEBUG("at86rf231 : ERROR : could not enter RX_ON mode\n");
return 0;
}
} while (at86rf231_get_status() != AT86RF231_TRX_STATUS__RX_ON);
/* read RNG values into CSMA_SEED_0 */
for (int i=0; i<7; i+=2) {
uint8_t tmp = at86rf231_reg_read(AT86RF231_REG__PHY_CC_CCA);
tmp = ((tmp&0x60)>>5);
at86rf231_reg_write(AT86RF231_REG__CSMA_SEED_0, tmp << i);
}
/* read CSMA_SEED_1 and write back with RNG value */
uint8_t tmp = at86rf231_reg_read(AT86RF231_REG__CSMA_SEED_1);
tmp |= ((at86rf231_reg_read(AT86RF231_REG__PHY_CC_CCA)&0x60)>>5);
at86rf231_reg_write(AT86RF231_REG__CSMA_SEED_1, tmp);
/* change into reception mode */
at86rf231_switch_to_rx();
return 1;
}
void at86rf231_off(void)
{
/* TODO */
}
int at86rf231_is_on(void)
{
return ((at86rf231_get_status() & 0x1f) != 0);
}
void at86rf231_switch_to_rx(void)
{
gpio_irq_disable(AT86RF231_INT);
/* now change to PLL_ON state for extended operating mode */
at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__PLL_ON);
do {
int max_wait = _MAX_RETRIES;
if (!--max_wait) {
DEBUG("at86rf231 : ERROR : could not enter PLL_ON mode\n");
break;
}
} while (at86rf231_get_status() != AT86RF231_TRX_STATUS__PLL_ON);
#ifndef MODULE_OPENWSN
/* Reset IRQ to TRX END only */
at86rf231_reg_write(AT86RF231_REG__IRQ_MASK, AT86RF231_IRQ_STATUS_MASK__TRX_END);
#else
/* OpenWSN also needs RX_START IRQ */
at86rf231_reg_write(AT86RF231_REG__IRQ_MASK, ( AT86RF231_IRQ_STATUS_MASK__RX_START | AT86RF231_IRQ_STATUS_MASK__TRX_END));
#endif
/* Read IRQ to clear it */
at86rf231_reg_read(AT86RF231_REG__IRQ_STATUS);
/* Enable IRQ interrupt */
gpio_irq_enable(AT86RF231_INT);
/* Enter RX_AACK_ON state */
at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__RX_AACK_ON);
do {
int max_wait = _MAX_RETRIES;
if (!--max_wait) {
DEBUG("at86rf231 : ERROR : could not enter RX_AACK_ON mode\n");
break;
}
} while (at86rf231_get_status() != AT86RF231_TRX_STATUS__RX_AACK_ON);
}
void at86rf231_rxoverflow_irq(void)
{
/* TODO */
}
#ifndef MODULE_OPENWSN
void at86rf231_rx_irq(void)
{
/* check if we are in sending state */
if (driver_state == AT_DRIVER_STATE_SENDING) {
/* Read IRQ to clear it */
at86rf231_reg_read(AT86RF231_REG__IRQ_STATUS);
/* tx done, listen again */
at86rf231_switch_to_rx();
/* clear internal state */
driver_state = AT_DRIVER_STATE_DEFAULT;
}
else {
/* handle receive */
at86rf231_rx_handler();
}
}
#endif
int at86rf231_add_raw_recv_callback(netdev_t *dev,
netdev_802154_raw_packet_cb_t recv_cb)
{
(void)dev;
if (at86rf231_raw_packet_cb == NULL){
at86rf231_raw_packet_cb = recv_cb;
return 0;
}
return -ENOBUFS;
}
int at86rf231_rem_raw_recv_callback(netdev_t *dev,
netdev_802154_raw_packet_cb_t recv_cb)
{
(void)dev;
at86rf231_raw_packet_cb = NULL;
return 0;
}
int at86rf231_add_data_recv_callback(netdev_t *dev,
netdev_rcv_data_cb_t recv_cb)
{
(void)dev;
if (at86rf231_data_packet_cb == NULL){
at86rf231_data_packet_cb = recv_cb;
return 0;
}
return -ENOBUFS;
}
int at86rf231_rem_data_recv_callback(netdev_t *dev,
netdev_rcv_data_cb_t recv_cb)
{
(void)dev;
at86rf231_data_packet_cb = NULL;
return 0;
}
radio_address_t at86rf231_set_address(radio_address_t address)
{
radio_address = address;
uint8_t old_state = at86rf231_get_status() & AT86RF231_TRX_STATUS_MASK__TRX_STATUS;
/* Go to state PLL_ON */
at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__PLL_ON);
/* wait until it is on PLL_ON state */
do {
int max_wait = _MAX_RETRIES;
if (!--max_wait) {
DEBUG("at86rf231 : ERROR : could not enter PLL_ON mode\n");
break;
}
} while ((at86rf231_get_status() & AT86RF231_TRX_STATUS_MASK__TRX_STATUS)
!= AT86RF231_TRX_STATUS__PLL_ON);
at86rf231_reg_write(AT86RF231_REG__SHORT_ADDR_0, (uint8_t)(0x00FF & radio_address));
at86rf231_reg_write(AT86RF231_REG__SHORT_ADDR_1, (uint8_t)(radio_address >> 8));
/* Go to state old state */
at86rf231_reg_write(AT86RF231_REG__TRX_STATE, old_state);
/* wait until it is on old state */
do {
int max_wait = _MAX_RETRIES;
if (!--max_wait) {
DEBUG("at86rf231 : ERROR : could not enter old state %x\n", old_state);
break;
}
} while ((at86rf231_get_status() & AT86RF231_TRX_STATUS_MASK__TRX_STATUS)
!= old_state);
return radio_address;
}
radio_address_t at86rf231_get_address(void)
{
return radio_address;
}
uint64_t at86rf231_set_address_long(uint64_t address)
{
radio_address_long = address;
uint8_t old_state = at86rf231_get_status() & AT86RF231_TRX_STATUS_MASK__TRX_STATUS;
/* Go to state PLL_ON */
at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__PLL_ON);
/* wait until it is on PLL_ON state */
do {
int max_wait = _MAX_RETRIES;
if (!--max_wait) {
DEBUG("at86rf231 : ERROR : could not enter PLL_ON mode\n");
break;
}
} while ((at86rf231_get_status() & AT86RF231_TRX_STATUS_MASK__TRX_STATUS)
!= AT86RF231_TRX_STATUS__PLL_ON);
at86rf231_reg_write(AT86RF231_REG__IEEE_ADDR_0, (uint8_t)(radio_address_long));
at86rf231_reg_write(AT86RF231_REG__IEEE_ADDR_1, (uint8_t)(radio_address_long >> 8));
at86rf231_reg_write(AT86RF231_REG__IEEE_ADDR_2, (uint8_t)(radio_address_long >> 16));
at86rf231_reg_write(AT86RF231_REG__IEEE_ADDR_3, (uint8_t)(radio_address_long >> 24));
at86rf231_reg_write(AT86RF231_REG__IEEE_ADDR_4, (uint8_t)(radio_address_long >> 32));
at86rf231_reg_write(AT86RF231_REG__IEEE_ADDR_5, (uint8_t)(radio_address_long >> 40));
at86rf231_reg_write(AT86RF231_REG__IEEE_ADDR_6, (uint8_t)(radio_address_long >> 48));
at86rf231_reg_write(AT86RF231_REG__IEEE_ADDR_7, (uint8_t)(radio_address_long >> 56));
/* Go to state old state */
at86rf231_reg_write(AT86RF231_REG__TRX_STATE, old_state);
/* wait until it is on old state */
do {
int max_wait = _MAX_RETRIES;
if (!--max_wait) {
DEBUG("at86rf231 : ERROR : could not enter old state %x\n", old_state);
break;
}
} while ((at86rf231_get_status() & AT86RF231_TRX_STATUS_MASK__TRX_STATUS)
!= old_state);
return radio_address_long;
}
uint64_t at86rf231_get_address_long(void)
{
return radio_address_long;
}
uint16_t at86rf231_set_pan(uint16_t pan)
{
radio_pan = pan;
at86rf231_reg_write(AT86RF231_REG__PAN_ID_0, (uint8_t)(0x00FF & radio_pan));
at86rf231_reg_write(AT86RF231_REG__PAN_ID_1, (uint8_t)(radio_pan >> 8));
return radio_pan;
}
uint16_t at86rf231_get_pan(void)
{
return radio_pan;
}
int at86rf231_set_channel(unsigned int channel)
{
radio_channel = channel;
if (channel < AT86RF231_MIN_CHANNEL ||
channel > AT86RF231_MAX_CHANNEL) {
#if DEVELHELP
puts("[at86rf231] channel out of range!");
#endif
return -1;
}
at86rf231_reg_write(AT86RF231_REG__PHY_CC_CCA, (radio_channel & AT86RF231_PHY_CC_CCA_MASK__CHANNEL));
return radio_channel;
}
unsigned int at86rf231_get_channel(void)
{
return radio_channel;
}
void at86rf231_set_monitor(int mode)
{
/* read register */
uint8_t tmp = at86rf231_reg_read(AT86RF231_REG__XAH_CTRL_1);
/* set promicuous mode depending on *mode* */
if (mode) {
at86rf231_reg_write(AT86RF231_REG__XAH_CTRL_1, (tmp|AT86RF231_XAH_CTRL_1__AACK_PROM_MODE));
}
else {
at86rf231_reg_write(AT86RF231_REG__XAH_CTRL_1, (tmp&(~AT86RF231_XAH_CTRL_1__AACK_PROM_MODE)));
}
}
int at86rf231_get_monitor(void)
{
return (at86rf231_reg_read(AT86RF231_REG__XAH_CTRL_1) & AT86RF231_XAH_CTRL_1__AACK_PROM_MODE);
}
void at86rf231_gpio_spi_interrupts_init(void)
{
/* SPI init */
spi_acquire(AT86RF231_SPI);
spi_init_master(AT86RF231_SPI, SPI_CONF_FIRST_RISING, SPI_SPEED);
spi_release(AT86RF231_SPI);
/* IRQ0 */
gpio_init_int(AT86RF231_INT, GPIO_NOPULL, GPIO_RISING, (gpio_cb_t)at86rf231_rx_irq, NULL);
/* CS */
gpio_init_out(AT86RF231_CS, GPIO_NOPULL);
/* SLEEP */
gpio_init_out(AT86RF231_SLEEP, GPIO_NOPULL);
/* RESET */
gpio_init_out(AT86RF231_RESET, GPIO_NOPULL);
}
void at86rf231_reset(void)
{
/* force reset */
gpio_clear(AT86RF231_RESET);
/* put pins to default values */
gpio_set(AT86RF231_CS);
gpio_clear(AT86RF231_SLEEP);
/* additional waiting to comply to min rst pulse width */
uint8_t volatile delay = 50; /* volatile to ensure it isn't optimized away */
while (--delay);
gpio_set(AT86RF231_RESET);
}
int at86rf231_get_option(netdev_t *dev, netdev_opt_t opt, void *value,
size_t *value_len)
{
/* XXX: first check only for backwards compatibility with transceiver
* (see at86rf231_init) remove when adapter for transceiver exists */
if (dev != &at86rf231_netdev) {
return -ENODEV;
}
switch (opt) {
case NETDEV_OPT_CHANNEL:
if (*value_len < sizeof(unsigned int)) {
return -EOVERFLOW;
}
if (*value_len > sizeof(unsigned int)) {
*value_len = sizeof(unsigned int);
}
*((unsigned int *)value) = at86rf231_get_channel();
break;
case NETDEV_OPT_ADDRESS:
if (*value_len < sizeof(uint16_t)) {
return -EOVERFLOW;
}
if (*value_len > sizeof(uint16_t)) {
*value_len = sizeof(uint16_t);
}
*((uint16_t *)value) = at86rf231_get_address();
break;
case NETDEV_OPT_NID:
if (*value_len < sizeof(uint16_t)) {
return -EOVERFLOW;
}
if (*value_len > sizeof(uint16_t)) {
*value_len = sizeof(uint16_t);
}
*((uint16_t *)value) = at86rf231_get_pan();
break;
case NETDEV_OPT_ADDRESS_LONG:
if (*value_len < sizeof(uint64_t)) {
return -EOVERFLOW;
}
if (*value_len > sizeof(uint64_t)) {
*value_len = sizeof(uint64_t);
}
*((uint64_t *)value) = at86rf231_get_address_long();
break;
case NETDEV_OPT_MAX_PACKET_SIZE:
if (*value_len == 0) {
return -EOVERFLOW;
}
if (*value_len > sizeof(uint8_t)) {
*value_len = sizeof(uint8_t);
}
*((uint8_t *)value) = AT86RF231_MAX_PKT_LENGTH;
break;
case NETDEV_OPT_PROTO:
if (*value_len < sizeof(netdev_proto_t)) {
return -EOVERFLOW;
}
if (*value_len > sizeof(netdev_proto_t)) {
*value_len = sizeof(netdev_proto_t);
}
*((netdev_type_t *)value) = NETDEV_PROTO_802154;
break;
case NETDEV_OPT_SRC_LEN:
if (*value_len < sizeof(size_t)) {
return -EOVERFLOW;
}
if (*value_len > sizeof(size_t)) {
*value_len = sizeof(size_t);
}
*((size_t *)value) = _default_src_addr_len;
default:
return -ENOTSUP;
}
return 0;
}
static int _type_pun_up_unsigned(void *value_out, size_t desired_len,
void *value_in, size_t given_len)
{
if (given_len > desired_len) {
return -EOVERFLOW;
}
/* XXX this is ugly, but bear with me */
switch (given_len) {
case 8:
switch (desired_len) {
case 8:
*((uint64_t *)value_out) = (*((uint64_t *)value_in));
return 0;
default:
return -EINVAL;
}
case 4:
switch (desired_len) {
case 8:
*((uint64_t *)value_out) = (uint64_t)(*((uint32_t *)value_in));
return 0;
case 4:
*((uint32_t *)value_out) = (*((uint32_t *)value_in));
return 0;
default:
return -EINVAL;
}
case 2:
switch (desired_len) {
case 8:
*((uint64_t *)value_out) = (uint64_t)(*((uint16_t *)value_in));
return 0;
case 4:
*((uint32_t *)value_out) = (uint32_t)(*((uint16_t *)value_in));
return 0;
case 2:
*((uint16_t *)value_out) = (*((uint16_t *)value_in));
return 0;
default:
return -EINVAL;
}
case 1:
switch (desired_len) {
case 8:
*((uint64_t *)value_out) = (uint64_t)(*((uint8_t *)value_in));
return 0;
case 4:
*((uint32_t *)value_out) = (uint32_t)(*((uint8_t *)value_in));
return 0;
case 2:
*((uint16_t *)value_out) = (uint16_t)(*((uint8_t *)value_in));
return 0;
case 1:
*((uint8_t *)value_out) = (*((uint8_t *)value_in));
return 0;
default:
return -EINVAL;
}
default:
return -EINVAL;
}
}
int at86rf231_set_option(netdev_t *dev, netdev_opt_t opt, void *value,
size_t value_len)
{
uint8_t set_value[sizeof(uint64_t)];
int res = 0;
/* XXX: first check only for backwards compatibility with transceiver
* (see at86rf231_init) remove when adapter for transceiver exists */
if (dev != &at86rf231_netdev) {
return -ENODEV;
}
switch (opt) {
case NETDEV_OPT_CHANNEL:
if ((res = _type_pun_up_unsigned(set_value, sizeof(unsigned int),
value, value_len)) == 0) {
unsigned int *v = (unsigned int *)set_value;
if (*v > 26) {
return -EINVAL;
}
at86rf231_set_channel(*v);
}
break;
case NETDEV_OPT_ADDRESS:
if ((res = _type_pun_up_unsigned(set_value, sizeof(uint16_t),
value, value_len)) == 0) {
uint16_t *v = (uint16_t *)set_value;
if (*v == 0xffff) {
/* Do not allow setting to broadcast */
return -EINVAL;
}
at86rf231_set_address(*v);
}
break;
case NETDEV_OPT_NID:
if ((res = _type_pun_up_unsigned(set_value, sizeof(uint16_t),
value, value_len)) == 0) {
uint16_t *v = (uint16_t *)set_value;
if (*v == 0xffff) {
/* Do not allow setting to broadcast */
return -EINVAL;
}
at86rf231_set_pan(*v);
}
break;
case NETDEV_OPT_ADDRESS_LONG:
if ((res = _type_pun_up_unsigned(set_value, sizeof(uint64_t),
value, value_len)) == 0) {
uint64_t *v = (uint64_t *)set_value;
/* TODO: error checking? */
at86rf231_set_address_long(*v);
}
break;
case NETDEV_OPT_SRC_LEN:
if ((res = _type_pun_up_unsigned(set_value, sizeof(size_t),
value, value_len)) == 0) {
size_t *v = (size_t *)set_value;
if (*v != 2 && *v != 8) {
return -EINVAL;
}
_default_src_addr_len = *v;
}
break;
default:
return -ENOTSUP;
}
return res;
}
int at86rf231_get_state(netdev_t *dev, netdev_state_t *state)
{
/* XXX: first check only for backwards compatibility with transceiver
* (see at86rf231_init) remove when adapter for transceiver exists */
if (dev != &at86rf231_netdev) {
return -ENODEV;
}
if (!at86rf231_is_on()) {
*state = NETDEV_STATE_POWER_OFF;
}
else if (at86rf231_get_monitor()) {
*state = NETDEV_STATE_PROMISCUOUS_MODE;
}
else {
*state = NETDEV_STATE_RX_MODE;
}
return 0;
}
int at86rf231_set_state(netdev_t *dev, netdev_state_t state)
{
/* XXX: first check only for backwards compatibility with transceiver
* (see at86rf231_init) remove when adapter for transceiver exists */
if (dev != &at86rf231_netdev) {
return -ENODEV;
}
if (state != NETDEV_STATE_PROMISCUOUS_MODE && at86rf231_get_monitor()) {
at86rf231_set_monitor(0);
}
switch (state) {
case NETDEV_STATE_POWER_OFF:
at86rf231_off();
break;
case NETDEV_STATE_RX_MODE:
at86rf231_switch_to_rx();
break;
case NETDEV_STATE_PROMISCUOUS_MODE:
at86rf231_set_monitor(1);
break;
default:
return -ENOTSUP;
}
return 0;
}
int at86rf231_channel_is_clear(netdev_t *dev)
{
(void)dev;
/* channel is checked by hardware automatically before transmission */
return 1;
}
void at86rf231_event(netdev_t *dev, uint32_t event_type)
{
(void)dev;
(void)event_type;
}
const netdev_802154_driver_t at86rf231_driver = {
.init = at86rf231_initialize,
.send_data = netdev_802154_send_data,
.add_receive_data_callback = at86rf231_add_data_recv_callback,
.rem_receive_data_callback = at86rf231_rem_data_recv_callback,
.get_option = at86rf231_get_option,
.set_option = at86rf231_set_option,
.get_state = at86rf231_get_state,
.set_state = at86rf231_set_state,
.event = at86rf231_event,
.load_tx = at86rf231_load_tx_buf,
.transmit = at86rf231_transmit_tx_buf,
.send = netdev_802154_send,
.add_receive_raw_callback = at86rf231_add_raw_recv_callback,
.rem_receive_raw_callback = at86rf231_rem_raw_recv_callback,
.channel_is_clear = at86rf231_channel_is_clear,
};
netdev_t at86rf231_netdev = { NETDEV_TYPE_802154, (netdev_driver_t *) &at86rf231_driver, NULL };