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 - UIP_LLH_LEN + 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_LLH_LEN],
256  UIP_BUFSIZE - UIP_LLH_LEN);
257 
258  if(uip_len > 0) {
259  if(input_callback) {
260  input_callback();
261  }
262  tcpip_input();
263  }
264  }
265 
266  PROCESS_END();
267 }
268 /*---------------------------------------------------------------------------*/
269 int
270 slip_input_byte(unsigned char c)
271 {
272  uint16_t cur_end;
273  switch(state) {
274  case STATE_RUBBISH:
275  if(c == SLIP_END) {
276  state = STATE_OK;
277  }
278  return 0;
279 
280  case STATE_ESC:
281  if(c != SLIP_ESC_END && c != SLIP_ESC_ESC) {
282  state = STATE_RUBBISH;
283  SLIP_STATISTICS(slip_rubbish++);
284  next_free = pkt_end; /* remove rubbish */
285  return 0;
286  }
287  state = STATE_OK;
288  break;
289  }
290 
291  if(c == SLIP_ESC) {
292  state = STATE_ESC;
293  }
294 
295  /* add_char: */
296  cur_end = next_free;
297  next_free = next_free + 1;
298  if(next_free == RX_BUFSIZE) {
299  next_free = 0;
300  }
301  if(next_free == begin) { /* rxbuf is full */
302  state = STATE_RUBBISH;
303  SLIP_STATISTICS(slip_overflow++);
304  next_free = pkt_end; /* remove rubbish */
305  return 0;
306  }
307  rxbuf[cur_end] = c;
308 
309  if(c == SLIP_END) {
310  /*
311  * We have a new packet, possibly of zero length.
312  *
313  * There may already be one packet buffered.
314  */
315  if(cur_end != pkt_end) { /* Non zero length. */
316  if(begin == pkt_end) { /* None buffered. */
317  pkt_end = cur_end;
318  } else {
319  SLIP_STATISTICS(slip_twopackets++);
320  }
321  process_poll(&slip_process);
322  return 1;
323  } else {
324  /* Empty packet, reset the pointer */
325  next_free = cur_end;
326  }
327  return 0;
328  }
329 
330  return 0;
331 }
332 /*---------------------------------------------------------------------------*/
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:142
#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:171
uint16_t uip_len
The length of the packet in the uip_buf buffer.
Definition: uip6.c:179
#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:154
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:190
int slip_input_byte(unsigned char c)
Input a SLIP byte.
Definition: slip.c:353
void process_poll(struct process *p)
Request a process to be polled.
Definition: process.c:371
#define UIP_LLH_LEN
The link level header length.
Definition: uipopt.h:141
#define uip_buf
Macro to access uip_aligned_buf as an array of bytes.
Definition: uip.h:513
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:1035
void tcpip_input(void)
Deliver an incoming packet to the TCP/IP stack.
Definition: tcpip.c:449