RF24Ethernet - TCP/IP over RF24Network v1.6.12
TMRh20 - Pushing the practical limits of RF24 modules
Loading...
Searching...
No Matches
RF24Client.cpp
Go to the documentation of this file.
1/*
2 RF24Client.cpp - Arduino implementation of a uIP wrapper class.
3 Copyright (c) 2014 tmrh20@gmail.com, github.com/TMRh20
4 Copyright (c) 2013 Norbert Truchsess <norbert.truchsess@t-online.de>
5 All rights reserved.
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17#include "RF24Ethernet.h"
18
19#define UIP_TCP_PHYH_LEN UIP_LLH_LEN + UIP_IPTCPH_LEN
20
21uip_userdata_t RF24Client::all_data[UIP_CONNS];
22
23/*************************************************************/
24
25RF24Client::RF24Client() : data(NULL) {}
26
27/*************************************************************/
28
29RF24Client::RF24Client(uip_userdata_t* conn_data) : data(conn_data) {}
30
31/*************************************************************/
32
34{
35 return (data && (data->packets_in != 0 || (data->state & UIP_CLIENT_CONNECTED))) ? 1 : 0;
36}
37
38/*************************************************************/
39
40int RF24Client::connect(IPAddress ip, uint16_t port)
41{
42#if UIP_ACTIVE_OPEN > 0
43
44 //do{
45
46 stop();
47 uip_ipaddr_t ipaddr;
48 uip_ip_addr(ipaddr, ip);
49
50 struct uip_conn* conn = uip_connect(&ipaddr, htons(port));
51
52 if (conn)
53 {
54 #if UIP_CONNECTION_TIMEOUT > 0
55 uint32_t timeout = millis();
56 #endif
57
58 while ((conn->tcpstateflags & UIP_TS_MASK) != UIP_CLOSED)
59 {
60 RF24EthernetClass::tick();
61
62 if ((conn->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED)
63 {
64 data = (uip_userdata_t*)conn->appstate;
65 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print(millis()); Serial.print(F(" connected, state: ")); Serial.print(data->state); Serial.print(F(", first packet in: ")); Serial.println(data->packets_in););
66 return 1;
67 }
68
69 #if UIP_CONNECTION_TIMEOUT > 0
70 if ((millis() - timeout) > UIP_CONNECTION_TIMEOUT)
71 {
72 conn->tcpstateflags = UIP_CLOSED;
73 break;
74 }
75 #endif
76 }
77 }
78 //delay(25);
79 //}while(millis()-timer < 175);
80
81#endif //Active open enabled
82
83 return 0;
84}
85
86/*************************************************************/
87
88int RF24Client::connect(const char* host, uint16_t port)
89{
90 // Look up the host first
91 int ret = 0;
92
93#if UIP_UDP
94 DNSClient dns;
95 IPAddress remote_addr;
96
97 dns.begin(RF24EthernetClass::_dnsServerAddress);
98 ret = dns.getHostByName(host, remote_addr);
99
100 if (ret == 1)
101 {
102 #if defined(ETH_DEBUG_L1) || #defined(RF24ETHERNET_DEBUG_DNS)
103 Serial.println(F("*UIP Got DNS*"));
104 #endif
105 return connect(remote_addr, port);
106 }
107#else // ! UIP_UDP
108 //Do something with the input parameters to prevent compile time warnings
109 if (host) {
110 };
111 if (port) {
112 };
113#endif // ! UIP_UDP
114
115#if defined(ETH_DEBUG_L1) || defined(RF24ETHERNET_DEBUG_DNS)
116 Serial.println(F("*UIP DNS fail*"));
117#endif
118
119 return ret;
120}
121
122/*************************************************************/
123
125{
126 if (data && data->state)
127 {
128
129 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print(millis()); Serial.println(F(" before stop(), with data")););
130
131 data->packets_in = 0;
132 data->dataCnt = 0;
133
134 if (data->state & UIP_CLIENT_REMOTECLOSED)
135 {
136 data->state = 0;
137 }
138 else
139 {
140 data->state |= UIP_CLIENT_CLOSE;
141 }
142
143 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(F("after stop()")););
144 }
145 else
146 {
147 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print(millis()); Serial.println(F(" stop(), data: NULL")););
148 }
149
150 data = NULL;
151 RF24Ethernet.tick();
152}
153
154/*************************************************************/
155
156// the next function allows us to use the client returned by
157// EthernetServer::available() as the condition in an if-statement.
159{
160 return data && rhs.data && (data == rhs.data);
161}
162
163/*************************************************************/
164
165RF24Client::operator bool()
166{
167 Ethernet.tick();
168 return data && (!(data->state & UIP_CLIENT_REMOTECLOSED) || data->packets_in != 0);
169}
170
171/*************************************************************/
172
173size_t RF24Client::write(uint8_t c)
174{
175 return _write(data, &c, 1);
176}
177
178/*************************************************************/
180size_t RF24Client::write(const uint8_t* buf, size_t size)
181{
182 return _write(data, buf, size);
183}
184
185/*************************************************************/
186
187size_t RF24Client::_write(uip_userdata_t* u, const uint8_t* buf, size_t size)
188{
189
190 size_t total_written = 0;
191 size_t payloadSize = rf24_min(size, UIP_TCP_MSS);
192
193test2:
194
195 RF24EthernetClass::tick();
196 if (u && !(u->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED)) && u->state & (UIP_CLIENT_CONNECTED))
197 {
198
199 if (u->out_pos + payloadSize > UIP_TCP_MSS || u->hold)
200 {
201 goto test2;
202 }
203
204 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(); Serial.print(millis()); Serial.print(F(" UIPClient.write: writePacket(")); Serial.print(u->packets_out); Serial.print(F(") pos: ")); Serial.print(u->out_pos); Serial.print(F(", buf[")); Serial.print(size - total_written); Serial.print(F("]: '")); Serial.write((uint8_t*)buf + total_written, payloadSize); Serial.println(F("'")););
205
206 memcpy(u->myData + u->out_pos, buf + total_written, payloadSize);
207 u->packets_out = 1;
208 u->out_pos += payloadSize;
209
210 total_written += payloadSize;
211
212 if (total_written < size)
213 {
214 size_t remain = size - total_written;
215 payloadSize = rf24_min(remain, UIP_TCP_MSS);
216
217 //RF24EthernetClass::tick();
218 goto test2;
219 }
220 return u->out_pos;
221 }
222 u->hold = false;
223 return -1;
224}
225
226/*************************************************************/
227
228void uip_log(char* msg)
229{
230 //Serial.println();
231 //Serial.println("** UIP LOG **");
232 //Serial.println(msg);
233 if (msg)
234 {
235 };
236}
237
238/*************************************************************/
239
241{
242 uip_userdata_t* u = (uip_userdata_t*)uip_conn->appstate;
243
244 if (u && u->connectTimeout > 0) {
245 if (millis() - u->connectTimer > u->connectTimeout && u->initialData == false) {
246 uip_close();
247 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(); Serial.print(millis()); Serial.println("UIP Client close(timeout)"););
248 }
249 }
250
251 /*******Connected**********/
252 if (!u && uip_connected())
253 {
254 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(); Serial.print(millis()); Serial.println(F(" UIPClient uip_connected")););
255
256 u = (uip_userdata_t*)EthernetClient::_allocateData();
257
258 if (u)
259 {
260 uip_conn->appstate = u;
261 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print(F("UIPClient allocated state: ")); Serial.println(u->state, BIN););
262 }
263 else
264 {
265 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(F("UIPClient allocation failed")););
266 }
267 }
268
269 /*******User Data RX**********/
270 if (u)
271 {
272 if (uip_newdata())
273 {
274 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(); Serial.print(millis()); Serial.print(F(" UIPClient uip_newdata, uip_len:")); Serial.println(uip_len););
275
276 u->initialData = true;
277
278 if (u->sent)
279 {
280 u->hold = (u->out_pos = (u->windowOpened = (u->packets_out = false)));
281 }
282 if (uip_len && !(u->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED)))
283 {
284 uip_stop();
285 u->state &= ~UIP_CLIENT_RESTART;
286 u->windowOpened = false;
287 u->connAbortTime = u->restartTime = millis();
288 memcpy(&u->myData[u->dataPos + u->dataCnt], uip_appdata, uip_datalen());
289 u->dataCnt += uip_datalen();
290
291 u->packets_in = 1;
292 }
293 goto finish;
294 }
295
296 /*******Closed/Timed-out/Aborted**********/
297 // If the connection has been closed, save received but unread data.
298 if (uip_closed() || uip_timedout() || uip_aborted())
299 {
300 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(); Serial.print(millis()); Serial.println(F(" UIPClient uip_closed")););
301 // drop outgoing packets not sent yet:
302 u->packets_out = 0;
303
304 if (u->packets_in)
305 {
306 ((uip_userdata_closed_t*)u)->lport = uip_conn->lport;
307 u->state |= UIP_CLIENT_REMOTECLOSED;
308 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(F("UIPClient close 1")););
309 }
310 else
311 {
312 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(F("UIPClient close 2")););
313 u->state = 0;
314 }
315
316 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(F("after UIPClient uip_closed")););
317 uip_conn->appstate = NULL;
318 goto finish;
319 }
320
321 /*******ACKED**********/
322 if (uip_acked())
323 {
324 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(); Serial.print(millis()); Serial.println(F(" UIPClient uip_acked")););
325 u->state &= ~UIP_CLIENT_RESTART;
326 u->hold = (u->out_pos = (u->windowOpened = (u->packets_out = false)));
327 u->connAbortTime = (u->restartTime = millis());
328 }
329
330 /*******Polling**********/
331 if (uip_poll() || uip_rexmit())
332 {
333 //IF_RF24ETHERNET_DEBUG_CLIENT( Serial.println(); Serial.println(F("UIPClient uip_poll")); );
334
335 if (u->packets_out != 0)
336 {
337 uip_len = u->out_pos;
338 uip_send(u->myData, u->out_pos);
339 u->hold = true;
340 u->sent = true;
341 goto finish;
342 }
343 else
344 // Restart mechanism to keep connections going
345 // Only call this if the TCP window has already been re-opened, the connection is being polled, but no data
346 // has been acked
347 if (!(u->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED)))
348 {
349
350 if (u->windowOpened == true && u->state & UIP_CLIENT_RESTART && millis() - u->restartTime > u->restartInterval)
351 {
352 u->restartTime = millis();
353// Abort the connection if the connection is dead after a set timeout period (uip-conf.h)
354#if defined UIP_CONNECTION_TIMEOUT
355 if (millis() - u->connAbortTime >= UIP_CONNECTION_TIMEOUT)
356 {
357 #if defined RF24ETHERNET_DEBUG_CLIENT || defined ETH_DEBUG_L1
358 Serial.println();
359 Serial.print(millis());
360 Serial.println(F(" *********** ABORTING CONNECTION ***************"));
361 #endif
362 u->windowOpened = false;
363 u->state = 0;
364 uip_conn->appstate = NULL;
365 uip_abort();
366 goto finish;
367 }
368 else
369 {
370#endif
371#if defined RF24ETHERNET_DEBUG_CLIENT || defined ETH_DEBUG_L1
372 Serial.println();
373 Serial.print(millis());
374 Serial.print(F(" UIPClient Re-Open TCP Window, time remaining before abort: "));
375 Serial.println((UIP_CONNECTION_TIMEOUT - (millis() - u->connAbortTime)) / 1000.00);
376#endif
377 u->restartInterval += 500;
378 u->restartInterval = rf24_min(u->restartInterval, 7000);
379 uip_restart();
380#if defined UIP_CONNECTION_TIMEOUT
381 }
382#endif
383 }
384 }
385 }
386
387 /*******Close**********/
388 if (u->state & UIP_CLIENT_CLOSE)
389 {
390 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(); Serial.print(millis()); Serial.println(F(" UIPClient state UIP_CLIENT_CLOSE")););
391
392 if (u->packets_out == 0)
393 {
394 u->state = 0;
395 uip_conn->appstate = NULL;
396 uip_close();
397 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(F("no blocks out -> free userdata")););
398 }
399 else
400 {
401 uip_stop();
402 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(F("blocks outstanding transfer -> uip_stop()")););
403 }
404 }
405finish:;
406
407 if (u->state & UIP_CLIENT_RESTART && !u->windowOpened)
408 {
409 if (!(u->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED)))
410 {
411 uip_restart();
412#if defined ETH_DEBUG_L1
413 Serial.println();
414 Serial.print(millis());
415 Serial.println(F(" UIPClient Re-Open TCP Window"));
416#endif
417 u->windowOpened = true;
418 u->restartInterval = UIP_WINDOW_REOPEN_DELAY; //.75 seconds
419 u->restartTime = u->connAbortTime = millis();
420 }
421 }
422 }
423}
424
425/*******************************************************/
426
427uip_userdata_t* RF24Client::_allocateData()
428{
429 for (uint8_t sock = 0; sock < UIP_CONNS; sock++)
430 {
431 uip_userdata_t* data = &RF24Client::all_data[sock];
432 if (!data->state)
433 {
434 data->state = sock | UIP_CLIENT_CONNECTED;
435 data->packets_in = 0;
436 data->packets_out = 0;
437 data->dataCnt = 0;
438 data->dataPos = 0;
439 data->out_pos = 0;
440 data->hold = 0;
441 data->initialData = false;
442 data->connectTimer = millis();
443 return data;
444 }
445 }
446 return NULL;
447}
448
449int RF24Client::waitAvailable(uint32_t timeout)
450{
451 uint32_t start = millis();
452 while (available() < 1)
453 {
454 if (millis() - start > timeout)
455 {
456 return 0;
457 }
458 RF24Ethernet.tick();
459 }
460 return available();
461}
462
463/*************************************************************/
464
466{
467 RF24Ethernet.tick();
468 if (*this)
469 {
470 return _available(data);
471 }
472 return 0;
473}
474
475/*************************************************************/
476
477int RF24Client::_available(uip_userdata_t* u)
478{
479 if (u->packets_in)
480 {
481 return u->dataCnt;
482 }
483 return 0;
484}
485
486int RF24Client::read(uint8_t* buf, size_t size)
487{
488 if (*this)
489 {
490 if (!data->packets_in)
491 {
492 return -1;
493 }
494
495 size = rf24_min(data->dataCnt, size);
496 memcpy(buf, &data->myData[data->dataPos], size);
497 data->dataCnt -= size;
498
499 data->dataPos += size;
500
501 if (!data->dataCnt)
502 {
503 data->packets_in = 0;
504 data->dataPos = 0;
505
506 if (uip_stopped(&uip_conns[data->state & UIP_CLIENT_SOCKETS]) && !(data->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED)))
507 {
508 data->state |= UIP_CLIENT_RESTART;
509 data->restartTime = 0;
510
511 IF_ETH_DEBUG_L2(Serial.print(F("UIPClient set restart ")); Serial.println(data->state & UIP_CLIENT_SOCKETS); Serial.println(F("**")); Serial.println(data->state, BIN); Serial.println(F("**")); Serial.println(UIP_CLIENT_SOCKETS, BIN); Serial.println(F("**")););
512 }
513 else
514 {
515 IF_ETH_DEBUG_L2(Serial.print(F("UIPClient stop?????? ")); Serial.println(data->state & UIP_CLIENT_SOCKETS); Serial.println(F("**")); Serial.println(data->state, BIN); Serial.println(F("**")); Serial.println(UIP_CLIENT_SOCKETS, BIN); Serial.println(F("**")););
516 }
517
518 if (data->packets_in == 0)
519 {
520 if (data->state & UIP_CLIENT_REMOTECLOSED)
521 {
522 data->state = 0;
523 data = NULL;
524 }
525 }
526 }
527 return size;
528 }
529
530 return -1;
531}
532
533/*************************************************************/
534
536{
537 uint8_t c;
538 if (read(&c, 1) < 0)
539 return -1;
540 return c;
541}
542
543/*************************************************************/
544
546{
547 if (available())
548 {
549 return data->myData[data->dataPos];
550 }
551 return -1;
552}
553
554/*************************************************************/
555
557{
558 if (*this)
559 {
560 data->packets_in = 0;
561 data->dataCnt = 0;
562 }
563}
void serialip_appcall(void)
Definition: RF24Client.cpp:240
void uip_log(char *msg)
Definition: RF24Client.cpp:228
#define UIP_CLIENT_CLOSE
Definition: RF24Client.h:32
#define UIP_CLIENT_RESTART
Definition: RF24Client.h:34
#define UIP_CLIENT_SOCKETS
Definition: RF24Client.h:36
#define UIP_CLIENT_REMOTECLOSED
Definition: RF24Client.h:33
#define UIP_CLIENT_CONNECTED
Definition: RF24Client.h:31
#define uip_ip_addr(addr, ip)
Definition: RF24Ethernet.h:77
RF24EthernetClass RF24Ethernet
virtual bool operator==(const EthernetClient &)
Definition: RF24Client.cpp:158
size_t write(uint8_t)
Definition: RF24Client.cpp:173
int connect(IPAddress ip, uint16_t port)
Definition: RF24Client.cpp:40
static uip_userdata_t all_data[UIP_CONNS]
Definition: RF24Client.h:163
int waitAvailable(uint32_t timeout=750)
Definition: RF24Client.cpp:449
void stop()
Definition: RF24Client.cpp:124
int available()
Definition: RF24Client.cpp:465
uint8_t connected()
Definition: RF24Client.cpp:33
void flush()
Definition: RF24Client.cpp:556
#define Ethernet
Definition: ethernet_comp.h:4
#define IF_ETH_DEBUG_L2(x)
#define IF_RF24ETHERNET_DEBUG_CLIENT(x)
#define UIP_CONNECTION_TIMEOUT
Optional: Uncomment to disable
Definition: uip-conf.h:90
#define UIP_WINDOW_REOPEN_DELAY
Optional: Used with UIP_CONNECTION_TIMEOUT
Definition: uip-conf.h:167