mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #5515 from miri64/csma_sender/fix/adaptations
csma_sender: fixes and adaptions
This commit is contained in:
commit
b43ffab953
@ -10,6 +10,11 @@ ifneq (,$(filter ccn-lite,$(USEPKG)))
|
||||
export CFLAGS += -DCCNL_RIOT
|
||||
endif
|
||||
|
||||
ifneq (,$(filter csma_sender,$(USEMODULE)))
|
||||
USEMODULE += random
|
||||
USEMODULE += xtimer
|
||||
endif
|
||||
|
||||
ifneq (,$(filter nhdp,$(USEMODULE)))
|
||||
USEMODULE += conn_udp
|
||||
USEMODULE += xtimer
|
||||
|
@ -1,3 +1,6 @@
|
||||
ifneq (,$(filter csma_sender,$(USEMODULE)))
|
||||
DIRS += net/link_layer/csma_sender
|
||||
endif
|
||||
ifneq (,$(filter posix_semaphore,$(USEMODULE)))
|
||||
DIRS += posix/semaphore
|
||||
endif
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2015 INRIA
|
||||
* Copyright (C) 2016 Freie Universität Berlin
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
@ -7,8 +8,8 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup net_gnrc_csma_sender Helper interface to send packets via CSMA/CA
|
||||
* @ingroup net_gnrc
|
||||
* @defgroup net_csma_sender CSMA/CA helper
|
||||
* @ingroup net
|
||||
* @brief This interface allows code from layer 2 (MAC) or higher
|
||||
* to send packets with CSMA/CA, whatever the abilities and/or
|
||||
* configuration of a given radio transceiver device are.
|
||||
@ -18,75 +19,78 @@
|
||||
* @brief Interface definition for the CSMA/CA helper
|
||||
*
|
||||
* @author Kévin Roussel <Kevin.Roussel@inria.fr>
|
||||
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
|
||||
*/
|
||||
|
||||
#ifndef GNRC_CSMA_SENDER_H_
|
||||
#define GNRC_CSMA_SENDER_H_
|
||||
#ifndef CSMA_SENDER_H_
|
||||
#define CSMA_SENDER_H_
|
||||
|
||||
#include "kernel.h"
|
||||
#include "net/gnrc.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#include "net/netdev2.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* @brief Default Minimal CSMA/CA Backoff Exponent
|
||||
*/
|
||||
#define MAC_MIN_BE_DEFAULT (3U)
|
||||
#ifndef CSMA_SENDER_MIN_BE_DEFAULT
|
||||
#define CSMA_SENDER_MIN_BE_DEFAULT (3U)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Default Maximal CSMA/CA Backoff Exponent
|
||||
*/
|
||||
#define MAC_MAX_BE_DEFAULT (5U)
|
||||
#ifndef CSMA_SENDER_MAX_BE_DEFAULT
|
||||
#define CSMA_SENDER_MAX_BE_DEFAULT (5U)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Default Maximal number of retries for sending
|
||||
* a given packet with the CSMA/CA method
|
||||
*/
|
||||
#define MAC_MAX_CSMA_BACKOFFS_DEFAULT (4U)
|
||||
#ifndef CSMA_SENDER_MAX_BACKOFFS_DEFAULT
|
||||
#define CSMA_SENDER_MAX_BACKOFFS_DEFAULT (4U)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief CSMA/CA backoff period, in microseconds
|
||||
*/
|
||||
#define A_UNIT_BACKOFF_PERIOD_MICROSEC (320U)
|
||||
#ifndef CSMA_SENDER_BACKOFF_PERIOD_UNIT
|
||||
#define CSMA_SENDER_BACKOFF_PERIOD_UNIT (320U)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Define a different (non-standard) value for
|
||||
* the CSMA macMinBE parameter.
|
||||
*
|
||||
* @param[in] val new value for macMinBE
|
||||
* @brief Configuration type for backoff
|
||||
*/
|
||||
void set_csma_mac_min_be(uint8_t val);
|
||||
typedef struct {
|
||||
uint8_t min_be; /**< minimum backoff exponent */
|
||||
uint8_t max_be; /**< maximum backoff exponent */
|
||||
uint16_t max_backoffs; /**< maximum number of retries */
|
||||
uint32_t backoff_period; /**< backoff period in microseconds */
|
||||
} csma_sender_conf_t;
|
||||
|
||||
/**
|
||||
* @brief Define a different (non-standard) value for
|
||||
* the CSMA macMaxBE parameter.
|
||||
*
|
||||
* @param[in] val new value for macMaxBE
|
||||
* @brief Default configuration.
|
||||
*/
|
||||
void set_csma_mac_max_be(uint8_t val);
|
||||
|
||||
/**
|
||||
* @brief Define a different (non-standard) value for
|
||||
* the CSMA macMaxCSMABackoffs parameter.
|
||||
*
|
||||
* @param[in] val new value for macMaxCSMABackoffs
|
||||
*/
|
||||
void set_csma_mac_max_csma_backoffs(uint8_t val);
|
||||
extern const csma_sender_conf_t CSMA_SENDER_CONF_DEFAULT;
|
||||
|
||||
/**
|
||||
* @brief Sends a 802.15.4 frame using the CSMA/CA method
|
||||
*
|
||||
* @pre `dev != NULL`
|
||||
*
|
||||
* If the transceiver can (and is configured to) do hardware-assisted
|
||||
* CSMA/CA, this feature is used. Otherwise, a software procedure is used.
|
||||
*
|
||||
* @param[in] dev netdev device, needs to be already initialized
|
||||
* @param[in] pkt pointer to the data in the packet buffer;
|
||||
* it must be a complete 802.15.4-compliant frame,
|
||||
* ready to be sent to the radio transceiver
|
||||
* @param[in] vector pointer to the data
|
||||
* @param[in] count number of elements in @p vector
|
||||
* @param[in] conf configuration for the backoff;
|
||||
* will be set to @ref CSMA_SENDER_CONF_DEFAULT if NULL.
|
||||
*
|
||||
* @return number of bytes that were actually send out
|
||||
* @return -ENODEV if @p dev is invalid
|
||||
@ -97,23 +101,28 @@ void set_csma_mac_max_csma_backoffs(uint8_t val);
|
||||
* @return -EBUSY if radio medium never was available
|
||||
* to send the given data
|
||||
*/
|
||||
int csma_ca_send(gnrc_netdev_t *dev, gnrc_pktsnip_t *pkt);
|
||||
int csma_sender_csma_ca_send(netdev2_t *dev, struct iovec *vector,
|
||||
unsigned count, const csma_sender_conf_t *conf);
|
||||
|
||||
/**
|
||||
* @brief Sends a 802.15.4 frame when medium is avaiable.
|
||||
*
|
||||
* @pre `dev != NULL`
|
||||
*
|
||||
* This function is useful for sending packets without the whole CSMA/CA
|
||||
* procedure, but *after* ensuring medium is available, that is :
|
||||
* after a successful CCA. <br/>
|
||||
* It is especially useful for broadcasting specific packets,
|
||||
* like beacons; or for many sending packets in burst. <br/>
|
||||
* ATTENTION: It only tries to send the given data once. If you want the
|
||||
* complete CSMA/CA procedure with retries, use @c csma_ca_send().
|
||||
* procedure, but *after* ensuring medium is available, that is after a
|
||||
* successful CCA.
|
||||
*
|
||||
* It is especially useful for broadcasting specific packets, like beacons; or
|
||||
* for many sending packets in burst.
|
||||
*
|
||||
* @warning **ATTENTION:** It only tries to send the given data once. If you
|
||||
* want the complete CSMA/CA procedure with retries, use
|
||||
* @ref csma_sender_csma_ca_send().
|
||||
*
|
||||
* @param[in] dev netdev device, needs to be already initialized
|
||||
* @param[in] pkt pointer to the data in the packet buffer;
|
||||
* it must be a complete 802.15.4-compliant frame,
|
||||
* ready to be sent to the radio transceiver
|
||||
* @param[in] vector pointer to the data
|
||||
* @param[in] count number of elements in @p vector
|
||||
*
|
||||
* @return number of bytes that were actually send out
|
||||
* @return -ENODEV if @p dev is invalid
|
||||
@ -124,13 +133,13 @@ int csma_ca_send(gnrc_netdev_t *dev, gnrc_pktsnip_t *pkt);
|
||||
* @return -EBUSY if radio medium was not available
|
||||
* to send the given data
|
||||
*/
|
||||
int cca_send(gnrc_netdev_t *dev, gnrc_pktsnip_t *pkt);
|
||||
int csma_sender_cca_send(netdev2_t *dev, struct iovec *vector, unsigned count);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* GNRC_CSMA_SENDER_H_ */
|
||||
#endif /* CSMA_SENDER_H_ */
|
||||
|
||||
/** @} */
|
@ -7,9 +7,6 @@ endif
|
||||
ifneq (,$(filter gnrc_conn_udp,$(USEMODULE)))
|
||||
DIRS += conn/udp
|
||||
endif
|
||||
ifneq (,$(filter gnrc_csma_sender,$(USEMODULE)))
|
||||
DIRS += link_layer/csma_sender
|
||||
endif
|
||||
ifneq (,$(filter gnrc_icmpv6,$(USEMODULE)))
|
||||
DIRS += network_layer/icmpv6
|
||||
endif
|
||||
|
@ -1,6 +0,0 @@
|
||||
MODULE = gnrc_csma_sender
|
||||
|
||||
USEMODULE += xtimer
|
||||
USEMODULE += random
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
1
sys/net/link_layer/csma_sender/Makefile
Normal file
1
sys/net/link_layer/csma_sender/Makefile
Normal file
@ -0,0 +1 @@
|
||||
include $(RIOTBASE)/Makefile.base
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2015 INRIA
|
||||
* Copyright (C) 2016 Freie Universität Berlin
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
@ -13,19 +14,21 @@
|
||||
* @brief Implementation of the CSMA/CA helper
|
||||
*
|
||||
* @author Kévin Roussel <Kevin.Roussel@inria.fr>
|
||||
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "kernel.h"
|
||||
#include "xtimer.h"
|
||||
#include "random.h"
|
||||
#include "net/gnrc/csma_sender.h"
|
||||
#include "net/gnrc.h"
|
||||
#include "net/netdev2.h"
|
||||
#include "net/netopt.h"
|
||||
|
||||
#include "net/csma_sender.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
@ -34,16 +37,12 @@
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
|
||||
|
||||
/** @brief Current value for mac_min_be parameter */
|
||||
static uint8_t mac_min_be = MAC_MIN_BE_DEFAULT;
|
||||
|
||||
/** @brief Current value for mac_max_be parameter */
|
||||
static uint8_t mac_max_be = MAC_MAX_BE_DEFAULT;
|
||||
|
||||
/** @brief Current value for mac_max_csma_backoffs parameter */
|
||||
static uint8_t mac_max_csma_backoffs = MAC_MAX_CSMA_BACKOFFS_DEFAULT;
|
||||
|
||||
const csma_sender_conf_t CSMA_SENDER_CONF_DEFAULT = {
|
||||
CSMA_SENDER_MIN_BE_DEFAULT,
|
||||
CSMA_SENDER_MAX_BE_DEFAULT,
|
||||
CSMA_SENDER_MAX_BACKOFFS_DEFAULT,
|
||||
CSMA_SENDER_BACKOFF_PERIOD_UNIT
|
||||
};
|
||||
|
||||
/*--------------------- "INTERNAL" UTILITY FUNCTIONS ---------------------*/
|
||||
|
||||
@ -55,19 +54,20 @@ static uint8_t mac_max_csma_backoffs = MAC_MAX_CSMA_BACKOFFS_DEFAULT;
|
||||
*
|
||||
* @return An adequate random backoff exponent in microseconds
|
||||
*/
|
||||
static inline uint32_t choose_backoff_period(int be)
|
||||
static inline uint32_t choose_backoff_period(int be,
|
||||
const csma_sender_conf_t *conf)
|
||||
{
|
||||
if (be < mac_min_be) {
|
||||
be = mac_min_be;
|
||||
if (be < conf->min_be) {
|
||||
be = conf->min_be;
|
||||
}
|
||||
if (be > mac_max_be) {
|
||||
be = mac_max_be;
|
||||
if (be > conf->max_be) {
|
||||
be = conf->max_be;
|
||||
}
|
||||
uint32_t max_backoff = ((1 << be) - 1) * A_UNIT_BACKOFF_PERIOD_MICROSEC;
|
||||
uint32_t max_backoff = ((1 << be) - 1) * CSMA_SENDER_BACKOFF_PERIOD_UNIT;
|
||||
|
||||
uint32_t period = genrand_uint32() % max_backoff;
|
||||
if (period < A_UNIT_BACKOFF_PERIOD_MICROSEC) {
|
||||
period = A_UNIT_BACKOFF_PERIOD_MICROSEC;
|
||||
uint32_t period = random_uint32() % max_backoff;
|
||||
if (period < CSMA_SENDER_BACKOFF_PERIOD_UNIT) {
|
||||
period = CSMA_SENDER_BACKOFF_PERIOD_UNIT;
|
||||
}
|
||||
|
||||
return period;
|
||||
@ -78,17 +78,17 @@ static inline uint32_t choose_backoff_period(int be)
|
||||
* @brief Perform a CCA and send the given packet if medium is available
|
||||
*
|
||||
* @param[in] device netdev device, needs to be already initialized
|
||||
* @param[in] data pointer to the data in the packet buffer;
|
||||
* it must be a complete 802.15.4-compliant frame,
|
||||
* ready to be sent to the radio transceiver
|
||||
* @param[in] vector pointer to the data
|
||||
* @param[in] count number of elements in @p vector
|
||||
*
|
||||
* @return the return value of device driver's @c send_data()
|
||||
* function if medium was avilable
|
||||
* @return -ECANCELED if an internal driver error occured
|
||||
* @return the return value of device driver's
|
||||
* netdev2_driver_t::send() function if medium was
|
||||
* available
|
||||
* @return -ECANCELED if an internal driver error occurred
|
||||
* @return -EBUSY if radio medium was not available
|
||||
* to send the given data
|
||||
*/
|
||||
static int send_if_cca(gnrc_netdev_t *device, gnrc_pktsnip_t *data)
|
||||
static int send_if_cca(netdev2_t *device, struct iovec *vector, unsigned count)
|
||||
{
|
||||
netopt_enable_t hwfeat;
|
||||
|
||||
@ -107,7 +107,7 @@ static int send_if_cca(gnrc_netdev_t *device, gnrc_pktsnip_t *data)
|
||||
/* if medium is clear, send the packet and return */
|
||||
if (hwfeat == NETOPT_ENABLE) {
|
||||
DEBUG("csma: Radio medium available: sending packet.\n");
|
||||
return device->driver->send_data(device, data);
|
||||
return device->driver->send(device, vector, count);
|
||||
}
|
||||
|
||||
/* if we arrive here, medium was not available for transmission */
|
||||
@ -117,72 +117,64 @@ static int send_if_cca(gnrc_netdev_t *device, gnrc_pktsnip_t *data)
|
||||
|
||||
/*------------------------- "EXPORTED" FUNCTIONS -------------------------*/
|
||||
|
||||
void set_csma_mac_min_be(uint8_t val)
|
||||
{
|
||||
mac_min_be = val;
|
||||
}
|
||||
|
||||
void set_csma_mac_max_be(uint8_t val)
|
||||
{
|
||||
mac_max_be = val;
|
||||
}
|
||||
|
||||
void set_csma_mac_max_csma_backoffs(uint8_t val)
|
||||
{
|
||||
mac_max_csma_backoffs = val;
|
||||
}
|
||||
|
||||
|
||||
int csma_ca_send(gnrc_netdev_t *dev, gnrc_pktsnip_t *pkt)
|
||||
int csma_sender_csma_ca_send(netdev2_t *dev, struct iovec *vector,
|
||||
unsigned count, const csma_sender_conf_t *conf)
|
||||
{
|
||||
netopt_enable_t hwfeat;
|
||||
|
||||
assert(dev);
|
||||
/* choose default configuration if none is given */
|
||||
if (conf == NULL) {
|
||||
conf = &CSMA_SENDER_CONF_DEFAULT;
|
||||
}
|
||||
/* Does the transceiver do automatic CSMA/CA when sending? */
|
||||
int res = dev->driver->get(dev,
|
||||
NETOPT_CSMA,
|
||||
(void *) &hwfeat,
|
||||
sizeof(netopt_enable_t));
|
||||
bool ok = false;
|
||||
|
||||
switch (res) {
|
||||
case -ENODEV:
|
||||
/* invalid device pointer given */
|
||||
return -ENODEV;
|
||||
case -ENOTSUP:
|
||||
/* device doesn't make auto-CSMA/CA */
|
||||
break;
|
||||
case -EOVERFLOW: /* (normally impossible...*/
|
||||
case -ECANCELED:
|
||||
DEBUG("csma: !!! DEVICE DRIVER FAILURE! TRANSMISSION ABORTED!\n");
|
||||
/* internal driver error! */
|
||||
return -ECANCELED;
|
||||
default:
|
||||
ok = (hwfeat == NETOPT_ENABLE);
|
||||
case -ENODEV:
|
||||
/* invalid device pointer given */
|
||||
return -ENODEV;
|
||||
case -ENOTSUP:
|
||||
/* device doesn't make auto-CSMA/CA */
|
||||
break;
|
||||
case -EOVERFLOW: /* (normally impossible...*/
|
||||
case -ECANCELED:
|
||||
DEBUG("csma: !!! DEVICE DRIVER FAILURE! TRANSMISSION ABORTED!\n");
|
||||
/* internal driver error! */
|
||||
return -ECANCELED;
|
||||
default:
|
||||
ok = (hwfeat == NETOPT_ENABLE);
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
/* device does CSMA/CA all by itself: let it do its job */
|
||||
DEBUG("csma: Network device does hardware CSMA/CA\n");
|
||||
return dev->driver->send_data(dev, pkt);
|
||||
return dev->driver->send(dev, vector, count);
|
||||
}
|
||||
|
||||
/* if we arrive here, then we must perform the CSMA/CA procedure
|
||||
ourselves by software */
|
||||
genrand_init(xtimer_now());
|
||||
random_init(xtimer_now());
|
||||
DEBUG("csma: Starting software CSMA/CA....\n");
|
||||
|
||||
int nb = 0, be = mac_min_be;
|
||||
int nb = 0, be = conf->min_be;
|
||||
|
||||
while (nb <= mac_max_csma_backoffs) {
|
||||
while (nb <= conf->max_be) {
|
||||
/* delay for an adequate random backoff period */
|
||||
uint32_t bp = choose_backoff_period(be);
|
||||
uint32_t bp = choose_backoff_period(be, conf);
|
||||
xtimer_usleep(bp);
|
||||
|
||||
/* try to send after a CCA */
|
||||
res = send_if_cca(dev, pkt);
|
||||
res = send_if_cca(dev, vector, count);
|
||||
if (res >= 0) {
|
||||
/* TX done */
|
||||
return res;
|
||||
} else if (res != -EBUSY) {
|
||||
}
|
||||
else if (res != -EBUSY) {
|
||||
/* something has gone wrong, return the error code */
|
||||
return res;
|
||||
}
|
||||
@ -190,8 +182,8 @@ int csma_ca_send(gnrc_netdev_t *dev, gnrc_pktsnip_t *pkt)
|
||||
/* medium is busy: increment CSMA counters */
|
||||
DEBUG("csma: Radio medium busy.\n");
|
||||
be++;
|
||||
if (be > mac_max_be) {
|
||||
be = mac_max_be;
|
||||
if (be > conf->max_be) {
|
||||
be = conf->max_be;
|
||||
}
|
||||
nb++;
|
||||
/* ... and try again if we have no exceeded the retry limit */
|
||||
@ -203,41 +195,43 @@ int csma_ca_send(gnrc_netdev_t *dev, gnrc_pktsnip_t *pkt)
|
||||
}
|
||||
|
||||
|
||||
int cca_send(gnrc_netdev_t *dev, gnrc_pktsnip_t *pkt)
|
||||
int csma_sender_cca_send(netdev2_t *dev, struct iovec *vector, unsigned count)
|
||||
{
|
||||
netopt_enable_t hwfeat;
|
||||
|
||||
assert(dev);
|
||||
/* Does the transceiver do automatic CCA before sending? */
|
||||
int res = dev->driver->get(dev,
|
||||
NETOPT_AUTOCCA,
|
||||
(void *) &hwfeat,
|
||||
sizeof(netopt_enable_t));
|
||||
bool ok = false;
|
||||
|
||||
switch (res) {
|
||||
case -ENODEV:
|
||||
/* invalid device pointer given */
|
||||
return -ENODEV;
|
||||
case -ENOTSUP:
|
||||
/* device doesn't make auto-CCA */
|
||||
break;
|
||||
case -EOVERFLOW: /* (normally impossible...*/
|
||||
case -ECANCELED:
|
||||
/* internal driver error! */
|
||||
DEBUG("csma: !!! DEVICE DRIVER FAILURE! TRANSMISSION ABORTED!\n");
|
||||
return -ECANCELED;
|
||||
default:
|
||||
ok = (hwfeat == NETOPT_ENABLE);
|
||||
case -ENODEV:
|
||||
/* invalid device pointer given */
|
||||
return -ENODEV;
|
||||
case -ENOTSUP:
|
||||
/* device doesn't make auto-CCA */
|
||||
break;
|
||||
case -EOVERFLOW: /* (normally impossible...*/
|
||||
case -ECANCELED:
|
||||
/* internal driver error! */
|
||||
DEBUG("csma: !!! DEVICE DRIVER FAILURE! TRANSMISSION ABORTED!\n");
|
||||
return -ECANCELED;
|
||||
default:
|
||||
ok = (hwfeat == NETOPT_ENABLE);
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
/* device does auto-CCA: let him do its job */
|
||||
DEBUG("csma: Network device does auto-CCA checking.\n");
|
||||
return dev->driver->send_data(dev, pkt);
|
||||
return dev->driver->send(dev, vector, count);
|
||||
}
|
||||
|
||||
/* if we arrive here, we must do CCA ourselves to see if radio medium
|
||||
is clear before sending */
|
||||
res = send_if_cca(dev, pkt);
|
||||
res = send_if_cca(dev, vector, count);
|
||||
if (res == -EBUSY) {
|
||||
DEBUG("csma: Transmission cancelled!\n");
|
||||
}
|
Loading…
Reference in New Issue
Block a user