Browse Source

drivers/at86rf231: refactoring of the at86rf231 radio driver

* deploy extended operation mode
* cleanup
* implement netdev 802154.h interface
dev/timer
Thomas Eichinger 8 years ago
parent
commit
dfb1b56fad
  1. 7
      Makefile.dep
  2. 4
      boards/iot-lab_M3/Makefile.dep
  3. 3
      drivers/Makefile
  4. 526
      drivers/at86rf231/at86rf231.c
  5. 30
      drivers/at86rf231/at86rf231_rx.c
  6. 4
      drivers/at86rf231/at86rf231_spi.c
  7. 224
      drivers/at86rf231/at86rf231_tx.c
  8. 364
      drivers/include/at86rf231.h
  9. 27
      drivers/include/at86rf231/at86rf231_settings.h
  10. 429
      drivers/include/netdev/802154.h
  11. 6
      drivers/include/netdev/base.h
  12. 7
      drivers/include/netdev/default.h
  13. 119
      drivers/netdev/802154/802154.c
  14. 5
      drivers/netdev/802154/Makefile
  15. 2
      drivers/netdev/base/base.c
  16. 3
      sys/config/config.c
  17. 1
      sys/include/config.h
  18. 11
      sys/shell/commands/sc_transceiver.c

7
Makefile.dep

@ -76,9 +76,8 @@ ifneq (,$(filter cc2420,$(USEMODULE)))
endif
ifneq (,$(filter at86rf231,$(USEMODULE)))
USEMODULE += transceiver
USEMODULE += netdev_802154
USEMODULE += ieee802154
USEMODULE += vtimer
endif
ifneq (,$(filter vtimer,$(USEMODULE)))
@ -95,6 +94,10 @@ ifneq (,$(filter ccn_lite,$(USEMODULE)))
USEMODULE += crypto
endif
ifneq (,$(filter netdev_802154,$(USEMODULE)))
USEMODULE += netdev_base
endif
ifneq (,$(filter rgbled,$(USEMODULE)))
USEMODULE += color
endif

4
boards/iot-lab_M3/Makefile.dep

@ -1,4 +1,6 @@
ifneq (,$(filter defaulttransceiver,$(USEMODULE)))
USEMODULE += at86rf231
USEMODULE += transceiver
ifeq (,$(filter netdev_base,$(USEMODULE)))
USEMODULE += transceiver
endif
endif

3
drivers/Makefile

@ -52,5 +52,8 @@ endif
ifneq (,$(filter lps331ap,$(USEMODULE)))
DIRS += lps331ap
endif
ifneq (,$(filter netdev_802154,$(USEMODULE)))
DIRS += netdev/802154
endif
include $(RIOTBASE)/Makefile.base

526
drivers/at86rf231/at86rf231.c

