34#include <sys/select.h>
41#ifndef UDP_THREAD_PRIO
42#define UDP_THREAD_PRIO 10
45static void *
udp_thread(
void *data __attribute__((unused)));
46static pthread_mutex_t
udp_mutex = PTHREAD_MUTEX_INITIALIZER;
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
75 struct UdpSocket
sock;
82 clock_gettime(CLOCK_MONOTONIC, &ts);
92 if (getifaddrs(&ifas) == 0) {
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)) {
98 memcpy(&au->
bcast[au->
nb_bcast], i->ifa_broadaddr,
sizeof(
struct sockaddr_in));
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);
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) {
136 au->
gcs[slot] = *from;
152 to[nb++] = au->
gcs[i];
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]));
167 for (
int i = 0; i < nb; i++) {
168 sendto(ua->
sock.
sockfd, buffer, size, MSG_DONTWAIT, (
struct sockaddr *)&to[i],
sizeof(to[i]));
191 for (
int p = 0; periphs[
p] != NULL;
p++) {
201 for (
int k = 0; k < nb; k++) {
202 known |= (addr[k].s_addr == ua->
au.
gcs[i].sin_addr.s_addr);
204 if (!known && nb < max) {
205 addr[nb++] = ua->
au.
gcs[i].sin_addr;
228 if (pthread_create(&tid, NULL,
udp_thread, NULL) != 0) {
229 fprintf(stderr,
"udp_arch_init: Could not create UDP reading thread.\n");
233 pthread_setname_np(tid,
"udp");
252 p->network = (
void *)ua;
263 int available =
p->rx_insert_idx -
p->rx_extract_idx;
279 uint8_t ret =
p->rx_buf[
p->rx_extract_idx];
290 if (
p == NULL) {
return; }
291 if (
p->network == NULL) {
return; }
298 if (available <= 0) {
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);
313 for (i = 0; i < byte_read; i++) {
314 p->rx_buf[
p->rx_insert_idx] = buf[i];
327 if (
p == NULL) {
return; }
328 if (
p->network == NULL) {
return; }
332 if (
p->tx_insert_idx > 0 && ((
struct UdpArch *)
p->network)->au.enabled) {
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,
338 if (bytes_sent !=
p->tx_insert_idx) {
339 if (bytes_sent < 0) {
340 perror(
"udp_send_message failed");
342 fprintf(stderr,
"udp_send_message: only sent %d bytes instead of %d\n",
343 (
int)bytes_sent,
p->tx_insert_idx);
346 p->tx_insert_idx = 0;
355 if (
p == NULL) {
return; }
356 if (
p->network == NULL) {
return; }
358 if (((
struct UdpArch *)
p->network)->au.enabled) {
363 ssize_t test __attribute__((unused)) = sendto(sock->
sockfd, buffer, size, MSG_DONTWAIT,
380 FD_ZERO(&socks_master);
382 int fd __attribute__((unused));
385 FD_SET(
fd, &socks_master);
392 FD_SET(
fd, &socks_master);
399 FD_SET(
fd, &socks_master);
410 socks = socks_master;
412 if (select(fdmax + 1, &socks, NULL, NULL, NULL) < 0) {
413 fprintf(stderr,
"udp_thread: select failed!");
417 if (FD_ISSET(
fd, &socks)) {
423 if (FD_ISSET(
fd, &socks)) {
429 if (FD_ISSET(
fd, &socks)) {
void udp_receive(struct udp_periph *p)
Read bytes from UDP.
void udp_arch_periph_init(struct udp_periph *p, char *host, int port_out, int port_in, bool broadcast)
Initialize the UDP peripheral.
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).
static void udp_auto_send(struct UdpArch *ua, uint8_t *buffer, uint16_t size)
Send to the GCS computers found, or broadcast (see UdpAuto).
static void udp_auto_refresh_bcast(struct UdpAuto *au)
Broadcast address of every interface that is up (not loopback).
void udp_send_raw(struct udp_periph *p, long fd, uint8_t *buffer, uint16_t size)
Send a packet from another buffer.
static void * udp_thread(void *data)
check for new udp packets to receive or send.
#define UDP_AUTO_IF_REFRESH_MS
int udp_arch_auto_gcs(struct in_addr *addr, int max)
GCS computers found by the links with host "auto", each IP address once.
#define UDP_AUTO_MAX_BCAST
static uint32_t udp_time_ms(void)
static pthread_mutex_t udp_mutex
uint8_t udp_getch(struct udp_periph *p)
Get the last character from the receive buffer.
int udp_char_available(struct udp_periph *p)
Get number of bytes available in receive buffer.
void udp_send_message(struct udp_periph *p, long fd)
Send a message.
#define UDP_AUTO_BCAST_PERIOD
#define UDP_AUTO_GCS_TIMEOUT_MS
Functions to obtain rt priority or set the nice level.
static int get_rt_prio(int prio)
struct sockaddr_in bcast[UDP_AUTO_MAX_BCAST]
uint32_t gcs_seen_ms[UDP_AUTO_MAX_GCS]
0: free slot
struct sockaddr_in gcs[UDP_AUTO_MAX_GCS]
uint32_t bcast_refresh_ms
#define UDP_RX_BUFFER_SIZE
int udp_socket_create(struct UdpSocket *sock, char *host, int port_out, int port_in, bool broadcast)
Create UDP socket and bind it.
Easily create and use UDP sockets.
struct sockaddr_in addr_in
struct sockaddr_in addr_out
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.