RF24Ethernet - TCP/IP over RF24Network v1.6.16
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/*************************************************************/
179
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 u->hold = false;
221 return u->out_pos;
222 }
223 u->hold = false;
224 return -1;
225}
226
227/*************************************************************/
228
229void uip_log(char* msg)
230{
231 // Serial.println();
232 // Serial.println("** UIP LOG **");
233 // Serial.println(msg);
234 if (msg)
235 {
236 };
237}
238
239/*************************************************************/
240
242{
243 uip_userdata_t* u = (uip_userdata_t*)uip_conn->appstate;
244
245 /*******Connected**********/
246 if (!u && uip_connected())
247 {
248 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(); Serial.print(millis()); Serial.println(F(" UIPClient uip_connected")););
249
250 u = (uip_userdata_t*)EthernetClient::_allocateData();
251
252 if (u)
253 {
254 uip_conn->appstate = u;
255 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print(F("UIPClient allocated state: ")); Serial.println(u->state, BIN););
256 }
257 else
258 {
259 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(F("UIPClient allocation failed")););
260 }
261 }
262
263#if UIP_CONNECTION_TIMEOUT > 0
264 if (u && u->connectTimeout > 0) {
265 if (millis() - u->connectTimer > u->connectTimeout) {
266 u->state |= UIP_CLIENT_CLOSE;
267 u->connectTimer = millis();
268 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(); Serial.print(millis()); Serial.println("UIP Client close(timeout)"););
269 }
270 }
271#endif
272
273 /*******User Data RX**********/
274 if (u)
275 {
276 if (uip_newdata())
277 {
278 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(); Serial.print(millis()); Serial.print(F(" UIPClient uip_newdata, uip_len:")); Serial.println(uip_len););
279#if UIP_CONNECTION_TIMEOUT > 0
280 u->connectTimer = millis();
281#endif
282 u->hold = (u->out_pos = (u->windowOpened = (u->packets_out = false)));
283
284 if (uip_len && !(u->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED)))
285 {
286 uip_stop();
287 u->state &= ~UIP_CLIENT_RESTART;
288 u->windowOpened = false;
289 u->restartTime = millis();
290 memcpy(&u->myData[u->in_pos + u->dataCnt], uip_appdata, uip_datalen());
291 u->dataCnt += uip_datalen();
292
293 u->packets_in = 1;
294 }
295 goto finish;
296 }
297
298 /*******Closed/Timed-out/Aborted**********/
299 // If the connection has been closed, save received but unread data.
300 if (uip_closed() || uip_timedout() || uip_aborted())
301 {
302 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(); Serial.print(millis()); Serial.println(F(" UIPClient uip_closed")););
303 // drop outgoing packets not sent yet:
304 u->packets_out = 0;
305
306 if (u->packets_in)
307 {
308 ((uip_userdata_closed_t*)u)->lport = uip_conn->lport;
309 u->state |= UIP_CLIENT_REMOTECLOSED;
310 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(F("UIPClient close 1")););
311 }
312 else
313 {
314 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(F("UIPClient close 2")););
315 u->state = 0;
316 }
317
318 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(F("after UIPClient uip_closed")););
319 uip_conn->appstate = NULL;
320 goto finish;
321 }
322
323 /*******ACKED**********/
324 if (uip_acked())
325 {
326 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(); Serial.print(millis()); Serial.println(F(" UIPClient uip_acked")););
327 u->state &= ~UIP_CLIENT_RESTART;
328 u->hold = (u->out_pos = (u->windowOpened = (u->packets_out = false)));
329 u->restartTime = millis();
330#if UIP_CONNECTION_TIMEOUT > 0
331 u->connectTimer = millis();
332#endif
333 }
334
335 /*******Polling**********/
336 if (uip_poll() || uip_rexmit())
337 {
338 if (uip_rexmit()) {
339 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print(F("ReXmit, Len: ")););
340 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(u->out_pos));
341 uip_len = u->out_pos;
342 uip_send(u->myData, u->out_pos);
343 u->hold = true;
344 goto finish;
345 }
346 // IF_RF24ETHERNET_DEBUG_CLIENT( Serial.println(); Serial.println(F("UIPClient uip_poll")); );
347
348 if (u->packets_out != 0 && !u->hold)
349 {
350 uip_len = u->out_pos;
351 uip_send(u->myData, u->out_pos);
352 u->hold = true;
353 goto finish;
354 }
355
356 // Restart mechanism to keep connections going
357 // Only call this if the TCP window has already been re-opened, the connection is being polled, but no data
358 // has been acked
359 if (!(u->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED)))
360 {
361
362 if (u->windowOpened == true && u->state & UIP_CLIENT_RESTART && millis() - u->restartTime > u->restartInterval)
363 {
364 u->restartTime = millis();
365#if defined RF24ETHERNET_DEBUG_CLIENT || defined ETH_DEBUG_L1
366 Serial.println();
367 Serial.print(millis());
368 #if UIP_CONNECTION_TIMEOUT > 0
369 Serial.print(F(" UIPClient Re-Open TCP Window, time remaining before abort: "));
370 Serial.println(UIP_CONNECTION_TIMEOUT - (millis() - u->connectTimer));
371 #endif
372#endif
373 u->restartInterval += 500;
374 u->restartInterval = rf24_min(u->restartInterval, 7000);
375 uip_restart();
376 }
377 }
378 }
379
380 /*******Close**********/
381 if (u->state & UIP_CLIENT_CLOSE)
382 {
383 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(); Serial.print(millis()); Serial.println(F(" UIPClient state UIP_CLIENT_CLOSE")););
384
385 if (u->packets_out == 0)
386 {
387 u->state = 0;
388 uip_conn->appstate = NULL;
389 uip_close();
390 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(F("no blocks out -> free userdata")););
391 }
392 else
393 {
394 uip_stop();
395 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(F("blocks outstanding transfer -> uip_stop()")););
396 }
397 }
398finish:;
399
400 if (u->state & UIP_CLIENT_RESTART && !u->windowOpened)
401 {
402 if (!(u->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED)))
403 {
404 uip_restart();
405#if defined ETH_DEBUG_L1
406 Serial.println();
407 Serial.print(millis());
408 Serial.println(F(" UIPClient Re-Open TCP Window"));
409#endif
410 u->windowOpened = true;
411 u->restartInterval = UIP_WINDOW_REOPEN_DELAY; //.75 seconds
412 u->restartTime = millis();
413 }
414 }
415 }
416}
417
418/*******************************************************/
419
420uip_userdata_t* RF24Client::_allocateData()
421{
422 for (uint8_t sock = 0; sock < UIP_CONNS; sock++)
423 {
424 uip_userdata_t* data = &RF24Client::all_data[sock];
425 if (!data->state)
426 {
427 data->state = sock | UIP_CLIENT_CONNECTED;
428 data->packets_in = 0;
429 data->packets_out = 0;
430 data->dataCnt = 0;
431 data->in_pos = 0;
432 data->out_pos = 0;
433 data->hold = 0;
434 data->restartTime = millis();
435 data->restartInterval = 5000;
436#if (UIP_CONNECTION_TIMEOUT > 0)
437 data->connectTimer = millis();
438 data->connectTimeout = UIP_CONNECTION_TIMEOUT;
439#endif
440 return data;
441 }
442 }
443 return NULL;
444}
445
446int RF24Client::waitAvailable(uint32_t timeout)
447{
448 uint32_t start = millis();
449 while (available() < 1)
450 {
451 if (millis() - start > timeout)
452 {
453 return 0;
454 }
455 RF24Ethernet.tick();
456 }
457 return available();
458}
459
460/*************************************************************/
461
463{
464 RF24Ethernet.tick();
465 if (*this)
466 {
467 return _available(data);
468 }
469 return 0;
470}
471
472/*************************************************************/
473
474int RF24Client::_available(uip_userdata_t* u)
475{
476 if (u->packets_in)
477 {
478 return u->dataCnt;
479 }
480 return 0;
481}
482
483int RF24Client::read(uint8_t* buf, size_t size)
484{
485 if (*this)
486 {
487 if (!data->packets_in)
488 {
489 return -1;
490 }
491
492 size = rf24_min(data->dataCnt, size);
493 memcpy(buf, &data->myData[data->in_pos], size);
494 data->dataCnt -= size;
495
496 data->in_pos += size;
497
498 if (!data->dataCnt)
499 {
500 data->packets_in = 0;
501 data->in_pos = 0;
502
503 if (uip_stopped(&uip_conns[data->state & UIP_CLIENT_SOCKETS]) && !(data->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED)))
504 {
505 data->state |= UIP_CLIENT_RESTART;
506 data->restartTime = 0;
507
508 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("**")););
509 }
510 else
511 {
512 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("**")););
513 }
514
515 if (data->packets_in == 0)
516 {
517 if (data->state & UIP_CLIENT_REMOTECLOSED)
518 {
519 data->state = 0;
520 data = NULL;
521 }
522 }
523 }
524 return size;
525 }
526
527 return -1;
528}
529
530/*************************************************************/
531
533{
534 uint8_t c;
535 if (read(&c, 1) < 0)
536 return -1;
537 return c;
538}
539
540/*************************************************************/
541
543{
544 if (available())
545 {
546 return data->myData[data->in_pos];
547 }
548 return -1;
549}
550
551/*************************************************************/
552
554{
555 if (*this)
556 {
557 data->packets_in = 0;
558 data->dataCnt = 0;
559 }
560}
void serialip_appcall(void)
void uip_log(char *msg)
#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)
RF24EthernetClass RF24Ethernet
virtual bool operator==(const EthernetClient &)
size_t write(uint8_t)
int connect(IPAddress ip, uint16_t port)
static uip_userdata_t all_data[UIP_CONNS]
Definition RF24Client.h:162
int waitAvailable(uint32_t timeout=750)
int available()
uint8_t connected()
#define Ethernet
#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