| /* |
| * Copyright (c) 2016 Intel Corporation. |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #if defined(CONFIG_NET_DEBUG_L2_IEEE802154) |
| #define SYS_LOG_DOMAIN "net/ieee802154" |
| #define NET_LOG_ENABLED 1 |
| #endif |
| |
| #include <net/net_core.h> |
| #include <net/net_if.h> |
| |
| #include <misc/util.h> |
| |
| #include <stdlib.h> |
| #include <errno.h> |
| |
| #include <net/ieee802154_radio.h> |
| |
| #include "ieee802154_frame.h" |
| #include "ieee802154_radio_utils.h" |
| |
| static inline int csma_ca_tx_fragment(struct net_if *iface, |
| struct net_pkt *pkt, |
| struct net_buf *frag) |
| { |
| const u8_t max_bo = CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA_MAX_BO; |
| const u8_t max_be = CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA_MAX_BE; |
| u8_t retries = CONFIG_NET_L2_IEEE802154_RADIO_TX_RETRIES; |
| struct ieee802154_context *ctx = net_if_l2_data(iface); |
| const struct ieee802154_radio_api *radio = iface->dev->driver_api; |
| bool ack_required = prepare_for_ack(ctx, pkt); |
| u8_t be = CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA_MIN_BE; |
| u8_t nb = 0; |
| int ret = -EIO; |
| |
| NET_DBG("frag %p", frag); |
| |
| loop: |
| while (retries) { |
| retries--; |
| |
| if (be) { |
| u8_t bo_n = sys_rand32_get() & (2 << (be + 1)); |
| |
| k_busy_wait(bo_n * 20); |
| } |
| |
| while (1) { |
| if (!radio->cca(iface->dev)) { |
| break; |
| } |
| |
| be = min(be + 1, max_be); |
| nb++; |
| |
| if (nb > max_bo) { |
| goto loop; |
| } |
| } |
| |
| ret = radio->tx(iface->dev, pkt, frag); |
| if (ret) { |
| continue; |
| } |
| |
| ret = wait_for_ack(ctx, ack_required); |
| if (!ret) { |
| break; |
| } |
| } |
| |
| return ret; |
| } |
| |
| static int csma_ca_radio_send(struct net_if *iface, struct net_pkt *pkt) |
| { |
| NET_DBG("pkt %p (frags %p)", pkt, pkt->frags); |
| |
| return tx_packet_fragments(iface, pkt, csma_ca_tx_fragment); |
| } |
| |
| static enum net_verdict csma_ca_radio_handle_ack(struct net_if *iface, |
| struct net_pkt *pkt) |
| { |
| struct ieee802154_context *ctx = net_if_l2_data(iface); |
| |
| return handle_ack(ctx, pkt); |
| } |
| |
| /* Declare the public Radio driver function used by the HW drivers */ |
| FUNC_ALIAS(csma_ca_radio_send, |
| ieee802154_radio_send, int); |
| |
| FUNC_ALIAS(csma_ca_radio_handle_ack, |
| ieee802154_radio_handle_ack, enum net_verdict); |