mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-01-17 05:32:45 +01:00
slipdev: simplify and solidify byte-unstuffing
This simplifies and solidifies the reversal of SLIP's byte-stuffing (aka byte-unstuffing ;-)) by 1. Using `tsrb` instead of `ringbuffer`: there are two actors. The ISR and the device's event handler. 2. Moving the byte-unstuffing from the UART RX-handler (i.e. the ISR) to the device's receive function (potentially not the ISR) 3. Removing the `pktfifo` member. The current number of bytes in the ringbuffer is returned for `recv(data = NULL, len = 0)`. If that is more than the packet contains (due to the byte stuffing it most likely will be) the packet is reallocated in GNRC anyway.
This commit is contained in:
parent
ef3c6022f2
commit
c61a343193
@ -246,6 +246,7 @@ ifneq (,$(filter si70%,$(USEMODULE)))
|
||||
endif
|
||||
|
||||
ifneq (,$(filter slipdev,$(USEMODULE)))
|
||||
USEMODULE += tsrb
|
||||
FEATURES_REQUIRED += periph_uart
|
||||
endif
|
||||
|
||||
|
@ -26,7 +26,7 @@
|
||||
#include "cib.h"
|
||||
#include "net/netdev.h"
|
||||
#include "periph/uart.h"
|
||||
#include "ringbuffer.h"
|
||||
#include "tsrb.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -36,20 +36,12 @@ extern "C" {
|
||||
* @brief UART buffer size used for TX and RX buffers
|
||||
*
|
||||
* Reduce this value if your expected traffic does not include full IPv6 MTU
|
||||
* sized packets
|
||||
* sized packets.
|
||||
*
|
||||
* @pre Needs to be power of two and `<= INT_MAX`
|
||||
*/
|
||||
#ifndef SLIPDEV_BUFSIZE
|
||||
#define SLIPDEV_BUFSIZE (1500U)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Packet FIFO size
|
||||
*
|
||||
* @note For GNRC it is recommended to have it the same size as the link-layer
|
||||
* thread's message queue, but it MUST be of power of 2
|
||||
*/
|
||||
#ifndef SLIPDEV_PKTFIFO_SIZE
|
||||
#define SLIPDEV_PKTFIFO_SIZE (8U)
|
||||
#define SLIPDEV_BUFSIZE (2048U)
|
||||
#endif
|
||||
|
||||
/**
|
||||
@ -68,13 +60,8 @@ typedef struct {
|
||||
typedef struct {
|
||||
netdev_t netdev; /**< parent class */
|
||||
slipdev_params_t config; /**< configuration parameters */
|
||||
ringbuffer_t inbuf; /**< RX buffer */
|
||||
tsrb_t inbuf; /**< RX buffer */
|
||||
char rxmem[SLIPDEV_BUFSIZE]; /**< memory used by RX buffer */
|
||||
uint16_t pktfifo[SLIPDEV_PKTFIFO_SIZE]; /**< FIFO of sizes of fully received
|
||||
* packets */
|
||||
cib_t pktfifo_idx; /**< CIB for slipdev_t::pktfifo */
|
||||
uint16_t inbytes; /**< the number of bytes received of
|
||||
* a currently incoming packet */
|
||||
uint16_t inesc; /**< device previously received an escape
|
||||
* byte */
|
||||
} slipdev_t;
|
||||
|
@ -48,53 +48,17 @@ void slipdev_setup(slipdev_t *dev, const slipdev_params_t *params)
|
||||
{
|
||||
/* set device descriptor fields */
|
||||
memcpy(&dev->config, params, sizeof(dev->config));
|
||||
dev->inbytes = 0U;
|
||||
dev->inesc = 0U;
|
||||
dev->netdev.driver = &slip_driver;
|
||||
}
|
||||
|
||||
static inline void _add_byte_to_inbuf(slipdev_t *dev, uint8_t byte)
|
||||
{
|
||||
if (ringbuffer_add_one(&dev->inbuf, byte) < 0) {
|
||||
dev->inbytes++;
|
||||
}
|
||||
}
|
||||
|
||||
static void _slip_rx_cb(void *arg, uint8_t data)
|
||||
static void _slip_rx_cb(void *arg, uint8_t byte)
|
||||
{
|
||||
slipdev_t *dev = arg;
|
||||
|
||||
if ((data == SLIP_END) && (dev->netdev.event_callback != NULL)) {
|
||||
int idx = cib_put(&dev->pktfifo_idx);
|
||||
if (idx >= 0) {
|
||||
dev->netdev.event_callback((netdev_t *)dev, NETDEV_EVENT_ISR);
|
||||
dev->pktfifo[idx] = dev->inbytes;
|
||||
}
|
||||
else {
|
||||
/* can't handover packet => dropping it */
|
||||
ringbuffer_remove(&dev->inbuf, dev->inbytes);
|
||||
}
|
||||
dev->inbytes = 0;
|
||||
}
|
||||
else if (dev->inesc) {
|
||||
dev->inesc = 0U;
|
||||
uint8_t actual = (data == SLIP_END_ESC) ? SLIP_END :
|
||||
((data == SLIP_ESC_ESC) ? SLIP_ESC : 0);
|
||||
|
||||
switch (data) {
|
||||
case SLIP_END_ESC:
|
||||
case SLIP_ESC_ESC:
|
||||
_add_byte_to_inbuf(dev, actual);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (data == SLIP_ESC) {
|
||||
dev->inesc = 1U;
|
||||
}
|
||||
else {
|
||||
_add_byte_to_inbuf(dev, data);
|
||||
tsrb_add_one(&dev->inbuf, byte);
|
||||
if ((byte == SLIP_END) && (dev->netdev.event_callback != NULL)) {
|
||||
dev->netdev.event_callback((netdev_t *)dev, NETDEV_EVENT_ISR);
|
||||
}
|
||||
}
|
||||
|
||||
@ -105,8 +69,7 @@ static int _init(netdev_t *netdev)
|
||||
DEBUG("slipdev: initializing device %p on UART %i with baudrate %" PRIu32 "\n",
|
||||
(void *)dev, dev->config.uart, dev->config.baudrate);
|
||||
/* initialize buffers */
|
||||
ringbuffer_init(&dev->inbuf, dev->rxmem, sizeof(dev->rxmem));
|
||||
cib_init(&dev->pktfifo_idx, SLIPDEV_PKTFIFO_SIZE);
|
||||
tsrb_init(&dev->inbuf, dev->rxmem, sizeof(dev->rxmem));
|
||||
if (uart_init(dev->config.uart, dev->config.baudrate, _slip_rx_cb,
|
||||
dev) != UART_OK) {
|
||||
LOG_ERROR("slipdev: error initializing UART %i with baudrate %" PRIu32 "\n",
|
||||
@ -155,30 +118,69 @@ static int _send(netdev_t *netdev, const struct iovec *vector, unsigned count)
|
||||
static int _recv(netdev_t *netdev, void *buf, size_t len, void *info)
|
||||
{
|
||||
slipdev_t *dev = (slipdev_t *)netdev;
|
||||
int res, idx = cib_peek(&dev->pktfifo_idx);
|
||||
int res = 0;
|
||||
|
||||
(void)info;
|
||||
if (idx < 0) {
|
||||
return -EFAULT;
|
||||
}
|
||||
if (buf == NULL) {
|
||||
if (len > 0) {
|
||||
/* drop packet */
|
||||
cib_get(&dev->pktfifo_idx);
|
||||
/* and remove data */
|
||||
res = ringbuffer_remove(&dev->inbuf, len);
|
||||
/* remove data */
|
||||
for (; len > 0; len--) {
|
||||
int byte = tsrb_get_one(&dev->inbuf);
|
||||
if ((byte == (int)SLIP_END) || (byte < 0)) {
|
||||
/* end early if end of packet or ringbuffer is reached;
|
||||
* len might be larger than the actual packet */
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* the user was warned not to use a buffer size > `INT_MAX` ;-) */
|
||||
res = (int)tsrb_avail(&dev->inbuf);
|
||||
}
|
||||
else {
|
||||
res = dev->pktfifo[idx];
|
||||
}
|
||||
}
|
||||
else if (len < dev->pktfifo[idx]) {
|
||||
res = -ENOBUFS;
|
||||
}
|
||||
else {
|
||||
size_t bytes = dev->pktfifo[cib_get(&dev->pktfifo_idx)];
|
||||
bytes = ringbuffer_get(&dev->inbuf, buf, bytes);
|
||||
res = bytes;
|
||||
int byte;
|
||||
uint8_t *ptr = buf;
|
||||
|
||||
do {
|
||||
if ((byte = tsrb_get_one(&dev->inbuf)) < 0) {
|
||||
/* something went wrong, return error */
|
||||
return -EIO;
|
||||
}
|
||||
switch (byte) {
|
||||
case SLIP_END:
|
||||
break;
|
||||
case SLIP_ESC:
|
||||
dev->inesc = 1;
|
||||
break;
|
||||
case SLIP_END_ESC:
|
||||
if (dev->inesc) {
|
||||
*(ptr++) = SLIP_END;
|
||||
res++;
|
||||
dev->inesc = 0;
|
||||
break;
|
||||
}
|
||||
/* falls through intentionally to default when !dev->inesc */
|
||||
case SLIP_ESC_ESC:
|
||||
if (dev->inesc) {
|
||||
*(ptr++) = SLIP_ESC;
|
||||
res++;
|
||||
dev->inesc = 0;
|
||||
break;
|
||||
}
|
||||
/* falls through intentionally to default when !dev->inesc */
|
||||
default:
|
||||
*(ptr++) = (uint8_t)byte;
|
||||
res++;
|
||||
break;
|
||||
}
|
||||
if ((unsigned)res > len) {
|
||||
while (byte != SLIP_END) {
|
||||
/* clear out unreceived packet */
|
||||
byte = tsrb_get_one(&dev->inbuf);
|
||||
}
|
||||
return -ENOBUFS;
|
||||
}
|
||||
} while (byte != SLIP_END);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user