1 /* 2 * Copyright (c) 2016 Intel Corporation. 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 * 6 * All references to the spec refer to IEEE 802.15.4-2020. 7 */ 8 9 #include <zephyr/logging/log.h> 10 LOG_MODULE_REGISTER(net_ieee802154_csma, CONFIG_NET_L2_IEEE802154_LOG_LEVEL); 11 12 #include <zephyr/net/ieee802154.h> 13 #include <zephyr/net/ieee802154_radio.h> 14 #include <zephyr/net/net_if.h> 15 #include <zephyr/random/random.h> 16 #include <zephyr/toolchain.h> 17 18 #include <errno.h> 19 #include <stdlib.h> 20 21 #include "ieee802154_priv.h" 22 #include "ieee802154_utils.h" 23 24 BUILD_ASSERT(CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA_MIN_BE <= 25 CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA_MAX_BE, 26 "The CSMA/CA min backoff exponent must be less or equal max backoff exponent."); 27 28 /* See section 6.2.5.1. */ unslotted_csma_ca_channel_access(struct net_if * iface)29static inline int unslotted_csma_ca_channel_access(struct net_if *iface) 30 { 31 struct ieee802154_context *ctx = net_if_l2_data(iface); 32 uint8_t be = CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA_MIN_BE; 33 uint32_t turnaround_time, unit_backoff_period_us; 34 35 turnaround_time = ieee802154_radio_get_a_turnaround_time(iface); 36 unit_backoff_period_us = ieee802154_radio_get_multiple_of_symbol_period( 37 iface, ctx->channel, 38 IEEE802154_MAC_A_UNIT_BACKOFF_PERIOD(turnaround_time)) / 39 NSEC_PER_USEC; 40 41 for (uint8_t nb = 0U; nb <= CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA_MAX_BO; nb++) { 42 int ret; 43 44 if (be) { 45 uint8_t bo_n = sys_rand32_get() & ((1 << be) - 1); 46 47 /* TODO: k_busy_wait() is too inaccurate on many platforms, the 48 * radio API should expose a precise radio clock instead (which may 49 * fall back to k_busy_wait() if the radio does not have a clock). 50 */ 51 k_busy_wait(bo_n * unit_backoff_period_us); 52 } 53 54 ret = ieee802154_radio_cca(iface); 55 if (ret == 0) { 56 /* Channel is idle -> CSMA Success */ 57 return 0; 58 } else if (ret != -EBUSY) { 59 /* CCA exited with failure code -> CSMA Abort */ 60 return -EIO; 61 } 62 63 /* Channel is busy -> CSMA Backoff */ 64 be = MIN(be + 1, CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA_MAX_BE); 65 } 66 67 /* Channel is still busy after max backoffs -> CSMA Failure */ 68 return -EBUSY; 69 } 70 71 /* Declare the public channel access algorithm function used by L2. */ 72 FUNC_ALIAS(unslotted_csma_ca_channel_access, ieee802154_wait_for_clear_channel, int); 73