From 3b7de34be2ed2c54e4a691744e51b668a8218fa6 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Thu, 25 May 2023 11:50:24 +0200 Subject: [PATCH 1/6] ieee802154/submac: dynamically set ack timeout/CSMA backoff period --- sys/include/net/ieee802154/submac.h | 2 ++ sys/net/link_layer/ieee802154/submac.c | 23 +++++++++++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/sys/include/net/ieee802154/submac.h b/sys/include/net/ieee802154/submac.h index 3890ab757982..8f9143cb06b6 100644 --- a/sys/include/net/ieee802154/submac.h +++ b/sys/include/net/ieee802154/submac.h @@ -195,6 +195,8 @@ struct ieee802154_submac { const ieee802154_submac_cb_t *cb; /**< pointer to the SubMAC callbacks */ ieee802154_csma_be_t be; /**< CSMA-CA backoff exponent params */ bool wait_for_ack; /**< SubMAC is waiting for an ACK frame */ + uint16_t ack_timeout_us; /**< ACK timeout in µs */ + uint16_t csma_backoff_us; /**< CSMA sender backoff period in µs */ uint16_t panid; /**< IEEE 802.15.4 PAN ID */ uint16_t channel_num; /**< IEEE 802.15.4 channel number */ uint8_t channel_page; /**< IEEE 802.15.4 channel page */ diff --git a/sys/net/link_layer/ieee802154/submac.c b/sys/net/link_layer/ieee802154/submac.c index 471bc0c32ddd..34ed868b6f28 100644 --- a/sys/net/link_layer/ieee802154/submac.c +++ b/sys/net/link_layer/ieee802154/submac.c @@ -227,7 +227,7 @@ static ieee802154_fsm_state_t _fsm_state_prepare(ieee802154_submac_t *submac, if (!_does_handle_csma(dev)) { /* delay for an adequate random backoff period */ uint32_t bp = (random_uint32() & submac->backoff_mask) * - CSMA_SENDER_BACKOFF_PERIOD_UNIT_US; + submac->csma_backoff_us; ztimer_sleep(ZTIMER_USEC, bp); /* Prepare for next iteration */ @@ -282,7 +282,7 @@ static ieee802154_fsm_state_t _fsm_state_tx_process_tx_done(ieee802154_submac_t assert (res >= 0); /* Handle ACK reception */ - ieee802154_submac_ack_timer_set(submac, ACK_TIMEOUT_US); + ieee802154_submac_ack_timer_set(submac, submac->ack_timeout_us); return IEEE802154_FSM_STATE_WAIT_FOR_ACK; } break; @@ -431,6 +431,21 @@ int ieee802154_send(ieee802154_submac_t *submac, const iolist_t *iolist) return 0; } +static int ieee802154_submac_config_phy(ieee802154_submac_t *submac, + const ieee802154_phy_conf_t *conf) +{ + switch (conf->phy_mode) { + case IEEE802154_PHY_OQPSK: + submac->ack_timeout_us = ACK_TIMEOUT_US; + submac->csma_backoff_us = CSMA_SENDER_BACKOFF_PERIOD_UNIT_US; + break; + default: + return -EINVAL; + } + + return ieee802154_radio_config_phy(&submac->dev, conf); +} + int ieee802154_submac_init(ieee802154_submac_t *submac, const network_uint16_t *short_addr, const eui64_t *ext_addr) { @@ -505,7 +520,7 @@ int ieee802154_submac_init(ieee802154_submac_t *submac, const network_uint16_t * .page = submac->channel_page, .pow = submac->tx_pow }; - ieee802154_radio_config_phy(dev, &conf); + ieee802154_submac_config_phy(submac, &conf); ieee802154_radio_set_cca_threshold(dev, CONFIG_IEEE802154_CCA_THRESH_DEFAULT); assert(res >= 0); @@ -539,7 +554,7 @@ int ieee802154_set_phy_conf(ieee802154_submac_t *submac, uint16_t channel_num, } } - res = ieee802154_radio_config_phy(dev, &conf); + res = ieee802154_submac_config_phy(submac, &conf); if (res >= 0) { submac->channel_num = channel_num; From 7b21b66fac33c01dd1cf5113bc232207ec611487 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Thu, 25 May 2023 11:53:51 +0200 Subject: [PATCH 2/6] ieee802154/submac: drop us param from ieee802154_submac_ack_timer_set() --- drivers/netdev_ieee802154_submac/netdev_ieee802154_submac.c | 4 ++-- sys/include/net/ieee802154/submac.h | 4 +--- sys/net/link_layer/ieee802154/submac.c | 2 +- tests/net/ieee802154_submac/main.c | 5 ++--- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/netdev_ieee802154_submac/netdev_ieee802154_submac.c b/drivers/netdev_ieee802154_submac/netdev_ieee802154_submac.c index 1e6bf71d7838..070fa341273c 100644 --- a/drivers/netdev_ieee802154_submac/netdev_ieee802154_submac.c +++ b/drivers/netdev_ieee802154_submac/netdev_ieee802154_submac.c @@ -135,13 +135,13 @@ void ieee802154_submac_bh_request(ieee802154_submac_t *submac) netdev->event_callback(netdev, NETDEV_EVENT_ISR); } -void ieee802154_submac_ack_timer_set(ieee802154_submac_t *submac, uint16_t us) +void ieee802154_submac_ack_timer_set(ieee802154_submac_t *submac) { netdev_ieee802154_submac_t *netdev_submac = container_of(submac, netdev_ieee802154_submac_t, submac); - ztimer_set(ZTIMER_USEC, &netdev_submac->ack_timer, us); + ztimer_set(ZTIMER_USEC, &netdev_submac->ack_timer, submac->ack_timeout_us); } void ieee802154_submac_ack_timer_cancel(ieee802154_submac_t *submac) diff --git a/sys/include/net/ieee802154/submac.h b/sys/include/net/ieee802154/submac.h index 8f9143cb06b6..d8923fa22822 100644 --- a/sys/include/net/ieee802154/submac.h +++ b/sys/include/net/ieee802154/submac.h @@ -503,10 +503,8 @@ int ieee802154_submac_init(ieee802154_submac_t *submac, const network_uint16_t * * @note This function should be implemented by the user of the SubMAC. * * @param[in] submac pointer to the SubMAC descriptor - * @param[in] us microseconds until the ACK timeout timer is fired */ -extern void ieee802154_submac_ack_timer_set(ieee802154_submac_t *submac, - uint16_t us); +extern void ieee802154_submac_ack_timer_set(ieee802154_submac_t *submac); /** * @brief Cancel the ACK timeout timer diff --git a/sys/net/link_layer/ieee802154/submac.c b/sys/net/link_layer/ieee802154/submac.c index 34ed868b6f28..1915d7820632 100644 --- a/sys/net/link_layer/ieee802154/submac.c +++ b/sys/net/link_layer/ieee802154/submac.c @@ -282,7 +282,7 @@ static ieee802154_fsm_state_t _fsm_state_tx_process_tx_done(ieee802154_submac_t assert (res >= 0); /* Handle ACK reception */ - ieee802154_submac_ack_timer_set(submac, submac->ack_timeout_us); + ieee802154_submac_ack_timer_set(submac); return IEEE802154_FSM_STATE_WAIT_FOR_ACK; } break; diff --git a/tests/net/ieee802154_submac/main.c b/tests/net/ieee802154_submac/main.c index 212e38716845..5fb6b73ce330 100644 --- a/tests/net/ieee802154_submac/main.c +++ b/tests/net/ieee802154_submac/main.c @@ -128,10 +128,9 @@ static void _ev_ack_timeout_handler(event_t *event) mutex_unlock(&lock); } -void ieee802154_submac_ack_timer_set(ieee802154_submac_t *submac, uint16_t us) +void ieee802154_submac_ack_timer_set(ieee802154_submac_t *submac) { - (void)submac; - ztimer_set(ZTIMER_USEC, &ack_timer, us); + ztimer_set(ZTIMER_USEC, &ack_timer, submac->ack_timeout_us); } void ieee802154_submac_ack_timer_cancel(ieee802154_submac_t *submac) From f8d38a99e2ebb2191fd02eb89919a928c6cc5501 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Thu, 25 May 2023 12:15:10 +0200 Subject: [PATCH 3/6] ieee802154/submac: implement MR-OQPSK timings --- sys/include/net/ieee802154.h | 27 +++++++- sys/include/net/ieee802154/radio.h | 9 +++ sys/net/link_layer/ieee802154/submac.c | 89 ++++++++++++++++++++++++++ 3 files changed, 124 insertions(+), 1 deletion(-) diff --git a/sys/include/net/ieee802154.h b/sys/include/net/ieee802154.h index 5b4393502d83..7d57db380e0c 100644 --- a/sys/include/net/ieee802154.h +++ b/sys/include/net/ieee802154.h @@ -25,8 +25,9 @@ #include #include "byteorder.h" -#include "net/eui64.h" #include "modules.h" +#include "net/eui64.h" +#include "time_units.h" #ifdef __cplusplus extern "C" { @@ -188,6 +189,16 @@ enum { IEEE802154_FEC_RSC /**< recursive and systematic code */ }; +/** + * @brief 802.15.4 MR-OQPSK chip rates + */ +typedef enum { + IEEE802154_MR_OQPSK_CHIPS_100, /**< 100 kChip/s */ + IEEE802154_MR_OQPSK_CHIPS_200, /**< 200 kChip/s */ + IEEE802154_MR_OQPSK_CHIPS_1000, /**< 1000 kChip/s */ + IEEE802154_MR_OQPSK_CHIPS_2000, /**< 2000 kChip/s */ +} ieee802154_mr_oqpsk_chips_t; + /** * @brief Special address definitions * @{ @@ -256,6 +267,20 @@ extern const uint8_t ieee802154_addr_bcast[IEEE802154_ADDR_BCAST_LEN]; #define CONFIG_IEEE802154_DEFAULT_SUBGHZ_PAGE (2U) #endif +/** + * @brief IEEE802.15.4 MR-OQPSK default chip rate + */ +#ifndef CONFIG_IEEE802154_MR_OQPSK_DEFAULT_CHIPS +#define CONFIG_IEEE802154_MR_OQPSK_DEFAULT_CHIPS IEEE802154_MR_OQPSK_CHIPS_1000 +#endif + +/** + * @brief IEEE802.15.4 MR-OQPSK default rate mode + */ +#ifndef CONFIG_IEEE802154_MR_OQPSK_DEFAULT_RATE +#define CONFIG_IEEE802154_MR_OQPSK_DEFAULT_RATE (2U) +#endif + /** * @brief IEEE802.15.4 default PANID */ diff --git a/sys/include/net/ieee802154/radio.h b/sys/include/net/ieee802154/radio.h index c8f71afa909a..e94f0953e66a 100644 --- a/sys/include/net/ieee802154/radio.h +++ b/sys/include/net/ieee802154/radio.h @@ -459,6 +459,15 @@ typedef struct { int8_t pow; /**< TX power in dBm */ } ieee802154_phy_conf_t; +/** + * @brief extension for IEEE 802.15.4g MR-OQPSK PHY + */ +typedef struct { + ieee802154_phy_conf_t super; /**< common settings */ + ieee802154_mr_oqpsk_chips_t chips; /**< chip rate */ + uint8_t rate_mode; /**< rate mode */ +} ieee802154_mr_oqpks_conf_t; + /** * @brief IEEE 802.15.4 radio operations */ diff --git a/sys/net/link_layer/ieee802154/submac.c b/sys/net/link_layer/ieee802154/submac.c index 1915d7820632..6faef6f6fdc8 100644 --- a/sys/net/link_layer/ieee802154/submac.c +++ b/sys/net/link_layer/ieee802154/submac.c @@ -431,6 +431,91 @@ int ieee802154_send(ieee802154_submac_t *submac, const iolist_t *iolist) return 0; } +/* + * MR-OQPSK timing calculations + * + * The standard unfortunately does not list the formula, instead it has to be pieced together + * from scattered information and tables in the IEEE 802.15.4 document - may contain errors. + */ + +static uint8_t _mr_oqpsk_spreading(uint8_t chips, uint8_t mode) +{ + if (mode == 4) { + return 1; + } + + uint8_t spread = 1 << (3 - mode); + + if (chips == IEEE802154_MR_OQPSK_CHIPS_1000) { + return 2 * spread; + } + + if (chips == IEEE802154_MR_OQPSK_CHIPS_2000) { + return 4 * spread; + } + + return spread; +} + +static inline uint16_t _mr_oqpsk_symbol_duration_us(uint8_t chips) +{ + /* 802.15.4g, Table 183 / Table 165 */ + switch (chips) { + case IEEE802154_MR_OQPSK_CHIPS_100: + return 320; + case IEEE802154_MR_OQPSK_CHIPS_200: + return 160; + case IEEE802154_MR_OQPSK_CHIPS_1000: + case IEEE802154_MR_OQPSK_CHIPS_2000: + default: + return 64; + } +} + +static inline uint8_t _mr_oqpsk_cca_duration_syms(uint8_t chips) +{ + /* 802.15.4g, Table 188 */ + return (chips < IEEE802154_MR_OQPSK_CHIPS_1000) ? 4 : 8; +} + +static inline uint8_t _mr_oqpsk_shr_duration_syms(uint8_t chips) +{ + /* 802.15.4g, Table 184 / Table 165 */ + return (chips < IEEE802154_MR_OQPSK_CHIPS_1000) ? 48 : 72; +} + +static inline uint8_t _mr_oqpsk_ack_psdu_duration_syms(uint8_t chips, uint8_t mode) +{ + /* pg. 119, section 18.3.2.14 */ + static const uint8_t sym_len[] = { 32, 32, 64, 128 }; + const uint8_t Ns = sym_len[chips]; + const uint8_t Rspread = _mr_oqpsk_spreading(chips, mode); + /* Nd == 63, since ACK length is 5 or 7 octets only */ + const uint16_t Npsdu = Rspread * 2 * 63; + + /* phyPSDUDuration = ceiling(Npsdu / Ns) + ceiling(Npsdu / Mp) */ + /* with Mp = Np * 16, see Table 182 */ + return (Npsdu + Ns/2) / Ns + (Npsdu + 8 * Ns) / (16 * Ns); +} + +static uint16_t _mr_oqpsk_ack_timeout_us(const ieee802154_mr_oqpks_conf_t *conf) +{ + /* see 802.15.4g-2012, p. 30 */ + uint16_t symbols = _mr_oqpsk_cca_duration_syms(conf->chips) + + _mr_oqpsk_shr_duration_syms(conf->chips) + + 15 /* PHR duration */ + + _mr_oqpsk_ack_psdu_duration_syms(conf->chips, conf->rate_mode); + + return _mr_oqpsk_symbol_duration_us(conf->chips) * symbols + + IEEE802154G_ATURNAROUNDTIME_US; +} + +static uint16_t _mr_oqpsk_csma_backoff_period_us(const ieee802154_mr_oqpks_conf_t *conf) +{ + return _mr_oqpsk_cca_duration_syms(conf->chips) * _mr_oqpsk_symbol_duration_us(conf->chips) + + IEEE802154G_ATURNAROUNDTIME_US; +} + static int ieee802154_submac_config_phy(ieee802154_submac_t *submac, const ieee802154_phy_conf_t *conf) { @@ -439,6 +524,10 @@ static int ieee802154_submac_config_phy(ieee802154_submac_t *submac, submac->ack_timeout_us = ACK_TIMEOUT_US; submac->csma_backoff_us = CSMA_SENDER_BACKOFF_PERIOD_UNIT_US; break; + case IEEE802154_PHY_MR_OQPSK: + submac->ack_timeout_us = _mr_oqpsk_ack_timeout_us((void *)conf); + submac->csma_backoff_us = _mr_oqpsk_csma_backoff_period_us((void *)conf); + break; default: return -EINVAL; } From f2c554bc3bd4cd5b7e9b4b607bc3e5f6b23fa293 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Thu, 25 May 2023 15:23:38 +0200 Subject: [PATCH 4/6] ieee802154/submac: let ieee802154_submac_config_phy() take whole struct --- sys/include/net/ieee802154.h | 4 +- sys/include/net/ieee802154/submac.h | 37 ++++++++++++------ sys/net/link_layer/ieee802154/submac.c | 53 +++++++++++++++++--------- 3 files changed, 63 insertions(+), 31 deletions(-) diff --git a/sys/include/net/ieee802154.h b/sys/include/net/ieee802154.h index 7d57db380e0c..670c4fb72d75 100644 --- a/sys/include/net/ieee802154.h +++ b/sys/include/net/ieee802154.h @@ -177,7 +177,9 @@ typedef enum { IEEE802154_PHY_OQPSK, /**< Offset Quadrature Phase-Shift Keying */ IEEE802154_PHY_MR_OQPSK, /**< Multi-Rate Offset Quadrature Phase-Shift Keying */ IEEE802154_PHY_MR_OFDM, /**< Multi-Rate Orthogonal Frequency-Division Multiplexing */ - IEEE802154_PHY_MR_FSK /**< Multi-Rate Frequency Shift Keying */ + IEEE802154_PHY_MR_FSK, /**< Multi-Rate Frequency Shift Keying */ + + IEEE802154_PHY_NO_OP, /**< don't change PHY configuration */ } ieee802154_phy_mode_t; /** diff --git a/sys/include/net/ieee802154/submac.h b/sys/include/net/ieee802154/submac.h index d8923fa22822..a41de6cc1540 100644 --- a/sys/include/net/ieee802154/submac.h +++ b/sys/include/net/ieee802154/submac.h @@ -312,9 +312,7 @@ static inline ieee802154_phy_mode_t ieee802154_get_phy_mode( * @brief Set IEEE 802.15.4 PHY configuration (channel, TX power) * * @param[in] submac pointer to the SubMAC descriptor - * @param[in] channel_num channel number - * @param[in] channel_page channel page - * @param[in] tx_pow transmission power (in dBm) + * @param[in] conf pointer to the PHY configuration * * @return 0 on success * @return -ENOTSUP if the PHY settings are not supported @@ -323,8 +321,7 @@ static inline ieee802154_phy_mode_t ieee802154_get_phy_mode( * @ref ieee802154_submac_cb_t::tx_done * @return negative errno on error */ -int ieee802154_set_phy_conf(ieee802154_submac_t *submac, uint16_t channel_num, - uint8_t channel_page, int8_t tx_pow); +int ieee802154_set_phy_conf(ieee802154_submac_t *submac, const ieee802154_phy_conf_t *conf); /** * @brief Set IEEE 802.15.4 channel number @@ -344,8 +341,14 @@ int ieee802154_set_phy_conf(ieee802154_submac_t *submac, uint16_t channel_num, static inline int ieee802154_set_channel_number(ieee802154_submac_t *submac, uint16_t channel_num) { - return ieee802154_set_phy_conf(submac, channel_num, submac->channel_page, - submac->tx_pow); + const ieee802154_phy_conf_t conf = { + .phy_mode = IEEE802154_PHY_NO_OP, + .channel = channel_num, + .page = submac->channel_page, + .pow = submac->tx_pow, + }; + + return ieee802154_set_phy_conf(submac, &conf); } /** @@ -366,8 +369,14 @@ static inline int ieee802154_set_channel_number(ieee802154_submac_t *submac, static inline int ieee802154_set_channel_page(ieee802154_submac_t *submac, uint16_t channel_page) { - return ieee802154_set_phy_conf(submac, submac->channel_num, channel_page, - submac->tx_pow); + const ieee802154_phy_conf_t conf = { + .phy_mode = IEEE802154_PHY_NO_OP, + .channel = submac->channel_num, + .page = channel_page, + .pow = submac->tx_pow, + }; + + return ieee802154_set_phy_conf(submac, &conf); } /** @@ -388,8 +397,14 @@ static inline int ieee802154_set_channel_page(ieee802154_submac_t *submac, static inline int ieee802154_set_tx_power(ieee802154_submac_t *submac, int8_t tx_pow) { - return ieee802154_set_phy_conf(submac, submac->channel_num, - submac->channel_page, tx_pow); + const ieee802154_phy_conf_t conf = { + .phy_mode = IEEE802154_PHY_NO_OP, + .channel = submac->channel_num, + .page = submac->channel_page, + .pow = tx_pow, + }; + + return ieee802154_set_phy_conf(submac, &conf); } /** diff --git a/sys/net/link_layer/ieee802154/submac.c b/sys/net/link_layer/ieee802154/submac.c index 6faef6f6fdc8..f7218e560312 100644 --- a/sys/net/link_layer/ieee802154/submac.c +++ b/sys/net/link_layer/ieee802154/submac.c @@ -498,7 +498,7 @@ static inline uint8_t _mr_oqpsk_ack_psdu_duration_syms(uint8_t chips, uint8_t mo return (Npsdu + Ns/2) / Ns + (Npsdu + 8 * Ns) / (16 * Ns); } -static uint16_t _mr_oqpsk_ack_timeout_us(const ieee802154_mr_oqpks_conf_t *conf) +static inline uint16_t _mr_oqpsk_ack_timeout_us(const ieee802154_mr_oqpks_conf_t *conf) { /* see 802.15.4g-2012, p. 30 */ uint16_t symbols = _mr_oqpsk_cca_duration_syms(conf->chips) @@ -510,7 +510,7 @@ static uint16_t _mr_oqpsk_ack_timeout_us(const ieee802154_mr_oqpks_conf_t *conf) + IEEE802154G_ATURNAROUNDTIME_US; } -static uint16_t _mr_oqpsk_csma_backoff_period_us(const ieee802154_mr_oqpks_conf_t *conf) +static inline uint16_t _mr_oqpsk_csma_backoff_period_us(const ieee802154_mr_oqpks_conf_t *conf) { return _mr_oqpsk_cca_duration_syms(conf->chips) * _mr_oqpsk_symbol_duration_us(conf->chips) + IEEE802154G_ATURNAROUNDTIME_US; @@ -524,10 +524,15 @@ static int ieee802154_submac_config_phy(ieee802154_submac_t *submac, submac->ack_timeout_us = ACK_TIMEOUT_US; submac->csma_backoff_us = CSMA_SENDER_BACKOFF_PERIOD_UNIT_US; break; +#ifdef MODULE_NETDEV_IEEE802154_MR_OQPSK case IEEE802154_PHY_MR_OQPSK: submac->ack_timeout_us = _mr_oqpsk_ack_timeout_us((void *)conf); submac->csma_backoff_us = _mr_oqpsk_csma_backoff_period_us((void *)conf); break; +#endif + case IEEE802154_PHY_NO_OP: + case IEEE802154_PHY_DISABLED: + break; default: return -EINVAL; } @@ -603,13 +608,26 @@ int ieee802154_submac_init(ieee802154_submac_t *submac, const network_uint16_t * ieee802154_radio_config_addr_filter(dev, IEEE802154_AF_PANID, &submac->panid); /* Configure PHY settings (mode, channel, TX power) */ - ieee802154_phy_conf_t conf = - { .phy_mode = submac->phy_mode, - .channel = submac->channel_num, - .page = submac->channel_page, - .pow = submac->tx_pow }; + union { + ieee802154_phy_conf_t super; +#ifdef MODULE_NETDEV_IEEE802154_MR_OQPSK + ieee802154_mr_oqpks_conf_t mr_oqpsk; +#endif + } conf; + +#ifdef MODULE_NETDEV_IEEE802154_MR_OQPSK + if (submac->phy_mode == IEEE802154_PHY_MR_OQPSK) { + conf.mr_oqpsk.chips = CONFIG_IEEE802154_MR_OQPSK_DEFAULT_CHIPS; + conf.mr_oqpsk.rate_mode = CONFIG_IEEE802154_MR_OQPSK_DEFAULT_RATE; + } +#endif - ieee802154_submac_config_phy(submac, &conf); + conf.super.phy_mode = submac->phy_mode; + conf.super.channel = submac->channel_num; + conf.super.page = submac->channel_page; + conf.super.pow = submac->tx_pow; + + ieee802154_submac_config_phy(submac, &conf.super); ieee802154_radio_set_cca_threshold(dev, CONFIG_IEEE802154_CCA_THRESH_DEFAULT); assert(res >= 0); @@ -619,15 +637,9 @@ int ieee802154_submac_init(ieee802154_submac_t *submac, const network_uint16_t * return res; } -int ieee802154_set_phy_conf(ieee802154_submac_t *submac, uint16_t channel_num, - uint8_t channel_page, int8_t tx_pow) +int ieee802154_set_phy_conf(ieee802154_submac_t *submac, const ieee802154_phy_conf_t *conf) { ieee802154_dev_t *dev = &submac->dev; - const ieee802154_phy_conf_t conf = - { .phy_mode = submac->phy_mode, - .channel = channel_num, - .page = channel_page, - .pow = tx_pow }; int res; ieee802154_fsm_state_t current_state = submac->fsm_state; @@ -643,12 +655,15 @@ int ieee802154_set_phy_conf(ieee802154_submac_t *submac, uint16_t channel_num, } } - res = ieee802154_submac_config_phy(submac, &conf); + res = ieee802154_submac_config_phy(submac, conf); if (res >= 0) { - submac->channel_num = channel_num; - submac->channel_page = channel_page; - submac->tx_pow = tx_pow; + submac->channel_num = conf->channel; + submac->channel_page = conf->page; + submac->tx_pow = conf->pow; + if (conf->phy_mode != IEEE802154_PHY_NO_OP) { + submac->phy_mode = conf->phy_mode; + } } while (ieee802154_radio_confirm_set_idle(dev) == -EAGAIN) {} From a886adf611060da655a2aca7ba362e44952e209c Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Thu, 25 May 2023 16:03:01 +0200 Subject: [PATCH 5/6] ieee802154/submac: implement MR-OFDM timings --- sys/include/net/ieee802154.h | 19 +++++++++ sys/include/net/ieee802154/radio.h | 9 +++++ sys/net/link_layer/ieee802154/submac.c | 53 ++++++++++++++++++++++++++ 3 files changed, 81 insertions(+) diff --git a/sys/include/net/ieee802154.h b/sys/include/net/ieee802154.h index 670c4fb72d75..6769d5b3db3d 100644 --- a/sys/include/net/ieee802154.h +++ b/sys/include/net/ieee802154.h @@ -120,6 +120,11 @@ extern "C" { */ #define IEEE802154_ACK_TIMEOUT_SYMS (54) +/** + * @brief Symbol time for IEEE 802.15.4 MR-OFDM in µs + */ +#define IEEE802154_MR_OFDM_SYMBOL_TIME_US (120) + /** * @brief value of measured power when RSSI is zero. * @@ -283,6 +288,20 @@ extern const uint8_t ieee802154_addr_bcast[IEEE802154_ADDR_BCAST_LEN]; #define CONFIG_IEEE802154_MR_OQPSK_DEFAULT_RATE (2U) #endif +/** + * @brief IEEE802.15.4 MR-OFDM default modulation option + */ +#ifndef CONFIG_IEEE802154_MR_OFDM_DEFAULT_OPTION +#define CONFIG_IEEE802154_MR_OFDM_DEFAULT_OPTION (2U) +#endif + +/** + * @brief IEEE802.15.4 MR-OFDM default Modulation & Coding Scheme + */ +#ifndef CONFIG_IEEE802154_MR_OFDM_DEFAULT_SCHEME +#define CONFIG_IEEE802154_MR_OFDM_DEFAULT_SCHEME (2U) +#endif + /** * @brief IEEE802.15.4 default PANID */ diff --git a/sys/include/net/ieee802154/radio.h b/sys/include/net/ieee802154/radio.h index e94f0953e66a..106a07ccdcb5 100644 --- a/sys/include/net/ieee802154/radio.h +++ b/sys/include/net/ieee802154/radio.h @@ -468,6 +468,15 @@ typedef struct { uint8_t rate_mode; /**< rate mode */ } ieee802154_mr_oqpks_conf_t; +/** + * @brief extension for IEEE 802.15.4g MR-ODFM PHY + */ +typedef struct { + ieee802154_phy_conf_t super; /**< common settings */ + uint8_t option; /**< OFDM Option */ + uint8_t scheme; /**< Modulation & Coding Scheme */ +} ieee802154_mr_odmf_conf_t; + /** * @brief IEEE 802.15.4 radio operations */ diff --git a/sys/net/link_layer/ieee802154/submac.c b/sys/net/link_layer/ieee802154/submac.c index f7218e560312..4838b2c73b93 100644 --- a/sys/net/link_layer/ieee802154/submac.c +++ b/sys/net/link_layer/ieee802154/submac.c @@ -516,6 +516,44 @@ static inline uint16_t _mr_oqpsk_csma_backoff_period_us(const ieee802154_mr_oqpk + IEEE802154G_ATURNAROUNDTIME_US; } +/* + * MR-OFDM timing calculations + * + * The standard unfortunately does not list the formula, instead it has to be pieced together + * from scattered information and tables in the IEEE 802.15.4 document - may contain errors. + */ + +static unsigned _mr_ofdm_frame_duration(uint8_t option, uint8_t scheme, uint8_t bytes) +{ + /* Table 150 - phySymbolsPerOctet values for MR-OFDM PHY, IEEE 802.15.4g-2012 */ + static const uint8_t quot[] = { 3, 3, 6, 12, 18, 24, 36 }; + + --option; + /* phyMaxFrameDuration = phySHRDuration + phyPHRDuration + * + ceiling [(aMaxPHYPacketSize + 1) x phySymbolsPerOctet] */ + const unsigned phySHRDuration = 6; + const unsigned phyPHRDuration = option ? 6 : 3; + const unsigned phyPDUDuration = ((bytes + 1) * (1 << option) + quot[scheme] - 1) + / quot[scheme]; + + return (phySHRDuration + phyPHRDuration + phyPDUDuration) * IEEE802154_MR_OFDM_SYMBOL_TIME_US; +} + +static inline uint16_t _mr_ofdm_csma_backoff_period_us(const ieee802154_mr_odmf_conf_t *conf) +{ + (void)conf; + + return IEEE802154_CCA_DURATION_IN_SYMBOLS * IEEE802154_MR_OFDM_SYMBOL_TIME_US + + IEEE802154G_ATURNAROUNDTIME_US; +} + +static inline uint16_t _mr_ofdm_ack_timeout_us(const ieee802154_mr_odmf_conf_t *conf) +{ + return _mr_ofdm_csma_backoff_period_us(conf) + + IEEE802154G_ATURNAROUNDTIME_US + + _mr_ofdm_frame_duration(conf->option, conf->scheme, IEEE802154_ACK_FRAME_LEN); +} + static int ieee802154_submac_config_phy(ieee802154_submac_t *submac, const ieee802154_phy_conf_t *conf) { @@ -529,6 +567,12 @@ static int ieee802154_submac_config_phy(ieee802154_submac_t *submac, submac->ack_timeout_us = _mr_oqpsk_ack_timeout_us((void *)conf); submac->csma_backoff_us = _mr_oqpsk_csma_backoff_period_us((void *)conf); break; +#endif +#ifdef MODULE_NETDEV_IEEE802154_MR_OFDM + case IEEE802154_PHY_MR_OFDM: + submac->ack_timeout_us = _mr_ofdm_ack_timeout_us((void *)conf); + submac->csma_backoff_us = _mr_ofdm_csma_backoff_period_us((void *)conf); + break; #endif case IEEE802154_PHY_NO_OP: case IEEE802154_PHY_DISABLED: @@ -612,6 +656,9 @@ int ieee802154_submac_init(ieee802154_submac_t *submac, const network_uint16_t * ieee802154_phy_conf_t super; #ifdef MODULE_NETDEV_IEEE802154_MR_OQPSK ieee802154_mr_oqpks_conf_t mr_oqpsk; +#endif +#ifdef MODULE_NETDEV_IEEE802154_MR_OFDM + ieee802154_mr_odmf_conf_t mr_ofdm; #endif } conf; @@ -621,6 +668,12 @@ int ieee802154_submac_init(ieee802154_submac_t *submac, const network_uint16_t * conf.mr_oqpsk.rate_mode = CONFIG_IEEE802154_MR_OQPSK_DEFAULT_RATE; } #endif +#ifdef MODULE_NETDEV_IEEE802154_MR_OFDM + if (submac->phy_mode == IEEE802154_PHY_MR_OFDM) { + conf.mr_ofdm.option = CONFIG_IEEE802154_MR_OFDM_DEFAULT_OPTION; + conf.mr_ofdm.scheme = CONFIG_IEEE802154_MR_OFDM_DEFAULT_SCHEME; + } +#endif conf.super.phy_mode = submac->phy_mode; conf.super.channel = submac->channel_num; From 73e45dd6caf423359c969f3db70e0786a56db154 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Thu, 25 May 2023 18:06:19 +0200 Subject: [PATCH 6/6] ieee802154/submac: implement MR-FSK timings --- sys/include/net/ieee802154.h | 77 +++++++++++++++++++++++++- sys/include/net/ieee802154/radio.h | 15 ++++- sys/net/link_layer/ieee802154/submac.c | 73 ++++++++++++++++++++++-- 3 files changed, 155 insertions(+), 10 deletions(-) diff --git a/sys/include/net/ieee802154.h b/sys/include/net/ieee802154.h index 6769d5b3db3d..a1efa1694e66 100644 --- a/sys/include/net/ieee802154.h +++ b/sys/include/net/ieee802154.h @@ -125,6 +125,13 @@ extern "C" { */ #define IEEE802154_MR_OFDM_SYMBOL_TIME_US (120) +/** + * @brief Symbol time for IEEE 802.15.4 MR-FSK in µs + * + * symbol time is always 20 µs for MR-FSK (table 0, pg. 7) + */ +#define IEEE802154_MR_FSK_SYMBOL_TIME_US (20) + /** * @brief value of measured power when RSSI is zero. * @@ -190,11 +197,23 @@ typedef enum { /** * @brief 802.15.4 forward error correction schemes */ -enum { +typedef enum { IEEE802154_FEC_NONE, /**< no forward error correction */ IEEE802154_FEC_NRNSC, /**< non-recursive and non-systematic code */ IEEE802154_FEC_RSC /**< recursive and systematic code */ -}; +} ieee802154_mr_fsk_fec_t; + +/** + * @brief 802.15.4 MR-FSK symbol rates + */ +typedef enum { + IEEE802154_MR_FSK_SRATE_50K, /**< 50k Symbols/s */ + IEEE802154_MR_FSK_SRATE_100K, /**< 100k Symbols/s */ + IEEE802154_MR_FSK_SRATE_150K, /**< 150k Symbols/s */ + IEEE802154_MR_FSK_SRATE_200K, /**< 200k Symbols/s */ + IEEE802154_MR_FSK_SRATE_300K, /**< 300k Symbols/s */ + IEEE802154_MR_FSK_SRATE_400K, /**< 400k Symbols/s */ +} ieee802154_mr_fsk_srate_t; /** * @brief 802.15.4 MR-OQPSK chip rates @@ -206,6 +225,32 @@ typedef enum { IEEE802154_MR_OQPSK_CHIPS_2000, /**< 2000 kChip/s */ } ieee802154_mr_oqpsk_chips_t; +/** + * @brief Get the minimum preamble length for a given symbol rate + * + * From IEEE 802.15.4g Table 6-64 + * + * @param[in] srate symbol rate + * @return preamble length in bytes + */ +static inline uint8_t ieee802154_mr_fsk_plen(ieee802154_mr_fsk_srate_t srate) +{ + switch (srate) { + case IEEE802154_MR_FSK_SRATE_50K: + return 2; + case IEEE802154_MR_FSK_SRATE_100K: + return 3; + case IEEE802154_MR_FSK_SRATE_150K: + case IEEE802154_MR_FSK_SRATE_200K: + case IEEE802154_MR_FSK_SRATE_300K: + return 8; + case IEEE802154_MR_FSK_SRATE_400K: + return 10; + } + + return 0; +} + /** * @brief Special address definitions * @{ @@ -302,6 +347,34 @@ extern const uint8_t ieee802154_addr_bcast[IEEE802154_ADDR_BCAST_LEN]; #define CONFIG_IEEE802154_MR_OFDM_DEFAULT_SCHEME (2U) #endif +/** + * @brief IEEE802.15.4 MR-FSK default symbol rate + */ +#ifndef CONFIG_IEEE802154_MR_FSK_DEFAULT_SRATE +#define CONFIG_IEEE802154_MR_FSK_DEFAULT_SRATE IEEE802154_MR_FSK_SRATE_200K +#endif + +/** + * @brief IEEE802.15.4 MR-FSK default modulation index, fraction of 64 + */ +#ifndef CONFIG_IEEE802154_MR_FSK_DEFAULT_MOD_IDX +#define CONFIG_IEEE802154_MR_FSK_DEFAULT_MOD_IDX (64U) +#endif + +/** + * @brief IEEE802.15.4 MR-FSK default modulation order + */ +#ifndef CONFIG_IEEE802154_MR_FSK_DEFAULT_MOD_ORD +#define CONFIG_IEEE802154_MR_FSK_DEFAULT_MOD_ORD (2U) +#endif + +/** + * @brief IEEE802.15.4 MR-FSK default error correction mode + */ +#ifndef CONFIG_IEEE802154_MR_FSK_DEFAULT_FEC +#define CONFIG_IEEE802154_MR_FSK_DEFAULT_FEC IEEE802154_FEC_NONE +#endif + /** * @brief IEEE802.15.4 default PANID */ diff --git a/sys/include/net/ieee802154/radio.h b/sys/include/net/ieee802154/radio.h index 106a07ccdcb5..eb20f33004b8 100644 --- a/sys/include/net/ieee802154/radio.h +++ b/sys/include/net/ieee802154/radio.h @@ -466,7 +466,7 @@ typedef struct { ieee802154_phy_conf_t super; /**< common settings */ ieee802154_mr_oqpsk_chips_t chips; /**< chip rate */ uint8_t rate_mode; /**< rate mode */ -} ieee802154_mr_oqpks_conf_t; +} ieee802154_mr_oqpsk_conf_t; /** * @brief extension for IEEE 802.15.4g MR-ODFM PHY @@ -475,7 +475,18 @@ typedef struct { ieee802154_phy_conf_t super; /**< common settings */ uint8_t option; /**< OFDM Option */ uint8_t scheme; /**< Modulation & Coding Scheme */ -} ieee802154_mr_odmf_conf_t; +} ieee802154_mr_ofdm_conf_t; + +/** + * @brief extension for IEEE 802.15.4g MR-FSK PHY + */ +typedef struct { + ieee802154_phy_conf_t super; /**< common settings */ + ieee802154_mr_fsk_srate_t srate; /**< symbol rate */ + uint8_t mod_ord; /**< modulation order, 2 or 4 */ + uint8_t mod_idx; /**< modulation index */ + ieee802154_mr_fsk_fec_t fec; /**< forward error correction */ +} ieee802154_mr_fsk_conf_t; /** * @brief IEEE 802.15.4 radio operations diff --git a/sys/net/link_layer/ieee802154/submac.c b/sys/net/link_layer/ieee802154/submac.c index 4838b2c73b93..b61125d1789f 100644 --- a/sys/net/link_layer/ieee802154/submac.c +++ b/sys/net/link_layer/ieee802154/submac.c @@ -498,7 +498,8 @@ static inline uint8_t _mr_oqpsk_ack_psdu_duration_syms(uint8_t chips, uint8_t mo return (Npsdu + Ns/2) / Ns + (Npsdu + 8 * Ns) / (16 * Ns); } -static inline uint16_t _mr_oqpsk_ack_timeout_us(const ieee802154_mr_oqpks_conf_t *conf) +MAYBE_UNUSED +static inline uint16_t _mr_oqpsk_ack_timeout_us(const ieee802154_mr_oqpsk_conf_t *conf) { /* see 802.15.4g-2012, p. 30 */ uint16_t symbols = _mr_oqpsk_cca_duration_syms(conf->chips) @@ -510,7 +511,8 @@ static inline uint16_t _mr_oqpsk_ack_timeout_us(const ieee802154_mr_oqpks_conf_t + IEEE802154G_ATURNAROUNDTIME_US; } -static inline uint16_t _mr_oqpsk_csma_backoff_period_us(const ieee802154_mr_oqpks_conf_t *conf) +MAYBE_UNUSED +static inline uint16_t _mr_oqpsk_csma_backoff_period_us(const ieee802154_mr_oqpsk_conf_t *conf) { return _mr_oqpsk_cca_duration_syms(conf->chips) * _mr_oqpsk_symbol_duration_us(conf->chips) + IEEE802154G_ATURNAROUNDTIME_US; @@ -539,7 +541,7 @@ static unsigned _mr_ofdm_frame_duration(uint8_t option, uint8_t scheme, uint8_t return (phySHRDuration + phyPHRDuration + phyPDUDuration) * IEEE802154_MR_OFDM_SYMBOL_TIME_US; } -static inline uint16_t _mr_ofdm_csma_backoff_period_us(const ieee802154_mr_odmf_conf_t *conf) +static inline uint16_t _mr_ofdm_csma_backoff_period_us(const ieee802154_mr_ofdm_conf_t *conf) { (void)conf; @@ -547,13 +549,55 @@ static inline uint16_t _mr_ofdm_csma_backoff_period_us(const ieee802154_mr_odmf_ + IEEE802154G_ATURNAROUNDTIME_US; } -static inline uint16_t _mr_ofdm_ack_timeout_us(const ieee802154_mr_odmf_conf_t *conf) +MAYBE_UNUSED +static inline uint16_t _mr_ofdm_ack_timeout_us(const ieee802154_mr_ofdm_conf_t *conf) { return _mr_ofdm_csma_backoff_period_us(conf) + IEEE802154G_ATURNAROUNDTIME_US + _mr_ofdm_frame_duration(conf->option, conf->scheme, IEEE802154_ACK_FRAME_LEN); } +/* + * MR-FSK timing calculations + * + * The standard unfortunately does not list the formula, instead it has to be pieced together + * from scattered information and tables in the IEEE 802.15.4 document - may contain errors. + */ + +MAYBE_UNUSED +static inline uint16_t _mr_fsk_csma_backoff_period_us(const ieee802154_mr_fsk_conf_t *conf) +{ + (void)conf; + + return IEEE802154_CCA_DURATION_IN_SYMBOLS * IEEE802154_MR_FSK_SYMBOL_TIME_US + + IEEE802154G_ATURNAROUNDTIME_US; +} + +MAYBE_UNUSED +static inline uint16_t _mr_fsk_ack_timeout_us(const ieee802154_mr_fsk_conf_t *conf) +{ + uint8_t ack_len = IEEE802154_ACK_FRAME_LEN; + uint8_t fsk_pl = ieee802154_mr_fsk_plen(conf->srate); + + /* PHR uses same data rate as PSDU */ + ack_len += 2; + + /* 4-FSK doubles data rate */ + if (conf->mod_ord == 4) { + ack_len /= 2; + } + + /* forward error correction halves data rate */ + if (conf->fec) { + ack_len *= 2; + } + + return _mr_fsk_csma_backoff_period_us(conf) + + IEEE802154G_ATURNAROUNDTIME_US + /* long Preamble + SFD; SFD=2 */ + + ((fsk_pl * 8 + 2) + ack_len) * 8 * IEEE802154_MR_FSK_SYMBOL_TIME_US; +} + static int ieee802154_submac_config_phy(ieee802154_submac_t *submac, const ieee802154_phy_conf_t *conf) { @@ -573,6 +617,12 @@ static int ieee802154_submac_config_phy(ieee802154_submac_t *submac, submac->ack_timeout_us = _mr_ofdm_ack_timeout_us((void *)conf); submac->csma_backoff_us = _mr_ofdm_csma_backoff_period_us((void *)conf); break; +#endif +#ifdef MODULE_NETDEV_IEEE802154_MR_FSK + case IEEE802154_PHY_MR_FSK: + submac->ack_timeout_us = _mr_fsk_ack_timeout_us((void *)conf); + submac->csma_backoff_us = _mr_fsk_csma_backoff_period_us((void *)conf); + break; #endif case IEEE802154_PHY_NO_OP: case IEEE802154_PHY_DISABLED: @@ -655,10 +705,13 @@ int ieee802154_submac_init(ieee802154_submac_t *submac, const network_uint16_t * union { ieee802154_phy_conf_t super; #ifdef MODULE_NETDEV_IEEE802154_MR_OQPSK - ieee802154_mr_oqpks_conf_t mr_oqpsk; + ieee802154_mr_oqpsk_conf_t mr_oqpsk; #endif #ifdef MODULE_NETDEV_IEEE802154_MR_OFDM - ieee802154_mr_odmf_conf_t mr_ofdm; + ieee802154_mr_ofdm_conf_t mr_ofdm; +#endif +#ifdef MODULE_NETDEV_IEEE802154_MR_FSK + ieee802154_mr_fsk_conf_t mr_fsk; #endif } conf; @@ -674,6 +727,14 @@ int ieee802154_submac_init(ieee802154_submac_t *submac, const network_uint16_t * conf.mr_ofdm.scheme = CONFIG_IEEE802154_MR_OFDM_DEFAULT_SCHEME; } #endif +#ifdef MODULE_NETDEV_IEEE802154_MR_FSK + if (submac->phy_mode == IEEE802154_PHY_MR_FSK) { + conf.mr_fsk.srate = CONFIG_IEEE802154_MR_FSK_DEFAULT_SRATE; + conf.mr_fsk.mod_ord = CONFIG_IEEE802154_MR_FSK_DEFAULT_MOD_ORD; + conf.mr_fsk.mod_idx = CONFIG_IEEE802154_MR_FSK_DEFAULT_MOD_IDX; + conf.mr_fsk.fec = CONFIG_IEEE802154_MR_FSK_DEFAULT_FEC; + } +#endif conf.super.phy_mode = submac->phy_mode; conf.super.channel = submac->channel_num;