1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

drivers/at86rf215: add setter for NETOPT_CHANNEL_PAGE

Signed-off-by: Jean Pierre Dudey <me@jeandudey.tech>
This commit is contained in:
Jean Pierre Dudey 2021-04-11 00:01:10 +02:00
parent 466069e151
commit 5588d7971e
7 changed files with 196 additions and 41 deletions

View File

@ -609,7 +609,10 @@ int at86rf215_FSK_set_channel_spacing(at86rf215_t *dev, uint8_t ch_space)
25UL * at86rf215_reg_read16(dev, dev->RF->RG_CCF0L) + (is_subGHz(dev) ? 0 : CCF0_24G_OFFSET));
/* adjust channel spacing */
dev->num_chans = is_subGHz(dev) ? 34 / (ch_space + 1) : (416 / (ch_space + 1)) - (ch_space * 2);
dev->chan_min = 0;
dev->chan_max = is_subGHz(dev) ? 34 / (ch_space + 1) : (416 / (ch_space + 1)) - (ch_space * 2);
dev->chan_max -= 1;
dev->netdev.chan = at86rf215_chan_valid(dev, dev->netdev.chan);
at86rf215_reg_write16(dev, dev->RF->RG_CNL, dev->netdev.chan);

View File

@ -107,6 +107,19 @@ void at86rf215_set_chan(at86rf215_t *dev, uint16_t channel)
uint8_t old_state = at86rf215_get_rf_state(dev);
if (dev->netdev.page == 2 && dev->netdev.chan != channel) {
/* page 2 has different bands, so we need to configure it again
* for 868 MHz or 915 MHz depending on the selected channel, also clamp it
* in order to avoid using the channel 0 which is the default behaviour.
*
* Doing the configuration again will also set the channel to the current
* one. */
dev->netdev.chan = channel >= dev->chan_max ? dev->chan_max : channel;
at86rf215_configure_legacy_OQPSK(dev, at86rf215_OQPSK_get_mode_legacy(dev));
return;
}
/* frequency has to be updated in TRXOFF or TXPREP (datatsheet: 6.3.2) */
if (old_state == RF_STATE_RX) {
at86rf215_rf_cmd(dev, CMD_RF_TXPREP);
@ -446,3 +459,74 @@ void at86rf215_disable_batmon(at86rf215_t *dev)
/* disable interrupt */
at86rf215_reg_and(dev, dev->RF->RG_IRQM, ~RF_IRQ_BATLOW);
}
int at86rf215_set_page(at86rf215_t *dev, uint8_t page)
{
if (!is_subGHz(dev) && page == 0) {
/* on page 0 at86rf215 only supports the range of channels
* 11-26, which is O-QPSK on 2.4 GHz band */
dev->netdev.page = 0;
dev->chan_min = IEEE802154_CHANNEL_MIN;
dev->chan_max = IEEE802154_CHANNEL_MAX;
at86rf215_configure_legacy_OQPSK(dev, at86rf215_OQPSK_get_mode_legacy(dev));
}
else if (is_subGHz(dev) && page == 2) {
/* page 2 is for sub-ghz O-QPSK, channel 0 is for 868 MHz and
* from 1 to 10 is for 915 MHz */
dev->netdev.page = 2;
dev->chan_min = 0;
dev->chan_min = 10;
at86rf215_configure_legacy_OQPSK(dev, at86rf215_OQPSK_get_mode_legacy(dev));
}
else if (page == 9) {
/* as we don't know the PHY we should use because the
* page doesn't specify that, lets use the user defined default */
bool use_mr_oqpsk = IS_ACTIVE(AT86RF215_DEFAULT_MR_OQPSK) &&
IS_USED(MODULE_NETDEV_IEEE802154_MR_OQPSK);
bool use_mr_ofdm = IS_ACTIVE(AT86RF215_DEFAULT_MR_OFDM) &&
IS_USED(MODULE_NETDEV_IEEE802154_MR_OFDM);
bool use_mr_fsk = IS_ACTIVE(AT86RF215_DEFAULT_MR_FSK) &&
IS_USED(MODULE_NETDEV_IEEE802154_MR_FSK);
/* either no default is set or no netdev_ieee802154_mr_xxxx
* module was specified, so return early */
if (!use_mr_oqpsk && !use_mr_ofdm && !use_mr_fsk) {
return -ENOTSUP;
}
dev->netdev.page = 9;
if (use_mr_oqpsk) {
/* TODO: only one channel for now on 868 MHz */
dev->chan_min = 0;
dev->chan_max = 0;
at86rf215_configure_OQPSK(dev, at86rf215_OQPSK_get_chips(dev),
at86rf215_OQPSK_get_mode(dev));
}
else if (use_mr_ofdm) {
at86rf215_configure_OFDM(dev, at86rf215_OFDM_get_option(dev),
at86rf215_OFDM_get_scheme(dev));
}
else if (use_mr_fsk) {
at86rf215_configure_FSK(dev, at86rf215_FSK_get_srate(dev),
at86rf215_FSK_get_mod_idx(dev),
at86rf215_FSK_get_mod_order(dev),
at86rf215_FSK_get_fec(dev));
}
}
else if (page == 10 && IS_USED(MODULE_NETDEV_IEEE802154_MR_FSK)) {
/* TODO: Generic FSK, add way to set generic FSK descriptors */
at86rf215_configure_FSK(dev, at86rf215_FSK_get_srate(dev),
at86rf215_FSK_get_mod_idx(dev),
at86rf215_FSK_get_mod_order(dev),
at86rf215_FSK_get_fec(dev));
}
else {
return -ENOTSUP;
}
return 0;
}

