diff --git a/Makefile.dep b/Makefile.dep index 2eb99d5a6996611080d66c6f890a32a81356539b..143d9c6caf7efcf39451356d7acb1150cdf63a38 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -180,6 +180,10 @@ ifneq (,$(filter ng_pktdump,$(USEMODULE))) USEMODULE += od endif +ifneq (,$(filter ng_slip,$(USEMODULE))) + USEMODULE += ng_netbase +endif + ifneq (,$(filter aodvv2,$(USEMODULE))) USEMODULE += vtimer USEMODULE += sixlowpan diff --git a/sys/Makefile b/sys/Makefile index 567fca59a130943e3b3037b22417240b63aa1f58..71fdea57aee6b6a025cecb862e65592a4a3a80d8 100644 --- a/sys/Makefile +++ b/sys/Makefile @@ -119,6 +119,9 @@ endif ifneq (,$(filter ng_sixlowpan_netif,$(USEMODULE))) DIRS += net/network_layer/ng_sixlowpan/netif endif +ifneq (,$(filter ng_slip,$(USEMODULE))) + DIRS += net/link_layer/ng_slip +endif ifneq (,$(filter netapi,$(USEMODULE))) DIRS += net/crosslayer/netapi endif diff --git a/sys/Makefile.include b/sys/Makefile.include index 0eb54fa292d0773b024e1837ee0d7965b43ac2dc..c491b9851fb7c9e3ae19ae8253fcad6426c99d90 100644 --- a/sys/Makefile.include +++ b/sys/Makefile.include @@ -82,6 +82,10 @@ ifneq (,$(filter cpp11-compat,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/sys/cpp11-compat/include endif +ifneq (,$(filter ng_slip,$(USEMODULE))) + FEATURES_REQUIRED += periph_uart +endif + ifneq (,$(filter embunit,$(USEMODULE))) ifeq ($(OUTPUT),XML) CFLAGS += -DOUTPUT=OUTPUT_XML diff --git a/sys/include/net/ng_slip.h b/sys/include/net/ng_slip.h new file mode 100644 index 0000000000000000000000000000000000000000..b3c5cb82a84e633214fde22f1fdda7766e28d648 --- /dev/null +++ b/sys/include/net/ng_slip.h @@ -0,0 +1,85 @@ +/* + * 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_ng_slip SLIP + * @ingroup net + * @brief Provides a SLIP interface over UART utilizing + * @ref driver_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 NG_SLIP_H_ +#define NG_SLIP_H_ + +#include <inttypes.h> + +#include "net/ng_netbase.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 NG_SLIP_BUFSIZE +#define NG_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[NG_SLIP_BUFSIZE]; /**< memory used by RX buffer */ + char tx_mem[NG_SLIP_BUFSIZE]; /**< memory used by TX 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 */ +} ng_slip_dev_t; + +/** + * @brief Initializes a new @ref net_ng_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 ng_slip_dev_t::uart of @p dev was no valid UART + */ +kernel_pid_t ng_slip_init(ng_slip_dev_t *dev, uart_t uart, uint32_t baudrate, + char *stack, size_t stack_size, char priority); + +#ifdef __cplusplus +} +#endif + +#endif /* __SLIP_H_ */ +/** @} */ diff --git a/sys/net/link_layer/ng_slip/Makefile b/sys/net/link_layer/ng_slip/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..48422e909a47d7cd428d10fa73825060ccc8d8c2 --- /dev/null +++ b/sys/net/link_layer/ng_slip/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/sys/net/link_layer/ng_slip/ng_slip.c b/sys/net/link_layer/ng_slip/ng_slip.c new file mode 100644 index 0000000000000000000000000000000000000000..61f95ef0be1d4d2842cf3d8dd5b5131227716e40 --- /dev/null +++ b/sys/net/link_layer/ng_slip/ng_slip.c @@ -0,0 +1,284 @@ +/* + * 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_ng_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.h" +#include "kernel_types.h" +#include "msg.h" +#include "net/ng_netbase.h" +#include "periph/uart.h" +#include "ringbuffer.h" +#include "thread.h" +#include "net/ng_ipv6/hdr.h" + +#include "net/ng_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) ((ng_slip_dev_t *)arg) + +/* UART callbacks */ +static void _slip_rx_cb(void *arg, char data) +{ + if (data == _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; + } + + if (_SLIP_DEV(arg)->in_esc) { + _SLIP_DEV(arg)->in_esc = 0; + + switch (data) { + case (_SLIP_END_ESC): + if (ringbuffer_add_one(_SLIP_DEV(arg)->in_buf, _SLIP_END) < 0) { + _SLIP_DEV(arg)->in_bytes++; + } + + break; + + case (_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 == _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++; + } + } +} + +int _slip_tx_cb(void *arg) +{ + if (_SLIP_DEV(arg)->out_buf->avail > 0) { + char c = (char)ringbuffer_get_one(_SLIP_DEV(arg)->out_buf); + uart_write((uart_t)(_SLIP_DEV(arg)->uart), c); + return 1; + } + + return 0; +} + +/* SLIP receive handler */ +static void _slip_receive(ng_slip_dev_t *dev, size_t bytes) +{ + ng_netif_hdr_t *hdr; + ng_netreg_entry_t *sendto; + ng_pktsnip_t *pkt, *netif_hdr; + + pkt = ng_pktbuf_add(NULL, NULL, bytes, NG_NETTYPE_UNDEF); + + if (pkt == NULL) { + DEBUG("slip: no space left in packet buffer\n"); + return; + } + + netif_hdr = ng_pktbuf_add(pkt, NULL, sizeof(ng_netif_hdr_t), + NG_NETTYPE_NETIF); + + if (netif_hdr == NULL) { + DEBUG("slip: no space left in packet buffer\n"); + ng_pktbuf_release(pkt); + return; + } + + hdr = netif_hdr->data; + ng_netif_hdr_init(hdr, 0, 0); + hdr->if_pid = thread_getpid(); + + if (ringbuffer_get(dev->in_buf, pkt->data, bytes) != bytes) { + DEBUG("slip: could not read %zu bytes from ringbuffer\n", bytes); + ng_pktbuf_release(pkt); + return; + } + +#ifdef MODULE_NG_IPV6 + if ((pkt->size >= sizeof(ng_ipv6_hdr_t)) && ng_ipv6_hdr_is_ipv6_hdr(pkt->data)) { + pkt->type = NG_NETTYPE_IPV6; + } +#endif + + sendto = ng_netreg_lookup(pkt->type, NG_NETREG_DEMUX_CTX_ALL); + + if (sendto == NULL) { + DEBUG("slip: unable to forward packet of type %i\n", pkt->type); + ng_pktbuf_release(pkt); + } + + ng_pktbuf_hold(pkt, ng_netreg_num(pkt->type, NG_NETREG_DEMUX_CTX_ALL) - 1); + + while (sendto != NULL) { + DEBUG("slip: sending pkt %p to PID %u\n", pkt, sendto->pid); + ng_netapi_receive(sendto->pid, pkt); + sendto = ng_netreg_getnext(sendto); + } +} + +static inline void _slip_send_char(ng_slip_dev_t *dev, char c) +{ + ringbuffer_add_one(dev->out_buf, c); + uart_tx_begin(dev->uart); +} + +/* SLIP send handler */ +static void _slip_send(ng_slip_dev_t *dev, ng_pktsnip_t *pkt) +{ + ng_pktsnip_t *ptr; + + ptr = pkt->next; /* ignore ng_netif_hdr_t, we don't need it */ + + while (ptr != NULL) { + DEBUG("slip: send pktsnip of length %zu over UART_%d\n", ptr->size, 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); + + ng_pktbuf_release(pkt); +} + +static void *_slip(void *args) +{ + ng_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(); + ng_netif_add(dev->slip_pid); + + DEBUG("slip: SLIP runs on UART_%d\n", uart); + + while (1) { + DEBUG("slip: waiting for incoming messages\n"); + msg_receive(&msg); + + switch (msg.type) { + case _SLIP_MSG_TYPE: + DEBUG("slip: incoming message from UART in buffer\n"); + _slip_receive(dev, (size_t)msg.content.value); + break; + + case NG_NETAPI_MSG_TYPE_SND: + DEBUG("slip: NG_NETAPI_MSG_TYPE_SND received\n"); + _slip_send(dev, (ng_pktsnip_t *)msg.content.ptr); + break; + + case NG_NETAPI_MSG_TYPE_GET: + case NG_NETAPI_MSG_TYPE_SET: + DEBUG("slip: NG_NETAPI_MSG_TYPE_GET or NG_NETAPI_MSG_TYPE_SET received\n"); + reply.type = NG_NETAPI_MSG_TYPE_ACK; + reply.content.value = (uint32_t)(-ENOTSUP); + DEBUG("slip: I don't support these but have to reply.\n"); + msg_reply(&msg, &reply); + break; + } + } + + /* should be never reached */ + return NULL; +} + +kernel_pid_t ng_slip_init(ng_slip_dev_t *dev, uart_t uart, uint32_t baudrate, + char *stack, size_t stack_size, char priority) +{ + int res; + kernel_pid_t pid; + + /* reset device descriptor fields */ + 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)); + ringbuffer_init(dev->out_buf, dev->tx_mem, sizeof(dev->tx_mem)); + + /* initialize UART */ + DEBUG("slip: initialize UART_%d\n", uart); + res = uart_init(uart, baudrate, _slip_rx_cb, _slip_tx_cb, dev); + if (res < 0) { + DEBUG("slip: error initializing UART_%i with baudrate %u\n", + uart, baudrate); + return -ENODEV; + } + + /* start SLIP thread */ + DEBUG("slip: starting SLIP thread\n"); + pid = thread_create(stack, stack_size, priority, CREATE_STACKTEST, + _slip, dev, _SLIP_NAME); + if (pid < 0) { + DEBUG("slip: unable to create SLIP thread\n"); + return -EFAULT; + } + return res; +}