RF24Ethernet - TCP/IP over RF24Network v2.0.2
TMRh20 - Pushing the practical limits of RF24 modules
Loading...
Searching...
No Matches
RF24Udp.cpp
Go to the documentation of this file.
1/*
2 RF24UDP.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
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20#include "RF24Ethernet.h"
21
22#if UIP_CONF_UDP > 0 || RF24ETHERNET_USE_UDP > 0
23
24 #if RF24ETHERNET_USE_UDP
25
26struct udp_pcb* RF24UDP::udpPcb;
27int8_t RF24UDP::udpDataIn[MAX_PAYLOAD_SIZE - 14];
28int8_t RF24UDP::udpDataOut[MAX_PAYLOAD_SIZE - 14];
29int32_t RF24UDP::dataInPos;
30int32_t RF24UDP::dataOutPos;
31
32 #if !defined ETHERNET_USING_LWIP_ARDUINO
33 #include "lwip/udp.h"
34 #include "lwip/tcpip.h"
35 #else
36 #include "lwip/include/lwip/udp.h"
37 #include "lwip/include/lwip/tcpip.h"
38 #endif
39 #endif
40
41 #ifdef RF24ETHERNET_DEBUG_UDP
42 #include "HardwareSerial.h"
43 #endif
44
45 #if UIP_UDP || RF24ETHERNET_USE_UDP
46 #define UIP_ARPHDRSIZE 42
47 #define UDPBUF ((struct uip_udpip_hdr*)&uip_buf[UIP_LLH_LEN])
48
49 /*******************************************************/
50
51 #ifndef RF24ETHERNET_USE_UDP
52// Constructor
53RF24UDP::RF24UDP() : _uip_udp_conn(NULL)
54{
55 memset(&appdata, 0, sizeof(appdata));
56}
57 #else
61 #endif
62/*******************************************************/
63
64// initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use
65uint8_t RF24UDP::begin(uint16_t port)
66{
67 #ifndef RF24ETHERNET_USE_UDP
68 if (!_uip_udp_conn)
69 {
70 _uip_udp_conn = uip_udp_new(NULL, 0);
71 }
72 if (_uip_udp_conn)
73 {
74 uip_udp_bind(_uip_udp_conn, htons(port));
75 _uip_udp_conn->appstate = &appdata;
76 return 1;
77 }
78 return 0;
79 #else
80
81 if (udpPcb == nullptr) {
82 udpPcb = udp_new();
83 }
84 err_t err = udp_bind(udpPcb, IP_ANY_TYPE, port);
85
86 if (err == ERR_OK) {
87 return 1;
88 }
89 return 0;
90 #endif
91}
92
93/*******************************************************/
94
95// Finish with the UDP socket
97{
98 #ifndef RF24ETHERNET_USE_UDP
99 if (_uip_udp_conn)
100 {
101 uip_udp_remove(_uip_udp_conn);
102 _uip_udp_conn->appstate = NULL;
103 _uip_udp_conn = NULL;
104 appdata.packet_in = 0;
105 appdata.packet_next = 0;
106 appdata.packet_out = 0;
107
108 memset(&appdata, 0, sizeof(appdata));
109 }
110 #else
111
112 if (udpPcb != nullptr) {
113 udp_disconnect(udpPcb);
114 }
115 #endif
116}
117
118/*******************************************************/
119
120// Sending UDP packets
121
122// Start building up a packet to send to the remote host specific in ip and port
123// Returns 1 if successful, 0 if there was a problem with the supplied IP address or port
124int RF24UDP::beginPacket(IPAddress ip, uint16_t port)
125{
126 #ifndef RF24ETHERNET_USE_UDP
127 RF24EthernetClass::tick();
128 if (ip && port)
129 {
130 uip_ipaddr_t ripaddr;
131 uip_ip_addr(&ripaddr, ip);
132 IF_RF24ETHERNET_DEBUG_UDP(Serial.print(F("RF24UDP udp beginPacket, ")););
133
134 if (_uip_udp_conn)
135 {
136 _uip_udp_conn->rport = htons(port);
137 uip_ipaddr_copy(_uip_udp_conn->ripaddr, &ripaddr);
138 }
139 else
140 {
141 _uip_udp_conn = uip_udp_new(&ripaddr, htons(port));
142 if (_uip_udp_conn)
143 {
144 IF_RF24ETHERNET_DEBUG_UDP(Serial.print(F("RF24UDP New connection, ")););
145 _uip_udp_conn->appstate = &appdata;
146 }
147 else
148 {
149 IF_RF24ETHERNET_DEBUG_UDP(Serial.println(F("RF24UDP Failed to allocate new connection")););
150 return 0;
151 }
152 }
153 IF_RF24ETHERNET_DEBUG_UDP(Serial.print(F("rip: ")); Serial.print(ip); Serial.print(F(", port: ")); Serial.println(port););
154 }
155
156 if (_uip_udp_conn)
157 {
158 if (appdata.packet_out == 0)
159 {
160 appdata.packet_out = 1;
161 appdata.out_pos = 0; // UIP_UDP_PHYH_LEN;
162 if (appdata.packet_out != 0)
163 {
164 return 1;
165 }
166 else
167 {
168 IF_RF24ETHERNET_DEBUG_UDP(Serial.println(F("RF24UDP Failed to allocate memory for packet")););
169 }
170 }
171 else
172 {
173 IF_RF24ETHERNET_DEBUG_UDP(Serial.println(F("RF24UDP Previous packet on that connection not sent yet")););
174 }
175 }
176 return 0;
177 #else
178
179 err_t err = ERR_OK;
180 ip4_addr_t myIp;
181 #if defined ARDUINO_ARCH_ESP32 || defined ARDUINO_ARCH_ESP8266 || defined ARDUINO_ARCH_RP2040 || defined ARDUINO_ARCH_RP2350
182 IP4_ADDR(&myIp, ip[0], ip[1], ip[2], ip[3]);
183 ip_addr_t generic_addr;
184 ip_addr_copy_from_ip4(generic_addr, myIp);
185 err = udp_connect(udpPcb, &generic_addr, port);
186 #else
187 IP4_ADDR(&myIp, ip[0], ip[1], ip[2], ip[3]);
188 // Start non-blocking connection
189 err = udp_connect(udpPcb, &myIp, port);
190 #endif
191
192 if (err == ERR_OK) {
193 return 1;
194 }
195 return 0;
196 #endif
197}
198
199/*******************************************************/
200
201// Start building up a packet to send to the remote host specific in host and port
202// Returns 1 if successful, 0 if there was a problem resolving the hostname or port
203int RF24UDP::beginPacket(const char* host, uint16_t port)
204{
205 #ifndef RF24ETHERNET_USE_UDP
206 // Look up the host first
207 int ret = 0;
208 DNSClient dns;
209 IPAddress remote_addr;
210
211 dns.begin(RF24Ethernet.dnsServerIP());
212 ret = dns.getHostByName(host, remote_addr);
213 if (ret == 1)
214 {
215 return beginPacket(remote_addr, port);
216 }
217 else
218 {
219 return ret;
220 }
221 #else
222 // Look up the host first
223 int ret = 0;
224 DNSClient dns;
225 IPAddress remote_addr;
226
227 dns.begin(RF24Ethernet.dnsServerIP());
228 ret = dns.getHostByName(host, remote_addr);
229 if (ret == 1)
230 {
231 return beginPacket(remote_addr, port);
232 }
233 else
234 {
235 return ret;
236 }
237
238 #endif
239}
240
241/*******************************************************/
242
243// Finish off this packet and send it
244// Returns 1 if the packet was sent successfully, 0 if there was an error
246{
247 #ifndef RF24ETHERNET_USE_UDP
248 if (_uip_udp_conn && appdata.packet_out != 0)
249 {
250 appdata.send = true;
251 IF_RF24ETHERNET_DEBUG_UDP(Serial.println(F("RF24UDP endpacket")););
252 uip_udp_periodic_conn(_uip_udp_conn);
253 if (uip_len > 0)
254 {
255 _send(&appdata);
256 return 1;
257 }
258 }
259 return 0;
260 #else
261
262 if (dataOutPos > 0) {
263 _send();
264 return 1;
265 }
266 return 0;
267 #endif
268}
269
270/*******************************************************/
271
272// Write a single byte into the packet
273size_t RF24UDP::write(uint8_t c)
274{
275 return write(&c, 1);
276}
277
278/*******************************************************/
279
280// Write size bytes from buffer into the packet
281size_t RF24UDP::write(const uint8_t* buffer, size_t size)
282{
283 #ifndef RF24ETHERNET_USE_UDP
284 if (appdata.packet_out != 0)
285 {
286 IF_RF24ETHERNET_DEBUG_UDP(Serial.println("RF24UDP Write: "); Serial.println(size); for (int i = 0; i < size; i++) { Serial.print((char)buffer[i]); Serial.print(" "); } Serial.println(""););
287 size_t ret = size;
288 memcpy(RF24Client::all_data[0].myData + appdata.out_pos, buffer, size);
289 appdata.out_pos += ret;
290 return ret;
291 }
292 return 0;
293 #else
294
295 memcpy(&udpDataOut[dataOutPos], buffer, size);
296 dataOutPos += size;
297
298 return size;
299 #endif
300}
301
302/*******************************************************/
303
304// Start processing the next available incoming packet
305// Returns the size of the packet in bytes, or 0 if no packets are available
307{
308 RF24EthernetClass::tick();
309
310 #ifndef RF24ETHERNET_USE_UDP
311
312 int size = appdata.packet_in_size;
313
314 IF_RF24ETHERNET_DEBUG_UDP(if (appdata.packet_in != 0) { Serial.print(F("RF24UDP udp parsePacket freeing previous packet: ")); Serial.println(appdata.packet_in); });
315
316 // appdata.packet_in_size = 0;
317
318 // appdata.packet_in = appdata.packet_next;
319 // appdata.packet_next = 0;
320
321 IF_RF24ETHERNET_DEBUG_UDP(if (appdata.packet_in != 0) { Serial.print(F("RF24UDP udp parsePacket received packet: ")); Serial.print(appdata.packet_in); } Serial.print(F(", size: ")); Serial.println(size););
322
323 return size;
324 #else
325
326 return dataInPos;
327 #endif
328}
329
330/*******************************************************/
331
332// Number of bytes remaining in the current packet
334{
335 RF24EthernetClass::tick();
336 #ifndef RF24ETHERNET_USE_UDP
337 return appdata.packet_in_size;
338 #else
339 return dataInPos;
340 #endif
341}
342
343/*******************************************************/
344
345// Read a single byte from the current packet
347{
348 unsigned char c;
349 if (read(&c, 1) > 0)
350 {
351 return c;
352 }
353 return -1;
354}
355
356/*******************************************************/
357
358// Read up to len bytes from the current packet and place them into buffer
359// Returns the number of bytes read, or 0 if none are available
360int RF24UDP::read(unsigned char* buffer, size_t len)
361{
362
363 //RF24EthernetClass::tick();
364 #ifndef RF24ETHERNET_USE_UDP
365 if (appdata.packet_in != 0)
366 {
367 memcpy(buffer, RF24Client::all_data[0].myData + appdata.in_pos, len);
368 appdata.in_pos += len;
369 appdata.packet_in_size -= len;
370
371 if (appdata.packet_in_size < 1)
372 {
373 appdata.packet_in = 0;
374 }
375 return len;
376 }
377 #else
378
379 if (dataInPos >= len) {
380
381 size_t remainder = dataInPos - len;
382 memcpy(&buffer[0], &udpDataIn[0], len);
383 if (remainder > 0) {
384 memmove(udpDataIn, &udpDataIn[len], remainder);
385 }
386 dataInPos = rf24_max(0, remainder);
387 return len;
388 }
389
390 #endif
391 return 0;
392}
393
394/*******************************************************/
395
396// Return the next byte from the current packet without moving on to the next byte
398{
399 #ifndef RF24ETHERNET_USE_UDP
400 RF24EthernetClass::tick();
401
402 if (appdata.packet_in != 0)
403 {
404 return RF24Client::all_data[0].myData[appdata.in_pos];
405 }
406 return -1;
407 #else
408
409 if (dataInPos > 0) {
410 return udpDataIn[0];
411 }
412 return -1;
413 #endif
414}
415
416/*******************************************************/
417
418// Finish reading the current packet
420{
421 #ifndef RF24ETHERNET_USE_UDP
422 appdata.packet_in = 0;
423 appdata.packet_in_size = 0;
424 #else
425 uint8_t c = 0;
426 while (read() > 0) {
427 };
428 #endif
429 //RF24EthernetClass::tick();
430}
431
432/*******************************************************/
433
434// Return the IP address of the host who sent the current incoming packet
436{
437 #ifndef RF24ETHERNET_USE_UDP
438 return _uip_udp_conn ? ip_addr_uip(_uip_udp_conn->ripaddr) : IPAddress();
439 #else
440
441 if (udpPcb != nullptr) {
442 const ip4_addr_t* addr = ip_2_ip4(&udpPcb->remote_ip);
443 return IPAddress(
444 ip4_addr_get_byte(addr, 0),
445 ip4_addr_get_byte(addr, 1),
446 ip4_addr_get_byte(addr, 2),
447 ip4_addr_get_byte(addr, 3));
448 }
449 return IPAddress {0, 0, 0, 0};
450 #endif
451}
452
453/*******************************************************/
454
455// Return the port of the host who sent the current incoming packet
457{
458 #ifndef RF24ETHERNET_USE_UDP
459 return _uip_udp_conn ? ntohs(_uip_udp_conn->rport) : 0;
460 #else
461
462 if (udpPcb != nullptr) {
463 return udpPcb->remote_port;
464 }
465 return 0;
466 #endif
467}
468
469/*******************************************************/
470
471// uIP callback function
472
474{
475 #ifndef RF24ETHERNET_USE_UDP
476 if (uip_udp_userdata_t* data = (uip_udp_userdata_t*)(uip_udp_conn->appstate))
477 {
478 if (uip_newdata())
479 {
480 if (data->packet_next == 0)
481 {
482 uip_udp_conn->rport = UDPBUF->srcport;
483 uip_ipaddr_copy(uip_udp_conn->ripaddr, UDPBUF->srcipaddr);
484
485 // discard Linklevel and IP and udp-header and any trailing bytes:
486 memcpy(RF24Client::all_data[0].myData, uip_appdata, uip_len);
487 data->packet_in_size += uip_len;
488 data->packet_in = 1;
489
490 IF_RF24ETHERNET_DEBUG_UDP(Serial.print(F("RF24UDP udp, uip_newdata received packet: ")); Serial.print(data->packet_next); Serial.print(F(", size: ")); Serial.println(data->packet_in_size); for (int i = 0; i < data->packet_in_size; i++) { Serial.print(RF24Client::all_data[0].myData[i],HEX); Serial.print(F(" : ")); } Serial.println(););
491 }
492 }
493 if (uip_poll() && data->send)
494 {
495 // set uip_slen (uip private) by calling uip_udp_send
496 IF_RF24ETHERNET_DEBUG_UDP(Serial.print(F("udp, uip_poll preparing packet to send: ")); Serial.print(data->packet_out); Serial.print(F(", size: ")); Serial.println(data->out_pos););
497
498 memcpy(uip_appdata, RF24Client::all_data[0].myData, data->out_pos);
499 uip_udp_send(data->out_pos);
500 }
501 }
502
503 #else
504
505 #endif
506}
507
508 #if RF24ETHERNET_USE_UDP
509void RF24UDP::receiveUdp(void* arg, struct udp_pcb* pcb, struct pbuf* p, const ip_addr_t* addr, u16_t port)
510{
511
512 if (p != NULL) {
513 memcpy(&udpDataIn[0], p->payload, p->len);
514 dataInPos += p->len;
515 pbuf_free(p);
516 if (udpState != nullptr) {
517 udpState->dataReceived = true;
518 }
519 }
520}
521
522 #endif
523
524void RF24UDP::sendUdp(void* arg)
525{
526
527 struct udp_send_ctx* data = (struct udp_send_ctx*)arg;
528
529 udp_send(data->pcb, data->p);
530}
531
532 /*******************************************************/
533 #ifndef RF24ETHERNET_USE_UDP
534void RF24UDP::_send(uip_udp_userdata_t* data)
535 #else
536void RF24UDP::_send()
537 #endif
538
539{
540 #ifndef RF24ETHERNET_USE_UDP
541 #if defined(RF24_TAP)
542 uip_arp_out(); // add arp
543 #endif
544 if (uip_len == UIP_ARPHDRSIZE)
545 {
546 // RF24EthernetClass::uip_packet = 0;
547 // RF24EthernetClass::packetstate &= ~UIPETHERNET_SENDPACKET;
548
549 IF_RF24ETHERNET_DEBUG_UDP(Serial.println(F("udp, uip_poll results in ARP-packet")););
550 RF24EthernetClass::network_send();
551 }
552 else
553 {
554 // arp found ethaddr for ip (otherwise packet is replaced by arp-request)
555 data->send = false;
556 data->packet_out = 0;
557 // RF24EthernetClass::packetstate |= UIPETHERNET_SENDPACKET;
558 IF_RF24ETHERNET_DEBUG_UDP(Serial.println(data->out_pos); Serial.print(F("udp, uip_packet to send: ")); for (int i = 0; i < data->out_pos; i++) { Serial.print((char)RF24Client::all_data[0].myData[i]); } Serial.println(""););
559
560 RF24NetworkHeader headerOut(00, EXTERNAL_DATA_TYPE);
561 RF24Ethernet.network.write(headerOut, uip_buf, data->out_pos + UIP_UDP_PHYH_LEN);
562 }
563
564 #else
565 if (udpState == nullptr) {
566 udpState = new UDPState;
567 }
568 udpState->dataReceived = false;
569 udp_recv(udpPcb, receiveUdp, udpState);
570
571 pbuf* p = pbuf_alloc(PBUF_RAW, dataOutPos, PBUF_RAM);
572 if (p) {
573 memcpy(reinterpret_cast<uint8_t*>(p->payload), &udpDataOut[0], dataOutPos);
574 p->len = dataOutPos;
575
576 udp_send(udpPcb, p);
577
578 dataOutPos = 0;
579 Ethernet.update();
580
581 pbuf_free(p);
582 }
583
584 #endif
585}
586 /*******************************************************/
587
588 #endif // UIP_UDP
589#endif // UDP Enabled
RF24EthernetClass RF24Ethernet
#define UIP_ARPHDRSIZE
Definition RF24Udp.cpp:46
void uipudp_appcall(void)
Definition RF24Udp.cpp:473
#define UDPBUF
Definition RF24Udp.cpp:47
#define UIP_UDP_PHYH_LEN
Definition RF24Udp.h:33
static UDPState * udpState
Definition RF24Udp.h:55
void begin(const IPAddress &aDNSServer)
Definition Dns.cpp:45
int getHostByName(const char *aHostname, IPAddress &aResult)
Definition Dns.cpp:110
int endPacket()
Finish off this packet and send it.
Definition RF24Udp.cpp:245
void flush()
Definition RF24Udp.cpp:419
int read()
Definition RF24Udp.cpp:346
int parsePacket()
Definition RF24Udp.cpp:306
size_t write(uint8_t)
Write a single byte into the packet.
Definition RF24Udp.cpp:273
uint16_t remotePort()
Definition RF24Udp.cpp:456
IPAddress remoteIP()
Definition RF24Udp.cpp:435
RF24UDP()
Constructor.
Definition RF24Udp.cpp:58
void stop()
Finish with the UDP socket.
Definition RF24Udp.cpp:96
int peek()
Definition RF24Udp.cpp:397
int beginPacket(IPAddress ip, uint16_t port)
Sending UDP packets.
Definition RF24Udp.cpp:124
int available()
Definition RF24Udp.cpp:333
uint8_t begin(uint16_t)
initialize, start listening on specified port.
Definition RF24Udp.cpp:65
#define Ethernet
#define IF_RF24ETHERNET_DEBUG_UDP(x)
uint16_t u16_t
16 bit datatype
Definition uip-conf.h:245