@ -31,32 +31,48 @@
#define ENABLE_DEBUG (0)
#include "debug.h"
#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;
uint8_t at86rf231_get_status(void);
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();
// TODO : Enable addr decode, auto ack, auto crc
// and configure security, power, channel, pan
at86rf231_on();
radio_pan = 0;
radio_pan = 0x00FF & (uint16_t)at86rf231_reg_read(AT86RF231_REG__PAN_ID_0);
radio_pan |= (uint16_t)at86rf231_reg_read(AT86RF231_REG__PAN_ID_1) << 8;
/* 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;
@ -72,49 +88,104 @@ void at86rf231_init(kernel_pid_t tpid)
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 */
do {
int delay = _MAX_RETRIES;
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 */
do {
int delay = _MAX_RETRIES;
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);
// Send a FORCE TRX OFF command
at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__FORCE_TRX_OFF);
/* 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);
// Reset IRQ to TRX END only
/* Reset IRQ to TRX END only */
at86rf231_reg_write(AT86RF231_REG__IRQ_MASK, AT86RF231_IRQ_STATUS_MASK__TRX_END);
// Read IRQ to clear it
/* Read IRQ to clear it */
at86rf231_reg_read(AT86RF231_REG__IRQ_STATUS);
// Enable IRQ interrupt
/* Enable IRQ interrupt */
gpio_irq_enable(AT86RF231_INT);
// Start RX
at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__RX_ON);
// wait until it is on RX_ON state
uint8_t status;
uint8_t max_wait = 100; // TODO : move elsewhere, this is in 10us
/* Enter RX_AACK_ON state */
at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__RX_AACK_ON);
do {
status = at86rf231_get_status();
hwtimer_wait(HWTIMER_TICKS(10));
int max_wait = _MAX_RETRIES;
if (!--max_wait) {
printf("at86rf231 : ERROR : could not enter RX_ON mode\n");
DEBUG("at86rf231 : ERROR : could not enter RX_AACK_ON mode\n");
break;
}
}
while ((status & AT86RF231_TRX_STATUS_MASK__TRX_STATUS) != AT86RF231_TRX_STATUS__RX_ON);
} while (at86rf231_get_status() != AT86RF231_TRX_STATUS__RX_AACK_ON);
}
void at86rf231_rx_irq(void *arg)
void at86rf231_rxoverflow_irq(void)
{
(void)arg;
/* TODO */
}
void at86rf231_rx_irq(void)
{
/* check if we are in sending state */
if (driver_state == AT_DRIVER_STATE_SENDING) {
/* Read IRQ to clear it */
@ -123,7 +194,6 @@ void at86rf231_rx_irq(void *arg)
at86rf231_switch_to_rx();
/* clear internal state */
driver_state = AT_DRIVER_STATE_DEFAULT;
return;
}
else {
/* handle receive */
@ -131,6 +201,51 @@ void at86rf231_rx_irq(void *arg)
}
}
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;
@ -182,34 +297,44 @@ uint16_t at86rf231_get_pan(void)
return radio_pan;
}
int8_t at86rf231_set_channel(uint8_t channel)
int at86rf231_set_channel(unsigned int channel)
{
uint8_t cca_state;
radio_channel = channel;
if (channel < RF86RF231_MIN_CHANNEL ||
channel > RF86RF231_MAX_CHANNEL) {
if (channel < AT86RF231_MIN_CHANNEL ||
channel > AT86RF231_MAX_CHANNEL) {
#if DEVELHELP
puts("[at86rf231] channel out of range!");
#endif
return -1;
}
cca_state = at86rf231_reg_read(AT86RF231_REG__PHY_CC_CCA) & ~AT86RF231_PHY_CC_CCA_MASK__CHANNEL;
at86rf231_reg_write(AT86RF231_REG__PHY_CC_CCA, cca_state | (radio_channel & AT86RF231_PHY_CC_CCA_MASK__CHANNEL));
at86rf231_reg_write(AT86RF231_REG__PHY_CC_CCA, (radio_channel & AT86RF231_PHY_CC_CCA_MASK__CHANNEL));
return radio_channel;
}
uint8_t at86rf231_get_channel(void)
unsigned int at86rf231_get_channel(void)
{
return radio_channel;
}
void at86rf231_set_monitor(uint8_t mode)
void at86rf231_set_monitor(int mode)
{
(void) mode;
// TODO
/* 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)
@ -217,7 +342,7 @@ void at86rf231_gpio_spi_interrupts_init(void)
/* SPI init */
spi_init_master(AT86RF231_SPI, SPI_CONF_FIRST_RISING, SPI_SPEED_5MHZ);
/* IRQ0 */
gpio_init_int(AT86RF231_INT, GPIO_NOPULL, GPIO_RISING, at86rf231_rx_irq, NULL);
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 */
@ -240,21 +365,320 @@ void at86rf231_reset(void)
while (delay--){}
gpio_set(AT86RF231_RESET);
}
/* Send a FORCE TRX OFF command */
at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__FORCE_TRX_OFF);
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;
}
/* busy wait for TRX_OFF state */
uint8_t status;
uint8_t max_wait = 100;
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;
do {
status = at86rf231_get_status();
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;
if (!--max_wait) {
printf("at86rf231 : ERROR : could not enter TRX_OFF mode\n");
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;
}
} while ((status & AT86RF231_TRX_STATUS_MASK__TRX_STATUS)
!= AT86RF231_TRX_STATUS__TRX_OFF);
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 };

