slip: port to be used with netdev

This commit is contained in:
Martine Lenders 2017-07-18 14:39:03 +02:00
parent 9368b1deb6
commit b74ee8869b
21 changed files with 554 additions and 465 deletions

View File

@ -377,10 +377,6 @@ ifneq (,$(filter gnrc_pktdump,$(USEMODULE)))
USEMODULE += od USEMODULE += od
endif endif
ifneq (,$(filter gnrc_slip,$(USEMODULE)))
FEATURES_REQUIRED += periph_uart
endif
ifneq (,$(filter od,$(USEMODULE))) ifneq (,$(filter od,$(USEMODULE)))
USEMODULE += fmt USEMODULE += fmt
endif endif

View File

@ -1,7 +1,7 @@
Creating a SLIP network interface Creating a SLIP network interface
================================= =================================
The module `gnrc_slip` (Serial line IP) enables the RIOT network stack to The module `slipdev` (Serial line IP) enables the RIOT network stack to
communicate IP packets over the serial interface. This collection of tools communicate IP packets over the serial interface. This collection of tools
originally from Contiki [1] enables Linux to interpret this data. Though there originally from Contiki [1] enables Linux to interpret this data. Though there
is a tool for such operations on Linux (`slattach`) it is only able to handle is a tool for such operations on Linux (`slattach`) it is only able to handle

View File

@ -246,6 +246,10 @@ ifneq (,$(filter lsm6dsl,$(USEMODULE)))
USEMODULE += xtimer USEMODULE += xtimer
endif endif
ifneq (,$(filter slipdev,$(USEMODULE)))
FEATURES_REQUIRED += periph_uart
endif
ifneq (,$(filter adc%1c,$(USEMODULE))) ifneq (,$(filter adc%1c,$(USEMODULE)))
FEATURES_REQUIRED += periph_gpio FEATURES_REQUIRED += periph_gpio
FEATURES_REQUIRED += periph_i2c FEATURES_REQUIRED += periph_i2c

View File

@ -213,7 +213,8 @@ enum {
NETDEV_TYPE_IEEE802154, NETDEV_TYPE_IEEE802154,
NETDEV_TYPE_CC110X, NETDEV_TYPE_CC110X,
NETDEV_TYPE_LORA, NETDEV_TYPE_LORA,
NETDEV_TYPE_NRFMIN NETDEV_TYPE_NRFMIN,
NETDEV_TYPE_SLIP,
}; };
/** /**

95
drivers/include/slipdev.h Normal file
View File

@ -0,0 +1,95 @@
/*
* Copyright (C) 2015-17 Freie Universität Berlin
*
* 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
* directory for more details.
*/
/**
* @defgroup drivers_slipdev SLIP network device
* @ingroup drivers_netdev
* @brief SLIP network device over @ref drivers_periph_uart
* @see [RFC 1055](https://github.com/RIOT-OS/RIOT/pull/6487)
* @{
*
* @file
* @brief SLIP device definitions
*
* @author Martine Lenders <m.lenders@fu-berlin.de>
*/
#ifndef SLIPDEV_H
#define SLIPDEV_H
#include <stdint.h>
#include "cib.h"
#include "net/netdev.h"
#include "periph/uart.h"
#include "ringbuffer.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @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
*/
#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)
#endif
/**
* @brief Configuration parameters for a slipdev
*/
typedef struct {
uart_t uart; /**< UART interface the device is connected to */
uint32_t baudrate; /**< baudrate to use with slipdev_params_t::uart */
} slipdev_params_t;
/**
* @brief Device descriptor for slipdev
*
* @extends netdev_t
*/
typedef struct {
netdev_t netdev; /**< parent class */
slipdev_params_t config; /**< configuration parameters */
ringbuffer_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;
/**
* @brief Setup a slipdev device state
*
* @param[in] dev device descriptor
* @param[in] params parameters for device initialization
*/
void slipdev_setup(slipdev_t *dev, const slipdev_params_t *params);
#ifdef __cplusplus
}
#endif
#endif /* SLIPDEV_H */
/** @} */

