1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-01-17 05:12:57 +01:00

drivers/at86rf231: refactoring of the at86rf231 radio driver

* deploy extended operation mode
* cleanup
* implement netdev 802154.h interface
This commit is contained in:
Thomas Eichinger 2014-10-20 16:46:53 +02:00
parent 5965220efe
commit dfb1b56fad
18 changed files with 1643 additions and 159 deletions

View File

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

View File

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

View File

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

View File

@ -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);
// Reset IRQ to TRX END only
at86rf231_reg_write(AT86RF231_REG__IRQ_MASK, AT86RF231_IRQ_STATUS_MASK__TRX_END);
// Read IRQ to clear it
at86rf231_reg_read(AT86RF231_REG__IRQ_STATUS);
// 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
/* now change to PLL_ON state for extended operating mode */
at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__PLL_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 PLL_ON mode\n");
break;
}
}
while ((status & AT86RF231_TRX_STATUS_MASK__TRX_STATUS) != AT86RF231_TRX_STATUS__RX_ON);
} while (at86rf231_get_status() != AT86RF231_TRX_STATUS__PLL_ON);
/* Reset IRQ to TRX END only */
at86rf231_reg_write(AT86RF231_REG__IRQ_MASK, AT86RF231_IRQ_STATUS_MASK__TRX_END);
/* 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_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);
/* busy wait for TRX_OFF state */
uint8_t status;
uint8_t max_wait = 100;
do {
status = at86rf231_get_status();
if (!--max_wait) {
printf("at86rf231 : ERROR : could not enter TRX_OFF mode\n");
break;
}
} while ((status & AT86RF231_TRX_STATUS_MASK__TRX_STATUS)
!= AT86RF231_TRX_STATUS__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;
}
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 };

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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();
hwtimer_wait(HWTIMER_TICKS(10));
int max_wait = _MAX_RETRIES;
if (!--max_wait) {
printf("at86rf231 : ERROR : could not enter PLL_ON mode");
DEBUG("at86rf231 : ERROR : could not enter PLL_ON mode\n");
break;
}
}
while ((status & AT86RF231_TRX_STATUS_MASK__TRX_STATUS) != AT86RF231_TRX_STATUS__PLL_ON);
} while ((at86rf231_get_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;
/* change into TX_ARET_ON state */
at86rf231_reg_write(AT86RF231_REG__TRX_STATE, AT86RF231_TRX_STATE__TX_ARET_ON);
// copy the packet to the radio FIFO
at86rf231_write_fifo(data, length);
do {
int max_wait = _MAX_RETRIES;
if (!--max_wait) {
DEBUG("at86rf231 : ERROR : could not enter TX_ARET_ON mode\n");
break;
}
} while (at86rf231_get_status() != AT86RF231_TRX_STATUS__TX_ARET_ON);
/* 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)
{

View File

@ -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)
/**
* Structure to represent a at86rf231 packet.
* @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
*/
typedef struct __attribute__((packed)) /* TODO: do we need the packed here? it leads to an
unaligned pointer -> trouble for M0 systems... */
#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)
/**
* @brief at86rf231's highest supported channel
*/
#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);
int8_t at86rf231_set_channel(uint8_t channel);
uint8_t at86rf231_get_channel(void);
/**
* @brief Turn at86rf231 off.
*/
void at86rf231_off(void);
uint16_t at86rf231_set_pan(uint16_t pan);
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 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);
void at86rf231_set_monitor(uint8_t mode);
/**
* @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);
enum {
RF86RF231_MAX_TX_LENGTH = 125,
RF86RF231_MAX_RX_LENGTH = 127,
RF86RF231_MIN_CHANNEL = 11,
RF86RF231_MAX_CHANNEL = 26
};
/**
* @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);
/**
* @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);
/**
* @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);
/**
* @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);
/**
* @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);
/**
* @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.
*
* @param[in] dev The network device to operate on. (Currently not used)
* @param[in] kind Kind of packet to transmit.
* @param[in] dest Address of the node to which the packet is sent.
* @param[in] use_long_addr 1 to use the 64-bit address mode
* with *dest* param; 0 to use
* "short" PAN-centric mode.
* @param[in] wants_ack 1 to request an acknowledgement
* from the receiving node for this packet;
* 0 otherwise.
* @param[in] upper_layer_hdrs header data from higher network layers from
* highest to lowest layer. Must be prepended to
* the data stream by the network device. May be
* NULL if there are none.
* @param[in] buf Pointer to the buffer containing the payload
* of the 802.15.4 packet to transmit.
* The frame header (i.e.: FCS, sequence number,
* src and dest PAN and addresses) is inserted
* using values in accord with *kind* parameter
* and transceiver configuration.
* @param[in] len Length (in bytes) of the outgoing packet payload.
*
* @return @ref netdev_802154_tx_status_t
*/
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);
/**
* @brief Transmit the data loaded into the at86rf231 TX buffer.
*
* @param[in] dev The network device to operate on. (Currently not used)
*
* @return @ref netdev_802154_tx_status_t
*/
netdev_802154_tx_status_t at86rf231_transmit_tx_buf(netdev_t *dev);
/**
* @brief Send function, sends a at86rf231_packet_t over the air.
*
* @param[in] *packet The Packet which will be send.
*
* @return The count of bytes which are send or -1 on error
*
*/
int16_t at86rf231_send(at86rf231_packet_t *packet);
/**
* RX Packet Buffer, read from the transceiver, filled by the at86rf231_rx_handler.
*/
extern at86rf231_packet_t at86rf231_rx_buffer[AT86RF231_RX_BUF_SIZE];
/**
* Get at86rf231's status byte
*/
uint8_t at86rf231_get_status(void);
/**
* Get at86rf231's TRAC status byte
*/
uint8_t at86rf231_get_trac_status(void);
/**
* at86rf231 low-level radio driver definition.
*/
extern const netdev_802154_driver_t at86rf231_driver;
#ifdef __cplusplus
}
#endif

