]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/Common/ethernet/FreeRTOS-uIP/psock.c
Add FreeRTOS-Plus directory.
[freertos] / FreeRTOS / Demo / Common / ethernet / FreeRTOS-uIP / psock.c
1 /*\r
2  * Copyright (c) 2004, Swedish Institute of Computer Science.\r
3  * All rights reserved.\r
4  *\r
5  * Redistribution and use in source and binary forms, with or without\r
6  * modification, are permitted provided that the following conditions\r
7  * are met:\r
8  * 1. Redistributions of source code must retain the above copyright\r
9  *    notice, this list of conditions and the following disclaimer.\r
10  * 2. Redistributions in binary form must reproduce the above copyright\r
11  *    notice, this list of conditions and the following disclaimer in the\r
12  *    documentation and/or other materials provided with the distribution.\r
13  * 3. Neither the name of the Institute nor the names of its contributors\r
14  *    may be used to endorse or promote products derived from this software\r
15  *    without specific prior written permission.\r
16  *\r
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND\r
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE\r
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\r
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\r
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\r
27  * SUCH DAMAGE.\r
28  *\r
29  * This file is part of the uIP TCP/IP stack\r
30  *\r
31  * Author: Adam Dunkels <adam@sics.se>\r
32  *\r
33  * $Id: psock.c,v 1.1 2007/01/04 11:06:40 adamdunkels Exp $\r
34  */\r
35 #include <stdio.h>\r
36 #include <string.h>\r
37 \r
38 #include "uipopt.h"\r
39 #include "psock.h"\r
40 #include "uip.h"\r
41 \r
42 #define STATE_NONE                              0\r
43 #define STATE_ACKED                             1\r
44 #define STATE_READ                              2\r
45 #define STATE_BLOCKED_NEWDATA   3\r
46 #define STATE_BLOCKED_CLOSE             4\r
47 #define STATE_BLOCKED_SEND              5\r
48 #define STATE_DATA_SENT                 6\r
49 \r
50 /*\r
51  * Return value of the buffering functions that indicates that a\r
52  * buffer was not filled by incoming data.\r
53  *\r
54  */\r
55 #define BUF_NOT_FULL    0\r
56 #define BUF_NOT_FOUND   0\r
57 \r
58 /*\r
59  * Return value of the buffering functions that indicates that a\r
60  * buffer was completely filled by incoming data.\r
61  *\r
62  */\r
63 #define BUF_FULL        1\r
64 \r
65 /*\r
66  * Return value of the buffering functions that indicates that an\r
67  * end-marker byte was found.\r
68  *\r
69  */\r
70 #define BUF_FOUND       2\r
71 \r
72 /*---------------------------------------------------------------------------*/\r
73 static void buf_setup( struct psock_buf *buf, u8_t *bufptr, u16_t bufsize )\r
74 {\r
75         buf->ptr = bufptr;\r
76         buf->left = bufsize;\r
77 }\r
78 \r
79 /*---------------------------------------------------------------------------*/\r
80 static u8_t buf_bufdata( struct psock_buf *buf, u16_t len, u8_t **dataptr, u16_t *datalen )\r
81 {\r
82         ( void ) len;\r
83 \r
84         if( *datalen < buf->left )\r
85         {\r
86                 memcpy( buf->ptr, *dataptr, *datalen );\r
87                 buf->ptr += *datalen;\r
88                 buf->left -= *datalen;\r
89                 *dataptr += *datalen;\r
90                 *datalen = 0;\r
91                 return BUF_NOT_FULL;\r
92         }\r
93         else if( *datalen == buf->left )\r
94         {\r
95                 memcpy( buf->ptr, *dataptr, *datalen );\r
96                 buf->ptr += *datalen;\r
97                 buf->left = 0;\r
98                 *dataptr += *datalen;\r
99                 *datalen = 0;\r
100                 return BUF_FULL;\r
101         }\r
102         else\r
103         {\r
104                 memcpy( buf->ptr, *dataptr, buf->left );\r
105                 buf->ptr += buf->left;\r
106                 *datalen -= buf->left;\r
107                 *dataptr += buf->left;\r
108                 buf->left = 0;\r
109                 return BUF_FULL;\r
110         }\r
111 }\r
112 \r
113 /*---------------------------------------------------------------------------*/\r
114 static u8_t buf_bufto( register struct psock_buf *buf, u8_t endmarker, register u8_t **dataptr, register u16_t *datalen )\r
115 {\r
116         u8_t    c;\r
117         while( buf->left > 0 && *datalen > 0 )\r
118         {\r
119                 c = *buf->ptr = **dataptr;\r
120                 ++ *dataptr;\r
121                 ++buf->ptr;\r
122                 -- *datalen;\r
123                 --buf->left;\r
124 \r
125                 if( c == endmarker )\r
126                 {\r
127                         return BUF_FOUND;\r
128                 }\r
129         }\r
130 \r
131         if( *datalen == 0 )\r
132         {\r
133                 return BUF_NOT_FOUND;\r
134         }\r
135 \r
136         while( *datalen > 0 )\r
137         {\r
138                 c = **dataptr;\r
139                 -- *datalen;\r
140                 ++ *dataptr;\r
141 \r
142                 if( c == endmarker )\r
143                 {\r
144                         return BUF_FOUND | BUF_FULL;\r
145                 }\r
146         }\r
147 \r
148         return BUF_FULL;\r
149 }\r
150 \r
151 /*---------------------------------------------------------------------------*/\r
152 static char send_data( register struct psock *s )\r
153 {\r
154         if( s->state != STATE_DATA_SENT || uip_rexmit() )\r
155         {\r
156                 if( s->sendlen > uip_mss() )\r
157                 {\r
158                         uip_send( s->sendptr, uip_mss() );\r
159                 }\r
160                 else\r
161                 {\r
162                         uip_send( s->sendptr, s->sendlen );\r
163                 }\r
164 \r
165                 s->state = STATE_DATA_SENT;\r
166                 return 1;\r
167         }\r
168 \r
169         return 0;\r
170 }\r
171 \r
172 /*---------------------------------------------------------------------------*/\r
173 static char data_acked( register struct psock *s )\r
174 {\r
175         if( s->state == STATE_DATA_SENT && uip_acked() )\r
176         {\r
177                 if( s->sendlen > uip_mss() )\r
178                 {\r
179                         s->sendlen -= uip_mss();\r
180                         s->sendptr += uip_mss();\r
181                 }\r
182                 else\r
183                 {\r
184                         s->sendptr += s->sendlen;\r
185                         s->sendlen = 0;\r
186                 }\r
187 \r
188                 s->state = STATE_ACKED;\r
189                 return 1;\r
190         }\r
191 \r
192         return 0;\r
193 }\r
194 \r
195 /*---------------------------------------------------------------------------*/\r
196 PT_THREAD( psock_send ( register struct psock *s, const char *buf, unsigned int len ) )\r
197 {\r
198         PT_BEGIN( &s->psockpt );\r
199 \r
200         /* If there is no data to send, we exit immediately. */\r
201         if( len == 0 )\r
202         {\r
203                 PT_EXIT( &s->psockpt );\r
204         }\r
205 \r
206         /* Save the length of and a pointer to the data that is to be\r
207      sent. */\r
208         s->sendptr = ( u8_t * ) buf;\r
209         s->sendlen = len;\r
210 \r
211         s->state = STATE_NONE;\r
212 \r
213         /* We loop here until all data is sent. The s->sendlen variable is\r
214      updated by the data_sent() function. */\r
215         while( s->sendlen > 0 )\r
216         {\r
217                 /*\r
218      * The condition for this PT_WAIT_UNTIL is a little tricky: the\r
219      * protothread will wait here until all data has been acknowledged\r
220      * (data_acked() returns true) and until all data has been sent\r
221      * (send_data() returns true). The two functions data_acked() and\r
222      * send_data() must be called in succession to ensure that all\r
223      * data is sent. Therefore the & operator is used instead of the\r
224      * && operator, which would cause only the data_acked() function\r
225      * to be called when it returns false.\r
226      */\r
227                 PT_WAIT_UNTIL( &s->psockpt, data_acked(s) & send_data(s) );\r
228         }\r
229 \r
230         s->state = STATE_NONE;\r
231 \r
232         PT_END( &s->psockpt );\r
233 }\r
234 \r
235 /*---------------------------------------------------------------------------*/\r
236 PT_THREAD( psock_generator_send ( register struct psock *s, unsigned short ( *generate ) ( void * ), void *arg ) )\r
237 {\r
238         PT_BEGIN( &s->psockpt );\r
239 \r
240         /* Ensure that there is a generator function to call. */\r
241         if( generate == NULL )\r
242         {\r
243                 PT_EXIT( &s->psockpt );\r
244         }\r
245 \r
246         /* Call the generator function to generate the data in the\r
247      uip_appdata buffer. */\r
248         s->sendlen = generate( arg );\r
249         s->sendptr = uip_appdata;\r
250 \r
251         s->state = STATE_NONE;\r
252         do\r
253         {\r
254                 /* Call the generator function again if we are called to perform a\r
255        retransmission. */\r
256                 if( uip_rexmit() )\r
257                 {\r
258                         generate( arg );\r
259                 }\r
260 \r
261                 /* Wait until all data is sent and acknowledged. */\r
262                 PT_WAIT_UNTIL( &s->psockpt, data_acked(s) & send_data(s) );\r
263         } while( s->sendlen > 0 );\r
264 \r
265         s->state = STATE_NONE;\r
266 \r
267         PT_END( &s->psockpt );\r
268 }\r
269 \r
270 /*---------------------------------------------------------------------------*/\r
271 u16_t psock_datalen( struct psock *psock )\r
272 {\r
273         return psock->bufsize - psock->buf.left;\r
274 }\r
275 \r
276 /*---------------------------------------------------------------------------*/\r
277 char psock_newdata( struct psock *s )\r
278 {\r
279         if( s->readlen > 0 )\r
280         {\r
281                 /* There is data in the uip_appdata buffer that has not yet been\r
282        read with the PSOCK_READ functions. */\r
283                 return 1;\r
284         }\r
285         else if( s->state == STATE_READ )\r
286         {\r
287                 /* All data in uip_appdata buffer already consumed. */\r
288                 s->state = STATE_BLOCKED_NEWDATA;\r
289                 return 0;\r
290         }\r
291         else if( uip_newdata() )\r
292         {\r
293                 /* There is new data that has not been consumed. */\r
294                 return 1;\r
295         }\r
296         else\r
297         {\r
298                 /* There is no new data. */\r
299                 return 0;\r
300         }\r
301 }\r
302 \r
303 /*---------------------------------------------------------------------------*/\r
304 PT_THREAD( psock_readto ( register struct psock *psock, unsigned char c ) )\r
305 {\r
306         PT_BEGIN( &psock->psockpt );\r
307 \r
308         buf_setup( &psock->buf, ( u8_t * ) psock->bufptr, psock->bufsize );\r
309 \r
310         /* XXX: Should add buf_checkmarker() before do{} loop, if\r
311      incoming data has been handled while waiting for a write. */\r
312         do\r
313         {\r
314                 if( psock->readlen == 0 )\r
315                 {\r
316                         PT_WAIT_UNTIL( &psock->psockpt, psock_newdata(psock) );\r
317                         psock->state = STATE_READ;\r
318                         psock->readptr = ( u8_t * ) uip_appdata;\r
319                         psock->readlen = uip_datalen();\r
320                 }\r
321         } while( (buf_bufto(&psock->buf, c, &psock->readptr, &psock->readlen) & BUF_FOUND) == 0 );\r
322 \r
323         if( psock_datalen(psock) == 0 )\r
324         {\r
325                 psock->state = STATE_NONE;\r
326                 PT_RESTART( &psock->psockpt );\r
327         }\r
328 \r
329         PT_END( &psock->psockpt );\r
330 }\r
331 \r
332 /*---------------------------------------------------------------------------*/\r
333 PT_THREAD( psock_readbuf ( register struct psock *psock ) )\r
334 {\r
335         PT_BEGIN( &psock->psockpt );\r
336 \r
337         buf_setup( &psock->buf, ( u8_t * ) psock->bufptr, psock->bufsize );\r
338 \r
339         /* XXX: Should add buf_checkmarker() before do{} loop, if\r
340      incoming data has been handled while waiting for a write. */\r
341         do\r
342         {\r
343                 if( psock->readlen == 0 )\r
344                 {\r
345                         PT_WAIT_UNTIL( &psock->psockpt, psock_newdata(psock) );\r
346                         printf( "Waited for newdata\n" );\r
347                         psock->state = STATE_READ;\r
348                         psock->readptr = ( u8_t * ) uip_appdata;\r
349                         psock->readlen = uip_datalen();\r
350                 }\r
351         } while( buf_bufdata(&psock->buf, psock->bufsize, &psock->readptr, &psock->readlen) != BUF_FULL );\r
352 \r
353         if( psock_datalen(psock) == 0 )\r
354         {\r
355                 psock->state = STATE_NONE;\r
356                 PT_RESTART( &psock->psockpt );\r
357         }\r
358 \r
359         PT_END( &psock->psockpt );\r
360 }\r
361 \r
362 /*---------------------------------------------------------------------------*/\r
363 void psock_init( register struct psock *psock, char *buffer, unsigned int buffersize )\r
364 {\r
365         psock->state = STATE_NONE;\r
366         psock->readlen = 0;\r
367         psock->bufptr = buffer;\r
368         psock->bufsize = buffersize;\r
369         buf_setup( &psock->buf, ( u8_t * ) buffer, buffersize );\r
370         PT_INIT( &psock->pt );\r
371         PT_INIT( &psock->psockpt );\r
372 }\r
373 \r
374 /*---------------------------------------------------------------------------*/\r