Merge pull request #14959 from benpicco/at86rf215-mr-fsk

drivers/at86rf215: implement MR-FSK
This commit is contained in:
benpicco 2020-11-03 11:26:24 +01:00 committed by GitHub
commit 9681c204d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 1273 additions and 11 deletions

View File

@ -72,6 +72,11 @@ config AT86RF215_DEFAULT_MR_OFDM
help
MR-O-OFDM according to IEEE 802.15.4g
config AT86RF215_DEFAULT_MR_FSK
bool "MR-FSK"
help
MR-FSK according to IEEE 802.15.4g
endchoice
menu "O-QPSK (802.15.4) configuration"
@ -148,4 +153,52 @@ config AT86RF215_DEFAULT_MR_OFDM_MCS
endmenu
menu "MR-FSK (802.15.4g) configuration"
depends on AT86RF215_DEFAULT_MR_FSK
config AT86RF215_DEFAULT_MR_FSK_SRATE
int "Default MR-FSK Symbol Rate"
range 0 5
default 3
help
Default Symbol Rate of the MR-FSK PHY
0: 50 kHz
1: 100 kHZ
2: 150 kHZ
3: 200 kHZ
4: 300 kHZ
5: 400 kHZ
config AT86RF215_DEFAULT_MR_FSK_MOD_IDX
int "Default MR-FSK Modulation Index"
range 0 128
default 64
help
Default Modulation Index of the MR-FSK PHY as a fraction of 64.
(32/64 = 0.5; 64/64 = 1 …)
config AT86RF215_DEFAULT_MR_FSK_MORD
int "Default MR-FSK Modulation Order"
range 0 1
default 1
help
Default FSK Modulation Order
0: 2-FSK
1: 4-FSk
config AT86RF215_DEFAULT_MR_FSK_FEC
int "Default MR-FSK Forward Error Correction Scheme"
range 0 2
default 0
help
Default Settings for Forward Error Correction
0: No Forward Error Correction
1: Non-recursive and non-systematic code
2: Recursive and systematic code
endmenu
endif # KCONFIG_USEMODULE_AT86RF215

View File

@ -14,6 +14,7 @@ DEFAULT_MODULE += netdev_ieee802154_multimode
DEFAULT_MODULE += netdev_ieee802154_oqpsk
DEFAULT_MODULE += netdev_ieee802154_mr_oqpsk
DEFAULT_MODULE += netdev_ieee802154_mr_ofdm
DEFAULT_MODULE += netdev_ieee802154_mr_fsk
FEATURES_REQUIRED += periph_gpio
FEATURES_REQUIRED += periph_gpio_irq

View File

@ -160,6 +160,12 @@ if (!IS_ACTIVE(CONFIG_AT86RF215_USE_CLOCK_OUTPUT)){
at86rf215_configure_OFDM(dev, CONFIG_AT86RF215_DEFAULT_MR_OFDM_OPT,
CONFIG_AT86RF215_DEFAULT_MR_OFDM_MCS);
}
if (CONFIG_AT86RF215_DEFAULT_PHY_MODE == IEEE802154_PHY_MR_FSK) {
at86rf215_configure_FSK(dev, CONFIG_AT86RF215_DEFAULT_MR_FSK_SRATE,
CONFIG_AT86RF215_DEFAULT_MR_FSK_MOD_IDX,
CONFIG_AT86RF215_DEFAULT_MR_FSK_MORD,
CONFIG_AT86RF215_DEFAULT_MR_FSK_FEC);
}
/* set default channel */
at86rf215_set_chan(dev, dev->netdev.chan);

View File

