Paparazzi UAS v7.1_unstable
Paparazzi is a free software Unmanned Aircraft System.
Loading...
Searching...
No Matches
udp_arch.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2014 Freek van Tienen <freek.v.tienen@gmail.com>
3 *
4 * This file is part of Paparazzi.
5 *
6 * Paparazzi 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 2, or (at your option)
9 * any later version.
10 *
11 * Paparazzi is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Paparazzi; see the file COPYING. If not, write to
18 * the Free Software Foundation, 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
20 */
21
25
26#include "mcu_periph/udp.h"
27#include "udp_socket.h"
28#include <stdlib.h>
29#include <stdio.h>
30#include <errno.h>
31#include <pthread.h>
32#include <string.h>
33#include <time.h>
34#include <sys/select.h>
35#include <arpa/inet.h>
36#include <ifaddrs.h>
37#include <net/if.h>
38
39#include "rt_priority.h"
40
41#ifndef UDP_THREAD_PRIO
42#define UDP_THREAD_PRIO 10
43#endif
44
45static void *udp_thread(void *data __attribute__((unused)));
46static pthread_mutex_t udp_mutex = PTHREAD_MUTEX_INITIALIZER;
47
48/*
49 * Host "auto": find the GCS computers instead of sending to one fixed address.
50 * Every address that sends to the input port is a GCS (link pings every 5 s) and gets the messages unicast
51 * (Wi-Fi acknowledges and retries unicast frames, not broadcast ones). Without a GCS, and for one send per
52 * second, the messages are broadcast instead to the broadcast address of every network interface, so a GCS
53 * started later finds the aircraft and no GCS gets a message twice.
54 */
55#define UDP_AUTO_HOST "auto"
56#define UDP_AUTO_MAX_GCS 8
57#define UDP_AUTO_MAX_BCAST 8
58#define UDP_AUTO_GCS_TIMEOUT_MS 15000
59#define UDP_AUTO_BCAST_PERIOD 1000
60#define UDP_AUTO_IF_REFRESH_MS 5000
61
62struct UdpAuto {
63 bool enabled;
65 struct sockaddr_in gcs[UDP_AUTO_MAX_GCS];
67 struct sockaddr_in bcast[UDP_AUTO_MAX_BCAST];
68 int nb_bcast;
71};
72
73/* The socket comes first, so p->network can still be used as a struct UdpSocket */
74struct UdpArch {
75 struct UdpSocket sock;
76 struct UdpAuto au;
77};
78
80{
81 struct timespec ts;
82 clock_gettime(CLOCK_MONOTONIC, &ts);
83 uint32_t ms = (uint32_t)(ts.tv_sec * 1000 + ts.tv_nsec / 1000000);
84 return ms ? ms : 1;
85}
86
88static void udp_auto_refresh_bcast(struct UdpAuto *au)
89{
90 struct ifaddrs *ifas;
91 au->nb_bcast = 0;
92 if (getifaddrs(&ifas) == 0) {
93 for (struct ifaddrs *i = ifas; i != NULL && au->nb_bcast < UDP_AUTO_MAX_BCAST; i = i->ifa_next) {
94 if (i->ifa_addr == NULL || i->ifa_addr->sa_family != AF_INET || i->ifa_broadaddr == NULL ||
95 !(i->ifa_flags & IFF_UP) || !(i->ifa_flags & IFF_BROADCAST) || (i->ifa_flags & IFF_LOOPBACK)) {
96 continue;
97 }
98 memcpy(&au->bcast[au->nb_bcast], i->ifa_broadaddr, sizeof(struct sockaddr_in));
99 au->bcast[au->nb_bcast].sin_port = htons(au->port_out);
100 au->nb_bcast++;
101 }
102 freeifaddrs(ifas);
103 }
104 if (au->nb_bcast == 0) {
105 memset(&au->bcast[0], 0, sizeof(au->bcast[0]));
106 au->bcast[0].sin_family = AF_INET;
107 au->bcast[0].sin_addr.s_addr = htonl(INADDR_BROADCAST);
108 au->bcast[0].sin_port = htons(au->port_out);
109 au->nb_bcast = 1;
110 }
111}
112
114static void udp_auto_gcs_seen(struct UdpAuto *au, struct sockaddr_in *from)
115{
116 uint32_t now = udp_time_ms();
117 int slot = -1;
118 for (int i = 0; i < UDP_AUTO_MAX_GCS; i++) {
119 if (au->gcs_seen_ms[i] != 0 && au->gcs[i].sin_addr.s_addr == from->sin_addr.s_addr &&
120 au->gcs[i].sin_port == from->sin_port) {
121 slot = i;
122 break;
123 }
124 }
125 if (slot < 0) {
126 // a free or expired slot, else the oldest one
127 for (int i = 0; i < UDP_AUTO_MAX_GCS; i++) {
128 if (slot < 0 || au->gcs_seen_ms[i] == 0 || now - au->gcs_seen_ms[i] > UDP_AUTO_GCS_TIMEOUT_MS ||
129 au->gcs_seen_ms[i] < au->gcs_seen_ms[slot]) {
130 slot = i;
131 }
132 if (au->gcs_seen_ms[slot] == 0 || now - au->gcs_seen_ms[slot] > UDP_AUTO_GCS_TIMEOUT_MS) {
133 break;
134 }
135 }
136 au->gcs[slot] = *from;
137 }
138 au->gcs_seen_ms[slot] = now;
139}
140
142static void udp_auto_send(struct UdpArch *ua, uint8_t *buffer, uint16_t size)
143{
144 struct UdpAuto *au = &ua->au;
145 uint32_t now = udp_time_ms();
146 struct sockaddr_in to[UDP_AUTO_MAX_GCS];
147 int nb = 0;
148
149 pthread_mutex_lock(&udp_mutex);
150 for (int i = 0; i < UDP_AUTO_MAX_GCS; i++) {
151 if (au->gcs_seen_ms[i] != 0 && now - au->gcs_seen_ms[i] <= UDP_AUTO_GCS_TIMEOUT_MS) {
152 to[nb++] = au->gcs[i];
153 }
154 }
155 pthread_mutex_unlock(&udp_mutex);
156
157 if (nb == 0 || now - au->last_bcast_ms >= UDP_AUTO_BCAST_PERIOD) {
158 if (au->bcast_refresh_ms == 0 || now - au->bcast_refresh_ms >= UDP_AUTO_IF_REFRESH_MS) {
160 au->bcast_refresh_ms = now;
161 }
162 au->last_bcast_ms = now;
163 for (int i = 0; i < au->nb_bcast; i++) {
164 sendto(ua->sock.sockfd, buffer, size, MSG_DONTWAIT, (struct sockaddr *)&au->bcast[i], sizeof(au->bcast[i]));
165 }
166 } else {
167 for (int i = 0; i < nb; i++) {
168 sendto(ua->sock.sockfd, buffer, size, MSG_DONTWAIT, (struct sockaddr *)&to[i], sizeof(to[i]));
169 }
170 }
171}
172
174int udp_arch_auto_gcs(struct in_addr *addr, int max)
175{
176 struct udp_periph *periphs[] = {
177#ifdef USE_UDP0
178 &udp0,
179#endif
180#ifdef USE_UDP1
181 &udp1,
182#endif
183#ifdef USE_UDP2
184 &udp2,
185#endif
186 NULL
187 };
188 uint32_t now = udp_time_ms();
189 int nb = 0;
190 pthread_mutex_lock(&udp_mutex);
191 for (int p = 0; periphs[p] != NULL; p++) {
192 struct UdpArch *ua = (struct UdpArch *) periphs[p]->network;
193 if (ua == NULL || !ua->au.enabled) {
194 continue;
195 }
196 for (int i = 0; i < UDP_AUTO_MAX_GCS; i++) {
197 if (ua->au.gcs_seen_ms[i] == 0 || now - ua->au.gcs_seen_ms[i] > UDP_AUTO_GCS_TIMEOUT_MS) {
198 continue;
199 }
200 bool known = false;
201 for (int k = 0; k < nb; k++) {
202 known |= (addr[k].s_addr == ua->au.gcs[i].sin_addr.s_addr);
203 }
204 if (!known && nb < max) {
205 addr[nb++] = ua->au.gcs[i].sin_addr;
206 }
207 }
208 }
209 pthread_mutex_unlock(&udp_mutex);
210 return nb;
211}
212
214{
215 pthread_mutex_init(&udp_mutex, NULL);
216
217#ifdef USE_UDP0
218 UDP0Init();
219#endif
220#ifdef USE_UDP1
221 UDP1Init();
222#endif
223#ifdef USE_UDP2
224 UDP2Init();
225#endif
226
227 pthread_t tid;
228 if (pthread_create(&tid, NULL, udp_thread, NULL) != 0) {
229 fprintf(stderr, "udp_arch_init: Could not create UDP reading thread.\n");
230 return;
231 }
232#ifndef __APPLE__
233 pthread_setname_np(tid, "udp");
234#endif
235}
236
241void udp_arch_periph_init(struct udp_periph *p, char *host, int port_out, int port_in, bool broadcast)
242{
243 struct UdpArch *ua = calloc(1, sizeof(struct UdpArch));
244 ua->au.enabled = (strcmp(host, UDP_AUTO_HOST) == 0);
245 ua->au.port_out = port_out;
246 if (ua->au.enabled) {
247 // broadcast until a GCS is found
248 udp_socket_create(&ua->sock, "255.255.255.255", port_out, port_in, true);
249 } else {
250 udp_socket_create(&ua->sock, host, port_out, port_in, broadcast);
251 }
252 p->network = (void *)ua;
253}
254
261{
262 pthread_mutex_lock(&udp_mutex);
263 int available = p->rx_insert_idx - p->rx_extract_idx;
264 if (available < 0) {
265 available += UDP_RX_BUFFER_SIZE;
266 }
267 pthread_mutex_unlock(&udp_mutex);
268 return available;
269}
270
277{
278 pthread_mutex_lock(&udp_mutex);
279 uint8_t ret = p->rx_buf[p->rx_extract_idx];
280 p->rx_extract_idx = (p->rx_extract_idx + 1) % UDP_RX_BUFFER_SIZE;
281 pthread_mutex_unlock(&udp_mutex);
282 return ret;
283}
284
289{
290 if (p == NULL) { return; }
291 if (p->network == NULL) { return; }
292
293 int16_t i;
296 struct UdpSocket *sock = (struct UdpSocket *) p->network;
297
298 if (available <= 0) {
299 return; // No space
300 }
301
302 socklen_t slen = sizeof(struct sockaddr_in);
303 ssize_t byte_read = recvfrom(sock->sockfd, buf, available, MSG_DONTWAIT,
304 (struct sockaddr *)&sock->addr_in, &slen);
305
306 pthread_mutex_lock(&udp_mutex);
307
308 if (byte_read > 0) {
309 struct UdpArch *ua = (struct UdpArch *) p->network;
310 if (ua->au.enabled) {
312 }
313 for (i = 0; i < byte_read; i++) {
314 p->rx_buf[p->rx_insert_idx] = buf[i];
315 p->rx_insert_idx = (p->rx_insert_idx + 1) % UDP_RX_BUFFER_SIZE;
316 }
317 }
318
319 pthread_mutex_unlock(&udp_mutex);
320}
321
325void udp_send_message(struct udp_periph *p, long fd __attribute__((unused)))
326{
327 if (p == NULL) { return; }
328 if (p->network == NULL) { return; }
329
330 struct UdpSocket *sock = (struct UdpSocket *) p->network;
331
332 if (p->tx_insert_idx > 0 && ((struct UdpArch *) p->network)->au.enabled) {
333 udp_auto_send((struct UdpArch *) p->network, p->tx_buf, p->tx_insert_idx);
334 p->tx_insert_idx = 0;
335 } else if (p->tx_insert_idx > 0) {
336 ssize_t bytes_sent = sendto(sock->sockfd, p->tx_buf, p->tx_insert_idx, MSG_DONTWAIT,
337 (struct sockaddr *)&sock->addr_out, sizeof(sock->addr_out));
338 if (bytes_sent != p->tx_insert_idx) {
339 if (bytes_sent < 0) {
340 perror("udp_send_message failed");
341 } else {
342 fprintf(stderr, "udp_send_message: only sent %d bytes instead of %d\n",
343 (int)bytes_sent, p->tx_insert_idx);
344 }
345 }
346 p->tx_insert_idx = 0;
347 }
348}
349
353void udp_send_raw(struct udp_periph *p, long fd __attribute__((unused)), uint8_t *buffer, uint16_t size)
354{
355 if (p == NULL) { return; }
356 if (p->network == NULL) { return; }
357
358 if (((struct UdpArch *) p->network)->au.enabled) {
359 udp_auto_send((struct UdpArch *) p->network, buffer, size);
360 return;
361 }
362 struct UdpSocket *sock = (struct UdpSocket *) p->network;
363 ssize_t test __attribute__((unused)) = sendto(sock->sockfd, buffer, size, MSG_DONTWAIT,
364 (struct sockaddr *)&sock->addr_out, sizeof(sock->addr_out));
365}
366
370static void *udp_thread(void *data __attribute__((unused)))
371{
373
374 /* file descriptor list */
375 fd_set socks_master;
376 /* maximum file descriptor number */
377 int fdmax = 0;
378
379 /* clear the fd list */
380 FD_ZERO(&socks_master);
381 /* add used sockets */
382 int fd __attribute__((unused));
383#if USE_UDP0
384 fd = ((struct UdpSocket *)udp0.network)->sockfd;
385 FD_SET(fd, &socks_master);
386 if (fd > fdmax) {
387 fdmax = fd;
388 }
389#endif
390#if USE_UDP1
391 fd = ((struct UdpSocket *)udp1.network)->sockfd;
392 FD_SET(fd, &socks_master);
393 if (fd > fdmax) {
394 fdmax = fd;
395 }
396#endif
397#if USE_UDP2
398 fd = ((struct UdpSocket *)udp2.network)->sockfd;
399 FD_SET(fd, &socks_master);
400 if (fd > fdmax) {
401 fdmax = fd;
402 }
403#endif
404
405 /* socks to be read, modified after each select */
406 fd_set socks;
407
408 while (1) {
409 /* reset list of socks to check */
410 socks = socks_master;
411
412 if (select(fdmax + 1, &socks, NULL, NULL, NULL) < 0) {
413 fprintf(stderr, "udp_thread: select failed!");
414 } else {
415#if USE_UDP0
416 fd = ((struct UdpSocket *)udp0.network)->sockfd;
417 if (FD_ISSET(fd, &socks)) {
418 udp_receive(&udp0);
419 }
420#endif
421#if USE_UDP1
422 fd = ((struct UdpSocket *)udp1.network)->sockfd;
423 if (FD_ISSET(fd, &socks)) {
424 udp_receive(&udp1);
425 }
426#endif
427#if USE_UDP2
428 fd = ((struct UdpSocket *)udp2.network)->sockfd;
429 if (FD_ISSET(fd, &socks)) {
430 udp_receive(&udp2);
431 }
432#endif
433 }
434 }
435 return 0;
436}
static float p[2][2]
#define UDP_THREAD_PRIO
Definition udp_arch.c:42
void udp_receive(struct udp_periph *p)
Read bytes from UDP.
Definition udp_arch.c:288
void udp_arch_periph_init(struct udp_periph *p, char *host, int port_out, int port_in, bool broadcast)
Initialize the UDP peripheral.
Definition udp_arch.c:241
static void udp_auto_gcs_seen(struct UdpAuto *au, struct sockaddr_in *from)
Remember the sender of a datagram as a GCS (called with the udp mutex).
Definition udp_arch.c:114
static void udp_auto_send(struct UdpArch *ua, uint8_t *buffer, uint16_t size)
Send to the GCS computers found, or broadcast (see UdpAuto).
Definition udp_arch.c:142
static void udp_auto_refresh_bcast(struct UdpAuto *au)
Broadcast address of every interface that is up (not loopback).
Definition udp_arch.c:88
void udp_send_raw(struct udp_periph *p, long fd, uint8_t *buffer, uint16_t size)
Send a packet from another buffer.
Definition udp_arch.c:353
static void * udp_thread(void *data)
check for new udp packets to receive or send.
Definition udp_arch.c:370
#define UDP_AUTO_IF_REFRESH_MS
Definition udp_arch.c:60
int udp_arch_auto_gcs(struct in_addr *addr, int max)
GCS computers found by the links with host "auto", each IP address once.
Definition udp_arch.c:174
#define UDP_AUTO_HOST
Definition udp_arch.c:55
void udp_arch_init(void)
Definition udp_arch.c:213
#define UDP_AUTO_MAX_BCAST
Definition udp_arch.c:57
static uint32_t udp_time_ms(void)
Definition udp_arch.c:79
#define UDP_AUTO_MAX_GCS
Definition udp_arch.c:56
static pthread_mutex_t udp_mutex
Definition udp_arch.c:46
uint8_t udp_getch(struct udp_periph *p)
Get the last character from the receive buffer.
Definition udp_arch.c:276
int udp_char_available(struct udp_periph *p)
Get number of bytes available in receive buffer.
Definition udp_arch.c:260
void udp_send_message(struct udp_periph *p, long fd)
Send a message.
Definition udp_arch.c:325
#define UDP_AUTO_BCAST_PERIOD
Definition udp_arch.c:59
#define UDP_AUTO_GCS_TIMEOUT_MS
Definition udp_arch.c:58
Functions to obtain rt priority or set the nice level.
static int get_rt_prio(int prio)
Definition rt_priority.h:32
int fd
Definition serial.c:26
struct sockaddr_in bcast[UDP_AUTO_MAX_BCAST]
Definition udp_arch.c:67
uint32_t gcs_seen_ms[UDP_AUTO_MAX_GCS]
0: free slot
Definition udp_arch.c:66
struct UdpAuto au
Definition udp_arch.c:76
uint16_t port_out
Definition udp_arch.c:64
int nb_bcast
Definition udp_arch.c:68
struct UdpSocket sock
Definition udp_arch.c:75
uint32_t last_bcast_ms
Definition udp_arch.c:70
bool enabled
Definition udp_arch.c:63
struct sockaddr_in gcs[UDP_AUTO_MAX_GCS]
Definition udp_arch.c:65
uint32_t bcast_refresh_ms
Definition udp_arch.c:69
arch independent UDP API
#define UDP_RX_BUFFER_SIZE
Definition udp.h:35
int udp_socket_create(struct UdpSocket *sock, char *host, int port_out, int port_in, bool broadcast)
Create UDP socket and bind it.
Definition udp_socket.c:49
Easily create and use UDP sockets.
struct sockaddr_in addr_in
Definition udp_socket.h:36
struct sockaddr_in addr_out
Definition udp_socket.h:37
unsigned short uint16_t
Typedef defining 16 bit unsigned short type.
unsigned int uint32_t
Typedef defining 32 bit unsigned int type.
short int16_t
Typedef defining 16 bit short type.
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.