Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] drivers/kw2xrf: CSMA support #12589

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 17 additions & 13 deletions drivers/include/kw2xrf.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,20 +88,14 @@ extern "C" {
#define KW2XRF_OPT_RAWDUMP (NETDEV_IEEE802154_RAW) /**< legacy define */
#define KW2XRF_OPT_ACK_REQ (NETDEV_IEEE802154_ACK_REQ) /**< legacy define */

#define KW2XRF_OPT_AUTOCCA (0x0100) /**< CCA before TX active */
#define KW2XRF_OPT_PROMISCUOUS (0x0200) /**< promiscuous mode
* active */
#define KW2XRF_OPT_CSMA (0x0100) /**< use CSMA/CA algorithm for sending */
#define KW2XRF_OPT_PROMISCUOUS (0x0200) /**< promiscuous mode active */
#define KW2XRF_OPT_PRELOADING (0x0400) /**< preloading enabled */
#define KW2XRF_OPT_TELL_TX_START (0x0800) /**< notify MAC layer on TX
* start */
#define KW2XRF_OPT_TELL_TX_END (0x1000) /**< notify MAC layer on TX
* finished */
#define KW2XRF_OPT_TELL_RX_START (0x2000) /**< notify MAC layer on RX
* start */
#define KW2XRF_OPT_TELL_RX_END (0x4000) /**< notify MAC layer on RX
* finished */
#define KW2XRF_OPT_AUTOACK (0x8000) /**< enable automatically ACK
* for incommint packet */
#define KW2XRF_OPT_TELL_TX_START (0x0800) /**< notify MAC layer on TX start */
#define KW2XRF_OPT_TELL_TX_END (0x1000) /**< notify MAC layer on TX finished */
#define KW2XRF_OPT_TELL_RX_START (0x2000) /**< notify MAC layer on RX start */
#define KW2XRF_OPT_TELL_RX_END (0x4000) /**< notify MAC layer on RX finished */
#define KW2XRF_OPT_AUTOACK (0x8000) /**< enable automatic ACK for incoming packet */
/** @} */

/**
Expand Down Expand Up @@ -135,6 +129,16 @@ typedef struct {
this is required to know when to
return to @ref kw2xrf_t::idle_state */
int16_t tx_power; /**< The current tx-power setting of the device */

/** -----------------Internal CSMA algorithm parameters-----------------*/
uint8_t csma_min_be; /**< Minimum backoff exponent (macMinBe) */
uint8_t csma_max_be; /**< Maximum backoff exponent (macMaxBe) */
uint8_t csma_be; /**< CSMA backoff exponent in the current transmission attempt */
uint32_t csma_delay; /**< The actual delay for the CSMA algorithm */

/** -----------------Internal counters-----------------*/
uint8_t num_backoffs; /**< Number of CSMA backoffs so far in the current transmission attempt */
uint8_t max_backoffs; /**< Maximum number of CSMA backoffs when waiting for channel clear (macMaxCsmaBackoffs) */
/** @} */
} kw2xrf_t;

Expand Down
8 changes: 7 additions & 1 deletion drivers/kw2xrf/kw2xrf.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ void kw2xrf_setup(kw2xrf_t *dev, const kw2xrf_params_t *params)
dev->idle_state = XCVSEQ_RECEIVE;
dev->state = 0;
dev->pending_tx = 0;

/* Set default parameters according to STD IEEE802.15.4-2015 */
dev->csma_max_be = 5;
dev->csma_min_be = 3;
dev->max_backoffs = 4;

kw2xrf_spi_init(dev);
kw2xrf_set_power_mode(dev, KW2XRF_IDLE);
DEBUG("[kw2xrf] setup finished\n");
Expand Down Expand Up @@ -105,7 +111,7 @@ void kw2xrf_reset_phy(kw2xrf_t *dev)

kw2xrf_set_option(dev, KW2XRF_OPT_AUTOACK, true);
kw2xrf_set_option(dev, KW2XRF_OPT_ACK_REQ, true);
kw2xrf_set_option(dev, KW2XRF_OPT_AUTOCCA, true);
kw2xrf_set_option(dev, KW2XRF_OPT_CSMA, true);

kw2xrf_set_power_mode(dev, KW2XRF_AUTODOZE);
kw2xrf_set_sequence(dev, dev->idle_state);
Expand Down
4 changes: 2 additions & 2 deletions drivers/kw2xrf/kw2xrf_getset.c
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ void kw2xrf_set_option(kw2xrf_t *dev, uint16_t option, bool state)