30
drivers/at86rf231/at86rf231_rx.c

@ -35,28 +35,29 @@
at86rf231_packet_t at86rf231_rx_buffer[AT86RF231_RX_BUF_SIZE];
uint8_t buffer[AT86RF231_RX_BUF_SIZE][AT86RF231_MAX_PKT_LENGTH];
volatile uint8_t rx_buffer_next;
extern netdev_802154_raw_packet_cb_t at86rf231_raw_packet_cb;
void at86rf231_rx_handler(void)
{
uint8_t lqi, fcs_rssi;
// read packet length
/* read packet length */
at86rf231_read_fifo(&at86rf231_rx_buffer[rx_buffer_next].length, 1);
// read psdu, read packet with length as first byte and lqi as last byte.
/* read psdu, read packet with length as first byte and lqi as last byte. */
uint8_t *buf = buffer[rx_buffer_next];
at86rf231_read_fifo(buf, at86rf231_rx_buffer[rx_buffer_next].length);
// read lqi which is appended after the psdu
/* read lqi which is appended after the psdu */
lqi = buf[at86rf231_rx_buffer[rx_buffer_next].length - 1];
// read fcs and rssi, from a register
/* read fcs and rssi, from a register */
fcs_rssi = at86rf231_reg_read(AT86RF231_REG__PHY_RSSI);
// build package
/* build package */
at86rf231_rx_buffer[rx_buffer_next].lqi = lqi;
// RSSI has no meaning here, it should be read during packet reception.
/* RSSI has no meaning here, it should be read during packet reception. */
at86rf231_rx_buffer[rx_buffer_next].rssi = fcs_rssi & 0x0F; // bit[4:0]
// bit7, boolean, 1 FCS valid, 0 FCS not valid
/* bit7, boolean, 1 FCS valid, 0 FCS not valid */
at86rf231_rx_buffer[rx_buffer_next].crc = (fcs_rssi >> 7) & 0x01;
if (at86rf231_rx_buffer[rx_buffer_next].crc == 0) {
@ -64,14 +65,21 @@ void at86rf231_rx_handler(void)
return;
}
/* read buffer into ieee802154_frame */
ieee802154_frame_read(&buf[1], &at86rf231_rx_buffer[rx_buffer_next].frame,
at86rf231_rx_buffer[rx_buffer_next].length);
/* if packet is no ACK */
if (at86rf231_rx_buffer[rx_buffer_next].frame.fcf.frame_type != 2) {
#ifdef DEBUG_ENABLED
ieee802154_frame_print_fcf_frame(&at86rf231_rx_buffer[rx_buffer_next].frame);
#endif
if (at86rf231_raw_packet_cb != NULL) {
at86rf231_raw_packet_cb(&at86rf231_netdev, (void*)buf,
at86rf231_rx_buffer[rx_buffer_next].length,
fcs_rssi, lqi, (fcs_rssi >> 7));
}
#ifdef MODULE_TRANSCEIVER
/* notify transceiver thread if any */
if (transceiver_pid != KERNEL_PID_UNDEF) {
msg_t m;
@ -79,19 +87,21 @@ void at86rf231_rx_handler(void)
m.content.value = rx_buffer_next;
msg_send_int(&m, transceiver_pid);
}
#endif
}
else {
/* This should not happen, ACKs are consumed by hardware */
#ifdef DEBUG_ENABLED
DEBUG("GOT ACK for SEQ %u\n", at86rf231_rx_buffer[rx_buffer_next].frame.seq_nr);
ieee802154_frame_print_fcf_frame(&at86rf231_rx_buffer[rx_buffer_next].frame);
#endif
}
// shift to next buffer element
/* shift to next buffer element */
if (++rx_buffer_next == AT86RF231_RX_BUF_SIZE) {
rx_buffer_next = 0;
}
// Read IRQ to clear it
/* Read IRQ to clear it */
at86rf231_reg_read(AT86RF231_REG__IRQ_STATUS);
}