View File

@ -1,3 +1 @@
MODULE = gnrc_slip
include $(RIOTBASE)/Makefile.base include $(RIOTBASE)/Makefile.base

222
drivers/slipdev/slipdev.c Normal file
View File

@ -0,0 +1,222 @@
/*
* Copyright (C) 2017 Freie Universität Berlin
*
* 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
* directory for more details.
*/
/**
* @{
*
* @file
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/
#include <errno.h>
#include <string.h>
#include "log.h"
#include "slipdev.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#define SLIP_END (0xc0U)
#define SLIP_ESC (0xdbU)
#define SLIP_END_ESC (0xdcU)
#define SLIP_ESC_ESC (0xddU)
static int _send(netdev_t *dev, const struct iovec *vector, unsigned count);
static int _recv(netdev_t *dev, void *buf, size_t len, void *info);
static int _init(netdev_t *dev);
static void _isr(netdev_t *dev);
static int _get(netdev_t *dev, netopt_t opt, void *value, size_t max_len);
static int _set(netdev_t *dev, netopt_t opt, const void *value,
size_t value_len);
static const netdev_driver_t slip_driver = {
.send = _send,
.recv = _recv,
.init = _init,
.isr = _isr,
.get = _get,
.set = _set,
};
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)
{
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);
}
}
static int _init(netdev_t *netdev)
{
slipdev_t *dev = (slipdev_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);
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",
dev->config.uart, dev->config.baudrate);
return -ENODEV;
}
return 0;
}
static inline void _write_byte(slipdev_t *dev, uint8_t byte)
{
uart_write(dev->config.uart, &byte, 1);
}
static int _send(netdev_t *netdev, const struct iovec *vector, unsigned count)
{
slipdev_t *dev = (slipdev_t *)netdev;
int bytes = 0;
DEBUG("slipdev: sending vector of length %u\n", count);
for (unsigned i = 0; i < count; i++) {
uint8_t *data = vector[i].iov_base;
for (unsigned j = 0; j < vector[i].iov_len; j++, data++) {
switch(*data) {
case SLIP_END:
/* escaping END byte*/
_write_byte(dev, SLIP_ESC);
_write_byte(dev, SLIP_END_ESC);
break;
case SLIP_ESC:
/* escaping ESC byte*/
_write_byte(dev, SLIP_ESC);
_write_byte(dev, SLIP_ESC_ESC);
break;
default:
_write_byte(dev, *data);
}
bytes++;
}
}
_write_byte(dev, SLIP_END);
return bytes;
}
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);
(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);
}
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;
}
return res;
}
static void _isr(netdev_t *netdev)
{
DEBUG("slipdev: handling ISR event\n");
if (netdev->event_callback != NULL) {
DEBUG("slipdev: event handler set, issuing RX_COMPLETE event\n");
netdev->event_callback(netdev, NETDEV_EVENT_RX_COMPLETE);
}
}
static int _get(netdev_t *netdev, netopt_t opt, void *value, size_t max_len)
{
(void)netdev;
(void)value;
(void)max_len;
switch (opt) {
case NETOPT_IS_WIRED:
return 1;
case NETOPT_DEVICE_TYPE:
assert(max_len == sizeof(uint16_t));
*((uint16_t *)value) = NETDEV_TYPE_SLIP;
return sizeof(uint16_t);
default:
return -ENOTSUP;
}
}
static int _set(netdev_t *netdev, netopt_t opt, const void *value,
size_t value_len)
{
(void)netdev;
(void)opt;
(void)value;
(void)value_len;
return -ENOTSUP;
}
/** @} */

View File

@ -48,7 +48,7 @@ USEMODULE += gnrc_rpl
# Border router requirements # Border router requirements
# Include SLIP package for IP over Serial communication # Include SLIP package for IP over Serial communication
USEMODULE += gnrc_slip USEMODULE += slipdev
# Specify the mandatory networking modules for 6LoWPAN border router # Specify the mandatory networking modules for 6LoWPAN border router
USEMODULE += gnrc_sixlowpan_border_router_default USEMODULE += gnrc_sixlowpan_border_router_default
# Additional networking modules that can be dropped if not needed # Additional networking modules that can be dropped if not needed

