mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #8304 from PeterKietzmann/pr_drivers_kw2x_txbusy
drivers/kw2xrf: finish ongoing transmission before sending next frame
This commit is contained in:
commit
9c1b6bd8c4
@ -142,6 +142,7 @@ ifneq (,$(filter kw2xrf,$(USEMODULE)))
|
||||
USEMODULE += netif
|
||||
USEMODULE += ieee802154
|
||||
USEMODULE += netdev_ieee802154
|
||||
USEMODULE += core_thread_flags
|
||||
FEATURES_REQUIRED += periph_spi
|
||||
endif
|
||||
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "net/netdev.h"
|
||||
#include "net/netdev/ieee802154.h"
|
||||
#include "net/gnrc/nettype.h"
|
||||
#include "thread.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -129,6 +130,7 @@ typedef struct {
|
||||
* @brief device specific fields
|
||||
* @{
|
||||
*/
|
||||
thread_t *thread; /**< Network driver thread, for providing feedback from IRQ handler */
|
||||
kw2xrf_params_t params; /**< parameters for initialization */
|
||||
uint8_t buf[KW2XRF_MAX_PKT_LENGTH]; /**< Buffer for incoming or outgoing packets */
|
||||
uint8_t state; /**< current state of the radio */
|
||||
|
@ -1,5 +1,7 @@
|
||||
/*
|
||||
* 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
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
@ -13,7 +15,9 @@
|
||||
* @file
|
||||
* @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>
|
||||
@ -21,6 +25,7 @@
|
||||
#include <errno.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "thread_flags.h"
|
||||
#include "net/eui64.h"
|
||||
#include "net/ieee802154.h"
|
||||
#include "net/netdev.h"
|
||||
@ -41,14 +46,28 @@
|
||||
|
||||
#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 void _isr(netdev_t *netdev);
|
||||
|
||||
static void _irq_handler(void *arg)
|
||||
{
|
||||
netdev_t *dev = (netdev_t *) arg;
|
||||
netdev_t *netdev = (netdev_t *) arg;
|
||||
kw2xrf_t *dev = (kw2xrf_t *)netdev;
|
||||
|
||||
if (dev->event_callback) {
|
||||
dev->event_callback(dev, NETDEV_EVENT_ISR);
|
||||
thread_flags_set(dev->thread, KW2XRF_THREAD_FLAG_ISR);
|
||||
|
||||
/* We use this counter to avoid filling the message queue with redundant ISR events */
|
||||
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)
|
||||
{
|
||||
kw2xrf_t *dev = (kw2xrf_t *)netdev;
|
||||
|
||||
dev->thread = (thread_t *)thread_get(thread_getpid());
|
||||
|
||||
/* initialize SPI and GPIOs */
|
||||
if (kw2xrf_init(dev, &_irq_handler)) {
|
||||
LOG_ERROR("[kw2xrf] unable to initialize device\n");
|
||||
@ -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)
|
||||
{
|
||||
kw2xrf_t *dev = (kw2xrf_t *)netdev;
|
||||
@ -98,6 +145,9 @@ static int _send(netdev_t *netdev, const struct iovec *vector, unsigned count)
|
||||
uint8_t *pkt_buf = &(dev->buf[1]);
|
||||
size_t len = 0;
|
||||
|
||||
/* wait for ongoing transmissions to finish */
|
||||
kw2xrf_wait_idle(dev);
|
||||
|
||||
/* load packet data into buffer */
|
||||
for (unsigned i = 0; i < count; i++, ptr++) {
|
||||
/* current packet data + FCS too long */
|
||||
@ -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);
|
||||
}
|
||||
|
||||
/* make sure ongoing t or tr sequenz are finished */
|
||||
if (kw2xrf_can_switch_to_idle(dev)) {
|
||||
kw2xrf_set_sequence(dev, XCVSEQ_IDLE);
|
||||
dev->pending_tx++;
|
||||
}
|
||||
else {
|
||||
/* do not wait, this can lead to a dead lock */
|
||||
return 0;
|
||||
}
|
||||
kw2xrf_set_sequence(dev, XCVSEQ_IDLE);
|
||||
dev->pending_tx++;
|
||||
|
||||
/*
|
||||
* Nbytes = FRAME_LEN - 2 -> FRAME_LEN = Nbytes + 2
|
||||
@ -690,6 +733,9 @@ static void _isr(netdev_t *netdev)
|
||||
{
|
||||
uint8_t dregs[MKW2XDM_PHY_CTRL4 + 1];
|
||||
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_mask_irq_b(dev);
|
||||
|
Loading…
Reference in New Issue
Block a user