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/*---------------------------------------------------------------------------*/
43PROCESS(slip_process, "SLIP driver");
44/*---------------------------------------------------------------------------*/
45static uint8_t slip_active;
46/*---------------------------------------------------------------------------*/
47#if SLIP_CONF_WITH_STATS
48static 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/*---------------------------------------------------------------------------*/
57enum {
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 */
74static uint8_t state = STATE_TWOPACKETS;
75static uint16_t begin, next_free;
76static uint8_t rxbuf[RX_BUFSIZE];
77static uint16_t pkt_end; /* SLIP_END tracker. */
78
79static void (*input_callback)(void) = NULL;
80/*---------------------------------------------------------------------------*/
81void
82slip_set_input_callback(void (*c)(void))
83{
84 input_callback = c;
85}
86/*---------------------------------------------------------------------------*/
87void
88slip_send(void)
89{
90 slip_write(uip_buf, uip_len);
91}
92/*---------------------------------------------------------------------------*/
93void
94slip_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 }
112 }
113
114 slip_arch_writeb(SLIP_END);
115}
116/*---------------------------------------------------------------------------*/
117static void
118rxbuf_init(void)
119{
120 begin = next_free = pkt_end = 0;
121 state = STATE_OK;
122}
123/*---------------------------------------------------------------------------*/
124static uint16_t
125slip_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/*---------------------------------------------------------------------------*/
243PROCESS_THREAD(slip_process, ev, data)
244{
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/*---------------------------------------------------------------------------*/
268int
269slip_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_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:1154
#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.