mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
618 lines
18 KiB
C
618 lines
18 KiB
C
/*
|
|
* Copyright (C) 2019 ML!PA Consulting GmbH
|
|
*
|
|
* This file is subject to the terms and conditions of the GNU Lesser
|
|
* General Public License v2.1. See the file LICENSE in the top level
|
|
* directory for more details.
|
|
*/
|
|
|
|
/**
|
|
* @ingroup drivers_at86rf215
|
|
* @{
|
|
*
|
|
* @file
|
|
* @brief Configuration of the MR-FSK PHY on the AT86RF215 chip
|
|
*
|
|
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com>
|
|
* @}
|
|
*/
|
|
|
|
#include "at86rf215.h"
|
|
#include "at86rf215_internal.h"
|
|
|
|
#define ENABLE_DEBUG 0
|
|
#include "debug.h"
|
|
|
|
/* symbol time is always 20 µs for MR-FSK (table 0, pg. 7) */
|
|
#define FSK_SYMBOL_TIME_US 20
|
|
|
|
/* also used by at86rf215_netdev.c */
|
|
const uint8_t _at86rf215_fsk_srate_10kHz[] = {
|
|
[FSK_SRATE_50K] = 5,
|
|
[FSK_SRATE_100K] = 10,
|
|
[FSK_SRATE_150K] = 15,
|
|
[FSK_SRATE_200K] = 20,
|
|
[FSK_SRATE_300K] = 30,
|
|
[FSK_SRATE_400K] = 40
|
|
};
|
|
|
|
/* also used by at86rf215_netdev.c */
|
|
const uint8_t _at86rf215_fsk_channel_spacing_25kHz[] = {
|
|
[FSK_CHANNEL_SPACING_200K] = 8,
|
|
[FSK_CHANNEL_SPACING_400K] = 16,
|
|
};
|
|
|
|
/* IEEE Std 802.15.4™-2015
|
|
* Table 10-10—Channel numbering for SUN PHYs,
|
|
* index is channel spacing */
|
|
static const uint16_t _chan_center_freq0_subghz_25khz[] = {
|
|
[FSK_CHANNEL_SPACING_200K] = 863125U / 25,
|
|
[FSK_CHANNEL_SPACING_400K] = 863225U / 25
|
|
};
|
|
|
|
/* IEEE Std 802.15.4™-2015
|
|
* Table 10-10—Channel numbering for SUN PHYs,
|
|
* index is channel spacing */
|
|
static const uint16_t _chan_center_freq0_24ghz_25khz[] = {
|
|
[FSK_CHANNEL_SPACING_200K] = (2400200U - CCF0_24G_OFFSET) / 25,
|
|
[FSK_CHANNEL_SPACING_400K] = (2400400U - CCF0_24G_OFFSET) / 25
|
|
};
|
|
|
|
/* Table 6-57, index is symbol rate */
|
|
static const uint8_t _FSKPE_Val[3][6] = {
|
|
{ 0x02, 0x0E, 0x3E, 0x74, 0x05, 0x13 }, /* FSKPE0 */
|
|
{ 0x03, 0x0F, 0x3F, 0x7F, 0x3C, 0x29 }, /* FSKPE1 */
|
|
{ 0xFC, 0xF0, 0xC0, 0x80, 0xC3, 0xC7 } /* FSKPE2 */
|
|
};
|
|
|
|
/* table 6-51: Symbol Rate Settings */
|
|
static uint8_t _TXDFE_SR(at86rf215_t *dev, uint8_t srate)
|
|
{
|
|
const uint8_t version = at86rf215_reg_read(dev, RG_RF_VN);
|
|
|
|
switch (srate) {
|
|
case FSK_SRATE_50K:
|
|
return version == 1 ? RF_SR_400K : RF_SR_500K;
|
|
case FSK_SRATE_100K:
|
|
return version == 1 ? RF_SR_800K : RF_SR_1000K;
|
|
case FSK_SRATE_150K:
|
|
case FSK_SRATE_200K:
|
|
return RF_SR_2000K;
|
|
case FSK_SRATE_300K:
|
|
case FSK_SRATE_400K:
|
|
return RF_SR_4000K;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* table 6-51: Symbol Rate Settings */
|
|
static uint8_t _RXDFE_SR(uint8_t srate)
|
|
{
|
|
switch (srate) {
|
|
case FSK_SRATE_50K:
|
|
return RF_SR_400K;
|
|
case FSK_SRATE_100K:
|
|
return RF_SR_800K;
|
|
case FSK_SRATE_150K:
|
|
case FSK_SRATE_200K:
|
|
return RF_SR_1000K;
|
|
case FSK_SRATE_300K:
|
|
case FSK_SRATE_400K:
|
|
return RF_SR_2000K;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* table 6-53 Recommended Configuration of the Transmitter Frontend */
|
|
static uint8_t _TXCUTC_PARAMP(uint8_t srate)
|
|
{
|
|
switch (srate) {
|
|
case FSK_SRATE_50K:
|
|
return RF_PARAMP32U;
|
|
case FSK_SRATE_100K:
|
|
case FSK_SRATE_150K:
|
|
case FSK_SRATE_200K:
|
|
return RF_PARAMP16U;
|
|
case FSK_SRATE_300K:
|
|
case FSK_SRATE_400K:
|
|
return RF_PARAMP8U;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Table 6-53. Recommended Configuration of the Transmitter Frontend (modulation index 0.5) */
|
|
static uint8_t _TXCUTC_LPFCUT_half(uint8_t srate)
|
|
{
|
|
switch (srate) {
|
|
case FSK_SRATE_50K:
|
|
return RF_FLC80KHZ;
|
|
case FSK_SRATE_100K:
|
|
return RF_FLC100KHZ;
|
|
case FSK_SRATE_150K:
|
|
return RF_FLC160KHZ;
|
|
case FSK_SRATE_200K:
|
|
return RF_FLC200KHZ;
|
|
case FSK_SRATE_300K:
|
|
return RF_FLC315KHZ;
|
|
case FSK_SRATE_400K:
|
|
return RF_FLC400KHZ;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* Table 6-54. Recommended Configuration of the Transmitter Frontend (modulation index 1) */
|
|
static uint8_t _TXCUTC_LPFCUT_full(uint8_t srate)
|
|
{
|
|
switch (srate) {
|
|
case FSK_SRATE_50K:
|
|
return RF_FLC80KHZ;
|
|
case FSK_SRATE_100K:
|
|
return RF_FLC160KHZ;
|
|
case FSK_SRATE_150K:
|
|
return RF_FLC250KHZ;
|
|
case FSK_SRATE_200K:
|
|
return RF_FLC315KHZ;
|
|
case FSK_SRATE_300K:
|
|
return RF_FLC500KHZ;
|
|
case FSK_SRATE_400K:
|
|
return RF_FLC625KHZ;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static inline uint8_t _TXCUTC_LPFCUT(uint8_t srate, bool half)
|
|
{
|
|
return half ? _TXCUTC_LPFCUT_half(srate) : _TXCUTC_LPFCUT_full(srate);
|
|
}
|
|
|
|
/* Table 6-60. Recommended Configuration values of the sub-1GHz Receiver Frontend (modulation index 1/2) */
|
|
static uint8_t _RXBWC_BW_subGHz_half(uint8_t srate)
|
|
{
|
|
switch (srate) {
|
|
case FSK_SRATE_50K:
|
|
return RF_BW160KHZ_IF250KHZ;
|
|
case FSK_SRATE_100K:
|
|
return RF_BW200KHZ_IF250KHZ;
|
|
case FSK_SRATE_150K:
|
|
case FSK_SRATE_200K:
|
|
return RF_BW320KHZ_IF500KHZ;
|
|
case FSK_SRATE_300K:
|
|
return (RF_BW500KHZ_IF500KHZ | (1 << RXBWC_IFS_SHIFT));
|
|
case FSK_SRATE_400K:
|
|
return RF_BW630KHZ_IF1000KHZ;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Table 6-61. Recommended Configuration values of the 2.4GHz Receiver Frontend (modulation index 1/2) */
|
|
static uint8_t _RXBWC_BW_2dot4GHz_half(uint8_t srate)
|
|
{
|
|
switch (srate) {
|
|
case FSK_SRATE_50K:
|
|
return RF_BW160KHZ_IF250KHZ;
|
|
case FSK_SRATE_100K:
|
|
return RF_BW200KHZ_IF250KHZ;
|
|
case FSK_SRATE_150K:
|
|
return RF_BW320KHZ_IF500KHZ;
|
|
case FSK_SRATE_200K:
|
|
return RF_BW400KHZ_IF500KHZ;
|
|
case FSK_SRATE_300K:
|
|
return RF_BW630KHZ_IF1000KHZ;
|
|
case FSK_SRATE_400K:
|
|
return RF_BW800KHZ_IF1000KHZ;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Table 6-62. Recommended Configuration values of the sub-1GHz Receiver Frontend (modulation index 1) */
|
|
static uint8_t _RXBWC_BW_subGHz_full(uint8_t srate)
|
|
{
|
|
switch (srate) {
|
|
case FSK_SRATE_50K:
|
|
return RF_BW160KHZ_IF250KHZ;
|
|
case FSK_SRATE_100K:
|
|
return RF_BW320KHZ_IF500KHZ;
|
|
case FSK_SRATE_150K:
|
|
return RF_BW400KHZ_IF500KHZ;
|
|
case FSK_SRATE_200K:
|
|
return (RF_BW500KHZ_IF500KHZ | (1 << RXBWC_IFS_SHIFT));
|
|
case FSK_SRATE_300K:
|
|
return RF_BW630KHZ_IF1000KHZ;
|
|
case FSK_SRATE_400K:
|
|
return (RF_BW1000KHZ_IF1000KHZ | (1 << RXBWC_IFS_SHIFT));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Table 6-63. Recommended Configuration values of the 2.4 GHz Receiver Frontend (modulation index 1) */
|
|
static uint8_t _RXBWC_BW_2dot4GHz_full(uint8_t srate)
|
|
{
|
|
switch (srate) {
|
|
case FSK_SRATE_50K:
|
|
return RF_BW200KHZ_IF250KHZ;
|
|
case FSK_SRATE_100K:
|
|
return RF_BW400KHZ_IF500KHZ;
|
|
case FSK_SRATE_150K:
|
|
case FSK_SRATE_200K:
|
|
return RF_BW630KHZ_IF1000KHZ;
|
|
case FSK_SRATE_300K:
|
|
return RF_BW800KHZ_IF1000KHZ;
|
|
case FSK_SRATE_400K:
|
|
return (RF_BW1000KHZ_IF1000KHZ | (1 << RXBWC_IFS_SHIFT));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static inline uint8_t _RXBWC_BW(uint8_t srate, bool subGHz, bool half)
|
|
{
|
|
if (subGHz) {
|
|
return half ? _RXBWC_BW_subGHz_half(srate) : _RXBWC_BW_subGHz_full(srate);
|
|
} else {
|
|
return half ? _RXBWC_BW_2dot4GHz_half(srate) : _RXBWC_BW_2dot4GHz_full(srate);
|
|
}
|
|
}
|
|
|
|
static uint8_t _RXDFE_RCUT_half(uint8_t srate, bool subGHz)
|
|
{
|
|
if (srate == FSK_SRATE_200K) {
|
|
return RF_RCUT_FS_BY_5P3;
|
|
}
|
|
|
|
if (srate == FSK_SRATE_400K && !subGHz) {
|
|
return RF_RCUT_FS_BY_5P3;
|
|
}
|
|
|
|
return RF_RCUT_FS_BY_8;
|
|
}
|
|
|
|
static uint8_t _RXDFE_RCUT_full(uint8_t srate, bool subGHz)
|
|
{
|
|
switch (srate) {
|
|
case FSK_SRATE_50K:
|
|
case FSK_SRATE_100K:
|
|
case FSK_SRATE_300K:
|
|
return RF_RCUT_FS_BY_5P3;
|
|
case FSK_SRATE_150K:
|
|
case FSK_SRATE_400K:
|
|
return subGHz ? RF_RCUT_FS_BY_5P3 : RF_RCUT_FS_BY_4;
|
|
case FSK_SRATE_200K:
|
|
return subGHz ? RF_RCUT_FS_BY_4 : RF_RCUT_FS_BY_2P6;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Table 6-64. Minimum Preamble Length */
|
|
static uint8_t _FSKPL(uint8_t srate)
|
|
{
|
|
switch (srate) {
|
|
case FSK_SRATE_50K:
|
|
return 2;
|
|
case FSK_SRATE_100K:
|
|
return 3;
|
|
case FSK_SRATE_150K:
|
|
case FSK_SRATE_200K:
|
|
case FSK_SRATE_300K:
|
|
return 8;
|
|
case FSK_SRATE_400K:
|
|
return 10;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* fsk modulation indices / 8 */
|
|
static const uint8_t _fsk_mod_idx[] = {
|
|
3, 4, 6, 8, 10, 12, 14, 16
|
|
};
|
|
|
|
/* FSK modulation scale / 8 */
|
|
static const uint8_t _fsk_mod_idx_scale[] = {
|
|
7, 8, 9, 10
|
|
};
|
|
|
|
static void _fsk_mod_idx_get(uint8_t num, uint8_t *idx, uint8_t *scale)
|
|
{
|
|
*idx = 0;
|
|
*scale = 0;
|
|
|
|
uint8_t diff = 0xFF;
|
|
for (uint8_t i = 0; i < ARRAY_SIZE(_fsk_mod_idx_scale); ++i) {
|
|
for (uint8_t j = 0; j < ARRAY_SIZE(_fsk_mod_idx); ++j) {
|
|
if (abs(num - _fsk_mod_idx_scale[i] * _fsk_mod_idx[j]) < diff) {
|
|
diff = abs(num - _fsk_mod_idx_scale[i] * _fsk_mod_idx[j]);
|
|
*idx = j;
|
|
*scale = i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static inline uint8_t _RXDFE_RCUT(uint8_t srate, bool subGHz, bool half)
|
|
{
|
|
return half ? _RXDFE_RCUT_half(srate, subGHz) : _RXDFE_RCUT_full(srate, subGHz);
|
|
}
|
|
|
|
void at86rf215_FSK_prepare_rx(at86rf215_t *dev)
|
|
{
|
|
at86rf215_reg_write(dev, dev->BBC->RG_FSKPLL, dev->fsk_pl);
|
|
|
|
/* Preamble detection takes RSSI values into account if the preamble length is less than 8 octets. */
|
|
if (dev->fsk_pl < 8) {
|
|
at86rf215_reg_or(dev, dev->BBC->RG_FSKC2, FSKC2_PDTM_MASK);
|
|
} else {
|
|
at86rf215_reg_and(dev, dev->BBC->RG_FSKC2, (uint8_t) ~FSKC2_PDTM_MASK);
|
|
}
|
|
}
|
|
|
|
void at86rf215_FSK_prepare_tx(at86rf215_t *dev)
|
|
{
|
|
/* send long preamble when TXing */
|
|
at86rf215_reg_write(dev, dev->BBC->RG_FSKPLL, dev->fsk_pl * 8);
|
|
}
|
|
|
|
static void _set_srate(at86rf215_t *dev, uint8_t srate, bool mod_idx_half)
|
|
{
|
|
/* Set Receiver Bandwidth: fBW = 160 kHz, fIF = 250 kHz */
|
|
at86rf215_reg_write(dev, dev->RF->RG_RXBWC, _RXBWC_BW(srate, is_subGHz(dev), mod_idx_half));
|
|
/* fS = 400 kHz; fCUT = fS/5.333 = 75 kHz */
|
|
at86rf215_reg_write(dev, dev->RF->RG_RXDFE, _RXDFE_SR(srate)
|
|
| _RXDFE_RCUT(srate, is_subGHz(dev), mod_idx_half));
|
|
/* Power Amplifier Ramp Time = 32 µs; fLPCUT = 80 kHz */
|
|
at86rf215_reg_write(dev, dev->RF->RG_TXCUTC, _TXCUTC_PARAMP(srate)
|
|
| _TXCUTC_LPFCUT(srate, mod_idx_half));
|
|
/* fS = 500 kHz; fCUT = fS/2 = 250 kHz */
|
|
at86rf215_reg_write(dev, dev->RF->RG_TXDFE, _TXDFE_SR(dev, srate)
|
|
| (mod_idx_half ? RF_RCUT_FS_BY_8 : RF_RCUT_FS_BY_2)
|
|
| TXDFE_DM_MASK);
|
|
|
|
/* configure pre-emphasis */
|
|
at86rf215_reg_write(dev, dev->BBC->RG_FSKPE0, _FSKPE_Val[0][srate]);
|
|
at86rf215_reg_write(dev, dev->BBC->RG_FSKPE1, _FSKPE_Val[1][srate]);
|
|
at86rf215_reg_write(dev, dev->BBC->RG_FSKPE2, _FSKPE_Val[2][srate]);
|
|
|
|
/* set preamble length in octets */
|
|
dev->fsk_pl = _FSKPL(srate);
|
|
|
|
at86rf215_FSK_prepare_rx(dev);
|
|
|
|
/* t_on = t_off = t_min (time to TX minimal preamble length) */
|
|
uint8_t t_on = 4 * _FSKPL(srate) * 100 / _at86rf215_fsk_srate_10kHz[srate];
|
|
|
|
at86rf215_reg_write(dev, dev->BBC->RG_FSKRPCONT, t_on);
|
|
at86rf215_reg_write(dev, dev->BBC->RG_FSKRPCOFFT, t_on);
|
|
|
|
DEBUG("[at86rf215] t_on: %d µs\n", t_on);
|
|
|
|
/* set symbol rate, preamble is less than 256 so set high bits 0 */
|
|
at86rf215_reg_write(dev, dev->BBC->RG_FSKC1, srate);
|
|
}
|
|
|
|
static void _set_ack_timeout(at86rf215_t *dev, bool mord4, bool fec)
|
|
{
|
|
uint8_t ack_len = AT86RF215_ACK_PSDU_BYTES;
|
|
|
|
/* PHR uses same data rate as PSDU */
|
|
ack_len += 2;
|
|
|
|
/* 4-FSK doubles data rate */
|
|
if (mord4) {
|
|
ack_len /= 2;
|
|
}
|
|
|
|
/* forward error correction halves data rate */
|
|
if (fec) {
|
|
ack_len *= 2;
|
|
}
|
|
|
|
dev->ack_timeout_usec = dev->csma_backoff_period
|
|
+ IEEE802154G_ATURNAROUNDTIME_US
|
|
/* long Preamble + SFD; SFD=2 */
|
|
+ ((dev->fsk_pl * 8 + 2)
|
|
+ ack_len) * 8 * FSK_SYMBOL_TIME_US;
|
|
|
|
DEBUG("[%s] ACK timeout: %"PRIu32" µs\n", "FSK", dev->ack_timeout_usec);
|
|
}
|
|
|
|
static void _set_csma_backoff_period(at86rf215_t *dev)
|
|
{
|
|
dev->csma_backoff_period = IEEE802154_CCA_DURATION_IN_SYMBOLS * FSK_SYMBOL_TIME_US
|
|
+ IEEE802154G_ATURNAROUNDTIME_US;
|
|
|
|
DEBUG("[%s] CSMA BACKOFF: %"PRIu32" µs\n", "FSK", dev->csma_backoff_period);
|
|
}
|
|
|
|
int at86rf215_configure_FSK(at86rf215_t *dev, uint8_t srate, uint8_t mod_idx, uint8_t mod_order, uint8_t fec)
|
|
{
|
|
if (srate > FSK_SRATE_400K) {
|
|
DEBUG("[%s] invalid symbol rate: %d\n", __func__, srate);
|
|
return -EINVAL;
|
|
}
|
|
|
|
bool mod_idx_half = mod_idx <= 32;
|
|
uint8_t _mod_idx, _mod_idx_scale;
|
|
_fsk_mod_idx_get(mod_idx, &_mod_idx, &_mod_idx_scale);
|
|
|
|
at86rf215_await_state_end(dev, RF_STATE_TX);
|
|
|
|
/* disable radio */
|
|
at86rf215_reg_write(dev, dev->BBC->RG_PC, 0);
|
|
|
|
_set_srate(dev, srate, mod_idx_half);
|
|
|
|
/* set receiver gain target according to data sheet */
|
|
at86rf215_reg_write(dev, dev->RF->RG_AGCS, 1 << AGCS_TGT_SHIFT);
|
|
/* enable automatic receiver gain */
|
|
at86rf215_reg_write(dev, dev->RF->RG_AGCC, AGCC_EN_MASK);
|
|
|
|
/* set Bandwidth Time Product, Modulation Index & Modulation Order */
|
|
/* effective modulation index = MIDXS * MIDX */
|
|
at86rf215_reg_write(dev, dev->BBC->RG_FSKC0, FSK_BT_20
|
|
| (_mod_idx << FSKC0_MIDX_SHIFT)
|
|
| (_mod_idx_scale << FSKC0_MIDXS_SHIFT)
|
|
| mod_order
|
|
);
|
|
|
|
/* enable direct modulation */
|
|
at86rf215_reg_write(dev, dev->BBC->RG_FSKDM, FSKDM_EN_MASK | FSKDM_PE_MASK);
|
|
|
|
/* 16 µs base time */
|
|
uint8_t fskrpc = 0x5;
|
|
|
|
/* Enable / Disable Reduced Power Consumption */
|
|
if (dev->flags & AT86RF215_OPT_RPC) {
|
|
fskrpc |= FSKRPC_EN_MASK;
|
|
}
|
|
at86rf215_reg_write(dev, dev->BBC->RG_FSKRPC, fskrpc);
|
|
|
|
/* set forward error correction */
|
|
at86rf215_FSK_set_fec(dev, fec);
|
|
|
|
at86rf215_FSK_set_channel_spacing(dev, FSK_CHANNEL_SPACING_400K);
|
|
|
|
at86rf215_enable_radio(dev, BB_MRFSK);
|
|
|
|
return 0;
|
|
}
|
|
|
|
uint8_t at86rf215_FSK_get_mod_order(at86rf215_t *dev)
|
|
{
|
|
return at86rf215_reg_read(dev, dev->BBC->RG_FSKC0) & FSKC0_MORD_MASK;
|
|
}
|
|
|
|
int at86rf215_FSK_set_mod_order(at86rf215_t *dev, uint8_t mod_order) {
|
|
|
|
at86rf215_await_state_end(dev, RF_STATE_TX);
|
|
|
|
if (mod_order) {
|
|
at86rf215_reg_or(dev, dev->BBC->RG_FSKC0, FSK_MORD_4SFK);
|
|
} else {
|
|
at86rf215_reg_and(dev, dev->BBC->RG_FSKC0, ~FSK_MORD_4SFK);
|
|
}
|
|
|
|
_set_ack_timeout(dev, mod_order, at86rf215_FSK_get_fec(dev));
|
|
return 0;
|
|
}
|
|
|
|
uint8_t at86rf215_FSK_get_mod_idx(at86rf215_t *dev)
|
|
{
|
|
uint8_t fskc0 = at86rf215_reg_read(dev, dev->BBC->RG_FSKC0);
|
|
uint8_t _mod_idx = (fskc0 & FSKC0_MIDX_MASK) >> FSKC0_MIDX_SHIFT;
|
|
uint8_t _mod_idx_scale = (fskc0 & FSKC0_MIDXS_MASK) >> FSKC0_MIDXS_SHIFT;
|
|
|
|
return _fsk_mod_idx[_mod_idx] * _fsk_mod_idx_scale[_mod_idx_scale];
|
|
}
|
|
|
|
int at86rf215_FSK_set_mod_idx(at86rf215_t *dev, uint8_t mod_idx)
|
|
{
|
|
uint8_t _mod_idx, _mod_idx_scale;
|
|
|
|
at86rf215_await_state_end(dev, RF_STATE_TX);
|
|
|
|
_set_srate(dev, at86rf215_FSK_get_srate(dev), mod_idx <= 32);
|
|
|
|
_fsk_mod_idx_get(mod_idx, &_mod_idx, &_mod_idx_scale);
|
|
at86rf215_reg_write(dev, dev->BBC->RG_FSKC0, FSK_BT_20
|
|
| (_mod_idx << FSKC0_MIDX_SHIFT)
|
|
| (_mod_idx_scale << FSKC0_MIDXS_SHIFT)
|
|
| at86rf215_FSK_get_mod_order(dev)
|
|
);
|
|
return 0;
|
|
}
|
|
|
|
uint8_t at86rf215_FSK_get_srate(at86rf215_t *dev)
|
|
{
|
|
return at86rf215_reg_read(dev, dev->BBC->RG_FSKC1) & FSKC1_SRATE_MASK;
|
|
}
|
|
|
|
int at86rf215_FSK_set_srate(at86rf215_t *dev, uint8_t srate)
|
|
{
|
|
if (srate > FSK_SRATE_400K) {
|
|
return -1;
|
|
}
|
|
|
|
at86rf215_await_state_end(dev, RF_STATE_TX);
|
|
|
|
_set_srate(dev, srate, at86rf215_FSK_get_mod_idx(dev) <= 32);
|
|
_set_csma_backoff_period(dev);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int at86rf215_FSK_set_fec(at86rf215_t *dev, uint8_t mode)
|
|
{
|
|
at86rf215_await_state_end(dev, RF_STATE_TX);
|
|
|
|
switch (mode) {
|
|
case IEEE802154_FEC_NONE:
|
|
at86rf215_reg_and(dev, dev->BBC->RG_FSKPHRTX, ~FSKPHRTX_SFD_MASK);
|
|
break;
|
|
case IEEE802154_FEC_NRNSC:
|
|
at86rf215_reg_or(dev, dev->BBC->RG_FSKPHRTX, FSKPHRTX_SFD_MASK);
|
|
at86rf215_reg_and(dev, dev->BBC->RG_FSKC2, ~FSKC2_FECS_MASK);
|
|
break;
|
|
case IEEE802154_FEC_RSC:
|
|
at86rf215_reg_or(dev, dev->BBC->RG_FSKPHRTX, FSKPHRTX_SFD_MASK);
|
|
at86rf215_reg_or(dev, dev->BBC->RG_FSKC2, FSKC2_FECS_MASK);
|
|
break;
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
_set_ack_timeout(dev, mode, at86rf215_FSK_get_mod_order(dev));
|
|
_set_csma_backoff_period(dev);
|
|
|
|
return 0;
|
|
}
|
|
|
|
uint8_t at86rf215_FSK_get_fec(at86rf215_t *dev)
|
|
{
|
|
/* SFD0 -> Uncoded IEEE mode */
|
|
/* SFD1 -> Coded IEEE mode */
|
|
if (!(at86rf215_reg_read(dev, dev->BBC->RG_FSKPHRTX) & FSKPHRTX_SFD_MASK)) {
|
|
return IEEE802154_FEC_NONE;
|
|
}
|
|
|
|
if (at86rf215_reg_read(dev, dev->BBC->RG_FSKC2) & FSKC2_FECS_MASK) {
|
|
return IEEE802154_FEC_RSC;
|
|
} else {
|
|
return IEEE802154_FEC_NRNSC;
|
|
}
|
|
}
|
|
|
|
int at86rf215_FSK_set_channel_spacing(at86rf215_t *dev, uint8_t ch_space)
|
|
{
|
|
if (ch_space > FSK_CHANNEL_SPACING_400K) {
|
|
return -1;
|
|
}
|
|
|
|
at86rf215_await_state_end(dev, RF_STATE_TX);
|
|
|
|
/* set channel spacing, same for both sub-GHz & 2.4 GHz */
|
|
at86rf215_reg_write(dev, dev->RF->RG_CS, _at86rf215_fsk_channel_spacing_25kHz[ch_space]);
|
|
|
|
/* set center frequency */
|
|
if (is_subGHz(dev)) {
|
|
at86rf215_reg_write16(dev, dev->RF->RG_CCF0L, _chan_center_freq0_subghz_25khz[ch_space]);
|
|
} else {
|
|
at86rf215_reg_write16(dev, dev->RF->RG_CCF0L, _chan_center_freq0_24ghz_25khz[ch_space]);
|
|
}
|
|
|
|
DEBUG("CCF0 configured as: %lu kHz\n",
|
|
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->netdev.chan = at86rf215_chan_valid(dev, dev->netdev.chan);
|
|
at86rf215_reg_write16(dev, dev->RF->RG_CNL, dev->netdev.chan);
|
|
|
|
return 0;
|
|
}
|