drivers/kw2xrf: finish ongoing transmission before sending next frame
This commit is contained in:
parent
29f5de38d1
commit
73a2810330
@ -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 @@
|
|||||||
#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 {
|
|||||||
* @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 */
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* 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 @@
|
|||||||
* @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 @@
|
|||||||
#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 @@
|
|||||||
|
|
||||||
#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;
|
||||||
|
|
||||||
if (dev->event_callback) {
|
thread_flags_set(dev->thread, KW2XRF_THREAD_FLAG_ISR);
|
||||||
dev->event_callback(dev, NETDEV_EVENT_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;
|
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)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
{
|
{
|
||||||
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);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user