Contiki 3.x
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/ip/uip.h"
49 #include "net/ipv4/uip-fw.h"
50 #define BUF ((struct uip_tcpip_hdr *)&uip_buf[UIP_LLH_LEN])
51 
52 #include "dev/slip.h"
53 
54 #define DEBUG 0
55 #if DEBUG
56 #include <stdio.h>
57 #define PRINTF(...) printf(__VA_ARGS__)
58 #define PUTCHAR(X) do { putchar(X); putchar('\n'); } while(0)
59 #else
60 #define PRINTF(...) do {} while(0)
61 #define PUTCHAR(X) do {} while(0)
62 #endif
63 
64 #define SLIP_END 0300
65 #define SLIP_ESC 0333
66 #define SLIP_ESC_END 0334
67 #define SLIP_ESC_ESC 0335
68 #define SLIP_NEUTRAL 0 /* means: none of the above */
69 #define SLIP_ESC_XON 0336
70 #define SLIP_ESC_XOFF 0337
71 #define XON ((unsigned char)17)
72 #define XOFF ((unsigned char)19)
73 #if UART_XONXOFF_FLOW_CTRL
74 volatile unsigned char xonxoff_state = XON;
75 #endif /* UART_XONXOFF_FLOW_CTRL */
76 
77 PROCESS(slip_process, "SLIP driver");
78 
79 #include "dev/uart0.h"
80 #define STORE_UART_INTERRUPTS uart0_store_interrupts
81 #define RESTORE_UART_INTERRUPTS uart0_restore_interrupts
82 #define DISABLE_UART_INTERRUPTS uart0_disable_interrupts
83 #define ENABLE_UART_INTERRUPTS uart0_enable_interrupts
84 
85 /**
86  * @brief A block of code may be made atomic by wrapping it with this
87  * macro. Something which is atomic cannot be interrupted by interrupts.
88  */
89 /* A specific ATMOIC that disables UART interrupts only */
90 #define ATOMIC(blah) \
91  { \
92  /* STORE_UART_INTERRUPTS(); */ \
93  DISABLE_UART_INTERRUPTS(); \
94  { blah } \
95  /* RESTORE_UART_INTERRUPTS(); */ \
96  ENABLE_UART_INTERRUPTS(); \
97  }
98 
99 /* A generic ATMOIC that disables all interrupts */
100 #define GLOBAL_ATOMIC(blah) \
101  { \
102  MICRO_DISABLE_INTERRUPTS(); \
103  { blah } \
104  MICRO_ENABLE_INTERRUPTS(); \
105  }
106 
107 #if 1
108 #define SLIP_STATISTICS(statement)
109 #else
110 uint16_t slip_drop_bytes, slip_overflow, slip_error_drop;
111 /* No used in this file */
112 uint16_t slip_rubbish, slip_twopackets, slip_ip_drop;
113 unsigned long slip_received, slip_frames;
114 #define SLIP_STATISTICS(statement) statement
115 #endif
116 
117 /* Must be at least one byte larger than UIP_BUFSIZE (for SLIP_END)! */
118 #ifdef SLIP_CONF_RX_BUFSIZE
119 #define RX_BUFSIZE SLIP_CONF_RX_BUFSIZE
120 
121 #if RX_BUFSIZE < (UIP_BUFSIZE - UIP_LLH_LEN + 16)
122 #error "SLIP_CONF_RX_BUFSIZE too small for UIP_BUFSIZE"
123 #endif
124 
125 #else
126 #define RX_BUFSIZE (UIP_CONF_BUFFER_SIZE * 2)
127 #endif
128 
129 /*
130  * Variables begin and end manage the buffer space in a cyclic
131  * fashion. The first used byte is at begin and end is one byte past
132  * the last. I.e. [begin, end) is the actively used space.
133  */
134 
135 static volatile uint16_t begin, end, end_counter;
136 static uint8_t rxbuf[RX_BUFSIZE];
137 static volatile uint8_t is_dropping = 0;
138 static volatile uint8_t is_full = 0;
139 
140 static void (*input_callback)(void) = NULL;
141 /*---------------------------------------------------------------------------*/
142 void
143 slip_set_input_callback(void (*c)(void))
144 {
145  input_callback = c;
146 }
147 static void
148 slip_write_char(uint8_t c)
149 {
150  /* Escape SLIP control characters */
151  if(c == SLIP_END) {
152  slip_arch_writeb(SLIP_ESC);
153  c = SLIP_ESC_END;
154  } else if(c == SLIP_ESC) {
155  slip_arch_writeb(SLIP_ESC);
156  c = SLIP_ESC_ESC;
157  }
158 #if UART_XONXOFF_FLOW_CTRL
159  /* Escape XON/XOFF characters */
160  else if(c == XON) {
161  slip_arch_writeb(SLIP_ESC);
162  c = SLIP_ESC_XON;
163  } else if(c == XOFF) {
164  slip_arch_writeb(SLIP_ESC);
165  c = SLIP_ESC_XOFF;
166  }
167 #endif /* UART_XONXOFF_FLOW_CTRL */
168  slip_arch_writeb(c);
169 }
170 /*---------------------------------------------------------------------------*/
171 uint8_t
172 slip_write(const void *_ptr, int len)
173 {
174  const uint8_t *ptr = _ptr;
175  uint16_t i;
176  uint8_t c;
177 
178  slip_arch_writeb(SLIP_END);
179 
180  for(i = 0; i < len; ++i) {
181  c = *ptr++;
182  slip_write_char(c);
183  }
184  slip_arch_writeb(SLIP_END);
185 
186  return len;
187 }
188 /*---------------------------------------------------------------------------*/
189 /* slip_send: forward (IPv4) packets with {UIP_FW_NETIF(..., slip_send)}
190  * was used in slip-bridge.c
191  */
192 uint8_t
194 {
195  uint16_t i;
196  uint8_t *ptr;
197  uint8_t c;
198 
199  slip_arch_writeb(SLIP_END);
200 
201  ptr = &uip_buf[UIP_LLH_LEN];
202  for(i = 0; i < uip_len; ++i) {
203  if(i == UIP_TCPIP_HLEN) {
204  ptr = (uint8_t *)uip_appdata;
205  }
206  c = *ptr++;
207  slip_write_char(c);
208  }
209  slip_arch_writeb(SLIP_END);
210 
211  return UIP_FW_OK;
212 }
213 /*---------------------------------------------------------------------------*/
214 static void
215 rxbuf_init(void)
216 {
217  begin = end = end_counter = 0;
218  is_dropping = 0;
219 }
220 /*---------------------------------------------------------------------------*/
221 /* Upper half does the polling. */
222 static uint16_t
223 slip_poll_handler(uint8_t *outbuf, uint16_t blen)
224 {
225  uint16_t len;
226  uint16_t pos;
227  uint8_t c;
228  uint8_t state;
229 
230  if(end_counter == 0 && is_full == 0) {
231  return 0;
232  }
233  for(len = 0, pos = begin, state = c = SLIP_NEUTRAL;
234  len < blen + 1; /* +1 for SLIP_END! */
235  ) {
236 
237  c = rxbuf[pos++];
238 
239  if(pos == RX_BUFSIZE) {
240  /* Circular buffer: warp around */
241  pos = 0;
242  }
243  if(c == SLIP_END) {
244  /* End of packet */
245  break;
246  }
247  if(len >= blen) {
248  /* End of buffer with no SLIP_END
249  * ==> something wrong happened */
250  break;
251  }
252  switch(c) {
253  case SLIP_ESC:
254  state = SLIP_ESC;
255  break;
256  case SLIP_ESC_END:
257  if(state == SLIP_ESC) {
258  outbuf[len++] = SLIP_END;
259  state = SLIP_NEUTRAL;
260  } else {
261  outbuf[len++] = c;
262  } break;
263  case SLIP_ESC_ESC:
264  if(state == SLIP_ESC) {
265  outbuf[len++] = SLIP_ESC;
266  state = SLIP_NEUTRAL;
267  } else {
268  outbuf[len++] = c;
269  } break;
270 #if UART_XONXOFF_FLOW_CTRL
271  case SLIP_ESC_XON:
272  if(state == SLIP_ESC) {
273  outbuf[len++] = XON;
274  state = SLIP_NEUTRAL;
275  } else {
276  outbuf[len++] = c;
277  } break;
278  case SLIP_ESC_XOFF:
279  if(state == SLIP_ESC) {
280  outbuf[len++] = XOFF;
281  state = SLIP_NEUTRAL;
282  } else {
283  outbuf[len++] = c;
284  } break;
285 #endif /* UART_XONXOFF_FLOW_CTRL */
286  default:
287  outbuf[len++] = c;
288  state = SLIP_NEUTRAL;
289  break;
290  }
291  }
292 
293  /* Update counters */
294  if(c == SLIP_END) {
295  ATOMIC(begin = pos;
296  if(end_counter) {
297  end_counter--;
298  }
299  )
300  PUTCHAR('P');
301  } else {
302  /* Something went wrong, no SLIP_END found, drop everything */
303  ATOMIC(rxbuf_init();
304  is_dropping = 1;
305  )
306  SLIP_STATISTICS(slip_error_drop++);
307  len = 0;
308  PRINTF("SLIP: *** out of sync!\n");
309  }
310 
311  if(end_counter > 0) {
312  /* One more packet is buffered, need to be polled again! */
313  process_poll(&slip_process);
314  }
315  return len;
316 }
317 /*---------------------------------------------------------------------------*/
318 PROCESS_THREAD(slip_process, ev, data)
319 {
320  PROCESS_BEGIN();
321 
322  rxbuf_init();
323 
324  while(1) {
325  PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL);
326 
327  /* Move packet from rxbuf to buffer provided by uIP. */
328  uip_len = slip_poll_handler(&uip_buf[UIP_LLH_LEN],
329  UIP_BUFSIZE - UIP_LLH_LEN);
330 
331  PRINTF("SLIP: recv bytes %u frames RECV: %u. is_full %u, is_dropping %u.\n",
332  end_counter, uip_len, is_full, is_dropping);
333 
334  /* We have free space now, resume slip RX */
335  if(is_full) {
336  is_full = 0;
337  ENABLE_UART_INTERRUPTS();
338  }
339 
340  if(uip_len > 0) {
341  if(input_callback) {
342  input_callback();
343  }
344 #ifdef SLIP_CONF_TCPIP_INPUT
345  SLIP_CONF_TCPIP_INPUT();
346 #else
347  tcpip_input();
348 #endif
349  }
350  }
351 
352  PROCESS_END();
353 }
354 /*---------------------------------------------------------------------------*/
355 /* Return status from slip_input_byte:
356  * -1 means RX buffer overflow ==> stop reading
357  * 0 means do not exit power saving mode
358  * 1 means exit power saving mode
359  **/
360 int
361 slip_input_byte(unsigned char c)
362 {
363  static int in_frame = 0;
364  uint16_t next, next_next;
365  int error_return_code = is_full ? -1 : 0;
366  int success_return_code = is_full ? -1 : 1;
367 
368  SLIP_STATISTICS(slip_received++);
369 
370 #if UART_XONXOFF_FLOW_CTRL
371  if(c == XOFF || c == XON) {
372  xonxoff_state = c;
373  return 1;
374  } else {
375  /* ANY char would be XON */
376  xonxoff_state = XON;
377  }
378 #endif /* UART_XONXOFF_FLOW_CTRL */
379 
380  if(is_dropping) {
381  /* Make sure to drop full frames when overflow or
382  * out of sync happens */
383  if(c != SLIP_END) {
384  SLIP_STATISTICS(slip_drop_bytes++);
385  } else {
386  is_dropping = 0;
387  in_frame = 0;
388  }
389  return error_return_code;
390  }
391 
392  if(!in_frame && c == SLIP_END) {
393  /* Ignore slip end when not receiving frame */
394  return error_return_code;
395  /* increment and wrap */
396  }
397  next = end + 1;
398  if(next >= RX_BUFSIZE) {
399  next = 0;
400  }
401  next_next = next + 1;
402  if(next_next >= RX_BUFSIZE) {
403  next_next = 0;
404  /* Next byte will overflow. Stop accepting. */
405  }
406  if(next_next == begin) {
407  is_full = 1;
408  /* disable UART interrupts */
409  DISABLE_UART_INTERRUPTS();
410  process_poll(&slip_process);
411  }
412 
413  /* Buffer is full. We can't store anymore.
414  * Shall not happen normally,
415  * because of overflow protection above. */
416  if(next == begin) {
417  is_dropping = 1;
418  SLIP_STATISTICS(slip_overflow++);
419  is_full = 1;
420  /* disable UART interrupts */
421  DISABLE_UART_INTERRUPTS();
422  process_poll(&slip_process);
423  return -1;
424  }
425 
426  rxbuf[end] = c;
427  end = next;
428  in_frame = 1;
429 
430  if(c == SLIP_END) {
431  in_frame = 0;
432  end_counter++;
433  SLIP_STATISTICS(slip_frames++);
434  process_poll(&slip_process);
435  return success_return_code;
436  }
437  return error_return_code;
438 }
439 /*---------------------------------------------------------------------------*/
440 #if SLIP_BRIDGE_CONF_NO_PUTCHAR
441 int
442 putchar(int c)
443 {
444  uart0_writeb(c);
445  return 1;
446 }
447 #endif
uip_len
The length of the packet in the uip_buf buffer.
Definition: tcp_loader.c:75
void process_poll(struct process *p)
Request a process to be polled.
Definition: process.c:371
uint8_t slip_send(void)
Send an IP packet from the uIP buffer with SLIP.
Definition: slip.c:193
#define UIP_FW_OK
A non-error message that indicates that something went OK.
Definition: uip-fw.h:132
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
void slip_arch_writeb(unsigned char c)
Copyright (c) 2014, Analog Devices, Inc.
Definition: slip-arch.c:46
#define UIP_LLH_LEN
The link level header length.
Definition: uipopt.h:160
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
Definition: process.h:273
uip_appdata
Pointer to the application data in the packet buffer.
Definition: tcp_loader.c:74
int slip_input_byte(unsigned char c)
Input a SLIP byte.
Definition: slip.c:361
#define ATOMIC(blah)
A block of code may be made atomic by wrapping it with this macro.
Definition: slip.c:90
#define uip_buf
Macro to access uip_aligned_buf as an array of bytes.
Definition: uip.h:523
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:143
#define NULL
The null pointer.
uIP packet forwarding header file.
Header file for the uIP TCP/IP stack.
#define PROCESS_YIELD_UNTIL(c)
Yield the currently running process until a condition occurs.
Definition: process.h:178
void tcpip_input(void)
Deliver an incoming packet to the TCP/IP stack.
Definition: tcpip.c:522
#define UIP_BUFSIZE
The size of the uIP packet buffer.
Definition: uipopt.h:173
tcirc_buf rxbuf
The RX circular buffer, for storing characters from serial port.
Definition: uart.c:56
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120