blob: a541e9bb14604209a5896fd048aa8ab1caa9652c [file] [log] [blame]
/*
* 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);