Skip to content
Snippets Groups Projects
Unverified Commit 9c1b6bd8 authored by Martine Lenders's avatar Martine Lenders Committed by GitHub
Browse files

Merge pull request #8304 from PeterKietzmann/pr_drivers_kw2x_txbusy

drivers/kw2xrf: finish ongoing transmission before sending next frame
parents 9163bdc4 73a28103
No related branches found
No related tags found
No related merge requests found
...@@ -142,6 +142,7 @@ ifneq (,$(filter kw2xrf,$(USEMODULE))) ...@@ -142,6 +142,7 @@ ifneq (,$(filter kw2xrf,$(USEMODULE)))
USEMODULE += netif USEMODULE += netif
USEMODULE += ieee802154 USEMODULE += ieee802154
USEMODULE += netdev_ieee802154 USEMODULE += netdev_ieee802154
USEMODULE += core_thread_flags
FEATURES_REQUIRED += periph_spi FEATURES_REQUIRED += periph_spi
endif endif
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include "net/netdev.h" #include "net/netdev.h"
#include "net/netdev/ieee802154.h" #include "net/netdev/ieee802154.h"
#include "net/gnrc/nettype.h" #include "net/gnrc/nettype.h"
#include "thread.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
...@@ -129,6 +130,7 @@ typedef struct { ...@@ -129,6 +130,7 @@ typedef struct {
* @brief device specific fields * @brief device specific fields
* @{ * @{
*/ */
thread_t *thread; /**< Network driver thread, for providing feedback from IRQ handler */
kw2xrf_params_t params; /**< parameters for initialization */ kw2xrf_params_t params; /**< parameters for initialization */
uint8_t buf[KW2XRF_MAX_PKT_LENGTH]; /**< Buffer for incoming or outgoing packets */ uint8_t buf[KW2XRF_MAX_PKT_LENGTH]; /**< Buffer for incoming or outgoing packets */
uint8_t state; /**< current state of the radio */ uint8_t state; /**< current state of the radio */
......
/* /*
* Copyright (C) 2016 Phytec Messtechnik GmbH * Copyright (C) 2016 Phytec Messtechnik GmbH
2017 HAW Hamburg
2017 SKF AB
* *
* This file is subject to the terms and conditions of the GNU Lesser * 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 * General Public License v2.1. See the file LICENSE in the top level
...@@ -13,7 +15,9 @@ ...@@ -13,7 +15,9 @@
* @file * @file
* @brief Netdev interface for kw2xrf drivers * @brief Netdev interface for kw2xrf drivers
* *
* @author Johann Fischer <j.fischer@phytec.de> * @author Johann Fischer <j.fischer@phytec.de>
* @author Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
*/ */
#include <string.h> #include <string.h>
...@@ -21,6 +25,7 @@ ...@@ -21,6 +25,7 @@
#include <errno.h> #include <errno.h>
#include "log.h" #include "log.h"
#include "thread_flags.h"
#include "net/eui64.h" #include "net/eui64.h"
#include "net/ieee802154.h" #include "net/ieee802154.h"
#include "net/netdev.h" #include "net/netdev.h"
...@@ -41,14 +46,28 @@ ...@@ -41,14 +46,28 @@
#define _MACACKWAITDURATION (864 / 16) /* 864us * 62500Hz */ #define _MACACKWAITDURATION (864 / 16) /* 864us * 62500Hz */
#define KW2XRF_THREAD_FLAG_ISR (1 << 8)
static volatile unsigned int num_irqs_queued = 0;
static volatile unsigned int num_irqs_handled = 0;
static unsigned int spinning_for_irq = 0;
static uint8_t _send_last_fcf; static uint8_t _send_last_fcf;
static void _isr(netdev_t *netdev);
static void _irq_handler(void *arg) static void _irq_handler(void *arg)
{ {
netdev_t *dev = (netdev_t *) arg; netdev_t *netdev = (netdev_t *) arg;
kw2xrf_t *dev = (kw2xrf_t *)netdev;
thread_flags_set(dev->thread, KW2XRF_THREAD_FLAG_ISR);
if (dev->event_callback) { /* We use this counter to avoid filling the message queue with redundant ISR events */
dev->event_callback(dev, NETDEV_EVENT_ISR); if (num_irqs_queued == num_irqs_handled) {
++num_irqs_queued;
if (netdev->event_callback) {
netdev->event_callback(netdev, NETDEV_EVENT_ISR);
}
} }
} }
...@@ -56,6 +75,8 @@ static int _init(netdev_t *netdev) ...@@ -56,6 +75,8 @@ static int _init(netdev_t *netdev)
{ {
kw2xrf_t *dev = (kw2xrf_t *)netdev; kw2xrf_t *dev = (kw2xrf_t *)netdev;
dev->thread = (thread_t *)thread_get(thread_getpid());
/* initialize SPI and GPIOs */ /* initialize SPI and GPIOs */
if (kw2xrf_init(dev, &_irq_handler)) { if (kw2xrf_init(dev, &_irq_handler)) {
LOG_ERROR("[kw2xrf] unable to initialize device\n"); LOG_ERROR("[kw2xrf] unable to initialize device\n");
...@@ -91,6 +112,32 @@ static void kw2xrf_tx_exec(kw2xrf_t *dev) ...@@ -91,6 +112,32 @@ static void kw2xrf_tx_exec(kw2xrf_t *dev)
} }
} }
static void kw2xrf_wait_idle(kw2xrf_t *dev)
{
/* make sure any ongoing T or TR sequence is finished */
if (kw2xrf_can_switch_to_idle(dev) == 0) {
DEBUG("[kw2xrf] TX already in progress\n");
num_irqs_handled = num_irqs_queued;
spinning_for_irq = 1;
thread_flags_clear(KW2XRF_THREAD_FLAG_ISR);
while (1) {
/* TX in progress */
/* Handle any outstanding IRQ first */
_isr((netdev_t *)dev);
/* _isr() will switch the transceiver back to idle after
* handling the TX complete IRQ */
if (kw2xrf_can_switch_to_idle(dev)) {
break;
}
/* Block until we get another IRQ */
thread_flags_wait_any(KW2XRF_THREAD_FLAG_ISR);
DEBUG("[kw2xrf] waited ISR\n");
}
spinning_for_irq = 0;
DEBUG("[kw2xrf] previous TX done\n");
}
}
static int _send(netdev_t *netdev, const struct iovec *vector, unsigned count) static int _send(netdev_t *netdev, const struct iovec *vector, unsigned count)
{ {
kw2xrf_t *dev = (kw2xrf_t *)netdev; kw2xrf_t *dev = (kw2xrf_t *)netdev;
...@@ -98,6 +145,9 @@ static int _send(netdev_t *netdev, const struct iovec *vector, unsigned count) ...@@ -98,6 +145,9 @@ static int _send(netdev_t *netdev, const struct iovec *vector, unsigned count)
uint8_t *pkt_buf = &(dev->buf[1]); uint8_t *pkt_buf = &(dev->buf[1]);
size_t len = 0; size_t len = 0;
/* wait for ongoing transmissions to finish */
kw2xrf_wait_idle(dev);
/* load packet data into buffer */ /* load packet data into buffer */
for (unsigned i = 0; i < count; i++, ptr++) { for (unsigned i = 0; i < count; i++, ptr++) {
/* current packet data + FCS too long */ /* current packet data + FCS too long */
...@@ -109,15 +159,8 @@ static int _send(netdev_t *netdev, const struct iovec *vector, unsigned count) ...@@ -109,15 +159,8 @@ static int _send(netdev_t *netdev, const struct iovec *vector, unsigned count)
len = kw2xrf_tx_load(pkt_buf, ptr->iov_base, ptr->iov_len, len); len = kw2xrf_tx_load(pkt_buf, ptr->iov_base, ptr->iov_len, len);
} }
/* make sure ongoing t or tr sequenz are finished */ kw2xrf_set_sequence(dev, XCVSEQ_IDLE);
if (kw2xrf_can_switch_to_idle(dev)) { dev->pending_tx++;
kw2xrf_set_sequence(dev, XCVSEQ_IDLE);
dev->pending_tx++;
}
else {
/* do not wait, this can lead to a dead lock */
return 0;
}
/* /*
* Nbytes = FRAME_LEN - 2 -> FRAME_LEN = Nbytes + 2 * Nbytes = FRAME_LEN - 2 -> FRAME_LEN = Nbytes + 2
...@@ -690,6 +733,9 @@ static void _isr(netdev_t *netdev) ...@@ -690,6 +733,9 @@ static void _isr(netdev_t *netdev)
{ {
uint8_t dregs[MKW2XDM_PHY_CTRL4 + 1]; uint8_t dregs[MKW2XDM_PHY_CTRL4 + 1];
kw2xrf_t *dev = (kw2xrf_t *)netdev; kw2xrf_t *dev = (kw2xrf_t *)netdev;
if (!spinning_for_irq) {
num_irqs_handled = num_irqs_queued;
}
kw2xrf_read_dregs(dev, MKW2XDM_IRQSTS1, dregs, MKW2XDM_PHY_CTRL4 + 1); kw2xrf_read_dregs(dev, MKW2XDM_IRQSTS1, dregs, MKW2XDM_PHY_CTRL4 + 1);
kw2xrf_mask_irq_b(dev); kw2xrf_mask_irq_b(dev);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment