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 */ if (state) { 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->netdev.long_addr); at86rf2xx_set_csma_max_retries(dev, 4); at86rf2xx_set_csma_backoff_exp(dev, 3, 5); break; case AT86RF2XX_OPT_PROMISCUOUS: DEBUG("[at86rf2xx] opt: enabling PROMISCUOUS mode\n"); /* disable auto ACKs in promiscuous mode */ tmp = at86rf2xx_reg_read(dev, AT86RF2XX_REG__CSMA_SEED_1); tmp |= AT86RF2XX_CSMA_SEED_1__AACK_DIS_ACK; at86rf2xx_reg_write(dev, AT86RF2XX_REG__CSMA_SEED_1, tmp); /* enable promiscuous mode */ tmp = at86rf2xx_reg_read(dev, AT86RF2XX_REG__XAH_CTRL_1); 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: enabling auto ACKs\n"); tmp = at86rf2xx_reg_read(dev, AT86RF2XX_REG__CSMA_SEED_1); 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: enabling SFD IRQ\n"); tmp = at86rf2xx_reg_read(dev, AT86RF2XX_REG__IRQ_MASK); tmp |= AT86RF2XX_IRQ_STATUS_MASK__RX_START; at86rf2xx_reg_write(dev, AT86RF2XX_REG__IRQ_MASK, tmp); break; default: /* do nothing */ break; } } else { dev->netdev.flags &= ~(option); /* trigger option specific actions */ switch (option) { case AT86RF2XX_OPT_CSMA: DEBUG("[at86rf2xx] opt: disabling CSMA mode\n"); /* setting retries to -1 means CSMA disabled */ at86rf2xx_set_csma_max_retries(dev, -1); break; case AT86RF2XX_OPT_PROMISCUOUS: DEBUG("[at86rf2xx] opt: disabling PROMISCUOUS mode\n"); /* disable promiscuous mode */ tmp = at86rf2xx_reg_read(dev, AT86RF2XX_REG__XAH_CTRL_1); 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->netdev.flags & AT86RF2XX_OPT_AUTOACK) { tmp = at86rf2xx_reg_read(dev, AT86RF2XX_REG__CSMA_SEED_1); tmp &= ~(AT86RF2XX_CSMA_SEED_1__AACK_DIS_ACK); at86rf2xx_reg_write(dev, AT86RF2XX_REG__CSMA_SEED_1, tmp); } break; case AT86RF2XX_OPT_AUTOACK: DEBUG("[at86rf2xx] opt: disabling auto ACKs\n"); tmp = at86rf2xx_reg_read(dev, AT86RF2XX_REG__CSMA_SEED_1); 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: disabling SFD IRQ\n"); tmp = at86rf2xx_reg_read(dev, AT86RF2XX_REG__IRQ_MASK); tmp &= ~AT86RF2XX_IRQ_STATUS_MASK__RX_START; at86rf2xx_reg_write(dev, AT86RF2XX_REG__IRQ_MASK, tmp); break; default: /* do nothing */ break; } } }
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; }