RF24Ethernet - TCP/IP over RF24Network v2.0.3
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#if USE_LWIP < 1
20
21 #define UIP_TCP_PHYH_LEN UIP_LLH_LEN + UIP_IPTCPH_LEN
22uip_userdata_t RF24Client::all_data[UIP_CONNS];
23
24#else
25// #define LWIP_ERR_T uint32_t
26
27 //
28 #if !defined ETHERNET_USING_LWIP_ARDUINO
29 #include <lwip/tcp.h>
30 #include "lwip/tcpip.h"
31 #include "lwip/timeouts.h"
32 #else
33 #include "lwip/include/lwip/tcp.h"
34 #include "lwip/include/lwip/tcpip.h"
35 #endif
36
37 #include "RF24Ethernet.h"
38/** \cond */
40char* RF24Client::incomingData[2];
41uint16_t RF24Client::dataSize[2];
42struct tcp_pcb* RF24Client::myPcb;
43uint32_t RF24Client::clientConnectionTimeout;
44uint32_t RF24Client::serverConnectionTimeout;
45uint32_t RF24Client::simpleCounter;
47int32_t RF24Client::accepts;
48
49/***************************************************************************************************/
50
51// Called when the remote host acknowledges receipt of data
52err_t RF24Client::sent_callback(void* arg, struct tcp_pcb* tpcb, u16_t len)
53{
54
55 ConnectState* state = (ConnectState*)arg;
56 if (state != nullptr) {
57 state->serverTimer = millis();
58 state->clientTimer = millis();
59 IF_ETH_DEBUG_L1(Serial.println("Client: Sent cb"););
60
61 state->waiting_for_ack = false; // Data is successfully out
62 state->finished = true;
63 }
64
65 return ERR_OK;
66}
67
68/***************************************************************************************************/
69
70err_t RF24Client::blocking_write(struct tcp_pcb* fpcb, ConnectState* fstate, const char* data, size_t len)
71{
72
73 if (fpcb == nullptr) {
74 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Client: Tx with no fpcb"););
75 return ERR_CLSD;
76 }
77
78 if (!fstate->connected) {
79 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Client: Tx with no connection"););
80 return ERR_CLSD;
81 }
82
83 uint32_t timeout = millis() + serverConnectionTimeout;
84 while (len > tcp_sndbuf(fpcb)) {
85 Ethernet.update();
86 if (millis() > timeout) {
87 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println("Client: TCP Send Buffer full"););
88 return ERR_BUF;
89 }
90 }
91
92 #if defined RF24ETHERNET_CORE_REQUIRES_LOCKING
93 if (Ethernet.useCoreLocking) {
94 ETHERNET_APPLY_LOCK();
95 }
96 #endif
97
98 err_t err = ERR_CLSD;
99 if (fpcb != nullptr) {
100 err = tcp_write(fpcb, data, len, TCP_WRITE_FLAG_COPY);
101 }
102
103 //Ethernet.update();
104 if (err != ERR_OK) {
105 if (fstate != nullptr) {
106 fstate->waiting_for_ack = false;
107 fstate->finished = true;
108 }
109 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Client: BLK Write fail 2: "); Serial.println((int)err););
110
111 #if defined RF24ETHERNET_CORE_REQUIRES_LOCKING
112 if (Ethernet.useCoreLocking) {
113 ETHERNET_REMOVE_LOCK();
114 }
115 #endif
116 return err;
117 }
118
119 if (fpcb != nullptr && fpcb->state != CLOSED && fstate->connected) {
120 tcp_sent(fpcb, sent_callback);
121 }
122 else {
123 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Client: TCP OUT FAIL"););
124
125 #if defined RF24ETHERNET_CORE_REQUIRES_LOCKING
126 if (Ethernet.useCoreLocking) {
127 ETHERNET_REMOVE_LOCK();
128 }
129 #endif
130 return ERR_BUF;
131 }
132 #if defined RF24ETHERNET_CORE_REQUIRES_LOCKING
133 if (Ethernet.useCoreLocking) {
134 ETHERNET_REMOVE_LOCK();
135 }
136 #endif
137
138 volatile uint32_t timer = millis() + 5000;
139 while (fstate != nullptr && fstate->waiting_for_ack && !fstate->finished) {
140 if (millis() > timer) {
141 if (fstate != nullptr) {
142 fstate->finished = true;
143 return ERR_CLSD;
144 }
145 break;
146 }
147 Ethernet.update();
148 }
149
150 return ERR_OK;
151}
152
153/***************************************************************************************************/
154
155void RF24Client::error_callback(void* arg, err_t err)
156{
157
158 ConnectState* state = (ConnectState*)arg;
159 if (state != nullptr) {
160 state->result = err;
161 state->connected = false;
162 state->finished = true; // Break the blocking loop
163 state->waiting_for_ack = false;
164 dataSize[state->stateActiveID] = 0;
165 if (state->stateActiveID == activeState) {
166 myPcb = nullptr;
167 }
168 }
169 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Client: Err cb: "); Serial.println((int)err););
170}
171
172/***************************************************************************************************/
173
174err_t RF24Client::srecv_callback(void* arg, struct tcp_pcb* tpcb, struct pbuf* p, err_t err)
175{
176
177 ConnectState* state = (ConnectState*)arg;
178
179 if (state != nullptr) {
180 state->serverTimer = millis();
181 }
182
183 if (p == nullptr) {
184 if (state != nullptr) {
185 state->connected = false;
186 state->finished = true; // Break the loop
187 }
188 if (tpcb != nullptr) {
189 if (tcp_close(tpcb) != ERR_OK) {
190 tcp_abort(tpcb);
191 tpcb = nullptr;
192 if (state->stateActiveID == activeState) {
193 myPcb = nullptr;
194 }
195 return ERR_ABRT;
196 }
197 tpcb = nullptr;
198 if (state->stateActiveID == activeState) {
199 myPcb = nullptr;
200 }
201 }
202 return ERR_OK;
203 }
204 if (err != ERR_OK || state == nullptr) {
205 if (p)
206 pbuf_free(p);
207 return ERR_OK;
208 }
209
210 const uint8_t* data = static_cast<const uint8_t*>(p->payload);
211
212 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Server: Copy data to "); Serial.println(state->stateActiveID););
213 if (dataSize[state->stateActiveID] + p->len < INCOMING_DATA_SIZE) {
214 memcpy(&incomingData[state->stateActiveID][dataSize[state->stateActiveID]], data, p->len);
215 dataSize[state->stateActiveID] += p->len;
216 }
217 else {
218 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println("Server: srecv - Out of incoming buffer space"););
219 }
220
221 if (tpcb != nullptr) {
222 tcp_recved(tpcb, p->len);
223 }
224 if (p) {
225 pbuf_free(p);
226 }
227 return ERR_OK;
228}
229
230/***************************************************************************************************/
231
232err_t RF24Client::recv_callback(void* arg, struct tcp_pcb* tpcb, struct pbuf* p, err_t err)
233{
234
235 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println("Client: Recv cb"););
236
237 ConnectState* state = (ConnectState*)arg;
238 if (p == nullptr) {
239 if (state != nullptr) {
240 state->connected = false;
241 state->finished = true; // Break the loop
242 }
243 if (tpcb != nullptr) {
244 if (tcp_close(tpcb) != ERR_OK) {
245 tcp_abort(tpcb);
246 tpcb = nullptr;
247 if (state->stateActiveID == activeState) {
248 myPcb = nullptr;
249 }
250 return ERR_ABRT;
251 }
252 tpcb = nullptr;
253 if (state->stateActiveID == activeState) {
254 myPcb = nullptr;
255 }
256 }
257 return err;
258 }
259 if (err != ERR_OK || state == nullptr) {
260 if (p)
261 pbuf_free(p);
262 return err;
263 }
264
265 if (state != nullptr) {
266 state->clientTimer = millis();
267 }
268 const uint8_t* data = static_cast<const uint8_t*>(p->payload);
269 if (dataSize[activeState] + p->len < INCOMING_DATA_SIZE) {
270 memcpy(&incomingData[activeState][dataSize[activeState]], data, p->len);
271 dataSize[activeState] += p->len;
272 }
273 else {
274 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println("Client: recv - Out of incoming buffer space"););
275 }
276
277 if (tpcb != nullptr) {
278 tcp_recved(tpcb, p->len);
279 }
280 if (p) {
281 pbuf_free(p);
282 }
283 return ERR_OK;
284}
285
286/***************************************************************************************************/
287
288//void RF24Client::setConnectionTimeout(uint32_t timeout)
289//{
290
291// clientConnectionTimeout = timeout;
292//}
293
294/***************************************************************************************************/
295
296err_t RF24Client::clientTimeouts(void* arg, struct tcp_pcb* tpcb)
297{
298
299 ConnectState* state = (ConnectState*)arg;
300
301 if (state != nullptr) {
302 if (millis() - state->clientTimer > state->cConnectionTimeout) {
303 if (tpcb->state == ESTABLISHED || tpcb->state == SYN_SENT || tpcb->state == SYN_RCVD) {
304 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println("Client: Closed Client PCB TIMEOUT"););
305 err_t err = tcp_close(tpcb);
306 state->result = err;
307 state->connected = false;
308 state->finished = true; // Break the blocking loop
309 state->waiting_for_ack = false;
310 }
311 }
312 }
313 return ERR_OK;
314}
315
316/***************************************************************************************************/
317
318err_t RF24Client::serverTimeouts(void* arg, struct tcp_pcb* tpcb)
319{
320
321 ConnectState* state = (ConnectState*)arg;
322
323 if (state != nullptr && tpcb != nullptr) {
324 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Server: Stimeout cb "); Serial.println(millis() - state->serverTimer););
325
326 state->result = ERR_OK;
327
328 if (millis() - state->serverTimer > state->sConnectionTimeout && state->backlogWasClosed == false) {
329 //if (tpcb->state == ESTABLISHED || tpcb->state == SYN_SENT || tpcb->state == SYN_RCVD) {
330 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println("Server: Closed Server PCB TIMEOUT "););
331
332 state->result = tcp_close(tpcb);
333 state->closeTimer = millis();
334 state->backlogWasClosed = true;
335 dataSize[activeState] = 0;
336 state->connected = false;
337 state->finished = true;
338 if (state->result != ERR_OK) {
339 tcp_abort(tpcb);
340 tpcb = nullptr;
341 return ERR_ABRT;
342 }
343 return state->result;
344
345 // }
346 }
347 if (state->backlogWasClosed == true) {
348 if (millis() - state->closeTimer > 5000) {
349 tcp_abort(tpcb);
350 tpcb = nullptr;
351 return ERR_ABRT;
352 }
353 }
354 }
355 return state->result;
356}
357
358/***************************************************************************************************/
359
360err_t RF24Client::closed_port(void* arg, struct tcp_pcb* tpcb)
361{
362
363 ConnectState* state = (ConnectState*)arg;
364
365 if (state != nullptr) {
366 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Server: Client Poll Cb ID: "); Serial.println(state->identifier));
367 }
368
369 if (myPcb == nullptr) {
370 if (state != nullptr && tpcb != nullptr) {
371
372 if ((tpcb->state == ESTABLISHED || tpcb->state == SYN_SENT || tpcb->state == SYN_RCVD)) {
373 if (state->backlogWasAccepted == false && state->backlogWasClosed == false) {
374
375 state->backlogWasAccepted = true;
376 state->connectTimestamp = millis();
377 state->connected = true;
378 state->finished = false;
379 accepts--;
380 myPcb = tpcb;
381 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Server: ACCEPT delayed PCB "); Serial.println(state->identifier););
382
383 tcp_backlog_accepted(tpcb);
384 activeState = state->stateActiveID;
385 return ERR_OK;
386 }
387 }
388 }
389 }
390
391 if (tpcb != nullptr) {
392 if (state != nullptr) {
393 if (millis() - state->connectTimestamp > state->sConnectionTimeout) {
394
395 if ((tpcb->state == ESTABLISHED || tpcb->state == SYN_SENT || tpcb->state == SYN_RCVD)) {
396 if (state->backlogWasClosed == false) {
397
398 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Server: Close off delayed PCB function 1, ID: "); Serial.println(state->identifier););
399
400 if (state->backlogWasAccepted == false) {
401 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println("Server: With backlog accepted"););
402 tcp_backlog_accepted(tpcb);
403 state->backlogWasAccepted = true;
404 accepts--;
405 }
406
407 state->result = tcp_close(tpcb);
408 state->backlogWasClosed = true;
409 if (state->result == ERR_OK) {
410 state->closeTimer = millis();
411 state->finished = true;
412 }
413 else {
414 tcp_abort(tpcb);
415 tpcb = nullptr;
416 return ERR_ABRT;
417 }
418
419 return state->result;
420 }
421 else {
422 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Server: Killing off TPCB already closed function 1, ID: "););
423
424 if (state != nullptr) {
425 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(state->identifier););
426 }
427 if (millis() - state->closeTimer > 5000) {
428 tcp_abort(tpcb);
429 tpcb = nullptr;
430 return ERR_ABRT;
431 }
432 }
433 }
434 }
435 }
436 }
437 if (tpcb != nullptr) {
438 if (state != nullptr) {
439 if (millis() - state->connectTimestamp > state->sConnectionTimeout) {
440 if (state->backlogWasClosed == false) {
441 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Server: Close off delayed PCB function 2, ID "); Serial.println(state->identifier););
442 if (state->backlogWasAccepted == false) {
443 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println("Server: With backlog accepted"););
444 tcp_backlog_accepted(tpcb);
445 state->backlogWasAccepted = true;
446 accepts--;
447 }
448 state->result = tcp_close(tpcb);
449 state->backlogWasClosed = true;
450 if (state->result == ERR_OK) {
451 state->closeTimer = millis();
452 state->finished = true;
453 }
454 else {
455 tcp_abort(tpcb);
456 tpcb = nullptr;
457 return ERR_ABRT;
458 }
459 return state->result;
460 }
461 else {
462 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Server: Killing off TPCB already closed function 2, ID: "););
463 if (state != nullptr) {
464 Serial.println(state->identifier);
465 if (millis() - state->closeTimer > 5000) {
466 tcp_abort(tpcb);
467 tpcb = nullptr;
468 return ERR_ABRT;
469 }
470 }
471 }
472 }
473 }
474 }
475
476 return ERR_OK;
477}
478
479/**************************************************************************************************/
480
481err_t RF24Client::accept(void* arg, struct tcp_pcb* tpcb, err_t err)
482{
483 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Server: Accept cb, ID: "); Serial.println(simpleCounter + 1););
484
485 if (tpcb == nullptr) {
486 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Server: Accepted conn, but no tpcb from: "); Serial.println(ip4addr_ntoa(ip_2_ip4(&tpcb->remote_ip))););
487 return ERR_CLSD;
488 }
489
490 if (tpcb != nullptr) {
491 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Server: Client connect from: "); Serial.println(ip4addr_ntoa(ip_2_ip4(&tpcb->remote_ip))););
492 }
493 bool actState = activeState;
494
495 if (myPcb != nullptr) {
496
497 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Server: Accept w/already connected: Accepted_Conns - Delayed_Conns == "); Serial.println(accepts););
498 tcp_backlog_delayed(tpcb);
499 accepts++;
500 tcp_poll(tpcb, closed_port, 5);
501 actState = !activeState;
502 gState[actState]->connected = false;
503 }
504 else {
505 myPcb = tpcb;
506 tcp_poll(tpcb, serverTimeouts, 8);
508 actState = activeState;
509 gState[actState]->connected = true;
510 }
511
512 dataSize[actState] = 0;
513
514 simpleCounter += 1;
515 gState[actState]->stateActiveID = actState;
516 gState[actState]->identifier = simpleCounter;
517 gState[actState]->finished = false;
518 gState[actState]->sConnectionTimeout = serverConnectionTimeout;
519 gState[actState]->waiting_for_ack = false;
520 gState[actState]->backlogWasAccepted = false;
521 gState[actState]->backlogWasClosed = false;
522 gState[actState]->connectTimestamp = millis();
523 gState[actState]->serverTimer = millis();
524
525 tcp_arg(tpcb, RF24Client::gState[actState]);
526 tcp_recv(tpcb, srecv_callback);
527 tcp_sent(tpcb, sent_callback);
528 tcp_err(tpcb, error_callback);
529
530 return ERR_OK;
531}
532
533/***************************************************************************************************/
534err_t RF24Client::closeConn(void* arg, struct tcp_pcb* tpcb)
535{
536 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println("Client: Immediate close"););
537 if (tpcb != nullptr) {
538 tcp_close(tpcb);
539 }
540
541 return ERR_OK;
542}
543
544/***************************************************************************************************/
545
546// Callback triggered by lwIP when handshake completes
547
548err_t RF24Client::on_connected(void* arg, struct tcp_pcb* tpcb, err_t err)
549{
550 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println("Client: Conn cb"););
551
552 ConnectState* state = (ConnectState*)arg;
553
554 if (state != nullptr) {
555 /*if (state->cConnectionTimeout > 0) {
556 #if defined RF24ETHERNET_CORE_REQUIRES_LOCKING
557 if(Ethernet.useCoreLocking){if(Ethernet.useCoreLocking){ ETHERNET_APPLY_LOCK(); } }
558 #endif
559 tcp_poll(tpcb, clientTimeouts, 30);
560 #if defined RF24ETHERNET_CORE_REQUIRES_LOCKING
561 if(Ethernet.useCoreLocking){ ETHERNET_REMOVE_LOCK(); }
562 #endif
563 }*/
564
565 state->cConnectionTimeout = clientConnectionTimeout;
566 state->clientTimer = millis();
567 state->result = err;
568 state->finished = true;
569 if (err == ERR_OK) {
570 state->connected = true;
571 }
572 else {
573 state->connected = false;
574 }
575 state->waiting_for_ack = false;
576 }
577 return err;
578}
579/** \endcond */
580#endif // USE_LWIP > 1
581
582/***************************************************************************************************/
583
584#if USE_LWIP < 1
585RF24Client::RF24Client() : data(NULL)
586{
587}
588#else
590{
591}
592
593#endif
594/*************************************************************/
595
596#if USE_LWIP < 1
597RF24Client::RF24Client(uip_userdata_t* conn_data) : data(conn_data)
598{
599}
600#else
601/** \cond */
602RF24Client::RF24Client(uint32_t data) : data(0)
603{
604}
605/** \endcond */
606#endif
607/*************************************************************/
608
610{
611#if USE_LWIP < 1
612 return (data && (data->packets_in != 0 || (data->state & UIP_CLIENT_CONNECTED))) ? 1 : 0;
613#else
614 if (gState[activeState] != nullptr) {
615 return gState[activeState]->connected;
616 }
617 return 0;
618#endif
619}
620
621/*************************************************************/
622
623int RF24Client::connect(IPAddress ip, uint16_t port)
624{
625
626#if USE_LWIP < 1
627 #if UIP_ACTIVE_OPEN > 0
628
629 // do{
630
631 stop();
632 uip_ipaddr_t ipaddr;
633 uip_ip_addr(ipaddr, ip);
634
635 struct uip_conn* conn = uip_connect(&ipaddr, htons(port));
636
637 if (conn)
638 {
639 #if UIP_CONNECTION_TIMEOUT > 0
640 uint32_t timeout = millis();
641 #endif
642
643 while ((conn->tcpstateflags & UIP_TS_MASK) != UIP_CLOSED)
644 {
645 Ethernet.update();
646
647 if ((conn->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED)
648 {
649 data = (uip_userdata_t*)conn->appstate;
650 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););
651 return 1;
652 }
653
654 #if UIP_CONNECTION_TIMEOUT > 0
655 if ((millis() - timeout) > UIP_CONNECTION_TIMEOUT)
656 {
657 conn->tcpstateflags = UIP_CLOSED;
658 break;
659 }
660 #endif
661 }
662 }
663 // delay(25);
664 // }while(millis()-timer < 175);
665
666 #endif // Active open enabled
667#else
668
669 if (myPcb != nullptr) {
670 #if defined RF24ETHERNET_CORE_REQUIRES_LOCKING
671 if (Ethernet.useCoreLocking) {
672 ETHERNET_APPLY_LOCK();
673 }
674 #endif
675 if (myPcb->state == ESTABLISHED || myPcb->state == SYN_SENT || myPcb->state == SYN_RCVD) {
676 if (tcp_close(myPcb) != ERR_OK) {
677 tcp_abort(myPcb);
678 }
679 //myPcb = NULL;
680 #if defined RF24ETHERNET_CORE_REQUIRES_LOCKING
681 if (Ethernet.useCoreLocking) {
682 ETHERNET_REMOVE_LOCK();
683 }
684 #endif
685 Ethernet.update();
686 return ERR_CLSD;
687 }
688 else {
689 #if defined RF24ETHERNET_CORE_REQUIRES_LOCKING
690 if (Ethernet.useCoreLocking) {
691 ETHERNET_REMOVE_LOCK();
692 }
693 #endif
694 myPcb = NULL;
695 }
696 }
697
698 #if defined RF24ETHERNET_CORE_REQUIRES_LOCKING
699 if (Ethernet.useCoreLocking) {
700 ETHERNET_APPLY_LOCK();
701 }
702 #endif
703
704 if (myPcb == nullptr) {
705 myPcb = tcp_new();
706 }
707
708 if (!myPcb) {
709
710 #if defined RF24ETHERNET_CORE_REQUIRES_LOCKING
711 if (Ethernet.useCoreLocking) {
712 ETHERNET_REMOVE_LOCK();
713 }
714 #endif
715 return 0;
716 }
717
718 dataSize[activeState] = 0;
719 memset(incomingData[activeState], 0, sizeof(incomingData[activeState]));
720
721 gState[activeState]->finished = false;
722 gState[activeState]->connected = false;
723 gState[activeState]->result = 0;
724 gState[activeState]->waiting_for_ack = false;
725
726 tcp_arg(myPcb, gState[activeState]);
727 tcp_err(myPcb, error_callback);
728 tcp_recv(myPcb, recv_callback);
729 //tcp_poll(myPcb, clientTimeouts, 30);
730
731 err_t err = ERR_OK;
732
733 ip_addr_t myIp;
734 IP_ADDR4(&myIp, ip[0], ip[1], ip[2], ip[3]);
735
736 err = tcp_connect(myPcb, &myIp, port, on_connected);
737
738 if (err != ERR_OK || gState[activeState]->result != ERR_OK) {
739 #if defined RF24ETHERNET_CORE_REQUIRES_LOCKING
740 if (Ethernet.useCoreLocking) {
741 ETHERNET_REMOVE_LOCK();
742 }
743 #endif
744
745 stop();
746 return ERR_CLSD;
747 }
748
749 #if defined RF24ETHERNET_CORE_REQUIRES_LOCKING
750 if (Ethernet.useCoreLocking) {
751 ETHERNET_REMOVE_LOCK();
752 }
753 #endif
754
755 uint32_t timeout = millis() + 5000;
756 // Simulate blocking by looping until the callback sets 'finished'
757 while (!gState[activeState]->finished && millis() < timeout) {
758 Ethernet.update();
759 }
760
761 if (clientConnectionTimeout > 0) {
762 gState[activeState]->clientPollingSetup = 1;
763 }
764
765 return gState[activeState]->connected;
766
767#endif
768 return 0;
769}
770
771/*************************************************************/
772
773#if USE_LWIP > 1
774void dnsCallback(const char* name, const ip_addr_t* ipaddr, void* callback_arg)
775{
776}
777#endif
778/*************************************************************/
779
780int RF24Client::connect(const char* host, uint16_t port)
781{
782 // Look up the host first
783 int ret = 0;
784
785#if UIP_UDP
786 DNSClient dns;
787 IPAddress remote_addr;
788
789 dns.begin(RF24EthernetClass::_dnsServerAddress);
790 ret = dns.getHostByName(host, remote_addr);
791
792 if (ret == 1)
793 {
794 #if defined(ETH_DEBUG_L1) || defined(RF24ETHERNET_DEBUG_DNS)
795 Serial.println(F("*UIP Got DNS*"));
796 #endif
797 return connect(remote_addr, port);
798 }
799#elif RF24ETHERNET_USE_UDP
800
801 DNSClient dns;
802 IPAddress remote_addr;
803
804 dns.begin(RF24EthernetClass::_dnsServerAddress);
805 ret = dns.getHostByName(host, remote_addr);
806
807 if (ret == 1)
808 {
809 #if defined(ETH_DEBUG_L1) || defined(RF24ETHERNET_DEBUG_DNS)
810 Serial.println(F("*lwIP Got DNS*"));
811 #endif
812 return connect(remote_addr, port);
813 }
814
815#else // ! UIP_UDP
816 // Do something with the input parameters to prevent compile time warnings
817 if (host) {
818 };
819 if (port) {
820 };
821#endif // ! UIP_UDP
822
823#if defined(ETH_DEBUG_L1) || defined(RF24ETHERNET_DEBUG_DNS)
824 Serial.println(F("* DNS fail*"));
825#endif
826
827 return ret;
828}
829
830/*************************************************************/
831
833{
834#if USE_LWIP < 1
835 if (data && data->state)
836 {
837
838 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print(millis()); Serial.println(F(" before stop(), with data")););
839
840 data->packets_in = 0;
841 data->dataCnt = 0;
842
843 if (data->state & UIP_CLIENT_REMOTECLOSED)
844 {
845 data->state = 0;
846 }
847 else
848 {
849 data->state |= UIP_CLIENT_CLOSE;
850 }
851
852 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(F("after stop()")););
853 }
854 else
855 {
856 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print(millis()); Serial.println(F(" stop(), data: NULL")););
857 }
858
859 data = NULL;
860 RF24Ethernet.update();
861#else
862
863 _stop();
864
865#endif
866}
867
868/***************************************************************************************************/
869#if USE_LWIP > 0
870void RF24Client::_stop()
871{
872 if (myPcb != nullptr) {
873
874 if (myPcb->state != CLOSED) {
875
876 #if defined RF24ETHERNET_CORE_REQUIRES_LOCKING
877 if (Ethernet.useCoreLocking) {
878 ETHERNET_APPLY_LOCK();
879 }
880 #endif
881 err_t err = tcp_close(myPcb);
882 if (err != ERR_OK) {
883 tcp_abort(myPcb);
884 }
885
886 #if defined RF24ETHERNET_CORE_REQUIRES_LOCKING
887 if (Ethernet.useCoreLocking) {
888 ETHERNET_REMOVE_LOCK();
889 }
890 #endif
891 }
892 }
893
894 gState[activeState]->connected = false;
895 gState[activeState]->finished = true;
896 dataSize[activeState] = 0;
897}
898#endif
899/*************************************************************/
900
901// the next function allows us to use the client returned by
902// EthernetServer::available() as the condition in an if-statement.
904{
905#if USE_LWIP < 1
906 return data && rhs.data && (data == rhs.data);
907#else
908 return dataSize[activeState] > 0 ? true : false;
909#endif
910}
911
912/*************************************************************/
913
914RF24Client::operator bool()
915{
916 Ethernet.update();
917#if USE_LWIP < 1
918 return data && (!(data->state & UIP_CLIENT_REMOTECLOSED) || data->packets_in != 0);
919#else
920 return dataSize[activeState] > 0 ? true : false;
921#endif
922}
923
924/*************************************************************/
925
926size_t RF24Client::write(uint8_t c)
927{
928 return _write(data, &c, 1);
929}
930
931/*************************************************************/
932
933size_t RF24Client::write(const uint8_t* buf, size_t size)
934{
935 return _write(data, buf, size);
936}
937
938/*************************************************************/
939#if USE_LWIP < 1
940size_t RF24Client::_write(uip_userdata_t* u, const uint8_t* buf, size_t size)
941#else
942size_t RF24Client::_write(uint8_t* data, const uint8_t* buf, size_t size)
943
944#endif
945
946{
947
948#if USE_LWIP < 1
949 size_t total_written = 0;
950 size_t payloadSize = rf24_min(size, UIP_TCP_MSS);
951
952test2:
953
954 Ethernet.update();
955 if (u && !(u->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED)) && u->state & (UIP_CLIENT_CONNECTED))
956 {
957
958 if (u->out_pos + payloadSize > UIP_TCP_MSS || u->hold)
959 {
960 goto test2;
961 }
962
963 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("'")););
964
965 memcpy(u->myData + u->out_pos, buf + total_written, payloadSize);
966 u->packets_out = 1;
967 u->out_pos += payloadSize;
968
969 total_written += payloadSize;
970
971 if (total_written < size)
972 {
973 size_t remain = size - total_written;
974 payloadSize = rf24_min(remain, UIP_TCP_MSS);
975
976 // RF24EthernetClass::update();
977 goto test2;
978 }
979 u->hold = false;
980 return u->out_pos;
981 }
982 u->hold = false;
983 return -1;
984#else
985
986 if (myPcb == nullptr) {
987 return ERR_CLSD;
988 }
989
990 bool initialActiveState = activeState;
991
992 char buffer[size];
993 uint32_t position = 0;
994 uint32_t timeout1 = millis() + 3000;
995
996 while (size > MAX_PAYLOAD_SIZE - 14 && millis() < timeout1) {
997 memcpy(buffer, &buf[position], MAX_PAYLOAD_SIZE - 14);
998
999 if (myPcb == nullptr) {
1000 return ERR_CLSD;
1001 }
1002 gState[initialActiveState]->waiting_for_ack = true;
1003 err_t write_err = blocking_write(myPcb, gState[initialActiveState], buffer, MAX_PAYLOAD_SIZE - 14);
1004
1005 if (write_err != ERR_OK) {
1006 gState[initialActiveState]->result = write_err;
1007 gState[initialActiveState]->connected = false;
1008 _stop();
1009 return (write_err);
1010 }
1011 position += MAX_PAYLOAD_SIZE - 14;
1012 size -= MAX_PAYLOAD_SIZE - 14;
1013 Ethernet.update();
1014 }
1015
1016 memcpy(buffer, &buf[position], size);
1017
1018 if (myPcb == nullptr) {
1019 return ERR_CLSD;
1020 }
1021
1022 gState[initialActiveState]->waiting_for_ack = true;
1023 err_t write_err = blocking_write(myPcb, gState[initialActiveState], buffer, size);
1024
1025 if (write_err != ERR_OK) {
1026 gState[initialActiveState]->result = write_err;
1027 gState[initialActiveState]->connected = false;
1028 _stop();
1029 return (write_err);
1030 }
1031
1032 return size;
1033#endif
1034}
1035
1036/*************************************************************/
1037
1038void uip_log(char* msg)
1039{
1040 // Serial.println();
1041 // Serial.println("** UIP LOG **");
1042 // Serial.println(msg);
1043 if (msg)
1044 {
1045 };
1046}
1047
1048/*************************************************************/
1049#if USE_LWIP < 1
1050void serialip_appcall(void)
1051{
1052 uip_userdata_t* u = (uip_userdata_t*)uip_conn->appstate;
1053
1054 /*******Connected**********/
1055 if (!u && uip_connected())
1056 {
1057 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(); Serial.print(millis()); Serial.println(F(" UIPClient uip_connected")););
1058
1059 u = (uip_userdata_t*)EthernetClient::_allocateData();
1060
1061 if (u)
1062 {
1063 uip_conn->appstate = u;
1064 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print(F("UIPClient allocated state: ")); Serial.println(u->state, BIN););
1065 }
1066 else
1067 {
1068 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(F("UIPClient allocation failed")););
1069 }
1070 }
1071
1072 #if UIP_CONNECTION_TIMEOUT > 0
1073 if (u && u->connectTimeout > 0) {
1074 if (millis() - u->connectTimer > u->connectTimeout) {
1075 u->state |= UIP_CLIENT_CLOSE;
1076 u->connectTimer = millis();
1077 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(); Serial.print(millis()); Serial.println("UIP Client close(timeout)"););
1078 }
1079 }
1080 #endif
1081
1082 /*******User Data RX**********/
1083 if (u)
1084 {
1085 if (uip_newdata())
1086 {
1087 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(); Serial.print(millis()); Serial.print(F(" UIPClient uip_newdata, uip_len:")); Serial.println(uip_len););
1088 #if UIP_CONNECTION_TIMEOUT > 0
1089 u->connectTimer = millis();
1090 #endif
1091 u->hold = (u->out_pos = (u->windowOpened = (u->packets_out = false)));
1092
1093 if (uip_len && !(u->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED)))
1094 {
1095 uip_stop();
1096 u->state &= ~UIP_CLIENT_RESTART;
1097 u->windowOpened = false;
1098 u->restartTime = millis();
1099 memcpy(&u->myData[u->in_pos + u->dataCnt], uip_appdata, uip_datalen());
1100 u->dataCnt += uip_datalen();
1101
1102 u->packets_in = 1;
1103 }
1104 goto finish;
1105 }
1106
1107 /*******Closed/Timed-out/Aborted**********/
1108 // If the connection has been closed, save received but unread data.
1109 if (uip_closed() || uip_timedout() || uip_aborted())
1110 {
1111 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(); Serial.print(millis()); Serial.println(F(" UIPClient uip_closed")););
1112 // drop outgoing packets not sent yet:
1113 u->packets_out = 0;
1114
1115 if (u->packets_in)
1116 {
1117 ((uip_userdata_closed_t*)u)->lport = uip_conn->lport;
1118 u->state |= UIP_CLIENT_REMOTECLOSED;
1119 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(F("UIPClient close 1")););
1120 }
1121 else
1122 {
1123 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(F("UIPClient close 2")););
1124 u->state = 0;
1125 }
1126
1127 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(F("after UIPClient uip_closed")););
1128 uip_conn->appstate = NULL;
1129 goto finish;
1130 }
1131
1132 /*******ACKED**********/
1133 if (uip_acked())
1134 {
1135 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(); Serial.print(millis()); Serial.println(F(" UIPClient uip_acked")););
1136 u->state &= ~UIP_CLIENT_RESTART;
1137 u->hold = (u->out_pos = (u->windowOpened = (u->packets_out = false)));
1138 u->restartTime = millis();
1139 #if UIP_CONNECTION_TIMEOUT > 0
1140 u->connectTimer = millis();
1141 #endif
1142 }
1143
1144 /*******Polling**********/
1145 if (uip_poll() || uip_rexmit())
1146 {
1147 if (uip_rexmit()) {
1148 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print(F("ReXmit, Len: ")););
1149 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(u->out_pos));
1150 uip_len = u->out_pos;
1151 uip_send(u->myData, u->out_pos);
1152 u->hold = true;
1153 goto finish;
1154 }
1155 // IF_RF24ETHERNET_DEBUG_CLIENT( Serial.println(); Serial.println(F("UIPClient uip_poll")); );
1156
1157 if (u->packets_out != 0 && !u->hold)
1158 {
1159 uip_len = u->out_pos;
1160 uip_send(u->myData, u->out_pos);
1161 u->hold = true;
1162 goto finish;
1163 }
1164
1165 // Restart mechanism to keep connections going
1166 // Only call this if the TCP window has already been re-opened, the connection is being polled, but no data
1167 // has been acked
1168 if (!(u->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED)))
1169 {
1170
1171 if (u->windowOpened == true && u->state & UIP_CLIENT_RESTART && millis() - u->restartTime > u->restartInterval)
1172 {
1173 u->restartTime = millis();
1174 #if defined RF24ETHERNET_DEBUG_CLIENT || defined ETH_DEBUG_L1
1175 Serial.println();
1176 Serial.print(millis());
1177 #if UIP_CONNECTION_TIMEOUT > 0
1178 Serial.print(F(" UIPClient Re-Open TCP Window, time remaining before abort: "));
1179 Serial.println(UIP_CONNECTION_TIMEOUT - (millis() - u->connectTimer));
1180 #endif
1181 #endif
1182 u->restartInterval += 500;
1183 u->restartInterval = rf24_min(u->restartInterval, 7000);
1184 uip_restart();
1185 }
1186 }
1187 }
1188
1189 /*******Close**********/
1190 if (u->state & UIP_CLIENT_CLOSE)
1191 {
1192 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(); Serial.print(millis()); Serial.println(F(" UIPClient state UIP_CLIENT_CLOSE")););
1193
1194 if (u->packets_out == 0)
1195 {
1196 u->state = 0;
1197 uip_conn->appstate = NULL;
1198 uip_close();
1199 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(F("no blocks out -> free userdata")););
1200 }
1201 else
1202 {
1203 uip_stop();
1204 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(F("blocks outstanding transfer -> uip_stop()")););
1205 }
1206 }
1207finish:;
1208
1209 if (u->state & UIP_CLIENT_RESTART && !u->windowOpened)
1210 {
1211 if (!(u->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED)))
1212 {
1213 uip_restart();
1214 #if defined ETH_DEBUG_L1
1215 Serial.println();
1216 Serial.print(millis());
1217 Serial.println(F(" UIPClient Re-Open TCP Window"));
1218 #endif
1219 u->windowOpened = true;
1220 u->restartInterval = UIP_WINDOW_REOPEN_DELAY; //.75 seconds
1221 u->restartTime = millis();
1222 }
1223 }
1224 }
1225}
1226#endif
1227/*******************************************************/
1228#if USE_LWIP < 1
1229uip_userdata_t* RF24Client::_allocateData()
1230{
1231 for (uint8_t sock = 0; sock < UIP_CONNS; sock++)
1232 {
1233 uip_userdata_t* data = &RF24Client::all_data[sock];
1234 if (!data->state)
1235 {
1236 data->state = sock | UIP_CLIENT_CONNECTED;
1237 data->packets_in = 0;
1238 data->packets_out = 0;
1239 data->dataCnt = 0;
1240 data->in_pos = 0;
1241 data->out_pos = 0;
1242 data->hold = 0;
1243 data->restartTime = millis();
1244 data->restartInterval = 5000;
1245 #if (UIP_CONNECTION_TIMEOUT > 0)
1246 data->connectTimer = millis();
1247 data->connectTimeout = UIP_CONNECTION_TIMEOUT;
1248 #endif
1249 return data;
1250 }
1251 }
1252 return NULL;
1253}
1254#endif
1255
1256int RF24Client::waitAvailable(uint32_t timeout)
1257{
1258 uint32_t start = millis();
1259 while (available() < 1)
1260 {
1261 if (millis() - start > timeout)
1262 {
1263 return 0;
1264 }
1265 RF24Ethernet.update();
1266 }
1267 return available();
1268}
1269
1270/*************************************************************/
1271
1273{
1274 RF24Ethernet.update();
1275#if USE_LWIP < 1
1276 if (*this)
1277 {
1278 return _available(data);
1279 }
1280#else
1281 return _available(data);
1282#endif
1283 return 0;
1284}
1285
1286/*************************************************************/
1287#if USE_LWIP < 1
1288int RF24Client::_available(uip_userdata_t* u)
1289#else
1290int RF24Client::_available(uint8_t* data)
1291#endif
1292{
1293#if USE_LWIP < 1
1294 if (u->packets_in)
1295 {
1296 return u->dataCnt;
1297 }
1298#else
1299 return dataSize[activeState];
1300#endif
1301 return 0;
1302}
1303
1304/*************************************************************/
1305
1306int RF24Client::read(uint8_t* buf, size_t size)
1307{
1308#if USE_LWIP < 1
1309 if (*this)
1310 {
1311 if (!data->packets_in)
1312 {
1313 return -1;
1314 }
1315
1316 size = rf24_min(data->dataCnt, size);
1317 memcpy(buf, &data->myData[data->in_pos], size);
1318 data->dataCnt -= size;
1319
1320 data->in_pos += size;
1321
1322 if (!data->dataCnt)
1323 {
1324 data->packets_in = 0;
1325 data->in_pos = 0;
1326
1327 if (uip_stopped(&uip_conns[data->state & UIP_CLIENT_SOCKETS]) && !(data->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED)))
1328 {
1329 data->state |= UIP_CLIENT_RESTART;
1330 data->restartTime = 0;
1331
1332 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("**")););
1333 }
1334 else
1335 {
1336 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("**")););
1337 }
1338
1339 if (data->packets_in == 0)
1340 {
1341 if (data->state & UIP_CLIENT_REMOTECLOSED)
1342 {
1343 data->state = 0;
1344 data = NULL;
1345 }
1346 }
1347 }
1348 return size;
1349 }
1350
1351 return -1;
1352#else
1353
1354 if (available()) {
1355
1356 if (size >= dataSize[activeState]) {
1357 memcpy(&buf[0], &incomingData[activeState][0], dataSize[activeState]);
1358 memmove(&incomingData[activeState][0], &incomingData[activeState][dataSize[activeState]], dataSize[activeState]);
1359 size = dataSize[activeState];
1360 dataSize[activeState] = 0;
1361 return size;
1362 }
1363 else {
1364 memcpy(&buf[0], &incomingData[activeState][0], size);
1365 memmove(&incomingData[activeState][0], &incomingData[activeState][size], dataSize[activeState] - size);
1366 dataSize[activeState] -= size;
1367 return size;
1368 }
1369 }
1370 return -1;
1371#endif
1372}
1373
1374/*************************************************************/
1375
1377{
1378 uint8_t c;
1379 if (read(&c, 1) < 0)
1380 return -1;
1381 return c;
1382}
1383
1384/*************************************************************/
1385
1387{
1388 if (available())
1389 {
1390#if USE_LWIP < 1
1391 return data->myData[data->in_pos];
1392#else
1393 return incomingData[activeState][0];
1394#endif
1395 }
1396 return -1;
1397}
1398
1399/*************************************************************/
1400
1402{
1403#if USE_LWIP < 1
1404 if (*this)
1405 {
1406 #if USE_LWIP < 1
1407 data->packets_in = 0;
1408 data->dataCnt = 0;
1409 #else
1410 data = 0;
1411 #endif
1412 }
1413#else
1414 while (available()) {
1415 read();
1416 }
1417#endif
1418}
void uip_log(char *msg)
volatile err_t result
Definition RF24Client.h:8
#define INCOMING_DATA_SIZE
Definition RF24Client.h:78
volatile bool finished
Definition RF24Client.h:0
RF24EthernetClass RF24Ethernet
void begin(const IPAddress &aDNSServer)
Definition Dns.cpp:45
int getHostByName(const char *aHostname, IPAddress &aResult)
Definition Dns.cpp:110
virtual bool operator==(const EthernetClient &)
size_t write(uint8_t)
int connect(IPAddress ip, uint16_t port)
static void error_callback(void *arg, err_t err)
static err_t srecv_callback(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
int waitAvailable(uint32_t timeout=750)
static ConnectState * gState[2]
Definition RF24Client.h:218
static bool activeState
Definition RF24Client.h:233
static err_t recv_callback(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
static err_t sent_callback(void *arg, struct tcp_pcb *tpcb, uint16_t len)
uint8_t connected()
#define Ethernet
#define IF_ETH_DEBUG_L2(x)
#define IF_RF24ETHERNET_DEBUG_CLIENT(x)
#define IF_ETH_DEBUG_L1(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
volatile err_t result
Definition RF24Client.h:206
uint16_t u16_t
16 bit datatype
Definition uip-conf.h:245
void serialip_appcall(void)