73 lines
2.2 KiB
C
73 lines
2.2 KiB
C
/*
|
|
* Copyright (c) 2016 Intel Corporation.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* All references to the spec refer to IEEE 802.15.4-2020.
|
|
*/
|
|
|
|
#include <zephyr/logging/log.h>
|
|
LOG_MODULE_REGISTER(net_ieee802154_csma, CONFIG_NET_L2_IEEE802154_LOG_LEVEL);
|
|
|
|
#include <zephyr/net/ieee802154.h>
|
|
#include <zephyr/net/ieee802154_radio.h>
|
|
#include <zephyr/net/net_if.h>
|
|
#include <zephyr/random/random.h>
|
|
#include <zephyr/toolchain.h>
|
|
|
|
#include <errno.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "ieee802154_priv.h"
|
|
#include "ieee802154_utils.h"
|
|
|
|
BUILD_ASSERT(CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA_MIN_BE <=
|
|
CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA_MAX_BE,
|
|
"The CSMA/CA min backoff exponent must be less or equal max backoff exponent.");
|
|
|
|
/* See section 6.2.5.1. */
|
|
static inline int unslotted_csma_ca_channel_access(struct net_if *iface)
|
|
{
|
|
struct ieee802154_context *ctx = net_if_l2_data(iface);
|
|
uint8_t be = CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA_MIN_BE;
|
|
uint32_t turnaround_time, unit_backoff_period_us;
|
|
|
|
turnaround_time = ieee802154_radio_get_a_turnaround_time(iface);
|
|
unit_backoff_period_us = ieee802154_radio_get_multiple_of_symbol_period(
|
|
iface, ctx->channel,
|
|
IEEE802154_MAC_A_UNIT_BACKOFF_PERIOD(turnaround_time)) /
|
|
NSEC_PER_USEC;
|
|
|
|
for (uint8_t nb = 0U; nb <= CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA_MAX_BO; nb++) {
|
|
int ret;
|
|
|
|
if (be) {
|
|
uint8_t bo_n = sys_rand32_get() & ((1 << be) - 1);
|
|
|
|
/* TODO: k_busy_wait() is too inaccurate on many platforms, the
|
|
* radio API should expose a precise radio clock instead (which may
|
|
* fall back to k_busy_wait() if the radio does not have a clock).
|
|
*/
|
|
k_busy_wait(bo_n * unit_backoff_period_us);
|
|
}
|
|
|
|
ret = ieee802154_radio_cca(iface);
|
|
if (ret == 0) {
|
|
/* Channel is idle -> CSMA Success */
|
|
return 0;
|
|
} else if (ret != -EBUSY) {
|
|
/* CCA exited with failure code -> CSMA Abort */
|
|
return -EIO;
|
|
}
|
|
|
|
/* Channel is busy -> CSMA Backoff */
|
|
be = MIN(be + 1, CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA_MAX_BE);
|
|
}
|
|
|
|
/* Channel is still busy after max backoffs -> CSMA Failure */
|
|
return -EBUSY;
|
|
}
|
|
|
|
/* Declare the public channel access algorithm function used by L2. */
|
|
FUNC_ALIAS(unslotted_csma_ca_channel_access, ieee802154_wait_for_clear_channel, int);
|