Contiki-NG
Loading...
Searching...
No Matches
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/*---------------------------------------------------------------------------*/
45#if SLIP_CONF_WITH_STATS
46static uint16_t slip_rubbish, slip_twopackets, slip_overflow, slip_ip_drop;
47#define SLIP_STATISTICS(statement) statement
48#else
49#define SLIP_STATISTICS(statement)
50#endif
51/*---------------------------------------------------------------------------*/
52/* Must be at least one byte larger than UIP_BUFSIZE! */
53#define RX_BUFSIZE (UIP_BUFSIZE + 16)
54/*---------------------------------------------------------------------------*/
55enum {
56 STATE_TWOPACKETS = 0, /* We have 2 packets and drop incoming data. */
57 STATE_OK = 1,
58 STATE_ESC = 2,
59 STATE_RUBBISH = 3,
60};
61/*---------------------------------------------------------------------------*/
62/*
63 * Variables begin and end manage the buffer space in a cyclic
64 * fashion. The first used byte is at begin and end is one byte past
65 * the last. I.e. [begin, end) is the actively used space.
66 *
67 * If begin != pkt_end we have a packet at [begin, pkt_end),
68 * furthermore, if state == STATE_TWOPACKETS we have one more packet at
69 * [pkt_end, end). If more bytes arrive in state STATE_TWOPACKETS
70 * they are discarded.
71 */
72static uint8_t state = STATE_TWOPACKETS;
73static uint16_t begin, next_free;
74static uint8_t rxbuf[RX_BUFSIZE];
75static uint16_t pkt_end; /* SLIP_END tracker. */
76
77static void (*input_callback)(void) = NULL;
78/*---------------------------------------------------------------------------*/
79void
80slip_set_input_callback(void (*c)(void))
81{
82 input_callback = c;
83}
84/*---------------------------------------------------------------------------*/
85void
86slip_send(void)
87{
88 slip_write(uip_buf, uip_len);
89}
90/*---------------------------------------------------------------------------*/
91void
92slip_write(const void *_ptr, int len)
93{
94 const uint8_t *ptr = _ptr;
95 uint16_t i;
96 uint8_t c;
97
98 slip_arch_writeb(SLIP_END);
99
100 for(i = 0; i < len; ++i) {
101 c = *ptr++;
102 if(c == SLIP_END) {
103 slip_arch_writeb(SLIP_ESC);
104 c = SLIP_ESC_END;
105 } else if(c == SLIP_ESC) {
106 slip_arch_writeb(SLIP_ESC);
107 c = SLIP_ESC_ESC;
108 }
109 slip_arch_writeb(c);
110 }
111
112 slip_arch_writeb(SLIP_END);
113}
114/*---------------------------------------------------------------------------*/
115static void
116rxbuf_init(void)
117{
118 begin = next_free = pkt_end = 0;
119 state = STATE_OK;
120}
121/*---------------------------------------------------------------------------*/
122static uint16_t
123slip_poll_handler(uint8_t *outbuf, uint16_t blen)
124{
125 /*
126 * Interrupt can not change begin but may change pkt_end.
127 * If pkt_end != begin it will not change again.
128 */
129 if(begin != pkt_end) {
130 uint16_t len;
131 uint16_t cur_next_free;
132 uint16_t cur_ptr;
133 int esc = 0;
134
135 if(begin < pkt_end) {
136 uint16_t i;
137 len = 0;
138 for(i = begin; i < pkt_end; ++i) {
139 if(len > blen) {
140 len = 0;
141 break;
142 }
143 if(esc) {
144 if(rxbuf[i] == SLIP_ESC_ESC) {
145 outbuf[len] = SLIP_ESC;
146 len++;
147 } else if(rxbuf[i] == SLIP_ESC_END) {
148 outbuf[len] = SLIP_END;
149 len++;
150 }
151 esc = 0;
152 } else if(rxbuf[i] == SLIP_ESC) {
153 esc = 1;
154 } else {
155 outbuf[len] = rxbuf[i];
156 len++;
157 }
158 }
159 } else {
160 uint16_t i;
161 len = 0;
162 for(i = begin; i < RX_BUFSIZE; ++i) {
163 if(len > blen) {
164 len = 0;
165 break;
166 }
167 if(esc) {
168 if(rxbuf[i] == SLIP_ESC_ESC) {
169 outbuf[len] = SLIP_ESC;
170 len++;
171 } else if(rxbuf[i] == SLIP_ESC_END) {
172 outbuf[len] = SLIP_END;
173 len++;
174 }
175 esc = 0;
176 } else if(rxbuf[i] == SLIP_ESC) {
177 esc = 1;
178 } else {
179 outbuf[len] = rxbuf[i];
180 len++;
181 }
182 }
183 for(i = 0; i < pkt_end; ++i) {
184 if(len > blen) {
185 len = 0;
186 break;
187 }
188 if(esc) {
189 if(rxbuf[i] == SLIP_ESC_ESC) {
190 outbuf[len] = SLIP_ESC;
191 len++;
192 } else if(rxbuf[i] == SLIP_ESC_END) {
193 outbuf[len] = SLIP_END;
194 len++;
195 }
196 esc = 0;
197 } else if(rxbuf[i] == SLIP_ESC) {
198 esc = 1;
199 } else {
200 outbuf[len] = rxbuf[i];
201 len++;
202 }
203 }
204 }
205
206 /* Remove data from buffer together with the copied packet. */
207 pkt_end = pkt_end + 1;
208 if(pkt_end == RX_BUFSIZE) {
209 pkt_end = 0;
210 }
211 if(pkt_end != next_free) {
212 cur_next_free = next_free;
213 cur_ptr = pkt_end;
214 while(cur_ptr != cur_next_free) {
215 if(rxbuf[cur_ptr] == SLIP_END) {
216 uint16_t tmp_begin = pkt_end;
217 pkt_end = cur_ptr;
218 begin = tmp_begin;
219 /* One more packet is buffered, need to be polled again! */
220 process_poll(&slip_process);
221 break;
222 }
223 cur_ptr++;
224 if(cur_ptr == RX_BUFSIZE) {
225 cur_ptr = 0;
226 }
227 }
228 if(cur_ptr == cur_next_free) {
229 /* no more pending full packet found */
230 begin = pkt_end;
231 }
232 } else {
233 begin = pkt_end;
234 }
235 return len;
236 }
237
238 return 0;
239}
240/*---------------------------------------------------------------------------*/
241PROCESS_THREAD(slip_process, ev, data)
242{
244
245 rxbuf_init();
246
247 while(1) {
248 PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL);
249 /* Move packet from rxbuf to buffer provided by uIP. */
250 uip_len = slip_poll_handler(uip_buf, UIP_BUFSIZE);
251
252 if(uip_len > 0) {
253 if(input_callback) {
254 input_callback();
255 }
256 tcpip_input();
257 }
258 }
259
260 PROCESS_END();
261}
262/*---------------------------------------------------------------------------*/
263int
264slip_input_byte(unsigned char c)
265{
266 uint16_t cur_end;
267 switch(state) {
268 case STATE_RUBBISH:
269 if(c == SLIP_END) {
270 state = STATE_OK;
271 }
272 return 0;
273
274 case STATE_ESC:
275 if(c != SLIP_ESC_END && c != SLIP_ESC_ESC) {
276 state = STATE_RUBBISH;
277 SLIP_STATISTICS(slip_rubbish++);
278 next_free = pkt_end; /* remove rubbish */
279 return 0;
280 }
281 state = STATE_OK;
282 break;
283 }
284
285 if(c == SLIP_ESC) {
286 state = STATE_ESC;
287 }
288
289 /* add_char: */
290 cur_end = next_free;
291 next_free = next_free + 1;
292 if(next_free == RX_BUFSIZE) {
293 next_free = 0;
294 }
295 if(next_free == begin) { /* rxbuf is full */
296 state = STATE_RUBBISH;
297 SLIP_STATISTICS(slip_overflow++);
298 next_free = pkt_end; /* remove rubbish */
299 return 0;
300 }
301 rxbuf[cur_end] = c;
302
303 if(c == SLIP_END) {
304 /*
305 * We have a new packet, possibly of zero length.
306 *
307 * There may already be one packet buffered.
308 */
309 if(cur_end != pkt_end) { /* Non zero length. */
310 if(begin == pkt_end) { /* None buffered. */
311 pkt_end = cur_end;
312 } else {
313 SLIP_STATISTICS(slip_twopackets++);
314 }
315 process_poll(&slip_process);
316 return 1;
317 } else {
318 /* Empty packet, reset the pointer */
319 next_free = cur_end;
320 }
321 return 0;
322 }
323
324 return 0;
325}
326/*---------------------------------------------------------------------------*/
#define PROCESS(name, strname)
Declare a process.
Definition process.h:308
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition process.h:121
#define PROCESS_END()
Define the end of a process.
Definition process.h:132
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
Definition process.h:274
#define PROCESS_YIELD_UNTIL(c)
Yield the currently running process until a condition occurs.
Definition process.h:179
void process_poll(struct process *p)
Request a process to be polled.
Definition process.c:366
void tcpip_input(void)
Deliver an incoming packet to the TCP/IP stack.
Definition tcpip.c:433
#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.