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