static int _init(netdev2_t *netdev) { at86rf2xx_t *dev = (at86rf2xx_t *)netdev; /* initialise GPIOs */ gpio_init(dev->params.cs_pin, GPIO_OUT); gpio_set(dev->params.cs_pin); gpio_init(dev->params.sleep_pin, GPIO_OUT); gpio_clear(dev->params.sleep_pin); gpio_init(dev->params.reset_pin, GPIO_OUT); gpio_set(dev->params.reset_pin); gpio_init_int(dev->params.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; } #ifdef MODULE_NETSTATS_L2 memset(&netdev->stats, 0, sizeof(netstats_t)); #endif /* reset device to default values and put it into RX state */ at86rf2xx_reset(dev); return 0; }
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_reset_state_machine(at86rf2xx_t *dev) { uint8_t old_state; at86rf2xx_assert_awake(dev); /* Wait for any state transitions to complete before forcing TRX_OFF */ do { old_state = at86rf2xx_get_status(dev); } while (old_state == AT86RF2XX_STATE_IN_PROGRESS); at86rf2xx_force_trx_off(dev); }
void at86rf2xx_set_state(at86rf2xx_t *dev, uint8_t state) { uint8_t old_state = at86rf2xx_get_status(dev); /* make sure there is no ongoing transmission, or state transition already * in progress */ while (old_state == AT86RF2XX_STATE_BUSY_RX_AACK || old_state == AT86RF2XX_STATE_BUSY_TX_ARET || old_state == AT86RF2XX_STATE_IN_PROGRESS) { old_state = at86rf2xx_get_status(dev); } if (state == old_state) { return; } /* we need to go via PLL_ON if we are moving between RX_AACK_ON <-> TX_ARET_ON */ if ((old_state == AT86RF2XX_STATE_RX_AACK_ON && state == AT86RF2XX_STATE_TX_ARET_ON) || (old_state == AT86RF2XX_STATE_TX_ARET_ON && state == AT86RF2XX_STATE_RX_AACK_ON)) { _set_state(dev, AT86RF2XX_STATE_PLL_ON); } /* 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"); 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->params.sleep_pin); dev->state = state; } else { _set_state(dev, state); } }
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; /* initialize device descriptor */ dev->spi = spi; dev->cs_pin = cs_pin; dev->int_pin = int_pin; 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); /* initialise GPIOs */ gpio_init(dev->cs_pin, GPIO_DIR_OUT, GPIO_NOPULL); gpio_set(dev->cs_pin); gpio_init(dev->sleep_pin, GPIO_DIR_OUT, GPIO_NOPULL); gpio_clear(dev->sleep_pin); gpio_init(dev->reset_pin, GPIO_DIR_OUT, GPIO_NOPULL); 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) { 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; }
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; at86rf2xx_reg_write(dev, AT86RF2XX_REG__PHY_CC_CCA, tmp); /* wait for result to be ready */ do { status = at86rf2xx_reg_read(dev, AT86RF2XX_REG__TRX_STATUS); } while (!(status & AT86RF2XX_TRX_STATUS_MASK__CCA_DONE)); /* return according to measurement */ if (status & AT86RF2XX_TRX_STATUS_MASK__CCA_STATUS) { return true; } else { return false; } }
static int _set(netdev2_t *netdev, netopt_t opt, void *val, size_t len) { at86rf2xx_t *dev = (at86rf2xx_t *) netdev; uint8_t old_state = at86rf2xx_get_status(dev); int res = -ENOTSUP; 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)) { res = -EOVERFLOW; } 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)); /* 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)); /* don't set res to set netdev2_ieee802154_t::pan */ } break; case NETOPT_CHANNEL: if (len != sizeof(uint16_t)) { res = -EINVAL; } else { uint8_t chan = ((uint8_t *)val)[0]; if (chan < AT86RF2XX_MIN_CHANNEL || chan > AT86RF2XX_MAX_CHANNEL) { res = -EINVAL; break; } at86rf2xx_set_chan(dev, chan); /* don't set res to set netdev2_ieee802154_t::chan */ } break; case NETOPT_CHANNEL_PAGE: if (len != sizeof(uint16_t)) { res = -EINVAL; } else { uint8_t page = ((uint8_t *)val)[0]; #ifdef MODULE_AT86RF212B if ((page != 0) && (page != 2)) { res = -EINVAL; } else { at86rf2xx_set_page(dev, page); res = sizeof(uint16_t); } #else /* rf23x only supports page 0, no need to configure anything in the driver. */ if (page != 0) { res = -EINVAL; } else { res = sizeof(uint16_t); } #endif } break; case NETOPT_TX_POWER: if (len > sizeof(int16_t)) { res = -EOVERFLOW; } else { at86rf2xx_set_txpower(dev, *((int16_t *)val)); res = sizeof(uint16_t); } break; case NETOPT_STATE: if (len > sizeof(netopt_state_t)) { res = -EOVERFLOW; } else { res = _set_state(dev, *((netopt_state_t *)val)); } break; case NETOPT_AUTOACK: at86rf2xx_set_option(dev, AT86RF2XX_OPT_AUTOACK, ((bool *)val)[0]); /* don't set res to set netdev2_ieee802154_t::flags */ break; case NETOPT_RETRANS: if (len > sizeof(uint8_t)) { res = -EOVERFLOW; } else { at86rf2xx_set_max_retries(dev, *((uint8_t *)val)); res = sizeof(uint8_t); } break; case NETOPT_PRELOADING: at86rf2xx_set_option(dev, AT86RF2XX_OPT_PRELOADING, ((bool *)val)[0]); res = sizeof(netopt_enable_t); break; case NETOPT_PROMISCUOUSMODE: at86rf2xx_set_option(dev, AT86RF2XX_OPT_PROMISCUOUS, ((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]); res = sizeof(netopt_enable_t); break; case NETOPT_RX_END_IRQ: at86rf2xx_set_option(dev, AT86RF2XX_OPT_TELL_RX_END, ((bool *)val)[0]); res = sizeof(netopt_enable_t); break; case NETOPT_TX_START_IRQ: at86rf2xx_set_option(dev, AT86RF2XX_OPT_TELL_TX_START, ((bool *)val)[0]); res = sizeof(netopt_enable_t); break; case NETOPT_TX_END_IRQ: at86rf2xx_set_option(dev, AT86RF2XX_OPT_TELL_TX_END, ((bool *)val)[0]); res = sizeof(netopt_enable_t); break; case NETOPT_CSMA: at86rf2xx_set_option(dev, AT86RF2XX_OPT_CSMA, ((bool *)val)[0]); res = sizeof(netopt_enable_t); break; case NETOPT_CSMA_RETRIES: if ((len > sizeof(uint8_t)) || (*((uint8_t *)val) > 5)) { res = -EOVERFLOW; } else if (dev->netdev.flags & AT86RF2XX_OPT_CSMA) { /* only set if CSMA is enabled */ at86rf2xx_set_csma_max_retries(dev, *((uint8_t *)val)); res = sizeof(uint8_t); } break; case NETOPT_CCA_THRESHOLD: if (len > sizeof(int8_t)) { res = -EOVERFLOW; } else { at86rf2xx_set_cca_threshold(dev, *((int8_t *)val)); res = sizeof(int8_t); } break; default: break; } /* 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); } if (res == -ENOTSUP) { res = netdev2_ieee802154_set((netdev2_ieee802154_t *)netdev, opt, val, len); } return res; }
static int _get(netdev2_t *netdev, netopt_t opt, void *val, size_t max_len) { at86rf2xx_t *dev = (at86rf2xx_t *) netdev; if (netdev == NULL) { return -ENODEV; } /* getting these options doesn't require the transceiver to be responsive */ switch (opt) { case NETOPT_CHANNEL_PAGE: if (max_len < sizeof(uint16_t)) { return -EOVERFLOW; } ((uint8_t *)val)[1] = 0; ((uint8_t *)val)[0] = at86rf2xx_get_page(dev); return sizeof(uint16_t); case NETOPT_MAX_PACKET_SIZE: if (max_len < sizeof(int16_t)) { return -EOVERFLOW; } *((uint16_t *)val) = AT86RF2XX_MAX_PKT_LENGTH - _MAX_MHR_OVERHEAD; return sizeof(uint16_t); case NETOPT_STATE: if (max_len < sizeof(netopt_state_t)) { return -EOVERFLOW; } *((netopt_state_t *)val) = _get_state(dev); return sizeof(netopt_state_t); case NETOPT_PRELOADING: if (dev->netdev.flags & AT86RF2XX_OPT_PRELOADING) { *((netopt_enable_t *)val) = NETOPT_ENABLE; } else { *((netopt_enable_t *)val) = NETOPT_DISABLE; } return sizeof(netopt_enable_t); case NETOPT_PROMISCUOUSMODE: if (dev->netdev.flags & AT86RF2XX_OPT_PROMISCUOUS) { *((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->netdev.flags & AT86RF2XX_OPT_TELL_RX_START); return sizeof(netopt_enable_t); case NETOPT_RX_END_IRQ: *((netopt_enable_t *)val) = !!(dev->netdev.flags & AT86RF2XX_OPT_TELL_RX_END); return sizeof(netopt_enable_t); case NETOPT_TX_START_IRQ: *((netopt_enable_t *)val) = !!(dev->netdev.flags & AT86RF2XX_OPT_TELL_TX_START); return sizeof(netopt_enable_t); case NETOPT_TX_END_IRQ: *((netopt_enable_t *)val) = !!(dev->netdev.flags & AT86RF2XX_OPT_TELL_TX_END); return sizeof(netopt_enable_t); case NETOPT_CSMA: *((netopt_enable_t *)val) = !!(dev->netdev.flags & AT86RF2XX_OPT_CSMA); return sizeof(netopt_enable_t); default: /* Can still be handled in second switch */ 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); 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; case NETOPT_CCA_THRESHOLD: if (max_len < sizeof(int8_t)) { res = -EOVERFLOW; } else { *((int8_t *)val) = at86rf2xx_get_cca_threshold(dev); res = sizeof(int8_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; }
void at86rf2xx_configure_phy(at86rf2xx_t *dev) { /* make sure device is not sleeping */ at86rf2xx_assert_awake(dev); uint8_t state; /* make sure ongoing transmissions are finished */ do { state = at86rf2xx_get_status(dev); } while ((state == AT86RF2XX_STATE_BUSY_TX_ARET) || (state == AT86RF2XX_STATE_BUSY_RX_AACK)); /* we must be in TRX_OFF before changing the PHY configuration */ at86rf2xx_force_trx_off(dev); #ifdef MODULE_AT86RF212B /* The TX power register must be updated after changing the channel if * moving between bands. */ int16_t txpower = at86rf2xx_get_txpower(dev); uint8_t trx_ctrl2 = at86rf2xx_reg_read(dev, AT86RF2XX_REG__TRX_CTRL_2); uint8_t rf_ctrl0 = at86rf2xx_reg_read(dev, AT86RF2XX_REG__RF_CTRL_0); /* Clear previous configuration for PHY mode */ trx_ctrl2 &= ~(AT86RF2XX_TRX_CTRL_2_MASK__FREQ_MODE); /* Clear previous configuration for GC_TX_OFFS */ rf_ctrl0 &= ~AT86RF2XX_RF_CTRL_0_MASK__GC_TX_OFFS; 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; } if (dev->page == 0) { /* BPSK coding */ /* Data sheet recommends using a +2 dB setting for BPSK */ rf_ctrl0 |= AT86RF2XX_RF_CTRL_0_GC_TX_OFFS__2DB; } else if (dev->page == 2) { /* O-QPSK coding */ trx_ctrl2 |= AT86RF2XX_TRX_CTRL_2_MASK__BPSK_OQPSK; /* Data sheet recommends using a +1 dB setting for O-QPSK */ rf_ctrl0 |= AT86RF2XX_RF_CTRL_0_GC_TX_OFFS__1DB; } at86rf2xx_reg_write(dev, AT86RF2XX_REG__TRX_CTRL_2, trx_ctrl2); at86rf2xx_reg_write(dev, AT86RF2XX_REG__RF_CTRL_0, rf_ctrl0); #endif uint8_t phy_cc_cca = at86rf2xx_reg_read(dev, AT86RF2XX_REG__PHY_CC_CCA); /* Clear previous configuration for channel number */ phy_cc_cca &= ~(AT86RF2XX_PHY_CC_CCA_MASK__CHANNEL); /* Update the channel register */ 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 /* Update the TX power register to achieve the same power (in dBm) */ at86rf2xx_set_txpower(dev, txpower); #endif /* Return to the state we had before reconfiguring */ at86rf2xx_set_state(dev, state); }