View File

@ -158,6 +158,8 @@ enum at86rf231_trx_status {
};
enum at86rf231_trx_state {
AT86RF231_TRX_STATE_MASK__TRAC = 0xe0,
AT86RF231_TRX_STATE__NOP = 0x00,
AT86RF231_TRX_STATE__TX_START = 0x02,
AT86RF231_TRX_STATE__FORCE_TRX_OFF = 0x03,
@ -167,6 +169,13 @@ enum at86rf231_trx_state {
AT86RF231_TRX_STATE__PLL_ON = 0x09,
AT86RF231_TRX_STATE__RX_AACK_ON = 0x16,
AT86RF231_TRX_STATE__TX_ARET_ON = 0x19,
AT86RF231_TRX_STATE__TRAC_SUCCESS = 0x00,
AT86RF231_TRX_STATE__TRAC_SUCCESS_DATA_PENDING = 0x20,
AT86RF231_TRX_STATE__TRAC_SUCCESS_WAIT_FOR_ACK = 0x40,
AT86RF231_TRX_STATE__TRAC_CHANNEL_ACCESS_FAILURE = 0x60,
AT86RF231_TRX_STATE__TRAC_NO_ACK = 0xa0,
AT86RF231_TRX_STATE__TRAC_INVALID = 0xe0,
};
enum at86rf231_phy_cc_cca {
@ -216,7 +225,7 @@ enum at86rf231_xosc_ctrl {
AT86RF231_XOSC_CTRL__XTAL_MODE_EXTERNAL = 0xF0,
};
enum {
enum at86rf231_timing {
AT86RF231_TIMING__VCC_TO_P_ON = 330,
AT86RF231_TIMING__SLEEP_TO_TRX_OFF = 380,
AT86RF231_TIMING__TRX_OFF_TO_PLL_ON = 110,
@ -227,8 +236,20 @@ enum {
AT86RF231_TIMING__RESET_TO_TRX_OFF = 37,
};
enum at86rf231_xah_ctrl_1 {
AT86RF231_XAH_CTRL_1__AACK_FLTR_RES_FT = 0x20,
AT86RF231_XAH_CTRL_1__AACK_UPLD_RES_FT = 0x10,
AT86RF231_XAH_CTRL_1__AACK_ACK_TIME = 0x04,
AT86RF231_XAH_CTRL_1__AACK_PROM_MODE = 0x02,
};
enum at86rf231_csma_seed_1 {
AT86RF231_CSMA_SEED_1__AACK_SET_PD = 0x20,
AT86RF231_CSMA_SEED_1__AACK_DIS_ACK = 0x10,
AT86RF231_CSMA_SEED_1__AACK_I_AM_COORD = 0x08,
};
#ifdef __cplusplus
}
#endif
#endif
#endif /* AT86AT86RF231_SETTINGS_H */

View File

@ -0,0 +1,429 @@
/*
* Copyright (C) 2014 INRIA
*
* 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 netdev_802154 IEEE 802.15.4 interface
* @addtogroup netdev
* @{
* @file netdev/802154.h
* @brief API definitions for 802.15.4 radio transceivers' drivers
* @author Kévin Roussel <Kevin.Roussel@inria.fr>
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*
*/
#ifndef __NETDEV_802154_H_
#define __NETDEV_802154_H_
#include <stdint.h>
#include "netdev/base.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Callback function type for receiving incoming packets
* from 802.15.4 radio transceiver.
*
* @param[in] buf Pointer to the buffer containing the incoming
* 802.15.4 packet's raw data.
* @param[in] len Length (in bytes) of the incoming packet's raw data.
* @param[in] rssi Value of the Receive Signal Strength Indicator (RSSI)
* for the incoming packet.
* @param[in] lqi Value of the Link Quality Indicator (LQI)
* for the incoming packet.
* @param[in] crc_ok 1 if incoming packet's checksum (CRC) is valid;
* 0 otherwise (corrupted packet).
*/
typedef void (* netdev_802154_raw_packet_cb_t)(netdev_t *dev,
void *buf,
size_t len,
int8_t rssi,
uint8_t lqi,
int crc_ok);
/**
* @brief Kind of packet to prepare/configure for transmission.
*
*/
typedef enum {
/** Beacon packet */
NETDEV_802154_PKT_KIND_BEACON,
/** Standard data packet */
NETDEV_802154_PKT_KIND_DATA,
/** Acknowledgement packet */
NETDEV_802154_PKT_KIND_ACK,
/** MAC command */
NETDEV_802154_PKT_KIND_MAC_CMD,
/** invalid packet kind */
NETDEV_802154_PKT_KIND_INVALID = -1
} netdev_802154_pkt_kind_t;
/**
* @brief Return values for packet emission function of 802.15.4 radio driver.
*
*/
typedef enum {
/** Transmission completed successfully */
NETDEV_802154_TX_STATUS_OK,
/** Device not found or not an IEEE 802.15.4 device */
NETDEV_802154_TX_STATUS_NO_DEV,
/** Transmission buffer underflow (forgot to call netdev_802154_driver_t::load_tx()
before netdev_802154_driver_t::transmit() ) */
NETDEV_802154_TX_STATUS_UNDERFLOW,
/** Transmission cannot start because radio medium is already busy */
NETDEV_802154_TX_STATUS_MEDIUM_BUSY,
/** Transmission failed because of collision on radio medium */
NETDEV_802154_TX_STATUS_COLLISION,
/** Wrong parameter given to TX-related functions */
NETDEV_802154_TX_STATUS_INVALID_PARAM,
/** Too much given data to be included in a single packet */
NETDEV_802154_TX_STATUS_PACKET_TOO_LONG,
/** Transmission supposedly failed since no ACK packet
has been received as response */
NETDEV_802154_TX_STATUS_NOACK,
/** Transmission failed because of an unexpected (fatal?) error */
NETDEV_802154_TX_STATUS_ERROR,
} netdev_802154_tx_status_t;
/**
* @brief Definition of an IEEE 802.15.4 node address.
*
* @details The `union` allows to choose between PAN-centric addressing
* ("volatile" 16-bit address and 16-bit PAN ID), or canonical
* IEEE 64-bit ("long") addressing.
*
*/
typedef union {
/** @brief PAN-centric ("short") addressing mode */
struct {
/** @brief Address assigned to the node within its current PAN */
uint16_t addr;
/** @brief ID of the PAN to which the node is currently associated */
uint16_t id;
} pan;
/** @brief 64-bit ("long") addressing mode */
uint64_t long_addr;
} netdev_802154_node_addr_t;
/**
* @brief IEEE 802.15.4 radio driver API definition.
*
* @details This is the set of functions that must be implemented
* by any driver for a 802.15.4 radio transceiver.
*
* @extends netdev_driver_t
*/
typedef struct {
/**
* @see netdev_driver_t::init
*/
int (*init)(netdev_t *dev);
/**
* @details wraps netdev_802154_driver_t::send with
*
* @see netdev_driver_t::send_data
*/
int (*send_data)(netdev_t *dev, void *dest, size_t dest_len,
netdev_hlist_t *upper_layer_hdrs, void *data,
size_t data_len);
/**
* @see netdev_driver_t::add_receive_data_callback
*/
int (*add_receive_data_callback)(netdev_t *dev, netdev_rcv_data_cb_t cb);
/**
* @see netdev_driver_t::rem_receive_data_callback
*/
int (*rem_receive_data_callback)(netdev_t *dev, netdev_rcv_data_cb_t cb);
/**
* @see netdev_driver_t::get_option
*
* @details The options are constrained as follows:
*
* *opt* | type | *value_len*
* --------------------------- | ----------- | -----------
* NETDEV_OPT_CHANNEL | uint8_t | >= 1
* NETDEV_OPT_ADDRESS | uint16_t | >= 2
* NETDEV_OPT_NID | uint16_t | >= 2
* NETDEV_OPT_ADDRESS_LONG | uint64_t | >= 8
* NETDEV_OPT_TX_POWER | int | >= 4
* NETDEV_OPT_MAX_PACKET_SIZE | uint8_t | >= 1
*/
int (*get_option)(netdev_t *dev, netdev_opt_t opt, void *value,
size_t *value_len);
/**
* @see netdev_driver_t::set_option
*
* @details The options are constrained as follows:
*
* *opt* | type | *value_len* | *value*
* --------------------------- | ----------- | ----------- | --------
* NETDEV_OPT_CHANNEL | uint8_t | >= 1 | <= 26
* NETDEV_OPT_ADDRESS | uint16_t | >= 2 |
* NETDEV_OPT_NID | uint16_t | >= 2 |
* NETDEV_OPT_ADDRESS_LONG | uint64_t | >= 8 |
* NETDEV_OPT_TX_POWER | int | >= 4 |
*
* NETDEV_OPT_MAX_PACKET_SIZE can not be set.
*/
int (*set_option)(netdev_t *dev, netdev_opt_t opt, void *value,
size_t value_len);
/**
* @see netdev_driver_t::get_state
*/
int (*get_state)(netdev_t *dev, netdev_state_t *state);
/**
* @see netdev_driver_t::set_state
*/
int (*set_state)(netdev_t *dev, netdev_state_t state);
/**
* @see netdev_driver_t::event
*/
void (*event)(netdev_t *dev, uint32_t event_type);
/**
* @brief Load the transceiver TX buffer with the given
* IEEE 802.15.4 packet.
*
* @param[in] dev the network device
* @param[in] kind Kind of packet to transmit.
* @param[in] dest Address of the node to which the packet is sent.
* @param[in] use_long_addr 1 to use the 64-bit address mode
* with *dest* param; 0 to use
* "short" PAN-centric mode.
* @param[in] wants_ack 1 to request an acknowledgement
* from the receiving node for this packet;
* 0 otherwise.
* @param[in] upper_layer_hdrs header data from higher network layers from
* highest to lowest layer. Must be prepended to
* the data stream by the network device. May be
* NULL if there are none.
* @param[in] buf Pointer to the buffer containing the payload
* of the 802.15.4 packet to transmit.
* The frame header (i.e.: FCS, sequence number,
* src and dest PAN and addresses) is inserted
* using values in accord with *kind* parameter
* and transceiver configuration.
* @param[in] len Length (in bytes) of the outgoing packet payload.
*
* @return The outcome of this packet's transmission.
* @see netdev_802154_tx_status_t
*/
netdev_802154_tx_status_t (* load_tx)(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);
/**
* @brief Transmit the data loaded into the transceiver TX buffer.
*
* @param[in] dev the network device
*
* @return The outcome of this packet's transmission.
* @see netdev_802154_tx_status_t
*/
netdev_802154_tx_status_t (* transmit)(netdev_t *dev);
/**
* @brief Transmit the given IEEE 802.15.4 packet,
* by calling successively functions netdev_802154_driver_t::load_tx()
* and netdev_802154_driver_t::transmit().
*
* @param[in] dev the network device
* @param[in] kind Kind of packet to transmit.
* @param[in] dest Address of the node to which the packet is sent.
* @param[in] use_long_addr 1 to use the 64-bit address mode
* with *dest* param; 0 to use
* "short" PAN-centric mode.
* @param[in] wants_ack 1 to request an acknowledgement
* from the receiving node for this packet;
* 0 otherwise.
* @param[in] upper_layer_hdrs header data from higher network layers from
* highest to lowest layer. Must be prepended to
* the data stream by the network device. May be
* NULL if there are none.
* @param[in] buf Pointer to the buffer containing the payload
* of the 802.15.4 packet to transmit.
* The frame header (i.e.: FCS, sequence number,
* src and dest PAN and addresses) is inserted
* using values in accord with *kind* parameter
* and transceiver configuration.
* @param[in] len Length (in bytes) of the outgoing packet payload.
*
* @return The outcome of this packet's transmission.
* @see netdev_802154_tx_status_t
*/
netdev_802154_tx_status_t (* send)(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);
/**
* @brief Add a function to be called back when the radio transceiver
* has received a incoming packet.
*
* @details This function differentiates from
* netdev_driver_t::add_receive_data_callback() as it expects
* a callback that excepts the raw frame format of IEEE 802.15.4,
* rather than just the source and destination addresses and the
* payload.
*
* @param[in] dev the network device
* @param[in] recv_func the callback function to invoke for each
* packet received by the radio transceiver.
* @see netdev_802153_raw_packet_cb_t
*
* @return 0, on success
* @return -ENOBUFS, if maximum number of registrable callbacks is exceeded
* @return -ENODEV, if *dev* is not recognized
*/
int (* add_receive_raw_callback)(netdev_t *dev, netdev_802154_raw_packet_cb_t recv_func);
/**
* @brief Remove a callback set by netdev_802154_driver_t::add_receive_raw_callback()
*
* @param[in] dev the network device
* @param[in] recv_func the callback function to invoke for each
* packet received by the radio transceiver.
* @see netdev_802153_raw_packet_cb_t
*
* @return 0, on success
* @return -ENODEV, if *dev* is not recognized
*/
int (* rem_receive_raw_callback)(netdev_t *dev, netdev_802154_raw_packet_cb_t recv_func);
/**
* @brief Indicates if the radio medium is available for transmission
* ("Clear Channel Assessment").
*
* @param[in] dev the network device
*
* @return 1 if radio medium is "clear" (available);
* @return 0 if another transmission is already running.
* @return -ENODEV, if *dev* is not recognized
*/
int (* channel_is_clear)(netdev_t *dev);
} netdev_802154_driver_t;
/* define to implement yourself and omit compilation of this function */
#ifndef NETDEV_802154_SEND_DATA_OVERLOAD
/**
* @brief wraps netdev_802154_driver_t::send(), default value for
* netdev_802154_driver_t::send_data().
*
* @param[in] dev the network device
* @param[in] dest the (hardware) destination address for the data
* in host byte order.
* @param[in] dest_len the length of *dest* in byte
* @param[in] upper_layer_hdrs header data from higher network layers from
* highest to lowest layer. Must be prepended to
* the data stream by the network device. May be
* NULL if there are none.
* @param[in] data the data to send
* @param[in] data_len the length of *data* in byte
*
* @return the number of byte actually (data_len + total length of upper layer
* headers) send on success
* @return -EAFNOSUPPORT if address of length dest_len is not supported
* by the device *dev*
* @return -EBUSY if transmission cannot start because radio medium is already
* busy or collision on radio medium occured.
* @return -EINVAL if wrong parameter was given
* @return -ENODEV if *dev* is not recognized as IEEE 802.15.4 device
* @return -EMSGSIZE if the total frame size is too long to fit in a frame
* of the device *dev*
* @return -EIO if any other occured (netdev_802154_driver_t::send() returned
* NETDEV_802154_TX_STATUS_ERROR)
*/
int netdev_802154_send_data(netdev_t *dev, void *dest, size_t dest_len,
netdev_hlist_t *upper_layer_hdrs, void *data,
size_t data_len);
#endif /* NETDEV_802154_SEND_DATA_OVERLOAD */
/* define to implement yourself and omit compilation of this function */
#ifndef NETDEV_802154_SEND_OVERLOAD
/**
* @brief Transmit the given IEEE 802.15.4 packet, by calling
* functions netdev_802154_driver_t::load_tx() and
* netdev_802154_driver_t::transmit() successfully. Default value for
* netdev_802154_driver_t::send()
*
* @param[in] dev the network device
* @param[in] kind Kind of packet to transmit.
* @param[in] dest Address of the node to which the packet is sent.
* @param[in] use_long_addr 1 to use the 64-bit address mode
* with *dest* param; 0 to use
* "short" PAN-centric mode.
* @param[in] wants_ack 1 to request an acknowledgement
* from the receiving node for this packet;
* 0 otherwise.
* @param[in] upper_layer_hdrs header data from higher network layers from
* highest to lowest layer. Must be prepended to
* the data stream by the network device. May be
* NULL if there are none.
* @param[in] buf Pointer to the buffer containing the payload
* of the 802.15.4 packet to transmit.
* The frame header (i.e.: FCS, sequence number,
* src and dest PAN and addresses) is inserted
* using values in accord with *kind* parameter
* and transceiver configuration.
* @param[in] len Length (in bytes) of the outgoing packet payload.
*
* @return @ref netdev_802154_tx_status_t
*/
netdev_802154_tx_status_t netdev_802154_send(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);
#endif /* NETDEV_802154_SEND_OVERLOAD */
#ifdef __cplusplus
}
#endif
#endif /* __NETDEV_802154_H_ */
/**
* @}
*/

View File

@ -41,6 +41,8 @@ typedef enum {
NETDEV_TYPE_UNKNOWN = 0, /**< Type was not specified and may not
understand this API */
NETDEV_TYPE_BASE, /**< Device understands this API */
NETDEV_TYPE_802154, /**< Device understands this API and the API
defined in @ref netdev_802154 */
} netdev_type_t;
/**
@ -105,6 +107,10 @@ typedef enum {
signed value in host byte order */
NETDEV_OPT_MAX_PACKET_SIZE, /**< Maximum packet size the device supports
unsigned value in host byte order */
NETDEV_OPT_SRC_LEN, /**< Default mode the source address is
set to as value of `size_t`. (e.g.
either PAN-centric 16-bit address or
EUI-64 in IEEE 802.15.4) */
/**
* @brief Last value for @netdev_opt_t defined here

View File

@ -27,6 +27,13 @@
*
* @brief Default device as a pointer of netdev_t.
*/
#ifdef MODULE_AT86RF231
#include "at86rf231.h"
#ifndef NETDEV_DEFAULT
#define NETDEV_DEFAULT ((netdev_t *)(&at86rf231_netdev))
#endif /* NETDEV_DEFAULT */
#endif /* MODULE_AT86RF231 */
#ifdef MODULE_NATIVENET

View File

@ -0,0 +1,119 @@
/*
* Copyright (C) 2014 Martin Lenders <mlenders@inf.fu-berlin.de>
*
* 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.
*/
/**
* @addtogroup netdev
* @{
*
* @file 802154.c
* @brief Provides wrappers of @ref netdev/base.h functions to
* netdev/802154.h functions.
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/
#include <errno.h>
#include <stdint.h>
#include <string.h>
#include "netdev/802154.h"
static inline netdev_802154_driver_t *_get_driver(netdev_t *dev)
{
return (netdev_802154_driver_t *)dev->driver;
}
/* define to implement yourself and omit compilation of this function */
#ifndef NETDEV_802154_SEND_DATA_OVERLOAD
static size_t _get_src_len(netdev_t *dev)
{
size_t src_len, src_len_len = sizeof(size_t);
if (_get_driver(dev)->get_option(dev, NETDEV_OPT_SRC_LEN, &src_len, &src_len_len) < 0) {
return 2;
}
return src_len;
}
int netdev_802154_send_data(netdev_t *dev, void *dest, size_t dest_len,
netdev_hlist_t *upper_layer_hdrs, void *data,
size_t data_len)
{
int use_long_addr;
if (dev == NULL || dev->type != NETDEV_TYPE_802154) {
return -ENODEV;
}
use_long_addr = _get_src_len(dev) == 8;
if (dest_len != 8 && dest_len != 4) { /* 8 for EUI-64, 4 for short address + PAN ID*/
return -EAFNOSUPPORT;
}
switch (_get_driver(dev)->send(dev, NETDEV_802154_PKT_KIND_DATA,
(netdev_802154_node_addr_t *)dest,
use_long_addr, 0, upper_layer_hdrs,
data, data_len)) {
case NETDEV_802154_TX_STATUS_OK:
return (int)(data_len + netdev_get_hlist_len(upper_layer_hdrs));
case NETDEV_802154_TX_STATUS_MEDIUM_BUSY:
case NETDEV_802154_TX_STATUS_COLLISION:
return -EBUSY;
case NETDEV_802154_TX_STATUS_INVALID_PARAM:
return -EINVAL;
case NETDEV_802154_TX_STATUS_PACKET_TOO_LONG:
return -EMSGSIZE;
case NETDEV_802154_TX_STATUS_ERROR:
default:
return -EIO;
/* NETDEV_802154_TX_STATUS_UNDERFLOW can not happen since
* netdev_802154_driver_t::send always calls
* netdev_802154_driver_t::load_tx */
/* NETDEV_802154_TX_STATUS_NOACK can not happen since
* wants_ack == 0 */
}
}
#endif /* NETDEV_802154_SEND_DATA_OVERLOAD */
/* define to implement yourself and omit compilation of this function */
#ifndef NETDEV_802154_SEND_OVERLOAD
netdev_802154_tx_status_t netdev_802154_send(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)
{
netdev_802154_tx_status_t status;
if (dev == NULL || dev->type != NETDEV_TYPE_802154) {
return NETDEV_802154_TX_STATUS_NO_DEV;
}
status = _get_driver(dev)->load_tx(dev, kind, dest, use_long_addr, wants_ack,
upper_layer_hdrs, buf, len);
if (status != NETDEV_802154_TX_STATUS_OK) {
return status;
}
return _get_driver(dev)->transmit(dev);
}
#endif /* NETDEV_802154_SEND_OVERLOAD */
/**
* @}
*/

View File

@ -0,0 +1,5 @@
MODULE := netdev_802154
INCLUDES += -I$(RIOTBASE)/drivers/include
include $(RIOTBASE)/Makefile.base

View File

@ -31,7 +31,7 @@ size_t netdev_get_hlist_len(const netdev_hlist_t *hlist)
do {
length += ptr->header_len;
clist_advance((clist_node_t **)&ptr);
netdev_hlist_advance(&ptr);
} while (ptr != hlist);
return length;

View File

@ -23,6 +23,7 @@ config_t sysconfig = {
#ifdef HAS_RADIO
0, /**< default radio address */
0, /**< default radio channel */
1, /**< default radio PAN id */
#endif
"foobar", /**< default name */
"foobar", /**< default name */
};

View File

@ -45,6 +45,7 @@ typedef struct {
#ifdef HAS_RADIO
radio_address_t radio_address; /**< address for radio communication */
uint8_t radio_channel; /**< current frequency */
uint16_t radio_pan_id; /**< PAN id for radio communication */
#endif
/* cppcheck-suppress unusedStructMember : useful for debug purposes */
char name[CONFIG_NAME_LEN]; /**< name of the node */

View File

@ -218,8 +218,8 @@ void _transceiver_send_handler(int argc, char **argv)
puts("Transceiver not initialized");
return;
}
if (argc != 3) {
printf("Usage:\t%s <ADDR> <MSG>\n", argv[0]);
if (argc < 3) {
printf("Usage:\t%s <ADDR> <MSG> [PAN]\n", argv[0]);
return;
}
@ -243,8 +243,13 @@ void _transceiver_send_handler(int argc, char **argv)
p.frame.payload_len = strlen(text_msg) + 1;
p.frame.fcf.dest_addr_m = IEEE_802154_SHORT_ADDR_M;
p.frame.fcf.src_addr_m = IEEE_802154_SHORT_ADDR_M;
p.frame.dest_pan_id = 1;
p.frame.dest_addr[1] = atoi(argv[1]);
if (argc == 4) {
p.frame.dest_pan_id = atoi(argv[3]);
}
else {
p.frame.dest_pan_id = 1;
}
#else
p.data = (uint8_t *) text_msg;
p.length = strlen(text_msg) + 1;