2015-08-09 21:24:55 +02:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2015 Freie Universität Berlin
|
2017-06-30 13:53:29 +02:00
|
|
|
* 2017 HAW Hamburg
|
2015-08-09 21:24:55 +02:00
|
|
|
*
|
|
|
|
* This file is subject to the terms and conditions of the GNU Lesser
|
|
|
|
* General Public License v2.1. See the file LICENSE in the top level
|
|
|
|
* directory for more details.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @ingroup drivers_at86rf2xx
|
|
|
|
* @{
|
|
|
|
*
|
|
|
|
* @file
|
|
|
|
* @brief Getter and setter functions for the AT86RF2xx drivers
|
|
|
|
*
|
|
|
|
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
|
|
|
|
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
|
|
|
* @author Baptiste Clenet <bapclenet@gmail.com>
|
2015-06-01 15:51:50 +02:00
|
|
|
* @author Daniel Krebs <github@daniel-krebs.net>
|
2015-10-22 23:01:26 +02:00
|
|
|
* @author Kévin Roussel <Kevin.Roussel@inria.fr>
|
2015-09-16 18:25:36 +02:00
|
|
|
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
|
2017-06-30 13:53:29 +02:00
|
|
|
* @author Sebastian Meiling <s@mlng.net>
|
2015-08-09 21:24:55 +02:00
|
|
|
* @}
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "at86rf2xx.h"
|
|
|
|
#include "at86rf2xx_internal.h"
|
|
|
|
#include "at86rf2xx_registers.h"
|
|
|
|
#include "periph/spi.h"
|
|
|
|
|
|
|
|
#define ENABLE_DEBUG (0)
|
|
|
|
#include "debug.h"
|
|
|
|
|
2015-08-12 17:08:42 +02:00
|
|
|
#ifdef MODULE_AT86RF212B
|
2015-08-09 21:24:55 +02:00
|
|
|
/* See: Table 9-15. Recommended Mapping of TX Power, Frequency Band, and
|
|
|
|
* PHY_TX_PWR (register 0x05), AT86RF212B data sheet. */
|
|
|
|
static const uint8_t dbm_to_tx_pow_868[] = {0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18,
|
|
|
|
0x17, 0x15, 0x14, 0x13, 0x12, 0x11,
|
|
|
|
0x10, 0x0f, 0x31, 0x30, 0x2f, 0x94,
|
|
|
|
0x93, 0x91, 0x90, 0x29, 0x49, 0x48,
|
|
|
|
0x47, 0xad, 0xcd, 0xcc, 0xcb, 0xea,
|
|
|
|
0xe9, 0xe8, 0xe7, 0xe6, 0xe4, 0x80,
|
|
|
|
0xa0};
|
|
|
|
static const uint8_t dbm_to_tx_pow_915[] = {0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x17,
|
|
|
|
0x16, 0x15, 0x14, 0x13, 0x12, 0x11,
|
|
|
|
0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b,
|
|
|
|
0x09, 0x91, 0x08, 0x07, 0x05, 0x27,
|
|
|
|
0x04, 0x03, 0x02, 0x01, 0x00, 0x86,
|
|
|
|
0x40, 0x84, 0x83, 0x82, 0x80, 0xc1,
|
|
|
|
0xc0};
|
2015-09-16 18:25:36 +02:00
|
|
|
|
2017-06-30 13:53:29 +02:00
|
|
|
static int16_t _tx_pow_to_dbm_212b(uint8_t channel, uint8_t page, uint8_t reg)
|
|
|
|
{
|
2015-09-16 18:25:36 +02:00
|
|
|
if (page == 0 || page == 2) {
|
2017-06-30 13:53:29 +02:00
|
|
|
const uint8_t *dbm_to_tx_pow;
|
|
|
|
size_t nelem;
|
|
|
|
|
2015-09-16 18:25:36 +02:00
|
|
|
if (channel == 0) {
|
2017-06-30 13:53:29 +02:00
|
|
|
/* Channel 0 is 868.3 MHz */
|
2015-09-16 18:25:36 +02:00
|
|
|
dbm_to_tx_pow = &dbm_to_tx_pow_868[0];
|
|
|
|
nelem = sizeof(dbm_to_tx_pow_868) / sizeof(dbm_to_tx_pow_868[0]);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* Channels 1+ are 915 MHz */
|
|
|
|
dbm_to_tx_pow = &dbm_to_tx_pow_915[0];
|
|
|
|
nelem = sizeof(dbm_to_tx_pow_915) / sizeof(dbm_to_tx_pow_915[0]);
|
|
|
|
}
|
|
|
|
|
2017-06-30 13:53:29 +02:00
|
|
|
for (size_t i = 0; i < nelem; ++i) {
|
|
|
|
if (dbm_to_tx_pow[i] == reg) {
|
|
|
|
return (i - AT86RF2XX_TXPOWER_OFF);
|
|
|
|
}
|
2015-08-09 21:24:55 +02:00
|
|
|
}
|
|
|
|
}
|
2017-06-30 13:53:29 +02:00
|
|
|
|
2015-08-09 21:24:55 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-08-12 17:08:42 +02:00
|
|
|
#elif MODULE_AT86RF233
|
2015-08-09 21:24:55 +02:00
|
|
|
static const int16_t tx_pow_to_dbm[] = {4, 4, 3, 3, 2, 2, 1,
|
|
|
|
0, -1, -2, -3, -4, -6, -8, -12, -17};
|
|
|
|
static const uint8_t dbm_to_tx_pow[] = {0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e,
|
|
|
|
0x0e, 0x0d, 0x0d, 0x0d, 0x0c, 0x0c,
|
|
|
|
0x0b, 0x0b, 0x0a, 0x09, 0x08, 0x07,
|
|
|
|
0x06, 0x05, 0x03,0x00};
|
|
|
|
#else
|
|
|
|
static const int16_t tx_pow_to_dbm[] = {3, 3, 2, 2, 1, 1, 0,
|
|
|
|
-1, -2, -3, -4, -5, -7, -9, -12, -17};
|
|
|
|
static const uint8_t dbm_to_tx_pow[] = {0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e,
|
|
|
|
0x0e, 0x0d, 0x0d, 0x0c, 0x0c, 0x0b,
|
|
|
|
0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06,
|
|
|
|
0x05, 0x03, 0x00};
|
|
|
|
#endif
|
|
|
|
|
2017-06-30 13:53:29 +02:00
|
|
|
uint16_t at86rf2xx_get_addr_short(const at86rf2xx_t *dev)
|
2015-08-09 21:24:55 +02:00
|
|
|
{
|
2016-03-18 10:26:33 +01:00
|
|
|
return (dev->netdev.short_addr[0] << 8) | dev->netdev.short_addr[1];
|
2015-08-09 21:24:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void at86rf2xx_set_addr_short(at86rf2xx_t *dev, uint16_t addr)
|
|
|
|
{
|
2016-03-18 10:26:33 +01:00
|
|
|
dev->netdev.short_addr[0] = (uint8_t)(addr);
|
|
|
|
dev->netdev.short_addr[1] = (uint8_t)(addr >> 8);
|
2015-11-03 03:02:04 +01:00
|
|
|
#ifdef MODULE_SIXLOWPAN
|
|
|
|
/* https://tools.ietf.org/html/rfc4944#section-12 requires the first bit to
|
|
|
|
* 0 for unicast addresses */
|
2016-03-18 10:26:33 +01:00
|
|
|
dev->netdev.short_addr[0] &= 0x7F;
|
2015-11-03 03:02:04 +01:00
|
|
|
#endif
|
2015-08-09 21:24:55 +02:00
|
|
|
at86rf2xx_reg_write(dev, AT86RF2XX_REG__SHORT_ADDR_0,
|
2016-03-18 10:26:33 +01:00
|
|
|
dev->netdev.short_addr[1]);
|
2015-08-09 21:24:55 +02:00
|
|
|
at86rf2xx_reg_write(dev, AT86RF2XX_REG__SHORT_ADDR_1,
|
2016-03-18 10:26:33 +01:00
|
|
|
dev->netdev.short_addr[0]);
|
2015-08-09 21:24:55 +02:00
|
|
|
}
|
|
|
|
|
2017-06-30 13:53:29 +02:00
|
|
|
uint64_t at86rf2xx_get_addr_long(const at86rf2xx_t *dev)
|
2015-08-09 21:24:55 +02:00
|
|
|
{
|
|
|
|
uint64_t addr;
|
|
|
|
uint8_t *ap = (uint8_t *)(&addr);
|
|
|
|
for (int i = 0; i < 8; i++) {
|
2016-03-18 10:26:33 +01:00
|
|
|
ap[i] = dev->netdev.long_addr[i];
|
2015-08-09 21:24:55 +02:00
|
|
|
}
|
|
|
|
return addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void at86rf2xx_set_addr_long(at86rf2xx_t *dev, uint64_t addr)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < 8; i++) {
|
2016-03-18 10:26:33 +01:00
|
|
|
dev->netdev.long_addr[i] = (uint8_t)(addr >> (i * 8));
|
2015-08-09 21:24:55 +02:00
|
|
|
at86rf2xx_reg_write(dev, (AT86RF2XX_REG__IEEE_ADDR_0 + i),
|
2016-03-18 10:26:33 +01:00
|
|
|
(addr >> ((7 - i) * 8)));
|
2015-08-09 21:24:55 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-30 13:53:29 +02:00
|
|
|
uint8_t at86rf2xx_get_chan(const at86rf2xx_t *dev)
|
2015-08-09 21:24:55 +02:00
|
|
|
{
|
2016-03-18 10:26:33 +01:00
|
|
|
return dev->netdev.chan;
|
2015-08-09 21:24:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void at86rf2xx_set_chan(at86rf2xx_t *dev, uint8_t channel)
|
|
|
|
{
|
make: fix various compile errors with Wextra
pkg, nordic_softdevice_ble: disable CFLAGS to omit compiler error
sys, pm_layered: fix casting nonscalar to the same type
cpu, stm32_common: fix type-limits, remove always true assert
cpu, stm32f4: fix pointer arithmetic in periph/i2c
drivers, at86rf2xx: fix type-limits where condition always true
saul, gpio: fix if no gpio configured for saul
cpu, saml21: add frequency check to periph/timer
driver, cc110x: fix unused param and type-limts errors
boards, wsn430-common: fix old-style-declaration
make: fix old style definition
drivers, sdcard_spi: fix old style typedef
driver, at30tse: remove unnecessary check
driver, nrf24: fix type-limit
driver, pn532: change buffer from char to uint8_t
tests/driver_sdcard: fix type limits
boards, feather-m0: add missing field inits
driver, tcs37727: fix type limits
pkg, emb6: disable some compiler warnings
tests/emb6: disable some compiler warings
pkg, openthread: fix sign compare and unused params
tests/trickle: fix struct init
tests/pthread_cooperation: fix type limits
board, mips-malta: remove feature periph_uart
shell: fix var size for netif command
gnrc, netif: fix sign-compare
gnrc, nib: fix sign-compare
shell: fix output in netif command
posix: fix type-limits in pthread_cond
2017-10-31 11:52:18 +01:00
|
|
|
if ((channel > AT86RF2XX_MAX_CHANNEL) ||
|
|
|
|
#if AT86RF2XX_MIN_CHANNEL /* is zero for sub-GHz */
|
|
|
|
(channel < AT86RF2XX_MIN_CHANNEL) ||
|
|
|
|
#endif
|
2016-03-18 10:26:33 +01:00
|
|
|
(dev->netdev.chan == channel)) {
|
2015-08-09 21:24:55 +02:00
|
|
|
return;
|
|
|
|
}
|
2015-09-16 18:25:36 +02:00
|
|
|
|
2016-03-18 10:26:33 +01:00
|
|
|
dev->netdev.chan = channel;
|
2015-09-16 18:25:36 +02:00
|
|
|
|
|
|
|
at86rf2xx_configure_phy(dev);
|
2015-08-09 21:24:55 +02:00
|
|
|
}
|
|
|
|
|
2017-06-30 13:53:29 +02:00
|
|
|
uint8_t at86rf2xx_get_page(const at86rf2xx_t *dev)
|
2015-08-09 21:24:55 +02:00
|
|
|
{
|
2015-09-16 18:25:36 +02:00
|
|
|
#ifdef MODULE_AT86RF212B
|
|
|
|
return dev->page;
|
|
|
|
#else
|
2016-10-18 10:21:54 +02:00
|
|
|
(void) dev;
|
2015-09-16 18:25:36 +02:00
|
|
|
return 0;
|
|
|
|
#endif
|
2015-08-09 21:24:55 +02:00
|
|
|
}
|
|
|
|
|
2015-09-16 18:25:36 +02:00
|
|
|
void at86rf2xx_set_page(at86rf2xx_t *dev, uint8_t page)
|
2015-08-09 21:24:55 +02:00
|
|
|
{
|
2015-09-16 18:25:36 +02:00
|
|
|
#ifdef MODULE_AT86RF212B
|
2017-06-30 13:53:29 +02:00
|
|
|
if ((page == 0) || (page == 2)) {
|
|
|
|
dev->page = page;
|
|
|
|
at86rf2xx_configure_phy(dev);
|
2015-08-09 21:24:55 +02:00
|
|
|
}
|
2016-10-18 10:21:54 +02:00
|
|
|
#else
|
|
|
|
(void) dev;
|
|
|
|
(void) page;
|
2015-08-09 21:24:55 +02:00
|
|
|
#endif
|
2015-09-16 18:25:36 +02:00
|
|
|
}
|
2015-08-09 21:24:55 +02:00
|
|
|
|
2017-06-30 13:53:29 +02:00
|
|
|
uint16_t at86rf2xx_get_pan(const at86rf2xx_t *dev)
|
2015-08-09 21:24:55 +02:00
|
|
|
{
|
2016-03-18 10:26:33 +01:00
|
|
|
return dev->netdev.pan;
|
2015-08-09 21:24:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void at86rf2xx_set_pan(at86rf2xx_t *dev, uint16_t pan)
|
|
|
|
{
|
2016-03-18 10:26:33 +01:00
|
|
|
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]);
|
2015-08-09 21:24:55 +02:00
|
|
|
}
|
|
|
|
|
2017-06-30 13:53:29 +02:00
|
|
|
int16_t at86rf2xx_get_txpower(const at86rf2xx_t *dev)
|
2015-08-09 21:24:55 +02:00
|
|
|
{
|
2015-08-12 17:08:42 +02:00
|
|
|
#ifdef MODULE_AT86RF212B
|
2015-08-09 21:24:55 +02:00
|
|
|
uint8_t txpower = at86rf2xx_reg_read(dev, AT86RF2XX_REG__PHY_TX_PWR);
|
|
|
|
DEBUG("txpower value: %x\n", txpower);
|
2016-03-18 10:26:33 +01:00
|
|
|
return _tx_pow_to_dbm_212b(dev->netdev.chan, dev->page, txpower);
|
2015-08-09 21:24:55 +02:00
|
|
|
#else
|
|
|
|
uint8_t txpower = at86rf2xx_reg_read(dev, AT86RF2XX_REG__PHY_TX_PWR)
|
|
|
|
& AT86RF2XX_PHY_TX_PWR_MASK__TX_PWR;
|
|
|
|
return tx_pow_to_dbm[txpower];
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2017-06-30 13:53:29 +02:00
|
|
|
void at86rf2xx_set_txpower(const at86rf2xx_t *dev, int16_t txpower)
|
2015-08-09 21:24:55 +02:00
|
|
|
{
|
2017-06-30 13:53:29 +02:00
|
|
|
txpower += AT86RF2XX_TXPOWER_OFF;
|
|
|
|
|
2015-08-09 21:24:55 +02:00
|
|
|
if (txpower < 0) {
|
|
|
|
txpower = 0;
|
|
|
|
}
|
2017-06-30 13:53:29 +02:00
|
|
|
else if (txpower > AT86RF2XX_TXPOWER_MAX) {
|
|
|
|
txpower = AT86RF2XX_TXPOWER_MAX;
|
2015-08-09 21:24:55 +02:00
|
|
|
}
|
2015-08-12 17:08:42 +02:00
|
|
|
#ifdef MODULE_AT86RF212B
|
2016-03-18 10:26:33 +01:00
|
|
|
if (dev->netdev.chan == 0) {
|
2015-08-09 21:24:55 +02:00
|
|
|
at86rf2xx_reg_write(dev, AT86RF2XX_REG__PHY_TX_PWR,
|
|
|
|
dbm_to_tx_pow_868[txpower]);
|
|
|
|
}
|
2016-03-18 10:26:33 +01:00
|
|
|
else if (dev->netdev.chan < 11) {
|
2015-09-16 18:25:36 +02:00
|
|
|
at86rf2xx_reg_write(dev, AT86RF2XX_REG__PHY_TX_PWR,
|
|
|
|
dbm_to_tx_pow_915[txpower]);
|
2015-08-09 21:24:55 +02:00
|
|
|
}
|
|
|
|
#else
|
|
|
|
at86rf2xx_reg_write(dev, AT86RF2XX_REG__PHY_TX_PWR,
|
|
|
|
dbm_to_tx_pow[txpower]);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2017-06-30 13:53:29 +02:00
|
|
|
uint8_t at86rf2xx_get_max_retries(const at86rf2xx_t *dev)
|
2015-08-09 21:24:55 +02:00
|
|
|
{
|
|
|
|
return (at86rf2xx_reg_read(dev, AT86RF2XX_REG__XAH_CTRL_0) >> 4);
|
|
|
|
}
|
|
|
|
|
2017-06-30 13:53:29 +02:00
|
|
|
void at86rf2xx_set_max_retries(const at86rf2xx_t *dev, uint8_t max)
|
2015-08-09 21:24:55 +02:00
|
|
|
{
|
|
|
|
uint8_t tmp = at86rf2xx_reg_read(dev, AT86RF2XX_REG__XAH_CTRL_0);
|
|
|
|
tmp &= ~(AT86RF2XX_XAH_CTRL_0__MAX_FRAME_RETRIES);
|
2017-06-30 13:53:29 +02:00
|
|
|
tmp |= ((max > 7) ? 7 : max) << 4;
|
2015-08-09 21:24:55 +02:00
|
|
|
at86rf2xx_reg_write(dev, AT86RF2XX_REG__XAH_CTRL_0, tmp);
|
|
|
|
}
|
|
|
|
|
2017-06-30 13:53:29 +02:00
|
|
|
uint8_t at86rf2xx_get_csma_max_retries(const at86rf2xx_t *dev)
|
2015-06-01 15:51:50 +02:00
|
|
|
{
|
|
|
|
uint8_t tmp;
|
|
|
|
tmp = at86rf2xx_reg_read(dev, AT86RF2XX_REG__XAH_CTRL_0);
|
|
|
|
tmp &= AT86RF2XX_XAH_CTRL_0__MAX_CSMA_RETRIES;
|
|
|
|
tmp >>= 1;
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
|
2017-06-30 13:53:29 +02:00
|
|
|
void at86rf2xx_set_csma_max_retries(const at86rf2xx_t *dev, int8_t retries)
|
2015-06-01 15:51:50 +02:00
|
|
|
{
|
|
|
|
retries = (retries > 5) ? 5 : retries; /* valid values: 0-5 */
|
|
|
|
retries = (retries < 0) ? 7 : retries; /* max < 0 => disable CSMA (set to 7) */
|
|
|
|
DEBUG("[at86rf2xx] opt: Set CSMA retries to %u\n", retries);
|
|
|
|
|
|
|
|
uint8_t tmp = at86rf2xx_reg_read(dev, AT86RF2XX_REG__XAH_CTRL_0);
|
|
|
|
tmp &= ~(AT86RF2XX_XAH_CTRL_0__MAX_CSMA_RETRIES);
|
|
|
|
tmp |= (retries << 1);
|
|
|
|
at86rf2xx_reg_write(dev, AT86RF2XX_REG__XAH_CTRL_0, tmp);
|
|
|
|
}
|
|
|
|
|
2017-06-30 13:53:29 +02:00
|
|
|
void at86rf2xx_set_csma_backoff_exp(const at86rf2xx_t *dev,
|
|
|
|
uint8_t min, uint8_t max)
|
2015-06-01 15:51:50 +02:00
|
|
|
{
|
|
|
|
max = (max > 8) ? 8 : max;
|
|
|
|
min = (min > max) ? max : min;
|
|
|
|
DEBUG("[at86rf2xx] opt: Set min BE=%u, max BE=%u\n", min, max);
|
|
|
|
|
2017-06-30 13:53:29 +02:00
|
|
|
at86rf2xx_reg_write(dev, AT86RF2XX_REG__CSMA_BE, (max << 4) | (min));
|
2015-06-01 15:51:50 +02:00
|
|
|
}
|
|
|
|
|
2017-06-30 13:53:29 +02:00
|
|
|
void at86rf2xx_set_csma_seed(const at86rf2xx_t *dev, const uint8_t entropy[2])
|
2015-06-01 15:51:50 +02:00
|
|
|
{
|
|
|
|
if(entropy == NULL) {
|
|
|
|
DEBUG("[at86rf2xx] opt: CSMA seed entropy is nullpointer\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
DEBUG("[at86rf2xx] opt: Set CSMA seed to 0x%x 0x%x\n", entropy[0], entropy[1]);
|
|
|
|
|
2017-06-30 13:53:29 +02:00
|
|
|
at86rf2xx_reg_write(dev, AT86RF2XX_REG__CSMA_SEED_0, entropy[0]);
|
2015-06-01 15:51:50 +02:00
|
|
|
|
|
|
|
uint8_t tmp = at86rf2xx_reg_read(dev, AT86RF2XX_REG__CSMA_SEED_1);
|
|
|
|
tmp &= ~(AT86RF2XX_CSMA_SEED_1__CSMA_SEED_1);
|
|
|
|
tmp |= entropy[1] & AT86RF2XX_CSMA_SEED_1__CSMA_SEED_1;
|
|
|
|
at86rf2xx_reg_write(dev, AT86RF2XX_REG__CSMA_SEED_1, tmp);
|
|
|
|
}
|
|
|
|
|
2017-06-30 13:53:29 +02:00
|
|
|
int8_t at86rf2xx_get_cca_threshold(const at86rf2xx_t *dev)
|
2015-10-22 23:01:26 +02:00
|
|
|
{
|
|
|
|
int8_t tmp = at86rf2xx_reg_read(dev, AT86RF2XX_REG__CCA_THRES);
|
|
|
|
tmp &= AT86RF2XX_CCA_THRES_MASK__CCA_ED_THRES;
|
|
|
|
tmp <<= 1;
|
|
|
|
return (RSSI_BASE_VAL + tmp);
|
|
|
|
}
|
|
|
|
|
2017-06-30 13:53:29 +02:00
|
|
|
void at86rf2xx_set_cca_threshold(const at86rf2xx_t *dev, int8_t value)
|
2015-10-22 23:01:26 +02:00
|
|
|
{
|
|
|
|
/* ensure the given value is negative, since a CCA threshold > 0 is
|
|
|
|
just impossible: thus, any positive value given is considered
|
|
|
|
to be the absolute value of the actually wanted threshold */
|
|
|
|
if (value > 0) {
|
|
|
|
value = -value;
|
|
|
|
}
|
|
|
|
/* transform the dBm value in the form
|
|
|
|
that will fit in the AT86RF2XX_REG__CCA_THRES register */
|
|
|
|
value -= RSSI_BASE_VAL;
|
|
|
|
value >>= 1;
|
|
|
|
value &= AT86RF2XX_CCA_THRES_MASK__CCA_ED_THRES;
|
|
|
|
value |= AT86RF2XX_CCA_THRES_MASK__RSVD_HI_NIBBLE;
|
|
|
|
at86rf2xx_reg_write(dev, AT86RF2XX_REG__CCA_THRES, value);
|
|
|
|
}
|
|
|
|
|
2017-09-04 20:16:07 +02:00
|
|
|
int8_t at86rf2xx_get_ed_level(at86rf2xx_t *dev)
|
|
|
|
{
|
|
|
|
uint8_t tmp = at86rf2xx_reg_read(dev, AT86RF2XX_REG__PHY_ED_LEVEL);
|
|
|
|
#if MODULE_AT86RF212B
|
|
|
|
/* AT86RF212B has different scale than the other variants */
|
|
|
|
int8_t ed = (int8_t)(((int16_t)tmp * 103) / 100) + RSSI_BASE_VAL;
|
|
|
|
#else
|
|
|
|
int8_t ed = (int8_t)tmp + RSSI_BASE_VAL;
|
|
|
|
#endif
|
|
|
|
return ed;
|
|
|
|
}
|
|
|
|
|
2015-08-09 21:24:55 +02:00
|
|
|
void at86rf2xx_set_option(at86rf2xx_t *dev, uint16_t option, bool state)
|
|
|
|
{
|
|
|
|
uint8_t tmp;
|
|
|
|
|
|
|
|
DEBUG("set option %i to %i\n", option, state);
|
|
|
|
|
|
|
|
/* set option field */
|
2017-06-30 13:47:12 +02:00
|
|
|
dev->netdev.flags = (state) ? (dev->netdev.flags | option)
|
|
|
|
: (dev->netdev.flags & ~option);
|
|
|
|
/* trigger option specific actions */
|
|
|
|
switch (option) {
|
|
|
|
case AT86RF2XX_OPT_CSMA:
|
|
|
|
if (state) {
|
2015-06-01 15:51:50 +02:00
|
|
|
DEBUG("[at86rf2xx] opt: enabling CSMA mode" \
|
|
|
|
"(4 retries, min BE: 3 max BE: 5)\n");
|
|
|
|
/* Initialize CSMA seed with hardware address */
|
2016-03-18 10:26:33 +01:00
|
|
|
at86rf2xx_set_csma_seed(dev, dev->netdev.long_addr);
|
2015-06-01 15:51:50 +02:00
|
|
|
at86rf2xx_set_csma_max_retries(dev, 4);
|
|
|
|
at86rf2xx_set_csma_backoff_exp(dev, 3, 5);
|
2017-06-30 13:47:12 +02:00
|
|
|
}
|
|
|
|
else {
|
2015-06-01 15:51:50 +02:00
|
|
|
DEBUG("[at86rf2xx] opt: disabling CSMA mode\n");
|
|
|
|
/* setting retries to -1 means CSMA disabled */
|
|
|
|
at86rf2xx_set_csma_max_retries(dev, -1);
|
2017-06-30 13:47:12 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case AT86RF2XX_OPT_PROMISCUOUS:
|
|
|
|
DEBUG("[at86rf2xx] opt: %s PROMISCUOUS mode\n",
|
2017-06-30 13:53:29 +02:00
|
|
|
(state ? "enable" : "disable"));
|
2017-06-30 13:47:12 +02:00
|
|
|
/* disable/enable auto ACKs in promiscuous mode */
|
|
|
|
tmp = at86rf2xx_reg_read(dev, AT86RF2XX_REG__CSMA_SEED_1);
|
|
|
|
tmp = (state) ? (tmp | AT86RF2XX_CSMA_SEED_1__AACK_DIS_ACK)
|
|
|
|
: (tmp & ~AT86RF2XX_CSMA_SEED_1__AACK_DIS_ACK);
|
|
|
|
at86rf2xx_reg_write(dev, AT86RF2XX_REG__CSMA_SEED_1, tmp);
|
|
|
|
/* enable/disable promiscuous mode */
|
|
|
|
tmp = at86rf2xx_reg_read(dev, AT86RF2XX_REG__XAH_CTRL_1);
|
|
|
|
tmp = (state) ? (tmp | AT86RF2XX_XAH_CTRL_1__AACK_PROM_MODE)
|
|
|
|
: (tmp & ~AT86RF2XX_XAH_CTRL_1__AACK_PROM_MODE);
|
|
|
|
at86rf2xx_reg_write(dev, AT86RF2XX_REG__XAH_CTRL_1, tmp);
|
|
|
|
break;
|
|
|
|
case AT86RF2XX_OPT_AUTOACK:
|
|
|
|
DEBUG("[at86rf2xx] opt: %s auto ACKs\n",
|
2017-06-30 13:53:29 +02:00
|
|
|
(state ? "enable" : "disable"));
|
2017-06-30 13:47:12 +02:00
|
|
|
tmp = at86rf2xx_reg_read(dev, AT86RF2XX_REG__CSMA_SEED_1);
|
|
|
|
tmp = (state) ? (tmp & ~AT86RF2XX_CSMA_SEED_1__AACK_DIS_ACK)
|
|
|
|
: (tmp | AT86RF2XX_CSMA_SEED_1__AACK_DIS_ACK);
|
|
|
|
at86rf2xx_reg_write(dev, AT86RF2XX_REG__CSMA_SEED_1, tmp);
|
|
|
|
break;
|
|
|
|
case AT86RF2XX_OPT_TELL_RX_START:
|
|
|
|
DEBUG("[at86rf2xx] opt: %s SFD IRQ\n",
|
2017-06-30 13:53:29 +02:00
|
|
|
(state ? "enable" : "disable"));
|
2017-06-30 13:47:12 +02:00
|
|
|
tmp = at86rf2xx_reg_read(dev, AT86RF2XX_REG__IRQ_MASK);
|
|
|
|
tmp = (state) ? (tmp | AT86RF2XX_IRQ_STATUS_MASK__RX_START)
|
|
|
|
: (tmp & ~AT86RF2XX_IRQ_STATUS_MASK__RX_START);
|
|
|
|
at86rf2xx_reg_write(dev, AT86RF2XX_REG__IRQ_MASK, tmp);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* do nothing */
|
|
|
|
break;
|
2015-08-09 21:24:55 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-06 15:09:00 +01:00
|
|
|
/**
|
|
|
|
* @brief Internal function to change state
|
|
|
|
* @details For all cases but AT86RF2XX_STATE_FORCE_TRX_OFF state and
|
|
|
|
* cmd parameter are the same.
|
|
|
|
*
|
|
|
|
* @param dev device to operate on
|
|
|
|
* @param state target state
|
|
|
|
* @param cmd command to initiate state transition
|
|
|
|
*/
|
|
|
|
|
|
|
|
static inline void _set_state(at86rf2xx_t *dev, uint8_t state, uint8_t cmd)
|
2015-08-09 21:24:55 +02:00
|
|
|
{
|
2015-12-06 15:09:00 +01:00
|
|
|
at86rf2xx_reg_write(dev, AT86RF2XX_REG__TRX_STATE, cmd);
|
2016-11-01 15:26:57 +01:00
|
|
|
|
|
|
|
/* To prevent a possible race condition when changing to
|
|
|
|
* RX_AACK_ON state the state doesn't get read back in that
|
|
|
|
* case. See discussion
|
|
|
|
* in https://github.com/RIOT-OS/RIOT/pull/5244
|
|
|
|
*/
|
|
|
|
if (state != AT86RF2XX_STATE_RX_AACK_ON) {
|
2017-06-11 20:08:10 +02:00
|
|
|
while (at86rf2xx_get_status(dev) != state) {}
|
2016-11-01 15:26:57 +01:00
|
|
|
}
|
2017-07-07 18:11:28 +02:00
|
|
|
/* Although RX_AACK_ON state doesn't get read back,
|
|
|
|
* at least make sure if state transition is in progress or not
|
|
|
|
*/
|
2017-07-07 12:48:46 +02:00
|
|
|
else {
|
|
|
|
while (at86rf2xx_get_status(dev) == AT86RF2XX_STATE_IN_PROGRESS) {}
|
|
|
|
}
|
2016-11-01 15:26:57 +01:00
|
|
|
|
2015-09-16 18:48:10 +02:00
|
|
|
dev->state = state;
|
2015-08-09 21:24:55 +02:00
|
|
|
}
|
|
|
|
|
2017-05-31 14:06:23 +02:00
|
|
|
uint8_t at86rf2xx_set_state(at86rf2xx_t *dev, uint8_t state)
|
2015-08-09 21:24:55 +02:00
|
|
|
{
|
2017-05-31 14:06:23 +02:00
|
|
|
uint8_t old_state;
|
2015-12-06 15:09:00 +01:00
|
|
|
|
2015-08-09 21:24:55 +02:00
|
|
|
/* make sure there is no ongoing transmission, or state transition already
|
|
|
|
* in progress */
|
2017-05-31 14:06:23 +02:00
|
|
|
do {
|
2015-08-09 21:24:55 +02:00
|
|
|
old_state = at86rf2xx_get_status(dev);
|
2017-05-31 14:06:23 +02:00
|
|
|
} while (old_state == AT86RF2XX_STATE_BUSY_RX_AACK ||
|
|
|
|
old_state == AT86RF2XX_STATE_BUSY_TX_ARET ||
|
|
|
|
old_state == AT86RF2XX_STATE_IN_PROGRESS);
|
|
|
|
|
|
|
|
if (state == AT86RF2XX_STATE_FORCE_TRX_OFF) {
|
|
|
|
_set_state(dev, AT86RF2XX_STATE_TRX_OFF, state);
|
2016-04-04 16:29:03 +02:00
|
|
|
}
|
2017-06-30 13:47:12 +02:00
|
|
|
else if (state != old_state) {
|
|
|
|
/* we need to go via PLL_ON if we are moving between RX_AACK_ON <-> TX_ARET_ON */
|
|
|
|
if ((old_state | state) == (AT86RF2XX_STATE_RX_AACK_ON | AT86RF2XX_STATE_TX_ARET_ON)) {
|
|
|
|
_set_state(dev, AT86RF2XX_STATE_PLL_ON, AT86RF2XX_STATE_PLL_ON);
|
|
|
|
}
|
|
|
|
/* check if we need to wake up from sleep mode */
|
|
|
|
if (state == AT86RF2XX_STATE_SLEEP) {
|
|
|
|
/* First go to TRX_OFF */
|
|
|
|
_set_state(dev, AT86RF2XX_STATE_TRX_OFF,
|
|
|
|
AT86RF2XX_STATE_FORCE_TRX_OFF);
|
|
|
|
/* Discard all IRQ flags, framebuffer is lost anyway */
|
|
|
|
at86rf2xx_reg_read(dev, AT86RF2XX_REG__IRQ_STATUS);
|
|
|
|
/* Go to SLEEP mode from TRX_OFF */
|
|
|
|
gpio_set(dev->params.sleep_pin);
|
|
|
|
dev->state = state;
|
|
|
|
} else {
|
|
|
|
if (old_state == AT86RF2XX_STATE_SLEEP) {
|
|
|
|
DEBUG("at86rf2xx: waking up from sleep mode\n");
|
|
|
|
at86rf2xx_assert_awake(dev);
|
|
|
|
}
|
|
|
|
_set_state(dev, state, state);
|
|
|
|
}
|
2015-08-09 21:24:55 +02:00
|
|
|
}
|
2017-05-31 14:06:23 +02:00
|
|
|
|
|
|
|
return old_state;
|
2015-08-09 21:24:55 +02:00
|
|
|
}
|