mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-12-25 14:33:52 +01:00
Merge pull request #4412 from DipSwitch/pr/at86rf2xx-phy-mode
at86rf2xx: Add support for channel page
This commit is contained in:
commit
10323329ce
@ -148,7 +148,7 @@ void at86rf2xx_reset(at86rf2xx_t *dev)
|
||||
at86rf2xx_reg_write(dev, AT86RF2XX_REG__TRX_CTRL_2,
|
||||
AT86RF2XX_TRX_CTRL_2_MASK__RX_SAFE_MODE);
|
||||
#ifdef MODULE_AT86RF212B
|
||||
at86rf2xx_set_freq(dev, AT86RF2XX_FREQ_915MHZ);
|
||||
at86rf2xx_set_page(dev, 0);
|
||||
#endif
|
||||
|
||||
/* don't populate masked interrupt flags to IRQ_STATUS register */
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
* @author Baptiste Clenet <bapclenet@gmail.com>
|
||||
* @author Daniel Krebs <github@daniel-krebs.net>
|
||||
* @author Kévin Roussel <Kevin.Roussel@inria.fr>
|
||||
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
@ -47,16 +48,29 @@ static const uint8_t dbm_to_tx_pow_915[] = {0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x17,
|
||||
0x04, 0x03, 0x02, 0x01, 0x00, 0x86,
|
||||
0x40, 0x84, 0x83, 0x82, 0x80, 0xc1,
|
||||
0xc0};
|
||||
int16_t tx_pow_to_dbm(at86rf2xx_freq_t freq, uint8_t reg) {
|
||||
for(int i = 0; i < 37; i++){
|
||||
if(freq == AT86RF2XX_FREQ_868MHZ){
|
||||
if (dbm_to_tx_pow_868[i] == reg) {
|
||||
return i -25;
|
||||
}
|
||||
} else if (freq == AT86RF2XX_FREQ_915MHZ){
|
||||
if (dbm_to_tx_pow_915[i] == reg) {
|
||||
return i -25;
|
||||
}
|
||||
static int16_t _tx_pow_to_dbm_212b(uint8_t channel, uint8_t page, uint8_t reg) {
|
||||
const uint8_t *dbm_to_tx_pow;
|
||||
size_t nelem;
|
||||
|
||||
if (page == 0 || page == 2) {
|
||||
/* Channel 0 is 868.3 MHz */
|
||||
if (channel == 0) {
|
||||
dbm_to_tx_pow = &dbm_to_tx_pow_868[0];
|
||||
nelem = sizeof(dbm_to_tx_pow_868) / sizeof(dbm_to_tx_pow_868[0]);
|
||||
}
|
||||
else {
|
||||
/* Channels 1+ are 915 MHz */
|
||||
dbm_to_tx_pow = &dbm_to_tx_pow_915[0];
|
||||
nelem = sizeof(dbm_to_tx_pow_915) / sizeof(dbm_to_tx_pow_915[0]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < nelem; i++){
|
||||
if (dbm_to_tx_pow[i] == reg) {
|
||||
return i - 25;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@ -124,61 +138,37 @@ uint8_t at86rf2xx_get_chan(at86rf2xx_t *dev)
|
||||
|
||||
void at86rf2xx_set_chan(at86rf2xx_t *dev, uint8_t channel)
|
||||
{
|
||||
uint8_t tmp;
|
||||
|
||||
if (channel < AT86RF2XX_MIN_CHANNEL
|
||||
|| channel > AT86RF2XX_MAX_CHANNEL) {
|
||||
if ((channel < AT86RF2XX_MIN_CHANNEL) ||
|
||||
(channel > AT86RF2XX_MAX_CHANNEL) ||
|
||||
(dev->chan == channel)) {
|
||||
return;
|
||||
}
|
||||
|
||||
dev->chan = channel;
|
||||
tmp = at86rf2xx_reg_read(dev, AT86RF2XX_REG__PHY_CC_CCA);
|
||||
tmp &= ~(AT86RF2XX_PHY_CC_CCA_MASK__CHANNEL);
|
||||
tmp |= (channel & AT86RF2XX_PHY_CC_CCA_MASK__CHANNEL);
|
||||
at86rf2xx_reg_write(dev, AT86RF2XX_REG__PHY_CC_CCA, tmp);
|
||||
|
||||
at86rf2xx_configure_phy(dev);
|
||||
}
|
||||
|
||||
uint8_t at86rf2xx_get_page(at86rf2xx_t *dev)
|
||||
{
|
||||
#ifdef MODULE_AT86RF212B
|
||||
at86rf2xx_freq_t at86rf2xx_get_freq(at86rf2xx_t *dev)
|
||||
{
|
||||
return dev->freq;
|
||||
}
|
||||
|
||||
void at86rf2xx_set_freq(at86rf2xx_t *dev, at86rf2xx_freq_t freq)
|
||||
{
|
||||
uint8_t trx_ctrl2 = 0, rf_ctrl0 = 0;
|
||||
trx_ctrl2 = at86rf2xx_reg_read(dev, AT86RF2XX_REG__TRX_CTRL_2);
|
||||
trx_ctrl2 &= ~(AT86RF2XX_TRX_CTRL_2_MASK__FREQ_MODE);
|
||||
rf_ctrl0 = at86rf2xx_reg_read(dev, AT86RF2XX_REG__RF_CTRL_0);
|
||||
/* Erase previous conf for GC_TX_OFFS */
|
||||
rf_ctrl0 &= ~AT86RF2XX_RF_CTRL_0_MASK__GC_TX_OFFS;
|
||||
|
||||
trx_ctrl2 |= AT86RF2XX_TRX_CTRL_2_MASK__SUB_MODE;
|
||||
rf_ctrl0 |= AT86RF2XX_RF_CTRL_0_GC_TX_OFFS__2DB;
|
||||
|
||||
switch(freq) {
|
||||
case AT86RF2XX_FREQ_915MHZ:
|
||||
if (dev->chan == 0) {
|
||||
at86rf2xx_set_chan(dev,AT86RF2XX_DEFAULT_CHANNEL);
|
||||
} else {
|
||||
at86rf2xx_set_chan(dev,dev->chan);
|
||||
}
|
||||
break;
|
||||
|
||||
case AT86RF2XX_FREQ_868MHZ:
|
||||
/* Channel = 0 for 868MHz means 868.3MHz, only one available */
|
||||
at86rf2xx_set_chan(dev,0x00);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG("at86rf2xx: Trying to set unknown frequency 0x%lx\n",
|
||||
(unsigned long) freq);
|
||||
return;
|
||||
}
|
||||
dev->freq = freq;
|
||||
at86rf2xx_reg_write(dev, AT86RF2XX_REG__TRX_CTRL_2, trx_ctrl2);
|
||||
at86rf2xx_reg_write(dev, AT86RF2XX_REG__RF_CTRL_0, rf_ctrl0);
|
||||
}
|
||||
return dev->page;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void at86rf2xx_set_page(at86rf2xx_t *dev, uint8_t page)
|
||||
{
|
||||
#ifdef MODULE_AT86RF212B
|
||||
if ((page != 0) && (page != 2)) {
|
||||
return;
|
||||
}
|
||||
dev->page = page;
|
||||
|
||||
at86rf2xx_configure_phy(dev);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint16_t at86rf2xx_get_pan(at86rf2xx_t *dev)
|
||||
{
|
||||
@ -198,7 +188,7 @@ int16_t at86rf2xx_get_txpower(at86rf2xx_t *dev)
|
||||
#ifdef MODULE_AT86RF212B
|
||||
uint8_t txpower = at86rf2xx_reg_read(dev, AT86RF2XX_REG__PHY_TX_PWR);
|
||||
DEBUG("txpower value: %x\n", txpower);
|
||||
return tx_pow_to_dbm(dev->freq, txpower);
|
||||
return _tx_pow_to_dbm_212b(dev->chan, dev->page, txpower);
|
||||
#else
|
||||
uint8_t txpower = at86rf2xx_reg_read(dev, AT86RF2XX_REG__PHY_TX_PWR)
|
||||
& AT86RF2XX_PHY_TX_PWR_MASK__TX_PWR;
|
||||
@ -230,16 +220,13 @@ void at86rf2xx_set_txpower(at86rf2xx_t *dev, int16_t txpower)
|
||||
#endif
|
||||
}
|
||||
#ifdef MODULE_AT86RF212B
|
||||
if (dev->freq == AT86RF2XX_FREQ_915MHZ) {
|
||||
at86rf2xx_reg_write(dev, AT86RF2XX_REG__PHY_TX_PWR,
|
||||
dbm_to_tx_pow_915[txpower]);
|
||||
}
|
||||
else if (dev->freq == AT86RF2XX_FREQ_868MHZ) {
|
||||
if (dev->chan == 0) {
|
||||
at86rf2xx_reg_write(dev, AT86RF2XX_REG__PHY_TX_PWR,
|
||||
dbm_to_tx_pow_868[txpower]);
|
||||
}
|
||||
else {
|
||||
return;
|
||||
else if (dev->chan < 11) {
|
||||
at86rf2xx_reg_write(dev, AT86RF2XX_REG__PHY_TX_PWR,
|
||||
dbm_to_tx_pow_915[txpower]);
|
||||
}
|
||||
#else
|
||||
at86rf2xx_reg_write(dev, AT86RF2XX_REG__PHY_TX_PWR,
|
||||
@ -433,12 +420,6 @@ static inline void _set_state(at86rf2xx_t *dev, uint8_t state)
|
||||
dev->state = state;
|
||||
}
|
||||
|
||||
static inline void _force_trx_off(at86rf2xx_t *dev)
|
||||
{
|
||||
at86rf2xx_reg_write(dev, AT86RF2XX_REG__TRX_STATE, AT86RF2XX_TRX_STATE__FORCE_TRX_OFF);
|
||||
while (at86rf2xx_get_status(dev) != AT86RF2XX_STATE_TRX_OFF);
|
||||
}
|
||||
|
||||
void at86rf2xx_set_state(at86rf2xx_t *dev, uint8_t state)
|
||||
{
|
||||
uint8_t old_state = at86rf2xx_get_status(dev);
|
||||
@ -469,7 +450,7 @@ void at86rf2xx_set_state(at86rf2xx_t *dev, uint8_t state)
|
||||
|
||||
if (state == AT86RF2XX_STATE_SLEEP) {
|
||||
/* First go to TRX_OFF */
|
||||
_force_trx_off(dev);
|
||||
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 */
|
||||
@ -491,5 +472,5 @@ void at86rf2xx_reset_state_machine(at86rf2xx_t *dev)
|
||||
old_state = at86rf2xx_get_status(dev);
|
||||
} while (old_state == AT86RF2XX_STATE_IN_PROGRESS);
|
||||
|
||||
_force_trx_off(dev);
|
||||
at86rf2xx_force_trx_off(dev);
|
||||
}
|
||||
|
||||
@ -135,3 +135,78 @@ void at86rf2xx_hardware_reset(at86rf2xx_t *dev)
|
||||
gpio_set(dev->reset_pin);
|
||||
xtimer_usleep(AT86RF2XX_RESET_DELAY);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
uint8_t phy_cc_cca = at86rf2xx_reg_read(dev, AT86RF2XX_REG__PHY_CC_CCA);
|
||||
|
||||
#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;
|
||||
/* Clear previous configuration for channel number */
|
||||
phy_cc_cca &= ~(AT86RF2XX_PHY_CC_CCA_MASK__CHANNEL);
|
||||
|
||||
if (dev->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
|
||||
|
||||
/* Update the channel register */
|
||||
phy_cc_cca |= (dev->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);
|
||||
}
|
||||
|
||||
void at86rf2xx_force_trx_off(const at86rf2xx_t *dev)
|
||||
{
|
||||
at86rf2xx_reg_write(dev,
|
||||
AT86RF2XX_REG__TRX_STATE,
|
||||
AT86RF2XX_TRX_STATE__FORCE_TRX_OFF);
|
||||
while (at86rf2xx_get_status(dev) != AT86RF2XX_STATE_TRX_OFF);
|
||||
}
|
||||
|
||||
@ -442,6 +442,14 @@ 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_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;
|
||||
@ -679,6 +687,29 @@ static int _set(gnrc_netdev_t *device, netopt_t opt, void *val, size_t len)
|
||||
}
|
||||
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 = -ENOTSUP;
|
||||
} 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 = -ENOTSUP;
|
||||
} else {
|
||||
res = sizeof(uint16_t);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
case NETOPT_TX_POWER:
|
||||
if (len > sizeof(int16_t)) {
|
||||
res = -EOVERFLOW;
|
||||
|
||||
@ -107,6 +107,13 @@ void at86rf2xx_sram_write(const at86rf2xx_t *dev,
|
||||
void at86rf2xx_fb_read(const at86rf2xx_t *dev,
|
||||
uint8_t *data, const size_t len);
|
||||
|
||||
/**
|
||||
* @brief Cancel ongoing transactions and switch to TRX_OFF state
|
||||
*
|
||||
* @param[in] dev device to manipulate
|
||||
*/
|
||||
void at86rf2xx_force_trx_off(const at86rf2xx_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Convenience function for reading the status of the given device
|
||||
*
|
||||
@ -131,6 +138,14 @@ void at86rf2xx_assert_awake(at86rf2xx_t *dev);
|
||||
void at86rf2xx_hardware_reset(at86rf2xx_t *dev);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set PHY parameters based on channel and page number
|
||||
*
|
||||
* @param[in] dev device to configure
|
||||
*/
|
||||
void at86rf2xx_configure_phy(at86rf2xx_t *dev);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
||||
* @author Daniel Krebs <github@daniel-krebs.net>
|
||||
* @author Kévin Roussel <Kevin.Roussel@inria.fr>
|
||||
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
|
||||
*/
|
||||
|
||||
#ifndef AT86RF2XX_H_
|
||||
@ -124,16 +125,6 @@ extern "C" {
|
||||
* PAN ID */
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Frequency configuration for sub-GHz devices.
|
||||
* @{
|
||||
*/
|
||||
typedef enum {
|
||||
AT86RF2XX_FREQ_915MHZ, /**< frequency 915MHz enabled */
|
||||
AT86RF2XX_FREQ_868MHZ, /**< frequency 868MHz enabled */
|
||||
} at86rf2xx_freq_t;
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Device descriptor for AT86RF2XX radio devices
|
||||
*/
|
||||
@ -153,9 +144,10 @@ typedef struct {
|
||||
uint8_t seq_nr; /**< sequence number to use next */
|
||||
uint8_t frame_len; /**< length of the current TX frame */
|
||||
uint16_t pan; /**< currently used PAN ID */
|
||||
uint8_t chan; /**< currently used channel */
|
||||
uint8_t chan; /**< currently used channel number */
|
||||
#ifdef MODULE_AT86RF212B
|
||||
at86rf2xx_freq_t freq; /**< currently used frequency */
|
||||
/* Only AT86RF212B supports multiple pages (PHY modes) */
|
||||
uint8_t page; /**< currently used channel page */
|
||||
#endif
|
||||
uint8_t addr_short[2]; /**< the radio's short address */
|
||||
uint8_t addr_long[8]; /**< the radio's long address */
|
||||
@ -245,40 +237,38 @@ uint64_t at86rf2xx_get_addr_long(at86rf2xx_t *dev);
|
||||
void at86rf2xx_set_addr_long(at86rf2xx_t *dev, uint64_t addr);
|
||||
|
||||
/**
|
||||
* @brief Get the configured channel of the given device
|
||||
* @brief Get the configured channel number of the given device
|
||||
*
|
||||
* @param[in] dev device to read from
|
||||
*
|
||||
* @return the currently set channel
|
||||
* @return the currently set channel number
|
||||
*/
|
||||
uint8_t at86rf2xx_get_chan(at86rf2xx_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Set the channel of the given device
|
||||
* @brief Set the channel number of the given device
|
||||
*
|
||||
* @param[in] dev device to write to
|
||||
* @param[in] chan channel to set
|
||||
* @param[in] chan channel number to set
|
||||
*/
|
||||
void at86rf2xx_set_chan(at86rf2xx_t *dev, uint8_t chan);
|
||||
|
||||
#ifdef MODULE_AT86RF212B
|
||||
/**
|
||||
* @brief Get the configured frequency of the given device
|
||||
* @brief Get the configured channel page of the given device
|
||||
*
|
||||
* @param[in] dev device to read from
|
||||
*
|
||||
* @return the currently set frequency
|
||||
* @return the currently set channel page
|
||||
*/
|
||||
at86rf2xx_freq_t at86rf2xx_get_freq(at86rf2xx_t *dev);
|
||||
uint8_t at86rf2xx_get_page(at86rf2xx_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Set the frequency of the given device
|
||||
* @brief Set the channel page of the given device
|
||||
*
|
||||
* @param[in] dev device to write to
|
||||
* @param[in] chan frequency to set
|
||||
* @param[in] page channel page to set
|
||||
*/
|
||||
void at86rf2xx_set_freq(at86rf2xx_t *dev, at86rf2xx_freq_t freq);
|
||||
#endif
|
||||
void at86rf2xx_set_page(at86rf2xx_t *dev, uint8_t page);
|
||||
|
||||
/**
|
||||
* @brief Get the configured PAN ID of the given device
|
||||
@ -358,7 +348,7 @@ uint8_t at86rf2xx_get_csma_max_retries(at86rf2xx_t *dev);
|
||||
* Valid values: 0 to 5, -1 means CSMA disabled
|
||||
*
|
||||
* @param[in] dev device to write to
|
||||
* @param[in] max the maximum number of retries
|
||||
* @param[in] retries the maximum number of retries
|
||||
*/
|
||||
void at86rf2xx_set_csma_max_retries(at86rf2xx_t *dev, int8_t retries);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user