39 #ifdef HAS_ETHERNETUDP
40 #include <interfaces/ARDUINO/UDPHelper_ARDUINO.h>
42 #include <interfaces/LINUX/UDPHelper_POSIX.h>
45 #include <PJONDefines.h>
48 #ifndef DUDP_RESPONSE_TIMEOUT
49 #define DUDP_RESPONSE_TIMEOUT 50000ul
55 #ifndef DUDP_MINIMUM_SEND_INTERVAL_MS
56 #define DUDP_MINIMUM_SEND_INTERVAL_MS 8
61 #define DUDP_BACKOFF(attempts) (1000ul * attempts + PJON_RANDOM(500))
65 #ifndef DUDP_MAX_RETRIES
66 #define DUDP_MAX_RETRIES 5
70 #ifndef DUDP_MAX_REMOTE_NODES
71 #define DUDP_MAX_REMOTE_NODES 10
75 #ifndef DUDP_MAX_FAILURES
76 #define DUDP_MAX_FAILURES 10
79 #define DUDP_DEFAULT_PORT 7500
80 #define DUDP_MAGIC_HEADER (uint32_t) 0x0EFA23FF
83 #ifndef DUDP_RECEIVE_TIME
84 #define DUDP_RECEIVE_TIME 0
91 bool _udp_initialized =
false;
92 bool _auto_registration =
true,
93 _auto_discovery =
true,
94 _did_broadcast =
false;
96 uint16_t _port = DUDP_DEFAULT_PORT;
97 uint8_t _unremovable_node_count = PJON_NOT_ASSIGNED;
100 uint8_t _last_out_receiver_id = 0;
101 uint8_t _last_out_sender_id = 0;
102 uint32_t _last_out_time = 0;
106 uint16_t _last_in_sender_port = 0;
107 uint8_t _last_in_sender_ip[4];
108 uint8_t _last_in_receiver_id = 0;
109 uint8_t _last_in_sender_id = 0;
112 uint8_t _remote_node_count = 0;
113 uint8_t _remote_id[DUDP_MAX_REMOTE_NODES];
114 uint8_t _remote_ip[DUDP_MAX_REMOTE_NODES][4];
115 uint16_t _remote_port[DUDP_MAX_REMOTE_NODES];
116 uint8_t _send_attempts[DUDP_MAX_REMOTE_NODES];
122 if(!_udp_initialized) {
123 udp.set_magic_header(htonl(DUDP_MAGIC_HEADER));
124 if(udp.begin(_port)) {
125 _udp_initialized =
true;
128 return _udp_initialized;
131 int16_t find_remote_node(uint8_t
id)
133 for(uint8_t i = 0; i < _remote_node_count; i++)
134 if(_remote_id[i] ==
id) {
140 int16_t autoregister_sender()
143 if(_auto_registration) {
145 if( _last_in_sender_id == 0) {
149 int16_t pos = find_remote_node( _last_in_sender_id);
157 memcpy(_remote_ip[pos], _last_in_sender_ip, 4);
158 _remote_port[pos] = _last_in_sender_port;
176 const uint8_t remote_ip[],
177 uint16_t port_number = DUDP_DEFAULT_PORT
180 if(_remote_node_count == DUDP_MAX_REMOTE_NODES) {
184 if(_unremovable_node_count == PJON_NOT_ASSIGNED) {
185 _unremovable_node_count = _remote_node_count;
187 #ifdef DUDP_DEBUG_PRINT
188 Serial.print(
"Register id ");
189 Serial.print(remote_id);
190 Serial.print(
" ip ");
191 Serial.println(remote_ip[3]);
194 _remote_id[_remote_node_count] = remote_id;
195 memcpy(_remote_ip[_remote_node_count], remote_ip, 4);
196 _remote_port[_remote_node_count] = port_number;
197 _send_attempts[_remote_node_count] = 0;
198 _remote_node_count++;
199 return _remote_node_count - 1;
204 bool remove_node(uint8_t pos)
207 if(pos < _unremovable_node_count) {
210 #ifdef DUDP_DEBUG_PRINT
211 Serial.print(
"Unregistering id ");
212 Serial.println(_remote_id[pos]);
214 for(uint8_t i = pos; i < _remote_node_count - 1; i++) {
215 _remote_id[i] = _remote_id[i + 1];
216 memcpy(_remote_ip[i], _remote_ip[i + 1], 4);
217 _remote_port[i] = _remote_port[i + 1];
218 _send_attempts[i] = _send_attempts[i + 1];
220 _remote_node_count--;
229 return _did_broadcast;
235 void set_autoregistration(
bool enabled =
true)
237 _auto_registration = enabled;
244 void set_autodiscovery(
bool enabled =
true)
246 _auto_discovery = enabled;
251 uint32_t back_off(uint8_t attempts)
253 return DUDP_BACKOFF(attempts);
259 bool begin(uint8_t device_id)
269 return check_udp() && ((uint32_t)(PJON_MILLIS() - _last_out_time) >=
270 DUDP_MINIMUM_SEND_INTERVAL_MS);
275 static uint8_t get_max_attempts()
277 return DUDP_MAX_RETRIES;
282 static uint16_t get_receive_time()
284 return DUDP_RECEIVE_TIME;
289 void handle_collision() { };
293 uint16_t receive_frame(uint8_t *
data, uint16_t max_length)
295 uint16_t length = udp.receive_frame(
data, max_length);
297 udp.get_sender( _last_in_sender_ip, _last_in_sender_port);
298 if(length != PJON_FAIL && length > 4) {
300 PJONTools::parse_header(
data, _packet_info);
301 _last_in_receiver_id = _packet_info.rx.id;
302 _last_in_sender_id = _packet_info.tx.id;
305 _packet_info.tx.id != PJON_NOT_ASSIGNED &&
306 _last_out_sender_id != PJON_NOT_ASSIGNED &&
307 _packet_info.rx.id == _last_out_sender_id
309 autoregister_sender();
317 uint16_t receive_response()
319 uint32_t start = PJON_MICROS();
321 uint16_t reply_length = 0;
323 reply_length = receive_frame(result,
sizeof result);
324 if(reply_length == PJON_FAIL) {
329 if(reply_length != 3) {
334 _last_in_receiver_id = result[0];
335 _last_in_sender_id = result[1];
336 uint8_t code = result[2];
339 if(_last_in_receiver_id != _last_out_sender_id) {
349 if(code == PJON_ACK) {
351 int16_t pos = autoregister_sender();
354 _send_attempts[pos] = 0;
358 }
while((uint32_t)(PJON_MICROS() - start) < DUDP_RESPONSE_TIMEOUT);
359 #ifdef DUDP_DEBUG_PRINT
360 Serial.println(
"Receive_response FAILED");
370 void send_response(uint8_t response)
373 buf[0] = _last_in_sender_id;
374 buf[1] = _last_in_receiver_id;
376 udp.send_response(buf, 3);
381 void send_frame(uint8_t *
data, uint16_t length)
383 _did_broadcast =
false;
386 PJONTools::parse_header(
data, _packet_info);
387 _last_out_receiver_id = _packet_info.rx.id;
388 _last_out_sender_id = _packet_info.tx.id;
392 if(_last_out_receiver_id != 0) {
393 pos = find_remote_node(_last_out_receiver_id);
399 (_send_attempts[pos] > (get_max_attempts() * DUDP_MAX_FAILURES)) &&
400 remove_node((uint8_t)pos)
406 if(_auto_discovery) {
407 udp.send_frame(
data, length);
409 _did_broadcast =
true;
410 #ifdef DUDP_DEBUG_PRINT
411 Serial.print(
"Broadcast, id ");
412 Serial.println(_last_out_receiver_id);
415 udp.send_frame(
data, length, _remote_ip[pos], _remote_port[pos]);
416 _send_attempts[pos]++;
418 _last_out_time = PJON_MILLIS();
424 void set_port(uint16_t port = DUDP_DEFAULT_PORT)