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