RF24Ethernet - TCP/IP over RF24Network v2.2.1
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 == 2
20 #include <zephyr/kernel.h>
21 #include <zephyr/net/socket.h>
22 #include <errno.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <fcntl.h>
26 #include <zephyr/net/net_if.h>
27 #include <zephyr/posix/sys/ioctl.h>
28 #ifdef __cplusplus
29extern "C" {
30 #endif
31
32struct net_if* rf24_netif_get_iface(void);
33
34 #ifdef __cplusplus
35}
36
37 #endif
38
39RF24Client* RF24Client::g_rf24client_instance = nullptr;
40int RF24Client::_socket;
41uint32_t RF24Client::serverConnectionTimeout;
42uint8_t RF24Client::peekBuffer[64];
43
44#endif
45#if USE_LWIP < 1
46
47 #define UIP_TCP_PHYH_LEN UIP_LLH_LEN + UIP_IPTCPH_LEN
48uip_userdata_t RF24Client::all_data[UIP_CONNS];
49
50#elif USE_LWIP == 1
51// #define LWIP_ERR_T uint32_t
52
53 //
54 #if !defined ETHERNET_USING_LWIP_ARDUINO
55 #include <lwip/tcp.h>
56 #include "lwip/tcpip.h"
57 #include "lwip/timeouts.h"
58 #else
59 #include "lwip/include/lwip/tcp.h"
60 #include "lwip/include/lwip/tcpip.h"
61 #endif
62
63 #include "RF24Ethernet.h"
64/** \cond */
66char* RF24Client::incomingData[2];
67uint16_t RF24Client::dataSize[2];
68struct tcp_pcb* RF24Client::myPcb;
69uint32_t RF24Client::clientConnectionTimeout;
70uint32_t RF24Client::serverConnectionTimeout;
71uint32_t RF24Client::simpleCounter;
73int32_t RF24Client::accepts;
74
75/***************************************************************************************************/
76
77// Called when the remote host acknowledges receipt of data
78err_t RF24Client::sent_callback(void* arg, struct tcp_pcb* tpcb, u16_t len)
79{
80
81 ConnectState* state = (ConnectState*)arg;
82 if (state != nullptr) {
83 state->serverTimer = millis();
84 state->clientTimer = millis();
85 IF_ETH_DEBUG_L1(Serial.println("Client: Sent cb"););
86
87 if (state->dataSentSize >= len) {
88 state->dataSentSize -= len;
89 }
90 else {
91 state->dataSentSize = 0;
92 }
93
94 if (state->dataSentSize == 0) {
95 state->waiting_for_ack = false;
96 }
97 else {
98 state->waiting_for_ack = true;
99 }
100 state->result = ERR_OK;
101 }
102
103 return ERR_OK;
104}
105
106/***************************************************************************************************/
107
108err_t RF24Client::blocking_write(struct tcp_pcb* fpcb, ConnectState* fstate, const char* data, size_t len)
109{
110
111 if (fpcb == nullptr) {
112 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Client: Tx with no fpcb"););
113 return ERR_CLSD;
114 }
115
116 if (!fstate->connected) {
117 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Client: Tx with no connection"););
118 return ERR_CLSD;
119 }
120
121 const uint32_t timeoutStart = millis();
122
123 if (len > tcp_sndbuf(fpcb)) {
124 #if defined RF24ETHERNET_CORE_REQUIRES_LOCKING
125 if (Ethernet.useCoreLocking) {
126 ETHERNET_APPLY_LOCK();
127 }
128 #endif
129 tcp_output(fpcb);
130 #if defined RF24ETHERNET_CORE_REQUIRES_LOCKING
131 if (Ethernet.useCoreLocking) {
132 ETHERNET_REMOVE_LOCK();
133 }
134 #endif
135 fstate->waiting_for_ack = true;
136 }
137
138 while (len > tcp_sndbuf(fpcb)) {
139 Ethernet.update();
140 if (millis() - timeoutStart > serverConnectionTimeout) {
141 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println("Client: TCP Send Buffer full"););
142 return ERR_BUF;
143 }
144 }
145
146 #if defined RF24ETHERNET_CORE_REQUIRES_LOCKING
147 if (Ethernet.useCoreLocking) {
148 ETHERNET_APPLY_LOCK();
149 }
150 #endif
151
152 err_t err = ERR_CLSD;
153 if (fpcb != nullptr) {
154 err = tcp_write(fpcb, data, len, TCP_WRITE_FLAG_COPY);
155 }
156
157 if (err != ERR_OK) {
158 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Client: BLK Write fail 2: "); Serial.println((int)err););
159
160 #if defined RF24ETHERNET_CORE_REQUIRES_LOCKING
161 if (Ethernet.useCoreLocking) {
162 ETHERNET_REMOVE_LOCK();
163 }
164 #endif
165 return err;
166 }
167
168 #if defined RF24ETHERNET_CORE_REQUIRES_LOCKING
169 if (Ethernet.useCoreLocking) {
170 ETHERNET_REMOVE_LOCK();
171 }
172 #endif
173
174 const uint32_t timerStart = millis();
175 while (fstate != nullptr && fstate->waiting_for_ack) {
176 if (!fstate->connected) {
177 return ERR_CLSD;
178 }
179 if (millis() - timerStart > 5000) {
180 if (fstate != nullptr) {
181 return ERR_CLSD;
182 }
183 break;
184 }
185 Ethernet.update();
186 }
187
188 return ERR_OK;
189}
190
191/***************************************************************************************************/
192
193void RF24Client::error_callback(void* arg, err_t err)
194{
195
196 ConnectState* state = (ConnectState*)arg;
197 if (state != nullptr) {
198 state->result = err;
199 state->connected = false;
200 state->waiting_for_ack = false;
201 state->dataSentSize = 0;
202 dataSize[state->stateActiveID] = 0;
203 if (state->stateActiveID == activeState) {
204 myPcb = nullptr;
205 }
206 }
207 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Client: Err cb: "); Serial.println((int)err););
208}
209
210/***************************************************************************************************/
211
212err_t RF24Client::srecv_callback(void* arg, struct tcp_pcb* tpcb, struct pbuf* p, err_t err)
213{
214
215 ConnectState* state = (ConnectState*)arg;
216
217 if (state != nullptr) {
218 state->serverTimer = millis();
219 }
220
221 if (p == nullptr) {
222 if (state != nullptr) {
223 state->connected = false;
224 }
225 if (tpcb != nullptr) {
226 if (tcp_close(tpcb) != ERR_OK) {
227 tcp_abort(tpcb);
228 tpcb = nullptr;
229 if (state->stateActiveID == activeState) {
230 myPcb = nullptr;
231 }
232 return ERR_ABRT;
233 }
234 tpcb = nullptr;
235 if (state->stateActiveID == activeState) {
236 myPcb = nullptr;
237 }
238 }
239 return ERR_OK;
240 }
241 if (err != ERR_OK || state == nullptr) {
242 if (p)
243 pbuf_free(p);
244 return ERR_OK;
245 }
246
247 bool id = state->stateActiveID;
248 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Server: Copy data to "); Serial.println(state->stateActiveID););
249
250 struct pbuf* q = p;
251
252 uint32_t timeout = millis();
253 while (q != nullptr) {
254 if (millis() - timeout > 3000) {
255 break;
256 }
257 const uint8_t* data = static_cast<const uint8_t*>(q->payload);
258 if (dataSize[id] + q->len < INCOMING_DATA_SIZE) {
259 memcpy(&incomingData[id][dataSize[id]], data, q->len);
260 dataSize[id] += q->len;
261 }
262 else {
263 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println("Server: srecv - Out of incoming buffer space"););
264 }
265 q = q->next;
266 }
267
268 if (tpcb != nullptr) {
269 tcp_recved(tpcb, p->tot_len);
270 }
271 if (p) {
272 pbuf_free(p);
273 }
274 return ERR_OK;
275}
276
277/***************************************************************************************************/
278
279err_t RF24Client::recv_callback(void* arg, struct tcp_pcb* tpcb, struct pbuf* p, err_t err)
280{
281
282 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println("Client: Recv cb"););
283
284 ConnectState* state = (ConnectState*)arg;
285 if (p == nullptr) {
286 if (state != nullptr) {
287 state->connected = false;
288 }
289 if (tpcb != nullptr) {
290 if (tcp_close(tpcb) != ERR_OK) {
291 tcp_abort(tpcb);
292 tpcb = nullptr;
293 if (state->stateActiveID == activeState) {
294 myPcb = nullptr;
295 }
296 return ERR_ABRT;
297 }
298 tpcb = nullptr;
299 if (state->stateActiveID == activeState) {
300 myPcb = nullptr;
301 }
302 }
303 return err;
304 }
305 if (err != ERR_OK || state == nullptr) {
306 if (p)
307 pbuf_free(p);
308
309 return err;
310 }
311
312 if (state != nullptr) {
313 state->clientTimer = millis();
314 }
315
316 bool id = state->stateActiveID;
317 struct pbuf* q = p;
318 uint32_t timeout = millis();
319 while (q != nullptr) {
320 if (millis() - timeout > 3000) {
321 break;
322 }
323 const uint8_t* data = static_cast<const uint8_t*>(q->payload);
324 if (dataSize[id] + q->len < INCOMING_DATA_SIZE) {
325 memcpy(&incomingData[id][dataSize[id]], data, q->len);
326 dataSize[id] += q->len;
327 }
328 else {
329 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println("Client: recv - Out of incoming buffer space"););
330 }
331 q = q->next;
332 }
333
334 if (tpcb != nullptr) {
335 tcp_recved(tpcb, p->tot_len);
336 }
337 if (p) {
338 pbuf_free(p);
339 }
340 return ERR_OK;
341}
342
343/***************************************************************************************************/
344
345//void RF24Client::setConnectionTimeout(uint32_t timeout)
346//{
347
348// clientConnectionTimeout = timeout;
349//}
350
351/***************************************************************************************************/
352
353err_t RF24Client::clientTimeouts(void* arg, struct tcp_pcb* tpcb)
354{
355
356 ConnectState* state = (ConnectState*)arg;
357
358 if (state != nullptr) {
359 if (millis() - state->clientTimer > state->cConnectionTimeout) {
360 if (tpcb->state == ESTABLISHED || tpcb->state == SYN_SENT || tpcb->state == SYN_RCVD) {
361 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println("Client: Closed Client PCB TIMEOUT"););
362 err_t err = tcp_close(tpcb);
363 state->result = err;
364 state->connected = false;
365 }
366 }
367 }
368 return ERR_OK;
369}
370
371/***************************************************************************************************/
372
373err_t RF24Client::serverTimeouts(void* arg, struct tcp_pcb* tpcb)
374{
375
376 ConnectState* state = (ConnectState*)arg;
377
378 if (state != nullptr && tpcb != nullptr) {
379 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Server: Stimeout cb "); Serial.println(millis() - state->serverTimer););
380
381 state->result = ERR_OK;
382
383 if (millis() - state->serverTimer > state->sConnectionTimeout) {
384 //if (tpcb->state == ESTABLISHED || tpcb->state == SYN_SENT || tpcb->state == SYN_RCVD) {
385 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println("Server: Closed Server PCB TIMEOUT "););
386
387 state->result = tcp_close(tpcb);
388 state->closeTimer = millis();
389 dataSize[activeState] = 0;
390 state->connected = false;
391 if (state->result != ERR_OK) {
392 tcp_arg(tpcb, nullptr);
393 tcp_abort(tpcb);
394 tpcb = nullptr;
395 tcp_arg(myPcb, nullptr);
396 myPcb = nullptr;
397 return ERR_ABRT;
398 }
399 myPcb = nullptr;
400 return state->result;
401
402 // }
403 }
404 return state->result;
405 }
406 return ERR_CLSD;
407}
408
409/***************************************************************************************************/
410
411err_t RF24Client::closed_port(void* arg, struct tcp_pcb* tpcb)
412{
413
414 ConnectState* state = (ConnectState*)arg;
415
416 if (state != nullptr) {
417 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Server: Client Poll Cb ID: "); Serial.println(state->identifier));
418 }
419
420 if (myPcb == nullptr) {
421 if (state != nullptr && tpcb != nullptr) {
422
423 if ((tpcb->state == ESTABLISHED || tpcb->state == SYN_SENT || tpcb->state == SYN_RCVD)) {
424 if (state->backlogWasAccepted == false) {
425
426 state->backlogWasAccepted = true;
427 state->connectTimestamp = millis();
428 state->connected = true;
429 accepts--;
430 myPcb = tpcb;
431 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Server: ACCEPT delayed PCB "); Serial.println(state->identifier););
432
433 tcp_backlog_accepted(tpcb);
434 activeState = state->stateActiveID;
435 return ERR_OK;
436 }
437 }
438 }
439 }
440
441 if (tpcb != nullptr) {
442 if (state != nullptr) {
443 if (millis() - state->connectTimestamp > state->sConnectionTimeout) {
444
445 if ((tpcb->state == ESTABLISHED || tpcb->state == SYN_SENT || tpcb->state == SYN_RCVD)) {
446
447 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Server: Close off delayed PCB function 1, ID: "); Serial.println(state->identifier););
448
449 if (state->backlogWasAccepted == false) {
450 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println("Server: With backlog accepted"););
451 tcp_backlog_accepted(tpcb);
452 state->backlogWasAccepted = true;
453 accepts--;
454 }
455
456 state->result = tcp_close(tpcb);
457 state->connected = false;
458 if (state->result == ERR_OK) {
459 state->closeTimer = millis();
460 }
461 else {
462 tcp_abort(tpcb);
463 tpcb = nullptr;
464 return ERR_ABRT;
465 }
466
467 return state->result;
468 }
469 }
470 }
471 }
472
473 return ERR_OK;
474}
475
476/**************************************************************************************************/
477
478err_t RF24Client::accept(void* arg, struct tcp_pcb* tpcb, err_t err)
479{
480 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Server: Accept cb, ID: "); Serial.println(simpleCounter + 1););
481
482 if (tpcb == nullptr) {
483 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Server: Accepted conn, but no tpcb from: "); Serial.println(ip4addr_ntoa(ip_2_ip4(&tpcb->remote_ip))););
484 return ERR_CLSD;
485 }
486
487 if (tpcb != nullptr) {
488 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Server: Client connect from: "); Serial.println(ip4addr_ntoa(ip_2_ip4(&tpcb->remote_ip))););
489 }
490 bool actState = activeState;
491
492 if (myPcb != nullptr) {
493
494 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Server: Accept w/already connected: Accepted_Conns - Delayed_Conns == "); Serial.println(accepts););
495 tcp_backlog_delayed(tpcb);
496 accepts++;
497 tcp_poll(tpcb, closed_port, 5);
498 actState = !activeState;
499 gState[actState]->connected = false;
500 gState[actState]->backlogWasAccepted = false;
501 }
502 else {
503 myPcb = tpcb;
504 tcp_poll(tpcb, serverTimeouts, 8);
506 actState = activeState;
507 gState[actState]->connected = true;
508 gState[actState]->backlogWasAccepted = true;
509 }
510
511 dataSize[actState] = 0;
512
513 simpleCounter += 1;
514 gState[actState]->stateActiveID = actState;
515 gState[actState]->identifier = simpleCounter;
516 gState[actState]->sConnectionTimeout = serverConnectionTimeout;
517 gState[actState]->connectTimestamp = millis();
518 gState[actState]->serverTimer = millis();
519 gState[actState]->dataSentSize = 0;
520
521 tcp_arg(tpcb, RF24Client::gState[actState]);
522 tcp_recv(tpcb, srecv_callback);
523 tcp_sent(tpcb, sent_callback);
524 tcp_err(tpcb, error_callback);
525
526 return ERR_OK;
527}
528
529/***************************************************************************************************/
530err_t RF24Client::closeConn(void* arg, struct tcp_pcb* tpcb)
531{
532 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println("Client: Immediate close"););
533 if (tpcb != nullptr) {
534 tcp_close(tpcb);
535 }
536
537 return ERR_OK;
538}
539
540/***************************************************************************************************/
541
542// Callback triggered by lwIP when handshake completes
543
544err_t RF24Client::on_connected(void* arg, struct tcp_pcb* tpcb, err_t err)
545{
546 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println("Client: Conn cb"););
547
548 ConnectState* state = (ConnectState*)arg;
549
550 if (state != nullptr) {
551 /*if (state->cConnectionTimeout > 0) {
552 #if defined RF24ETHERNET_CORE_REQUIRES_LOCKING
553 if(Ethernet.useCoreLocking){if(Ethernet.useCoreLocking){ ETHERNET_APPLY_LOCK(); } }
554 #endif
555 tcp_poll(tpcb, clientTimeouts, 30);
556 #if defined RF24ETHERNET_CORE_REQUIRES_LOCKING
557 if(Ethernet.useCoreLocking){ ETHERNET_REMOVE_LOCK(); }
558 #endif
559 }*/
560
561 state->cConnectionTimeout = clientConnectionTimeout;
562 state->clientTimer = millis();
563 state->result = err;
564 if (err == ERR_OK) {
565 state->connected = true;
566 }
567 else {
568 state->connected = false;
569 }
570 }
571 return err;
572}
573/** \endcond */
574#endif // USE_LWIP == 1
575
576/***************************************************************************************************/
577
578#if USE_LWIP < 1
579RF24Client::RF24Client() : data(NULL)
580{
581}
582#elif USE_LWIP == 1
584{
585}
586#elif USE_LWIP == 2
587RF24Client::RF24Client() : data(0), _lastError(0)
588{
589 g_rf24client_instance = this;
590}
591#endif
592/*************************************************************/
593
594#if USE_LWIP < 1
595RF24Client::RF24Client(uip_userdata_t* conn_data) : data(conn_data)
596{
597}
598#else
599/** \cond */
600RF24Client::RF24Client(uint32_t data) : data(0)
601{
602}
603/** \endcond */
604#endif
605/*************************************************************/
606
608{
609#if USE_LWIP < 1
610 return (data && (data->packets_in != 0 || (data->state & UIP_CLIENT_CONNECTED))) ? 1 : 0;
611#elif USE_LWIP == 1
612 if (gState[activeState] != nullptr) {
613 return gState[activeState]->connected;
614 }
615 return 0;
616#elif USE_LWIP == 2
617
618 if (_socket < 0) {
619 return 0;
620 }
621
622 RF24Ethernet.update();
623
624 // 1. If we already established the connection before, track via standard POLLIN/errors
625 if (connectionEstablished) {
626 struct zsock_pollfd pfd {};
627 pfd.fd = _socket;
628 pfd.events = ZSOCK_POLLIN;
629
630 int rc = zsock_poll(&pfd, 1, 0);
631 if (rc < 0)
632 return 0;
633
634 if (rc > 0) {
635 if (pfd.revents & (ZSOCK_POLLHUP | ZSOCK_POLLERR | ZSOCK_POLLNVAL)) {
636 connectionEstablished = false;
637 if (_socket >= 0) {
638 zsock_close(_socket);
639 _socket = -1;
640 }
641 return 0;
642 }
643 if (pfd.revents & ZSOCK_POLLIN) {
644 uint8_t dummy;
645 int n = zsock_recv(_socket, &dummy, 1, ZSOCK_MSG_PEEK | ZSOCK_MSG_DONTWAIT);
646 if (n == 0) { // Remote peer closed connection (FIN)
647 connectionEstablished = false;
648 if (_socket >= 0) {
649 zsock_close(_socket);
650 _socket = -1;
651 }
652 return 0;
653 }
654 }
655 }
656 return 1;
657 }
658
659 // 2. Handshake Phase: Check if the background connect has finished
660 struct zsock_pollfd pfd {};
661 pfd.fd = _socket;
662 pfd.events = ZSOCK_POLLOUT; // A successful non-blocking connect makes the socket writable
663
664 int rc = zsock_poll(&pfd, 1, 0);
665 if (rc < 0) {
666 return 0; // Poll failed
667 }
668
669 // If poll returns 0, the handshake is still actively processing in the background (EINPROGRESS)
670 if (rc == 0) {
671 return 0;
672 }
673
674 // The socket state changed. Let's see if it's an error or a success.
675 if (pfd.revents & (ZSOCK_POLLERR | ZSOCK_POLLHUP)) {
676 if (_socket >= 0) {
677 zsock_close(_socket);
678 _socket = -1;
679 }
680 return 0; // Failed to connect
681 }
682
683 if (pfd.revents & ZSOCK_POLLOUT) {
684 // Double-check the socket's internal error state to confirm success
685 int error = 0;
686 socklen_t len = sizeof(error);
687
688 int ret = zsock_getsockopt(_socket, SOL_SOCKET, SO_ERROR, &error, &len);
689 if (ret < 0 || error != 0) {
690 if (_socket >= 0) {
691 zsock_close(_socket);
692 _socket = -1;
693 }
694 return 0; // The handshake failed behind the scenes (e.g. Connection Refused)
695 }
696
697 // Connection successfully established!
698 connectionEstablished = true;
699 return 1;
700 }
701
702 if (_socket >= 0) {
703 zsock_close(_socket);
704 _socket = -1;
705 }
706 return 0;
707
708#endif
709}
710
711/*************************************************************/
712
713int RF24Client::connect(IPAddress ip, uint16_t port)
714{
715
716#if USE_LWIP < 1
717 #if UIP_ACTIVE_OPEN > 0
718
719 // do{
720
721 stop();
722 uip_ipaddr_t ipaddr;
723 uip_ip_addr(ipaddr, ip);
724
725 struct uip_conn* conn = uip_connect(&ipaddr, htons(port));
726
727 if (conn)
728 {
729 #if UIP_CONNECTION_TIMEOUT > 0
730 uint32_t timeout = millis();
731 #endif
732
733 while ((conn->tcpstateflags & UIP_TS_MASK) != UIP_CLOSED)
734 {
735 Ethernet.update();
736
737 if ((conn->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED)
738 {
739 data = (uip_userdata_t*)conn->appstate;
740 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););
741 return 1;
742 }
743
744 #if UIP_CONNECTION_TIMEOUT > 0
745 if ((millis() - timeout) > UIP_CONNECTION_TIMEOUT)
746 {
747 conn->tcpstateflags = UIP_CLOSED;
748 break;
749 }
750 #endif
751 }
752 }
753 // delay(25);
754 // }while(millis()-timer < 175);
755
756 #endif // Active open enabled
757#elif USE_LWIP == 1
758
759 if (myPcb != nullptr) {
760 _stop();
761 return ERR_CLSD;
762 }
763
764 #if defined RF24ETHERNET_CORE_REQUIRES_LOCKING
765 if (Ethernet.useCoreLocking) {
766 ETHERNET_APPLY_LOCK();
767 }
768 #endif
769
770 if (myPcb == nullptr) {
771 myPcb = tcp_new();
772 }
773
774 if (!myPcb) {
775 #if defined RF24ETHERNET_CORE_REQUIRES_LOCKING
776 if (Ethernet.useCoreLocking) {
777 ETHERNET_REMOVE_LOCK();
778 }
779 #endif
780 return 0;
781 }
782
783 dataSize[activeState] = 0;
784 memset(incomingData[activeState], 0, INCOMING_DATA_SIZE);
785 gState[activeState]->dataSentSize = 0;
786 gState[activeState]->connected = false;
787 gState[activeState]->result = 0;
788 tcp_arg(myPcb, gState[activeState]);
789 tcp_err(myPcb, error_callback);
790 tcp_recv(myPcb, recv_callback);
791 tcp_sent(myPcb, sent_callback);
792 //tcp_poll(myPcb, clientTimeouts, 30);
793
794 err_t err = ERR_OK;
795
796 ip_addr_t myIp;
797 IP_ADDR4(&myIp, ip[0], ip[1], ip[2], ip[3]);
798
799 err = tcp_connect(myPcb, &myIp, port, on_connected);
800
801 if (err != ERR_OK || gState[activeState]->result != ERR_OK) {
802 #if defined RF24ETHERNET_CORE_REQUIRES_LOCKING
803 if (Ethernet.useCoreLocking) {
804 ETHERNET_REMOVE_LOCK();
805 }
806 #endif
807
808 stop();
809 return ERR_CLSD;
810 }
811
812 #if defined RF24ETHERNET_CORE_REQUIRES_LOCKING
813 if (Ethernet.useCoreLocking) {
814 ETHERNET_REMOVE_LOCK();
815 }
816 #endif
817
818 const uint32_t timeoutStart = millis();
819 // Simulate blocking by looping until the callback sets 'connected'
820 while (!gState[activeState]->connected && millis() - timeoutStart < 5000) {
821 Ethernet.update();
822 }
823
824 if (clientConnectionTimeout > 0) {
825 gState[activeState]->clientPollingSetup = 1;
826 }
827
828 return gState[activeState]->connected;
829
830#elif USE_LWIP == 2
831
832 if (port == 0)
833 return -EINVAL;
834
835 int sock = zsock_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
836 if (sock < 0) {
837 return -errno;
838 }
839
840 // --- CRITICAL FIX 1: Set the socket to non-blocking BEFORE connecting ---
841 int flags = zsock_fcntl(sock, F_GETFL, 0);
842 if (flags < 0) {
843 int e = errno;
844 zsock_close(sock);
845 return -e;
846 }
847 zsock_fcntl(sock, F_SETFL, flags | O_NONBLOCK);
848
849 struct sockaddr_in addr = {};
850 addr.sin_family = AF_INET;
851 addr.sin_port = htons(port);
852
853 char ipstr[16];
854 snprintf(ipstr, sizeof(ipstr), "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
855 if (net_addr_pton(AF_INET, ipstr, &addr.sin_addr) < 0) {
856 zsock_close(sock);
857 return -EINVAL;
858 }
859
860 int rc = zsock_connect(sock, (const struct sockaddr*)&addr, sizeof(addr));
861 if (rc == 0) {
862
863 _socket = sock; // <-- save it here
864 _lastError = 0;
865 IF_RF24ETHERNET_DEBUG_CLIENT(printk("CONNECT OK fd=%d\n", _socket));
867 return 1;
868 }
869 if (errno != EINPROGRESS) {
870 int e = errno;
871 zsock_close(sock);
872 return -e;
873 }
874
875 // --- CRITICAL FIX 2: Use Zephyr's native uptime timer instead of Arduino's millis() ---
876 int64_t start_time = k_uptime_get();
877
878 // Loop for up to 5000 milliseconds (5 seconds)
879 while (k_uptime_get() - start_time < 5000) {
880 // 1) Service RF24 every iteration
881 RF24Ethernet.update();
882
883 // 2) Non-blocking check of connect completion
884 struct zsock_pollfd pfd = {
885 .fd = sock,
886 .events = ZSOCK_POLLOUT,
887 .revents = 0,
888 };
889
890 rc = zsock_poll(&pfd, 1, 0); // zero timeout
891 if (rc < 0) {
892 int e = errno;
893 zsock_close(sock);
894 return -e;
895 }
896
897 if (rc > 0 && (pfd.revents & (ZSOCK_POLLOUT | ZSOCK_POLLERR | ZSOCK_POLLHUP))) {
898 int soerr = 0;
899 socklen_t slen = sizeof(soerr);
900 if (zsock_getsockopt(sock, SOL_SOCKET, SO_ERROR, &soerr, &slen) < 0) {
901 int e = errno;
902 zsock_close(sock);
903 return -e;
904 }
905
906 if (soerr == 0) {
907 // Remove O_NONBLOCK flag to cleanly destroy blocking context
908 zsock_fcntl(sock, F_SETFL, flags & ~O_NONBLOCK);
909 _socket = sock; // <-- save it here
910 _lastError = 0;
911 IF_RF24ETHERNET_DEBUG_CLIENT(printk("CONNECT OK fd=%d\n", _socket));
913 return 1;
914 }
915
916 zsock_fcntl(sock, F_SETFL, flags & ~O_NONBLOCK);
917 zsock_close(sock);
918 return -soerr;
919 }
920
921 // --- CRITICAL FIX 3: Use Zephyr's native kernel sleep to yield CPU time ---
922 // This yields execution to Zephyr's network workqueues, timers, and scheduler threads
923 k_msleep(2);
924 }
925
926 // Timed out cleanup
927 zsock_fcntl(sock, F_SETFL, flags & ~O_NONBLOCK);
928 zsock_close(sock);
929 return -ETIMEDOUT;
930
931 return 0;
932
933#endif
934 return 0;
935}
936
937/*************************************************************/
938
939#if USE_LWIP == 1
940void dnsCallback(const char* name, const ip_addr_t* ipaddr, void* callback_arg)
941{
942}
943#endif
944/*************************************************************/
945
946int RF24Client::connect(const char* host, uint16_t port)
947{
948 // Look up the host first
949 int ret = 0;
950
951#if UIP_UDP
952 DNSClient dns;
953 IPAddress remote_addr;
954
955 dns.begin(RF24EthernetClass::_dnsServerAddress);
956 ret = dns.getHostByName(host, remote_addr);
957
958 if (ret == 1)
959 {
960 #if defined(ETH_DEBUG_L1) || defined(RF24ETHERNET_DEBUG_DNS)
961 Serial.println(F("*UIP Got DNS*"));
962 #endif
963 return connect(remote_addr, port);
964 }
965#elif RF24ETHERNET_USE_UDP
966
967 DNSClient dns;
968 IPAddress remote_addr;
969
970 dns.begin(RF24EthernetClass::_dnsServerAddress);
971 ret = dns.getHostByName(host, remote_addr);
972
973 if (ret == 1)
974 {
975 #if defined(ETH_DEBUG_L1) || defined(RF24ETHERNET_DEBUG_DNS)
976 Serial.println(F("*lwIP Got DNS*"));
977 #endif
978 return connect(remote_addr, port);
979 }
980
981#else // ! UIP_UDP
982 // Do something with the input parameters to prevent compile time warnings
983 if (host) {
984 };
985 if (port) {
986 };
987#endif // ! UIP_UDP
988
989#if defined(ETH_DEBUG_L1) || defined(RF24ETHERNET_DEBUG_DNS)
990 Serial.println(F("* DNS fail*"));
991#endif
992
993 return 0;
994}
995
996/*************************************************************/
997
999{
1000#if USE_LWIP < 1
1001 if (data && data->state)
1002 {
1003
1004 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print(millis()); Serial.println(F(" before stop(), with data")););
1005
1006 data->packets_in = 0;
1007 data->dataCnt = 0;
1008
1009 if (data->state & UIP_CLIENT_REMOTECLOSED)
1010 {
1011 data->state = 0;
1012 }
1013 else
1014 {
1015 data->state |= UIP_CLIENT_CLOSE;
1016 }
1017
1018 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(F("after stop()")););
1019 }
1020 else
1021 {
1022 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print(millis()); Serial.println(F(" stop(), data: NULL")););
1023 }
1024
1025 data = NULL;
1026 RF24Ethernet.update();
1027#elif USE_LWIP == 1
1028
1029 _stop();
1030
1031#elif USE_LWIP == 2
1032 if (_socket >= 0) {
1033 zsock_close(_socket);
1034 _socket = -1;
1035 }
1037
1038#endif
1039}
1040
1041/***************************************************************************************************/
1042#if USE_LWIP == 1
1043void RF24Client::_stop()
1044{
1045 tcp_pcb* pcb = myPcb;
1046 myPcb = nullptr;
1047
1048 if (pcb != nullptr) {
1049 #if defined RF24ETHERNET_CORE_REQUIRES_LOCKING
1050 if (Ethernet.useCoreLocking) {
1051 ETHERNET_APPLY_LOCK();
1052 }
1053 #endif
1054 if (pcb->state != CLOSED) {
1055 tcp_arg(pcb, NULL);
1056 tcp_recv(pcb, NULL);
1057 tcp_sent(pcb, NULL);
1058 tcp_err(pcb, NULL);
1059
1060 err_t err = tcp_close(pcb);
1061 if (err != ERR_OK) {
1062 tcp_abort(pcb);
1063 }
1064 }
1065 #if defined RF24ETHERNET_CORE_REQUIRES_LOCKING
1066 if (Ethernet.useCoreLocking) {
1067 ETHERNET_REMOVE_LOCK();
1068 }
1069 #endif
1070 }
1071
1072 gState[activeState]->connected = false;
1073 gState[activeState]->dataSentSize = 0;
1074}
1075#endif
1076/*************************************************************/
1077
1078// the next function allows us to use the client returned by
1079// EthernetServer::available() as the condition in an if-statement.
1081{
1082#if USE_LWIP < 1
1083 return data && rhs.data && (data == rhs.data);
1084#elif USE_LWIP == 1
1085 return dataSize[activeState] > 0 ? true : false;
1086#elif USE_LWIP == 2
1087 return available();
1088
1089#endif
1090}
1091
1092/*************************************************************/
1093
1094RF24Client::operator bool()
1095{
1096 Ethernet.update();
1097#if USE_LWIP < 1
1098 return data && (!(data->state & UIP_CLIENT_REMOTECLOSED) || data->packets_in != 0);
1099#elif USE_LWIP == 1
1100 return dataSize[activeState] > 0 ? true : false;
1101#elif USE_LWIP == 2
1102
1103 return available();
1104#endif
1105}
1106
1107/*************************************************************/
1108
1109size_t RF24Client::write(uint8_t c)
1110{
1111 return _write(data, &c, 1);
1112}
1113
1114/*************************************************************/
1115
1116size_t RF24Client::write(const uint8_t* buf, size_t size)
1117{
1118 return _write(data, buf, size);
1119}
1120
1121/*************************************************************/
1122#if USE_LWIP < 1
1123size_t RF24Client::_write(uip_userdata_t* u, const uint8_t* buf, size_t size)
1124#else
1125size_t RF24Client::_write(uint8_t* data, const uint8_t* buf, size_t size)
1126
1127#endif
1128
1129{
1130
1131#if USE_LWIP < 1
1132 size_t total_written = 0;
1133 size_t payloadSize = rf24_min(size, UIP_TCP_MSS);
1134 uint32_t start = millis();
1135
1136test2:
1137
1138 Ethernet.update();
1139
1140 if (millis() - start > 5000)
1141 {
1142 if (u) {
1143 u->hold = false;
1144 }
1145 return total_written;
1146 }
1147
1148 if (u && !(u->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED)) && (u->state & UIP_CLIENT_CONNECTED))
1149 {
1150 if (u->out_pos + payloadSize > UIP_TCP_MSS || u->hold)
1151 {
1152 goto test2;
1153 }
1154
1156 Serial.println();
1157 Serial.print(millis());
1158 Serial.print(F(" UIPClient.write: writePacket("));
1159 Serial.print(u->packets_out);
1160 Serial.print(F(") pos: "));
1161 Serial.print(u->out_pos);
1162 Serial.print(F(", buf["));
1163 Serial.print(size - total_written);
1164 Serial.print(F("]: '"));
1165 Serial.write((uint8_t*)buf + total_written, payloadSize);
1166 Serial.println(F("'")););
1167
1168 memcpy(u->myData + u->out_pos, buf + total_written, payloadSize);
1169 u->packets_out = 1;
1170 u->out_pos += payloadSize;
1171 total_written += payloadSize;
1172
1173 if (total_written < size)
1174 {
1175 size_t remain = size - total_written;
1176 payloadSize = rf24_min(remain, UIP_TCP_MSS);
1177 goto test2;
1178 }
1179
1180 u->hold = false;
1181 return u->out_pos;
1182 }
1183
1184 if (u) {
1185 u->hold = false;
1186 }
1187 return 0;
1188#elif USE_LWIP == 1
1189
1190 bool initialActiveState = activeState;
1191 size_t chunk = MAX_PAYLOAD_SIZE - 14; // 14 = Ethernet/link-layer header bytes reserved per frame
1192 size_t position = 0;
1193
1194 gState[initialActiveState]->waiting_for_ack = false;
1195 uint32_t timeout = millis();
1196 while (size > chunk) {
1197 if (millis() - timeout > 3000) {
1198 break;
1199 }
1200 if (myPcb == nullptr)
1201 return 0;
1202
1203 gState[initialActiveState]->dataSentSize += chunk;
1204 err_t write_err = blocking_write(myPcb, gState[initialActiveState], reinterpret_cast<const char*>(&buf[position]), chunk);
1205
1206 if (write_err != ERR_OK) {
1207 gState[initialActiveState]->result = write_err;
1208 gState[initialActiveState]->connected = false;
1209 _stop();
1210 return 0;
1211 }
1212 position += chunk;
1213 size -= chunk;
1214 Ethernet.update();
1215 }
1216
1217 if (myPcb == nullptr)
1218 return 0;
1219
1220 gState[initialActiveState]->dataSentSize += chunk;
1221 err_t write_err = blocking_write(myPcb, gState[initialActiveState], reinterpret_cast<const char*>(&buf[position]), size);
1222
1223 if (write_err != ERR_OK) {
1224 gState[initialActiveState]->result = write_err;
1225 gState[initialActiveState]->connected = false;
1226 _stop();
1227 return 0;
1228 }
1229
1230 return position + size;
1231#elif USE_LWIP == 2
1232
1233 RF24Client* self = RF24Client::g_rf24client_instance;
1234 if (!self || !buf || size == 0)
1235 return 0;
1236
1237 if (self->_socket < 0) {
1238 self->_lastError = ENOTCONN;
1239 return 0;
1240 }
1241
1242 size_t total = 0;
1243 while (total < size) {
1244
1245 ssize_t n = zsock_send(self->_socket, buf + total, size - total, 0);
1246
1247 if (n > 0) {
1248 total += (size_t)n;
1249 continue;
1250 }
1251 if (n == 0)
1252 break;
1253
1254 int err = errno;
1255 self->_lastError = err;
1256 if (err == EINTR)
1257 continue;
1258 if (err == EAGAIN || err == EWOULDBLOCK)
1259 break;
1260 break;
1261 }
1262 Ethernet.update();
1263 return total;
1264
1265#endif
1266}
1267
1268/*************************************************************/
1269
1270void uip_log(char* msg)
1271{
1272 // Serial.println();
1273 // Serial.println("** UIP LOG **");
1274 // Serial.println(msg);
1275 if (msg)
1276 {
1277 };
1278}
1279
1280/*************************************************************/
1281#if USE_LWIP < 1
1282void serialip_appcall(void)
1283{
1284 uip_userdata_t* u = (uip_userdata_t*)uip_conn->appstate;
1285
1286 /*******Connected**********/
1287 if (!u && uip_connected())
1288 {
1289 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(); Serial.print(millis()); Serial.println(F(" UIPClient uip_connected")););
1290
1291 u = (uip_userdata_t*)EthernetClient::_allocateData();
1292
1293 if (u)
1294 {
1295 uip_conn->appstate = u;
1296 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print(F("UIPClient allocated state: ")); Serial.println(u->state, BIN););
1297 }
1298 else
1299 {
1300 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(F("UIPClient allocation failed")););
1301 }
1302 }
1303
1304 #if UIP_CONNECTION_TIMEOUT > 0
1305 if (u && u->connectTimeout > 0) {
1306 if (millis() - u->connectTimer > u->connectTimeout) {
1307 u->state |= UIP_CLIENT_CLOSE;
1308 u->connectTimer = millis();
1309 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(); Serial.print(millis()); Serial.println("UIP Client close(timeout)"););
1310 }
1311 }
1312 #endif
1313
1314 /*******User Data RX**********/
1315 if (u)
1316 {
1317 if (uip_newdata())
1318 {
1319 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(); Serial.print(millis()); Serial.print(F(" UIPClient uip_newdata, uip_len:")); Serial.println(uip_len););
1320 #if UIP_CONNECTION_TIMEOUT > 0
1321 u->connectTimer = millis();
1322 #endif
1323 u->hold = (u->out_pos = (u->windowOpened = (u->packets_out = false)));
1324
1325 if (uip_len && !(u->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED)))
1326 {
1327 uip_stop();
1328 u->state &= ~UIP_CLIENT_RESTART;
1329 u->windowOpened = false;
1330 u->restartTime = millis();
1331
1332 uint16_t writePos = u->in_pos + u->dataCnt;
1333 uint16_t incomingLen = uip_datalen();
1334
1335 if (writePos <= OUTPUT_BUFFER_SIZE && incomingLen <= (OUTPUT_BUFFER_SIZE - writePos))
1336 {
1337 memcpy(&u->myData[writePos], uip_appdata, incomingLen);
1338 u->dataCnt += incomingLen;
1339 u->packets_in = 1;
1340 }
1341 else
1342 {
1344 Serial.println(F("UIPClient RX overflow, closing connection")););
1345 u->state |= UIP_CLIENT_CLOSE;
1346 }
1347 }
1348 goto finish;
1349 }
1350
1351 /*******Closed/Timed-out/Aborted**********/
1352 // If the connection has been closed, save received but unread data.
1353 if (uip_closed() || uip_timedout() || uip_aborted())
1354 {
1355 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(); Serial.print(millis()); Serial.println(F(" UIPClient uip_closed")););
1356 // drop outgoing packets not sent yet:
1357 u->packets_out = 0;
1358
1359 if (u->packets_in)
1360 {
1361 ((uip_userdata_closed_t*)u)->lport = uip_conn->lport;
1362 u->state |= UIP_CLIENT_REMOTECLOSED;
1363 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(F("UIPClient close 1")););
1364 }
1365 else
1366 {
1367 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(F("UIPClient close 2")););
1368 u->state = 0;
1369 }
1370
1371 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(F("after UIPClient uip_closed")););
1372 uip_conn->appstate = NULL;
1373 goto finish;
1374 }
1375
1376 /*******ACKED**********/
1377 if (uip_acked())
1378 {
1379 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(); Serial.print(millis()); Serial.println(F(" UIPClient uip_acked")););
1380 u->state &= ~UIP_CLIENT_RESTART;
1381 u->hold = (u->out_pos = (u->windowOpened = (u->packets_out = false)));
1382 u->restartTime = millis();
1383 #if UIP_CONNECTION_TIMEOUT > 0
1384 u->connectTimer = millis();
1385 #endif
1386 }
1387
1388 /*******Polling**********/
1389 if (uip_poll() || uip_rexmit())
1390 {
1391 if (uip_rexmit()) {
1392 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print(F("ReXmit, Len: ")););
1393 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(u->out_pos));
1394 uip_len = u->out_pos;
1395 uip_send(u->myData, u->out_pos);
1396 u->hold = true;
1397 goto finish;
1398 }
1399 // IF_RF24ETHERNET_DEBUG_CLIENT( Serial.println(); Serial.println(F("UIPClient uip_poll")); );
1400
1401 if (u->packets_out != 0 && !u->hold)
1402 {
1403 uip_len = u->out_pos;
1404 uip_send(u->myData, u->out_pos);
1405 u->hold = true;
1406 goto finish;
1407 }
1408
1409 // Restart mechanism to keep connections going
1410 // Only call this if the TCP window has already been re-opened, the connection is being polled, but no data
1411 // has been acked
1412 if (!(u->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED)))
1413 {
1414
1415 if (u->windowOpened == true && u->state & UIP_CLIENT_RESTART && millis() - u->restartTime > u->restartInterval)
1416 {
1417 u->restartTime = millis();
1418 #if defined RF24ETHERNET_DEBUG_CLIENT || defined ETH_DEBUG_L1
1419 Serial.println();
1420 Serial.print(millis());
1421 #if UIP_CONNECTION_TIMEOUT > 0
1422 Serial.print(F(" UIPClient Re-Open TCP Window, time remaining before abort: "));
1423 Serial.println(UIP_CONNECTION_TIMEOUT - (millis() - u->connectTimer));
1424 #endif
1425 #endif
1426 u->restartInterval += 500;
1427 u->restartInterval = rf24_min(u->restartInterval, 7000);
1428 uip_restart();
1429 }
1430 }
1431 }
1432
1433 /*******Close**********/
1434 if (u->state & UIP_CLIENT_CLOSE)
1435 {
1436 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(); Serial.print(millis()); Serial.println(F(" UIPClient state UIP_CLIENT_CLOSE")););
1437
1438 if (u->packets_out == 0)
1439 {
1440 u->state = 0;
1441 uip_conn->appstate = NULL;
1442 uip_close();
1443 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(F("no blocks out -> free userdata")););
1444 }
1445 else
1446 {
1447 uip_stop();
1448 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(F("blocks outstanding transfer -> uip_stop()")););
1449 }
1450 }
1451finish:;
1452
1453 if (u->state & UIP_CLIENT_RESTART && !u->windowOpened)
1454 {
1455 if (!(u->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED)))
1456 {
1457 uip_restart();
1458 #if defined ETH_DEBUG_L1
1459 Serial.println();
1460 Serial.print(millis());
1461 Serial.println(F(" UIPClient Re-Open TCP Window"));
1462 #endif
1463 u->windowOpened = true;
1464 u->restartInterval = UIP_WINDOW_REOPEN_DELAY; //.75 seconds
1465 u->restartTime = millis();
1466 }
1467 }
1468 }
1469}
1470#endif
1471/*******************************************************/
1472#if USE_LWIP < 1
1473uip_userdata_t* RF24Client::_allocateData()
1474{
1475 for (uint8_t sock = 0; sock < UIP_CONNS; sock++)
1476 {
1477 uip_userdata_t* data = &RF24Client::all_data[sock];
1478 if (!data->state)
1479 {
1480 data->state = sock | UIP_CLIENT_CONNECTED;
1481 data->packets_in = 0;
1482 data->packets_out = 0;
1483 data->dataCnt = 0;
1484 data->in_pos = 0;
1485 data->out_pos = 0;
1486 data->hold = 0;
1487 data->restartTime = millis();
1488 data->restartInterval = 5000;
1489 #if (UIP_CONNECTION_TIMEOUT > 0)
1490 data->connectTimer = millis();
1491 data->connectTimeout = UIP_CONNECTION_TIMEOUT;
1492 #endif
1493 return data;
1494 }
1495 }
1496 return NULL;
1497}
1498#endif
1499
1500int RF24Client::waitAvailable(uint32_t timeout)
1501{
1502 uint32_t start = millis();
1503 while (available() < 1)
1504 {
1505 if (millis() - start > timeout)
1506 {
1507 return 0;
1508 }
1509 RF24Ethernet.update();
1510 }
1511 return available();
1512}
1513
1514/*************************************************************/
1515
1517{
1518 RF24Ethernet.update();
1519#if USE_LWIP < 1
1520 if (*this)
1521 {
1522 return _available(data);
1523 }
1524#else
1525 return _available(data);
1526#endif
1527 return 0;
1528}
1529
1530/*************************************************************/
1531#if USE_LWIP < 1
1532int RF24Client::_available(uip_userdata_t* u)
1533#else
1534int RF24Client::_available(uint8_t* data)
1535#endif
1536{
1537#if USE_LWIP < 1
1538 if (u->packets_in)
1539 {
1540 return u->dataCnt;
1541 }
1542#elif USE_LWIP == 1
1543 return dataSize[activeState];
1544#elif USE_LWIP == 2
1545
1546 RF24Client* self = RF24Client::g_rf24client_instance;
1547 if (!self || self->_socket < 0)
1548 return 0;
1549
1550 // First: is there readable/hup state?
1551 struct zsock_pollfd pfd
1552 {
1553 };
1554 pfd.fd = self->_socket;
1555 pfd.events = ZSOCK_POLLIN;
1556 int pr = zsock_poll(&pfd, 1, 0);
1557 if (pr <= 0)
1558 return 0;
1559
1560 // If peer closed, report 0 available
1561 //if (pfd.revents & (ZSOCK_POLLHUP | ZSOCK_POLLNVAL)) return 0;
1562 //if (!(pfd.revents & ZSOCK_POLLIN)) return 0;
1563
1564 // Peek queued bytes without consuming
1565 int n = zsock_recv(self->_socket, peekBuffer, sizeof(peekBuffer),
1566 ZSOCK_MSG_PEEK | ZSOCK_MSG_DONTWAIT);
1567
1568 if (n > 0)
1569 return n; // bytes currently queued (up to 1024)
1570 if (n == 0)
1571 return 0; // closed cleanly
1572 if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
1573 return 0;
1574 return 0;
1575#endif
1576 return 0;
1577}
1578
1579/*************************************************************/
1580
1581int RF24Client::read(uint8_t* buf, size_t size)
1582{
1583#if USE_LWIP < 1
1584 if (*this)
1585 {
1586 if (!data->packets_in)
1587 {
1588 return -1;
1589 }
1590 if (data->in_pos > OUTPUT_BUFFER_SIZE || data->dataCnt > OUTPUT_BUFFER_SIZE || (data->in_pos + data->dataCnt) > OUTPUT_BUFFER_SIZE)
1591 {
1592 data->state |= UIP_CLIENT_CLOSE;
1593 data->in_pos = 0;
1594 data->dataCnt = 0;
1595 return -1;
1596 }
1597 size = rf24_min(data->dataCnt, size);
1598 memcpy(buf, &data->myData[data->in_pos], size);
1599 data->dataCnt -= size;
1600
1601 data->in_pos += size;
1602
1603 if (!data->dataCnt)
1604 {
1605 data->packets_in = 0;
1606 data->in_pos = 0;
1607
1608 if (uip_stopped(&uip_conns[data->state & UIP_CLIENT_SOCKETS]) && !(data->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED)))
1609 {
1610 data->state |= UIP_CLIENT_RESTART;
1611 data->restartTime = 0;
1612
1613 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("**")););
1614 }
1615 else
1616 {
1617 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("**")););
1618 }
1619
1620 if (data->packets_in == 0)
1621 {
1622 if (data->state & UIP_CLIENT_REMOTECLOSED)
1623 {
1624 data->state = 0;
1625 data = NULL;
1626 }
1627 }
1628 }
1629 return size;
1630 }
1631
1632 return -1;
1633#elif USE_LWIP == 1
1634
1635 if (available()) {
1636
1637 if (size >= dataSize[activeState]) {
1638 memcpy(&buf[0], &incomingData[activeState][0], dataSize[activeState]);
1639 memmove(&incomingData[activeState][0], &incomingData[activeState][dataSize[activeState]], dataSize[activeState]);
1640 size = dataSize[activeState];
1641 dataSize[activeState] = 0;
1642 return size;
1643 }
1644 else {
1645 memcpy(&buf[0], &incomingData[activeState][0], size);
1646 memmove(&incomingData[activeState][0], &incomingData[activeState][size], dataSize[activeState] - size);
1647 dataSize[activeState] -= size;
1648 return size;
1649 }
1650 }
1651 return -1;
1652#elif USE_LWIP == 2
1653
1654 if (!buf || size == 0)
1655 return 0;
1656 if (_socket < 0) {
1657 _lastError = ENOTCONN;
1658 return -1;
1659 }
1660
1661 int n = zsock_recv(_socket, buf, size, ZSOCK_MSG_DONTWAIT);
1662
1663 if (n > 0) {
1664 return n; // got bytes
1665 }
1666
1667 if (n == 0) {
1668 // Peer performed orderly shutdown.
1669 // Do NOT close fd here; let caller decide via connected()/stop().
1671 _lastError = 0;
1672 return 0;
1673 }
1674
1675 // n < 0
1676 int err = errno;
1677 _lastError = err;
1678
1679 if (err == EAGAIN || err == EWOULDBLOCK || err == EINTR) {
1680 // no data yet, try again later
1681 return 0;
1682 }
1683
1684 // real error; optionally keep socket open unless clearly unusable
1685 if (err == EBADF || err == ENOTSOCK) {
1686 _socket = -1; // already invalid
1687 }
1688
1689 return -1;
1690#endif
1691}
1692
1693/*************************************************************/
1694
1696{
1697 uint8_t c;
1698 if (read(&c, 1) < 0)
1699 return -1;
1700 return c;
1701}
1702
1703/*************************************************************/
1704
1706{
1707 if (available())
1708 {
1709#if USE_LWIP < 1
1710 return data->myData[data->in_pos];
1711#elif USE_LWIP == 1
1712 return incomingData[activeState][0];
1713#elif USE_LWIP == 2
1714 return 0;
1715#endif
1716 }
1717 return -1;
1718}
1719
1720/*************************************************************/
1721
1723{
1724#if USE_LWIP < 1
1725 if (*this)
1726 {
1727 #if USE_LWIP < 1
1728 data->packets_in = 0;
1729 data->dataCnt = 0;
1730 #else
1731 data = 0;
1732 #endif
1733 }
1734#elif USE_LWIP == 1
1735 dataSize[activeState] = 0;
1736 gState[activeState]->dataSentSize = 0;
1737#elif USE_LWIP == 2
1738 while (available()) {
1739 read();
1740 }
1741#endif
1742}
void uip_log(char *msg)
void dnsCallback(const char *name, const ip_addr_t *ipaddr, void *callback_arg)
volatile err_t result
Definition RF24Client.h:4
#define INCOMING_DATA_SIZE
Definition RF24Client.h:85
#define uip_ip_addr(addr, ip)
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:226
static bool activeState
Definition RF24Client.h:241
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()
static bool connectionActive
Definition RF24Server.h:53
#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 OUTPUT_BUFFER_SIZE
Definition uip-conf.h:153
#define UIP_WINDOW_REOPEN_DELAY
Optional: Used with UIP_CONNECTION_TIMEOUT
Definition uip-conf.h:167
volatile bool stateActiveID
Definition RF24Client.h:208
uint16_t u16_t
16 bit datatype
Definition uip-conf.h:245
void serialip_appcall(void)