FreeRTOS
[armadillo_firmware.git] / FreeRTOS / Common / ethernet / FreeTCPIP / psock.c
blob6bd1f6affb94e1994281e8d672a2f5d981266571
1 /*
2 * Copyright (c) 2004, Swedish Institute of Computer Science.
3 * All rights reserved.
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.
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.
29 * This file is part of the uIP TCP/IP stack
31 * Author: Adam Dunkels <adam@sics.se>
33 * $Id: psock.c,v 1.2 2006/06/12 08:00:30 adam Exp $
36 #include <stdio.h>
37 #include <string.h>
39 #include "net/uipopt.h"
40 #include "net/psock.h"
41 #include "net/uip.h"
43 #define STATE_NONE 0
44 #define STATE_ACKED 1
45 #define STATE_READ 2
46 #define STATE_BLOCKED_NEWDATA 3
47 #define STATE_BLOCKED_CLOSE 4
48 #define STATE_BLOCKED_SEND 5
49 #define STATE_DATA_SENT 6
52 * Return value of the buffering functions that indicates that a
53 * buffer was not filled by incoming data.
56 #define BUF_NOT_FULL 0
57 #define BUF_NOT_FOUND 0
60 * Return value of the buffering functions that indicates that a
61 * buffer was completely filled by incoming data.
64 #define BUF_FULL 1
67 * Return value of the buffering functions that indicates that an
68 * end-marker byte was found.
71 #define BUF_FOUND 2
73 /*---------------------------------------------------------------------------*/
74 static void
75 buf_setup(struct psock_buf *buf,
76 u8_t *bufptr, u16_t bufsize)
78 buf->ptr = bufptr;
79 buf->left = bufsize;
81 /*---------------------------------------------------------------------------*/
82 static u8_t
83 buf_bufdata(struct psock_buf *buf, u16_t len,
84 u8_t **dataptr, u16_t *datalen)
86 ( void ) len;
87 if(*datalen < buf->left) {
88 memcpy(buf->ptr, *dataptr, *datalen);
89 buf->ptr += *datalen;
90 buf->left -= *datalen;
91 *dataptr += *datalen;
92 *datalen = 0;
93 return BUF_NOT_FULL;
94 } else if(*datalen == buf->left) {
95 memcpy(buf->ptr, *dataptr, *datalen);
96 buf->ptr += *datalen;
97 buf->left = 0;
98 *dataptr += *datalen;
99 *datalen = 0;
100 return BUF_FULL;
101 } else {
102 memcpy(buf->ptr, *dataptr, buf->left);
103 buf->ptr += buf->left;
104 *datalen -= buf->left;
105 *dataptr += buf->left;
106 buf->left = 0;
107 return BUF_FULL;
110 /*---------------------------------------------------------------------------*/
111 static u8_t
112 buf_bufto(register struct psock_buf *buf, u8_t endmarker,
113 register u8_t **dataptr, register u16_t *datalen)
115 u8_t c;
116 while(buf->left > 0 && *datalen > 0) {
117 c = *buf->ptr = **dataptr;
118 ++*dataptr;
119 ++buf->ptr;
120 --*datalen;
121 --buf->left;
123 if(c == endmarker) {
124 return BUF_FOUND;
128 if(*datalen == 0) {
129 return BUF_NOT_FOUND;
132 while(*datalen > 0) {
133 c = **dataptr;
134 --*datalen;
135 ++*dataptr;
137 if(c == endmarker) {
138 return BUF_FOUND | BUF_FULL;
142 return BUF_FULL;
144 /*---------------------------------------------------------------------------*/
145 static char
146 send_data(register struct psock *s)
148 if(s->state != STATE_DATA_SENT || uip_rexmit()) {
149 if(s->sendlen > uip_mss()) {
150 uip_send(s->sendptr, uip_mss());
151 } else {
152 uip_send(s->sendptr, s->sendlen);
154 s->state = STATE_DATA_SENT;
155 return 1;
157 return 0;
159 /*---------------------------------------------------------------------------*/
160 static char
161 data_acked(register struct psock *s)
163 if(s->state == STATE_DATA_SENT && uip_acked()) {
164 if(s->sendlen > uip_mss()) {
165 s->sendlen -= uip_mss();
166 s->sendptr += uip_mss();
167 } else {
168 s->sendptr += s->sendlen;
169 s->sendlen = 0;
171 s->state = STATE_ACKED;
172 return 1;
174 return 0;
176 /*---------------------------------------------------------------------------*/
177 PT_THREAD(psock_send(register struct psock *s, const char *buf,
178 unsigned int len))
180 PT_BEGIN(&s->psockpt);
182 /* If there is no data to send, we exit immediately. */
183 if(len == 0) {
184 PT_EXIT(&s->psockpt);
187 /* Save the length of and a pointer to the data that is to be
188 sent. */
189 s->sendptr = (unsigned char*)buf;
190 s->sendlen = (unsigned short)len;
192 s->state = STATE_NONE;
194 /* We loop here until all data is sent. The s->sendlen variable is
195 updated by the data_sent() function. */
196 while(s->sendlen > 0) {
199 * The condition for this PT_WAIT_UNTIL is a little tricky: the
200 * protothread will wait here until all data has been acknowledged
201 * (data_acked() returns true) and until all data has been sent
202 * (send_data() returns true). The two functions data_acked() and
203 * send_data() must be called in succession to ensure that all
204 * data is sent. Therefore the & operator is used instead of the
205 * && operator, which would cause only the data_acked() function
206 * to be called when it returns false.
208 PT_WAIT_UNTIL(&s->psockpt, data_acked(s) & send_data(s));
211 s->state = STATE_NONE;
213 PT_END(&s->psockpt);
215 /*---------------------------------------------------------------------------*/
216 PT_THREAD(psock_generator_send(register struct psock *s,
217 unsigned short (*generate)(void *), void *arg))
219 PT_BEGIN(&s->psockpt);
221 /* Ensure that there is a generator function to call. */
222 if(generate == NULL) {
223 PT_EXIT(&s->psockpt);
226 /* Call the generator function to generate the data in the
227 uip_appdata buffer. */
228 s->sendlen = generate(arg);
229 s->sendptr = uip_appdata;
231 s->state = STATE_NONE;
232 do {
233 /* Call the generator function again if we are called to perform a
234 retransmission. */
235 if(uip_rexmit()) {
236 generate(arg);
238 /* Wait until all data is sent and acknowledged. */
239 PT_WAIT_UNTIL(&s->psockpt, data_acked(s) & send_data(s));
240 } while(s->sendlen > 0);
242 s->state = STATE_NONE;
244 PT_END(&s->psockpt);
246 /*---------------------------------------------------------------------------*/
247 u16_t
248 psock_datalen(struct psock *psock)
250 return psock->bufsize - psock->buf.left;
252 /*---------------------------------------------------------------------------*/
253 char
254 psock_newdata(struct psock *s)
256 if(s->readlen > 0) {
257 /* There is data in the uip_appdata buffer that has not yet been
258 read with the PSOCK_READ functions. */
259 return 1;
260 } else if(s->state == STATE_READ) {
261 /* All data in uip_appdata buffer already consumed. */
262 s->state = STATE_BLOCKED_NEWDATA;
263 return 0;
264 } else if(uip_newdata()) {
265 /* There is new data that has not been consumed. */
266 return 1;
267 } else {
268 /* There is no new data. */
269 return 0;
272 /*---------------------------------------------------------------------------*/
273 PT_THREAD(psock_readto(register struct psock *psock, unsigned char c))
275 PT_BEGIN(&psock->psockpt);
277 buf_setup(&psock->buf, (unsigned char*)psock->bufptr, psock->bufsize);
279 /* XXX: Should add buf_checkmarker() before do{} loop, if
280 incoming data has been handled while waiting for a write. */
282 do {
283 if(psock->readlen == 0) {
284 PT_WAIT_UNTIL(&psock->psockpt, psock_newdata(psock));
285 psock->state = STATE_READ;
286 psock->readptr = (u8_t *)uip_appdata;
287 psock->readlen = uip_datalen();
289 } while((buf_bufto(&psock->buf, c,
290 &psock->readptr,
291 &psock->readlen) & BUF_FOUND) == 0);
293 if(psock_datalen(psock) == 0) {
294 psock->state = STATE_NONE;
295 PT_RESTART(&psock->psockpt);
297 PT_END(&psock->psockpt);
299 /*---------------------------------------------------------------------------*/
300 PT_THREAD(psock_readbuf(register struct psock *psock))
302 PT_BEGIN(&psock->psockpt);
304 buf_setup(&psock->buf, (unsigned char * ) psock->bufptr, psock->bufsize);
306 /* XXX: Should add buf_checkmarker() before do{} loop, if
307 incoming data has been handled while waiting for a write. */
309 do {
310 if(psock->readlen == 0) {
311 PT_WAIT_UNTIL(&psock->psockpt, psock_newdata(psock));
312 psock->state = STATE_READ;
313 psock->readptr = (u8_t *)uip_appdata;
314 psock->readlen = uip_datalen();
316 } while(buf_bufdata(&psock->buf, psock->bufsize,
317 &psock->readptr,
318 &psock->readlen) != BUF_FULL);
320 if(psock_datalen(psock) == 0) {
321 psock->state = STATE_NONE;
322 PT_RESTART(&psock->psockpt);
324 PT_END(&psock->psockpt);
326 /*---------------------------------------------------------------------------*/
327 void
328 psock_init(register struct psock *psock, char *buffer, unsigned int buffersize)
330 psock->state = STATE_NONE;
331 psock->readlen = 0;
332 psock->bufptr = buffer;
333 psock->bufsize = buffersize;
334 buf_setup(&psock->buf, (unsigned char*) buffer, buffersize);
335 PT_INIT(&psock->pt);
336 PT_INIT(&psock->psockpt);
338 /*---------------------------------------------------------------------------*/