Skip to content

Commit 166ffcb

Browse files
committed
driver/slip: Add slipmux frames
1 parent 734c570 commit 166ffcb

File tree

7 files changed

+207
-21
lines changed

7 files changed

+207
-21
lines changed

drivers/include/slipdev.h

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
* @defgroup drivers_slipdev_stdio STDIO via SLIP
1313
* @ingroup sys_stdio
1414
* @brief Standard input/output backend multiplexed via SLIP
15+
* @see [draft-bormann-t2trg-slipmux-03](https://datatracker.ietf.org/doc/html/draft-bormann-t2trg-slipmux-03)
16+
*
17+
* This extension is part of the [Slipmux draft](https://datatracker.ietf.org/doc/html/draft-bormann-t2trg-slipmux-03).
18+
* @warning This module is under development for optimizations and module names might change!
1519
*
1620
* This will multiplex STDIO via the Serial Line Internet Protocol.
1721
* The shell can be accessed via the `sliptty` tool.
@@ -23,11 +27,32 @@
2327
* @see drivers_slipdev
2428
*/
2529

30+
/**
31+
* @defgroup drivers_slipdev_configuration CoAP via SLIP
32+
* @ingroup drivers_slipdev
33+
* @brief Exchange CoAP requests and responses via SLIP
34+
* @see [draft-bormann-t2trg-slipmux-03](https://datatracker.ietf.org/doc/html/draft-bormann-t2trg-slipmux-03)
35+
*
36+
* This extension is part of the [Slipmux draft](https://datatracker.ietf.org/doc/html/draft-bormann-t2trg-slipmux-03).
37+
* @warning This module is under development for optimizations and module names might change!
38+
*
39+
* This will multiplex CoAP messages via the Serial Line Internet Protocol.
40+
* It spawns an extra thread as a CoAP server. The incoming requests are handled with `nanocoap`
41+
* according to any `NANOCOAP_RESOURCE`s present in the binary. See @ref net_nanocoap for more.
42+
*
43+
* To enable this implementation, select
44+
*
45+
* USEMODULE += slipdev_config
46+
*
47+
* @see drivers_slipdev
48+
*/
49+
2650
/**
2751
* @defgroup drivers_slipdev SLIP network device
2852
* @ingroup drivers_netdev
2953
* @brief SLIP network device over @ref drivers_periph_uart
30-
* @see [RFC 1055](https://github.com/RIOT-OS/RIOT/pull/6487)
54+
* @see [RFC 1055](https://datatracker.ietf.org/doc/html/rfc1055)
55+
*
3156
* @{
3257
*
3358
* @file
@@ -42,6 +67,7 @@
4267
#include "net/netdev.h"
4368
#include "periph/uart.h"
4469
#include "chunked_ringbuffer.h"
70+
#include "sched.h"
4571

4672
#ifdef __cplusplus
4773
extern "C" {
@@ -93,6 +119,14 @@ enum {
93119
* @brief Device writes received data to stdin, next byte is escaped
94120
*/
95121
SLIPDEV_STATE_STDIN_ESC,
122+
/**
123+
* @brief Device writes received data as CoAP message
124+
*/
125+
SLIPDEV_STATE_CONFIG,
126+
/**
127+
* @brief Device writes received data as CoAP message, next byte is escaped
128+
*/
129+
SLIPDEV_STATE_CONFIG_ESC,
96130
/**
97131
* @brief Device is in standby, will wake up when sending data
98132
*/
@@ -120,13 +154,19 @@ typedef struct {
120154
typedef struct {
121155
netdev_t netdev; /**< parent class */
122156
slipdev_params_t config; /**< configuration parameters */
123-
chunk_ringbuf_t rb; /**< Ringbuffer to store received frames. */
157+
chunk_ringbuf_t rb; /**< Ringbuffer to store received networking frames.*/
124158
/* Written to from interrupts (with irq_disable */
125159
/* to prevent any simultaneous writes), */
126160
/* consumed exclusively in the network stack's */
127161
/* loop at _isr. */
128162

129163
uint8_t rxmem[CONFIG_SLIPDEV_BUFSIZE]; /**< memory used by RX buffer */
164+
165+
#if IS_USED(MODULE_SLIPDEV_CONFIG)
166+
chunk_ringbuf_t rb_config; /**< Ringbuffer stores received configuration frames */
167+
uint8_t rxmem_config[CONFIG_SLIPDEV_BUFSIZE]; /**< memory used by RX buffer */
168+
kernel_pid_t coap_server_pid; /**< The PID of the CoAP server */
169+
#endif
130170
/**
131171
* @brief Device state
132172
* @see [Device state definitions](@ref drivers_slipdev_states)

drivers/slipdev/Makefile.dep

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,10 @@ FEATURES_REQUIRED += periph_uart
77
ifneq (,$(filter slipdev_stdio,$(USEMODULE)))
88
USEMODULE += isrpipe
99
endif
10+
ifneq (,$(filter slipdev_config,$(USEMODULE)))
11+
USEMODULE += checksum
12+
USEMODULE += sock_udp
13+
USEMODULE += gnrc_ipv6
14+
USEMODULE += nanocoap_sock
15+
USEMODULE += nanocoap_resources
16+
endif

drivers/slipdev/include/slipdev_internal.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,16 @@ extern "C" {
4343
/**
4444
* @brief Marker byte for beginning of stdio
4545
* @see taken from diagnostic transfer from
46-
* [SLIPMUX](https://tools.ietf.org/html/draft-bormann-t2trg-slipmux-02#section-4)
46+
* [SLIPMUX](https://tools.ietf.org/html/draft-bormann-t2trg-slipmux-03#section-4)
4747
*/
4848
#define SLIPDEV_STDIO_START (0x0aU)
49+
50+
/**
51+
* @brief Marker byte for beginning of configuration/CoAP
52+
* @see taken from configuration from
53+
* [SLIPMUX](https://tools.ietf.org/html/draft-bormann-t2trg-slipmux-03#section-5)
54+
*/
55+
#define SLIPDEV_CONFIG_START (0xa9U)
4956
/** @} */
5057

5158
/**

drivers/slipdev/slipdev.c

Lines changed: 146 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
* @file
1313
* @author Martine Lenders <[email protected]>
1414
* @author Benjamin Valentin <[email protected]>
15+
* @author Bennet Hattesen <[email protected]>
1516
*/
1617

1718
#include <assert.h>
@@ -31,20 +32,37 @@
3132

3233
#include "isrpipe.h"
3334
#include "mutex.h"
35+
#if IS_USED(MODULE_SLIPDEV_CONFIG)
36+
#include "checksum/crc16_ccitt.h"
37+
#include "net/nanocoap.h"
38+
#endif
3439
#include "stdio_uart.h"
3540

41+
#if (IS_USED(MODULE_SLIPDEV_STDIO) || IS_USED(MODULE_SLIPDEV_CONFIG))
42+
/* For synchronization with stdio/config threads */
43+
mutex_t slipdev_mutex = MUTEX_INIT;
44+
#endif
45+
46+
#if IS_USED(MODULE_SLIPDEV_CONFIG)
47+
/* The special init is the result of normal fcs init combined with slipmux config start (0xa9) */
48+
#define SPECIAL_INIT_FCS (0x374cU)
49+
#define COAP_STACKSIZE (1024)
50+
51+
static char coap_stack[COAP_STACKSIZE];
52+
#endif /* IS_USED(MODULE_SLIPDEV_CONFIG) */
53+
3654
static int _check_state(slipdev_t *dev);
3755

3856
static inline void slipdev_lock(void)
3957
{
40-
if (IS_USED(MODULE_SLIPDEV_STDIO)) {
58+
if (IS_USED(MODULE_SLIPDEV_STDIO) || IS_USED(MODULE_SLIPDEV_CONFIG)) {
4159
mutex_lock(&slipdev_mutex);
4260
}
4361
}
4462

4563
static inline void slipdev_unlock(void)
4664
{
47-
if (IS_USED(MODULE_SLIPDEV_STDIO)) {
65+
if (IS_USED(MODULE_SLIPDEV_STDIO) || IS_USED(MODULE_SLIPDEV_CONFIG)) {
4866
mutex_unlock(&slipdev_mutex);
4967
}
5068
}
@@ -54,7 +72,6 @@ static void _slip_rx_cb(void *arg, uint8_t byte)
5472
slipdev_t *dev = arg;
5573

5674
switch (dev->state) {
57-
#if IS_USED(MODULE_SLIPDEV_STDIO)
5875
case SLIPDEV_STATE_STDIN:
5976
switch (byte) {
6077
case SLIPDEV_ESC:
@@ -64,7 +81,11 @@ static void _slip_rx_cb(void *arg, uint8_t byte)
6481
dev->state = SLIPDEV_STATE_NONE;
6582
break;
6683
default:
67-
isrpipe_write_one(&stdin_isrpipe, byte);
84+
#if IS_USED(MODULE_SLIPDEV_STDIO)
85+
if (dev->config.uart == STDIO_UART_DEV) {
86+
isrpipe_write_one(&stdin_isrpipe, byte);
87+
}
88+
#endif
6889
break;
6990
}
7091
return;
@@ -78,24 +99,81 @@ static void _slip_rx_cb(void *arg, uint8_t byte)
7899
break;
79100
}
80101
dev->state = SLIPDEV_STATE_STDIN;
81-
isrpipe_write_one(&stdin_isrpipe, byte);
102+
#if IS_USED(MODULE_SLIPDEV_STDIO)
103+
if (dev->config.uart == STDIO_UART_DEV) {
104+
isrpipe_write_one(&stdin_isrpipe, byte);
105+
}
106+
#endif
82107
return;
108+
case SLIPDEV_STATE_CONFIG:
109+
switch (byte) {
110+
case SLIPDEV_ESC:
111+
dev->state = SLIPDEV_STATE_CONFIG_ESC;
112+
break;
113+
case SLIPDEV_END:
114+
dev->state = SLIPDEV_STATE_NONE;
115+
#if IS_USED(MODULE_SLIPDEV_CONFIG)
116+
crb_end_chunk(&dev->rb_config, true);
117+
thread_flags_set(thread_get(dev->coap_server_pid), 1);
83118
#endif
119+
break;
120+
default:
121+
#if IS_USED(MODULE_SLIPDEV_CONFIG)
122+
/* discard frame if byte can't be added */
123+
if (!crb_add_byte(&dev->rb_config, byte)) {
124+
DEBUG("slipdev: rx buffer full, drop frame\n");
125+
crb_end_chunk(&dev->rb_config, false);
126+
dev->state = SLIPDEV_STATE_NONE;
127+
return;
128+
}
129+
#endif
130+
break;
131+
}
132+
return;
133+
case SLIPDEV_STATE_CONFIG_ESC:
134+
switch (byte) {
135+
case SLIPDEV_END_ESC:
136+
byte = SLIPDEV_END;
137+
break;
138+
case SLIPDEV_ESC_ESC:
139+
byte = SLIPDEV_ESC;
140+
break;
141+
}
142+
#if IS_USED(MODULE_SLIPDEV_CONFIG)
143+
/* discard frame if byte can't be added */
144+
if (!crb_add_byte(&dev->rb_config, byte)) {
145+
DEBUG("slipdev: rx buffer full, drop frame\n");
146+
crb_end_chunk(&dev->rb_config, false);
147+
dev->state = SLIPDEV_STATE_NONE;
148+
return;
149+
}
150+
#endif
151+
dev->state = SLIPDEV_STATE_CONFIG;
152+
return;
84153
case SLIPDEV_STATE_NONE:
85154
/* is diagnostic frame? */
86-
if (IS_USED(MODULE_SLIPDEV_STDIO) &&
87-
(byte == SLIPDEV_STDIO_START) &&
88-
(dev->config.uart == STDIO_UART_DEV)) {
155+
if (byte == SLIPDEV_STDIO_START) {
89156
dev->state = SLIPDEV_STATE_STDIN;
90157
return;
91158
}
92159

160+
if (byte == SLIPDEV_CONFIG_START) {
161+
#if IS_USED(MODULE_SLIPDEV_CONFIG)
162+
/* try to create new frame */
163+
if (!crb_start_chunk(&dev->rb_config)) {
164+
return;
165+
}
166+
#endif
167+
dev->state = SLIPDEV_STATE_CONFIG;
168+
return;
169+
}
170+
93171
/* ignore empty frame */
94172
if (byte == SLIPDEV_END) {
95173
return;
96174
}
97175

98-
/* try to create new frame */
176+
/* try to create new ip frame */
99177
if (!crb_start_chunk(&dev->rb)) {
100178
return;
101179
}
@@ -198,8 +276,8 @@ void slipdev_write_bytes(uart_t uart, const uint8_t *data, size_t len)
198276

199277
static int _check_state(slipdev_t *dev)
200278
{
201-
/* power states not supported when multiplexing stdio */
202-
if (IS_USED(MODULE_SLIPDEV_STDIO)) {
279+
/* power states not supported when multiplexing stdio / configuration */
280+
if (IS_USED(MODULE_SLIPDEV_STDIO) || IS_USED(MODULE_SLIPDEV_CONFIG)) {
203281
return 0;
204282
}
205283

@@ -272,7 +350,7 @@ static void _isr(netdev_t *netdev)
272350
}
273351
}
274352

275-
#if !IS_USED(MODULE_SLIPDEV_STDIO)
353+
#if !(IS_USED(MODULE_SLIPDEV_STDIO) || IS_USED(MODULE_SLIPDEV_CONFIG))
276354
static int _set_state(slipdev_t *dev, netopt_state_t state)
277355
{
278356
if (IS_USED(MODULE_SLIPDEV_STDIO)) {
@@ -309,7 +387,7 @@ static int _set(netdev_t *netdev, netopt_t opt, const void *value, size_t max_le
309387
return -ENOTSUP;
310388
}
311389
}
312-
#endif /* !MODULE_SLIPDEV_STDIO */
390+
#endif /* !(MODULE_SLIPDEV_STDIO || MODULE_SLIPDEV_CONFIG) */
313391

314392
static int _get(netdev_t *netdev, netopt_t opt, void *value, size_t max_len)
315393
{
@@ -348,15 +426,69 @@ static const netdev_driver_t slip_driver = {
348426
.isr = _isr,
349427
.get = _get,
350428
.confirm_send = _confirm_send,
351-
#if IS_USED(MODULE_SLIPDEV_STDIO)
429+
#if (IS_USED(MODULE_SLIPDEV_STDIO) || IS_USED(MODULE_SLIPDEV_CONFIG))
352430
.set = netdev_set_notsup,
353431
#else
354432
.set = _set,
355433
#endif
356434
};
357435

436+
#if IS_USED(MODULE_SLIPDEV_CONFIG)
437+
static void *_coap_server_thread(void *arg)
438+
{
439+
static uint8_t buf[512];
440+
slipdev_t *dev = arg;
441+
while (1) {
442+
thread_flags_wait_any(1);
443+
size_t len;
444+
while (crb_get_chunk_size(&dev->rb_config, &len)) {
445+
crb_consume_chunk(&dev->rb_config, buf, len);
446+
447+
/* Is the crc correct via residue(=0xF0B8) test */
448+
if (crc16_ccitt_fcs_update(SPECIAL_INIT_FCS, buf, len) != 0xF0B8) {
449+
break;
450+
}
451+
452+
/* cut off the FCS checksum at the end */
453+
size_t pktlen = len - 2;
454+
455+
coap_pkt_t pkt;
456+
sock_udp_ep_t remote;
457+
coap_request_ctx_t ctx = {
458+
.remote = &remote,
459+
};
460+
if (coap_parse(&pkt, buf, pktlen) < 0) {
461+
break;
462+
}
463+
unsigned int res = 0;
464+
if ((res = coap_handle_req(&pkt, buf, sizeof(buf), &ctx)) <= 0) {
465+
break;
466+
}
467+
468+
uint16_t fcs_sum = crc16_ccitt_fcs_finish(SPECIAL_INIT_FCS, buf, res);
469+
470+
slipdev_lock();
471+
slipdev_write_byte(dev->config.uart, SLIPDEV_CONFIG_START);
472+
slipdev_write_bytes(dev->config.uart, buf, res);
473+
slipdev_write_bytes(dev->config.uart, (uint8_t *) &fcs_sum, 2);
474+
slipdev_write_byte(dev->config.uart, SLIPDEV_END);
475+
slipdev_unlock();
476+
}
477+
}
478+
479+
return NULL;
480+
}
481+
#endif /* MODULE_SLIPDEV_CONFIG */
482+
358483
void slipdev_setup(slipdev_t *dev, const slipdev_params_t *params, uint8_t index)
359484
{
485+
#if IS_USED(MODULE_SLIPDEV_CONFIG)
486+
crb_init(&dev->rb_config, dev->rxmem_config, sizeof(dev->rxmem_config));
487+
488+
dev->coap_server_pid = thread_create(coap_stack, sizeof(coap_stack), THREAD_PRIORITY_MAIN - 1,
489+
THREAD_CREATE_STACKTEST, _coap_server_thread,
490+
(void *)dev, "Slipmux CoAP server");
491+
#endif
360492
/* set device descriptor fields */
361493
dev->config = *params;
362494
dev->state = 0;

drivers/slipdev/stdio.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@
2424
#include "stdio_base.h"
2525
#include "stdio_uart.h"
2626

27-
mutex_t slipdev_mutex = MUTEX_INIT;
28-
2927
static void _isrpipe_write(void *arg, uint8_t data)
3028
{
3129
isrpipe_write_one(arg, (char)data);
@@ -34,9 +32,11 @@ static void _isrpipe_write(void *arg, uint8_t data)
3432
static void _init(void)
3533
{
3634
/* intentionally overwritten in netdev init so we have stdio before
37-
* the network device is initialized is initialized */
35+
* the network device is initialized */
3836
uart_init(slipdev_params[0].uart, slipdev_params[0].baudrate,
3937
_isrpipe_write, &stdin_isrpipe);
38+
39+
slipdev_write_byte(slipdev_params[0].uart, SLIPDEV_END);
4040
}
4141

4242
static ssize_t _write(const void *buffer, size_t len)

0 commit comments

Comments
 (0)