RF24Ethernet - TCP/IP over RF24Network v2.2.6
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 state->result = ERR_OK;
88 }
89
90 return ERR_OK;
91}
92
93/***************************************************************************************************/
94
95err_t RF24Client::blocking_write(struct tcp_pcb* fpcb, ConnectState* fstate, const char* data, size_t len)
96{
97
98 if (fpcb == nullptr) {
99 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Client: Tx with no fpcb"););
100 return ERR_CLSD;
101 }
102
103 if (!fstate->connected) {
104 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Client: Tx with no connection"););
105 return ERR_CLSD;
106 }
107
108 const uint32_t timeoutStart = millis();
109
110 if (len > tcp_sndbuf(fpcb)) {
111 #if defined RF24ETHERNET_CORE_REQUIRES_LOCKING
112 if (Ethernet.useCoreLocking) {
113 ETHERNET_APPLY_LOCK();
114 }
115 #endif
116 tcp_output(fpcb);
117 #if defined RF24ETHERNET_CORE_REQUIRES_LOCKING
118 if (Ethernet.useCoreLocking) {
119 ETHERNET_REMOVE_LOCK();
120 }
121 #endif
122 }
123
124 while (len > tcp_sndbuf(fpcb)) {
125 Ethernet.update();
126 if (!fstate->connected || myPcb != fpcb) {
127 return ERR_CLSD;
128 }
129 if (millis() - timeoutStart > serverConnectionTimeout) {
130 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println("Client: TCP Send Buffer full"););
131 return ERR_BUF;
132 }
133 }
134
135 #if defined RF24ETHERNET_CORE_REQUIRES_LOCKING
136 if (Ethernet.useCoreLocking) {
137 ETHERNET_APPLY_LOCK();
138 }
139 #endif
140
141 size_t written = 0;
142 while (written < len) {
143 size_t segment = fpcb->snd_wnd_max / 2 < fpcb->mss ? fpcb->snd_wnd_max / 2 : fpcb->mss;
144 if (segment < 1) {
145 segment = 1;
146 }
147 const size_t piece = (len - written) < segment ? (len - written) : segment;
148
149 err_t err = tcp_write(fpcb, data + written, piece, TCP_WRITE_FLAG_COPY);
150 if (err == ERR_OK) {
151 written += piece;
152 continue;
153 }
154 if (err != ERR_MEM) {
155 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Client: BLK Write fail 2: "); Serial.println((int)err););
156 #if defined RF24ETHERNET_CORE_REQUIRES_LOCKING
157 if (Ethernet.useCoreLocking) {
158 ETHERNET_REMOVE_LOCK();
159 }
160 #endif
161 return err;
162 }
163
164 // ERR_MEM: lwIP's send queue is full. That is not an error: send what is queued and wait
165 tcp_output(fpcb);
166
167 #if defined RF24ETHERNET_CORE_REQUIRES_LOCKING
168 if (Ethernet.useCoreLocking) {
169 ETHERNET_REMOVE_LOCK();
170 }
171 #endif
172 Ethernet.update();
173 if (!fstate->connected || myPcb != fpcb) {
174 return ERR_CLSD;
175 }
176 if (millis() - timeoutStart > serverConnectionTimeout) {
177 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println("Client: TCP Send queue full"););
178 return ERR_BUF;
179 }
180 #if defined RF24ETHERNET_CORE_REQUIRES_LOCKING
181 if (Ethernet.useCoreLocking) {
182 ETHERNET_APPLY_LOCK();
183 }
184 #endif
185 }
186
187 #if defined RF24ETHERNET_CORE_REQUIRES_LOCKING
188 if (Ethernet.useCoreLocking) {
189 ETHERNET_REMOVE_LOCK();
190 }
191 #endif
192
193 Ethernet.update();
194 return ERR_OK;
195}
196
197/***************************************************************************************************/
198
199void RF24Client::error_callback(void* arg, err_t err)
200{
201
202 ConnectState* state = (ConnectState*)arg;
203 if (state != nullptr) {
204 state->result = err;
205 state->connected = false;
206 dataSize[state->stateActiveID] = 0;
207 if (state->stateActiveID == activeState) {
208 myPcb = nullptr;
209 }
210 }
211 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Client: Err cb: "); Serial.println((int)err););
212}
213
214/***************************************************************************************************/
215
216err_t RF24Client::srecv_callback(void* arg, struct tcp_pcb* tpcb, struct pbuf* p, err_t err)
217{
218
219 ConnectState* state = (ConnectState*)arg;
220
221 if (state != nullptr) {
222 state->serverTimer = millis();
223 }
224
225 if (p == nullptr) {
226 if (state != nullptr) {
227 state->connected = false;
228 }
229 if (tpcb != nullptr) {
230 if (tcp_close(tpcb) != ERR_OK) {
231 if (myPcb == tpcb) {
232 myPcb = nullptr;
233 }
234 tcp_abort(tpcb);
235 tpcb = nullptr;
236 return ERR_ABRT;
237 }
238 if (myPcb == tpcb) {
239 myPcb = nullptr;
240 }
241 tpcb = nullptr;
242 }
243 return ERR_OK;
244 }
245 if (err != ERR_OK || state == nullptr) {
246 if (p)
247 pbuf_free(p);
248 return ERR_OK;
249 }
250
251 bool id = state->stateActiveID;
252 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Server: Copy data to "); Serial.println(state->stateActiveID););
253
254 struct pbuf* q = p;
255 uint16_t acked = 0;
256
257 if (dataSize[id] + p->tot_len > INCOMING_DATA_SIZE) {
258 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println("Client: recv - Out of incoming buffer space"););
259 return ERR_MEM;
260 }
261
262 while (q != nullptr) {
263 memcpy(&incomingData[id][dataSize[id]], q->payload, q->len);
264 dataSize[id] += q->len;
265 acked += q->len;
266 q = q->next;
267 }
268
269 if (tpcb != nullptr && acked > 0) {
270 tcp_recved(tpcb, acked);
271 }
272 if (p) {
273 pbuf_free(p);
274 }
275 return ERR_OK;
276}
277
278/***************************************************************************************************/
279
280err_t RF24Client::recv_callback(void* arg, struct tcp_pcb* tpcb, struct pbuf* p, err_t err)
281{
282
283 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println("Client: Recv cb"););
284
285 ConnectState* state = (ConnectState*)arg;
286 if (p == nullptr) {
287 if (state != nullptr) {
288 state->connected = false;
289 }
290 if (tpcb != nullptr) {
291 if (tcp_close(tpcb) != ERR_OK) {
292 if (myPcb == tpcb) {
293 myPcb = nullptr;
294 }
295 tcp_abort(tpcb);
296 tpcb = nullptr;
297 return ERR_ABRT;
298 }
299 if (myPcb == tpcb) {
300 myPcb = nullptr;
301 }
302 tpcb = nullptr;
303 }
304 return err;
305 }
306 if (err != ERR_OK || state == nullptr) {
307 if (p)
308 pbuf_free(p);
309
310 return err;
311 }
312
313 if (state != nullptr) {
314 state->clientTimer = millis();
315 }
316
317 bool id = state->stateActiveID;
318 struct pbuf* q = p;
319 uint16_t acked = 0;
320
321 if (dataSize[id] + p->tot_len > INCOMING_DATA_SIZE) {
322 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println("Client: recv - Out of incoming buffer space"););
323 return ERR_MEM;
324 }
325
326 while (q != nullptr) {
327 memcpy(&incomingData[id][dataSize[id]], q->payload, q->len);
328 dataSize[id] += q->len;
329 acked += q->len;
330 q = q->next;
331 }
332
333 if (tpcb != nullptr && acked > 0) {
334 tcp_recved(tpcb, acked);
335 }
336 if (p) {
337 pbuf_free(p);
338 }
339 return ERR_OK;
340}
341
342/***************************************************************************************************/
343
344//void RF24Client::setConnectionTimeout(uint32_t timeout)
345//{
346
347// clientConnectionTimeout = timeout;
348//}
349
350/***************************************************************************************************/
351
352err_t RF24Client::clientTimeouts(void* arg, struct tcp_pcb* tpcb)
353{
354
355 ConnectState* state = (ConnectState*)arg;
356
357 if (state != nullptr) {
358 if (millis() - state->clientTimer > state->cConnectionTimeout) {
359 if (tpcb->state == ESTABLISHED || tpcb->state == SYN_SENT || tpcb->state == SYN_RCVD) {
360 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println("Client: Closed Client PCB TIMEOUT"););
361 err_t err = tcp_close(tpcb);
362 state->result = err;
363 state->connected = false;
364 }
365 }
366 }
367 return ERR_OK;
368}
369
370/***************************************************************************************************/
371
372err_t RF24Client::serverTimeouts(void* arg, struct tcp_pcb* tpcb)
373{
374
375 ConnectState* state = (ConnectState*)arg;
376
377 if (state != nullptr && tpcb != nullptr) {
378 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Server: Stimeout cb "); Serial.println(millis() - state->serverTimer););
379
380 state->result = ERR_OK;
381
382 if (millis() - state->serverTimer > state->sConnectionTimeout) {
383 //if (tpcb->state == ESTABLISHED || tpcb->state == SYN_SENT || tpcb->state == SYN_RCVD) {
384 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println("Server: Closed Server PCB TIMEOUT "););
385
386 state->result = tcp_close(tpcb);
387 state->closeTimer = millis();
388 dataSize[activeState] = 0;
389 state->connected = false;
390 if (state->result != ERR_OK) {
391 if (myPcb == tpcb) {
392 tcp_arg(myPcb, nullptr);
393 myPcb = nullptr;
394 }
395 tcp_arg(tpcb, nullptr);
396 tcp_abort(tpcb);
397 tpcb = nullptr;
398 return ERR_ABRT;
399 }
400 myPcb = nullptr;
401 return state->result;
402
403 // }
404 }
405 return state->result;
406 }
407 return ERR_CLSD;
408}
409
410/***************************************************************************************************/
411
412err_t RF24Client::closed_port(void* arg, struct tcp_pcb* tpcb)
413{
414
415 ConnectState* state = (ConnectState*)arg;
416
417 if (state != nullptr) {
418 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Server: Client Poll Cb ID: "); Serial.println(state->identifier));
419 }
420
421 if (myPcb == nullptr) {
422 if (state != nullptr && tpcb != nullptr) {
423
424 if ((tpcb->state == ESTABLISHED || tpcb->state == SYN_SENT || tpcb->state == SYN_RCVD)) {
425 if (state->backlogWasAccepted == false) {
426
427 state->backlogWasAccepted = true;
428 state->connectTimestamp = millis();
429 state->connected = true;
430 accepts--;
431 myPcb = tpcb;
432 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Server: ACCEPT delayed PCB "); Serial.println(state->identifier););
433
434 tcp_backlog_accepted(tpcb);
435 activeState = state->stateActiveID;
436 return ERR_OK;
437 }
438 }
439 }
440 }
441
442 if (tpcb != nullptr) {
443 if (state != nullptr) {
444 if (millis() - state->connectTimestamp > state->sConnectionTimeout * 2) {
445
446 if ((tpcb->state == ESTABLISHED || tpcb->state == SYN_SENT || tpcb->state == SYN_RCVD)) {
447
448 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Server: Close off delayed PCB function 1, ID: "); Serial.println(state->identifier););
449
450 if (state->backlogWasAccepted == false) {
451 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println("Server: With backlog accepted"););
452 tcp_backlog_accepted(tpcb);
453 state->backlogWasAccepted = true;
454 accepts--;
455 }
456
457 state->result = tcp_close(tpcb);
458 state->connected = false;
459 if (state->result == ERR_OK) {
460 state->closeTimer = millis();
461 }
462 else {
463 tcp_abort(tpcb);
464 tpcb = nullptr;
465 return ERR_ABRT;
466 }
467
468 return state->result;
469 }
470 }
471 }
472 }
473
474 return ERR_OK;
475}
476
477/**************************************************************************************************/
478
479err_t RF24Client::accept(void* arg, struct tcp_pcb* tpcb, err_t err)
480{
481 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Server: Accept cb, ID: "); Serial.println(simpleCounter + 1););
482
483 if (tpcb == nullptr) {
484 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Server: Accepted conn, but no tpcb from: "); Serial.println(ip4addr_ntoa(ip_2_ip4(&tpcb->remote_ip))););
485 return ERR_CLSD;
486 }
487
488 if (tpcb != nullptr) {
489 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Server: Client connect from: "); Serial.println(ip4addr_ntoa(ip_2_ip4(&tpcb->remote_ip))););
490 }
491 bool actState = activeState;
492
493 if (myPcb != nullptr) {
494
495 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print("Server: Accept w/already connected: Accepted_Conns - Delayed_Conns == "); Serial.println(accepts););
496 tcp_backlog_delayed(tpcb);
497 accepts++;
498 tcp_poll(tpcb, closed_port, 5);
499 actState = !activeState;
500 gState[actState]->connected = false;
501 gState[actState]->backlogWasAccepted = false;
502 }
503 else {
504 myPcb = tpcb;
505 tcp_poll(tpcb, serverTimeouts, 8);
507 actState = activeState;
508 gState[actState]->connected = true;
509 gState[actState]->backlogWasAccepted = true;
510 }
511
512 dataSize[actState] = 0;
513
514 simpleCounter += 1;
515 gState[actState]->stateActiveID = actState;
516 gState[actState]->identifier = simpleCounter;
517 gState[actState]->sConnectionTimeout = serverConnectionTimeout;
518 gState[actState]->connectTimestamp = millis();
519 gState[actState]->serverTimer = millis();
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 || dataSize[activeState] > 0;
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]->connected = false;
786 gState[activeState]->result = 0;
787 tcp_arg(myPcb, gState[activeState]);
788 tcp_err(myPcb, error_callback);
789 tcp_recv(myPcb, recv_callback);
790 tcp_sent(myPcb, sent_callback);
791 //tcp_poll(myPcb, clientTimeouts, 30);
792
793 err_t err = ERR_OK;
794
795 ip_addr_t myIp;
796 IP_ADDR4(&myIp, ip[0], ip[1], ip[2], ip[3]);
797
798 err = tcp_connect(myPcb, &myIp, port, on_connected);
799
800 if (err != ERR_OK || gState[activeState]->result != ERR_OK) {
801 #if defined RF24ETHERNET_CORE_REQUIRES_LOCKING
802 if (Ethernet.useCoreLocking) {
803 ETHERNET_REMOVE_LOCK();
804 }
805 #endif
806
807 stop();
808 return ERR_CLSD;
809 }
810
811 #if defined RF24ETHERNET_CORE_REQUIRES_LOCKING
812 if (Ethernet.useCoreLocking) {
813 ETHERNET_REMOVE_LOCK();
814 }
815 #endif
816
817 const uint32_t timeoutStart = millis();
818 // Simulate blocking by looping until the callback sets 'connected'
819 while (!gState[activeState]->connected && millis() - timeoutStart < 5000) {
820 Ethernet.update();
821 }
822
823 if (clientConnectionTimeout > 0) {
824 gState[activeState]->clientPollingSetup = 1;
825 }
826
827 return gState[activeState]->connected;
828
829#elif USE_LWIP == 2
830
831 if (port == 0)
832 return -EINVAL;
833
834 int sock = zsock_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
835 if (sock < 0) {
836 return -errno;
837 }
838
839 // --- CRITICAL FIX 1: Set the socket to non-blocking BEFORE connecting ---
840 int flags = zsock_fcntl(sock, F_GETFL, 0);
841 if (flags < 0) {
842 int e = errno;
843 zsock_close(sock);
844 return -e;
845 }
846 zsock_fcntl(sock, F_SETFL, flags | O_NONBLOCK);
847
848 struct sockaddr_in addr = {};
849 addr.sin_family = AF_INET;
850 addr.sin_port = htons(port);
851
852 char ipstr[16];
853 snprintf(ipstr, sizeof(ipstr), "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
854 if (net_addr_pton(AF_INET, ipstr, &addr.sin_addr) < 0) {
855 zsock_close(sock);
856 return -EINVAL;
857 }
858
859 int rc = zsock_connect(sock, (const struct sockaddr*)&addr, sizeof(addr));
860 if (rc == 0) {
861
862 _socket = sock; // <-- save it here
863 _lastError = 0;
864 IF_RF24ETHERNET_DEBUG_CLIENT(printk("CONNECT OK fd=%d\n", _socket));
866 return 1;
867 }
868 if (errno != EINPROGRESS) {
869 int e = errno;
870 zsock_close(sock);
871 return -e;
872 }
873
874 // --- CRITICAL FIX 2: Use Zephyr's native uptime timer instead of Arduino's millis() ---
875 int64_t start_time = k_uptime_get();
876
877 // Loop for up to 5000 milliseconds (5 seconds)
878 while (k_uptime_get() - start_time < 5000) {
879 // 1) Service RF24 every iteration
880 RF24Ethernet.update();
881
882 // 2) Non-blocking check of connect completion
883 struct zsock_pollfd pfd = {
884 .fd = sock,
885 .events = ZSOCK_POLLOUT,
886 .revents = 0,
887 };
888
889 rc = zsock_poll(&pfd, 1, 0); // zero timeout
890 if (rc < 0) {
891 int e = errno;
892 zsock_close(sock);
893 return -e;
894 }
895
896 if (rc > 0 && (pfd.revents & (ZSOCK_POLLOUT | ZSOCK_POLLERR | ZSOCK_POLLHUP))) {
897 int soerr = 0;
898 socklen_t slen = sizeof(soerr);
899 if (zsock_getsockopt(sock, SOL_SOCKET, SO_ERROR, &soerr, &slen) < 0) {
900 int e = errno;
901 zsock_close(sock);
902 return -e;
903 }
904
905 if (soerr == 0) {
906 // Remove O_NONBLOCK flag to cleanly destroy blocking context
907 zsock_fcntl(sock, F_SETFL, flags & ~O_NONBLOCK);
908 _socket = sock; // <-- save it here
909 _lastError = 0;
910 IF_RF24ETHERNET_DEBUG_CLIENT(printk("CONNECT OK fd=%d\n", _socket));
912 return 1;
913 }
914
915 zsock_fcntl(sock, F_SETFL, flags & ~O_NONBLOCK);
916 zsock_close(sock);
917 return -soerr;
918 }
919
920 // --- CRITICAL FIX 3: Use Zephyr's native kernel sleep to yield CPU time ---
921 // This yields execution to Zephyr's network workqueues, timers, and scheduler threads
922 k_msleep(2);
923 }
924
925 // Timed out cleanup
926 zsock_fcntl(sock, F_SETFL, flags & ~O_NONBLOCK);
927 zsock_close(sock);
928 return -ETIMEDOUT;
929
930 return 0;
931
932#endif
933 return 0;
934}
935
936/*************************************************************/
937
938#if USE_LWIP == 1
939void dnsCallback(const char* name, const ip_addr_t* ipaddr, void* callback_arg)
940{
941}
942#endif
943/*************************************************************/
944
945int RF24Client::connect(const char* host, uint16_t port)
946{
947 // Look up the host first
948 int ret = 0;
949
950#if UIP_UDP
951 DNSClient dns;
952 IPAddress remote_addr;
953
954 dns.begin(RF24EthernetClass::_dnsServerAddress);
955 ret = dns.getHostByName(host, remote_addr);
956
957 if (ret == 1)
958 {
959 #if defined(ETH_DEBUG_L1) || defined(RF24ETHERNET_DEBUG_DNS)
960 Serial.println(F("*UIP Got DNS*"));
961 #endif
962 return connect(remote_addr, port);
963 }
964#elif RF24ETHERNET_USE_UDP
965
966 DNSClient dns;
967 IPAddress remote_addr;
968
969 dns.begin(RF24EthernetClass::_dnsServerAddress);
970 ret = dns.getHostByName(host, remote_addr);
971
972 if (ret == 1)
973 {
974 #if defined(ETH_DEBUG_L1) || defined(RF24ETHERNET_DEBUG_DNS)
975 Serial.println(F("*lwIP Got DNS*"));
976 #endif
977 return connect(remote_addr, port);
978 }
979
980#else // ! UIP_UDP
981 // Do something with the input parameters to prevent compile time warnings
982 if (host) {
983 };
984 if (port) {
985 };
986#endif // ! UIP_UDP
987
988#if defined(ETH_DEBUG_L1) || defined(RF24ETHERNET_DEBUG_DNS)
989 Serial.println(F("* DNS fail*"));
990#endif
991
992 return 0;
993}
994
995/*************************************************************/
996
998{
999#if USE_LWIP < 1
1000 if (data && data->state)
1001 {
1002
1003 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print(millis()); Serial.println(F(" before stop(), with data")););
1004
1005 data->packets_in = 0;
1006 data->dataCnt = 0;
1007
1008 if (data->state & UIP_CLIENT_REMOTECLOSED)
1009 {
1010 data->state = 0;
1011 }
1012 else
1013 {
1014 data->state |= UIP_CLIENT_CLOSE;
1015 }
1016
1017 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(F("after stop()")););
1018 }
1019 else
1020 {
1021 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print(millis()); Serial.println(F(" stop(), data: NULL")););
1022 }
1023
1024 data = NULL;
1025 RF24Ethernet.update();
1026#elif USE_LWIP == 1
1027
1028 _stop();
1029
1030#elif USE_LWIP == 2
1031 if (_socket >= 0) {
1032 zsock_close(_socket);
1033 _socket = -1;
1034 }
1036
1037#endif
1038}
1039
1040/***************************************************************************************************/
1041#if USE_LWIP == 1
1042void RF24Client::_stop()
1043{
1044
1045 const uint32_t drainStart = millis();
1046 while (myPcb != nullptr && gState[activeState]->connected && (myPcb->unsent != nullptr || myPcb->unacked != nullptr)) {
1047 if (millis() - drainStart > 5000) {
1048 break;
1049 }
1050 #if defined RF24ETHERNET_CORE_REQUIRES_LOCKING
1051 if (Ethernet.useCoreLocking) {
1052 ETHERNET_APPLY_LOCK();
1053 }
1054 #endif
1055 tcp_output(myPcb);
1056 #if defined RF24ETHERNET_CORE_REQUIRES_LOCKING
1057 if (Ethernet.useCoreLocking) {
1058 ETHERNET_REMOVE_LOCK();
1059 }
1060 #endif
1061 Ethernet.update();
1062 }
1063
1064 tcp_pcb* pcb = myPcb;
1065 myPcb = nullptr;
1066
1067 if (pcb != nullptr) {
1068 #if defined RF24ETHERNET_CORE_REQUIRES_LOCKING
1069 if (Ethernet.useCoreLocking) {
1070 ETHERNET_APPLY_LOCK();
1071 }
1072 #endif
1073 if (pcb->state != CLOSED) {
1074 tcp_arg(pcb, NULL);
1075 tcp_recv(pcb, NULL);
1076 tcp_sent(pcb, NULL);
1077 tcp_err(pcb, NULL);
1078
1079 err_t err = tcp_close(pcb);
1080 if (err != ERR_OK) {
1081 tcp_abort(pcb);
1082 }
1083 }
1084 #if defined RF24ETHERNET_CORE_REQUIRES_LOCKING
1085 if (Ethernet.useCoreLocking) {
1086 ETHERNET_REMOVE_LOCK();
1087 }
1088 #endif
1089 }
1090
1091 dataSize[activeState] = 0;
1092 gState[activeState]->connected = false;
1093}
1094#endif
1095/*************************************************************/
1096
1097// the next function allows us to use the client returned by
1098// EthernetServer::available() as the condition in an if-statement.
1100{
1101#if USE_LWIP < 1
1102 return data && rhs.data && (data == rhs.data);
1103#elif USE_LWIP == 1
1104 return dataSize[activeState] > 0 ? true : false;
1105#elif USE_LWIP == 2
1106 return available();
1107
1108#endif
1109}
1110
1111/*************************************************************/
1112
1113RF24Client::operator bool()
1114{
1115 Ethernet.update();
1116#if USE_LWIP < 1
1117 return data && (!(data->state & UIP_CLIENT_REMOTECLOSED) || data->packets_in != 0);
1118#elif USE_LWIP == 1
1119 return dataSize[activeState] > 0 ? true : false;
1120#elif USE_LWIP == 2
1121
1122 return available();
1123#endif
1124}
1125
1126/*************************************************************/
1127
1128size_t RF24Client::write(uint8_t c)
1129{
1130 return _write(data, &c, 1);
1131}
1132
1133/*************************************************************/
1134
1135size_t RF24Client::write(const uint8_t* buf, size_t size)
1136{
1137 return _write(data, buf, size);
1138}
1139
1140/*************************************************************/
1141#if USE_LWIP < 1
1142size_t RF24Client::_write(uip_userdata_t* u, const uint8_t* buf, size_t size)
1143#else
1144size_t RF24Client::_write(uint8_t* data, const uint8_t* buf, size_t size)
1145
1146#endif
1147
1148{
1149
1150#if USE_LWIP < 1
1151 size_t total_written = 0;
1152 size_t payloadSize = rf24_min(size, UIP_TCP_MSS);
1153 uint32_t start = millis();
1154
1155test2:
1156
1157 Ethernet.update();
1158
1159 if (millis() - start > 5000)
1160 {
1161 if (u) {
1162 u->hold = false;
1163 }
1164 return total_written;
1165 }
1166
1167 if (u && !(u->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED)) && (u->state & UIP_CLIENT_CONNECTED))
1168 {
1169 if (u->out_pos + payloadSize > UIP_TCP_MSS || u->hold)
1170 {
1171 goto test2;
1172 }
1173
1175 Serial.println();
1176 Serial.print(millis());
1177 Serial.print(F(" UIPClient.write: writePacket("));
1178 Serial.print(u->packets_out);
1179 Serial.print(F(") pos: "));
1180 Serial.print(u->out_pos);
1181 Serial.print(F(", buf["));
1182 Serial.print(size - total_written);
1183 Serial.print(F("]: '"));
1184 Serial.write((uint8_t*)buf + total_written, payloadSize);
1185 Serial.println(F("'")););
1186
1187 memcpy(u->myData + u->out_pos, buf + total_written, payloadSize);
1188 u->packets_out = 1;
1189 u->out_pos += payloadSize;
1190 total_written += payloadSize;
1191
1192 if (total_written < size)
1193 {
1194 size_t remain = size - total_written;
1195 payloadSize = rf24_min(remain, UIP_TCP_MSS);
1196 goto test2;
1197 }
1198
1199 u->hold = false;
1200 return total_written;
1201 }
1202
1203 if (u) {
1204 u->hold = false;
1205 }
1206 return 0;
1207#elif USE_LWIP == 1
1208
1209 bool initialActiveState = activeState;
1210 size_t chunk = (MAX_PAYLOAD_SIZE - 14) < TCP_SND_BUF ? (MAX_PAYLOAD_SIZE - 14) : TCP_SND_BUF; // Max chunk size is equal to RF24Network MAX_PAYLOAD_SIZE capped by TCP_SND_BUF size
1211 size_t position = 0;
1212
1213 uint32_t timeout = millis();
1214 while (size > chunk) {
1215 if (millis() - timeout > 3000) {
1216 break;
1217 }
1218 if (myPcb == nullptr)
1219 return 0;
1220
1221 err_t write_err = blocking_write(myPcb, gState[initialActiveState], reinterpret_cast<const char*>(&buf[position]), chunk);
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 position += chunk;
1230 size -= chunk;
1231 timeout = millis();
1232 Ethernet.update();
1233 }
1234
1235 if (myPcb == nullptr)
1236 return 0;
1237
1238 err_t write_err = blocking_write(myPcb, gState[initialActiveState], reinterpret_cast<const char*>(&buf[position]), size);
1239
1240 if (write_err != ERR_OK) {
1241 gState[initialActiveState]->result = write_err;
1242 gState[initialActiveState]->connected = false;
1243 _stop();
1244 return 0;
1245 }
1246
1247 return position + size;
1248#elif USE_LWIP == 2
1249
1250 RF24Client* self = RF24Client::g_rf24client_instance;
1251 if (!self || !buf || size == 0)
1252 return 0;
1253
1254 if (self->_socket < 0) {
1255 self->_lastError = ENOTCONN;
1256 return 0;
1257 }
1258
1259 size_t total = 0;
1260 while (total < size) {
1261
1262 ssize_t n = zsock_send(self->_socket, buf + total, size - total, 0);
1263
1264 if (n > 0) {
1265 total += (size_t)n;
1266 continue;
1267 }
1268 if (n == 0)
1269 break;
1270
1271 int err = errno;
1272 self->_lastError = err;
1273 if (err == EINTR)
1274 continue;
1275 if (err == EAGAIN || err == EWOULDBLOCK)
1276 break;
1277 break;
1278 }
1279 Ethernet.update();
1280 return total;
1281
1282#endif
1283}
1284
1285/*************************************************************/
1286
1287void uip_log(char* msg)
1288{
1289 // Serial.println();
1290 // Serial.println("** UIP LOG **");
1291 // Serial.println(msg);
1292 if (msg)
1293 {
1294 };
1295}
1296
1297/*************************************************************/
1298#if USE_LWIP < 1
1299void serialip_appcall(void)
1300{
1301 uip_userdata_t* u = (uip_userdata_t*)uip_conn->appstate;
1302
1303 /*******Connected**********/
1304 if (!u && uip_connected())
1305 {
1306 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(); Serial.print(millis()); Serial.println(F(" UIPClient uip_connected")););
1307
1308 u = (uip_userdata_t*)EthernetClient::_allocateData();
1309
1310 if (u)
1311 {
1312 uip_conn->appstate = u;
1313 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print(F("UIPClient allocated state: ")); Serial.println(u->state, BIN););
1314 }
1315 else
1316 {
1317 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(F("UIPClient allocation failed")););
1318 }
1319 }
1320
1321 #if UIP_CONNECTION_TIMEOUT > 0
1322 if (u && u->connectTimeout > 0) {
1323 if (millis() - u->connectTimer > u->connectTimeout) {
1324 u->state |= UIP_CLIENT_CLOSE;
1325 u->connectTimer = millis();
1326 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(); Serial.print(millis()); Serial.println("UIP Client close(timeout)"););
1327 }
1328 }
1329 #endif
1330
1331 /*******User Data RX**********/
1332 if (u)
1333 {
1334 if (uip_newdata())
1335 {
1336 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(); Serial.print(millis()); Serial.print(F(" UIPClient uip_newdata, uip_len:")); Serial.println(uip_len););
1337 #if UIP_CONNECTION_TIMEOUT > 0
1338 u->connectTimer = millis();
1339 #endif
1340 u->hold = (u->out_pos = (u->windowOpened = (u->packets_out = false)));
1341
1342 if (uip_len && !(u->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED)))
1343 {
1344 uip_stop();
1345 u->state &= ~UIP_CLIENT_RESTART;
1346 u->windowOpened = false;
1347 u->restartTime = millis();
1348
1349 uint16_t writePos = u->in_pos + u->dataCnt;
1350 uint16_t incomingLen = uip_datalen();
1351
1352 if (writePos <= OUTPUT_BUFFER_SIZE && incomingLen <= (OUTPUT_BUFFER_SIZE - writePos))
1353 {
1354 memcpy(&u->myData[writePos], uip_appdata, incomingLen);
1355 u->dataCnt += incomingLen;
1356 u->packets_in = 1;
1357 }
1358 else
1359 {
1361 Serial.println(F("UIPClient RX overflow, closing connection")););
1362 u->state |= UIP_CLIENT_CLOSE;
1363 }
1364 }
1365 goto finish;
1366 }
1367
1368 /*******Closed/Timed-out/Aborted**********/
1369 // If the connection has been closed, save received but unread data.
1370 if (uip_closed() || uip_timedout() || uip_aborted())
1371 {
1372 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(); Serial.print(millis()); Serial.println(F(" UIPClient uip_closed")););
1373 // drop outgoing packets not sent yet:
1374 u->packets_out = 0;
1375
1376 if (u->packets_in)
1377 {
1378 ((uip_userdata_closed_t*)u)->lport = uip_conn->lport;
1379 u->state |= UIP_CLIENT_REMOTECLOSED;
1380 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(F("UIPClient close 1")););
1381 }
1382 else
1383 {
1384 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(F("UIPClient close 2")););
1385 u->state = 0;
1386 }
1387
1388 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(F("after UIPClient uip_closed")););
1389 uip_conn->appstate = NULL;
1390 goto finish;
1391 }
1392
1393 /*******ACKED**********/
1394 if (uip_acked())
1395 {
1396 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(); Serial.print(millis()); Serial.println(F(" UIPClient uip_acked")););
1397 u->state &= ~UIP_CLIENT_RESTART;
1398 u->hold = (u->out_pos = (u->windowOpened = (u->packets_out = false)));
1399 u->restartTime = millis();
1400 #if UIP_CONNECTION_TIMEOUT > 0
1401 u->connectTimer = millis();
1402 #endif
1403 }
1404
1405 /*******Polling**********/
1406 if (uip_poll() || uip_rexmit())
1407 {
1408 if (uip_rexmit()) {
1409 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.print(F("ReXmit, Len: ")););
1410 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(u->out_pos));
1411 uip_len = u->out_pos;
1412 uip_send(u->myData, u->out_pos);
1413 u->hold = true;
1414 goto finish;
1415 }
1416 // IF_RF24ETHERNET_DEBUG_CLIENT( Serial.println(); Serial.println(F("UIPClient uip_poll")); );
1417
1418 if (u->packets_out != 0 && !u->hold)
1419 {
1420 uip_len = u->out_pos;
1421 uip_send(u->myData, u->out_pos);
1422 u->hold = true;
1423 goto finish;
1424 }
1425
1426 // Restart mechanism to keep connections going
1427 // Only call this if the TCP window has already been re-opened, the connection is being polled, but no data
1428 // has been acked
1429 if (!(u->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED)))
1430 {
1431
1432 if (u->windowOpened == true && u->state & UIP_CLIENT_RESTART && millis() - u->restartTime > u->restartInterval)
1433 {
1434 u->restartTime = millis();
1435 #if defined RF24ETHERNET_DEBUG_CLIENT || defined ETH_DEBUG_L1
1436 Serial.println();
1437 Serial.print(millis());
1438 #if UIP_CONNECTION_TIMEOUT > 0
1439 Serial.print(F(" UIPClient Re-Open TCP Window, time remaining before abort: "));
1440 Serial.println(UIP_CONNECTION_TIMEOUT - (millis() - u->connectTimer));
1441 #endif
1442 #endif
1443 u->restartInterval += 500;
1444 u->restartInterval = rf24_min(u->restartInterval, 7000);
1445 uip_restart();
1446 }
1447 }
1448 }
1449
1450 /*******Close**********/
1451 if (u->state & UIP_CLIENT_CLOSE)
1452 {
1453 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(); Serial.print(millis()); Serial.println(F(" UIPClient state UIP_CLIENT_CLOSE")););
1454
1455 if (u->packets_out == 0)
1456 {
1457 u->state = 0;
1458 uip_conn->appstate = NULL;
1459 uip_close();
1460 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(F("no blocks out -> free userdata")););
1461 }
1462 else
1463 {
1464 uip_stop();
1465 IF_RF24ETHERNET_DEBUG_CLIENT(Serial.println(F("blocks outstanding transfer -> uip_stop()")););
1466 }
1467 }
1468finish:;
1469
1470 if (u->state & UIP_CLIENT_RESTART && !u->windowOpened)
1471 {
1472 if (!(u->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED)))
1473 {
1474 uip_restart();
1475 #if defined ETH_DEBUG_L1
1476 Serial.println();
1477 Serial.print(millis());
1478 Serial.println(F(" UIPClient Re-Open TCP Window"));
1479 #endif
1480 u->windowOpened = true;
1481 u->restartInterval = UIP_WINDOW_REOPEN_DELAY; //.75 seconds
1482 u->restartTime = millis();
1483 }
1484 }
1485 }
1486}
1487#endif
1488/*******************************************************/
1489#if USE_LWIP < 1
1490uip_userdata_t* RF24Client::_allocateData()
1491{
1492 for (uint8_t sock = 0; sock < UIP_CONNS; sock++)
1493 {
1494 uip_userdata_t* data = &RF24Client::all_data[sock];
1495 if (!data->state)
1496 {
1497 data->state = sock | UIP_CLIENT_CONNECTED;
1498 data->packets_in = 0;
1499 data->packets_out = 0;
1500 data->dataCnt = 0;
1501 data->in_pos = 0;
1502 data->out_pos = 0;
1503 data->hold = 0;
1504 data->restartTime = millis();
1505 data->restartInterval = 5000;
1506 #if (UIP_CONNECTION_TIMEOUT > 0)
1507 data->connectTimer = millis();
1508 data->connectTimeout = UIP_CONNECTION_TIMEOUT;
1509 #endif
1510 return data;
1511 }
1512 }
1513 return NULL;
1514}
1515#endif
1516
1517int RF24Client::waitAvailable(uint32_t timeout)
1518{
1519 uint32_t start = millis();
1520 while (available() < 1)
1521 {
1522 if (millis() - start > timeout)
1523 {
1524 return 0;
1525 }
1526 RF24Ethernet.update();
1527 }
1528 return available();
1529}
1530
1531/*************************************************************/
1532
1534{
1535 RF24Ethernet.update();
1536#if USE_LWIP < 1
1537 if (*this)
1538 {
1539 return _available(data);
1540 }
1541#else
1542 return _available(data);
1543#endif
1544 return 0;
1545}
1546
1547/*************************************************************/
1548#if USE_LWIP < 1
1549int RF24Client::_available(uip_userdata_t* u)
1550#else
1551int RF24Client::_available(uint8_t* data)
1552#endif
1553{
1554#if USE_LWIP < 1
1555 if (u->packets_in)
1556 {
1557 return u->dataCnt;
1558 }
1559#elif USE_LWIP == 1
1560 return dataSize[activeState];
1561#elif USE_LWIP == 2
1562
1563 RF24Client* self = RF24Client::g_rf24client_instance;
1564 if (!self || self->_socket < 0)
1565 return 0;
1566
1567 // First: is there readable/hup state?
1568 struct zsock_pollfd pfd
1569 {
1570 };
1571 pfd.fd = self->_socket;
1572 pfd.events = ZSOCK_POLLIN;
1573 int pr = zsock_poll(&pfd, 1, 0);
1574 if (pr <= 0)
1575 return 0;
1576
1577 // If peer closed, report 0 available
1578 //if (pfd.revents & (ZSOCK_POLLHUP | ZSOCK_POLLNVAL)) return 0;
1579 //if (!(pfd.revents & ZSOCK_POLLIN)) return 0;
1580
1581 // Peek queued bytes without consuming
1582 int n = zsock_recv(self->_socket, peekBuffer, sizeof(peekBuffer),
1583 ZSOCK_MSG_PEEK | ZSOCK_MSG_DONTWAIT);
1584
1585 if (n > 0)
1586 return n; // bytes currently queued (up to 1024)
1587 if (n == 0)
1588 return 0; // closed cleanly
1589 if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
1590 return 0;
1591 return 0;
1592#endif
1593 return 0;
1594}
1595
1596/*************************************************************/
1597
1598int RF24Client::read(uint8_t* buf, size_t size)
1599{
1600#if USE_LWIP < 1
1601 if (*this)
1602 {
1603 if (!data->packets_in) {
1604 Ethernet.update();
1605 if (!*this || !data->packets_in) {
1606 return -1;
1607 }
1608 }
1609
1610 if (data->in_pos > OUTPUT_BUFFER_SIZE || data->dataCnt > OUTPUT_BUFFER_SIZE || (data->in_pos + data->dataCnt) > OUTPUT_BUFFER_SIZE)
1611 {
1612 data->state |= UIP_CLIENT_CLOSE;
1613 data->in_pos = 0;
1614 data->dataCnt = 0;
1615 return -1;
1616 }
1617 size = rf24_min(data->dataCnt, size);
1618 memcpy(buf, &data->myData[data->in_pos], size);
1619 data->dataCnt -= size;
1620
1621 data->in_pos += size;
1622
1623 if (!data->dataCnt)
1624 {
1625 data->packets_in = 0;
1626 data->in_pos = 0;
1627
1628 if (uip_stopped(&uip_conns[data->state & UIP_CLIENT_SOCKETS]) && !(data->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED)))
1629 {
1630 data->state |= UIP_CLIENT_RESTART;
1631 data->restartTime = 0;
1632
1633 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("**")););
1634 }
1635 else
1636 {
1637 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("**")););
1638 }
1639
1640 if (data->packets_in == 0)
1641 {
1642 if (data->state & UIP_CLIENT_REMOTECLOSED)
1643 {
1644 data->state = 0;
1645 data = NULL;
1646 }
1647 }
1648 }
1649 return size;
1650 }
1651
1652 return -1;
1653#elif USE_LWIP == 1
1654
1655 if (available()) {
1656
1657 const uint16_t avail = dataSize[activeState];
1658
1659 if (size >= dataSize[activeState]) {
1660 memcpy(&buf[0], &incomingData[activeState][0], avail);
1661 dataSize[activeState] = 0;
1662 return avail;
1663 }
1664 else {
1665 memcpy(&buf[0], &incomingData[activeState][0], size);
1666 memmove(&incomingData[activeState][0], &incomingData[activeState][size], avail - size);
1667 dataSize[activeState] = avail - size;
1668 return size;
1669 }
1670 }
1671 return -1;
1672#elif USE_LWIP == 2
1673
1674 if (!buf || size == 0)
1675 return 0;
1676 if (_socket < 0) {
1677 _lastError = ENOTCONN;
1678 return -1;
1679 }
1680
1681 int n = zsock_recv(_socket, buf, size, ZSOCK_MSG_DONTWAIT);
1682
1683 if (n < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
1684 Ethernet.update();
1685 n = zsock_recv(_socket, buf, size, ZSOCK_MSG_DONTWAIT);
1686 }
1687
1688 if (n > 0) {
1689 return n; // got bytes
1690 }
1691
1692 if (n == 0) {
1693 // Peer performed orderly shutdown.
1694 // Do NOT close fd here; let caller decide via connected()/stop().
1696 _lastError = 0;
1697 return 0;
1698 }
1699
1700 // n < 0
1701 int err = errno;
1702 _lastError = err;
1703
1704 if (err == EAGAIN || err == EWOULDBLOCK || err == EINTR) {
1705 // no data yet, try again later
1706 return 0;
1707 }
1708
1709 // real error; optionally keep socket open unless clearly unusable
1710 if (err == EBADF || err == ENOTSOCK) {
1711 _socket = -1; // already invalid
1712 }
1713
1714 return -1;
1715#endif
1716}
1717
1718/*************************************************************/
1719
1721{
1722 uint8_t c;
1723 if (read(&c, 1) <= 0)
1724 return -1;
1725 return c;
1726}
1727
1728/*************************************************************/
1729
1731{
1732 if (available())
1733 {
1734#if USE_LWIP < 1
1735 return data->myData[data->in_pos];
1736#elif USE_LWIP == 1
1737 return incomingData[activeState][0];
1738#elif USE_LWIP == 2
1739 return (uint8_t)peekBuffer[0];
1740#endif
1741 }
1742 return -1;
1743}
1744
1745/*************************************************************/
1746
1748{
1749#if USE_LWIP < 1
1750 if (*this)
1751 {
1752 #if USE_LWIP < 1
1753 data->packets_in = 0;
1754 data->dataCnt = 0;
1755 #else
1756 data = 0;
1757 #endif
1758 }
1759#elif USE_LWIP == 1
1760 dataSize[activeState] = 0;
1761#elif USE_LWIP == 2
1762 while (available()) {
1763 read();
1764 }
1765#endif
1766}
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
volatile bool connected
Definition RF24Client.h:14
#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:224
static bool activeState
Definition RF24Client.h:239
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)