diff --git a/cpu/nrf52/include/nrf802154.h b/cpu/nrf52/include/nrf802154.h index 7718f3efc0..89181e00ea 100644 --- a/cpu/nrf52/include/nrf802154.h +++ b/cpu/nrf52/include/nrf802154.h @@ -42,6 +42,23 @@ extern "C" { #endif +/** + * @defgroup drivers_nrf52_802154_conf nrf802154 driver compile configuration + * @ingroup drivers_nrf52_802154 + * @ingroup config + * @{ + */ + +/** + * @brief NRF802154 default CCA threshold value for CCACTRL register. + * + * @note This value was copied from the Nordic reference driver configuration + */ +#ifndef CONFIG_NRF802154_CCA_THRESH_DEFAULT +#define CONFIG_NRF802154_CCA_THRESH_DEFAULT 0x14 +#endif +/** @} */ + /** * @brief Export the netdev device descriptor */ diff --git a/cpu/nrf52/radio/nrf802154/nrf802154.c b/cpu/nrf52/radio/nrf802154/nrf802154.c index 2eb901e210..ac3886e341 100644 --- a/cpu/nrf52/radio/nrf802154/nrf802154.c +++ b/cpu/nrf52/radio/nrf802154/nrf802154.c @@ -17,6 +17,7 @@ * @author Hauke Petersen * @author Dimitri Nahm * @author Semjon Kerner + * @author José I. Alamos * @} */ @@ -120,6 +121,63 @@ static void _enable_tx(void) DEBUG("[nrf802154] Device state: TXIDLE\n"); } +/** + * @brief Convert from dBm to the internal representation, when the + * radio operates as a IEEE802.15.4 transceiver. + */ +static inline uint8_t _dbm_to_ieee802154_hwval(int8_t dbm) +{ + return ((dbm - ED_RSSIOFFS) / ED_RSSISCALE); +} + +/** + * @brief Convert from the internal representation to dBm, when the + * radio operates as a IEEE802.15.4 transceiver. + */ +static inline int8_t _hwval_to_ieee802154_dbm(uint8_t hwval) +{ + return (ED_RSSISCALE * hwval) + ED_RSSIOFFS; +} + +/** + * @brief Get CCA threshold value in internal represetion + */ +static int _get_cca_thresh(void) +{ + return (NRF_RADIO->CCACTRL & RADIO_CCACTRL_CCAEDTHRES_Msk) >> + RADIO_CCACTRL_CCAEDTHRES_Pos; +} + +/** + * @brief Set CCA threshold value in internal represetion + */ +static void _set_cca_thresh(uint8_t thresh) +{ + NRF_RADIO->CCACTRL &= ~RADIO_CCACTRL_CCAEDTHRES_Msk; + NRF_RADIO->CCACTRL |= thresh << RADIO_CCACTRL_CCAEDTHRES_Pos; +} + +/** + * @brief Check whether the channel is clear or not + * @note So far only CCA with Energy Detection is supported (CCA_MODE=1). + */ +static bool _channel_is_clear(void) +{ + NRF_RADIO->CCACTRL |= RADIO_CCACTRL_CCAMODE_EdMode; + NRF_RADIO->EVENTS_CCAIDLE = 0; + NRF_RADIO->EVENTS_CCABUSY = 0; + NRF_RADIO->TASKS_CCASTART = 1; + + for(;;) { + if(NRF_RADIO->EVENTS_CCAIDLE) { + return true; + } + if(NRF_RADIO->EVENTS_CCABUSY) { + return false; + } + } +} + /** * @brief Reset the RXIDLE state */ @@ -243,6 +301,9 @@ static int _init(netdev_t *dev) /* set default channel */ _set_chan(nrf802154_dev.chan); + /* set default CCA threshold */ + _set_cca_thresh(CONFIG_NRF802154_CCA_THRESH_DEFAULT); + /* configure some shortcuts */ NRF_RADIO->SHORTS = RADIO_SHORTS_RXREADY_START_Msk | RADIO_SHORTS_TXREADY_START_Msk; @@ -382,7 +443,14 @@ static int _get(netdev_t *dev, netopt_t opt, void *value, size_t max_len) assert(max_len >= sizeof(int16_t)); *((int16_t *)value) = _get_txpower(); return sizeof(int16_t); - + case NETOPT_IS_CHANNEL_CLR: + assert(max_len >= sizeof(netopt_enable_t)); + *((netopt_enable_t*)value) = _channel_is_clear(); + return sizeof(netopt_enable_t); + case NETOPT_CCA_THRESHOLD: + assert(max_len >= sizeof(int8_t)); + *((int8_t*)value) = _hwval_to_ieee802154_dbm(_get_cca_thresh()); + return sizeof(netopt_enable_t); default: return netdev_ieee802154_get((netdev_ieee802154_t *)dev, opt, value, max_len); @@ -400,6 +468,7 @@ static int _set(netdev_t *dev, netopt_t opt, DEBUG("[nrf802154] set: %d\n", opt); #endif + int8_t tmp; switch (opt) { case NETOPT_CHANNEL: assert(value_len == sizeof(uint16_t)); @@ -409,7 +478,15 @@ static int _set(netdev_t *dev, netopt_t opt, assert(value_len == sizeof(int16_t)); _set_txpower(*((int16_t *)value)); return sizeof(int16_t); - + case NETOPT_CCA_THRESHOLD: + assert(value_len == sizeof(int8_t)); + tmp = *((int8_t*) value); + /* ED offset cannot be less than the min RSSI offset */ + if ((tmp - ED_RSSIOFFS) < 0) { + return -EINVAL; + } + _set_cca_thresh(_dbm_to_ieee802154_hwval(tmp)); + return sizeof(int8_t); default: return netdev_ieee802154_set((netdev_ieee802154_t *)dev, opt, value, value_len);