View File

@ -172,19 +172,11 @@ uint16_t at86rf215_chan_valid(at86rf215_t *dev, uint16_t chan)
*
* This is explained on IEEE Std 802.15.4-2020, Section 10.1.3.1 General,
* also specified on the 2006 version */
if (is_subGHz(dev)) {
if (chan >= dev->num_chans) {
return 0;
}
} else {
if (chan < IEEE802154_CHANNEL_MIN) {
return IEEE802154_CHANNEL_MIN;
} else if (chan >= IEEE802154_CHANNEL_MIN + dev->num_chans) {
return IEEE802154_CHANNEL_MIN;
}
if (chan >= dev->chan_min && chan <= dev->chan_max) {
return chan;
}
return chan;
return dev->chan_min;
}
const char* at86rf215_hw_state2a(uint8_t state)

View File

@ -330,12 +330,8 @@ static int _get(netdev_t *netdev, netopt_t opt, void *val, size_t max_len)
case NETOPT_CHANNEL_PAGE:
assert(max_len >= sizeof(uint16_t));
if (at86rf215_get_phy_mode(dev) != IEEE802154_PHY_OQPSK) {
return -ENOTSUP;
}
((uint8_t *)val)[1] = 0;
((uint8_t *)val)[0] = is_subGHz(dev) ? 2 : 0;
((uint8_t *)val)[0] = dev->netdev.page;
return sizeof(uint16_t);
case NETOPT_AUTOCCA:
@ -393,8 +389,13 @@ static int _get(netdev_t *netdev, netopt_t opt, void *val, size_t max_len)
case NETOPT_IEEE802154_PHY:
assert(max_len >= sizeof(int8_t));
*((int8_t *)val) = at86rf215_get_phy_mode(dev);
res = max_len;
if (dev->netdev.page == 9) {
*((int8_t *)val) = at86rf215_get_phy_mode(dev);
res = max_len;
}
else {
return -EINVAL;
}
break;
#ifdef MODULE_NETDEV_IEEE802154_MR_FSK
case NETOPT_MR_FSK_MODULATION_INDEX:
@ -534,6 +535,16 @@ static int _set(netdev_t *netdev, netopt_t opt, const void *val, size_t len)
res = sizeof(netopt_enable_t);
break;
case NETOPT_CHANNEL_PAGE:
assert(len == sizeof(uint16_t));
if (at86rf215_set_page(dev, ((const uint8_t *)val)[1]) < 0) {
res = -ENOTSUP;
}
else {
res = sizeof(uint16_t);
}
break;
case NETOPT_AUTOCCA:
at86rf215_set_option(dev, AT86RF215_OPT_CCATX,
((const bool *)val)[0]);
@ -606,13 +617,14 @@ static int _set(netdev_t *netdev, netopt_t opt, const void *val, size_t len)
case NETOPT_IEEE802154_PHY:
assert(len <= sizeof(uint8_t));
switch (*(uint8_t *)val) {
#ifdef MODULE_NETDEV_IEEE802154_OQPSK
case IEEE802154_PHY_OQPSK:
at86rf215_configure_legacy_OQPSK(dev, at86rf215_OQPSK_get_mode_legacy(dev));
res = sizeof(uint8_t);
/* only SUN PHYs can be changed, others are changed using
* the channel page */
if (dev->netdev.page != 9) {
res = -EINVAL;
break;
#endif /* MODULE_NETDEV_IEEE802154_OQPSK */
}
switch (*(uint8_t *)val) {
#ifdef MODULE_NETDEV_IEEE802154_MR_OQPSK
case IEEE802154_PHY_MR_OQPSK:
at86rf215_configure_OQPSK(dev,
@ -1120,7 +1132,8 @@ static void _isr(netdev_t *netdev)
/* This should never happen */
if (++iter > 3) {
puts("AT86RF215: stuck in ISR");
printf("\tnum_channels: %d\n", dev->num_chans);
printf("\tchan_min: %d\n", dev->chan_min);
printf("\tchan_max: %d\n", dev->chan_max);
printf("\tHW: %s\n", at86rf215_hw_state2a(at86rf215_get_rf_state(dev)));
printf("\tSW: %s\n", at86rf215_sw_state2a(dev->state));
printf("\trf_irq_mask: %x\n", rf_irq_mask);

View File

@ -27,9 +27,13 @@
* Table 68eCenter frequencies for the MR-O-QPSK PHY operating in the 868870 MHz band
*/
/* currently only EU-868 MHz band is supported */
#define QPSK_CHANNEL_SPACING_SUBGHZ (650U) /* kHz */
#define QPSK_CENTER_FREQUENCY_SUBGHZ (868300U) /* Hz */
/* EU-868 MHz band */
#define QPSK_CHANNEL_SPACING_868MHZ (650U) /* kHz */
#define QPSK_CENTER_FREQUENCY_868MHZ (868300U) /* Hz */
/* ISM 915 MHz band */
#define QPSK_CHANNEL_SPACING_915MHZ (2000U) /* kHz */
#define QPSK_CENTER_FREQUENCY_915MHZ (906000U) /* Hz */
#define QPSK_CHANNEL_SPACING_24GHZ (5000U) /* kHz */
#define QPSK_CENTER_FREQUENCY_24GHZ (2350000U - CCF0_24G_OFFSET) /* Hz */
@ -328,21 +332,69 @@ static inline void _set_csma_backoff_period_legacy(at86rf215_t *dev)
void _end_configure_OQPSK(at86rf215_t *dev)
{
/* set channel spacing with 25 kHz resolution */
if (is_subGHz(dev)) {
at86rf215_reg_write(dev, dev->RF->RG_CS, QPSK_CHANNEL_SPACING_SUBGHZ / 25);
at86rf215_reg_write16(dev, dev->RF->RG_CCF0L, QPSK_CENTER_FREQUENCY_SUBGHZ / 25);
} else {
at86rf215_reg_write(dev, dev->RF->RG_CS, QPSK_CHANNEL_SPACING_24GHZ / 25);
at86rf215_reg_write16(dev, dev->RF->RG_CCF0L, QPSK_CENTER_FREQUENCY_24GHZ / 25);
uint32_t cs;
uint32_t cf;
/* obtain a valid channel first to set the correct frequency */
dev->netdev.chan = at86rf215_chan_valid(dev, dev->netdev.chan);
/* page, chan, chan_min and chan_max must be set prior to the call
* of this function, if not, it will probably eat your dog :D.
*
* For reference, see:
*
* IEEE Std 802.15.4-2006, Section 6.1.2.2 Channel Pages
* IEEE Std 802.15.4g-2012, Figure 64a-Channel page structure for channel
* pages nine and ten
* IEEE Std 802.15.4-2020, Section 10.1.3 Channel assigments
*/
if (!is_subGHz(dev) && dev->netdev.page == 0) {
cs = QPSK_CHANNEL_SPACING_24GHZ;
cf = QPSK_CENTER_FREQUENCY_24GHZ;
}
else if (is_subGHz(dev) && dev->netdev.page == 2) {
assert(dev->chan_min == 0 && dev->chan_max == 10);
/* channel 0 is for 868 MHz */
if (dev->netdev.chan == 0) {
cs = QPSK_CHANNEL_SPACING_868MHZ;
cf = QPSK_CENTER_FREQUENCY_868MHZ;
}
/* channels 1-10 is for 915 MHz */
else {
assert(dev->netdev.chan <= dev->chan_max);
cs = QPSK_CHANNEL_SPACING_915MHZ;
cf = QPSK_CENTER_FREQUENCY_915MHZ;
}
}
else if (dev->netdev.page == 9) {
if (is_subGHz(dev)) {
/* TODO: we still don't have a way to set the band on SUN PHYs, but
* for now we stick to MR-O-OQPSK on 868 MHz band for now. */
cs = QPSK_CHANNEL_SPACING_868MHZ;
cf = QPSK_CENTER_FREQUENCY_868MHZ;
}
else {
cs = QPSK_CHANNEL_SPACING_24GHZ;
cf = QPSK_CENTER_FREQUENCY_24GHZ;
}
}
else {
DEBUG("[at86rf215] invalid channel / page configuration"
"(page=%"PRIu16", chan=%"PRIu16")\n", dev->netdev.page,
dev->netdev.chan);
return;
}
/* set channel spacing and center frequency */
at86rf215_reg_write(dev, dev->RF->RG_CS, cs / 25);
at86rf215_reg_write16(dev, dev->RF->RG_CCF0L, cf / 25);
/* lowest preamble detection sensitivity, enable receiver override */
at86rf215_reg_write(dev, dev->BBC->RG_OQPSKC1, OQPSKC1_RXO_MASK | OQPSKC1_RXOLEG_MASK);
/* make sure the channel config is still valid */
dev->num_chans = is_subGHz(dev) ? 1 : 16;
dev->netdev.chan = at86rf215_chan_valid(dev, dev->netdev.chan);
/* write channel config */
at86rf215_reg_write16(dev, dev->RF->RG_CNL, dev->netdev.chan);
/* disable FSK preamble switching */

View File

@ -195,8 +195,10 @@ static void _set_option(at86rf215_t *dev, uint8_t option)
at86rf215_reg_write(dev, dev->BBC->RG_OFDMC, option - 1);
dev->chan_min = 0;
dev->chan_max = _get_max_chan(dev, option);
/* make sure channel config is still valid */
dev->num_chans = _get_max_chan(dev, option);
dev->netdev.chan = at86rf215_chan_valid(dev, dev->netdev.chan);
at86rf215_reg_write16(dev, dev->RF->RG_CNL, dev->netdev.chan);
}

View File

@ -351,7 +351,8 @@ typedef struct at86rf215 {
uint32_t ack_timeout_usec; /**< time to wait before retransmission in µs */
uint32_t csma_backoff_period; /**< CSMA Backoff period */
uint16_t flags; /**< Device specific flags */
uint16_t num_chans; /**< Number of legal channel at current modulation */
uint16_t chan_min; /**< Minimum channel supported in current page */
uint16_t chan_max; /**< Maximum channel supported in current page */
uint16_t tx_frame_len; /**< length of the current TX frame */
uint8_t timeout; /**< indicates which timeout was reached */
uint8_t state; /**< current state of the radio */
@ -678,6 +679,14 @@ int at86rf215_enable_batmon(at86rf215_t *dev, unsigned voltage);
*/
void at86rf215_disable_batmon(at86rf215_t *dev);
/**
* @brief Set the channel page to use.
*
* @param[in] dev device to configure
* @param[in] page channel page to set
*/
int at86rf215_set_page(at86rf215_t *dev, uint8_t page);
#ifdef __cplusplus
}
#endif