1
0
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:
Martine Lenders 2018-01-09 16:59:03 +01:00 committed by GitHub
commit 9c1b6bd8c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 62 additions and 13 deletions

View File

@ -142,6 +142,7 @@ ifneq (,$(filter kw2xrf,$(USEMODULE)))
USEMODULE += netif
USEMODULE += ieee802154
USEMODULE += netdev_ieee802154
USEMODULE += core_thread_flags
FEATURES_REQUIRED += periph_spi
endif

View File

@ -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 */

View File

@ -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);