Contiki-NG
slip.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2014, SICS Swedish ICT.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the Institute nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * This file is part of the Contiki operating system.
30 *
31 */
32
33/**
34 * \file
35 * Alternative implementation for SLIP:
36 * 1. Accepts more than two packet
37 * 2. Disables UART rx interrupt when buffer is full
38 * (thus invoking flow control if configured)
39 * \author
40 * Niklas Finne <nfi@sics.se>
41 * Beshr Al Nahas <beshr@sics.se>
42 *
43 */
44
45#include "contiki.h"
46
47#include <MicroInt.h>
48#include "net/ipv6/uip.h"
49
50#include "dev/slip.h"
51
52#define DEBUG 0
53#if DEBUG
54#include <stdio.h>
55#define PRINTF(...) printf(__VA_ARGS__)
56#define PUTCHAR(X) do { putchar(X); putchar('\n'); } while(0)
57#else
58#define PRINTF(...) do {} while(0)
59#define PUTCHAR(X) do {} while(0)
60#endif
61
62#define SLIP_END 0300
63#define SLIP_ESC 0333
64#define SLIP_ESC_END 0334
65#define SLIP_ESC_ESC 0335
66#define SLIP_NEUTRAL 0 /* means: none of the above */
67#define SLIP_ESC_XON 0336
68#define SLIP_ESC_XOFF 0337
69#define XON ((unsigned char)17)
70#define XOFF ((unsigned char)19)
71#if UART_XONXOFF_FLOW_CTRL
72volatile unsigned char xonxoff_state = XON;
73#endif /* UART_XONXOFF_FLOW_CTRL */
74
75PROCESS(slip_process, "SLIP driver");
76
77#include "dev/uart0.h"
78#define STORE_UART_INTERRUPTS uart0_store_interrupts
79#define RESTORE_UART_INTERRUPTS uart0_restore_interrupts
80#define DISABLE_UART_INTERRUPTS uart0_disable_interrupts
81#define ENABLE_UART_INTERRUPTS uart0_enable_interrupts
82
83/**
84 * @brief A block of code may be made atomic by wrapping it with this
85 * macro. Something which is atomic cannot be interrupted by interrupts.
86 */
87/* A specific ATMOIC that disables UART interrupts only */
88#define ATOMIC(blah) \
89 { \
90 /* STORE_UART_INTERRUPTS(); */ \
91 DISABLE_UART_INTERRUPTS(); \
92 { blah } \
93 /* RESTORE_UART_INTERRUPTS(); */ \
94 ENABLE_UART_INTERRUPTS(); \
95 }
96
97/* A generic ATMOIC that disables all interrupts */
98#define GLOBAL_ATOMIC(blah) \
99 { \
100 MICRO_DISABLE_INTERRUPTS(); \
101 { blah } \
102 MICRO_ENABLE_INTERRUPTS(); \
103 }
104
105#if 1
106#define SLIP_STATISTICS(statement)
107#else
108uint16_t slip_drop_bytes, slip_overflow, slip_error_drop;
109/* No used in this file */
110uint16_t slip_rubbish, slip_twopackets, slip_ip_drop;
111unsigned long slip_received, slip_frames;
112#define SLIP_STATISTICS(statement) statement
113#endif
114
115/* Must be at least one byte larger than UIP_BUFSIZE (for SLIP_END)! */
116#ifdef SLIP_CONF_RX_BUFSIZE
117#define RX_BUFSIZE SLIP_CONF_RX_BUFSIZE
118
119#if RX_BUFSIZE < (UIP_BUFSIZE + 16)
120#error "SLIP_CONF_RX_BUFSIZE too small for UIP_BUFSIZE"
121#endif
122
123#else
124#define RX_BUFSIZE (UIP_CONF_BUFFER_SIZE * 2)
125#endif
126
127/*
128 * Variables begin and end manage the buffer space in a cyclic
129 * fashion. The first used byte is at begin and end is one byte past
130 * the last. I.e. [begin, end) is the actively used space.
131 */
132
133static volatile uint16_t begin, end, end_counter;
134static uint8_t rxbuf[RX_BUFSIZE];
135static volatile uint8_t is_dropping = 0;
136static volatile uint8_t is_full = 0;
137
138static void (*input_callback)(void) = NULL;
139/*---------------------------------------------------------------------------*/
140void
142{
143 input_callback = c;
144}
145static void
146slip_write_char(uint8_t c)
147{
148 /* Escape SLIP control characters */
149 if(c == SLIP_END) {
150 slip_arch_writeb(SLIP_ESC);
151 c = SLIP_ESC_END;
152 } else if(c == SLIP_ESC) {
153 slip_arch_writeb(SLIP_ESC);
154 c = SLIP_ESC_ESC;
155 }
156#if UART_XONXOFF_FLOW_CTRL
157 /* Escape XON/XOFF characters */
158 else if(c == XON) {
159 slip_arch_writeb(SLIP_ESC);
160 c = SLIP_ESC_XON;
161 } else if(c == XOFF) {
162 slip_arch_writeb(SLIP_ESC);
163 c = SLIP_ESC_XOFF;
164 }
165#endif /* UART_XONXOFF_FLOW_CTRL */
167}
168/*---------------------------------------------------------------------------*/
169void
170slip_write(const void *_ptr, int len)
171{
172 const uint8_t *ptr = _ptr;
173 uint16_t i;
174 uint8_t c;
175
176 slip_arch_writeb(SLIP_END);
177
178 for(i = 0; i < len; ++i) {
179 c = *ptr++;
180 slip_write_char(c);
181 }
182 slip_arch_writeb(SLIP_END);
183}
184/*---------------------------------------------------------------------------*/
185/* slip_send: forward (IPv4) packets with {UIP_FW_NETIF(..., slip_send)}
186 * was used in slip-bridge.c
187 */
188void
190{
191 uint16_t i;
192 uint8_t *ptr;
193 uint8_t c;
194
195 slip_arch_writeb(SLIP_END);
196
197 ptr = uip_buf;
198 for(i = 0; i < uip_len; ++i) {
199 c = *ptr++;
200 slip_write_char(c);
201 }
202 slip_arch_writeb(SLIP_END);
203}
204/*---------------------------------------------------------------------------*/
205static void
206rxbuf_init(void)
207{
208 begin = end = end_counter = 0;
209 is_dropping = 0;
210}
211/*---------------------------------------------------------------------------*/
212/* Upper half does the polling. */
213static uint16_t
214slip_poll_handler(uint8_t *outbuf, uint16_t blen)
215{
216 uint16_t len;
217 uint16_t pos;
218 uint8_t c;
219 uint8_t state;
220
221 if(end_counter == 0 && is_full == 0) {
222 return 0;
223 }
224 for(len = 0, pos = begin, state = c = SLIP_NEUTRAL;
225 len < blen + 1; /* +1 for SLIP_END! */
226 ) {
227
228 c = rxbuf[pos++];
229
230 if(pos == RX_BUFSIZE) {
231 /* Circular buffer: warp around */
232 pos = 0;
233 }
234 if(c == SLIP_END) {
235 /* End of packet */
236 break;
237 }
238 if(len >= blen) {
239 /* End of buffer with no SLIP_END
240 * ==> something wrong happened */
241 break;
242 }
243 switch(c) {
244 case SLIP_ESC:
245 state = SLIP_ESC;
246 break;
247 case SLIP_ESC_END:
248 if(state == SLIP_ESC) {
249 outbuf[len++] = SLIP_END;
250 state = SLIP_NEUTRAL;
251 } else {
252 outbuf[len++] = c;
253 } break;
254 case SLIP_ESC_ESC:
255 if(state == SLIP_ESC) {
256 outbuf[len++] = SLIP_ESC;
257 state = SLIP_NEUTRAL;
258 } else {
259 outbuf[len++] = c;
260 } break;
261#if UART_XONXOFF_FLOW_CTRL
262 case SLIP_ESC_XON:
263 if(state == SLIP_ESC) {
264 outbuf[len++] = XON;
265 state = SLIP_NEUTRAL;
266 } else {
267 outbuf[len++] = c;
268 } break;
269 case SLIP_ESC_XOFF:
270 if(state == SLIP_ESC) {
271 outbuf[len++] = XOFF;
272 state = SLIP_NEUTRAL;
273 } else {
274 outbuf[len++] = c;
275 } break;
276#endif /* UART_XONXOFF_FLOW_CTRL */
277 default:
278 outbuf[len++] = c;
279 state = SLIP_NEUTRAL;
280 break;
281 }
282 }
283
284 /* Update counters */
285 if(c == SLIP_END) {
286 ATOMIC(begin = pos;
287 if(end_counter) {
288 end_counter--;
289 }
290 )
291 PUTCHAR('P');
292 } else {
293 /* Something went wrong, no SLIP_END found, drop everything */
294 ATOMIC(rxbuf_init();
295 is_dropping = 1;
296 )
297 SLIP_STATISTICS(slip_error_drop++);
298 len = 0;
299 PRINTF("SLIP: *** out of sync!\n");
300 }
301
302 if(end_counter > 0) {
303 /* One more packet is buffered, need to be polled again! */
304 process_poll(&slip_process);
305 }
306 return len;
307}
308/*---------------------------------------------------------------------------*/
309PROCESS_THREAD(slip_process, ev, data)
310{
312
313 rxbuf_init();
314
315 while(1) {
316 PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL);
317
318 /* Move packet from rxbuf to buffer provided by uIP. */
319 uip_len = slip_poll_handler(uip_buf, UIP_BUFSIZE);
320
321 PRINTF("SLIP: recv bytes %u frames RECV: %u. is_full %u, is_dropping %u.\n",
322 end_counter, uip_len, is_full, is_dropping);
323
324 /* We have free space now, resume slip RX */
325 if(is_full) {
326 is_full = 0;
327 ENABLE_UART_INTERRUPTS();
328 }
329
330 if(uip_len > 0) {
331 if(input_callback) {
332 input_callback();
333 }
334#ifdef SLIP_CONF_TCPIP_INPUT
335 SLIP_CONF_TCPIP_INPUT();
336#else
337 tcpip_input();
338#endif
339 }
340 }
341
342 PROCESS_END();
343}
344/*---------------------------------------------------------------------------*/
345/* Return status from slip_input_byte:
346 * -1 means RX buffer overflow ==> stop reading
347 * 0 means do not exit power saving mode
348 * 1 means exit power saving mode
349 **/
350int
351slip_input_byte(unsigned char c)
352{
353 static int in_frame = 0;
354 uint16_t next, next_next;
355 int error_return_code = is_full ? -1 : 0;
356 int success_return_code = is_full ? -1 : 1;
357
358 SLIP_STATISTICS(slip_received++);
359
360#if UART_XONXOFF_FLOW_CTRL
361 if(c == XOFF || c == XON) {
362 xonxoff_state = c;
363 return 1;
364 } else {
365 /* ANY char would be XON */
366 xonxoff_state = XON;
367 }
368#endif /* UART_XONXOFF_FLOW_CTRL */
369
370 if(is_dropping) {
371 /* Make sure to drop full frames when overflow or
372 * out of sync happens */
373 if(c != SLIP_END) {
374 SLIP_STATISTICS(slip_drop_bytes++);
375 } else {
376 is_dropping = 0;
377 in_frame = 0;
378 }
379 return error_return_code;
380 }
381
382 if(!in_frame && c == SLIP_END) {
383 /* Ignore slip end when not receiving frame */
384 return error_return_code;
385 /* increment and wrap */
386 }
387 next = end + 1;
388 if(next >= RX_BUFSIZE) {
389 next = 0;
390 }
391 next_next = next + 1;
392 if(next_next >= RX_BUFSIZE) {
393 next_next = 0;
394 /* Next byte will overflow. Stop accepting. */
395 }
396 if(next_next == begin) {
397 is_full = 1;
398 /* disable UART interrupts */
399 DISABLE_UART_INTERRUPTS();
400 process_poll(&slip_process);
401 }
402
403 /* Buffer is full. We can't store anymore.
404 * Shall not happen normally,
405 * because of overflow protection above. */
406 if(next == begin) {
407 is_dropping = 1;
408 SLIP_STATISTICS(slip_overflow++);
409 is_full = 1;
410 /* disable UART interrupts */
411 DISABLE_UART_INTERRUPTS();
412 process_poll(&slip_process);
413 return -1;
414 }
415
416 rxbuf[end] = c;
417 end = next;
418 in_frame = 1;
419
420 if(c == SLIP_END) {
421 in_frame = 0;
422 end_counter++;
423 SLIP_STATISTICS(slip_frames++);
424 process_poll(&slip_process);
425 return success_return_code;
426 }
427 return error_return_code;
428}
429/*---------------------------------------------------------------------------*/
void slip_write(const void *_ptr, int len)
Send using SLIP len bytes starting from the location pointed to by ptr.
Definition: slip.c:170
void slip_set_input_callback(void(*c)(void))
Set a function to be called when there is activity on the SLIP interface; used for detecting if a nod...
Definition: slip.c:141
int slip_input_byte(unsigned char c)
Input a SLIP byte.
Definition: slip.c:351
void slip_send(void)
Send an IP packet from the uIP buffer with SLIP.
Definition: slip.c:189
#define ATOMIC(blah)
A block of code may be made atomic by wrapping it with this macro.
Definition: slip.c:88
void slip_arch_writeb(unsigned char c)
Write a single byte over SLIP.
Definition: slip-arch.c:53
PROCESS_THREAD(cc2538_rf_process, ev, data)
Implementation of the cc2538 RF driver process.
Definition: cc2538-rf.c:1110
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
#define PROCESS_YIELD_UNTIL(c)
Yield the currently running process until a condition occurs.
Definition: process.h:178
void process_poll(struct process *p)
Request a process to be polled.
Definition: process.c:371
void tcpip_input(void)
Deliver an incoming packet to the TCP/IP stack.
Definition: tcpip.c:445
#define uip_buf
Macro to access uip_aligned_buf as an array of bytes.
Definition: uip.h:465
uint16_t uip_len
The length of the packet in the uip_buf buffer.
Definition: uip6.c:159
#define UIP_BUFSIZE
The size of the uIP packet buffer.
Definition: uipopt.h:93
Header file for the uIP TCP/IP stack.