View File

@ -16,16 +16,16 @@
* @author Martine Lenders <mlenders@inf.fu-berlin.de> * @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/ */
#ifndef SLIP_PARAMS_H #ifndef SLIPDEV_PARAMS_H
#define SLIP_PARAMS_H #define SLIPDEV_PARAMS_H
#include "net/gnrc/slip.h" #include "slipdev.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
static gnrc_slip_params_t gnrc_slip_params[] = { static slipdev_params_t slipdev_params[] = {
{ {
.uart = SLIP_UART, .uart = SLIP_UART,
.baudrate = SLIP_BAUDRATE, .baudrate = SLIP_BAUDRATE,
@ -35,5 +35,5 @@ static gnrc_slip_params_t gnrc_slip_params[] = {
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* SLIP_PARAMS_H */ #endif /* SLIPDEV_PARAMS_H */
/** @} */ /** @} */

View File

@ -47,7 +47,7 @@ endif
#CFLAGS += -DSLIP_UART=$(SLIP_UART) #CFLAGS += -DSLIP_UART=$(SLIP_UART)
#CFLAGS += -DSLIP_BAUDRATE=$(SLIP_BAUDRATE) #CFLAGS += -DSLIP_BAUDRATE=$(SLIP_BAUDRATE)
# Include SLIP package for IP over Serial communication # Include SLIP package for IP over Serial communication
#USEMODULE += gnrc_slip #USEMODULE += slipdev
# Include packages that pull up and auto-init the link layer. # Include packages that pull up and auto-init the link layer.
# NOTE: 6LoWPAN will be included if IEEE802.15.4 devices are present # NOTE: 6LoWPAN will be included if IEEE802.15.4 devices are present

View File

@ -210,7 +210,7 @@ INCLUDES += -I$(CURDIR)
CFLAGS += -DSLIP_UART=$(SLIP_UART) CFLAGS += -DSLIP_UART=$(SLIP_UART)
CFLAGS += -DSLIP_BAUDRATE=$(SLIP_BAUDRATE) CFLAGS += -DSLIP_BAUDRATE=$(SLIP_BAUDRATE)
# Include SLIP package for IP over Serial communication # Include SLIP package for IP over Serial communication
USEMODULE += gnrc_slip USEMODULE += slipdev
``` ```

View File

@ -200,9 +200,9 @@ void auto_init(void)
auto_init_ethos(); auto_init_ethos();
#endif #endif
#ifdef MODULE_GNRC_SLIP #ifdef MODULE_SLIPDEV
extern void auto_init_slip(void); extern void auto_init_slipdev(void);
auto_init_slip(); auto_init_slipdev();
#endif #endif
#ifdef MODULE_CC110X #ifdef MODULE_CC110X

View File

@ -1,68 +0,0 @@
/*
* Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
*
* 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
* directory for more details.
*
*/
/**
* @ingroup auto_init_gnrc_netif
* @{
*
* @file
* @brief Auto initialization for XBee network interfaces
*
* @author Kaspar Schleiser <kaspar@schleiser.de>
*/
#ifdef MODULE_GNRC_SLIP
#include "log.h"
#include "board.h"
#include "net/gnrc/netdev.h"
#include "net/gnrc.h"
#include "net/gnrc/slip.h"
#include "slip_params.h"
#define SLIP_NUM (sizeof(gnrc_slip_params)/sizeof(gnrc_slip_params_t))
static gnrc_slip_dev_t slip_devs[SLIP_NUM];
/**
* @brief Define stack parameters for the MAC layer thread
* @{
*/
#define SLIP_STACKSIZE (THREAD_STACKSIZE_DEFAULT)
#ifndef SLIP_PRIO
#define SLIP_PRIO (GNRC_NETDEV_MAC_PRIO)
#endif
/**
* @brief Stacks for the MAC layer threads
*/
static char _slip_stacks[SLIP_NUM][SLIP_STACKSIZE];
void auto_init_slip(void)
{
for (unsigned i = 0; i < SLIP_NUM; i++) {
const gnrc_slip_params_t *p = &gnrc_slip_params[i];
LOG_DEBUG("[auto_init_netif] initializing slip #%u\n", i);
kernel_pid_t res = gnrc_slip_init(&slip_devs[i], p->uart, p->baudrate,
_slip_stacks[i], SLIP_STACKSIZE,
SLIP_PRIO);
if (res <= KERNEL_PID_UNDEF) {
LOG_ERROR("[auto_init_netif] error initializing slip #%u\n", i);
}
}
}
#else
typedef int dont_be_pedantic;
#endif /* MODULE_GNRC_SLIP */
/** @} */

View File

@ -0,0 +1,69 @@
/*
* Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
*
* 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
* directory for more details.
*
*/
/**
* @ingroup auto_init_gnrc_netif
* @{
*
* @file
* @brief Auto initialization for XBee network interfaces
*
* @author Kaspar Schleiser <kaspar@schleiser.de>
*/
#ifdef MODULE_SLIPDEV
#include "log.h"
#include "board.h"
#include "net/gnrc/netdev.h"
#include "net/gnrc/netdev/raw.h"
#include "net/gnrc.h"
#include "slipdev.h"
#include "slipdev_params.h"
#define SLIPDEV_NUM (sizeof(slipdev_params)/sizeof(slipdev_params_t))
/**
* @brief Define stack parameters for the MAC layer thread
* @{
*/
#define SLIPDEV_STACKSIZE (THREAD_STACKSIZE_DEFAULT)
#ifndef SLIPDEV_PRIO
#define SLIPDEV_PRIO (GNRC_NETDEV_MAC_PRIO)
#endif
static slipdev_t slipdevs[SLIPDEV_NUM];
static gnrc_netdev_t gnrc_adpt[SLIPDEV_NUM];
static char _slipdev_stacks[SLIPDEV_NUM][SLIPDEV_STACKSIZE];
void auto_init_slipdev(void)
{
for (unsigned i = 0; i < SLIPDEV_NUM; i++) {
const slipdev_params_t *p = &slipdev_params[i];
LOG_DEBUG("[auto_init_netif] initializing slip #%u\n", i);
slipdev_setup(&slipdevs[i], p);
kernel_pid_t res = gnrc_netdev_raw_init(&gnrc_adpt[i],
(netdev_t *)&slipdevs[i]);
if (res < 0) {
LOG_ERROR("[auto_init_netif] error initializing slipdev #%u\n", i);
}
else {
gnrc_netdev_init(_slipdev_stacks[i], SLIPDEV_STACKSIZE,
SLIPDEV_PRIO, "slipdev", &gnrc_adpt[i]);
}
}
}
#else
typedef int dont_be_pedantic;
#endif /* MODULE_SLIPDEV */
/** @} */

View File

@ -0,0 +1,43 @@
/*
* Copyright (C) 2017 Freie Universität Berlin
*
* 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
* directory for more details.
*/
/**
* @ingroup net_gnrc_netdev
* @{
*
* @file
* @brief netdev gnrc raw (i.e. pure L3) glue code interface
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/
#ifndef NET_GNRC_NETDEV_RAW_H
#define NET_GNRC_NETDEV_RAW_H
#include "net/gnrc/netdev.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Initialize gnrc handler for netdev raw L3 devices
*
* @param[in] gnrc_netdev gnrc_netdev struct to initialize
* @param[in] dev network device to handle
*
* @return 1 on success
* @return <=0 on error
*/
int gnrc_netdev_raw_init(gnrc_netdev_t *gnrc_netdev, netdev_t *dev);
#ifdef __cplusplus
}
#endif
#endif /* NET_GNRC_NETDEV_RAW_H */
/** @} */

View File

@ -1,92 +0,0 @@
/*
* Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.de>
*
* 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
* directory for more details.
*/
/**
* @defgroup net_gnrc_slip SLIP
* @ingroup net_gnrc
* @brief Provides a SLIP interface over UART utilizing
* @ref drivers_periph_uart.
* @see <a href="https://www.ietf.org/rfc/rfc1055">RFC 1055</a>
* @{
*
* @file
* @brief SLIP interface defintion
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*/
#ifndef NET_GNRC_SLIP_H
#define NET_GNRC_SLIP_H
#include <inttypes.h>
#include "net/gnrc.h"
#include "periph/uart.h"
#include "ringbuffer.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @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
*/
#ifndef GNRC_SLIP_BUFSIZE
#define GNRC_SLIP_BUFSIZE (1500U)
#endif
/**
* @brief Device descriptor for SLIP devices
*/
typedef struct {
uart_t uart; /**< the UART interface */
ringbuffer_t in_buf; /**< RX buffer */
ringbuffer_t out_buf; /**< TX buffer */
char rx_mem[GNRC_SLIP_BUFSIZE]; /**< memory used by RX buffer */
uint32_t in_bytes; /**< the number of bytes received of a
* currently incoming packet */
uint16_t in_esc; /**< receiver is in escape mode */
kernel_pid_t slip_pid; /**< PID of the device thread */
} gnrc_slip_dev_t;
/**
* @brief auto_init struct holding SLIP initalization params
*/
typedef struct xbee_params {
uart_t uart; /**< UART interfaced the device is connected to */
uint32_t baudrate; /**< baudrate to use */
} gnrc_slip_params_t;
/**
* @brief Initializes a new @ref net_gnrc_slip control thread for UART device
* @p uart
*
* @param[in] dev un-initialized SLIP device descriptor
* @param[in] uart UART device to use
* @param[in] baudrate baudrate to use
* @param[in] stack stack memory to use for the SLIP devices thread
* @param[in] stack_size size of @p stack
* @param[in] priority priority for the newly created thread
*
* @return PID of SLIP thread on success
* @return -EFAULT, if slip thread could not be created
* @return -ENODEV, if gnrc_slip_dev_t::uart of @p dev was no valid UART
*/
kernel_pid_t gnrc_slip_init(gnrc_slip_dev_t *dev, uart_t uart, uint32_t baudrate,
char *stack, size_t stack_size, char priority);
#ifdef __cplusplus
}
#endif
#endif /* NET_GNRC_SLIP_H */
/** @} */

View File

@ -118,9 +118,6 @@ endif
ifneq (,$(filter gnrc_sixlowpan_netif,$(USEMODULE))) ifneq (,$(filter gnrc_sixlowpan_netif,$(USEMODULE)))
DIRS += network_layer/sixlowpan/netif DIRS += network_layer/sixlowpan/netif
endif endif
ifneq (,$(filter gnrc_slip,$(USEMODULE)))
DIRS += link_layer/slip
endif
ifneq (,$(filter gnrc_sock,$(USEMODULE))) ifneq (,$(filter gnrc_sock,$(USEMODULE)))
DIRS += sock DIRS += sock
endif endif

View File

@ -0,0 +1,99 @@
/*
* Copyright (C) 2017 Freie Universität Berlin
*
* 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
* directory for more details.
*/
/**
* @{
*
* @file
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/
#include "net/gnrc/netdev/raw.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#define IP_VERSION_MASK (0xf0)
#define IP_VERSION4 (0x40)
#define IP_VERSION6 (0x60)
static gnrc_pktsnip_t *_recv(gnrc_netdev_t *gnrc_netdev)
{
netdev_t *dev = gnrc_netdev->dev;
int bytes_expected = dev->driver->recv(dev, NULL, 0, NULL);
gnrc_pktsnip_t *pkt = NULL;
if (bytes_expected > 0) {
int nread;
pkt = gnrc_pktbuf_add(NULL, NULL, bytes_expected, GNRC_NETTYPE_UNDEF);
if (!pkt) {
DEBUG("gnrc_netdev_raw: cannot allocate pktsnip.\n");
/* drop packet */
dev->driver->recv(dev, NULL, bytes_expected, NULL);
return pkt;
}
nread = dev->driver->recv(dev, pkt->data, bytes_expected, NULL);
if (nread <= 0) {
DEBUG("gnrc_netdev_raw: read error.\n");
gnrc_pktbuf_release(pkt);
return NULL;
}
if (nread < bytes_expected) {
/* we've got less then the expected packet size,
* so free the unused space.*/
DEBUG("gnrc_netdev_raw: reallocating.\n");
gnrc_pktbuf_realloc_data(pkt, nread);
}
switch (((uint8_t *)pkt->data)[0] & IP_VERSION_MASK) {
#ifdef MODULE_GNRC_IPV6
case IP_VERSION6:
pkt->type = GNRC_NETTYPE_IPV6;
break;
#endif
default:
/* leave UNDEF */
break;
}
}
return pkt;
}
static int _send(gnrc_netdev_t *gnrc_netdev, gnrc_pktsnip_t *pkt)
{
gnrc_pktsnip_t *vector;
int res = -ENOBUFS;
size_t n;
if (pkt->type == GNRC_NETTYPE_NETIF) {
/* we don't need the netif snip: remove it */
pkt = gnrc_pktbuf_remove_snip(pkt, pkt);
}
vector = gnrc_pktbuf_get_iovec(pkt, &n);
if (vector != NULL) {
struct iovec *v = (struct iovec *)vector->data;
netdev_t *dev = gnrc_netdev->dev;
#ifdef MODULE_NETSTATS_L2
gnrc_netdev->dev->stats.tx_unicast_count++;
#endif
res = dev->driver->send(dev, v, n);
}
return res;
}
int gnrc_netdev_raw_init(gnrc_netdev_t *gnrc_netdev, netdev_t *dev)
{
gnrc_netdev->send = _send;
gnrc_netdev->recv = _recv;
gnrc_netdev->dev = dev;
return 0;
}
/** @} */

