//
// MacOS < 10.12 does not have clock_gettime
//
-// Contribution from github user "ra1nb0w"
+// Contributed initially by Davide "ra1nb0w"
//
#define CLOCK_REALTIME 0
#define CLOCK_MONOTONIC 6
-#define CLOCK_MONOTONIC_RAW 6
+#define CLOCK_MONOTONIC_RAW 4
typedef int clockid_t;
#include <sys/time.h>
ts->tv_sec = tv.tv_sec;
ts->tv_nsec = tv.tv_usec * 1000;
}
- else if ( CLOCK_MONOTONIC == clk_id )
+ else if ( CLOCK_MONOTONIC == clk_id || CLOCK_MONOTONIC_RAW == clk_id )
{
+ //
+ // For the time being, accept CLOCK_MONOTONIC_RAW but treat it
+ // the same way as CLOCK_MONOTONIC.
+ //
const uint64_t t = mach_absolute_time();
mach_timebase_info_data_t timebase;
mach_timebase_info(&timebase);
struct _DISCOVERED {
int protocol;
int device;
- int use_tcp; // use TCP rather than UDP to connect to radio
+ int use_tcp; // Radio connection is via TCP
+ int use_routing; // Radio connection is "routed" to some IP address
char name[64];
int software_version;
int status;
GtkWidget *tcpaddr;
#define IPADDR_LEN 20
-static char ipaddr_tcp_buf[IPADDR_LEN] = "10.10.10.10";
-char *ipaddr_tcp = &ipaddr_tcp_buf[0];
+static char ipaddr_buf[IPADDR_LEN] = "";
+char *ipaddr_radio = &ipaddr_buf[0];
#ifdef CLIENT_SERVER
GtkWidget *host_addr_entry;
gint host_port=50000; // default listening port
#endif
-//
-// This is a variable for the second phase of STEMlab discovery.
-// If set, we already have detected + selected the STEMlab,
-// started the SDR app on the RedPitaya and run a "P1 only"
-// discovery to obtain data from the SDR app
-//
-static int discover_only_p1 = 0;
-
static gboolean delete_event_cb(GtkWidget *widget, GdkEvent *event, gpointer data) {
_exit(0);
}
//
stemlab_cleanup();
sleep(2); // let Stemlab SDR app start
- discover_only_p1=1;
+ discover_only_stemlab=1;
gtk_widget_destroy(discovery_dialog);
g_idle_add(ext_discovery,NULL);
return TRUE;
return TRUE;
}
-static gboolean tcp_cb (GtkWidget *widget, GdkEventButton *event, gpointer data) {
- strncpy(ipaddr_tcp, gtk_entry_get_text(GTK_ENTRY(tcpaddr)), IPADDR_LEN);
- ipaddr_tcp[IPADDR_LEN-1]=0;
- // remove possible trailing newline chars in ipaddr_tcp
- int len=strnlen(ipaddr_tcp,IPADDR_LEN);
- while (--len >= 0) {
- if (ipaddr_tcp[len] != '\n') break;
- ipaddr_tcp[len]=0;
- }
- //fprintf(stderr,"New TCP addr = %s.\n", ipaddr_tcp);
- // save this value to config file
- FILE *fp = fopen("ip.addr", "w");
- if (fp) {
- fprintf(fp,"%s\n",ipaddr_tcp);
- fclose(fp);
- }
- gtk_widget_destroy(discovery_dialog);
- g_idle_add(ext_discovery,NULL);
- return TRUE;
- }
+static gboolean radio_ip_cb (GtkWidget *widget, GdkEventButton *event, gpointer data) {
+ struct sockaddr_in sa;
+ int len;
+ const char *cp;
+
+ cp = gtk_entry_get_text(GTK_ENTRY(tcpaddr));
+ len=strnlen(cp,IPADDR_LEN);
+ fprintf(stderr,">>>>%s<<<<\n", cp);
+ if (len == 0) return TRUE;
+ if (inet_pton(AF_INET, cp, &(sa.sin_addr)) != 1) return TRUE;
+
+ strncpy(ipaddr_radio, cp, IPADDR_LEN);
+ ipaddr_radio[IPADDR_LEN-1]=0;
+
+ // The new value is written upon each key stroke, so what?
+ // fprintf(stderr,"New TCP addr = %s.\n", ipaddr_radio);
+ FILE *fp = fopen("ip.addr", "w");
+ if (fp) {
+ fprintf(fp,"%s\n",ipaddr_radio);
+ fclose(fp);
+ }
+ return FALSE;
+}
#ifdef CLIENT_SERVER
static gboolean connect_cb (GtkWidget *widget, GdkEventButton *event, gpointer data) {
// Try to locate IP addr
FILE *fp=fopen("ip.addr","r");
if (fp) {
- char *c=fgets(ipaddr_tcp, IPADDR_LEN,fp);
+ char *c=fgets(ipaddr_radio, IPADDR_LEN,fp);
fclose(fp);
- ipaddr_tcp[IPADDR_LEN-1]=0;
- // remove possible trailing newline char in ipaddr_tcp
- int len=strnlen(ipaddr_tcp,IPADDR_LEN);
+ ipaddr_radio[IPADDR_LEN-1]=0;
+ // remove possible trailing newline char in ipaddr_radio
+ int len=strnlen(ipaddr_radio,IPADDR_LEN);
while (--len >= 0) {
- if (ipaddr_tcp[len] != '\n') break;
- ipaddr_tcp[len]=0;
+ if (ipaddr_radio[len] != '\n') break;
+ ipaddr_radio[len]=0;
}
}
#ifdef USBOZY
#endif
#ifdef STEMLAB_DISCOVERY
- if(enable_stemlab && !discover_only_p1) {
+ if(enable_stemlab && !discover_only_stemlab) {
#ifdef NO_AVAHI
status_text("Looking for STEMlab WEB apps");
#else
old_discovery();
}
- if(enable_protocol_2 && !discover_only_p1) {
+ if(enable_protocol_2 && !discover_only_stemlab) {
status_text("Protocol 2 ... Discovering Devices");
new_discovery();
}
#ifdef SOAPYSDR
- if(enable_soapy_protocol && !discover_only_p1) {
+ if(enable_soapy_protocol && !discover_only_stemlab) {
status_text("SoapySDR ... Discovering Devices");
soapy_discovery();
}
#endif
// subsequent discoveries check all protocols enabled.
- discover_only_p1=0;
+ discover_only_stemlab=0;
status_text("Discovery");
}
#ifdef SOAPYSDR
- if(d->device!=SOAPYSDR_USB_DEVICE) {
+ if(d->device!=SOAPYSDR_USB_DEVICE)
#endif
- // if not on the same subnet then cannot start it
- //
- // NOTE: self-assigned IP (a.k.a. APIPA) addresses
- // these addresses are of the numerical form 169.254.xxx.yyy and used
- // by many radios if they do not get a DHCP address. These addresses are valid even if outside the
- // netmask of the (physical) interface making the connection - so do not complain in this case!
+ {
+ int can_connect = 0;
//
- // If the radio has a valid IP address but the computer only has an APIPA address, this also
- // leads to a radio address outside the netmask and can be ignored. So if either the radio
- // or the interface address starts with 169.254., suppress "Subnet!" complaint.
+ // We can connect if
+ // a) either the computer or the radio have a self-assigned IP 169.254.xxx.yyy address
+ // b) we have a "routed" (TCP or UDP) connection to the radio
+ // c) radio and network address are in the same subnet
//
- if (strncmp(inet_ntoa(d->info.network.address.sin_addr),"169.254.",8) &&
- strncmp(inet_ntoa(d->info.network.interface_address.sin_addr),"169.254.",8)) {
- if((d->info.network.interface_address.sin_addr.s_addr&d->info.network.interface_netmask.sin_addr.s_addr) != (d->info.network.address.sin_addr.s_addr&d->info.network.interface_netmask.sin_addr.s_addr)) {
+ if (!strncmp(inet_ntoa(d->info.network.address.sin_addr),"169.254.",8)) can_connect=1;
+ if (!strncmp(inet_ntoa(d->info.network.interface_address.sin_addr),"169.254.",8)) can_connect=1;
+ if (d->use_routing) can_connect=1;
+ if((d->info.network.interface_address.sin_addr.s_addr&d->info.network.interface_netmask.sin_addr.s_addr) ==
+ (d->info.network.address.sin_addr.s_addr&d->info.network.interface_netmask.sin_addr.s_addr)) can_connect=1;
+
+ if (!can_connect) {
gtk_button_set_label(GTK_BUTTON(start_button),"Subnet!");
gtk_widget_set_sensitive(start_button, FALSE);
- }
}
-#ifdef SOAPYSDR
}
-#endif
#ifdef STEMLAB_DISCOVERY
if (d->protocol == STEMLAB_PROTOCOL) {
gtk_grid_attach(GTK_GRID(grid),gpio_b,0,row,1,1);
#endif
- GtkWidget *tcp_b=gtk_button_new_with_label("Use new TCP Addr:");
- g_signal_connect (tcp_b, "button-press-event", G_CALLBACK(tcp_cb), NULL);
+ GtkWidget *tcp_b=gtk_label_new("Radio IP Addr:");
gtk_grid_attach(GTK_GRID(grid),tcp_b,1,row,1,1);
tcpaddr=gtk_entry_new();
gtk_entry_set_max_length(GTK_ENTRY(tcpaddr), 20);
gtk_grid_attach(GTK_GRID(grid),tcpaddr,2,row,1,1);
- gtk_entry_set_text(GTK_ENTRY(tcpaddr), ipaddr_tcp);
+ gtk_entry_set_text(GTK_ENTRY(tcpaddr), ipaddr_radio);
+ g_signal_connect (tcpaddr, "changed", G_CALLBACK(radio_ip_cb), NULL);
GtkWidget *exit_b=gtk_button_new_with_label("Exit");
g_signal_connect (exit_b, "button-press-event", G_CALLBACK(exit_cb), NULL);
*/
extern void discovery(void);
-extern char *ipaddr_tcp;
+extern char *ipaddr_radio;
#include "discovered.h"
#include "discovery.h"
#include "old_discovery.h"
+#include "stemlab_discovery.h"
static char interface_name[64];
static struct sockaddr_in interface_addr={0};
static GThread *discover_thread_id;
static gpointer discover_receive_thread(gpointer data);
-static void discover(struct ifaddrs* iface) {
+//
+// discflag = 1: discover by sending UDP broadcast packet
+// discflag = 2: discover by sending UDP backet to Radio IP address
+// discflag = 3: discover by connecting via TCP
+//
+static void discover(struct ifaddrs* iface, int discflag) {
int rc;
struct sockaddr_in *sa;
struct sockaddr_in *mask;
unsigned char buffer[1032];
int i, len;
- if (iface == NULL) {
+ switch (discflag) {
+ case 1:
//
- // This indicates that we want to connect to an SDR which
- // cannot be reached by (UDP) broadcast packets, but that
- // we know its fixed IP address
- // Therefore we try to send a METIS detection packet via TCP
- // to a "fixed" ip address.
+ // Send METIS discovery packet to broadcast address on interface iface
//
- fprintf(stderr,"Trying to detect at TCP addr %s\n", ipaddr_tcp);
+ strcpy(interface_name,iface->ifa_name);
+ fprintf(stderr,"discover: looking for HPSDR devices on %s\n", interface_name);
+
+ // send a broadcast to locate hpsdr boards on the network
+ discovery_socket=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
+ if(discovery_socket<0) {
+ perror("discover: create socket failed for discovery_socket:");
+ return;
+ }
+
+ sa = (struct sockaddr_in *) iface->ifa_addr;
+ mask = (struct sockaddr_in *) iface->ifa_netmask;
+ interface_netmask.sin_addr.s_addr = mask->sin_addr.s_addr;
+
+ // bind to this interface and the discovery port
+ interface_addr.sin_family = AF_INET;
+ interface_addr.sin_addr.s_addr = sa->sin_addr.s_addr;
+ //interface_addr.sin_port = htons(DISCOVERY_PORT*2);
+ interface_addr.sin_port = htons(0); // system assigned port
+ if(bind(discovery_socket,(struct sockaddr*)&interface_addr,sizeof(interface_addr))<0) {
+ perror("discover: bind socket failed for discovery_socket:");
+ return;
+ }
+
+ fprintf(stderr,"discover: bound to %s\n",interface_name);
+
+ // allow broadcast on the socket
+ int on=1;
+ rc=setsockopt(discovery_socket, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
+ if(rc != 0) {
+ fprintf(stderr,"discover: cannot set SO_BROADCAST: rc=%d\n", rc);
+ return;
+ }
+
+ // setup to address
+ to_addr.sin_family=AF_INET;
+ to_addr.sin_port=htons(DISCOVERY_PORT);
+ to_addr.sin_addr.s_addr=htonl(INADDR_BROADCAST);
+ break;
+ case 2:
+ //
+ // Send METIS detection packet via UDP to ipaddr_radio
+ //
+ fprintf(stderr,"discover: looking for HPSDR device with IP %s\n", ipaddr_radio);
+
+ discovery_socket=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
+ if(discovery_socket<0) {
+ perror("discover: create socket failed for discovery_socket:");
+ return;
+ }
+ to_addr.sin_family=AF_INET;
+ to_addr.sin_port=htons(DISCOVERY_PORT);
+ if (inet_aton(ipaddr_radio, &to_addr.sin_addr) == 0) {
+ fprintf(stderr, "discover: Radio UDP addr %s is invalid!\n", ipaddr_radio);
+ return;
+ }
+ break;
+ case 3:
+ //
+ // Send METIS detection packet via TCP to ipaddr_radio
+ // This is rather tricky, one must avoid "hanging" when the
+ // connection does not succeed.
+ //
+ fprintf(stderr,"Trying to detect via TCP with IP %s\n", ipaddr_radio);
memset(&to_addr, 0, sizeof(to_addr));
to_addr.sin_family = AF_INET;
- if (inet_aton(ipaddr_tcp, &to_addr.sin_addr) == 0) {
- fprintf(stderr,"discover: TCP addr %s is invalid!\n",ipaddr_tcp);
+ if (inet_aton(ipaddr_radio, &to_addr.sin_addr) == 0) {
+ fprintf(stderr,"discover: TCP addr %s is invalid!\n",ipaddr_radio);
return;
}
to_addr.sin_port=htons(DISCOVERY_PORT);
}
// Step 4. reset the socket to normal (blocking) mode
fcntl(discovery_socket, F_SETFL, flags & ~O_NONBLOCK);
- } else {
-
- strcpy(interface_name,iface->ifa_name);
- fprintf(stderr,"discover: looking for HPSDR devices on %s\n", interface_name);
-
- // send a broadcast to locate hpsdr boards on the network
- discovery_socket=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
- if(discovery_socket<0) {
- perror("discover: create socket failed for discovery_socket:");
- exit(-1);
- }
-
- sa = (struct sockaddr_in *) iface->ifa_addr;
- mask = (struct sockaddr_in *) iface->ifa_netmask;
- interface_netmask.sin_addr.s_addr = mask->sin_addr.s_addr;
-
- // bind to this interface and the discovery port
- interface_addr.sin_family = AF_INET;
- interface_addr.sin_addr.s_addr = sa->sin_addr.s_addr;
- //interface_addr.sin_port = htons(DISCOVERY_PORT*2);
- interface_addr.sin_port = htons(0); // system assigned port
- if(bind(discovery_socket,(struct sockaddr*)&interface_addr,sizeof(interface_addr))<0) {
- perror("discover: bind socket failed for discovery_socket:");
- return;
- }
-
- fprintf(stderr,"discover: bound to %s\n",interface_name);
-
- // allow broadcast on the socket
- int on=1;
- rc=setsockopt(discovery_socket, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
- if(rc != 0) {
- fprintf(stderr,"discover: cannot set SO_BROADCAST: rc=%d\n", rc);
- exit(-1);
- }
-
- // setup to address
- to_addr.sin_family=AF_INET;
- to_addr.sin_port=htons(DISCOVERY_PORT);
- to_addr.sin_addr.s_addr=htonl(INADDR_BROADCAST);
+ break;
+ default:
+ return;
+ break;
}
+
optval = 1;
setsockopt(discovery_socket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
setsockopt(discovery_socket, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval));
rc=devices;
// start a receive thread to collect discovery response packets
discover_thread_id = g_thread_new( "old discover receive", discover_receive_thread, NULL);
- if( ! discover_thread_id )
- {
- fprintf(stderr,"g_thread_new failed on discover_receive_thread\n");
- exit( -1 );
- }
-
-
// send discovery packet
// If this is a TCP connection, send a "long" packet
- len=63;
- if (iface == NULL) len=1032;
+ switch (discflag) {
+ case 1:
+ case 2:
+ len=63; // send UDP packet
+ break;
+ case 3:
+ len=1032; // send TCP packet
+ break;
+ }
buffer[0]=0xEF;
buffer[1]=0xFE;
buffer[2]=0x02;
close(discovery_socket);
- if (iface == NULL) {
- fprintf(stderr,"discover: exiting TCP discover for %s\n",ipaddr_tcp);
- if (devices == rc+1) {
- //
- // We have exactly found one TCP device
- // and have to patch the TCP addr into the device field
- // and set the "use TCP" flag.
- //
- memcpy((void*)&discovered[rc].info.network.address,(void*)&to_addr,sizeof(to_addr));
- discovered[rc].info.network.address_length=sizeof(to_addr);
- memcpy((void*)&discovered[rc].info.network.interface_address,(void*)&to_addr,sizeof(to_addr));
- memcpy((void*)&discovered[rc].info.network.interface_netmask,(void*)&to_addr,sizeof(to_addr));
- discovered[rc].info.network.interface_length=sizeof(to_addr);
- strcpy(discovered[rc].info.network.interface_name,"TCP");
- discovered[rc].use_tcp=1;
- }
- } else {
- fprintf(stderr,"discover: exiting discover for %s\n",iface->ifa_name);
+ switch (discflag) {
+ case 1:
+ fprintf(stderr,"discover: exiting discover for %s\n",iface->ifa_name);
+ break;
+ case 2:
+ fprintf(stderr,"discover: exiting HPSDR discover for IP %s\n",ipaddr_radio);
+ if (devices == rc+1) {
+ //
+ // METIS detection UDP packet sent to fixed IP address got a valid response.
+ //
+ memcpy((void *)&discovered[rc].info.network.address, (void *)&to_addr,sizeof(to_addr));
+ discovered[rc].info.network.address_length = sizeof(to_addr);
+ strcpy(discovered[rc].info.network.interface_name,"UDP");
+ discovered[rc].use_routing=1;
+ }
+ break;
+ case 3:
+ fprintf(stderr,"discover: exiting TCP discover for IP %s\n",ipaddr_radio);
+ if (devices == rc+1) {
+ //
+ // METIS detection TCP packet sent to fixed IP address got a valid response.
+ // Patch the IP addr into the device field
+ // and set the "use TCP" flag.
+ //
+ memcpy((void*)&discovered[rc].info.network.address,(void*)&to_addr,sizeof(to_addr));
+ discovered[rc].info.network.address_length=sizeof(to_addr);
+ memcpy((void*)&discovered[rc].info.network.interface_address,(void*)&to_addr,sizeof(to_addr));
+ memcpy((void*)&discovered[rc].info.network.interface_netmask,(void*)&to_addr,sizeof(to_addr));
+ discovered[rc].info.network.interface_length=sizeof(to_addr);
+ strcpy(discovered[rc].info.network.interface_name,"TCP");
+ discovered[rc].use_routing=1;
+ discovered[rc].use_tcp=1;
+ }
+ break;
}
-
}
//static void *discover_receive_thread(void* arg) {
discovered[devices].info.network.interface_length=sizeof(interface_addr);
strcpy(discovered[devices].info.network.interface_name,interface_name);
discovered[devices].use_tcp=0;
+ discovered[devices].use_routing=0;
discovered[devices].supported_receivers=2;
fprintf(stderr,"old_discovery: found device=%d software_version=%d status=%d address=%s (%02X:%02X:%02X:%02X:%02X:%02X) on %s min=%f max=%f\n",
discovered[devices].device,
struct ifaddrs *addrs,*ifa;
fprintf(stderr,"old_discovery\n");
- getifaddrs(&addrs);
- ifa = addrs;
- while (ifa) {
+ //
+ // In the second phase of the STEMlab (RedPitaya) discovery,
+ // we know that it can be reached by a specific IP address
+ // and do not need broadcast packets
+ //
+ if (!discover_only_stemlab) {
+ getifaddrs(&addrs);
+ ifa = addrs;
+ while (ifa) {
g_main_context_iteration(NULL, 0);
if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET) {
if((ifa->ifa_flags&IFF_UP)==IFF_UP
&& (ifa->ifa_flags&IFF_RUNNING)==IFF_RUNNING) {
//&& (ifa->ifa_flags&IFF_LOOPBACK)!=IFF_LOOPBACK) {
- discover(ifa);
+ discover(ifa, 1); // send UDP broadcast packet to interface
}
}
ifa = ifa->ifa_next;
+ }
+ freeifaddrs(addrs);
}
- freeifaddrs(addrs);
- // Do one additional "discover" for a fixed TCP address
- discover(NULL);
+ //
+ // If a radio ip addr is given, try sending a UDP packet to that address
+ // and try connecting via TCP
+ //
+ if (strlen(ipaddr_radio) > 1) {
+ discover(NULL, 2);
+ discover(NULL, 3);
+ }
fprintf(stderr, "discovery found %d devices\n",devices);
#include <avahi-gobject/ga-service-resolver.h>
#endif
+int discover_only_stemlab=0;
+
// As we only run in the GTK+ main event loop, which is single-threaded and
// non-preemptive, we shouldn't need any additional synchronisation mechanisms.
static bool discovery_done = FALSE;
struct sockaddr_in netmask;
fprintf(stderr,"Stripped-down STEMLAB/HAMLAB discovery...\n");
- fprintf(stderr,"STEMLAB: using inet addr %s\n", ipaddr_tcp);
+ fprintf(stderr,"STEMLAB: using inet addr %s\n", ipaddr_radio);
ip_address.sin_family = AF_INET;
- if (inet_aton(ipaddr_tcp, &ip_address.sin_addr) == 0) {
- fprintf(stderr,"StemlabDiscovery: TCP %s is invalid!\n", ipaddr_tcp);
+ if (inet_aton(ipaddr_radio, &ip_address.sin_addr) == 0) {
+ fprintf(stderr,"StemlabDiscovery: TCP %s is invalid!\n", ipaddr_radio);
return;
}
return;
}
app_list=0;
- sprintf(txt,"http://%s",ipaddr_tcp);
+ sprintf(txt,"http://%s",ipaddr_radio);
curl_easy_setopt(curl_handle, CURLOPT_URL, txt);
curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, (long) 5);
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, get_list_cb);
curl_error = curl_easy_perform(curl_handle);
curl_easy_cleanup(curl_handle);
if (curl_error == CURLE_OPERATION_TIMEDOUT) {
- sprintf(txt,"No response from web server at %s", ipaddr_tcp);
+ sprintf(txt,"No response from web server at %s", ipaddr_radio);
status_text(txt);
fprintf(stderr,"%s\n",txt);
}
fprintf(stderr, "stemlab_start: Failed to create cURL handle\n");
return;
}
- sprintf(txt,"http://%s/bazaar?apps=", ipaddr_tcp);
+ sprintf(txt,"http://%s/bazaar?apps=", ipaddr_radio);
curl_easy_setopt(curl_handle, CURLOPT_URL, txt);
curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, (long) 20);
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, app_list_cb);
*
*/
+extern int discover_only_stemlab;
+
extern void stemlab_discovery(void);
extern int stemlab_start_app(const char * const app_id);
extern int alpine_start_app(const char * const app_id);