
6 changed files with 381 additions and 0 deletions
@ -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_ */ |
||||
/** @} */ |
@ -0,0 +1 @@
|
||||
include $(RIOTBASE)/Makefile.base |
@ -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; |
||||
} |
Loading…
Reference in new issue