View File

@ -1,277 +0,0 @@
/*
* Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.de>
*
* 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
* directory for more details.
*/
/**
* @ingroup net_gnrc_slip
* @{
*
* @file
* @brief SLIP device implementation
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*
* @}
*/
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "kernel_types.h"
#include "msg.h"
#include "net/gnrc.h"
#include "periph/uart.h"
#include "od.h"
#include "ringbuffer.h"
#include "thread.h"
#include "net/ipv6/hdr.h"
#include "net/gnrc/slip.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#define _SLIP_END ('\xc0')
#define _SLIP_ESC ('\xdb')
#define _SLIP_END_ESC ('\xdc')
#define _SLIP_ESC_ESC ('\xdd')
#define _SLIP_MSG_TYPE (0xc1dc) /* chosen randomly */
#define _SLIP_NAME "SLIP"
#define _SLIP_MSG_QUEUE_SIZE (8U)
#define _SLIP_DEV(arg) ((gnrc_slip_dev_t *)arg)
/* UART callbacks */
static void _slip_rx_cb(void *arg, uint8_t data)
{
if (data == (uint8_t)_SLIP_END) {
msg_t msg;
msg.type = _SLIP_MSG_TYPE;
msg.content.value = _SLIP_DEV(arg)->in_bytes;
msg_send_int(&msg, _SLIP_DEV(arg)->slip_pid);
_SLIP_DEV(arg)->in_bytes = 0;
}
else if (_SLIP_DEV(arg)->in_esc) {
_SLIP_DEV(arg)->in_esc = 0;
switch (data) {
case ((uint8_t)_SLIP_END_ESC):
if (ringbuffer_add_one(&_SLIP_DEV(arg)->in_buf, _SLIP_END) < 0) {
_SLIP_DEV(arg)->in_bytes++;
}
break;
case ((uint8_t)_SLIP_ESC_ESC):
if (ringbuffer_add_one(&_SLIP_DEV(arg)->in_buf, _SLIP_ESC) < 0) {
_SLIP_DEV(arg)->in_bytes++;
}
break;
default:
break;
}
}
else if (data == (uint8_t)_SLIP_ESC) {
_SLIP_DEV(arg)->in_esc = 1;
}
else {
if (ringbuffer_add_one(&_SLIP_DEV(arg)->in_buf, data) < 0) {
_SLIP_DEV(arg)->in_bytes++;
}
}
}
/* SLIP receive handler */
static void _slip_receive(gnrc_slip_dev_t *dev, size_t bytes)
{
gnrc_pktsnip_t *pkt, *hdr;
hdr = gnrc_netif_hdr_build(NULL, 0, NULL, 0);
if (hdr == NULL) {
DEBUG("slip: no space left in packet buffer\n");
return;
}
((gnrc_netif_hdr_t *)(hdr->data))->if_pid = thread_getpid();
pkt = gnrc_pktbuf_add(hdr, NULL, bytes, GNRC_NETTYPE_UNDEF);
if (pkt == NULL) {
DEBUG("slip: no space left in packet buffer\n");
gnrc_pktbuf_release(hdr);
return;
}
if (ringbuffer_get(&dev->in_buf, pkt->data, bytes) != bytes) {
DEBUG("slip: could not read %u bytes from ringbuffer\n", (unsigned)bytes);
gnrc_pktbuf_release(pkt);
return;
}
#if ENABLE_DEBUG && defined(MODULE_OD)
else {
DEBUG("slip: received data\n");
od_hex_dump(pkt->data, bytes, OD_WIDTH_DEFAULT);
}
#endif
#ifdef MODULE_GNRC_IPV6
if ((pkt->size >= sizeof(ipv6_hdr_t)) && ipv6_hdr_is(pkt->data)) {
pkt->type = GNRC_NETTYPE_IPV6;
}
#endif
if (gnrc_netapi_dispatch_receive(pkt->type, GNRC_NETREG_DEMUX_CTX_ALL, pkt) == 0) {
DEBUG("slip: unable to forward packet of type %i\n", pkt->type);
gnrc_pktbuf_release(pkt);
}
}
static inline void _slip_send_char(gnrc_slip_dev_t *dev, char c)
{
uart_write(dev->uart, (uint8_t *)&c, 1);
}
/* SLIP send handler */
static void _slip_send(gnrc_slip_dev_t *dev, gnrc_pktsnip_t *pkt)
{
gnrc_pktsnip_t *ptr;
ptr = pkt->next; /* ignore gnrc_netif_hdr_t, we don't need it */
while (ptr != NULL) {
DEBUG("slip: send pktsnip of length %u over UART_%d\n", (unsigned)ptr->size, dev->uart);
char *data = ptr->data;
for (size_t i = 0; i < ptr->size; i++) {
switch (data[i]) {
case _SLIP_END:
DEBUG("slip: encountered END byte on send: stuff with ESC\n");
_slip_send_char(dev, _SLIP_ESC);
_slip_send_char(dev, _SLIP_END_ESC);
break;
case _SLIP_ESC:
DEBUG("slip: encountered ESC byte on send: stuff with ESC\n");
_slip_send_char(dev, _SLIP_ESC);
_slip_send_char(dev, _SLIP_ESC_ESC);
break;
default:
_slip_send_char(dev, data[i]);
break;
}
}
ptr = ptr->next;
}
_slip_send_char(dev, _SLIP_END);
gnrc_pktbuf_release(pkt);
}
static inline int _slip_get(gnrc_netapi_opt_t *opt)
{
switch (opt->opt) {
case NETOPT_IS_WIRED:
return 1;
default:
return -ENOTSUP;
}
}
static void *_slip(void *args)
{
gnrc_slip_dev_t *dev = _SLIP_DEV(args);
msg_t msg, reply, msg_q[_SLIP_MSG_QUEUE_SIZE];
msg_init_queue(msg_q, _SLIP_MSG_QUEUE_SIZE);
dev->slip_pid = thread_getpid();
gnrc_netif_add(dev->slip_pid);
DEBUG("slip: SLIP runs on UART_%d\n", dev->uart);
while (1) {
DEBUG("slip: waiting for incoming messages\n");
msg_receive(&msg);
switch (msg.type) {
case _SLIP_MSG_TYPE:
DEBUG("slip: incoming message of size %" PRIu32 " from UART_%d in buffer\n",
msg.content.value, dev->uart);
_slip_receive(dev, (size_t)msg.content.value);
break;
case GNRC_NETAPI_MSG_TYPE_SND:
DEBUG("slip: GNRC_NETAPI_MSG_TYPE_SND received\n");
_slip_send(dev, msg.content.ptr);
break;
case GNRC_NETAPI_MSG_TYPE_GET:
DEBUG("slip: GNRC_NETAPI_MSG_TYPE_GET received\n");
reply.type = GNRC_NETAPI_MSG_TYPE_ACK;
reply.content.value = (uint32_t)_slip_get(msg.content.ptr);
msg_reply(&msg, &reply);
break;
case GNRC_NETAPI_MSG_TYPE_SET:
DEBUG("slip: GNRC_NETAPI_MSG_TYPE_SET received\n");
reply.type = GNRC_NETAPI_MSG_TYPE_ACK;
reply.content.value = (uint32_t)(-ENOTSUP);
DEBUG("slip: I don't support this but have to reply.\n");
msg_reply(&msg, &reply);
break;
}
}
/* should be never reached */
return NULL;
}
kernel_pid_t gnrc_slip_init(gnrc_slip_dev_t *dev, uart_t uart, uint32_t baudrate,
char *stack, size_t stack_size, char priority)
{
kernel_pid_t pid;
/* reset device descriptor fields */
dev->uart = uart;
dev->in_bytes = 0;
dev->in_esc = 0;
dev->slip_pid = KERNEL_PID_UNDEF;
/* initialize buffers */
ringbuffer_init(&dev->in_buf, dev->rx_mem, sizeof(dev->rx_mem));
/* initialize UART */
DEBUG("slip: initialize UART_%d with baudrate %" PRIu32 "\n", uart,
baudrate);
if (uart_init(uart, baudrate, _slip_rx_cb, dev) != UART_OK) {
DEBUG("slip: error initializing UART_%i with baudrate %" PRIu32 "\n",
uart, baudrate);
return -ENODEV;
}
/* start SLIP thread */
DEBUG("slip: starting SLIP thread\n");
pid = thread_create(stack, stack_size, priority, THREAD_CREATE_STACKTEST,
_slip, dev, _SLIP_NAME);
if (pid < 0) {
DEBUG("slip: unable to create SLIP thread\n");
return -EFAULT;
}
return pid;
}