@ -0,0 +1,617 @@
/*
* 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-10Channel 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-10Channel 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;
}

View File

@ -212,6 +212,13 @@ void at86rf215_enable_rpc(at86rf215_t *dev)
/* no Reduced Power mode available for OFDM */
#ifdef MODULE_NETDEV_IEEE802154_MR_FSK
if (dev->fsk_pl) {
/* MR-FSK */
at86rf215_reg_or(dev, dev->BBC->RG_FSKRPC, FSKRPC_EN_MASK);
return;
}
#endif
#ifdef MODULE_NETDEV_IEEE802154_MR_OQPSK
{
/* MR-O-QPSK */
@ -228,6 +235,13 @@ void at86rf215_disable_rpc(at86rf215_t *dev)
/* no Reduced Power mode available for OFDM */
#ifdef MODULE_NETDEV_IEEE802154_MR_FSK
if (dev->fsk_pl) {
/* MR-FSK */
at86rf215_reg_and(dev, dev->BBC->RG_FSKRPC, ~FSKRPC_EN_MASK);
return;
}
#endif
#ifdef MODULE_NETDEV_IEEE802154_MR_OQPSK
{
/* MR-O-QPSK */

View File

@ -67,6 +67,20 @@ static bool _is_busy(at86rf215_t *dev)
return false;
}
static uint8_t _get_best_match(const uint8_t *array, uint8_t len, uint8_t val)
{
uint8_t res = 0;
uint8_t best = 0xFF;
for (uint8_t i = 0; i < len; ++i) {
if (abs((int)array[i] - val) < best) {
best = abs((int)array[i] - val);
res = i;
}
}
return res;
}
/* executed in the GPIO ISR context */
static void _irq_handler(void *arg)
{
@ -393,7 +407,40 @@ static int _get(netdev_t *netdev, netopt_t opt, void *val, size_t max_len)
*((int8_t *)val) = at86rf215_get_phy_mode(dev);
res = max_len;
break;
#ifdef MODULE_NETDEV_IEEE802154_MR_FSK
case NETOPT_MR_FSK_MODULATION_INDEX:
assert(max_len >= sizeof(int8_t));
*((int8_t *)val) = at86rf215_FSK_get_mod_idx(dev);
res = max_len;
break;
case NETOPT_MR_FSK_MODULATION_ORDER:
assert(max_len >= sizeof(int8_t));
/* 0 -> 2-FSK, 1 -> 4-FSK */
*((int8_t *)val) = 2 + 2 * at86rf215_FSK_get_mod_order(dev);
res = max_len;
break;
case NETOPT_MR_FSK_SRATE:
assert(max_len >= sizeof(uint16_t));
/* netopt expects symbol rate in kHz, internally it's stored in 10kHz steps */
*((uint16_t *)val) = _at86rf215_fsk_srate_10kHz[at86rf215_FSK_get_srate(dev)]
* 10;
res = max_len;
break;
case NETOPT_MR_FSK_FEC:
assert(max_len >= sizeof(uint8_t));
*((uint8_t *)val) = at86rf215_FSK_get_fec(dev);
res = max_len;
break;
case NETOPT_CHANNEL_SPACING:
assert(max_len >= sizeof(uint16_t));
*((uint16_t *)val) = at86rf215_get_channel_spacing(dev);
res = max_len;
break;
#endif /* MODULE_NETDEV_IEEE802154_MR_FSK */
#ifdef MODULE_NETDEV_IEEE802154_MR_OFDM
case NETOPT_MR_OFDM_OPTION:
assert(max_len >= sizeof(int8_t));
@ -601,11 +648,93 @@ static int _set(netdev_t *netdev, netopt_t opt, const void *val, size_t len)
res = sizeof(uint8_t);
break;
#endif /* MODULE_NETDEV_IEEE802154_MR_OFDM */
#ifdef MODULE_NETDEV_IEEE802154_MR_FSK
case IEEE802154_PHY_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));
res = sizeof(uint8_t);
break;
#endif /* MODULE_NETDEV_IEEE802154_MR_FSK */
default:
return -ENOTSUP;
}
break;
#ifdef MODULE_NETDEV_IEEE802154_MR_FSK
case NETOPT_MR_FSK_MODULATION_INDEX:
if (at86rf215_get_phy_mode(dev) != IEEE802154_PHY_MR_FSK) {
return -ENOTSUP;
}
if (at86rf215_FSK_set_mod_idx(dev, *(uint8_t *)val) == 0) {
res = at86rf215_FSK_get_mod_idx(dev);
} else {
res = -ERANGE;
}
break;
case NETOPT_MR_FSK_MODULATION_ORDER:
if (at86rf215_get_phy_mode(dev) != IEEE802154_PHY_MR_FSK) {
return -ENOTSUP;
}
if (*(uint8_t *)val != 2 && *(uint8_t *)val != 4) {
res = -ERANGE;
} else {
/* 4-FSK -> 1, 2-FSK -> 0 */
at86rf215_FSK_set_mod_order(dev, *(uint8_t *)val >> 2);
res = sizeof(uint8_t);
}
break;
case NETOPT_MR_FSK_SRATE:
if (at86rf215_get_phy_mode(dev) != IEEE802154_PHY_MR_FSK) {
return -ENOTSUP;
}
/* find the closest symbol rate value (in 10 kHz) that matches
the requested input (in kHz) */
res = _get_best_match(_at86rf215_fsk_srate_10kHz,
FSK_SRATE_400K + 1, *(uint16_t *)val / 10);
if (at86rf215_FSK_set_srate(dev, res) == 0) {
res = 10 * _at86rf215_fsk_srate_10kHz[res];
} else {
res = -ERANGE;
}
break;
case NETOPT_MR_FSK_FEC:
if (at86rf215_get_phy_mode(dev) != IEEE802154_PHY_MR_FSK) {
return -ENOTSUP;
}
if (at86rf215_FSK_set_fec(dev, *(uint8_t *)val) == 0) {
res = sizeof(uint8_t);
} else {
res = -ERANGE;
}
break;
case NETOPT_CHANNEL_SPACING:
if (at86rf215_get_phy_mode(dev) != IEEE802154_PHY_MR_FSK) {
return -ENOTSUP;
}
/* find the closest channel spacing value (in 25 kHz) that matches
the requested input (in kHz) */
res = _get_best_match(_at86rf215_fsk_channel_spacing_25kHz,
FSK_CHANNEL_SPACING_400K + 1, *(uint16_t *)val / 25);
if (at86rf215_FSK_set_channel_spacing(dev, res) == 0) {
res = 25 * _at86rf215_fsk_channel_spacing_25kHz[res];
} else {
res = -ERANGE;
}
break;
#endif /* MODULE_NETDEV_IEEE802154_MR_FSK */
#ifdef MODULE_NETDEV_IEEE802154_MR_OFDM
case NETOPT_MR_OFDM_OPTION:
if (at86rf215_get_phy_mode(dev) != IEEE802154_PHY_MR_OFDM) {
@ -937,6 +1066,13 @@ static void _isr(netdev_t *netdev)
rx_ack_req = 0;
}
#ifdef MODULE_NETDEV_IEEE802154_MR_FSK
/* listen for short preamble in RX */
if (bb_irq_mask & BB_IRQ_TXFE && dev->fsk_pl) {
at86rf215_FSK_prepare_rx(dev);
}
#endif /* MODULE_NETDEV_IEEE802154_MR_FSK */
if (dev->flags & AT86RF215_OPT_CCA_PENDING) {
/* Start ED or handle result */
@ -957,6 +1093,13 @@ static void _isr(netdev_t *netdev)
/* start transmitting the frame */
if (rf_irq_mask & RF_IRQ_TRXRDY) {
#ifdef MODULE_NETDEV_IEEE802154_MR_FSK
/* send long preamble in TX */
if (dev->fsk_pl) {
at86rf215_FSK_prepare_tx(dev);
}
#endif /* MODULE_NETDEV_IEEE802154_MR_FSK */
/* automatically switch to RX when TX is done */
_enable_tx2rx(dev);

View File

@ -314,13 +314,15 @@ static void _set_ack_timeout(at86rf215_t *dev, uint8_t chips, uint8_t mode)
static inline void _set_csma_backoff_period(at86rf215_t *dev, uint8_t chips)
{
dev->csma_backoff_period = AT86RF215_BACKOFF_PERIOD_IN_SYMBOLS * _get_symbol_duration_us(chips);
dev->csma_backoff_period = _get_cca_duration_syms(chips) * _get_symbol_duration_us(chips)
+ IEEE802154G_ATURNAROUNDTIME_US;
DEBUG("[%s] CSMA BACKOFF: %"PRIu32" µs\n", "O-QPSK", dev->csma_backoff_period);
}
static inline void _set_csma_backoff_period_legacy(at86rf215_t *dev)
{
dev->csma_backoff_period = AT86RF215_BACKOFF_PERIOD_IN_SYMBOLS * LEGACY_QPSK_SYMBOL_TIME_US;
dev->csma_backoff_period = (IEEE802154_ATURNAROUNDTIME_IN_SYMBOLS + IEEE802154_CCA_DURATION_IN_SYMBOLS)
* LEGACY_QPSK_SYMBOL_TIME_US;
DEBUG("[%s] CSMA BACKOFF: %"PRIu32" µs\n", "legacy O-QPSK", dev->csma_backoff_period);
}
@ -343,6 +345,11 @@ void _end_configure_OQPSK(at86rf215_t *dev)
dev->netdev.chan = at86rf215_chan_valid(dev, dev->netdev.chan);
at86rf215_reg_write16(dev, dev->RF->RG_CNL, dev->netdev.chan);
/* disable FSK preamble switching */
#ifdef MODULE_NETDEV_IEEE802154_MR_FSK
dev->fsk_pl = 0;
#endif
at86rf215_enable_radio(dev, BB_MROQPSK);
}

View File

@ -268,13 +268,19 @@ int at86rf215_configure_OFDM(at86rf215_t *dev, uint8_t option, uint8_t scheme)
at86rf215_reg_write(dev, dev->BBC->RG_OFDMPHRTX, scheme);
dev->csma_backoff_period = AT86RF215_BACKOFF_PERIOD_IN_SYMBOLS *
OFDM_SYMBOL_TIME_US;
dev->csma_backoff_period = IEEE802154G_ATURNAROUNDTIME_US
+ IEEE802154_CCA_DURATION_IN_SYMBOLS
* OFDM_SYMBOL_TIME_US;
DEBUG("[%s] CSMA BACKOFF: %" PRIu32 " µs\n", "OFDM",
dev->csma_backoff_period);
_set_ack_timeout(dev, option, scheme);
/* disable FSK preamble switching */
#ifdef MODULE_NETDEV_IEEE802154_MR_FSK
dev->fsk_pl = 0;
#endif
at86rf215_enable_radio(dev, BB_MROFDM);
return 0;

View File

@ -43,12 +43,6 @@ extern "C" {
/** Default energy detect threshold for CSMA (reset value) */
#define AT86RF215_EDT_DEFAULT (-84) /* dBm */
/**
* This is used to calculate the csma backoff based on the bitrate.
*/
/** 20 symbols is the std period length */
#define AT86RF215_BACKOFF_PERIOD_IN_SYMBOLS (20U)
/**
* Default Parameters for 802.15.4 retransmissions & CSMA
* @{
@ -139,6 +133,171 @@ void at86rf215_filter_ack(at86rf215_t *dev, bool on);
*/
void at86rf215_get_random(at86rf215_t *dev, void *data, size_t len);
/**
* @ingroup drivers_at86rf215
* @defgroup drivers_at86rf215_fsk AT86RF215 MR-FSK PHY
* @{
*/
/**
* @brief Symbol Rates for register values, in 10kHz
*/
extern const uint8_t _at86rf215_fsk_srate_10kHz[];
/**
* @brief Channel Spacing for register values, in 25kHz
*/
extern const uint8_t _at86rf215_fsk_channel_spacing_25kHz[];
/**
* @brief Configure the radio to make use of FSK modulation
*
* @param[in] dev device to configure
* @param[in] srate symbol rate, possible values: FSK_SRATE_50K FSK_SRATE_400K
* @param[in] mod_idx modulation index, multiplied by 64 (½ -> 32; 1 -> 64)
* @param[in] mod_order modulation order, may be FSK_MORD_2SFK or FSK_MORD_4SFK
* @param[in] fec forward error correction, may be @ref IEEE802154_FEC_NONE,
* @ref IEEE802154_FEC_NRNSC or @ref IEEE802154_FEC_RSC
*
* @return 0 on success, error otherwise
*/
int at86rf215_configure_FSK(at86rf215_t *dev, uint8_t srate, uint8_t mod_idx, uint8_t mod_order, uint8_t fec);
/**
* @brief Configure the symbol rate of the FSK modulation
*
* @param[in] dev device to configure
* @param[in] srate symbol rate, possible values: FSK_SRATE_50K FSK_SRATE_400K
*/
int at86rf215_FSK_set_srate(at86rf215_t *dev, uint8_t srate);
/**
* @brief Get the symbol rate of the FSK modulation
*
* @param[in] dev device to read from
*
* @return symbol rate, possible values: FSK_SRATE_50K FSK_SRATE_400K
*/
uint8_t at86rf215_FSK_get_srate(at86rf215_t *dev);
/**
* @brief Configure the modulation index of the FSK modulation
* The modulation index is a fractional value, it is represented as
* fractions of 64.
* Not all possible fractional values are configurable by the hardware.
* If the fractional can not be mapped to the hardware, the nearest matching
* one is chosen.
*
* @param[in] dev device to configure
* @param[in] mod_idx modulation index, multiplied by 64 (½ -> 32; 1 -> 64)
*
* @return 0 on success, failure otherwise
*/
int at86rf215_FSK_set_mod_idx(at86rf215_t *dev, uint8_t mod_idx);
/**
* @brief Get the current modulation index of the FSK modulation
* The modulation index is a fractional value, it is represented as
* fractions of 64.
*
* @param[in] dev device to read from
*
* @return the current modulation index, multiplied by 64
*/
uint8_t at86rf215_FSK_get_mod_idx(at86rf215_t *dev);
/**
* @brief Configure the Forward Error Correction (coding) scheme for FSK modulation.
* Supported values are:
* - no error correction
* - non-recursive and non-systematic code (NRNSC)
* - recursive and systematic code (RSC)
*
* @param[in] dev device to configure
* @param[in] mode forward error correction, may be @ref IEEE802154_FEC_NONE,
* @ref IEEE802154_FEC_NRNSC or @ref IEEE802154_FEC_RSC
*
* @return 0 on success, failure otherwise
*/
int at86rf215_FSK_set_fec(at86rf215_t *dev, uint8_t mode);
/**
* @brief Get the Forward Error Correction (coding) scheme for FSK modulation.
* Supported values are:
* - no error correction
* - non-recursive and non-systematic code (NRNSC)
* - recursive and systematic code (RSC)
*
* @param[in] dev device to read from
*
* @return current coding scheme, may be @ref IEEE802154_FEC_NONE,
* @ref IEEE802154_FEC_NRNSC or @ref IEEE802154_FEC_RSC
*/
uint8_t at86rf215_FSK_get_fec(at86rf215_t *dev);
/**
* @brief Configure the channel spacing for the FSK modulation
*
* @param[in] dev device to configure
* @param[in] ch_space channel spacing, possible values: FSK_CHANNEL_SPACING_200K _400K
*
* @return 0 on success, failure otherwise
*/
int at86rf215_FSK_set_channel_spacing(at86rf215_t *dev, uint8_t ch_space);
/**
* @brief Get the configured channel spacing
*
* @param[in] dev device to read from
*
* @return channel spacing in kHz
*/
uint16_t at86rf215_get_channel_spacing(at86rf215_t *dev);
/**
* @brief Configure the FSK modulation order.
* You can choose between 2-level and 4-level FSK
*
* @param[in] dev device to configure
* @param[in] mod_order modulation order, may be FSK_MORD_2SFK or FSK_MORD_4SFK
*
* @return 0 on success, failure otherwise
*/
int at86rf215_FSK_set_mod_order(at86rf215_t *dev, uint8_t mod_order);
/**
* @brief Get the current FSK modulation order.
* You can choose between 2-level and 4-level FSK
*
* @param[in] dev device to read from
*
* @return modulation order, may be FSK_MORD_2SFK or FSK_MORD_4SFK
*/
uint8_t at86rf215_FSK_get_mod_order(at86rf215_t *dev);
/**
* @brief The FSK premable length needs to be switched between RX and TX
* This function takes care of putting FSK into RX mode.
*
* @param[in] dev device that is entering RX mode
*/
void at86rf215_FSK_prepare_rx(at86rf215_t *dev);
/**
* @brief The FSK premable length needs to be switched between RX and TX
* This function takes care of putting FSK into TX mode.
*
* @param[in] dev device that is entering TX mode
*/
void at86rf215_FSK_prepare_tx(at86rf215_t *dev);
/** @} */
/**
* @ingroup drivers_at86rf215
* @defgroup drivers_at86rf215_ofdm AT86RF215 MR-OFDM PHY
* @{
*/
/**
* @brief Configure the radio to make use of OFDM modulation.
* There are 4 OFDM options, each with a different number of active tones.
@ -190,6 +349,8 @@ int at86rf215_OFDM_set_option(at86rf215_t *dev, uint8_t option);
*/
uint8_t at86rf215_OFDM_get_option(at86rf215_t *dev);
/** @} */
/**
* @ingroup drivers_at86rf215
* @defgroup drivers_at86rf215_oqpsk AT86RF215 MR-O-QPSK PHY

View File

@ -196,6 +196,42 @@ enum {
#endif
/** @} */
/**
* @name Default MR-FSK Symbol Rate
* @{
*/
#ifndef CONFIG_AT86RF215_DEFAULT_MR_FSK_SRATE
#define CONFIG_AT86RF215_DEFAULT_MR_FSK_SRATE FSK_SRATE_200K
#endif
/** @} */
/**
* @name Default MR-FSK Modulation Index, fraction of 64
* @{
*/
#ifndef CONFIG_AT86RF215_DEFAULT_MR_FSK_MOD_IDX
#define CONFIG_AT86RF215_DEFAULT_MR_FSK_MOD_IDX (64)
#endif
/** @} */
/**
* @name Default MR-FSK Modulation Order
* @{
*/
#ifndef CONFIG_AT86RF215_DEFAULT_MR_FSK_MORD
#define CONFIG_AT86RF215_DEFAULT_MR_FSK_MORD FSK_MORD_4SFK
#endif
/** @} */
/**
* @name Default MR-FSK Forward Error Correction Scheme
* @{
*/
#ifndef CONFIG_AT86RF215_DEFAULT_MR_FSK_FEC
#define CONFIG_AT86RF215_DEFAULT_MR_FSK_FEC IEEE802154_FEC_NONE
#endif
/** @} */
/**
* @brief Default TX power (0dBm)
*/
@ -290,6 +326,9 @@ typedef struct at86rf215 {
uint8_t retries; /**< retries left */
uint8_t csma_retries_max; /**< number of retries until channel is clear */
uint8_t csma_retries; /**< CSMA retries left */
#ifdef MODULE_NETDEV_IEEE802154_MR_FSK
uint8_t fsk_pl; /**< FSK Preamble Length */
#endif
uint8_t csma_minbe; /**< CSMA minimum backoff exponent */
uint8_t csma_maxbe; /**< CSMA maximum backoff exponent */
int8_t csma_ed; /**< CSMA energy detect threshold */

View File

@ -126,7 +126,22 @@ extern "C" {
*
* 802.15.4g, Table 70 (p. 43)
*/
#define IEEE802154G_ATURNAROUNDTIME_US (1 * US_PER_MS)
#define IEEE802154G_ATURNAROUNDTIME_US (1 * US_PER_MS)
/**
* IEEE Std 802.15.4-2020
* Table 11-1PHY constants: The value is 12 for all other PHYs.
*/
#define IEEE802154_ATURNAROUNDTIME_IN_SYMBOLS (12)
/**
* IEEE Std 802.15.4-2020
* Table 11-1PHY constants: For all other PHYs¹, the duration of
* 8 symbol periods.
*
* [1] all but MR-O-QPSK
*/
#define IEEE802154_CCA_DURATION_IN_SYMBOLS (8)
/**
* @brief 802.15.4 PHY modes

View File

@ -689,6 +689,26 @@ typedef enum {
*/
NETOPT_MR_OFDM_MCS,
/**
* @brief (uint8_t) MR-FSK PHY Modulation Index (x 64)
*/
NETOPT_MR_FSK_MODULATION_INDEX,
/**
* @brief (uint8_t) MR-FSK Modulation Order
*/
NETOPT_MR_FSK_MODULATION_ORDER,
/**
* @brief (uint8_t) MR-FSK PHY Symbol Rate (kHz)
*/
NETOPT_MR_FSK_SRATE,
/**
* @brief (uint8_t) MR-FSK PHY Forward Error Correction
*/
NETOPT_MR_FSK_FEC,
/**
* @brief (uint8_t) PHY Channel Spacing (kHz)
*/

View File

@ -113,6 +113,10 @@ static const char *_netopt_strmap[] = {
[NETOPT_MR_OQPSK_RATE] = "NETOPT_MR-O-QPSK_RATE",
[NETOPT_MR_OFDM_OPTION] = "NETOPT_MR-OFDM_OPTION",
[NETOPT_MR_OFDM_MCS] = "NETOPT_MR-OFDM_MCS",
[NETOPT_MR_FSK_MODULATION_INDEX] = "NETOPT_MR-FSK_MODULATION_INDEX",
[NETOPT_MR_FSK_MODULATION_ORDER] = "NETOPT_MR-FSK_MODULATION_ORDER",
[NETOPT_MR_FSK_SRATE] = "NETOPT_MR-FSK_SRATE",
[NETOPT_MR_FSK_FEC] = "NETOPT_MR-FSK_FEC",
[NETOPT_CHANNEL_SPACING] = "NETOPT_CHANNEL_SPACING",
[NETOPT_SYNCWORD] = "NETOPT_SYNCWORD",
[NETOPT_RANDOM] = "NETOPT_RANDOM",

View File

@ -97,6 +97,42 @@ static void str_toupper(char *str)
}
}
__attribute__ ((unused))
static uint8_t gcd(uint8_t a, uint8_t b)
{
if (a == 0 || b == 0) {
return 0;
}
do {
uint8_t r = a % b;
a = b;
b = r;
} while (b);
return a;
}
__attribute__ ((unused))
static void frac_short(uint8_t *a, uint8_t *b)
{
uint8_t d = gcd(*a, *b);
if (d == 0) {
return;
}
*a /= d;
*b /= d;
}
__attribute__ ((unused))
static void frac_extend(uint8_t *a, uint8_t *b, uint8_t base)
{
*a *= base / *b;
*b = base;
}
#ifdef MODULE_NETSTATS
static const char *_netstats_module_to_str(uint8_t module)
{
@ -195,6 +231,13 @@ static void _set_usage(char *cmd_name)
#ifdef MODULE_NETDEV_IEEE802154_MR_OFDM
" * \"option\" - OFDM option\n"
" * \"scheme\" - OFDM modulation & coding scheme\n"
#endif
#ifdef MODULE_NETDEV_IEEE802154_MR_FSK
" * \"modulation_index\" - FSK modulation index\n"
" * \"modulation_order\" - FSK modulation order\n"
" * \"symbol_rate\" - FSK symbol rate\n"
" * \"fec\" - FSK forward error correction\n"
" * \"channel_spacing\" - channel spacing\n"
#endif
" * \"power\" - TX power in dBm\n"
" * \"retrans\" - max. number of retransmissions\n"
@ -362,6 +405,29 @@ static void _print_netopt(netopt_t opt)
break;
#endif /* MODULE_NETDEV_IEEE802154_MR_OFDM */
#ifdef MODULE_NETDEV_IEEE802154_MR_FSK
case NETOPT_MR_FSK_MODULATION_INDEX:
printf("FSK modulation index");
break;
case NETOPT_MR_FSK_MODULATION_ORDER:
printf("FSK modulation order");
break;
case NETOPT_MR_FSK_SRATE:
printf("FSK symbol rate");
break;
case NETOPT_MR_FSK_FEC:
printf("FSK Forward Error Correction");
break;
case NETOPT_CHANNEL_SPACING:
printf("Channel Spacing");
break;
#endif /* MODULE_NETDEV_IEEE802154_MR_FSK */
case NETOPT_CHECKSUM:
printf("checksum");
@ -442,6 +508,14 @@ static const char *_netopt_ofdm_mcs_str[] = {
};
#endif
#ifdef MODULE_NETDEV_IEEE802154_MR_FSK
static const char *_netopt_fec_str[] = {
[IEEE802154_FEC_NONE] = "none",
[IEEE802154_FEC_NRNSC] = "NRNSC",
[IEEE802154_FEC_RSC] = "RSC"
};
#endif
/* for some lines threshold might just be 0, so we can't use _LINE_THRESHOLD
* here */
static unsigned _newline(unsigned threshold, unsigned line_thresh)
@ -628,6 +702,38 @@ static void _netif_list(netif_t *iface)
break;
#endif /* MODULE_NETDEV_IEEE802154_MR_OFDM */
#ifdef MODULE_NETDEV_IEEE802154_MR_FSK
case IEEE802154_PHY_MR_FSK:
printf("\n ");
res = netif_get_opt(iface, NETOPT_MR_FSK_MODULATION_INDEX, 0, &u8, sizeof(u8));
if (res >= 0) {
hwaddr[0] = 64; /* convenient temp var */
frac_short(&u8, hwaddr);
if (hwaddr[0] == 1) {
printf(" modulation index: %u ", u8);
} else {
printf(" modulation index: %u/%u ", u8, hwaddr[0]);
}
}
res = netif_get_opt(iface, NETOPT_MR_FSK_MODULATION_ORDER, 0, &u8, sizeof(u8));
if (res >= 0) {
printf(" %u-FSK ", u8);
}
res = netif_get_opt(iface, NETOPT_MR_FSK_SRATE, 0, &u16, sizeof(u16));
if (res >= 0) {
printf(" symbol rate: %u kHz ", u16);
}
res = netif_get_opt(iface, NETOPT_MR_FSK_FEC, 0, &u8, sizeof(u8));
if (res >= 0) {
printf(" FEC: %s ", _netopt_fec_str[u8]);
}
res = netif_get_opt(iface, NETOPT_CHANNEL_SPACING, 0, &u16, sizeof(u16));
if (res >= 0) {
printf(" BW: %ukHz ", u16);
}
break;
#endif /* MODULE_NETDEV_IEEE802154_MR_FSK */
}
}
#endif /* MODULE_NETDEV_IEEE802154 */
@ -921,6 +1027,57 @@ static int _netif_set_coding_rate(netif_t *iface, char *value)
}
#endif /* MODULE_GNRC_NETIF_CMD_LORA */
#ifdef MODULE_NETDEV_IEEE802154_MR_FSK
static int _netif_set_fsk_fec(netif_t *iface, char *value)
{
/* ignore case */
str_toupper(value);
for (size_t i = 0; i < ARRAY_SIZE(_netopt_fec_str); ++i) {
if (strcmp(value, _netopt_fec_str[i])) {
continue;
}
if (netif_set_opt(iface, NETOPT_MR_FSK_FEC, 0, &i, sizeof(uint8_t)) < 0) {
printf("error: unable to set forward error correction to %s\n", value);
return 1;
}
printf("success: set forward error correction to %s\n", value);
return 0;
}
puts("usage: ifconfig <if_id> set fec [none|NRNSC|RSC]");
return 1;
}
static int _netif_set_fsk_modulation_index(netif_t *iface, char *value)
{
uint8_t a, b;
char* frac = strchr(value, '/');
if (frac) {
*frac = 0;
b = atoi(frac + 1);
} else {
b = 1;
}
a = atoi(value);
frac_extend(&a, &b, 64);
int res = netif_set_opt(iface, NETOPT_MR_FSK_MODULATION_INDEX, 0, &a, sizeof(uint8_t));
if (res < 0) {
printf("error: unable to set modulation index to %d/%d\n", a, b);
return 1;
} else {
printf("success: set modulation index to %d/%d\n", res, b);
}
return 0;
}
#endif /* MODULE_NETDEV_IEEE802154_MR_FSK */
#ifdef MODULE_NETDEV_IEEE802154_MULTIMODE
static int _netif_set_ieee802154_phy_mode(netif_t *iface, char *value)
{
@ -1359,6 +1516,23 @@ static int _netif_set(char *cmd_name, netif_t *iface, char *key, char *value)
return _netif_set_u8(iface, NETOPT_MR_OFDM_MCS, 0, value);
}
#endif /* MODULE_NETDEV_IEEE802154_MR_OFDM */
#ifdef MODULE_NETDEV_IEEE802154_MR_FSK
else if ((strcmp("modulation_index", key) == 0) || (strcmp("midx", key) == 0)) {
return _netif_set_fsk_modulation_index(iface, value);
}
else if ((strcmp("modulation_order", key) == 0) || (strcmp("mord", key) == 0)) {
return _netif_set_u8(iface, NETOPT_MR_FSK_MODULATION_ORDER, 0, value);
}
else if ((strcmp("symbol_rate", key) == 0) || (strcmp("srate", key) == 0)) {
return _netif_set_u16(iface, NETOPT_MR_FSK_SRATE, 0, value);
}
else if ((strcmp("forward_error_correction", key) == 0) || (strcmp("fec", key) == 0)) {
return _netif_set_fsk_fec(iface, value);
}
else if ((strcmp("channel_spacing", key) == 0) || (strcmp("bw", key) == 0)) {
return _netif_set_u16(iface, NETOPT_CHANNEL_SPACING, 0, value);
}
#endif /* MODULE_NETDEV_IEEE802154_MR_FSK */
else if ((strcmp("channel", key) == 0) || (strcmp("chan", key) == 0)) {
return _netif_set_u16(iface, NETOPT_CHANNEL, 0, value);
}

View File

@ -5,8 +5,10 @@ BOARD_INSUFFICIENT_MEMORY := \
arduino-nano \
arduino-uno \
atmega328p \
atmega1284p \
derfmega128 \
i-nucleo-lrwan1 \
mega-xplained \
microduino-corerf \
msb-430 \
msb-430h \