4
drivers/at86rf231/at86rf231_spi.c

@ -72,6 +72,6 @@ void at86rf231_write_fifo(const uint8_t *data, radio_packet_length_t length)
uint8_t at86rf231_get_status(void)
{
return at86rf231_reg_read(AT86RF231_REG__TRX_STATUS)
& AT86RF231_TRX_STATUS_MASK__TRX_STATUS;
return (at86rf231_reg_read(AT86RF231_REG__TRX_STATUS)
& AT86RF231_TRX_STATUS_MASK__TRX_STATUS);
}

224
drivers/at86rf231/at86rf231_tx.c

@ -11,7 +11,7 @@
* @{
*
* @file
* @brief RX related functionality for the AT86RF231 device driver
* @brief TX related functionality for the AT86RF231 device driver
*
* @author Alaeddine Weslati <alaeddine.weslati@inria.fr>
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
@ -26,16 +26,182 @@
#define ENABLE_DEBUG (0)
#include "debug.h"
static void at86rf231_xmit(uint8_t *data, radio_packet_length_t length);
#define _MAX_RETRIES (100)
static int16_t at86rf231_load(at86rf231_packet_t *packet);
static void at86rf231_gen_pkt(uint8_t *buf, at86rf231_packet_t *packet);
static uint8_t sequence_nr;
static uint8_t wait_for_ack;
int16_t at86rf231_send(at86rf231_packet_t *packet)
{
int16_t result;
result = at86rf231_load(packet);
if (result < 0) {
return result;
}
at86rf231_transmit_tx_buf(NULL);
return result;
}
netdev_802154_tx_status_t at86rf231_load_tx_buf(netdev_t *dev,
netdev_802154_pkt_kind_t kind,
netdev_802154_node_addr_t *dest,
int use_long_addr,
int wants_ack,
netdev_hlist_t *upper_layer_hdrs,
void *buf,
unsigned int len)
{
(void)dev;
uint8_t mhr[24];
uint8_t index = 3;
/* frame type */
switch (kind) {
case NETDEV_802154_PKT_KIND_BEACON:
mhr[0] = 0x00;
break;
case NETDEV_802154_PKT_KIND_DATA:
mhr[0] = 0x01;
break;
case NETDEV_802154_PKT_KIND_ACK:
mhr[0] = 0x02;
break;
default:
return NETDEV_802154_TX_STATUS_INVALID_PARAM;
}
if (wants_ack) {
mhr[0] |= 0x20;
}
wait_for_ack = wants_ack;
uint16_t src_pan = at86rf231_get_pan();
uint8_t compress_pan = 0;
if (use_long_addr) {
mhr[1] = 0xcc;
}
else {
mhr[1] = 0x88;
if (dest->pan.id == src_pan) {
compress_pan = 1;
mhr[0] |= 0x40;
}
}
mhr[2] = sequence_nr++;
/* First 3 bytes are fixed with FCS and SEQ, resume with index=3 */
if (use_long_addr) {
mhr[index++] = (uint8_t)(dest->long_addr & 0xFF);
mhr[index++] = (uint8_t)(dest->long_addr >> 8);
mhr[index++] = (uint8_t)(dest->long_addr >> 16);
mhr[index++] = (uint8_t)(dest->long_addr >> 24);
mhr[index++] = (uint8_t)(dest->long_addr >> 32);
mhr[index++] = (uint8_t)(dest->long_addr >> 40);
mhr[index++] = (uint8_t)(dest->long_addr >> 48);
mhr[index++] = (uint8_t)(dest->long_addr >> 56);
uint64_t src_long_addr = at86rf231_get_address_long();
mhr[index++] = (uint8_t)(src_long_addr & 0xFF);
mhr[index++] = (uint8_t)(src_long_addr >> 8);
mhr[index++] = (uint8_t)(src_long_addr >> 16);
mhr[index++] = (uint8_t)(src_long_addr >> 24);
mhr[index++] = (uint8_t)(src_long_addr >> 32);
mhr[index++] = (uint8_t)(src_long_addr >> 40);
mhr[index++] = (uint8_t)(src_long_addr >> 48);
mhr[index++] = (uint8_t)(src_long_addr >> 56);
}
else {
mhr[index++] = (uint8_t)(dest->pan.id & 0xFF);
mhr[index++] = (uint8_t)(dest->pan.id >> 8);
mhr[index++] = (uint8_t)(dest->pan.addr & 0xFF);
mhr[index++] = (uint8_t)(dest->pan.addr >> 8);
if (!compress_pan) {
mhr[index++] = (uint8_t)(src_pan & 0xFF);
mhr[index++] = (uint8_t)(src_pan >> 8);
}
uint16_t src_addr = at86rf231_get_address();
mhr[index++] = (uint8_t)(src_addr & 0xFF);
mhr[index++] = (uint8_t)(src_addr >> 8);
}
/* total frame size:
* index -> MAC header
* len -> payload length
* 2 -> CRC bytes
* + lengths of upper layers' headers */
size_t size = index + len + 2 + netdev_get_hlist_len(upper_layer_hdrs);
if (size > AT86RF231_MAX_PKT_LENGTH) {
return NETDEV_802154_TX_STATUS_PACKET_TOO_LONG;
}
uint8_t size_byte = (uint8_t)size;
netdev_hlist_t *ptr = upper_layer_hdrs;
at86rf231_write_fifo(&size_byte, 1);
at86rf231_write_fifo(mhr, (radio_packet_length_t)index);
if (upper_layer_hdrs) {
do {
at86rf231_write_fifo(ptr->header,
(radio_packet_length_t)(ptr->header_len));
netdev_hlist_advance(&ptr);
} while (ptr != upper_layer_hdrs);
}
at86rf231_write_fifo((uint8_t*)buf, len);
return NETDEV_802154_TX_STATUS_OK;
}
netdev_802154_tx_status_t at86rf231_transmit_tx_buf(netdev_t *dev)
{
(void)dev;
/* radio driver state: sending */
/* will be freed in at86rf231_rx_irq when TRX_END interrupt occurs */
driver_state = AT_DRIVER_STATE_SENDING;
/* Start TX */
at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__TX_START);
DEBUG("Started TX\n");
if (!wait_for_ack) {
return NETDEV_802154_TX_STATUS_OK;
}
uint8_t trac_status;
do {
trac_status = at86rf231_reg_read(AT86RF231_REG__TRX_STATE);
trac_status &= AT86RF231_TRX_STATE_MASK__TRAC;
}
while (trac_status == AT86RF231_TRX_STATE__TRAC_INVALID);
switch (trac_status) {
case AT86RF231_TRX_STATE__TRAC_CHANNEL_ACCESS_FAILURE:
return NETDEV_802154_TX_STATUS_MEDIUM_BUSY;
case AT86RF231_TRX_STATE__TRAC_NO_ACK:
return NETDEV_802154_TX_STATUS_NOACK;
default:
return NETDEV_802154_TX_STATUS_OK;
}
}
int16_t at86rf231_load(at86rf231_packet_t *packet)
{
// Set missing frame information
packet->frame.fcf.frame_ver = 0;
packet->frame.fcf.frame_type = 0x1;
packet->frame.src_pan_id = at86rf231_get_pan();
if (packet->frame.src_pan_id == packet->frame.dest_pan_id) {
packet->frame.fcf.panid_comp = 1;
@ -59,12 +225,9 @@ int16_t at86rf231_send(at86rf231_packet_t *packet)
packet->frame.src_addr[7] = (uint8_t)(at86rf231_get_address_long() & 0xFF);
}
packet->frame.src_pan_id = at86rf231_get_pan();
packet->frame.seq_nr = sequence_nr;
packet->frame.seq_nr = sequence_nr++;
sequence_nr += 1;
// calculate size of the frame (payload + FCS) */
/* calculate size of the frame (payload + FCS) */
packet->length = ieee802154_frame_get_hdr_len(&packet->frame) +
packet->frame.payload_len + 1;
@ -72,54 +235,45 @@ int16_t at86rf231_send(at86rf231_packet_t *packet)
return -1;
}
// FCS is added in hardware
/* FCS is added in hardware */
uint8_t pkt[packet->length];
/* generate pkt */
at86rf231_gen_pkt(pkt, packet);
// transmit packet
at86rf231_xmit(pkt, packet->length);
return packet->length;
}
static void at86rf231_xmit(uint8_t *data, radio_packet_length_t length)
{
// Go to state PLL_ON
/* 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
uint8_t status;
uint8_t max_wait = 100; // TODO : move elsewhere, this is in 10us
/* wait until it is on PLL_ON state */
do {
status = at86rf231_get_status();
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);
hwtimer_wait(HWTIMER_TICKS(10));
/* change into TX_ARET_ON state */
at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__TX_ARET_ON);
do {
int max_wait = _MAX_RETRIES;
if (!--max_wait) {
printf("at86rf231 : ERROR : could not enter PLL_ON mode");
DEBUG("at86rf231 : ERROR : could not enter TX_ARET_ON mode\n");
break;
}
}
while ((status & AT86RF231_TRX_STATUS_MASK__TRX_STATUS) != AT86RF231_TRX_STATUS__PLL_ON);
/* radio driver state: sending */
/* will be freed in at86rf231_rx_irq when TRX_END interrupt occurs */
driver_state = AT_DRIVER_STATE_SENDING;
} while (at86rf231_get_status() != AT86RF231_TRX_STATUS__TX_ARET_ON);
// copy the packet to the radio FIFO
at86rf231_write_fifo(data, length);
/* load packet into fifo */
at86rf231_write_fifo(pkt, packet->length);
DEBUG("Wrote to FIFO\n");
// Start TX
at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__TX_START);
DEBUG("Started TX\n");
return packet->length;
}
/**
* @brief Static function to generate byte array from at86rf231 packet.
*
*/
static void at86rf231_gen_pkt(uint8_t *buf, at86rf231_packet_t *packet)
{

364
drivers/include/at86rf231.h

@ -7,7 +7,7 @@
*/
/**
* @defgroup drivers_at86rf231
* @defgroup drivers_at86rf231 at86rf231
* @ingroup drivers
* @brief Device driver for the Atmel AT86RF231 radio
* @{
@ -31,34 +31,66 @@
#include "ieee802154_frame.h"
#include "at86rf231/at86rf231_settings.h"
#include "periph/gpio.h"
#include "netdev/802154.h"
#ifdef __cplusplus
extern "C" {
#endif
#define AT86RF231_MAX_PKT_LENGTH 127
#define AT86RF231_MAX_DATA_LENGTH 118
/**
* @brief Maximum length of a frame on at86rf231
*/
#define AT86RF231_MAX_PKT_LENGTH (127)
/**
* @brief Maximum payload length
* @details Assuming intra PAN short address mode
* results in 2 bytes FCF
* + 1 bytes SEQNr
* + 2 bytes PAN Id
* + 2 bytes destination address
* + 2 bytes source address
*/
#define AT86RF231_MAX_DATA_LENGTH (118)
/**
* @brief Broadcast address
*/
#define AT86RF231_BROADCAST_ADDRESS (0xFFFF)
/**
* @brief at86rf231's lowest supported channel
*/
#define AT86RF231_MIN_CHANNEL (11)
/**
* Structure to represent a at86rf231 packet.
* @brief at86rf231's highest supported channel
*/
typedef struct __attribute__((packed)) /* TODO: do we need the packed here? it leads to an
unaligned pointer -> trouble for M0 systems... */
#define AT86RF231_MAX_CHANNEL (26)
/**
* @brief Structure to represent a at86rf231 packet.
*/
typedef struct __attribute__((packed))
{
/* @{ */
uint8_t length; /** < the length of the frame of the frame including fcs*/
ieee802154_frame_t frame; /** < the ieee802154 frame */
int8_t rssi; /** < the rssi value */
uint8_t crc; /** < 1 if crc was successfull, 0 otherwise */
uint8_t lqi; /** < the link quality indicator */
/* @} */
}
at86rf231_packet_t;
/** @{ */
uint8_t length; /**< the length of the frame of the frame including fcs*/
ieee802154_frame_t frame; /**< the ieee802154 frame */
int8_t rssi; /**< the rssi value */
uint8_t crc; /**< 1 if crc was successfull, 0 otherwise */
uint8_t lqi; /**< the link quality indicator */
/** @} */
} at86rf231_packet_t;
extern volatile kernel_pid_t transceiver_pid;
extern netdev_t at86rf231_netdev; /**< netdev representation of this driver */
/**
* @brief States to be assigned to `driver_state`
* @{
*/
#define AT_DRIVER_STATE_DEFAULT (0)
#define AT_DRIVER_STATE_SENDING (1)
/** @} */
/**
* @brief To keep state inside of at86rf231 driver
@ -68,38 +100,300 @@ extern volatile kernel_pid_t transceiver_pid;
*/
extern uint8_t driver_state;
/**
* @brief Initialize the at86rf231 transceiver
*/
int at86rf231_initialize(netdev_t *dev);
#ifdef MODULE_TRANSCEIVER
/**
* @brief Init the at86rf231 for use with RIOT's transceiver module.
*
* @param[in] tpid The PID of the transceiver thread.
*/
void at86rf231_init(kernel_pid_t tpid);
/* void at86rf231_reset(void); */
void at86rf231_rx(void);
void at86rf231_rx_handler(void);
void at86rf231_rx_irq(void *arg);
#endif
int16_t at86rf231_send(at86rf231_packet_t *packet);
/**
* @brief Turn at86rf231 on.
*
* @return 1 if the radio was correctly turned on; 0 otherwise.
*/
int at86rf231_on(void);
/**
* @brief Turn at86rf231 off.
*/
void at86rf231_off(void);
/**
* @brief Indicate if the at86rf231 is on.
*
* @return 1 if the radio transceiver is on (active); 0 otherwise.
*/
int at86rf231_is_on(void);
/**
* @brief Switches the at86rf231 into receive mode.
*/
void at86rf231_switch_to_rx(void);
/**
* @brief Turns monitor (promiscuous) mode on or off.
*
* @param[in] mode The desired mode:
* 1 for monitor (promiscuous) mode;
* 0 for normal (auto address-decoding) mode.
*/
void at86rf231_set_monitor(int mode);
/**
* @brief Indicate if the at86rf231 is in monitor (promiscuous) mode.
*
* @return 1 if the transceiver is in monitor (promiscuous) mode;
* 0 if it is in normal (auto address-decoding) mode.
*/
int at86rf231_get_monitor(void);
/**
* @brief Set the channel of the at86rf231.
*
* @param[in] chan The desired channel, valid channels are from 11 to 26.
*
* @return The tuned channel after calling, or -1 on error.
*/
int at86rf231_set_channel(unsigned int chan);
/**
* @brief Get the channel of the at86rf231.
*
* @return The tuned channel.
*/
unsigned int at86rf231_get_channel(void);
int8_t at86rf231_set_channel(uint8_t channel);
uint8_t at86rf231_get_channel(void);
/**
* @brief Sets the short address of the at86rf231.
*
* @param[in] addr The desired address.
*
* @return The set address after calling.
*/
uint16_t at86rf231_set_address(uint16_t addr);
/**
* @brief Gets the current short address of the at86rf231.
*
* @return The current short address.
*/
uint16_t at86rf231_get_address(void);
/**
* @brief Sets the IEEE long address of the at86rf231.
*
* @param[in] addr The desired address.
*
* @return The set address after calling.
*/
uint64_t at86rf231_set_address_long(uint64_t addr);
/**
* @brief Gets the current IEEE long address of the at86rf231.
*
* @return The current IEEE long address.
*/
uint64_t at86rf231_get_address_long(void);
/**
* @brief Sets the pan ID of the at86rf231.
*
* @param[in] pan The desired pan ID.
*
* @return The set pan ID after calling.
*/
uint16_t at86rf231_set_pan(uint16_t pan);
/**
* @brief Gets the current IEEE long address of the at86rf231.
*
* @return The current IEEE long address.
*/
uint16_t at86rf231_get_pan(void);
radio_address_t at86rf231_set_address(radio_address_t address);
radio_address_t at86rf231_get_address(void);
uint64_t at86rf231_get_address_long(void);
uint64_t at86rf231_set_address_long(uint64_t address);
/**
* @brief Sets the output (TX) power of the at86rf231.
*
* @param[in] pow The desired TX (output) power in dBm,
* valid values are -25 to 0; other values
* will be "saturated" into this range.
*
* @return The set TX (output) power after calling.
*/
int at86rf231_set_tx_power(int pow);
void at86rf231_switch_to_rx(void);
/**
* @brief Gets the current output (TX) power of the at86rf231.
*
* @return The current TX (output) power.
*/
int at86rf231_get_tx_power(void);
/**
* @brief Checks if the radio medium is available/clear to send
* ("Clear Channel Assessment" a.k.a. CCA).
*
* @return a 1 value if radio medium is clear (available),
* a 0 value otherwise.
*
*/
int at86rf231_channel_is_clear(netdev_t *dev);
void at86rf231_set_monitor(uint8_t mode);
/**
* @brief Interrupt handler, gets fired when a RX overflow happens.
*
*/
void at86rf231_rxoverflow_irq(void);
/**
* @brief Interrupt handler, gets fired when bytes in the RX FIFO are present.
*
*/
void at86rf231_rx_irq(void);
/**
* @brief Sets the function called back when a packet is received.
* (Low-level mechanism, parallel to the `transceiver` module).
*
* @param[in] dev The network device to operate on. (Currently not used)
* @param[in] recv_cb callback function for 802.15.4 packet arrival
*
* @return 0 on success
* @return -ENODEV if *dev* is not recognized
* @return -ENOBUFS, if maximum number of registable callbacks is exceeded
*/
int at86rf231_add_raw_recv_callback(netdev_t *dev,
netdev_802154_raw_packet_cb_t recv_cb);
enum {
RF86RF231_MAX_TX_LENGTH = 125,
RF86RF231_MAX_RX_LENGTH = 127,
RF86RF231_MIN_CHANNEL = 11,
RF86RF231_MAX_CHANNEL = 26
};
/**
* @brief Unsets the function called back when a packet is received.
* (Low-level mechanism, parallel to the `transceiver` module).
*
* @param[in] dev The network device to operate on. (Currently not used)
* @param[in] recv_cb callback function to unset
*
* @return 0 on success
* @return -ENODEV if *dev* is not recognized
* @return -ENOBUFS, if maximum number of registable callbacks is exceeded
*/
int at86rf231_rem_raw_recv_callback(netdev_t *dev,
netdev_802154_raw_packet_cb_t recv_cb);
/**
* @brief Sets a function called back when a data packet is received.
*
* @param[in] dev The network device to operate on. (Currently not used)
* @param[in] recv_cb callback function for 802.15.4 data packet arrival
*
* @return 0 on success
* @return -ENODEV if *dev* is not recognized
* @return -ENOBUFS, if maximum number of registable callbacks is exceeded
*/
int at86rf231_add_data_recv_callback(netdev_t *dev,
netdev_rcv_data_cb_t recv_cb);
/**
* @brief Unsets a function called back when a data packet is received.
*
* @param[in] dev The network device to operate on. (Currently not used)
* @param[in] recv_cb callback function to unset
*
* @return 0 on success
* @return -ENODEV if *dev* is not recognized
* @return -ENOBUFS, if maximum number of registable callbacks is exceeded
*/
int at86rf231_rem_data_recv_callback(netdev_t *dev,
netdev_rcv_data_cb_t recv_cb);
/**
* @brief RX handler, process data from the RX FIFO.
*
*/
void at86rf231_rx_handler(void);
/**
* @brief Prepare the at86rf231 TX buffer to send with the given packet.
*
<