View File

@ -10,7 +10,9 @@ BOARD_BLACKLIST += mips-malta
USEMODULE += auto_init_gnrc_netif USEMODULE += auto_init_gnrc_netif
USEMODULE += gnrc USEMODULE += gnrc
USEMODULE += gnrc_pktdump USEMODULE += gnrc_pktdump
USEMODULE += gnrc_slip USEMODULE += gnrc_netdev
USEMODULE += gnrc_txtsnd
USEMODULE += slipdev
USEMODULE += shell USEMODULE += shell
USEMODULE += shell_commands USEMODULE += shell_commands

View File

@ -16,16 +16,16 @@
* @author Martine Lenders <mlenders@inf.fu-berlin.de> * @author Martine Lenders <mlenders@inf.fu-berlin.de>
*/ */
#ifndef SLIP_PARAMS_H #ifndef SLIPDEV_PARAMS_H
#define SLIP_PARAMS_H #define SLIPDEV_PARAMS_H
#include "net/gnrc/slip.h" #include "slipdev.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
static gnrc_slip_params_t gnrc_slip_params[] = { static slipdev_params_t slipdev_params[] = {
{ {
.uart = SLIP_UART, .uart = SLIP_UART,
.baudrate = SLIP_BAUDRATE, .baudrate = SLIP_BAUDRATE,
@ -35,5 +35,5 @@ static gnrc_slip_params_t gnrc_slip_params[] = {
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* SLIP_PARAMS_H */ #endif /* SLIPDEV_PARAMS_H */
/** @} */ /** @} */