1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-12-25 14:33:52 +01:00

at86rf2xx: implement sleep mode

This commit is contained in:
daniel-k 2015-09-16 18:48:10 +02:00
parent 7bf121903a
commit 502786b9f7
5 changed files with 248 additions and 108 deletions

View File

@ -23,7 +23,6 @@
* @}
*/
#include "xtimer.h"
#include "periph/cpuid.h"
#include "byteorder.h"
#include "net/ieee802154.h"
@ -36,9 +35,6 @@
#include "debug.h"
#define RESET_DELAY (1U) /* must be > 625ns */
static void _irq_handler(void *arg)
{
msg_t msg;
@ -62,6 +58,7 @@ int at86rf2xx_init(at86rf2xx_t *dev, spi_t spi, spi_speed_t spi_speed,
dev->sleep_pin = sleep_pin;
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);
@ -74,6 +71,9 @@ int at86rf2xx_init(at86rf2xx_t *dev, spi_t spi, spi_speed_t spi_speed,
gpio_set(dev->reset_pin);
gpio_init_int(dev->int_pin, GPIO_NOPULL, 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) {
@ -83,6 +83,7 @@ int at86rf2xx_init(at86rf2xx_t *dev, spi_t spi, spi_speed_t spi_speed,
/* reset device to default values and put it into RX state */
at86rf2xx_reset(dev);
return 0;
}
@ -93,12 +94,7 @@ void at86rf2xx_reset(at86rf2xx_t *dev)
eui64_t addr_long;
#endif
/* wake from sleep in case radio is sleeping */
gpio_clear(dev->sleep_pin);
/* trigger hardware reset */
gpio_clear(dev->reset_pin);
xtimer_usleep(RESET_DELAY);
gpio_set(dev->reset_pin);
at86rf2xx_hardware_reset(dev);
/* Reset state machine to ensure a known state */
at86rf2xx_reset_state_machine(dev);
@ -184,6 +180,8 @@ bool at86rf2xx_cca(at86rf2xx_t *dev)
uint8_t tmp;
uint8_t status;
at86rf2xx_assert_awake(dev);
/* trigger CCA measurment */
tmp = at86rf2xx_reg_read(dev, AT86RF2XX_REG__PHY_CC_CCA);
tmp &= AT86RF2XX_PHY_CC_CCA_MASK__CCA_REQUEST;

View File

@ -399,6 +399,7 @@ static inline void _set_state(at86rf2xx_t *dev, uint8_t state)
{
at86rf2xx_reg_write(dev, AT86RF2XX_REG__TRX_STATE, state);
while (at86rf2xx_get_status(dev) != state);
dev->state = state;
}
void at86rf2xx_set_state(at86rf2xx_t *dev, uint8_t state)
@ -426,15 +427,17 @@ void at86rf2xx_set_state(at86rf2xx_t *dev, uint8_t state)
/* check if we need to wake up from sleep mode */
else if (old_state == AT86RF2XX_STATE_SLEEP) {
DEBUG("at86rf2xx: waking up from sleep mode\n");
gpio_clear(dev->sleep_pin);
while (at86rf2xx_get_status(dev) != AT86RF2XX_STATE_TRX_OFF);
at86rf2xx_assert_awake(dev);
}
if (state == AT86RF2XX_STATE_SLEEP) {
/* First go to TRX_OFF */
at86rf2xx_force_trx_off(dev);
/* 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->sleep_pin);
dev->state = state;
} else {
_set_state(dev, state);
}
@ -444,8 +447,7 @@ void at86rf2xx_reset_state_machine(at86rf2xx_t *dev)
{
uint8_t old_state;
/* Wake up */
gpio_clear(dev->sleep_pin);
at86rf2xx_assert_awake(dev);
/* Wait for any state transitions to complete before forcing TRX_OFF */
do {

View File

@ -24,6 +24,7 @@
#include "periph/spi.h"
#include "periph/gpio.h"
#include "xtimer.h"
#include "at86rf2xx_internal.h"
#include "at86rf2xx_registers.h"
@ -101,8 +102,38 @@ void at86rf2xx_fb_read(const at86rf2xx_t *dev,
uint8_t at86rf2xx_get_status(const at86rf2xx_t *dev)
{
return (at86rf2xx_reg_read(dev, AT86RF2XX_REG__TRX_STATUS)
& AT86RF2XX_TRX_STATUS_MASK__TRX_STATUS);
/* if sleeping immediately return state */
if(dev->state == AT86RF2XX_STATE_SLEEP)
return dev->state;
return at86rf2xx_reg_read(dev, AT86RF2XX_REG__TRX_STATUS)
& AT86RF2XX_TRX_STATUS_MASK__TRX_STATUS;
}
void at86rf2xx_assert_awake(at86rf2xx_t *dev)
{
if(at86rf2xx_get_status(dev) == AT86RF2XX_STATE_SLEEP) {
/* wake up and wait for transition to TRX_OFF */
gpio_clear(dev->sleep_pin);
xtimer_usleep(AT86RF2XX_WAKEUP_DELAY);
/* update state */
dev->state = at86rf2xx_reg_read(dev, AT86RF2XX_REG__TRX_STATUS)
& AT86RF2XX_TRX_STATUS_MASK__TRX_STATUS;
}
}
void at86rf2xx_hardware_reset(at86rf2xx_t *dev)
{
/* wake up from sleep in case radio is sleeping */
at86rf2xx_assert_awake(dev);
/* trigger hardware reset */
gpio_clear(dev->reset_pin);
xtimer_usleep(AT86RF2XX_RESET_PULSE_WIDTH);
gpio_set(dev->reset_pin);
xtimer_usleep(AT86RF2XX_RESET_DELAY);
}
void at86rf2xx_force_trx_off(const at86rf2xx_t *dev)

View File

@ -322,7 +322,7 @@ static int _set_state(at86rf2xx_t *dev, netopt_state_t state)
{
switch (state) {
case NETOPT_STATE_SLEEP:
at86rf2xx_set_state(dev, AT86RF2XX_STATE_TRX_OFF);
at86rf2xx_set_state(dev, AT86RF2XX_STATE_SLEEP);
break;
case NETOPT_STATE_IDLE:
at86rf2xx_set_state(dev, AT86RF2XX_STATE_RX_AACK_ON);
@ -359,11 +359,13 @@ netopt_state_t _get_state(at86rf2xx_t *dev)
static int _get(gnrc_netdev_t *device, netopt_t opt, void *val, size_t max_len)
{
at86rf2xx_t *dev = (at86rf2xx_t *) device;
if (device == NULL) {
return -ENODEV;
}
at86rf2xx_t *dev = (at86rf2xx_t *) device;
/* getting these options doesn't require the transceiver to be responsive */
switch (opt) {
case NETOPT_ADDRESS:
@ -435,13 +437,6 @@ static int _get(gnrc_netdev_t *device, netopt_t opt, void *val, size_t max_len)
((uint8_t *)val)[0] = at86rf2xx_get_chan(dev);
return sizeof(uint16_t);
case NETOPT_TX_POWER:
if (max_len < sizeof(int16_t)) {
return -EOVERFLOW;
}
*((uint16_t *)val) = at86rf2xx_get_txpower(dev);
return sizeof(uint16_t);
case NETOPT_MAX_PACKET_SIZE:
if (max_len < sizeof(int16_t)) {
return -EOVERFLOW;
@ -454,7 +449,7 @@ static int _get(gnrc_netdev_t *device, netopt_t opt, void *val, size_t max_len)
return -EOVERFLOW;
}
*((netopt_state_t*)val) = _get_state(dev);
break;
return sizeof(netopt_state_t);
case NETOPT_PRELOADING:
if (dev->options & AT86RF2XX_OPT_PRELOADING) {
@ -474,13 +469,6 @@ static int _get(gnrc_netdev_t *device, netopt_t opt, void *val, size_t max_len)
}
return sizeof(netopt_enable_t);
case NETOPT_RETRANS:
if (max_len < sizeof(uint8_t)) {
return -EOVERFLOW;
}
*((uint8_t *)val) = at86rf2xx_get_max_retries(dev);
return sizeof(uint8_t);
case NETOPT_PROMISCUOUSMODE:
if (dev->options & AT86RF2XX_OPT_PROMISCUOUS) {
*((netopt_enable_t *)val) = NETOPT_ENABLE;
@ -499,15 +487,6 @@ static int _get(gnrc_netdev_t *device, netopt_t opt, void *val, size_t max_len)
}
return sizeof(netopt_enable_t);
case NETOPT_IS_CHANNEL_CLR:
if (at86rf2xx_cca(dev)) {
*((netopt_enable_t *)val) = NETOPT_ENABLE;
}
else {
*((netopt_enable_t *)val) = NETOPT_DISABLE;
}
return sizeof(netopt_enable_t);
case NETOPT_RX_START_IRQ:
*((netopt_enable_t *)val) =
!!(dev->options & AT86RF2XX_OPT_TELL_RX_START);
@ -533,161 +512,253 @@ static int _get(gnrc_netdev_t *device, netopt_t opt, void *val, size_t max_len)
!!(dev->options & AT86RF2XX_OPT_CSMA);
return sizeof(netopt_enable_t);
case NETOPT_CSMA_RETRIES:
if (max_len < sizeof(uint8_t)) {
return -EOVERFLOW;
}
*((uint8_t *)val) = at86rf2xx_get_csma_max_retries(dev);
return sizeof(uint8_t);
default:
return -ENOTSUP;
/* Can still be handled in second switch */
break;
}
return 0;
uint8_t old_state = at86rf2xx_get_status(dev);
int res = 0;
/* temporarily wake up if sleeping */
if(old_state == AT86RF2XX_STATE_SLEEP) {
at86rf2xx_assert_awake(dev);
}
/* these options require the transceiver to be not sleeping*/
switch (opt) {
case NETOPT_TX_POWER:
if (max_len < sizeof(int16_t)) {
res = -EOVERFLOW;
} else {
*((uint16_t *)val) = at86rf2xx_get_txpower(dev);
res = sizeof(uint16_t);
}
break;
case NETOPT_RETRANS:
if (max_len < sizeof(uint8_t)) {
res = -EOVERFLOW;
} else {
*((uint8_t *)val) = at86rf2xx_get_max_retries(dev);
res = sizeof(uint8_t);
}
break;
case NETOPT_IS_CHANNEL_CLR:
if (at86rf2xx_cca(dev)) {
*((netopt_enable_t *)val) = NETOPT_ENABLE;
}
else {
*((netopt_enable_t *)val) = NETOPT_DISABLE;
}
res = sizeof(netopt_enable_t);
break;
case NETOPT_CSMA_RETRIES:
if (max_len < sizeof(uint8_t)) {
res = -EOVERFLOW;
} else {
*((uint8_t *)val) = at86rf2xx_get_csma_max_retries(dev);
res = sizeof(uint8_t);
}
break;
default:
res = -ENOTSUP;
}
/* go back to sleep if were sleeping */
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)
{
at86rf2xx_t *dev = (at86rf2xx_t *) device;
uint8_t old_state = at86rf2xx_get_status(dev);
int res = 0;
if (dev == NULL) {
return -ENODEV;
}
/* temporarily wake up if sleeping */
if(old_state == AT86RF2XX_STATE_SLEEP) {
at86rf2xx_assert_awake(dev);
}
switch (opt) {
case NETOPT_ADDRESS:
if (len > sizeof(uint16_t)) {
return -EOVERFLOW;
res = -EOVERFLOW;
} else {
at86rf2xx_set_addr_short(dev, *((uint16_t*)val));
res = sizeof(uint16_t);
}
at86rf2xx_set_addr_short(dev, *((uint16_t*)val));
return sizeof(uint16_t);
break;
case NETOPT_ADDRESS_LONG:
if (len > sizeof(uint64_t)) {
return -EOVERFLOW;
res = -EOVERFLOW;
} else {
at86rf2xx_set_addr_long(dev, *((uint64_t*)val));
res = sizeof(uint64_t);
}
at86rf2xx_set_addr_long(dev, *((uint64_t*)val));
return sizeof(uint64_t);
break;
case NETOPT_SRC_LEN:
if (len > sizeof(uint16_t)) {
return -EOVERFLOW;
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);
}
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 {
return -ENOTSUP;
}
return sizeof(uint16_t);
break;
case NETOPT_NID:
if (len > sizeof(uint16_t)) {
return -EOVERFLOW;
res = -EOVERFLOW;
} else {
at86rf2xx_set_pan(dev, *((uint16_t *)val));
res = sizeof(uint16_t);
}
at86rf2xx_set_pan(dev, *((uint16_t *)val));
return sizeof(uint16_t);
break;
case NETOPT_CHANNEL:
if (len != sizeof(uint16_t)) {
return -EINVAL;
res = -EINVAL;
} else {
uint8_t chan = ((uint8_t *)val)[0];
if (chan < AT86RF2XX_MIN_CHANNEL ||
chan > AT86RF2XX_MAX_CHANNEL) {
res = -ENOTSUP;
break;
}
at86rf2xx_set_chan(dev, chan);
res = sizeof(uint16_t);
}
uint8_t chan = ((uint8_t *)val)[0];
if (chan < AT86RF2XX_MIN_CHANNEL ||
chan > AT86RF2XX_MAX_CHANNEL) {
return -ENOTSUP;
}
at86rf2xx_set_chan(dev, chan);
return sizeof(uint16_t);
break;
case NETOPT_TX_POWER:
if (len > sizeof(int16_t)) {
return -EOVERFLOW;
res = -EOVERFLOW;
} else {
at86rf2xx_set_txpower(dev, *((int16_t *)val));
res = sizeof(uint16_t);
}
at86rf2xx_set_txpower(dev, *((int16_t *)val));
return sizeof(uint16_t);
break;
case NETOPT_STATE:
if (len > sizeof(netopt_state_t)) {
return -EOVERFLOW;
res = -EOVERFLOW;
} else {
res = _set_state(dev, *((netopt_state_t *)val));
}
return _set_state(dev, *((netopt_state_t *)val));
break;
case NETOPT_AUTOACK:
at86rf2xx_set_option(dev, AT86RF2XX_OPT_AUTOACK,
((bool *)val)[0]);
return sizeof(netopt_enable_t);
res = sizeof(netopt_enable_t);
break;
case NETOPT_RETRANS:
if (len > sizeof(uint8_t)) {
return -EOVERFLOW;
res = -EOVERFLOW;
} else {
at86rf2xx_set_max_retries(dev, *((uint8_t *)val));
res = sizeof(uint8_t);
}
at86rf2xx_set_max_retries(dev, *((uint8_t *)val));
return sizeof(uint8_t);
break;
case NETOPT_PRELOADING:
at86rf2xx_set_option(dev, AT86RF2XX_OPT_PRELOADING,
((bool *)val)[0]);
return sizeof(netopt_enable_t);
res = sizeof(netopt_enable_t);
break;
case NETOPT_PROMISCUOUSMODE:
at86rf2xx_set_option(dev, AT86RF2XX_OPT_PROMISCUOUS,
((bool *)val)[0]);
return sizeof(netopt_enable_t);
res = sizeof(netopt_enable_t);
break;
case NETOPT_RAWMODE:
at86rf2xx_set_option(dev, AT86RF2XX_OPT_RAWDUMP,
((bool *)val)[0]);
return sizeof(netopt_enable_t);
res = sizeof(netopt_enable_t);
break;
case NETOPT_RX_START_IRQ:
at86rf2xx_set_option(dev, AT86RF2XX_OPT_TELL_RX_START,
((bool *)val)[0]);
return sizeof(netopt_enable_t);
res = sizeof(netopt_enable_t);
break;
case NETOPT_RX_END_IRQ:
at86rf2xx_set_option(dev, AT86RF2XX_OPT_TELL_RX_END,
((bool *)val)[0]);
return sizeof(netopt_enable_t);
res = sizeof(netopt_enable_t);
break;
case NETOPT_TX_START_IRQ:
at86rf2xx_set_option(dev, AT86RF2XX_OPT_TELL_TX_START,
((bool *)val)[0]);
return sizeof(netopt_enable_t);
res = sizeof(netopt_enable_t);
break;
case NETOPT_TX_END_IRQ:
at86rf2xx_set_option(dev, AT86RF2XX_OPT_TELL_TX_END,
((bool *)val)[0]);
return sizeof(netopt_enable_t);
res = sizeof(netopt_enable_t);
break;
case NETOPT_CSMA:
at86rf2xx_set_option(dev, AT86RF2XX_OPT_CSMA,
((bool *)val)[0]);
return sizeof(netopt_enable_t);
res = sizeof(netopt_enable_t);
break;
case NETOPT_CSMA_RETRIES:
if( (len > sizeof(uint8_t)) ||
(*((uint8_t *)val) > 5) ) {
return -EOVERFLOW;
res = -EOVERFLOW;
} else if( !(dev->options & AT86RF2XX_OPT_CSMA) ) {
/* If CSMA is disabled, don't allow setting retries */
res = -ENOTSUP;
} else {
at86rf2xx_set_csma_max_retries(dev, *((uint8_t *)val));
res = sizeof(uint8_t);
}
/* If CSMA is disabled, don't allow setting retries */
if( !(dev->options & AT86RF2XX_OPT_CSMA) ) {
return -ENOTSUP;
}
at86rf2xx_set_csma_max_retries(dev, *((uint8_t *)val));
return sizeof(uint8_t);
break;
default:
return -ENOTSUP;
res = -ENOTSUP;
}
return 0;
/* go back to sleep if were sleeping and state hasn't been changed */
if( (old_state == AT86RF2XX_STATE_SLEEP) &&
(opt != NETOPT_STATE) ) {
at86rf2xx_set_state(dev, AT86RF2XX_STATE_SLEEP);
}
return res;
}
static int _add_event_cb(gnrc_netdev_t *dev, gnrc_netdev_event_cb_t cb)
@ -723,10 +794,16 @@ static void _isr_event(gnrc_netdev_t *device, uint32_t event_type)
uint8_t state;
uint8_t trac_status;
/* If transceiver is sleeping register access is impossible and frames are
* lost anyway, so return immediately.
*/
state = at86rf2xx_get_status(dev);
if(state == AT86RF2XX_STATE_SLEEP)
return;
/* read (consume) device status */
irq_mask = at86rf2xx_reg_read(dev, AT86RF2XX_REG__IRQ_STATUS);
state = at86rf2xx_get_status(dev);
trac_status = at86rf2xx_reg_read(dev, AT86RF2XX_REG__TRX_STATE) &
AT86RF2XX_TRX_STATE_MASK__TRAC;

View File

@ -31,6 +31,23 @@
extern "C" {
#endif
/**
* @brief Transition time from SLEEP to TRX_OFF in us, refer figure 7-4, p.42.
* For different environments refer figure 13-13, p.201
*/
#define AT86RF2XX_WAKEUP_DELAY (300U)
/**
* @brief Minimum reset pulse width, refer p.190
*/
#define AT86RF2XX_RESET_PULSE_WIDTH (1U)
/**
* @brief Transition time to TRX_OFF after reset pulse in us, refer
* figure 7-8, p. 44.
*/
#define AT86RF2XX_RESET_DELAY (26U)
/**
* @brief Read from a register at address `addr` from device `dev`.
*
@ -106,6 +123,21 @@ void at86rf2xx_force_trx_off(const at86rf2xx_t *dev);
*/
uint8_t at86rf2xx_get_status(const at86rf2xx_t *dev);
/**
* @brief Make sure that device is not sleeping
*
* @param[in] dev device to eventually wake up
*/
void at86rf2xx_assert_awake(at86rf2xx_t *dev);
/**
* @brief Trigger a hardware reset
*
* @param[in] dev device to reset
*/
void at86rf2xx_hardware_reset(at86rf2xx_t *dev);
#ifdef __cplusplus
}
#endif