mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #4646 from authmillenon/at86rf2xx/api/netdev2
at86rf2xx: port to netdev2
This commit is contained in:
commit
2510fe03f5
@ -12,6 +12,10 @@ ifneq (,$(filter nhdp,$(USEMODULE)))
|
||||
USEMODULE += oonf_rfc5444
|
||||
endif
|
||||
|
||||
ifneq (,$(filter at86rf2%,$(USEMODULE)))
|
||||
USEMODULE += netdev2_ieee802154
|
||||
endif
|
||||
|
||||
ifneq (,$(filter netdev2_ieee802154,$(USEMODULE)))
|
||||
USEMODULE += ieee802154
|
||||
endif
|
||||
|
@ -1,6 +1,6 @@
|
||||
ifneq (,$(filter gnrc_netif_default,$(USEMODULE)))
|
||||
USEMODULE += at86rf231
|
||||
USEMODULE += gnrc_nomac
|
||||
USEMODULE += gnrc_netdev2
|
||||
endif
|
||||
|
||||
ifneq (,$(filter saul_default,$(USEMODULE)))
|
||||
|
@ -1,6 +1,6 @@
|
||||
ifneq (,$(filter gnrc_netif_default,$(USEMODULE)))
|
||||
USEMODULE += at86rf231
|
||||
USEMODULE += gnrc_nomac
|
||||
USEMODULE += gnrc_netdev2
|
||||
endif
|
||||
|
||||
ifneq (,$(filter saul_default,$(USEMODULE)))
|
||||
|
@ -1,6 +1,6 @@
|
||||
ifneq (,$(filter gnrc_netif_default,$(USEMODULE)))
|
||||
USEMODULE += at86rf212b
|
||||
USEMODULE += gnrc_nomac
|
||||
USEMODULE += gnrc_netdev2
|
||||
endif
|
||||
|
||||
ifneq (,$(filter saul_default,$(USEMODULE)))
|
||||
|
@ -1,6 +1,6 @@
|
||||
ifneq (,$(filter gnrc_netif_default,$(USEMODULE)))
|
||||
USEMODULE += at86rf233
|
||||
USEMODULE += gnrc_nomac
|
||||
USEMODULE += gnrc_netdev2
|
||||
endif
|
||||
|
||||
ifneq (,$(filter saul_default,$(USEMODULE)))
|
||||
|
@ -35,22 +35,13 @@
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
static void _irq_handler(void *arg)
|
||||
void at86rf2xx_setup(at86rf2xx_t *dev, spi_t spi, spi_speed_t spi_speed,
|
||||
gpio_t cs_pin, gpio_t int_pin, gpio_t sleep_pin,
|
||||
gpio_t reset_pin)
|
||||
{
|
||||
msg_t msg;
|
||||
at86rf2xx_t *dev = (at86rf2xx_t *) arg;
|
||||
|
||||
/* tell driver thread about the interrupt */
|
||||
msg.type = GNRC_NETDEV_MSG_TYPE_EVENT;
|
||||
msg_send(&msg, dev->mac_pid);
|
||||
}
|
||||
|
||||
int at86rf2xx_init(at86rf2xx_t *dev, spi_t spi, spi_speed_t spi_speed,
|
||||
gpio_t cs_pin, gpio_t int_pin,
|
||||
gpio_t sleep_pin, gpio_t reset_pin)
|
||||
{
|
||||
dev->driver = &at86rf2xx_driver;
|
||||
netdev2_t *netdev = (netdev2_t *)dev;
|
||||
|
||||
netdev->driver = &at86rf2xx_driver;
|
||||
/* initialize device descriptor */
|
||||
dev->spi = spi;
|
||||
dev->cs_pin = cs_pin;
|
||||
@ -59,32 +50,8 @@ int at86rf2xx_init(at86rf2xx_t *dev, spi_t spi, spi_speed_t spi_speed,
|
||||
dev->reset_pin = reset_pin;
|
||||
dev->idle_state = AT86RF2XX_STATE_TRX_OFF;
|
||||
dev->state = AT86RF2XX_STATE_SLEEP;
|
||||
|
||||
/* initialise SPI */
|
||||
spi_init_master(dev->spi, SPI_CONF_FIRST_RISING, spi_speed);
|
||||
/* initialise GPIOs */
|
||||
gpio_init(dev->cs_pin, GPIO_OUT);
|
||||
gpio_set(dev->cs_pin);
|
||||
gpio_init(dev->sleep_pin, GPIO_OUT);
|
||||
gpio_clear(dev->sleep_pin);
|
||||
gpio_init(dev->reset_pin, GPIO_OUT);
|
||||
gpio_set(dev->reset_pin);
|
||||
gpio_init_int(dev->int_pin, GPIO_IN, GPIO_RISING, _irq_handler, dev);
|
||||
|
||||
/* make sure device is not sleeping, so we can query part number */
|
||||
at86rf2xx_assert_awake(dev);
|
||||
|
||||
/* test if the SPI is set up correctly and the device is responding */
|
||||
if (at86rf2xx_reg_read(dev, AT86RF2XX_REG__PART_NUM) !=
|
||||
AT86RF2XX_PARTNUM) {
|
||||
DEBUG("[at86rf2xx] error: unable to read correct part number\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* reset device to default values and put it into RX state */
|
||||
at86rf2xx_reset(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void at86rf2xx_reset(at86rf2xx_t *dev)
|
||||
@ -100,8 +67,8 @@ void at86rf2xx_reset(at86rf2xx_t *dev)
|
||||
at86rf2xx_reset_state_machine(dev);
|
||||
|
||||
/* reset options and sequence number */
|
||||
dev->seq_nr = 0;
|
||||
dev->options = 0;
|
||||
dev->netdev.seq = 0;
|
||||
dev->netdev.flags = 0;
|
||||
/* set short and long address */
|
||||
#if CPUID_LEN
|
||||
cpuid_get(cpuid);
|
||||
@ -134,15 +101,16 @@ void at86rf2xx_reset(at86rf2xx_t *dev)
|
||||
/* set default TX power */
|
||||
at86rf2xx_set_txpower(dev, AT86RF2XX_DEFAULT_TXPOWER);
|
||||
/* set default options */
|
||||
at86rf2xx_set_option(dev, NETDEV2_IEEE802154_PAN_COMP, true);
|
||||
at86rf2xx_set_option(dev, AT86RF2XX_OPT_AUTOACK, true);
|
||||
at86rf2xx_set_option(dev, AT86RF2XX_OPT_CSMA, true);
|
||||
at86rf2xx_set_option(dev, AT86RF2XX_OPT_TELL_RX_START, false);
|
||||
at86rf2xx_set_option(dev, AT86RF2XX_OPT_TELL_RX_END, true);
|
||||
/* set default protocol */
|
||||
#ifdef MODULE_GNRC_SIXLOWPAN
|
||||
dev->proto = GNRC_NETTYPE_SIXLOWPAN;
|
||||
#else
|
||||
dev->proto = GNRC_NETTYPE_UNDEF;
|
||||
dev->netdev.proto = GNRC_NETTYPE_SIXLOWPAN;
|
||||
#elif MODULE_GNRC
|
||||
dev->netdev.proto = GNRC_NETTYPE_UNDEF;
|
||||
#endif
|
||||
/* enable safe mode (protect RX FIFO until reading data starts) */
|
||||
at86rf2xx_reg_write(dev, AT86RF2XX_REG__TRX_CTRL_2,
|
||||
@ -219,39 +187,42 @@ void at86rf2xx_tx_prepare(at86rf2xx_t *dev)
|
||||
/* make sure ongoing transmissions are finished */
|
||||
do {
|
||||
state = at86rf2xx_get_status(dev);
|
||||
}
|
||||
while (state == AT86RF2XX_STATE_BUSY_RX_AACK ||
|
||||
state == AT86RF2XX_STATE_BUSY_TX_ARET);
|
||||
} while (state == AT86RF2XX_STATE_BUSY_RX_AACK ||
|
||||
state == AT86RF2XX_STATE_BUSY_TX_ARET);
|
||||
if (state != AT86RF2XX_STATE_TX_ARET_ON) {
|
||||
dev->idle_state = state;
|
||||
}
|
||||
at86rf2xx_set_state(dev, AT86RF2XX_STATE_TX_ARET_ON);
|
||||
dev->frame_len = IEEE802154_FCS_LEN;
|
||||
dev->tx_frame_len = IEEE802154_FCS_LEN;
|
||||
}
|
||||
|
||||
size_t at86rf2xx_tx_load(at86rf2xx_t *dev, uint8_t *data,
|
||||
size_t len, size_t offset)
|
||||
{
|
||||
dev->frame_len += (uint8_t)len;
|
||||
dev->tx_frame_len += (uint8_t)len;
|
||||
at86rf2xx_sram_write(dev, offset + 1, data, len);
|
||||
return offset + len;
|
||||
}
|
||||
|
||||
void at86rf2xx_tx_exec(at86rf2xx_t *dev)
|
||||
{
|
||||
netdev2_t *netdev = (netdev2_t *)dev;
|
||||
|
||||
/* write frame length field in FIFO */
|
||||
at86rf2xx_sram_write(dev, 0, &(dev->frame_len), 1);
|
||||
at86rf2xx_sram_write(dev, 0, &(dev->tx_frame_len), 1);
|
||||
/* trigger sending of pre-loaded frame */
|
||||
at86rf2xx_reg_write(dev, AT86RF2XX_REG__TRX_STATE,
|
||||
AT86RF2XX_TRX_STATE__TX_START);
|
||||
if (dev->event_cb && (dev->options & AT86RF2XX_OPT_TELL_TX_START)) {
|
||||
dev->event_cb(NETDEV_EVENT_TX_STARTED, NULL);
|
||||
if (netdev->event_callback &&
|
||||
(dev->netdev.flags & AT86RF2XX_OPT_TELL_TX_START)) {
|
||||
netdev->event_callback(netdev, NETDEV2_EVENT_TX_STARTED, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
size_t at86rf2xx_rx_len(at86rf2xx_t *dev)
|
||||
{
|
||||
uint8_t phr;
|
||||
|
||||
at86rf2xx_fb_read(dev, &phr, 1);
|
||||
|
||||
/* ignore MSB (refer p.80) and substract length of FCS field */
|
||||
|
@ -94,22 +94,22 @@ static const uint8_t dbm_to_tx_pow[] = {0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e,
|
||||
|
||||
uint16_t at86rf2xx_get_addr_short(at86rf2xx_t *dev)
|
||||
{
|
||||
return (dev->addr_short[0] << 8) | dev->addr_short[1];
|
||||
return (dev->netdev.short_addr[0] << 8) | dev->netdev.short_addr[1];
|
||||
}
|
||||
|
||||
void at86rf2xx_set_addr_short(at86rf2xx_t *dev, uint16_t addr)
|
||||
{
|
||||
dev->addr_short[0] = addr >> 8;
|
||||
dev->addr_short[1] = addr;
|
||||
dev->netdev.short_addr[0] = (uint8_t)(addr);
|
||||
dev->netdev.short_addr[1] = (uint8_t)(addr >> 8);
|
||||
#ifdef MODULE_SIXLOWPAN
|
||||
/* https://tools.ietf.org/html/rfc4944#section-12 requires the first bit to
|
||||
* 0 for unicast addresses */
|
||||
dev->addr_short[1] &= 0x7F;
|
||||
dev->netdev.short_addr[0] &= 0x7F;
|
||||
#endif
|
||||
at86rf2xx_reg_write(dev, AT86RF2XX_REG__SHORT_ADDR_0,
|
||||
dev->addr_short[0]);
|
||||
dev->netdev.short_addr[1]);
|
||||
at86rf2xx_reg_write(dev, AT86RF2XX_REG__SHORT_ADDR_1,
|
||||
dev->addr_short[1]);
|
||||
dev->netdev.short_addr[0]);
|
||||
}
|
||||
|
||||
uint64_t at86rf2xx_get_addr_long(at86rf2xx_t *dev)
|
||||
@ -117,7 +117,7 @@ uint64_t at86rf2xx_get_addr_long(at86rf2xx_t *dev)
|
||||
uint64_t addr;
|
||||
uint8_t *ap = (uint8_t *)(&addr);
|
||||
for (int i = 0; i < 8; i++) {
|
||||
ap[i] = dev->addr_long[7 - i];
|
||||
ap[i] = dev->netdev.long_addr[i];
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@ -125,26 +125,26 @@ uint64_t at86rf2xx_get_addr_long(at86rf2xx_t *dev)
|
||||
void at86rf2xx_set_addr_long(at86rf2xx_t *dev, uint64_t addr)
|
||||
{
|
||||
for (int i = 0; i < 8; i++) {
|
||||
dev->addr_long[i] = (addr >> ((7 - i) * 8));
|
||||
dev->netdev.long_addr[i] = (uint8_t)(addr >> (i * 8));
|
||||
at86rf2xx_reg_write(dev, (AT86RF2XX_REG__IEEE_ADDR_0 + i),
|
||||
dev->addr_long[i]);
|
||||
(addr >> ((7 - i) * 8)));
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t at86rf2xx_get_chan(at86rf2xx_t *dev)
|
||||
{
|
||||
return dev->chan;
|
||||
return dev->netdev.chan;
|
||||
}
|
||||
|
||||
void at86rf2xx_set_chan(at86rf2xx_t *dev, uint8_t channel)
|
||||
{
|
||||
if ((channel < AT86RF2XX_MIN_CHANNEL) ||
|
||||
(channel > AT86RF2XX_MAX_CHANNEL) ||
|
||||
(dev->chan == channel)) {
|
||||
(dev->netdev.chan == channel)) {
|
||||
return;
|
||||
}
|
||||
|
||||
dev->chan = channel;
|
||||
dev->netdev.chan = channel;
|
||||
|
||||
at86rf2xx_configure_phy(dev);
|
||||
}
|
||||
@ -172,15 +172,16 @@ void at86rf2xx_set_page(at86rf2xx_t *dev, uint8_t page)
|
||||
|
||||
uint16_t at86rf2xx_get_pan(at86rf2xx_t *dev)
|
||||
{
|
||||
return dev->pan;
|
||||
return dev->netdev.pan;
|
||||
}
|
||||
|
||||
void at86rf2xx_set_pan(at86rf2xx_t *dev, uint16_t pan)
|
||||
{
|
||||
dev->pan = pan;
|
||||
DEBUG("pan0: %u, pan1: %u\n", (uint8_t)pan, pan >> 8);
|
||||
at86rf2xx_reg_write(dev, AT86RF2XX_REG__PAN_ID_0, (uint8_t)pan);
|
||||
at86rf2xx_reg_write(dev, AT86RF2XX_REG__PAN_ID_1, (pan >> 8));
|
||||
le_uint16_t le_pan = byteorder_btols(byteorder_htons(pan));
|
||||
dev->netdev.pan = pan;
|
||||
DEBUG("pan0: %u, pan1: %u\n", le_pan.u8[0], le_pan.u8[1]);
|
||||
at86rf2xx_reg_write(dev, AT86RF2XX_REG__PAN_ID_0, le_pan.u8[0]);
|
||||
at86rf2xx_reg_write(dev, AT86RF2XX_REG__PAN_ID_1, le_pan.u8[1]);
|
||||
}
|
||||
|
||||
int16_t at86rf2xx_get_txpower(at86rf2xx_t *dev)
|
||||
@ -188,7 +189,7 @@ int16_t at86rf2xx_get_txpower(at86rf2xx_t *dev)
|
||||
#ifdef MODULE_AT86RF212B
|
||||
uint8_t txpower = at86rf2xx_reg_read(dev, AT86RF2XX_REG__PHY_TX_PWR);
|
||||
DEBUG("txpower value: %x\n", txpower);
|
||||
return _tx_pow_to_dbm_212b(dev->chan, dev->page, txpower);
|
||||
return _tx_pow_to_dbm_212b(dev->netdev.chan, dev->page, txpower);
|
||||
#else
|
||||
uint8_t txpower = at86rf2xx_reg_read(dev, AT86RF2XX_REG__PHY_TX_PWR)
|
||||
& AT86RF2XX_PHY_TX_PWR_MASK__TX_PWR;
|
||||
@ -220,11 +221,11 @@ void at86rf2xx_set_txpower(at86rf2xx_t *dev, int16_t txpower)
|
||||
#endif
|
||||
}
|
||||
#ifdef MODULE_AT86RF212B
|
||||
if (dev->chan == 0) {
|
||||
if (dev->netdev.chan == 0) {
|
||||
at86rf2xx_reg_write(dev, AT86RF2XX_REG__PHY_TX_PWR,
|
||||
dbm_to_tx_pow_868[txpower]);
|
||||
}
|
||||
else if (dev->chan < 11) {
|
||||
else if (dev->netdev.chan < 11) {
|
||||
at86rf2xx_reg_write(dev, AT86RF2XX_REG__PHY_TX_PWR,
|
||||
dbm_to_tx_pow_915[txpower]);
|
||||
}
|
||||
@ -331,14 +332,14 @@ void at86rf2xx_set_option(at86rf2xx_t *dev, uint16_t option, bool state)
|
||||
|
||||
/* set option field */
|
||||
if (state) {
|
||||
dev->options |= option;
|
||||
dev->netdev.flags |= option;
|
||||
/* trigger option specific actions */
|
||||
switch (option) {
|
||||
case AT86RF2XX_OPT_CSMA:
|
||||
DEBUG("[at86rf2xx] opt: enabling CSMA mode" \
|
||||
"(4 retries, min BE: 3 max BE: 5)\n");
|
||||
/* Initialize CSMA seed with hardware address */
|
||||
at86rf2xx_set_csma_seed(dev, dev->addr_long);
|
||||
at86rf2xx_set_csma_seed(dev, dev->netdev.long_addr);
|
||||
at86rf2xx_set_csma_max_retries(dev, 4);
|
||||
at86rf2xx_set_csma_backoff_exp(dev, 3, 5);
|
||||
break;
|
||||
@ -371,7 +372,7 @@ void at86rf2xx_set_option(at86rf2xx_t *dev, uint16_t option, bool state)
|
||||
}
|
||||
}
|
||||
else {
|
||||
dev->options &= ~(option);
|
||||
dev->netdev.flags &= ~(option);
|
||||
/* trigger option specific actions */
|
||||
switch (option) {
|
||||
case AT86RF2XX_OPT_CSMA:
|
||||
@ -386,7 +387,7 @@ void at86rf2xx_set_option(at86rf2xx_t *dev, uint16_t option, bool state)
|
||||
tmp &= ~(AT86RF2XX_XAH_CTRL_1__AACK_PROM_MODE);
|
||||
at86rf2xx_reg_write(dev, AT86RF2XX_REG__XAH_CTRL_1, tmp);
|
||||
/* re-enable AUTOACK only if the option is set */
|
||||
if (dev->options & AT86RF2XX_OPT_AUTOACK) {
|
||||
if (dev->netdev.flags & AT86RF2XX_OPT_AUTOACK) {
|
||||
tmp = at86rf2xx_reg_read(dev,
|
||||
AT86RF2XX_REG__CSMA_SEED_1);
|
||||
tmp &= ~(AT86RF2XX_CSMA_SEED_1__AACK_DIS_ACK);
|
||||
|
@ -173,7 +173,7 @@ void at86rf2xx_configure_phy(at86rf2xx_t *dev)
|
||||
/* Clear previous configuration for GC_TX_OFFS */
|
||||
rf_ctrl0 &= ~AT86RF2XX_RF_CTRL_0_MASK__GC_TX_OFFS;
|
||||
|
||||
if (dev->chan != 0) {
|
||||
if (dev->netdev.chan != 0) {
|
||||
/* Set sub mode bit on 915 MHz as recommended by the data sheet */
|
||||
trx_ctrl2 |= AT86RF2XX_TRX_CTRL_2_MASK__SUB_MODE;
|
||||
}
|
||||
@ -199,7 +199,7 @@ void at86rf2xx_configure_phy(at86rf2xx_t *dev)
|
||||
phy_cc_cca &= ~(AT86RF2XX_PHY_CC_CCA_MASK__CHANNEL);
|
||||
|
||||
/* Update the channel register */
|
||||
phy_cc_cca |= (dev->chan & AT86RF2XX_PHY_CC_CCA_MASK__CHANNEL);
|
||||
phy_cc_cca |= (dev->netdev.chan & AT86RF2XX_PHY_CC_CCA_MASK__CHANNEL);
|
||||
at86rf2xx_reg_write(dev, AT86RF2XX_REG__PHY_CC_CCA, phy_cc_cca);
|
||||
|
||||
#ifdef MODULE_AT86RF212B
|
||||
|
@ -16,13 +16,19 @@
|
||||
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
* @author Kévin Roussel <Kevin.Roussel@inria.fr>
|
||||
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "net/eui64.h"
|
||||
#include "net/ieee802154.h"
|
||||
#include "net/gnrc.h"
|
||||
#include "net/netdev2.h"
|
||||
#include "net/netdev2/ieee802154.h"
|
||||
|
||||
#include "at86rf2xx.h"
|
||||
#include "at86rf2xx_netdev.h"
|
||||
#include "at86rf2xx_internal.h"
|
||||
@ -33,243 +39,92 @@
|
||||
|
||||
#define _MAX_MHR_OVERHEAD (25)
|
||||
|
||||
/* TODO: generalize and move to (gnrc_)ieee802154 */
|
||||
static size_t _make_data_frame_hdr(at86rf2xx_t *dev, uint8_t *buf,
|
||||
gnrc_netif_hdr_t *hdr)
|
||||
static int _send(netdev2_t *netdev, const struct iovec *vector, int count);
|
||||
static int _recv(netdev2_t *netdev, char *buf, int len, void *info);
|
||||
static int _init(netdev2_t *netdev);
|
||||
static void _isr(netdev2_t *netdev);
|
||||
static int _get(netdev2_t *netdev, netopt_t opt, void *val, size_t max_len);
|
||||
static int _set(netdev2_t *netdev, netopt_t opt, void *val, size_t len);
|
||||
|
||||
const netdev2_driver_t at86rf2xx_driver = {
|
||||
.send = _send,
|
||||
.recv = _recv,
|
||||
.init = _init,
|
||||
.isr = _isr,
|
||||
.get = _get,
|
||||
.set = _set,
|
||||
};
|
||||
|
||||
static void _irq_handler(void *arg)
|
||||
{
|
||||
int pos = 0;
|
||||
netdev2_t *dev = (netdev2_t *) arg;
|
||||
|
||||
/* we are building a data frame here */
|
||||
buf[0] = IEEE802154_FCF_TYPE_DATA;
|
||||
buf[1] = IEEE802154_FCF_VERS_V1;
|
||||
|
||||
/* if AUTOACK is enabled, then we also expect ACKs for this packet */
|
||||
if (!(hdr->flags & GNRC_NETIF_HDR_FLAGS_BROADCAST) &&
|
||||
!(hdr->flags & GNRC_NETIF_HDR_FLAGS_MULTICAST) &&
|
||||
(dev->options & AT86RF2XX_OPT_AUTOACK)) {
|
||||
buf[0] |= IEEE802154_FCF_ACK_REQ;
|
||||
if (dev->event_callback) {
|
||||
dev->event_callback(dev, NETDEV2_EVENT_ISR, NULL);
|
||||
}
|
||||
|
||||
/* fill in destination PAN ID */
|
||||
pos = 3;
|
||||
buf[pos++] = (uint8_t)((dev->pan) & 0xff);
|
||||
buf[pos++] = (uint8_t)((dev->pan) >> 8);
|
||||
|
||||
/* fill in destination address */
|
||||
if (hdr->flags &
|
||||
(GNRC_NETIF_HDR_FLAGS_BROADCAST | GNRC_NETIF_HDR_FLAGS_MULTICAST)) {
|
||||
buf[1] |= IEEE802154_FCF_DST_ADDR_SHORT;
|
||||
buf[pos++] = 0xff;
|
||||
buf[pos++] = 0xff;
|
||||
}
|
||||
else if (hdr->dst_l2addr_len == 2) {
|
||||
uint8_t *dst_addr = gnrc_netif_hdr_get_dst_addr(hdr);
|
||||
buf[1] |= IEEE802154_FCF_DST_ADDR_SHORT;
|
||||
buf[pos++] = dst_addr[1];
|
||||
buf[pos++] = dst_addr[0];
|
||||
}
|
||||
else if (hdr->dst_l2addr_len == 8) {
|
||||
buf[1] |= IEEE802154_FCF_DST_ADDR_LONG;
|
||||
uint8_t *dst_addr = gnrc_netif_hdr_get_dst_addr(hdr);
|
||||
for (int i = 7; i >= 0; i--) {
|
||||
buf[pos++] = dst_addr[i];
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* unsupported address length */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* fill in source PAN ID (if applicable */
|
||||
if (dev->options & AT86RF2XX_OPT_USE_SRC_PAN) {
|
||||
buf[pos++] = (uint8_t)((dev->pan) & 0xff);
|
||||
buf[pos++] = (uint8_t)((dev->pan) >> 8);
|
||||
} else {
|
||||
buf[0] |= IEEE802154_FCF_PAN_COMP;
|
||||
}
|
||||
|
||||
/* fill in source address */
|
||||
if (dev->options & AT86RF2XX_OPT_SRC_ADDR_LONG) {
|
||||
buf[1] |= IEEE802154_FCF_SRC_ADDR_LONG;
|
||||
memcpy(&(buf[pos]), dev->addr_long, 8);
|
||||
pos += 8;
|
||||
}
|
||||
else {
|
||||
buf[1] |= IEEE802154_FCF_SRC_ADDR_SHORT;
|
||||
buf[pos++] = dev->addr_short[0];
|
||||
buf[pos++] = dev->addr_short[1];
|
||||
}
|
||||
|
||||
/* set sequence number */
|
||||
buf[2] = dev->seq_nr++;
|
||||
/* return actual header length */
|
||||
return pos;
|
||||
}
|
||||
|
||||
/* TODO: generalize and move to ieee802154 */
|
||||
/* TODO: include security header implications */
|
||||
static size_t _get_frame_hdr_len(uint8_t *mhr)
|
||||
static int _init(netdev2_t *netdev)
|
||||
{
|
||||
uint8_t tmp;
|
||||
size_t len = 3;
|
||||
at86rf2xx_t *dev = (at86rf2xx_t *)netdev;
|
||||
|
||||
/* figure out address sizes */
|
||||
tmp = (mhr[1] & IEEE802154_FCF_DST_ADDR_MASK);
|
||||
if (tmp == IEEE802154_FCF_DST_ADDR_SHORT) {
|
||||
len += 4;
|
||||
}
|
||||
else if (tmp == IEEE802154_FCF_DST_ADDR_LONG) {
|
||||
len += 10;
|
||||
}
|
||||
else if (tmp != IEEE802154_FCF_DST_ADDR_VOID) {
|
||||
return 0;
|
||||
}
|
||||
tmp = (mhr[1] & IEEE802154_FCF_SRC_ADDR_MASK);
|
||||
if (tmp == IEEE802154_FCF_SRC_ADDR_VOID) {
|
||||
return len;
|
||||
}
|
||||
else {
|
||||
if (!(mhr[0] & IEEE802154_FCF_PAN_COMP)) {
|
||||
len += 2;
|
||||
}
|
||||
if (tmp == IEEE802154_FCF_SRC_ADDR_SHORT) {
|
||||
return (len + 2);
|
||||
}
|
||||
else if (tmp == IEEE802154_FCF_SRC_ADDR_LONG) {
|
||||
return (len + 8);
|
||||
}
|
||||
/* initialise GPIOs */
|
||||
gpio_init(dev->cs_pin, GPIO_OUT);
|
||||
gpio_set(dev->cs_pin);
|
||||
gpio_init(dev->sleep_pin, GPIO_OUT);
|
||||
gpio_clear(dev->sleep_pin);
|
||||
gpio_init(dev->reset_pin, GPIO_OUT);
|
||||
gpio_set(dev->reset_pin);
|
||||
gpio_init_int(dev->int_pin, GPIO_IN, GPIO_RISING, _irq_handler, dev);
|
||||
|
||||
/* make sure device is not sleeping, so we can query part number */
|
||||
at86rf2xx_assert_awake(dev);
|
||||
|
||||
/* test if the SPI is set up correctly and the device is responding */
|
||||
if (at86rf2xx_reg_read(dev, AT86RF2XX_REG__PART_NUM) !=
|
||||
AT86RF2XX_PARTNUM) {
|
||||
DEBUG("[at86rf2xx] error: unable to read correct part number\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* reset device to default values and put it into RX state */
|
||||
at86rf2xx_reset(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TODO: generalize and move to (gnrc_)ieee802154 */
|
||||
static gnrc_pktsnip_t *_make_netif_hdr(uint8_t *mhr)
|
||||
{
|
||||
uint8_t tmp;
|
||||
uint8_t *addr;
|
||||
uint8_t src_len, dst_len;
|
||||
gnrc_pktsnip_t *snip;
|
||||
gnrc_netif_hdr_t *hdr;
|
||||
|
||||
/* figure out address sizes */
|
||||
tmp = mhr[1] & IEEE802154_FCF_SRC_ADDR_MASK;
|
||||
if (tmp == IEEE802154_FCF_SRC_ADDR_SHORT) {
|
||||
src_len = 2;
|
||||
}
|
||||
else if (tmp == IEEE802154_FCF_SRC_ADDR_LONG) {
|
||||
src_len = 8;
|
||||
}
|
||||
else if (tmp == IEEE802154_FCF_SRC_ADDR_VOID) {
|
||||
src_len = 0;
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
tmp = mhr[1] & IEEE802154_FCF_DST_ADDR_MASK;
|
||||
if (tmp == IEEE802154_FCF_DST_ADDR_SHORT) {
|
||||
dst_len = 2;
|
||||
}
|
||||
else if (tmp == IEEE802154_FCF_DST_ADDR_LONG) {
|
||||
dst_len = 8;
|
||||
}
|
||||
else if (tmp == IEEE802154_FCF_DST_ADDR_VOID) {
|
||||
dst_len = 0;
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
/* allocate space for header */
|
||||
snip = gnrc_pktbuf_add(NULL, NULL, sizeof(gnrc_netif_hdr_t) + src_len + dst_len,
|
||||
GNRC_NETTYPE_NETIF);
|
||||
if (snip == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
/* fill header */
|
||||
hdr = (gnrc_netif_hdr_t *)snip->data;
|
||||
gnrc_netif_hdr_init(hdr, src_len, dst_len);
|
||||
if (dst_len > 0) {
|
||||
hdr->flags |= GNRC_NETIF_HDR_FLAGS_BROADCAST;
|
||||
tmp = 5 + dst_len;
|
||||
addr = gnrc_netif_hdr_get_dst_addr(hdr);
|
||||
for (int i = 0; i < dst_len; i++) {
|
||||
addr[i] = mhr[5 + (dst_len - i) - 1];
|
||||
if(addr[i] != 0xff) {
|
||||
hdr->flags &= ~(GNRC_NETIF_HDR_FLAGS_BROADCAST);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
tmp = 3;
|
||||
}
|
||||
if (!(mhr[0] & IEEE802154_FCF_PAN_COMP)) {
|
||||
tmp += 2;
|
||||
}
|
||||
if (src_len > 0) {
|
||||
addr = gnrc_netif_hdr_get_src_addr(hdr);
|
||||
for (int i = 0; i < src_len; i++) {
|
||||
addr[i] = mhr[tmp + (src_len - i) - 1];
|
||||
}
|
||||
}
|
||||
return snip;
|
||||
}
|
||||
|
||||
|
||||
static int _send(gnrc_netdev_t *netdev, gnrc_pktsnip_t *pkt)
|
||||
static int _send(netdev2_t *netdev, const struct iovec *vector, int count)
|
||||
{
|
||||
at86rf2xx_t *dev = (at86rf2xx_t *)netdev;
|
||||
gnrc_pktsnip_t *snip;
|
||||
uint8_t mhr[IEEE802154_MAX_HDR_LEN];
|
||||
size_t len;
|
||||
|
||||
if (pkt == NULL) {
|
||||
return -ENOMSG;
|
||||
}
|
||||
if (dev == NULL) {
|
||||
gnrc_pktbuf_release(pkt);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* create 802.15.4 header */
|
||||
len = _make_data_frame_hdr(dev, mhr, (gnrc_netif_hdr_t *)pkt->data);
|
||||
if (len == 0) {
|
||||
DEBUG("[at86rf2xx] error: unable to create 802.15.4 header\n");
|
||||
gnrc_pktbuf_release(pkt);
|
||||
return -ENOMSG;
|
||||
}
|
||||
/* check if packet (header + payload + FCS) fits into FIFO */
|
||||
snip = pkt->next;
|
||||
if ((gnrc_pkt_len(snip) + len + 2) > AT86RF2XX_MAX_PKT_LENGTH) {
|
||||
printf("[at86rf2xx] error: packet too large (%u byte) to be send\n",
|
||||
gnrc_pkt_len(snip) + len + 2);
|
||||
gnrc_pktbuf_release(pkt);
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
const struct iovec *ptr = vector;
|
||||
size_t len = 0;
|
||||
|
||||
at86rf2xx_tx_prepare(dev);
|
||||
/* put header into FIFO */
|
||||
len = at86rf2xx_tx_load(dev, mhr, len, 0);
|
||||
|
||||
/* load packet data into FIFO */
|
||||
while (snip) {
|
||||
len = at86rf2xx_tx_load(dev, snip->data, snip->size, len);
|
||||
snip = snip->next;
|
||||
for (int i = 0; i < count; i++, ptr++) {
|
||||
/* current packet data + FCS too long */
|
||||
if ((len + ptr->iov_len + 2) > AT86RF2XX_MAX_PKT_LENGTH) {
|
||||
printf("[at86rf2xx] error: packet too large (%u byte) to be send\n",
|
||||
(unsigned)len + 2);
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
len = at86rf2xx_tx_load(dev, ptr->iov_base, ptr->iov_len, len);
|
||||
}
|
||||
|
||||
/* send data out directly if pre-loading id disabled */
|
||||
if (!(dev->options & AT86RF2XX_OPT_PRELOADING)) {
|
||||
if (!(dev->netdev.flags & AT86RF2XX_OPT_PRELOADING)) {
|
||||
at86rf2xx_tx_exec(dev);
|
||||
}
|
||||
/* release packet */
|
||||
gnrc_pktbuf_release(pkt);
|
||||
/* return the number of bytes that were actually send out */
|
||||
return (int)len;
|
||||
}
|
||||
|
||||
static void _receive_data(at86rf2xx_t *dev)
|
||||
static int _recv(netdev2_t *netdev, char *buf, int len, void *info)
|
||||
{
|
||||
uint8_t mhr[IEEE802154_MAX_HDR_LEN];
|
||||
at86rf2xx_t *dev = (at86rf2xx_t *)netdev;
|
||||
uint8_t phr;
|
||||
size_t pkt_len, hdr_len;
|
||||
gnrc_pktsnip_t *hdr, *payload = NULL;
|
||||
gnrc_netif_hdr_t *netif;
|
||||
size_t pkt_len;
|
||||
|
||||
/* frame buffer protection will be unlocked as soon as at86rf2xx_fb_stop()
|
||||
* is called*/
|
||||
@ -281,75 +136,38 @@ static void _receive_data(at86rf2xx_t *dev)
|
||||
/* Ignore FCS for packet length */
|
||||
pkt_len = phr - 2;
|
||||
|
||||
/* abort here already if no event callback is registered */
|
||||
if (!dev->event_cb) {
|
||||
/* just return length when buf == NULL */
|
||||
if (buf == NULL) {
|
||||
at86rf2xx_fb_stop(dev);
|
||||
return;
|
||||
return pkt_len;
|
||||
}
|
||||
|
||||
/* in raw mode, just read the binary dump into the packet buffer */
|
||||
if (dev->options & AT86RF2XX_OPT_RAWDUMP) {
|
||||
payload = gnrc_pktbuf_add(NULL, NULL, pkt_len, GNRC_NETTYPE_UNDEF);
|
||||
if (payload == NULL ) {
|
||||
at86rf2xx_fb_stop(dev);
|
||||
DEBUG("[at86rf2xx] error: unable to allocate RAW data\n");
|
||||
return;
|
||||
}
|
||||
at86rf2xx_fb_read(dev, payload->data, pkt_len);
|
||||
/* not enough space in buf */
|
||||
if (pkt_len > len) {
|
||||
at86rf2xx_fb_stop(dev);
|
||||
dev->event_cb(NETDEV_EVENT_RX_COMPLETE, payload);
|
||||
return;
|
||||
}
|
||||
|
||||
/* get FCF field and compute 802.15.4 header length */
|
||||
at86rf2xx_fb_read(dev, mhr, 2);
|
||||
|
||||
hdr_len = _get_frame_hdr_len(mhr);
|
||||
if (hdr_len == 0) {
|
||||
at86rf2xx_fb_stop(dev);
|
||||
DEBUG("[at86rf2xx] error: unable parse incoming frame header\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* read the rest of the header and parse the netif header from it */
|
||||
at86rf2xx_fb_read(dev, &(mhr[2]), hdr_len - 2);
|
||||
hdr = _make_netif_hdr(mhr);
|
||||
if (hdr == NULL) {
|
||||
at86rf2xx_fb_stop(dev);
|
||||
DEBUG("[at86rf2xx] error: unable to allocate netif header\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* fill missing fields in netif header */
|
||||
netif = (gnrc_netif_hdr_t *)hdr->data;
|
||||
netif->if_pid = dev->mac_pid;
|
||||
|
||||
/* allocate payload */
|
||||
payload = gnrc_pktbuf_add(hdr, NULL, (pkt_len - hdr_len), dev->proto);
|
||||
if (payload == NULL) {
|
||||
at86rf2xx_fb_stop(dev);
|
||||
DEBUG("[at86rf2xx] error: unable to allocate incoming payload\n");
|
||||
gnrc_pktbuf_release(hdr);
|
||||
return;
|
||||
return -ENOBUFS;
|
||||
}
|
||||
/* copy payload */
|
||||
at86rf2xx_fb_read(dev, payload->data, payload->size);
|
||||
at86rf2xx_fb_read(dev, (uint8_t *)buf, pkt_len);
|
||||
|
||||
/* Ignore FCS but advance fb read */
|
||||
at86rf2xx_fb_read(dev, NULL, 2);
|
||||
|
||||
at86rf2xx_fb_read(dev, &(netif->lqi), 1);
|
||||
|
||||
if (info != NULL) {
|
||||
netdev2_ieee802154_rx_info_t *radio_info = info;
|
||||
at86rf2xx_fb_read(dev, &(radio_info->lqi), 1);
|
||||
#ifndef MODULE_AT86RF231
|
||||
at86rf2xx_fb_read(dev, &(netif->rssi), 1);
|
||||
at86rf2xx_fb_stop(dev);
|
||||
at86rf2xx_fb_read(dev, &(radio_info->rssi), 1);
|
||||
at86rf2xx_fb_stop(dev);
|
||||
#else
|
||||
at86rf2xx_fb_stop(dev);
|
||||
netif->rssi = at86rf2xx_reg_read(dev, AT86RF2XX_REG__PHY_ED_LEVEL);
|
||||
at86rf2xx_fb_stop(dev);
|
||||
radio_info->rssi = at86rf2xx_reg_read(dev, AT86RF2XX_REG__PHY_ED_LEVEL);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
at86rf2xx_fb_stop(dev);
|
||||
}
|
||||
|
||||
/* finish up and send data to upper layers */
|
||||
dev->event_cb(NETDEV_EVENT_RX_COMPLETE, payload);
|
||||
return pkt_len;
|
||||
}
|
||||
|
||||
static int _set_state(at86rf2xx_t *dev, netopt_state_t state)
|
||||
@ -362,7 +180,7 @@ static int _set_state(at86rf2xx_t *dev, netopt_state_t state)
|
||||
at86rf2xx_set_state(dev, AT86RF2XX_STATE_RX_AACK_ON);
|
||||
break;
|
||||
case NETOPT_STATE_TX:
|
||||
if (dev->options & AT86RF2XX_OPT_PRELOADING) {
|
||||
if (dev->netdev.flags & AT86RF2XX_OPT_PRELOADING) {
|
||||
at86rf2xx_tx_exec(dev);
|
||||
}
|
||||
break;
|
||||
@ -391,86 +209,16 @@ netopt_state_t _get_state(at86rf2xx_t *dev)
|
||||
}
|
||||
}
|
||||
|
||||
static int _get(gnrc_netdev_t *device, netopt_t opt, void *val, size_t max_len)
|
||||
static int _get(netdev2_t *netdev, netopt_t opt, void *val, size_t max_len)
|
||||
{
|
||||
at86rf2xx_t *dev = (at86rf2xx_t *) device;
|
||||
at86rf2xx_t *dev = (at86rf2xx_t *) netdev;
|
||||
|
||||
if (device == NULL) {
|
||||
if (netdev == NULL) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* getting these options doesn't require the transceiver to be responsive */
|
||||
switch (opt) {
|
||||
|
||||
case NETOPT_ADDRESS:
|
||||
if (max_len < sizeof(uint16_t)) {
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
*((uint16_t *)val) = at86rf2xx_get_addr_short(dev);
|
||||
return sizeof(uint16_t);
|
||||
|
||||
case NETOPT_ADDRESS_LONG:
|
||||
if (max_len < sizeof(uint64_t)) {
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
*((uint64_t *)val) = at86rf2xx_get_addr_long(dev);
|
||||
return sizeof(uint64_t);
|
||||
|
||||
case NETOPT_ADDR_LEN:
|
||||
if (max_len < sizeof(uint16_t)) {
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
*((uint16_t *)val) = 2;
|
||||
return sizeof(uint16_t);
|
||||
|
||||
case NETOPT_SRC_LEN:
|
||||
if (max_len < sizeof(uint16_t)) {
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
if (dev->options & AT86RF2XX_OPT_SRC_ADDR_LONG) {
|
||||
*((uint16_t *)val) = 8;
|
||||
}
|
||||
else {
|
||||
*((uint16_t *)val) = 2;
|
||||
}
|
||||
return sizeof(uint16_t);
|
||||
|
||||
case NETOPT_NID:
|
||||
if (max_len < sizeof(uint16_t)) {
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
*((uint16_t *)val) = dev->pan;
|
||||
return sizeof(uint16_t);
|
||||
|
||||
case NETOPT_IPV6_IID:
|
||||
if (max_len < sizeof(eui64_t)) {
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
if (dev->options & AT86RF2XX_OPT_SRC_ADDR_LONG) {
|
||||
uint64_t addr = at86rf2xx_get_addr_long(dev);
|
||||
ieee802154_get_iid(val, (uint8_t *)&addr, 8);
|
||||
}
|
||||
else {
|
||||
uint16_t addr = at86rf2xx_get_addr_short(dev);
|
||||
ieee802154_get_iid(val, (uint8_t *)&addr, 2);
|
||||
}
|
||||
return sizeof(eui64_t);
|
||||
|
||||
case NETOPT_PROTO:
|
||||
if (max_len < sizeof(gnrc_nettype_t)) {
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
*((gnrc_nettype_t *)val) = dev->proto;
|
||||
return sizeof(gnrc_nettype_t);
|
||||
|
||||
case NETOPT_CHANNEL:
|
||||
if (max_len < sizeof(uint16_t)) {
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
((uint8_t *)val)[1] = 0;
|
||||
((uint8_t *)val)[0] = at86rf2xx_get_chan(dev);
|
||||
return sizeof(uint16_t);
|
||||
|
||||
case NETOPT_CHANNEL_PAGE:
|
||||
if (max_len < sizeof(uint16_t)) {
|
||||
return -EOVERFLOW;
|
||||
@ -490,20 +238,11 @@ static int _get(gnrc_netdev_t *device, netopt_t opt, void *val, size_t max_len)
|
||||
if (max_len < sizeof(netopt_state_t)) {
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
*((netopt_state_t*)val) = _get_state(dev);
|
||||
*((netopt_state_t *)val) = _get_state(dev);
|
||||
return sizeof(netopt_state_t);
|
||||
|
||||
case NETOPT_PRELOADING:
|
||||
if (dev->options & AT86RF2XX_OPT_PRELOADING) {
|
||||
*((netopt_enable_t *)val) = NETOPT_ENABLE;
|
||||
}
|
||||
else {
|
||||
*((netopt_enable_t *)val) = NETOPT_DISABLE;
|
||||
}
|
||||
return sizeof(netopt_enable_t);
|
||||
|
||||
case NETOPT_AUTOACK:
|
||||
if (dev->options & AT86RF2XX_OPT_AUTOACK) {
|
||||
if (dev->netdev.flags & AT86RF2XX_OPT_PRELOADING) {
|
||||
*((netopt_enable_t *)val) = NETOPT_ENABLE;
|
||||
}
|
||||
else {
|
||||
@ -512,16 +251,7 @@ static int _get(gnrc_netdev_t *device, netopt_t opt, void *val, size_t max_len)
|
||||
return sizeof(netopt_enable_t);
|
||||
|
||||
case NETOPT_PROMISCUOUSMODE:
|
||||
if (dev->options & AT86RF2XX_OPT_PROMISCUOUS) {
|
||||
*((netopt_enable_t *)val) = NETOPT_ENABLE;
|
||||
}
|
||||
else {
|
||||
*((netopt_enable_t *)val) = NETOPT_DISABLE;
|
||||
}
|
||||
return sizeof(netopt_enable_t);
|
||||
|
||||
case NETOPT_RAWMODE:
|
||||
if (dev->options & AT86RF2XX_OPT_RAWDUMP) {
|
||||
if (dev->netdev.flags & AT86RF2XX_OPT_PROMISCUOUS) {
|
||||
*((netopt_enable_t *)val) = NETOPT_ENABLE;
|
||||
}
|
||||
else {
|
||||
@ -531,27 +261,27 @@ static int _get(gnrc_netdev_t *device, netopt_t opt, void *val, size_t max_len)
|
||||
|
||||
case NETOPT_RX_START_IRQ:
|
||||
*((netopt_enable_t *)val) =
|
||||
!!(dev->options & AT86RF2XX_OPT_TELL_RX_START);
|
||||
!!(dev->netdev.flags & AT86RF2XX_OPT_TELL_RX_START);
|
||||
return sizeof(netopt_enable_t);
|
||||
|
||||
case NETOPT_RX_END_IRQ:
|
||||
*((netopt_enable_t *)val) =
|
||||
!!(dev->options & AT86RF2XX_OPT_TELL_RX_END);
|
||||
!!(dev->netdev.flags & AT86RF2XX_OPT_TELL_RX_END);
|
||||
return sizeof(netopt_enable_t);
|
||||
|
||||
case NETOPT_TX_START_IRQ:
|
||||
*((netopt_enable_t *)val) =
|
||||
!!(dev->options & AT86RF2XX_OPT_TELL_TX_START);
|
||||
!!(dev->netdev.flags & AT86RF2XX_OPT_TELL_TX_START);
|
||||
return sizeof(netopt_enable_t);
|
||||
|
||||
case NETOPT_TX_END_IRQ:
|
||||
*((netopt_enable_t *)val) =
|
||||
!!(dev->options & AT86RF2XX_OPT_TELL_TX_END);
|
||||
!!(dev->netdev.flags & AT86RF2XX_OPT_TELL_TX_END);
|
||||
return sizeof(netopt_enable_t);
|
||||
|
||||
case NETOPT_CSMA:
|
||||
*((netopt_enable_t *)val) =
|
||||
!!(dev->options & AT86RF2XX_OPT_CSMA);
|
||||
!!(dev->netdev.flags & AT86RF2XX_OPT_CSMA);
|
||||
return sizeof(netopt_enable_t);
|
||||
|
||||
default:
|
||||
@ -559,12 +289,18 @@ static int _get(gnrc_netdev_t *device, netopt_t opt, void *val, size_t max_len)
|
||||
break;
|
||||
}
|
||||
|
||||
int res;
|
||||
|
||||
if (((res = netdev2_ieee802154_get((netdev2_ieee802154_t *)netdev, opt, val,
|
||||
max_len)) >= 0) || (res != -ENOTSUP)) {
|
||||
return res;
|
||||
}
|
||||
|
||||
uint8_t old_state = at86rf2xx_get_status(dev);
|
||||
int res = 0;
|
||||
res = 0;
|
||||
|
||||
/* temporarily wake up if sleeping */
|
||||
if(old_state == AT86RF2XX_STATE_SLEEP) {
|
||||
if (old_state == AT86RF2XX_STATE_SLEEP) {
|
||||
at86rf2xx_assert_awake(dev);
|
||||
}
|
||||
|
||||
@ -573,7 +309,8 @@ static int _get(gnrc_netdev_t *device, netopt_t opt, void *val, size_t max_len)
|
||||
case NETOPT_TX_POWER:
|
||||
if (max_len < sizeof(int16_t)) {
|
||||
res = -EOVERFLOW;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
*((uint16_t *)val) = at86rf2xx_get_txpower(dev);
|
||||
res = sizeof(uint16_t);
|
||||
}
|
||||
@ -582,7 +319,8 @@ static int _get(gnrc_netdev_t *device, netopt_t opt, void *val, size_t max_len)
|
||||
case NETOPT_RETRANS:
|
||||
if (max_len < sizeof(uint8_t)) {
|
||||
res = -EOVERFLOW;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
*((uint8_t *)val) = at86rf2xx_get_max_retries(dev);
|
||||
res = sizeof(uint8_t);
|
||||
}
|
||||
@ -601,7 +339,8 @@ static int _get(gnrc_netdev_t *device, netopt_t opt, void *val, size_t max_len)
|
||||
case NETOPT_CSMA_RETRIES:
|
||||
if (max_len < sizeof(uint8_t)) {
|
||||
res = -EOVERFLOW;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
*((uint8_t *)val) = at86rf2xx_get_csma_max_retries(dev);
|
||||
res = sizeof(uint8_t);
|
||||
}
|
||||
@ -610,7 +349,8 @@ static int _get(gnrc_netdev_t *device, netopt_t opt, void *val, size_t max_len)
|
||||
case NETOPT_CCA_THRESHOLD:
|
||||
if (max_len < sizeof(int8_t)) {
|
||||
res = -EOVERFLOW;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
*((int8_t *)val) = at86rf2xx_get_cca_threshold(dev);
|
||||
res = sizeof(int8_t);
|
||||
}
|
||||
@ -621,16 +361,16 @@ static int _get(gnrc_netdev_t *device, netopt_t opt, void *val, size_t max_len)
|
||||
}
|
||||
|
||||
/* go back to sleep if were sleeping */
|
||||
if(old_state == AT86RF2XX_STATE_SLEEP) {
|
||||
if (old_state == AT86RF2XX_STATE_SLEEP) {
|
||||
at86rf2xx_set_state(dev, AT86RF2XX_STATE_SLEEP);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int _set(gnrc_netdev_t *device, netopt_t opt, void *val, size_t len)
|
||||
static int _set(netdev2_t *netdev, netopt_t opt, void *val, size_t len)
|
||||
{
|
||||
at86rf2xx_t *dev = (at86rf2xx_t *) device;
|
||||
at86rf2xx_t *dev = (at86rf2xx_t *) netdev;
|
||||
uint8_t old_state = at86rf2xx_get_status(dev);
|
||||
int res = 0;
|
||||
|
||||
@ -639,7 +379,7 @@ static int _set(gnrc_netdev_t *device, netopt_t opt, void *val, size_t len)
|
||||
}
|
||||
|
||||
/* temporarily wake up if sleeping */
|
||||
if(old_state == AT86RF2XX_STATE_SLEEP) {
|
||||
if (old_state == AT86RF2XX_STATE_SLEEP) {
|
||||
at86rf2xx_assert_awake(dev);
|
||||
}
|
||||
|
||||
@ -647,64 +387,38 @@ static int _set(gnrc_netdev_t *device, netopt_t opt, void *val, size_t len)
|
||||
case NETOPT_ADDRESS:
|
||||
if (len > sizeof(uint16_t)) {
|
||||
res = -EOVERFLOW;
|
||||
} else {
|
||||
at86rf2xx_set_addr_short(dev, *((uint16_t*)val));
|
||||
res = sizeof(uint16_t);
|
||||
}
|
||||
else {
|
||||
at86rf2xx_set_addr_short(dev, *((uint16_t *)val));
|
||||
/* don't set res to set netdev2_ieee802154_t::short_addr */
|
||||
}
|
||||
break;
|
||||
|
||||
case NETOPT_ADDRESS_LONG:
|
||||
if (len > sizeof(uint64_t)) {
|
||||
res = -EOVERFLOW;
|
||||
} else {
|
||||
at86rf2xx_set_addr_long(dev, *((uint64_t*)val));
|
||||
res = sizeof(uint64_t);
|
||||
}
|
||||
break;
|
||||
|
||||
case NETOPT_SRC_LEN:
|
||||
if (len > sizeof(uint16_t)) {
|
||||
res = -EOVERFLOW;
|
||||
} else {
|
||||
if (*((uint16_t *)val) == 2) {
|
||||
at86rf2xx_set_option(dev, AT86RF2XX_OPT_SRC_ADDR_LONG,
|
||||
false);
|
||||
}
|
||||
else if (*((uint16_t *)val) == 8) {
|
||||
at86rf2xx_set_option(dev, AT86RF2XX_OPT_SRC_ADDR_LONG,
|
||||
true);
|
||||
}
|
||||
else {
|
||||
res = -ENOTSUP;
|
||||
break;
|
||||
}
|
||||
res = sizeof(uint16_t);
|
||||
else {
|
||||
at86rf2xx_set_addr_long(dev, *((uint64_t *)val));
|
||||
/* don't set res to set netdev2_ieee802154_t::long_addr */
|
||||
}
|
||||
break;
|
||||
|
||||
case NETOPT_NID:
|
||||
if (len > sizeof(uint16_t)) {
|
||||
res = -EOVERFLOW;
|
||||
} else {
|
||||
at86rf2xx_set_pan(dev, *((uint16_t *)val));
|
||||
res = sizeof(uint16_t);
|
||||
}
|
||||
break;
|
||||
|
||||
case NETOPT_PROTO:
|
||||
if (len != sizeof(gnrc_nettype_t)) {
|
||||
res = -EINVAL;
|
||||
}
|
||||
else {
|
||||
dev->proto = *((gnrc_nettype_t*) val);
|
||||
res = sizeof(gnrc_nettype_t);
|
||||
at86rf2xx_set_pan(dev, *((uint16_t *)val));
|
||||
/* don't set res to set netdev2_ieee802154_t::pan */
|
||||
}
|
||||
break;
|
||||
|
||||
case NETOPT_CHANNEL:
|
||||
if (len != sizeof(uint16_t)) {
|
||||
res = -EINVAL;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
uint8_t chan = ((uint8_t *)val)[0];
|
||||
if (chan < AT86RF2XX_MIN_CHANNEL ||
|
||||
chan > AT86RF2XX_MAX_CHANNEL) {
|
||||
@ -712,19 +426,21 @@ static int _set(gnrc_netdev_t *device, netopt_t opt, void *val, size_t len)
|
||||
break;
|
||||
}
|
||||
at86rf2xx_set_chan(dev, chan);
|
||||
res = sizeof(uint16_t);
|
||||
/* don't set res to set netdev2_ieee802154_t::chan */
|
||||
}
|
||||
break;
|
||||
|
||||
case NETOPT_CHANNEL_PAGE:
|
||||
if (len != sizeof(uint16_t)) {
|
||||
res = -EINVAL;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
uint8_t page = ((uint8_t *)val)[0];
|
||||
#ifdef MODULE_AT86RF212B
|
||||
if ((page != 0) && (page != 2)) {
|
||||
res = -ENOTSUP;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
at86rf2xx_set_page(dev, page);
|
||||
res = sizeof(uint16_t);
|
||||
}
|
||||
@ -732,7 +448,8 @@ static int _set(gnrc_netdev_t *device, netopt_t opt, void *val, size_t len)
|
||||
/* rf23x only supports page 0, no need to configure anything in the driver. */
|
||||
if (page != 0) {
|
||||
res = -ENOTSUP;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
res = sizeof(uint16_t);
|
||||
}
|
||||
#endif
|
||||
@ -742,7 +459,8 @@ static int _set(gnrc_netdev_t *device, netopt_t opt, void *val, size_t len)
|
||||
case NETOPT_TX_POWER:
|
||||
if (len > sizeof(int16_t)) {
|
||||
res = -EOVERFLOW;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
at86rf2xx_set_txpower(dev, *((int16_t *)val));
|
||||
res = sizeof(uint16_t);
|
||||
}
|
||||
@ -751,7 +469,8 @@ static int _set(gnrc_netdev_t *device, netopt_t opt, void *val, size_t len)
|
||||
case NETOPT_STATE:
|
||||
if (len > sizeof(netopt_state_t)) {
|
||||
res = -EOVERFLOW;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
res = _set_state(dev, *((netopt_state_t *)val));
|
||||
}
|
||||
break;
|
||||
@ -759,13 +478,14 @@ static int _set(gnrc_netdev_t *device, netopt_t opt, void *val, size_t len)
|
||||
case NETOPT_AUTOACK:
|
||||
at86rf2xx_set_option(dev, AT86RF2XX_OPT_AUTOACK,
|
||||
((bool *)val)[0]);
|
||||
res = sizeof(netopt_enable_t);
|
||||
/* don't set res to set netdev2_ieee802154_t::flags */
|
||||
break;
|
||||
|
||||
case NETOPT_RETRANS:
|
||||
if (len > sizeof(uint8_t)) {
|
||||
res = -EOVERFLOW;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
at86rf2xx_set_max_retries(dev, *((uint8_t *)val));
|
||||
res = sizeof(uint8_t);
|
||||
}
|
||||
@ -783,12 +503,6 @@ static int _set(gnrc_netdev_t *device, netopt_t opt, void *val, size_t len)
|
||||
res = sizeof(netopt_enable_t);
|
||||
break;
|
||||
|
||||
case NETOPT_RAWMODE:
|
||||
at86rf2xx_set_option(dev, AT86RF2XX_OPT_RAWDUMP,
|
||||
((bool *)val)[0]);
|
||||
res = sizeof(netopt_enable_t);
|
||||
break;
|
||||
|
||||
case NETOPT_RX_START_IRQ:
|
||||
at86rf2xx_set_option(dev, AT86RF2XX_OPT_TELL_RX_START,
|
||||
((bool *)val)[0]);
|
||||
@ -815,18 +529,20 @@ static int _set(gnrc_netdev_t *device, netopt_t opt, void *val, size_t len)
|
||||
|
||||
case NETOPT_CSMA:
|
||||
at86rf2xx_set_option(dev, AT86RF2XX_OPT_CSMA,
|
||||
((bool *)val)[0]);
|
||||
((bool *)val)[0]);
|
||||
res = sizeof(netopt_enable_t);
|
||||
break;
|
||||
|
||||
case NETOPT_CSMA_RETRIES:
|
||||
if( (len > sizeof(uint8_t)) ||
|
||||
(*((uint8_t *)val) > 5) ) {
|
||||
if ((len > sizeof(uint8_t)) ||
|
||||
(*((uint8_t *)val) > 5)) {
|
||||
res = -EOVERFLOW;
|
||||
} else if( !(dev->options & AT86RF2XX_OPT_CSMA) ) {
|
||||
}
|
||||
else if (!(dev->netdev.flags & AT86RF2XX_OPT_CSMA)) {
|
||||
/* If CSMA is disabled, don't allow setting retries */
|
||||
res = -ENOTSUP;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
at86rf2xx_set_csma_max_retries(dev, *((uint8_t *)val));
|
||||
res = sizeof(uint8_t);
|
||||
}
|
||||
@ -835,7 +551,8 @@ static int _set(gnrc_netdev_t *device, netopt_t opt, void *val, size_t len)
|
||||
case NETOPT_CCA_THRESHOLD:
|
||||
if (len > sizeof(int8_t)) {
|
||||
res = -EOVERFLOW;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
at86rf2xx_set_cca_threshold(dev, *((int8_t *)val));
|
||||
res = sizeof(int8_t);
|
||||
}
|
||||
@ -846,44 +563,22 @@ static int _set(gnrc_netdev_t *device, netopt_t opt, void *val, size_t len)
|
||||
}
|
||||
|
||||
/* go back to sleep if were sleeping and state hasn't been changed */
|
||||
if( (old_state == AT86RF2XX_STATE_SLEEP) &&
|
||||
(opt != NETOPT_STATE) ) {
|
||||
if ((old_state == AT86RF2XX_STATE_SLEEP) &&
|
||||
(opt != NETOPT_STATE)) {
|
||||
at86rf2xx_set_state(dev, AT86RF2XX_STATE_SLEEP);
|
||||
}
|
||||
|
||||
if (res == -ENOTSUP) {
|
||||
res = netdev2_ieee802154_set((netdev2_ieee802154_t *)netdev, opt,
|
||||
val, len);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int _add_event_cb(gnrc_netdev_t *dev, gnrc_netdev_event_cb_t cb)
|
||||
static void _isr(netdev2_t *netdev)
|
||||
{
|
||||
if (dev == NULL) {
|
||||
return -ENODEV;
|
||||
}
|
||||
if (dev->event_cb) {
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
dev->event_cb = cb;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _rem_event_cb(gnrc_netdev_t *dev, gnrc_netdev_event_cb_t cb)
|
||||
{
|
||||
if (dev == NULL) {
|
||||
return -ENODEV;
|
||||
}
|
||||
if (dev->event_cb != cb) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
dev->event_cb = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _isr_event(gnrc_netdev_t *device, uint32_t event_type)
|
||||
{
|
||||
(void) event_type;
|
||||
at86rf2xx_t *dev = (at86rf2xx_t *) device;
|
||||
at86rf2xx_t *dev = (at86rf2xx_t *) netdev;
|
||||
uint8_t irq_mask;
|
||||
uint8_t state;
|
||||
uint8_t trac_status;
|
||||
@ -892,28 +587,29 @@ static void _isr_event(gnrc_netdev_t *device, uint32_t event_type)
|
||||
* lost anyway, so return immediately.
|
||||
*/
|
||||
state = at86rf2xx_get_status(dev);
|
||||
if(state == AT86RF2XX_STATE_SLEEP)
|
||||
if (state == AT86RF2XX_STATE_SLEEP) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* read (consume) device status */
|
||||
irq_mask = at86rf2xx_reg_read(dev, AT86RF2XX_REG__IRQ_STATUS);
|
||||
|
||||
trac_status = at86rf2xx_reg_read(dev, AT86RF2XX_REG__TRX_STATE) &
|
||||
AT86RF2XX_TRX_STATE_MASK__TRAC;
|
||||
AT86RF2XX_TRX_STATE_MASK__TRAC;
|
||||
|
||||
if (irq_mask & AT86RF2XX_IRQ_STATUS_MASK__RX_START) {
|
||||
dev->event_cb(NETDEV_EVENT_RX_STARTED, NULL);
|
||||
netdev->event_callback(netdev, NETDEV2_EVENT_RX_STARTED, NULL);
|
||||
DEBUG("[at86rf2xx] EVT - RX_START\n");
|
||||
}
|
||||
|
||||
if (irq_mask & AT86RF2XX_IRQ_STATUS_MASK__TRX_END) {
|
||||
if(state == AT86RF2XX_STATE_RX_AACK_ON ||
|
||||
state == AT86RF2XX_STATE_BUSY_RX_AACK) {
|
||||
if (state == AT86RF2XX_STATE_RX_AACK_ON ||
|
||||
state == AT86RF2XX_STATE_BUSY_RX_AACK) {
|
||||
DEBUG("[at86rf2xx] EVT - RX_END\n");
|
||||
if (!(dev->options & AT86RF2XX_OPT_TELL_RX_END)) {
|
||||
if (!(dev->netdev.flags & AT86RF2XX_OPT_TELL_RX_END)) {
|
||||
return;
|
||||
}
|
||||
_receive_data(dev);
|
||||
netdev->event_callback(netdev, NETDEV2_EVENT_RX_COMPLETE, NULL);
|
||||
}
|
||||
else if (state == AT86RF2XX_STATE_TX_ARET_ON ||
|
||||
state == AT86RF2XX_STATE_BUSY_TX_ARET) {
|
||||
@ -921,35 +617,26 @@ static void _isr_event(gnrc_netdev_t *device, uint32_t event_type)
|
||||
DEBUG("[at86rf2xx] EVT - TX_END\n");
|
||||
DEBUG("[at86rf2xx] return to state 0x%x\n", dev->idle_state);
|
||||
|
||||
if (dev->event_cb && (dev->options & AT86RF2XX_OPT_TELL_TX_END)) {
|
||||
switch(trac_status) {
|
||||
case AT86RF2XX_TRX_STATE__TRAC_SUCCESS:
|
||||
case AT86RF2XX_TRX_STATE__TRAC_SUCCESS_DATA_PENDING:
|
||||
dev->event_cb(NETDEV_EVENT_TX_COMPLETE, NULL);
|
||||
DEBUG("[at86rf2xx] TX SUCCESS\n");
|
||||
break;
|
||||
case AT86RF2XX_TRX_STATE__TRAC_NO_ACK:
|
||||
dev->event_cb(NETDEV_EVENT_TX_NOACK, NULL);
|
||||
DEBUG("[at86rf2xx] TX NO_ACK\n");
|
||||
break;
|
||||
case AT86RF2XX_TRX_STATE__TRAC_CHANNEL_ACCESS_FAILURE:
|
||||
dev->event_cb(NETDEV_EVENT_TX_MEDIUM_BUSY, NULL);
|
||||
DEBUG("[at86rf2xx] TX_CHANNEL_ACCESS_FAILURE\n");
|
||||
break;
|
||||
default:
|
||||
DEBUG("[at86rf2xx] Unhandled TRAC_STATUS: %d\n",
|
||||
trac_status >> 5);
|
||||
if (netdev->event_callback && (dev->netdev.flags & AT86RF2XX_OPT_TELL_TX_END)) {
|
||||
switch (trac_status) {
|
||||
case AT86RF2XX_TRX_STATE__TRAC_SUCCESS:
|
||||
case AT86RF2XX_TRX_STATE__TRAC_SUCCESS_DATA_PENDING:
|
||||
netdev->event_callback(netdev, NETDEV2_EVENT_TX_COMPLETE, NULL);
|
||||
DEBUG("[at86rf2xx] TX SUCCESS\n");
|
||||
break;
|
||||
case AT86RF2XX_TRX_STATE__TRAC_NO_ACK:
|
||||
netdev->event_callback(netdev, NETDEV2_EVENT_TX_NOACK, NULL);
|
||||
DEBUG("[at86rf2xx] TX NO_ACK\n");
|
||||
break;
|
||||
case AT86RF2XX_TRX_STATE__TRAC_CHANNEL_ACCESS_FAILURE:
|
||||
netdev->event_callback(netdev, NETDEV2_EVENT_TX_MEDIUM_BUSY, NULL);
|
||||
DEBUG("[at86rf2xx] TX_CHANNEL_ACCESS_FAILURE\n");
|
||||
break;
|
||||
default:
|
||||
DEBUG("[at86rf2xx] Unhandled TRAC_STATUS: %d\n",
|
||||
trac_status >> 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const gnrc_netdev_driver_t at86rf2xx_driver = {
|
||||
.send_data = _send,
|
||||
.add_event_callback = _add_event_cb,
|
||||
.rem_event_callback = _rem_event_cb,
|
||||
.get = _get,
|
||||
.set = _set,
|
||||
.isr_event = _isr_event,
|
||||
};
|
||||
|
@ -19,7 +19,7 @@
|
||||
#ifndef AT86RF2XX_NETDEV_H_
|
||||
#define AT86RF2XX_NETDEV_H_
|
||||
|
||||
#include "net/gnrc/netdev.h"
|
||||
#include "net/netdev2.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -28,7 +28,7 @@ extern "C" {
|
||||
/**
|
||||
* @brief Reference to the netdev device driver struct
|
||||
*/
|
||||
extern const gnrc_netdev_driver_t at86rf2xx_driver;
|
||||
extern const netdev2_driver_t at86rf2xx_driver;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
/**
|
||||
* @defgroup drivers_at86rf2xx AT86RF2xx based drivers
|
||||
* @ingroup drivers_netdev
|
||||
* @ingroup drivers_netdev_netdev2
|
||||
*
|
||||
* This module contains drivers for radio devices in Atmel's AT86RF2xx series.
|
||||
* The driver is aimed to work with all devices of this series.
|
||||
@ -34,7 +34,9 @@
|
||||
#include "board.h"
|
||||
#include "periph/spi.h"
|
||||
#include "periph/gpio.h"
|
||||
#include "net/gnrc/netdev.h"
|
||||
#include "net/netdev2.h"
|
||||
#include "net/netdev2/ieee802154.h"
|
||||
#include "net/gnrc/nettype.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -54,9 +56,9 @@ extern "C" {
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Channel configuration
|
||||
* @{
|
||||
*/
|
||||
* @brief Channel configuration
|
||||
* @{
|
||||
*/
|
||||
#ifdef MODULE_AT86RF212B
|
||||
/* the AT86RF212B has a sub-1GHz radio */
|
||||
#define AT86RF2XX_MIN_CHANNEL (0)
|
||||
@ -106,57 +108,54 @@ extern "C" {
|
||||
|
||||
/**
|
||||
* @brief Internal device option flags
|
||||
*
|
||||
* `0x00ff` is reserved for general IEEE 802.15.4 flags
|
||||
* (see @ref netdev2_ieee802154_t)
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
#define AT86RF2XX_OPT_AUTOACK (0x0001) /**< auto ACKs active */
|
||||
#define AT86RF2XX_OPT_CSMA (0x0002) /**< CSMA active */
|
||||
#define AT86RF2XX_OPT_PROMISCUOUS (0x0004) /**< promiscuous mode
|
||||
#define AT86RF2XX_OPT_SRC_ADDR_LONG (NETDEV2_IEEE802154_SRC_MODE_LONG) /**< legacy define */
|
||||
#define AT86RF2XX_OPT_RAWDUMP (NETDEV2_IEEE802154_RAW) /**< legacy define */
|
||||
#define AT86RF2XX_OPT_AUTOACK (NETDEV2_IEEE802154_ACK_REQ) /**< legacy define */
|
||||
|
||||
#define AT86RF2XX_OPT_CSMA (0x0100) /**< CSMA active */
|
||||
#define AT86RF2XX_OPT_PROMISCUOUS (0x0200) /**< promiscuous mode
|
||||
* active */
|
||||
#define AT86RF2XX_OPT_PRELOADING (0x0008) /**< preloading enabled */
|
||||
#define AT86RF2XX_OPT_TELL_TX_START (0x0010) /**< notify MAC layer on TX
|
||||
#define AT86RF2XX_OPT_PRELOADING (0x0400) /**< preloading enabled */
|
||||
#define AT86RF2XX_OPT_TELL_TX_START (0x0800) /**< notify MAC layer on TX
|
||||
* start */
|
||||
#define AT86RF2XX_OPT_TELL_TX_END (0x0020) /**< notify MAC layer on TX
|
||||
#define AT86RF2XX_OPT_TELL_TX_END (0x1000) /**< notify MAC layer on TX
|
||||
* finished */
|
||||
#define AT86RF2XX_OPT_TELL_RX_START (0x0040) /**< notify MAC layer on RX
|
||||
#define AT86RF2XX_OPT_TELL_RX_START (0x2000) /**< notify MAC layer on RX
|
||||
* start */
|
||||
#define AT86RF2XX_OPT_TELL_RX_END (0x0080) /**< notify MAC layer on RX
|
||||
#define AT86RF2XX_OPT_TELL_RX_END (0x4000) /**< notify MAC layer on RX
|
||||
* finished */
|
||||
#define AT86RF2XX_OPT_RAWDUMP (0x0100) /**< pass RAW frame data to
|
||||
* upper layer */
|
||||
#define AT86RF2XX_OPT_SRC_ADDR_LONG (0x0200) /**< send data using long
|
||||
* source address */
|
||||
#define AT86RF2XX_OPT_USE_SRC_PAN (0x0400) /**< do not compress source
|
||||
* PAN ID */
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Device descriptor for AT86RF2XX radio devices
|
||||
*
|
||||
* @extends netdev2_ieee802154_t
|
||||
*/
|
||||
typedef struct {
|
||||
/* netdev fields */
|
||||
const gnrc_netdev_driver_t *driver; /**< pointer to the devices interface */
|
||||
gnrc_netdev_event_cb_t event_cb; /**< netdev event callback */
|
||||
kernel_pid_t mac_pid; /**< the driver's thread's PID */
|
||||
/* device specific fields */
|
||||
spi_t spi; /**< used SPI device */
|
||||
gpio_t cs_pin; /**< chip select pin */
|
||||
gpio_t sleep_pin; /**< sleep pin */
|
||||
gpio_t reset_pin; /**< reset pin */
|
||||
gpio_t int_pin; /**< external interrupt pin */
|
||||
gnrc_nettype_t proto; /**< protocol the radio expects */
|
||||
uint8_t state; /**< current state of the radio */
|
||||
uint8_t seq_nr; /**< sequence number to use next */
|
||||
uint8_t frame_len; /**< length of the current TX frame */
|
||||
uint16_t pan; /**< currently used PAN ID */
|
||||
uint8_t chan; /**< currently used channel number */
|
||||
netdev2_ieee802154_t netdev; /**< netdev2 parent struct */
|
||||
/**
|
||||
* @brief device specific fields
|
||||
* @{
|
||||
*/
|
||||
spi_t spi; /**< used SPI device */
|
||||
gpio_t cs_pin; /**< chip select pin */
|
||||
gpio_t sleep_pin; /**< sleep pin */
|
||||
gpio_t reset_pin; /**< reset pin */
|
||||
gpio_t int_pin; /**< external interrupt pin */
|
||||
uint8_t state; /**< current state of the radio */
|
||||
uint8_t tx_frame_len; /**< length of the current TX frame */
|
||||
#ifdef MODULE_AT86RF212B
|
||||
/* Only AT86RF212B supports multiple pages (PHY modes) */
|
||||
uint8_t page; /**< currently used channel page */
|
||||
#endif
|
||||
uint8_t addr_short[2]; /**< the radio's short address */
|
||||
uint8_t addr_long[8]; /**< the radio's long address */
|
||||
uint16_t options; /**< state of used options */
|
||||
uint8_t idle_state; /**< state to return to after sending */
|
||||
/** @} */
|
||||
} at86rf2xx_t;
|
||||
|
||||
/**
|
||||
@ -172,7 +171,7 @@ typedef struct at86rf2xx_params {
|
||||
} at86rf2xx_params_t;
|
||||
|
||||
/**
|
||||
* @brief Initialize a given AT86RF2xx device
|
||||
* @brief Setup an AT86RF2xx based device state
|
||||
*
|
||||
* @param[out] dev device descriptor
|
||||
* @param[in] spi SPI bus the device is connected to
|
||||
@ -181,13 +180,10 @@ typedef struct at86rf2xx_params {
|
||||
* @param[in] int_pin GPIO pin connected to the interrupt pin
|
||||
* @param[in] sleep_pin GPIO pin connected to the sleep pin
|
||||
* @param[in] reset_pin GPIO pin connected to the reset pin
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return <0 on error
|
||||
*/
|
||||
int at86rf2xx_init(at86rf2xx_t *dev, spi_t spi, spi_speed_t spi_speed,
|
||||
gpio_t cs_pin, gpio_t int_pin,
|
||||
gpio_t sleep_pin, gpio_t reset_pin);
|
||||
void at86rf2xx_setup(at86rf2xx_t *dev, spi_t spi, spi_speed_t spi_speed,
|
||||
gpio_t cs_pin, gpio_t int_pin, gpio_t sleep_pin,
|
||||
gpio_t reset_pin);
|
||||
|
||||
/**
|
||||
* @brief Trigger a hardware reset and configure radio with default values
|
||||
|
@ -20,7 +20,8 @@
|
||||
#ifdef MODULE_AT86RF2XX
|
||||
|
||||
#include "board.h"
|
||||
#include "net/gnrc/nomac.h"
|
||||
#include "net/gnrc/netdev2.h"
|
||||
#include "net/gnrc/netdev2/ieee802154.h"
|
||||
#include "net/gnrc.h"
|
||||
|
||||
#include "at86rf2xx.h"
|
||||
@ -36,32 +37,38 @@
|
||||
#define AT86RF2XX_MAC_STACKSIZE (THREAD_STACKSIZE_DEFAULT)
|
||||
#define AT86RF2XX_MAC_PRIO (THREAD_PRIORITY_MAIN - 4)
|
||||
|
||||
#define AT86RF2XX_NUM (sizeof(at86rf2xx_params)/sizeof(at86rf2xx_params[0]))
|
||||
#define AT86RF2XX_NUM (sizeof(at86rf2xx_params) / sizeof(at86rf2xx_params[0]))
|
||||
|
||||
static at86rf2xx_t at86rf2xx_devs[AT86RF2XX_NUM];
|
||||
static char _nomac_stacks[AT86RF2XX_MAC_STACKSIZE][AT86RF2XX_NUM];
|
||||
static gnrc_netdev2_t gnrc_adpt[AT86RF2XX_NUM];
|
||||
static char _at86rf2xx_stacks[AT86RF2XX_MAC_STACKSIZE][AT86RF2XX_NUM];
|
||||
|
||||
void auto_init_at86rf2xx(void)
|
||||
{
|
||||
for (unsigned i = 0; i < AT86RF2XX_NUM; i++) {
|
||||
const at86rf2xx_params_t *p = &at86rf2xx_params[i];
|
||||
int res;
|
||||
|
||||
DEBUG("Initializing AT86RF2xx radio at SPI_%i\n", p->spi);
|
||||
int res = at86rf2xx_init(&at86rf2xx_devs[i],
|
||||
p->spi,
|
||||
p->spi_speed,
|
||||
p->cs_pin,
|
||||
p->int_pin,
|
||||
p->sleep_pin,
|
||||
p->reset_pin);
|
||||
at86rf2xx_setup(&at86rf2xx_devs[i],
|
||||
p->spi,
|
||||
p->spi_speed,
|
||||
p->cs_pin,
|
||||
p->int_pin,
|
||||
p->sleep_pin,
|
||||
p->reset_pin);
|
||||
res = gnrc_netdev2_ieee802154_init(&gnrc_adpt[i],
|
||||
(netdev2_ieee802154_t *)&at86rf2xx_devs[i]);
|
||||
|
||||
if (res < 0) {
|
||||
DEBUG("Error initializing AT86RF2xx radio device!\n");
|
||||
}
|
||||
else {
|
||||
gnrc_nomac_init(_nomac_stacks[i],
|
||||
AT86RF2XX_MAC_STACKSIZE, AT86RF2XX_MAC_PRIO,
|
||||
"at86rfxx", (gnrc_netdev_t *)&at86rf2xx_devs[i]);
|
||||
gnrc_netdev2_init(_at86rf2xx_stacks[i],
|
||||
AT86RF2XX_MAC_STACKSIZE,
|
||||
AT86RF2XX_MAC_PRIO,
|
||||
"at86rf2xx",
|
||||
&gnrc_adpt[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,12 +3,9 @@ include ../Makefile.tests_common
|
||||
|
||||
FEATURES_REQUIRED = periph_spi periph_gpio
|
||||
|
||||
BOARD_INSUFFICIENT_MEMORY := nucleo-f334 stm32f0discovery weio
|
||||
DISABLE_MODULE += auto_init
|
||||
|
||||
USEMODULE += auto_init_gnrc_netif
|
||||
USEMODULE += gnrc_netif
|
||||
USEMODULE += gnrc_nomac
|
||||
USEMODULE += gnrc_pktdump
|
||||
USEMODULE += od
|
||||
USEMODULE += shell
|
||||
USEMODULE += shell_commands
|
||||
USEMODULE += ps
|
||||
|
31
tests/driver_at86rf2xx/addr.c
Normal file
31
tests/driver_at86rf2xx/addr.c
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) Freie Universität Berlin
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
void print_addr(uint8_t *addr, size_t addr_len)
|
||||
{
|
||||
for (int i = 0; i < addr_len; i++) {
|
||||
if (i != 0) {
|
||||
printf(":");
|
||||
}
|
||||
printf("%02x", (unsigned)addr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/** @} */
|
306
tests/driver_at86rf2xx/cmd.c
Normal file
306
tests/driver_at86rf2xx/cmd.c
Normal file
@ -0,0 +1,306 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Freie Universität Berlin
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "net/netdev2/ieee802154.h"
|
||||
#include "net/ieee802154.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "od.h"
|
||||
|
||||
#define _MAX_ADDR_LEN (8)
|
||||
|
||||
static int _parse_addr(uint8_t *out, size_t out_len, const char *in);
|
||||
static int send(int iface, le_uint16_t dst_pan, uint8_t *dst_addr,
|
||||
size_t dst_len, char *data);
|
||||
|
||||
int ifconfig_list(int idx)
|
||||
{
|
||||
int res;
|
||||
uint8_t array_val[_MAX_ADDR_LEN];
|
||||
netdev2_ieee802154_t *dev = (netdev2_ieee802154_t *)(&devs[idx]);
|
||||
|
||||
int (*get)(netdev2_t *, netopt_t, void *, size_t) = dev->netdev.driver->get;
|
||||
netopt_enable_t enable_val;
|
||||
uint16_t u16_val;
|
||||
|
||||
printf("Iface %3d HWaddr: ", idx);
|
||||
print_addr(dev->short_addr, IEEE802154_SHORT_ADDRESS_LEN);
|
||||
printf(", Long HWaddr: ");
|
||||
print_addr(dev->long_addr, IEEE802154_LONG_ADDRESS_LEN);
|
||||
printf(", PAN: 0x%04x", dev->pan);
|
||||
|
||||
res = get((netdev2_t *)dev, NETOPT_ADDR_LEN, &u16_val, sizeof(u16_val));
|
||||
if (res < 0) {
|
||||
puts("(err)");
|
||||
return 1;
|
||||
}
|
||||
printf("\n Address length: %u", (unsigned)u16_val);
|
||||
|
||||
res = get((netdev2_t *)dev, NETOPT_SRC_LEN, &u16_val, sizeof(u16_val));
|
||||
if (res < 0) {
|
||||
puts("(err)");
|
||||
return 1;
|
||||
}
|
||||
printf(", Source address length: %u", (unsigned)u16_val);
|
||||
|
||||
res = get((netdev2_t *)dev, NETOPT_MAX_PACKET_SIZE, &u16_val,
|
||||
sizeof(u16_val));
|
||||
if (res < 0) {
|
||||
puts("(err)");
|
||||
return 1;
|
||||
}
|
||||
printf(", Max.Payload: %u", (unsigned)u16_val);
|
||||
|
||||
res = get((netdev2_t *)dev, NETOPT_IPV6_IID, array_val, sizeof(array_val));
|
||||
if (res > 0) {
|
||||
printf("\n IPv6 IID: ");
|
||||
print_addr(array_val, res);
|
||||
}
|
||||
|
||||
printf("\n Channel: %u", dev->chan);
|
||||
|
||||
res = get((netdev2_t *)dev, NETOPT_CHANNEL_PAGE, &u16_val, sizeof(u16_val));
|
||||
if (res < 0) {
|
||||
puts("(err)");
|
||||
return 1;
|
||||
}
|
||||
printf(", Ch.page: %u", (unsigned)u16_val);
|
||||
|
||||
res = get((netdev2_t *)dev, NETOPT_TX_POWER, &u16_val, sizeof(u16_val));
|
||||
if (res < 0) {
|
||||
puts("(err)");
|
||||
return 1;
|
||||
}
|
||||
printf(", TXPower: %d dBm", (int)u16_val);
|
||||
res = get((netdev2_t *)dev, NETOPT_IS_WIRED, &u16_val, sizeof(u16_val));
|
||||
if (res < 0) {
|
||||
puts(", wireless");
|
||||
}
|
||||
else {
|
||||
puts(", wired");
|
||||
}
|
||||
|
||||
printf(" ");
|
||||
res = get((netdev2_t *)dev, NETOPT_PRELOADING, &enable_val,
|
||||
sizeof(netopt_enable_t));
|
||||
if ((res > 0) && (enable_val == NETOPT_ENABLE)) {
|
||||
printf(" PRELOAD");
|
||||
}
|
||||
res = get((netdev2_t *)dev, NETOPT_AUTOACK, &enable_val,
|
||||
sizeof(netopt_enable_t));
|
||||
if ((res > 0) && (enable_val == NETOPT_ENABLE)) {
|
||||
printf(" AUTOACK");
|
||||
}
|
||||
res = get((netdev2_t *)dev, NETOPT_RAWMODE, &enable_val,
|
||||
sizeof(netopt_enable_t));
|
||||
if ((res > 0) && (enable_val == NETOPT_ENABLE)) {
|
||||
printf(" RAW");
|
||||
}
|
||||
res = get((netdev2_t *)dev, NETOPT_AUTOCCA, &enable_val,
|
||||
sizeof(netopt_enable_t));
|
||||
if ((res > 0) && (enable_val == NETOPT_ENABLE)) {
|
||||
printf(" AUTOCCA");
|
||||
}
|
||||
res = get((netdev2_t *)dev, NETOPT_CSMA, &enable_val,
|
||||
sizeof(netopt_enable_t));
|
||||
if ((res > 0) && (enable_val == NETOPT_ENABLE)) {
|
||||
printf(" CSMA");
|
||||
}
|
||||
puts("");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ifconfig(int argc, char **argv)
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
for (int i = 0; i < AT86RF2XX_NUM; i++) {
|
||||
ifconfig_list(i);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void txtsnd_usage(char *cmd_name)
|
||||
{
|
||||
printf("usage: %s <iface> [<pan>] <addr> <text>\n", cmd_name);
|
||||
}
|
||||
|
||||
int txtsnd(int argc, char **argv)
|
||||
{
|
||||
char *text;
|
||||
uint8_t addr[_MAX_ADDR_LEN];
|
||||
int iface, idx = 2, res;
|
||||
le_uint16_t pan = { 0 };
|
||||
|
||||
switch (argc) {
|
||||
case 4:
|
||||
break;
|
||||
case 5:
|
||||
res = _parse_addr((uint8_t *)&pan, sizeof(pan), argv[idx++]);
|
||||
if ((res <= 0) || (res > sizeof(pan))) {
|
||||
txtsnd_usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
pan.u16 = byteorder_swaps(pan.u16);
|
||||
break;
|
||||
default:
|
||||
txtsnd_usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
iface = atoi(argv[1]);
|
||||
res = _parse_addr(addr, sizeof(addr), argv[idx++]);
|
||||
if (res <= 0) {
|
||||
txtsnd_usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
text = argv[idx++];
|
||||
return send(iface, pan, addr, (size_t)res, text);
|
||||
}
|
||||
|
||||
static inline int _dehex(char c, int default_)
|
||||
{
|
||||
if ('0' <= c && c <= '9') {
|
||||
return c - '0';
|
||||
}
|
||||
else if ('A' <= c && c <= 'F') {
|
||||
return c - 'A' + 10;
|
||||
}
|
||||
else if ('a' <= c && c <= 'f') {
|
||||
return c - 'a' + 10;
|
||||
}
|
||||
else {
|
||||
return default_;
|
||||
}
|
||||
}
|
||||
|
||||
static int _parse_addr(uint8_t *out, size_t out_len, const char *in)
|
||||
{
|
||||
const char *end_str = in;
|
||||
uint8_t *out_end = out;
|
||||
size_t count = 0;
|
||||
int assert_cell = 1;
|
||||
|
||||
if (!in || !*in) {
|
||||
return 0;
|
||||
}
|
||||
while (end_str[1]) {
|
||||
++end_str;
|
||||
}
|
||||
|
||||
while (end_str >= in) {
|
||||
int a = 0, b = _dehex(*end_str--, -1);
|
||||
if (b < 0) {
|
||||
if (assert_cell) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
assert_cell = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
assert_cell = 0;
|
||||
|
||||
if (end_str >= in) {
|
||||
a = _dehex(*end_str--, 0);
|
||||
}
|
||||
|
||||
if (++count > out_len) {
|
||||
return 0;
|
||||
}
|
||||
*out_end++ = (a << 4) | b;
|
||||
}
|
||||
if (assert_cell) {
|
||||
return 0;
|
||||
}
|
||||
/* out is reversed */
|
||||
|
||||
while (out < --out_end) {
|
||||
uint8_t tmp = *out_end;
|
||||
*out_end = *out;
|
||||
*out++ = tmp;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int send(int iface, le_uint16_t dst_pan, uint8_t *dst, size_t dst_len,
|
||||
char *data)
|
||||
{
|
||||
int res;
|
||||
netdev2_ieee802154_t *dev;
|
||||
const size_t count = 2; /* mhr + payload */
|
||||
struct iovec vector[count];
|
||||
uint8_t *src;
|
||||
size_t src_len;
|
||||
uint8_t mhr[IEEE802154_MAX_HDR_LEN];
|
||||
uint8_t flags;
|
||||
le_uint16_t src_pan;
|
||||
|
||||
if (((unsigned)iface) > (AT86RF2XX_NUM - 1)) {
|
||||
printf("txtsnd: %d is not an interface\n", iface);
|
||||
return 1;
|
||||
}
|
||||
|
||||
dev = (netdev2_ieee802154_t *)&devs[iface];
|
||||
flags = (uint8_t)(dev->flags & NETDEV2_IEEE802154_SEND_MASK);
|
||||
flags |= IEEE802154_FCF_TYPE_DATA;
|
||||
vector[1].iov_base = data;
|
||||
vector[1].iov_len = strlen(data);
|
||||
src_pan = byteorder_btols(byteorder_htons(dev->pan));
|
||||
if (dst_pan.u16 == 0) {
|
||||
dst_pan = src_pan;
|
||||
}
|
||||
if (dev->flags & NETDEV2_IEEE802154_SRC_MODE_LONG) {
|
||||
src_len = 8;
|
||||
src = dev->long_addr;
|
||||
}
|
||||
else {
|
||||
src_len = 2;
|
||||
src = dev->short_addr;
|
||||
}
|
||||
/* fill MAC header, seq should be set by device */
|
||||
if ((res = ieee802154_set_frame_hdr(mhr, src, src_len,
|
||||
dst, dst_len,
|
||||
src_pan, dst_pan,
|
||||
flags, dev->seq++)) < 0) {
|
||||
puts("txtsnd: Error preperaring frame");
|
||||
return 1;
|
||||
}
|
||||
vector[0].iov_base = mhr;
|
||||
vector[0].iov_len = (size_t)res;
|
||||
res = dev->netdev.driver->send((netdev2_t *)dev, vector, count);
|
||||
if (res < 0) {
|
||||
puts("txtsnd: Error on sending");
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
printf("txtsnd: send %u bytes to ", (unsigned)vector[1].iov_len);
|
||||
print_addr(dst, dst_len);
|
||||
printf(" (PAN: ");
|
||||
print_addr((uint8_t *)&dst_pan, sizeof(dst_pan));
|
||||
puts(")");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @} */
|
53
tests/driver_at86rf2xx/common.h
Normal file
53
tests/driver_at86rf2xx/common.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Martine 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup tests
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Common header for at86rf2xx tests
|
||||
*
|
||||
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
|
||||
*/
|
||||
#ifndef COMMON_H_
|
||||
#define COMMON_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "at86rf2xx.h"
|
||||
#include "at86rf2xx_params.h"
|
||||
#include "net/netdev2.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Application-internal functions and variables for at86rf2xx tests
|
||||
* @internal
|
||||
* @{
|
||||
*/
|
||||
#define AT86RF2XX_NUM (sizeof(at86rf2xx_params) / sizeof(at86rf2xx_params[0]))
|
||||
|
||||
extern at86rf2xx_t devs[AT86RF2XX_NUM];
|
||||
|
||||
void recv(netdev2_t *dev);
|
||||
int ifconfig(int argc, char **argv);
|
||||
int txtsnd(int argc, char **argv);
|
||||
void print_addr(uint8_t *addr, size_t addr_len);
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* COMMON_H_ */
|
||||
/** @} */
|
@ -20,31 +20,102 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "net/netdev2.h"
|
||||
#include "shell.h"
|
||||
#include "shell_commands.h"
|
||||
#include "net/gnrc/pktdump.h"
|
||||
#include "net/gnrc.h"
|
||||
#include "thread.h"
|
||||
#include "xtimer.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#define _STACKSIZE (THREAD_STACKSIZE_DEFAULT + THREAD_EXTRA_STACKSIZE_PRINTF)
|
||||
#define MSG_TYPE_ISR (0x3456)
|
||||
|
||||
static char stack[_STACKSIZE];
|
||||
static kernel_pid_t _recv_pid;
|
||||
|
||||
at86rf2xx_t devs[AT86RF2XX_NUM];
|
||||
|
||||
static const shell_command_t shell_commands[] = {
|
||||
{ "ifconfig", "Configure netdev2", ifconfig },
|
||||
{ "txtsnd", "Send IEEE 802.15.4 packet", txtsnd },
|
||||
{ NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
static void _event_cb(netdev2_t *dev, netdev2_event_t event, void *data)
|
||||
{
|
||||
(void) data;
|
||||
|
||||
if (event == NETDEV2_EVENT_ISR) {
|
||||
msg_t msg;
|
||||
|
||||
msg.type = MSG_TYPE_ISR;
|
||||
msg.content.ptr = (void *) dev;
|
||||
|
||||
if (msg_send(&msg, _recv_pid) <= 0) {
|
||||
puts("gnrc_netdev2: possibly lost interrupt.");
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch (event) {
|
||||
case NETDEV2_EVENT_RX_COMPLETE:
|
||||
{
|
||||
recv(dev);
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
puts("Unexpected event received");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void *_recv_thread(void *arg)
|
||||
{
|
||||
while (1) {
|
||||
msg_t msg;
|
||||
msg_receive(&msg);
|
||||
if (msg.type == MSG_TYPE_ISR) {
|
||||
netdev2_t *dev = (netdev2_t *)msg.content.ptr;
|
||||
dev->driver->isr(dev);
|
||||
}
|
||||
else {
|
||||
puts("unexpected message type");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Maybe you are a golfer?!
|
||||
*/
|
||||
int main(void)
|
||||
{
|
||||
gnrc_netreg_entry_t dump;
|
||||
|
||||
puts("AT86RF2xx device driver test");
|
||||
xtimer_init();
|
||||
|
||||
/* register the pktdump thread */
|
||||
puts("Register the packet dump thread for GNRC_NETTYPE_UNDEF packets");
|
||||
dump.pid = gnrc_pktdump_pid;
|
||||
dump.demux_ctx = GNRC_NETREG_DEMUX_CTX_ALL;
|
||||
gnrc_netreg_register(GNRC_NETTYPE_UNDEF, &dump);
|
||||
for (unsigned i = 0; i < AT86RF2XX_NUM; i++) {
|
||||
const at86rf2xx_params_t *p = &at86rf2xx_params[i];
|
||||
netdev2_t *dev = (netdev2_t *)(&devs[i]);
|
||||
|
||||
printf("Initializing AT86RF2xx radio at SPI_%d\n", p->spi);
|
||||
at86rf2xx_setup(&devs[i], p->spi, p->spi_speed, p->cs_pin,
|
||||
p->int_pin, p->sleep_pin, p->reset_pin);
|
||||
dev->event_callback = _event_cb;
|
||||
dev->driver->init(dev);
|
||||
}
|
||||
|
||||
_recv_pid = thread_create(stack, sizeof(stack), THREAD_PRIORITY_MAIN - 1,
|
||||
THREAD_CREATE_STACKTEST, _recv_thread, NULL,
|
||||
"recv_thread");
|
||||
|
||||
if (_recv_pid <= KERNEL_PID_UNDEF) {
|
||||
puts("Creation of receiver thread failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* start the shell */
|
||||
puts("Initialization successful - starting the shell now");
|
||||
|
||||
char line_buf[SHELL_DEFAULT_BUFSIZE];
|
||||
shell_run(NULL, line_buf, SHELL_DEFAULT_BUFSIZE);
|
||||
shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
117
tests/driver_at86rf2xx/recv.c
Normal file
117
tests/driver_at86rf2xx/recv.c
Normal file
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (C) Freie Universität Berlin
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "at86rf2xx.h"
|
||||
#include "od.h"
|
||||
#include "net/ieee802154.h"
|
||||
#include "net/netdev2.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#define MAX_LINE (80)
|
||||
|
||||
static uint8_t buffer[AT86RF2XX_MAX_PKT_LENGTH];
|
||||
|
||||
void recv(netdev2_t *dev)
|
||||
{
|
||||
uint8_t src[IEEE802154_LONG_ADDRESS_LEN], dst[IEEE802154_LONG_ADDRESS_LEN];
|
||||
size_t mhr_len, data_len, src_len, dst_len;
|
||||
netdev2_ieee802154_rx_info_t rx_info;
|
||||
le_uint16_t src_pan, dst_pan;
|
||||
|
||||
putchar('\n');
|
||||
data_len = dev->driver->recv(dev, (char *)buffer, sizeof(buffer), &rx_info);
|
||||
mhr_len = ieee802154_get_frame_hdr_len(buffer);
|
||||
if (mhr_len == 0) {
|
||||
puts("Unexpected MHR for incoming packet");
|
||||
return;
|
||||
}
|
||||
dst_len = ieee802154_get_dst(buffer, dst, &dst_pan);
|
||||
src_len = ieee802154_get_src(buffer, src, &src_pan);
|
||||
switch (buffer[0] & IEEE802154_FCF_TYPE_MASK) {
|
||||
case IEEE802154_FCF_TYPE_BEACON:
|
||||
puts("BEACON");
|
||||
break;
|
||||
case IEEE802154_FCF_TYPE_DATA:
|
||||
puts("DATA");
|
||||
break;
|
||||
case IEEE802154_FCF_TYPE_ACK:
|
||||
puts("ACK");
|
||||
break;
|
||||
case IEEE802154_FCF_TYPE_MACCMD:
|
||||
puts("MACCMD");
|
||||
break;
|
||||
default:
|
||||
puts("UNKNOWN");
|
||||
break;
|
||||
}
|
||||
printf("Dest. PAN: 0x%04x, Dest. addr.: ",
|
||||
byteorder_ntohs(byteorder_ltobs(dst_pan)));
|
||||
print_addr(dst, dst_len);
|
||||
printf("\nSrc. PAN: 0x%04x, Src. addr.: ",
|
||||
byteorder_ntohs(byteorder_ltobs(src_pan)));
|
||||
print_addr(src, src_len);
|
||||
printf("\nSecurity: ");
|
||||
if (buffer[0] & IEEE802154_FCF_SECURITY_EN) {
|
||||
printf("1, ");
|
||||
}
|
||||
else {
|
||||
printf("0, ");
|
||||
}
|
||||
printf("Frame pend.: ");
|
||||
if (buffer[0] & IEEE802154_FCF_FRAME_PEND) {
|
||||
printf("1, ");
|
||||
}
|
||||
else {
|
||||
printf("0, ");
|
||||
}
|
||||
printf("ACK req.: ");
|
||||
if (buffer[0] & IEEE802154_FCF_ACK_REQ) {
|
||||
printf("1, ");
|
||||
}
|
||||
else {
|
||||
printf("0, ");
|
||||
}
|
||||
printf("PAN comp.: ");
|
||||
if (buffer[0] & IEEE802154_FCF_ACK_REQ) {
|
||||
puts("1");
|
||||
}
|
||||
else {
|
||||
puts("0");
|
||||
}
|
||||
printf("Version: ");
|
||||
printf("%u, ", (unsigned)((buffer[1] & IEEE802154_FCF_VERS_MASK) >> 4));
|
||||
printf("Seq.: %u\n", (unsigned)ieee802154_get_seq(buffer));
|
||||
od_hex_dump(buffer + mhr_len, data_len - mhr_len, 0);
|
||||
printf("txt: ");
|
||||
for (int i = mhr_len; i < data_len; i++) {
|
||||
if ((buffer[i] > 0x1F) && (buffer[i] < 0x80)) {
|
||||
putchar((char)buffer[i]);
|
||||
}
|
||||
else {
|
||||
putchar('?');
|
||||
}
|
||||
if (((((i - mhr_len) + 1) % (MAX_LINE - sizeof("txt: "))) == 1) &&
|
||||
(i - mhr_len) != 0) {
|
||||
printf("\n ");
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
printf("RSSI: %u, LQI: %u\n\n", rx_info.rssi, rx_info.lqi);
|
||||
}
|
||||
|
||||
/** @} */
|
Loading…
Reference in New Issue
Block a user