Contiki-NG
slip.c
1 /* -*- C -*- */
2 /*
3  * Copyright (c) 2005, Swedish Institute of Computer Science
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  * 3. Neither the name of the Institute nor the names of its contributors
15  * may be used to endorse or promote products derived from this software
16  * without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 /*---------------------------------------------------------------------------*/
31 #include "contiki.h"
32 #include "net/ipv6/uip.h"
33 #include "dev/slip.h"
34 
35 #include <stdio.h>
36 #include <string.h>
37 /*---------------------------------------------------------------------------*/
38 #define SLIP_END 0300
39 #define SLIP_ESC 0333
40 #define SLIP_ESC_END 0334
41 #define SLIP_ESC_ESC 0335
42 /*---------------------------------------------------------------------------*/
43 PROCESS(slip_process, "SLIP driver");
44 /*---------------------------------------------------------------------------*/
45 static uint8_t slip_active;
46 /*---------------------------------------------------------------------------*/
47 #if SLIP_CONF_WITH_STATS
48 static uint16_t slip_rubbish, slip_twopackets, slip_overflow, slip_ip_drop;
49 #define SLIP_STATISTICS(statement) statement
50 #else
51 #define SLIP_STATISTICS(statement)
52 #endif
53 /*---------------------------------------------------------------------------*/
54 /* Must be at least one byte larger than UIP_BUFSIZE! */
55 #define RX_BUFSIZE (UIP_BUFSIZE + 16)
56 /*---------------------------------------------------------------------------*/
57 enum {
58  STATE_TWOPACKETS = 0, /* We have 2 packets and drop incoming data. */
59  STATE_OK = 1,
60  STATE_ESC = 2,
61  STATE_RUBBISH = 3,
62 };
63 /*---------------------------------------------------------------------------*/
64 /*
65  * Variables begin and end manage the buffer space in a cyclic
66  * fashion. The first used byte is at begin and end is one byte past
67  * the last. I.e. [begin, end) is the actively used space.
68  *
69  * If begin != pkt_end we have a packet at [begin, pkt_end),
70  * furthermore, if state == STATE_TWOPACKETS we have one more packet at
71  * [pkt_end, end). If more bytes arrive in state STATE_TWOPACKETS
72  * they are discarded.
73  */
74 static uint8_t state = STATE_TWOPACKETS;
75 static uint16_t begin, next_free;
76 static uint8_t rxbuf[RX_BUFSIZE];
77 static uint16_t pkt_end; /* SLIP_END tracker. */
78 
79 static void (*input_callback)(void) = NULL;
80 /*---------------------------------------------------------------------------*/
81 void
82 slip_set_input_callback(void (*c)(void))
83 {
84  input_callback = c;
85 }
86 /*---------------------------------------------------------------------------*/
87 void
88 slip_send(void)
89 {
91 }
92 /*---------------------------------------------------------------------------*/
93 void
94 slip_write(const void *_ptr, int len)
95 {
96  const uint8_t *ptr = _ptr;
97  uint16_t i;
98  uint8_t c;
99 
100  slip_arch_writeb(SLIP_END);
101 
102  for(i = 0; i < len; ++i) {
103  c = *ptr++;
104  if(c == SLIP_END) {
105  slip_arch_writeb(SLIP_ESC);
106  c = SLIP_ESC_END;
107  } else if(c == SLIP_ESC) {
108  slip_arch_writeb(SLIP_ESC);
109  c = SLIP_ESC_ESC;
110  }
111  slip_arch_writeb(c);
112  }
113 
114  slip_arch_writeb(SLIP_END);
115 }
116 /*---------------------------------------------------------------------------*/
117 static void
118 rxbuf_init(void)
119 {
120  begin = next_free = pkt_end = 0;
121  state = STATE_OK;
122 }
123 /*---------------------------------------------------------------------------*/
124 static uint16_t
125 slip_poll_handler(uint8_t *outbuf, uint16_t blen)
126 {
127  /*
128  * Interrupt can not change begin but may change pkt_end.
129  * If pkt_end != begin it will not change again.
130  */
131  if(begin != pkt_end) {
132  uint16_t len;
133  uint16_t cur_next_free;
134  uint16_t cur_ptr;
135  int esc = 0;
136 
137  if(begin < pkt_end) {
138  uint16_t i;
139  len = 0;
140  for(i = begin; i < pkt_end; ++i) {
141  if(len > blen) {
142  len = 0;
143  break;
144  }
145  if(esc) {
146  if(rxbuf[i] == SLIP_ESC_ESC) {
147  outbuf[len] = SLIP_ESC;
148  len++;
149  } else if(rxbuf[i] == SLIP_ESC_END) {
150  outbuf[len] = SLIP_END;
151  len++;
152  }
153  esc = 0;
154  } else if(rxbuf[i] == SLIP_ESC) {
155  esc = 1;
156  } else {
157  outbuf[len] = rxbuf[i];
158  len++;
159  }
160  }
161  } else {
162  uint16_t i;
163  len = 0;
164  for(i = begin; i < RX_BUFSIZE; ++i) {
165  if(len > blen) {
166  len = 0;
167  break;
168  }
169  if(esc) {
170  if(rxbuf[i] == SLIP_ESC_ESC) {
171  outbuf[len] = SLIP_ESC;
172  len++;
173  } else if(rxbuf[i] == SLIP_ESC_END) {
174  outbuf[len] = SLIP_END;
175  len++;
176  }
177  esc = 0;
178  } else if(rxbuf[i] == SLIP_ESC) {
179  esc = 1;
180  } else {
181  outbuf[len] = rxbuf[i];
182  len++;
183  }
184  }
185  for(i = 0; i < pkt_end; ++i) {
186  if(len > blen) {
187  len = 0;
188  break;
189  }
190  if(esc) {
191  if(rxbuf[i] == SLIP_ESC_ESC) {
192  outbuf[len] = SLIP_ESC;
193  len++;
194  } else if(rxbuf[i] == SLIP_ESC_END) {
195  outbuf[len] = SLIP_END;
196  len++;
197  }
198  esc = 0;
199  } else if(rxbuf[i] == SLIP_ESC) {
200  esc = 1;
201  } else {
202  outbuf[len] = rxbuf[i];
203  len++;
204  }
205  }
206  }
207 
208  /* Remove data from buffer together with the copied packet. */
209  pkt_end = pkt_end + 1;
210  if(pkt_end == RX_BUFSIZE) {
211  pkt_end = 0;
212  }
213  if(pkt_end != next_free) {
214  cur_next_free = next_free;
215  cur_ptr = pkt_end;
216  while(cur_ptr != cur_next_free) {
217  if(rxbuf[cur_ptr] == SLIP_END) {
218  uint16_t tmp_begin = pkt_end;
219  pkt_end = cur_ptr;
220  begin = tmp_begin;
221  /* One more packet is buffered, need to be polled again! */
222  process_poll(&slip_process);
223  break;
224  }
225  cur_ptr++;
226  if(cur_ptr == RX_BUFSIZE) {
227  cur_ptr = 0;
228  }
229  }
230  if(cur_ptr == cur_next_free) {
231  /* no more pending full packet found */
232  begin = pkt_end;
233  }
234  } else {
235  begin = pkt_end;
236  }
237  return len;
238  }
239 
240  return 0;
241 }
242 /*---------------------------------------------------------------------------*/
243 PROCESS_THREAD(slip_process, ev, data)
244 {
245  PROCESS_BEGIN();
246 
247  rxbuf_init();
248 
249  while(1) {
250  PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL);
251 
252  slip_active = 1;
253 
254  /* Move packet from rxbuf to buffer provided by uIP. */
255  uip_len = slip_poll_handler(uip_buf, UIP_BUFSIZE);
256 
257  if(uip_len > 0) {
258  if(input_callback) {
259  input_callback();
260  }
261  tcpip_input();
262  }
263  }
264 
265  PROCESS_END();
266 }
267 /*---------------------------------------------------------------------------*/
268 int
269 slip_input_byte(unsigned char c)
270 {
271  uint16_t cur_end;
272  switch(state) {
273  case STATE_RUBBISH:
274  if(c == SLIP_END) {
275  state = STATE_OK;
276  }
277  return 0;
278 
279  case STATE_ESC:
280  if(c != SLIP_ESC_END && c != SLIP_ESC_ESC) {
281  state = STATE_RUBBISH;
282  SLIP_STATISTICS(slip_rubbish++);
283  next_free = pkt_end; /* remove rubbish */
284  return 0;
285  }
286  state = STATE_OK;
287  break;
288  }
289 
290  if(c == SLIP_ESC) {
291  state = STATE_ESC;
292  }
293 
294  /* add_char: */
295  cur_end = next_free;
296  next_free = next_free + 1;
297  if(next_free == RX_BUFSIZE) {
298  next_free = 0;
299  }
300  if(next_free == begin) { /* rxbuf is full */
301  state = STATE_RUBBISH;
302  SLIP_STATISTICS(slip_overflow++);
303  next_free = pkt_end; /* remove rubbish */
304  return 0;
305  }
306  rxbuf[cur_end] = c;
307 
308  if(c == SLIP_END) {
309  /*
310  * We have a new packet, possibly of zero length.
311  *
312  * There may already be one packet buffered.
313  */
314  if(cur_end != pkt_end) { /* Non zero length. */
315  if(begin == pkt_end) { /* None buffered. */
316  pkt_end = cur_end;
317  } else {
318  SLIP_STATISTICS(slip_twopackets++);
319  }
320  process_poll(&slip_process);
321  return 1;
322  } else {
323  /* Empty packet, reset the pointer */
324  next_free = cur_end;
325  }
326  return 0;
327  }
328 
329  return 0;
330 }
331 /*---------------------------------------------------------------------------*/
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
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
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
uint16_t uip_len
The length of the packet in the uip_buf buffer.
Definition: uip6.c:159
#define PROCESS_YIELD_UNTIL(c)
Yield the currently running process until a condition occurs.
Definition: process.h:178
#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 UIP_BUFSIZE
The size of the uIP packet buffer.
Definition: uipopt.h:134
void slip_arch_writeb(unsigned char c)
Write a single byte over SLIP.
Definition: slip-arch.c:53
void slip_send(void)
Send an IP packet from the uIP buffer with SLIP.
Definition: slip.c:189
int slip_input_byte(unsigned char c)
Input a SLIP byte.
Definition: slip.c:351
void process_poll(struct process *p)
Request a process to be polled.
Definition: process.c:371
#define uip_buf
Macro to access uip_aligned_buf as an array of bytes.
Definition: uip.h:510
Header file for the uIP TCP/IP stack.
PROCESS_THREAD(cc2538_rf_process, ev, data)
Implementation of the cc2538 RF driver process.
Definition: cc2538-rf.c:1110
void tcpip_input(void)
Deliver an incoming packet to the TCP/IP stack.
Definition: tcpip.c:445