/* trigger option specific actions */
switch (option) {
case KW2XRF_OPT_AUTOCCA:
case KW2XRF_OPT_CSMA:
LOG_DEBUG("[kw2xrf] opt: enabling CCA before TX mode\n");
kw2xrf_set_dreg_bit(dev, MKW2XDM_PHY_CTRL1,
MKW2XDM_PHY_CTRL1_CCABFRTX);
Expand Down Expand Up @@ -423,7 +423,7 @@ void kw2xrf_set_option(kw2xrf_t *dev, uint16_t option, bool state)
dev->netdev.flags &= ~(option);
/* trigger option specific actions */
switch (option) {
case KW2XRF_OPT_AUTOCCA:
case KW2XRF_OPT_CSMA:
kw2xrf_clear_dreg_bit(dev, MKW2XDM_PHY_CTRL1,
MKW2XDM_PHY_CTRL1_CCABFRTX);
break;
Expand Down
199 changes: 180 additions & 19 deletions drivers/kw2xrf/kw2xrf_netdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,18 @@
* @author Johann Fischer <j.fischer@phytec.de>
* @author Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
* @author Adem-Can Agdas <adem-can.agdas@haw-hamburg.de>
*/

// >>< TODO: Complete DEBUG messages
// >>< TODO: Code conventions

#include <string.h>
#include <assert.h>
#include <errno.h>

#include "log.h"
#include "random.h"
#include "thread_flags.h"
#include "net/eui64.h"
#include "net/ieee802154.h"
Expand All @@ -43,6 +48,7 @@
#include "debug.h"

#define _MACACKWAITDURATION (864 / 16) /* 864us * 62500Hz */
#define KW2XRF_CSMA_UNIT_TIME 20 //320 us

#define KW2XRF_THREAD_FLAG_ISR (1 << 8)

Expand Down Expand Up @@ -95,15 +101,52 @@ static size_t kw2xrf_tx_load(uint8_t *pkt_buf, uint8_t *buf, size_t len, size_t
return offset + len;
}

/**
* @brief Generate a random number for using as a CSMA delay value
*/
static inline uint32_t kw2xrf_csma_random_delay(kw2xrf_t *dev)
{
/* Use topmost csma_be bits of the random number */
uint32_t rnd = random_uint32() >> (32 - dev->csma_be);

if(rnd == 0)
{
rnd = 1; //Wait at least ONE unit time, so timer target doesn't pass
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this rather be the statement of the sort rnd = max(rnd,1) ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't that describe the same logic? Or am I missing something?

return (rnd * KW2XRF_CSMA_UNIT_TIME);
}

static void kw2xrf_tx_exec(kw2xrf_t *dev)
{
if ((dev->netdev.flags & KW2XRF_OPT_ACK_REQ) &&
(_send_last_fcf & IEEE802154_FCF_ACK_REQ)) {
kw2xrf_set_sequence(dev, XCVSEQ_IDLE);

bool transmit_with_receive = ((dev->netdev.flags & KW2XRF_OPT_ACK_REQ) &&
(_send_last_fcf & IEEE802154_FCF_ACK_REQ));
bool csma_requested = (dev->netdev.flags & KW2XRF_OPT_CSMA);

if(csma_requested)
{
/* Allow TMR2 interrupt to schedule a TX operation */
/* This MUST be done BEFORE the sequence has been written to XCVSEQ, otherwise it will be executed immediately */
/* For more info check the Reference Manual */
/* Chapter 7.7.3 Using T2CMP to Trigger Transceiver Operations*/
kw2xrf_timer2_seq_start_on(dev);
}

if (transmit_with_receive) {
kw2xrf_set_sequence(dev, XCVSEQ_TX_RX);
}
else {
kw2xrf_set_sequence(dev, XCVSEQ_TRANSMIT);
}

if(csma_requested)
{
/* Enable TMR2 interrupt and set timeout for TMR2 */
/* This should be done after the sequence has been written to XCVSEQ */
kw2xrf_trigger_tx_ops_enable(dev, dev->csma_delay);
}
}

static void kw2xrf_wait_idle(kw2xrf_t *dev)
Expand Down Expand Up @@ -152,7 +195,6 @@ static int _send(netdev_t *netdev, const iolist_t *iolist)
len = kw2xrf_tx_load(pkt_buf, iol->iol_base, iol->iol_len, len);
}

kw2xrf_set_sequence(dev, XCVSEQ_IDLE);
dev->pending_tx++;

/*
Expand All @@ -168,6 +210,10 @@ static int _send(netdev_t *netdev, const iolist_t *iolist)

/* send data out directly if pre-loading id disabled */
if (!(dev->netdev.flags & KW2XRF_OPT_PRELOADING)) {
/* New transmission! Reset the CSMA counters */
dev->csma_be = dev->csma_min_be;
dev->num_backoffs = 0;
dev->csma_delay = kw2xrf_csma_random_delay(dev);
kw2xrf_tx_exec(dev);
}

Expand Down Expand Up @@ -315,11 +361,32 @@ int _get(netdev_t *netdev, netopt_t opt, void *value, size_t len)
!!(dev->netdev.flags & KW2XRF_OPT_TELL_TX_END);
return sizeof(netopt_enable_t);

case NETOPT_AUTOCCA:
case NETOPT_CSMA:
*((netopt_enable_t *)value) =
!!(dev->netdev.flags & KW2XRF_OPT_AUTOCCA);
!!(dev->netdev.flags & KW2XRF_OPT_CSMA);
return sizeof(netopt_enable_t);

case NETOPT_CSMA_RETRIES:
if (len != sizeof(uint8_t)) {
return -EOVERFLOW;
}
*((uint8_t *)value) = dev->max_backoffs;
return len;

case NETOPT_CSMA_MAXBE:
if (len != sizeof(uint8_t)) {
return -EOVERFLOW;
}
*((uint8_t *)value) = dev->csma_max_be;
return len;

case NETOPT_CSMA_MINBE:
if (len != sizeof(uint8_t)) {
return -EOVERFLOW;
}
*((uint8_t *)value) = dev->csma_min_be;
return len;

case NETOPT_CHANNEL:
if (len < sizeof(uint16_t)) {
return -EOVERFLOW;
Expand Down Expand Up @@ -503,13 +570,39 @@ static int _set(netdev_t *netdev, netopt_t opt, const void *value, size_t len)
((bool *)value)[0]);
res = sizeof(netopt_enable_t);
break;

case NETOPT_AUTOCCA:
kw2xrf_set_option(dev, KW2XRF_OPT_AUTOCCA,
case NETOPT_CSMA:
kw2xrf_set_option(dev, KW2XRF_OPT_CSMA,
((bool *)value)[0]);
res = sizeof(netopt_enable_t);
break;

case NETOPT_CSMA_RETRIES:
if (len != sizeof(uint8_t)) {
res = -EOVERFLOW;
break;
}
dev->max_backoffs = *((const uint8_t*)value);
res = len;
break;

case NETOPT_CSMA_MAXBE:
if (len != sizeof(uint8_t)) {
res = -EOVERFLOW;
break;
}
dev->csma_max_be = *((const uint8_t*)value);
res = len;
break;

case NETOPT_CSMA_MINBE:
if (len != sizeof(uint8_t)) {
res = -EOVERFLOW;
break;
}
dev->csma_min_be = *((const uint8_t*)value);
res = len;
break;

case NETOPT_CCA_THRESHOLD:
if (len < sizeof(uint8_t)) {
res = -EOVERFLOW;
Expand Down Expand Up @@ -614,21 +707,55 @@ static void _isr_event_seq_t(netdev_t *netdev, uint8_t *dregs)
if (dregs[MKW2XDM_IRQSTS1] & MKW2XDM_IRQSTS1_SEQIRQ) {
DEBUG("[kw2xrf] SEQIRQ\n");
irqsts1 |= MKW2XDM_IRQSTS1_SEQIRQ;
bool retransmission_issued = false;

if (dregs[MKW2XDM_IRQSTS1] & MKW2XDM_IRQSTS1_CCAIRQ) {
irqsts1 |= MKW2XDM_IRQSTS1_CCAIRQ;

if (dregs[MKW2XDM_IRQSTS2] & MKW2XDM_IRQSTS2_CCA) {
DEBUG("[kw2xrf] CCA CH busy\n");
netdev->event_callback(netdev, NETDEV_EVENT_TX_MEDIUM_BUSY);
/* Channel busy: Try CSMA backoff */
/* Info: The fact, that a CCA was performed here, means that NETOPT_CSMA was set before, so we don't have to check that */
/* Limit reached ? */
if(dev->num_backoffs < dev->max_backoffs)
{
/* Limit for retransmissions hasn't been reached yet: try again! */
dev->num_backoffs++;
if(dev->csma_be < dev->csma_max_be)
{
dev->csma_be++;
}
dev->csma_delay = kw2xrf_csma_random_delay(dev);
kw2xrf_tx_exec(dev);
retransmission_issued = true;
}
else
{
/* Limit for retransmissions reached: give up */
netdev->event_callback(netdev, NETDEV_EVENT_TX_MEDIUM_BUSY);
}
}
else {
netdev->event_callback(netdev, NETDEV_EVENT_TX_COMPLETE);
}
}

assert(dev->pending_tx != 0);
dev->pending_tx--;
kw2xrf_set_idle_sequence(dev);
if(!retransmission_issued)
{
/* If a retransmission was issued, that means we're not done yet! */
assert(dev->pending_tx != 0);
dev->pending_tx--;
kw2xrf_set_idle_sequence(dev);
}
}

if (dregs[MKW2XDM_IRQSTS3] & MKW2XDM_IRQSTS3_TMR2IRQ) {
/* TMR2 interrupt means a TX operation that was scheduled by TMR2 has been executed */

/* Disallow TMR2 interrupt to schedule a TX operation */
kw2xrf_timer2_seq_start_off(dev);
/* Disable TMR2 interrupt and reset TMR2IRQ */
kw2xrf_trigger_tx_ops_disable(dev);
}

kw2xrf_write_dreg(dev, MKW2XDM_IRQSTS1, irqsts1);
Expand Down Expand Up @@ -689,18 +816,37 @@ static void _isr_event_seq_tr(netdev_t *netdev, uint8_t *dregs)
}

if (dregs[MKW2XDM_IRQSTS1] & MKW2XDM_IRQSTS1_SEQIRQ) {
DEBUG("[kw2xrf] SEQIRQ\n");
irqsts1 |= MKW2XDM_IRQSTS1_SEQIRQ;
bool retry_issued = false;

if (dregs[MKW2XDM_IRQSTS1] & MKW2XDM_IRQSTS1_CCAIRQ) {
irqsts1 |= MKW2XDM_IRQSTS1_CCAIRQ;
if (dregs[MKW2XDM_IRQSTS2] & MKW2XDM_IRQSTS2_CCA) {
DEBUG("[kw2xrf] CCA CH busy\n");
netdev->event_callback(netdev, NETDEV_EVENT_TX_MEDIUM_BUSY);
/* Channel busy: Try CSMA backoff */
/* Info: The fact, that a CCA was performed here, means that NETOPT_CSMA was set before, so we don't have to check that */
/* Limit reached ? */
if(dev->num_backoffs < dev->max_backoffs)
{
/* Limit for backoffs hasn't been reached yet: try again! */
dev->num_backoffs++;
if(dev->csma_be < dev->csma_max_be)
{
dev->csma_be++;
}
dev->csma_delay = kw2xrf_csma_random_delay(dev);
kw2xrf_tx_exec(dev);
retry_issued = true;
}
else
{
/* Limit for retransmissions reached: give up */
netdev->event_callback(netdev, NETDEV_EVENT_TX_MEDIUM_BUSY);
}
}
}

irqsts1 |= MKW2XDM_IRQSTS1_SEQIRQ;
assert(dev->pending_tx != 0);
dev->pending_tx--;

if (dregs[MKW2XDM_IRQSTS3] & MKW2XDM_IRQSTS3_TMR3IRQ) {
/* if the sequence was aborted by timer 3, ACK timed out */
DEBUG("[kw2xrf] TC3TMOUT, SEQIRQ, TX failed\n");
Expand All @@ -714,8 +860,23 @@ static void _isr_event_seq_tr(netdev_t *netdev, uint8_t *dregs)
kw2xrf_timer3_seq_abort_off(dev);
/* Disable interrupt for TMR3 and reset TMR3IRQ */
kw2xrf_abort_rx_ops_disable(dev);
/* Go back to idle state */
kw2xrf_set_idle_sequence(dev);

if(!retry_issued)
{
/* If a retry was issued, that means we're not done yet! */
assert(dev->pending_tx != 0);
dev->pending_tx--;
kw2xrf_set_idle_sequence(dev);
}
}

if (dregs[MKW2XDM_IRQSTS3] & MKW2XDM_IRQSTS3_TMR2IRQ) {
/* TMR2 interrupt means a TX operation that was scheduled by TMR2 has been executed */

/* Disallow TMR2 interrupt to schedule a TX operation */
kw2xrf_timer2_seq_start_off(dev);
/* Disable TMR2 interrupt and reset TMR2IRQ */
kw2xrf_trigger_tx_ops_disable(dev);
}

kw2xrf_write_dreg(dev, MKW2XDM_IRQSTS1, irqsts1);
Expand Down