From: c vw Date: Tue, 24 Jul 2018 08:00:12 +0000 (+0200) Subject: Changes that affect the user interface X-Git-Url: https://git.rkrishnan.org/pf/content/en/seg/status?a=commitdiff_plain;h=027cb031f89d6edbd9b082e76ba47ca7fd865ad7;p=pihpsdr.git Changes that affect the user interface ====================================== A. applies only if compiled with the STEMLAB_DISCOVERY_OPTION: unified non-AVAHI and AVAHI versions of stemlab_discovery. STEMLAB_DISCOVERY_MAC in Makefile.mac no longer needed. Made the user interface more specific in the NO_AVAHI version. Currently, the no-avahi version is only activated in Makefile.mac but could be useful for *nix systems where you do not have avahi. B. applies only if compiled with SPLIT_RXTX defined: if using two receivers, the TX panel only "hides" the first one. it is possible to listen to RX2 while TXing on the RX1 frequency, very useful for measurements where you feed-back the attenuated TX signal to the RX2 antenna jack. This implies that if RX2 is active while TXing, you see the S-meter of RX2 and not the TX levels (to be able to measure the signal strength). RXing with RX2 and TXing with TX on the RX1 frequency implies that you go "split". This is so useful that it is the default option for me now. C. applies only if compiled with DIGI_MODES defined: when switching to DIGU or DIGL, you automatically get wide RX filters (0 ... 3000 Hz) and all noise reduction OFF without changing the current settings. So when returning to another mode (say, CWL or USB), the filter/NR settings effective before switching to digi are restored. This is so useful that it is the default option for me now. D. if *not* compiled with the PURESIGNAL_OPTION, you still get a two-tone generator for testing purposed. The new button TT is located exactly where the PS button is placed if compiled with PURESIGNAL. E. Small change to make B. meaningful: - Upon TX, mute only that RX that is bound to the TX frequency - Upon TX, mute the audio of the active_receiver only in CW mode (to give room for the side tone). Error corrections (only the most important ones) ================================================ - avoid core dump if using PURESIGNAL with METIS devices: create receiver[PS_T(R)X_FEEDBACK] in any case - colouring the correct TX frequency in red in the VFO panel - use correct attenuation scale for filter_board == CHARLY25 - initialize tx->attenuation - explicitly specifying levels and frequencies for two-tone (the defaults were silently used). - changed an #ifdef FREEDV to #ifdef PURESIGNAL in vfo_menu.c (obvious error) --- diff --git a/Makefile.mac b/Makefile.mac index 514ab03..b551b64 100644 --- a/Makefile.mac +++ b/Makefile.mac @@ -30,11 +30,8 @@ STEMLAB_FIX_OPTION=-DSTEMLAB_FIX # uncomment the line to below include support local CW keyer #LOCALCW_INCLUDE=LOCALCW -# uncomment the line below to include support for STEMlab discovery (does not work on MacOS) -#STEMLAB_DISCOVERY=STEMLAB_DISCOVERY - -# uncomment the line below to include support for stripped-down STEMlab discovery that works on MacOS -STEMLAB_DISCOVERY=STEMLAB_DISCOVERY_MAC +# uncomment the line below to include support for STEMlab discovery +STEMLAB_DISCOVERY=STEMLAB_DISCOVERY #uncomment the line below for the platform being compiled on UNAME_N=MacOS @@ -44,6 +41,15 @@ UNAME_N=MacOS #UNAME_N=pine64 #UNAME_N=jetsen +# Additional options that can be chosen at compile time: +# -DDIGI_MODES wide filters and no noise reduction in DIGU/DIGL +# -DSPLIT_RXTX if there is more than one receiver, TX panel only "hides" the first one +# -DPROTOCOL_DEBUG logs (on stderr) all state changes sent to the SDR (only old protocol) +# +# leave the list empty if no such option should be used + +ADDITIONAL_OPTIONS= -DDIGI_MODES -DSPLIT_RXTX + CC=gcc ifeq ($(UNAME_N),MacOS) @@ -181,21 +187,11 @@ ifeq ($(I2C_INCLUDE),I2C) endif # -# STEMLAB_DISCOVERY_MAC depends on curl but not on avahi +# Here in Makefile.mac, we use the version that does not need avahi # -ifeq ($(STEMLAB_DISCOVERY), STEMLAB_DISCOVERY_MAC) -STEMLAB_OPTIONS=-D STEMLAB_DISCOVERY `pkg-config --cflags libcurl` -STEMLAB_LIBS=`pkg-config --libs libcurl` -STEMLAB_SOURCES=stemlab_discovery.c -STEMLAB_HEADERS=stemlab_discovery.h -STEMLAB_OBJS=stemlab_discovery.o -endif - ifeq ($(STEMLAB_DISCOVERY), STEMLAB_DISCOVERY) -STEMLAB_OPTIONS=-D STEMLAB_DISCOVERY \ - `pkg-config --cflags avahi-gobject` \ - `pkg-config --cflags libcurl` -STEMLAB_LIBS=`pkg-config --libs avahi-gobject` `pkg-config --libs libcurl` +STEMLAB_OPTIONS=-D STEMLAB_DISCOVERY -D NO_AVAHI `pkg-config --cflags libcurl` +STEMLAB_LIBS=`pkg-config --libs libcurl` STEMLAB_SOURCES=stemlab_discovery.c STEMLAB_HEADERS=stemlab_discovery.h STEMLAB_OBJS=stemlab_discovery.o @@ -214,7 +210,7 @@ AUDIO_LIBS=-lportaudio OPTIONS=-g -Wno-deprecated-declarations $(PURESIGNAL_OPTIONS) $(REMOTE_OPTIONS) $(RADIOBERRY_OPTIONS) \ $(USBOZY_OPTIONS) $(I2C_OPTIONS) $(GPIO_OPTIONS) $(LIMESDR_OPTIONS) $(FREEDV_OPTIONS) \ $(LOCALCW_OPTIONS) $(PSK_OPTIONS) $(STEMLAB_OPTIONS) $(STEMLAB_FIX_OPTION) \ - $(PORTAUDIO_OPTIONS) \ + $(PORTAUDIO_OPTIONS) $(ADDITIONAL_OPTIONS) \ -D GIT_DATE='"$(GIT_DATE)"' -D GIT_VERSION='"$(GIT_VERSION)"' $(DEBUG_OPTION) -O3 LIBS= $(AUDIO_LIBS) $(USBOZY_LIBS) $(PSKLIBS) $(GTKLIBS) $(GPIO_LIBS) \ diff --git a/audio.c b/audio.c index 277a06a..8d9ccf6 100644 --- a/audio.c +++ b/audio.c @@ -364,8 +364,16 @@ int audio_write(RECEIVER *rx,short left_sample,short right_sample) { snd_pcm_sframes_t delay; int error; long trim; - - if (rx == active_receiver && isTransmitting()) return; + int mode=transmitter->mode; + // + // We have to stop the stream here if a CW side tone may occur. + // This might cause underflows, but we cannot use audio_write + // and cw_audio_write simultaneously on the same device. + // Instead, the side tone version will take over. + // If *not* doing CW, the stream continues because we might wish + // to listen to this rx while transmitting. + // + if (rx == active_receiver && isTransmitting() && (mode==modeCWU || mode==modeCWL)) return 0; if(rx->playback_handle!=NULL && rx->playback_buffer!=NULL) { rx->playback_buffer[rx->playback_offset++]=right_sample; diff --git a/discovery.c b/discovery.c index f34ea51..c59a6a2 100644 --- a/discovery.c +++ b/discovery.c @@ -61,6 +61,14 @@ fprintf(stderr,"start_cb: %p\n",data); if (radio->protocol == STEMLAB_PROTOCOL) { const int device_id = radio - discovered; stemlab_start_app(gtk_combo_box_get_active_id(GTK_COMBO_BOX(apps_combobox[device_id]))); +#ifdef NO_AVAHI + // We only have started the app, but not queried e.g. the MAC address. + // Therefore, we have to clean up and re-start the discovery process. + stemlab_cleanup(); + gtk_widget_destroy(discovery_dialog); + g_idle_add(ext_discovery,NULL); + return TRUE; +#endif } stemlab_cleanup(); #endif @@ -113,7 +121,11 @@ fprintf(stderr,"discovery\n"); #endif #ifdef STEMLAB_DISCOVERY +#ifdef NO_AVAHI + status_text("Looking for STEMlab WEB apps"); +#else status_text("STEMlab (Avahi) ... Discovering Devices"); +#endif stemlab_discovery(); #endif @@ -211,7 +223,7 @@ fprintf(stderr,"%p Protocol=%d name=%s\n",d,d->protocol,d->name); sprintf(text,"%s (%s) on USB /dev/ozy", d->name, d->protocol==ORIGINAL_PROTOCOL?"Protocol 1":"Protocol 2"); } else { #endif - sprintf(text,"%s (%s %s) %s (%02X:%02X:%02X:%02X:%02X:%02X) on %s", + sprintf(text,"%s (%s %s) %s (%02X:%02X:%02X:%02X:%02X:%02X) on %s ", d->name, d->protocol==ORIGINAL_PROTOCOL?"Protocol 1":"Protocol 2", version, @@ -235,6 +247,9 @@ fprintf(stderr,"%p Protocol=%d name=%s\n",d,d->protocol,d->name); #endif #ifdef STEMLAB_DISCOVERY case STEMLAB_PROTOCOL: +#ifdef NO_AVAHI + sprintf(text,"Choose App from %s and re-Discover:",inet_ntoa(d->info.network.address.sin_addr)); +#else sprintf(text, "STEMlab (%02X:%02X:%02X:%02X:%02X:%02X) on %s", d->info.network.mac_address[0], d->info.network.mac_address[1], @@ -243,11 +258,13 @@ fprintf(stderr,"%p Protocol=%d name=%s\n",d,d->protocol,d->name); d->info.network.mac_address[4], d->info.network.mac_address[5], d->info.network.interface_name); +#endif #endif } GtkWidget *label=gtk_label_new(text); gtk_widget_override_font(label, pango_font_description_from_string("FreeMono 12")); + gtk_widget_set_halign (label, GTK_ALIGN_START); gtk_widget_show(label); gtk_grid_attach(GTK_GRID(grid),label,0,i,3,1); @@ -279,7 +296,7 @@ fprintf(stderr,"%p Protocol=%d name=%s\n",d,d->protocol,d->name); gtk_widget_override_font(apps_combobox[i], pango_font_description_from_string("FreeMono 12")); // We want the default selection priority for the STEMlab app to be - // RP-Trx > Pavel-Trx > Pavel-Rx, so we add in decreasing order and + // RP-Trx > HAMlab-Trx > Pavel-Trx > Pavel-Rx, so we add in decreasing order and // always set the newly added entry to be active. if ((d->software_version & STEMLAB_PAVEL_RX) != 0) { gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(apps_combobox[i]), @@ -293,18 +310,18 @@ fprintf(stderr,"%p Protocol=%d name=%s\n",d,d->protocol,d->name); gtk_combo_box_set_active_id(GTK_COMBO_BOX(apps_combobox[i]), "sdr_transceiver_hpsdr"); } - if ((d->software_version & STEMLAB_RP_TRX) != 0) { - gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(apps_combobox[i]), - "stemlab_sdr_transceiver_hpsdr", "STEMlab-Trx"); - gtk_combo_box_set_active_id(GTK_COMBO_BOX(apps_combobox[i]), - "stemlab_sdr_transceiver_hpsdr"); - } if ((d->software_version & HAMLAB_RP_TRX) != 0) { gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(apps_combobox[i]), "hamlab_sdr_transceiver_hpsdr", "HAMlab-Trx"); gtk_combo_box_set_active_id(GTK_COMBO_BOX(apps_combobox[i]), "hamlab_sdr_transceiver_hpsdr"); } + if ((d->software_version & STEMLAB_RP_TRX) != 0) { + gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(apps_combobox[i]), + "stemlab_sdr_transceiver_hpsdr", "STEMlab-Trx"); + gtk_combo_box_set_active_id(GTK_COMBO_BOX(apps_combobox[i]), + "stemlab_sdr_transceiver_hpsdr"); + } gtk_widget_show(apps_combobox[i]); gtk_grid_attach(GTK_GRID(grid), apps_combobox[i], 4, i, 1, 1); } diff --git a/filter_menu.c b/filter_menu.c index 092d890..cacf920 100644 --- a/filter_menu.c +++ b/filter_menu.c @@ -196,6 +196,13 @@ void filter_menu(GtkWidget *parent) { } break; +#ifdef DIGI_MODES + case modeDIGU: + case modeDIGL: + gtk_button_set_label(GTK_BUTTON(close_b), "DIGU/DIGL have a fixed wide filter."); + break; +#endif + default: for(i=0;itwotone?0:1; + tx_set_twotone(transmitter,state); + if(state) { + set_button_text_color(widget,"red"); + } else { + set_button_text_color(widget,"black"); + } + return TRUE; +} #endif #ifdef GPIO @@ -478,6 +492,15 @@ void new_menu() g_signal_connect (ps_b, "button-press-event", G_CALLBACK(ps_cb), NULL); gtk_grid_attach(GTK_GRID(grid),ps_b,(i%5),i/5,1,1); i++; +#else + GtkWidget *tt_b=gtk_button_new_with_label("TT"); + gtk_widget_show(tt_b); + gtk_grid_attach(GTK_GRID(grid),tt_b,(i%5),i/5,1,1); + g_signal_connect (tt_b, "pressed", G_CALLBACK(tt_cb), NULL); + if(transmitter->twotone) { + set_button_text_color(tt_b,"red"); + } + i++; #endif GtkWidget *pa_b=gtk_button_new_with_label("PA"); diff --git a/new_protocol.c b/new_protocol.c index 93d84a9..a30d2ea 100644 --- a/new_protocol.c +++ b/new_protocol.c @@ -417,10 +417,6 @@ void new_protocol_init(int pixels) { rc=sem_init(&iq_sem_buffer[ddc], 0, 0); #endif iq_thread_id[ddc] = g_thread_new( "ps iq thread", ps_iq_thread, (gpointer)(long)PS_TX_FEEDBACK); - if( ! iq_thread_id ) { - fprintf(stderr,"g_thread_new failed for ps_iq_thread: rx=%d\n",PS_TX_FEEDBACK); - exit( -1 ); - } fprintf(stderr, "iq_thread: id=%p\n",iq_thread_id); } #endif @@ -1446,7 +1442,7 @@ static void process_ps_iq_data(RECEIVER *rx) { } rx->iq_sequence++; - timestamp=((long long)(buffer[4]&0xFF)<<56)+((long long)(buffer[5]&0xFF)<<48)+((long long)(buffer[6]&0xFF)<<40)+((long long)(buffer[7]&0xFF)<<32); + timestamp=((long long)(buffer[4]&0xFF)<<56)+((long long)(buffer[5]&0xFF)<<48)+((long long)(buffer[6]&0xFF)<<40)+((long long)(buffer[7]&0xFF)<<32)+ ((long long)(buffer[8]&0xFF)<<24)+((long long)(buffer[9]&0xFF)<<16)+((long long)(buffer[10]&0xFF)<<8)+(long long)(buffer[11]&0xFF); bitspersample=((buffer[12]&0xFF)<<8)+(buffer[13]&0xFF); samplesperframe=((buffer[14]&0xFF)<<8)+(buffer[15]&0xFF); diff --git a/noise_menu.c b/noise_menu.c index d26f0d2..a377332 100644 --- a/noise_menu.c +++ b/noise_menu.c @@ -59,7 +59,20 @@ static gboolean delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_d return FALSE; } +#ifdef DIGI_MODES +void noise_off() { + SetEXTANBRun(active_receiver->id, 0); + SetEXTNOBRun(active_receiver->id, 0); + SetRXAANRRun(active_receiver->id, 0); + SetRXAEMNRRun(active_receiver->id, 0); + SetRXAANFRun(active_receiver->id, 0); + SetRXASNBARun(active_receiver->id, 0); +} + +void update_noise() { +#else static void update_noise() { +#endif SetEXTANBRun(active_receiver->id, active_receiver->nb); SetEXTNOBRun(active_receiver->id, active_receiver->nb2); SetRXAANRRun(active_receiver->id, active_receiver->nr); @@ -118,6 +131,7 @@ static void snb_cb(GtkWidget *widget, gpointer data) { void noise_menu(GtkWidget *parent) { GtkWidget *b; int i; + int mode=vfo[active_receiver->id].mode; parent_window=parent; @@ -145,6 +159,14 @@ void noise_menu(GtkWidget *parent) { gtk_grid_set_column_spacing (GTK_GRID(grid),5); gtk_grid_set_row_spacing (GTK_GRID(grid),5); +#ifdef DIGI_MODES + if (mode == modeDIGU || mode == modeDIGL) { + GtkWidget *close_b=gtk_button_new_with_label("DIGU/DIGL have no noise options."); + g_signal_connect (close_b, "pressed", G_CALLBACK(close_cb), NULL); + gtk_grid_attach(GTK_GRID(grid),close_b,0,0,1,1); + } + else { +#endif GtkWidget *close_b=gtk_button_new_with_label("Close"); g_signal_connect (close_b, "pressed", G_CALLBACK(close_cb), NULL); gtk_grid_attach(GTK_GRID(grid),close_b,0,0,1,1); @@ -229,6 +251,9 @@ void noise_menu(GtkWidget *parent) { gtk_widget_show(b_nr2); gtk_grid_attach(GTK_GRID(grid),b_nr2,col,row,1,1); g_signal_connect(b_nr2,"pressed",G_CALLBACK(nr2_cb),NULL); +#ifdef DIGI_MODES + } +#endif gtk_container_add(GTK_CONTAINER(content),grid); diff --git a/noise_menu.h b/noise_menu.h index fed2a2e..bbd684f 100644 --- a/noise_menu.h +++ b/noise_menu.h @@ -18,3 +18,8 @@ */ extern void noise_menu(GtkWidget *parent); + +#ifdef DIGI_MODES +extern void noise_off(); +extern void update_noise(); +#endif diff --git a/old_protocol.c b/old_protocol.c index 99814a0..06105d0 100644 --- a/old_protocol.c +++ b/old_protocol.c @@ -766,8 +766,9 @@ static void process_bandscope_buffer(char *buffer) { */ #ifdef PROTOCOL_DEBUG -// DL1YCF Debug: save last values and log changes +// DL1YCF Debug: save last values and print any changes to stderr static unsigned char last_c1[20], last_c2[20], last_c3[20], last_c4[20], last_mox; +static long long last_tx, last_rx[8]; #endif void ozy_send_buffer() { @@ -965,6 +966,12 @@ void ozy_send_buffer() { output_buffer[C2]=txFrequency>>16; output_buffer[C3]=txFrequency>>8; output_buffer[C4]=txFrequency; +#ifdef PROTOCOL_DEBUG + if (last_tx != txFrequency) { + fprintf(stderr,"TX1 FREQ CHANGE from %lld to %lld\n", last_tx, txFrequency); + last_tx=txFrequency; + } +#endif break; case 2: // rx frequency #ifdef PURESIGNAL @@ -1017,6 +1024,12 @@ void ozy_send_buffer() { output_buffer[C2]=rxFrequency>>16; output_buffer[C3]=rxFrequency>>8; output_buffer[C4]=rxFrequency; +#ifdef PROTOCOL_DEBUG + if (rxFrequency != last_rx[current_rx]) { + fprintf(stderr,"RX%d FREQ CHANGE from %lld to %lld\n", current_rx+1, last_rx[current_rx], rxFrequency); + last_rx[current_rx] = rxFrequency; + } +#endif #ifdef PURESIGNAL } #endif @@ -1245,21 +1258,24 @@ void ozy_send_buffer() { // leave it here deactivated // int ind = output_buffer[C0] >> 1; - if (last_c1[ind] != output_buffer[C1]) { - fprintf(stderr, "C0=%x Old C1=%x New C1=%x\n", 2*ind,last_c1[ind], output_buffer[C1]); - last_c1[ind]=output_buffer[C1]; - } - if (last_c2[ind] != output_buffer[C2]) { - fprintf(stderr, "C0=%x Old C2=%x New C2=%x\n", 2*ind,last_c2[ind], output_buffer[C2]); - last_c2[ind]=output_buffer[C2]; - } - if (last_c3[ind] != output_buffer[C3]) { - fprintf(stderr, "C0=%x Old C3=%x New C3=%x\n", 2*ind,last_c3[ind], output_buffer[C3]); - last_c3[ind]=output_buffer[C3]; - } - if (last_c4[ind] != output_buffer[C4]) { - fprintf(stderr, "C0=%x Old C4=%x New C4=%x\n", 2*ind,last_c4[ind], output_buffer[C4]); - last_c4[ind]=output_buffer[C4]; + if (ind == 0 || ind > 8) { + // Frequency changes are reported above. + if (last_c1[ind] != output_buffer[C1]) { + fprintf(stderr, "C0=%x Old C1=%x New C1=%x\n", 2*ind,last_c1[ind], output_buffer[C1]); + last_c1[ind]=output_buffer[C1]; + } + if (last_c2[ind] != output_buffer[C2]) { + fprintf(stderr, "C0=%x Old C2=%x New C2=%x\n", 2*ind,last_c2[ind], output_buffer[C2]); + last_c2[ind]=output_buffer[C2]; + } + if (last_c3[ind] != output_buffer[C3]) { + fprintf(stderr, "C0=%x Old C3=%x New C3=%x\n", 2*ind,last_c3[ind], output_buffer[C3]); + last_c3[ind]=output_buffer[C3]; + } + if (last_c4[ind] != output_buffer[C4]) { + fprintf(stderr, "C0=%x Old C4=%x New C4=%x\n", 2*ind,last_c4[ind], output_buffer[C4]); + last_c4[ind]=output_buffer[C4]; + } } if ((output_buffer[C0] & 1) != last_mox) { fprintf(stderr, "Last Mox=%d New Mox=%d\n", last_mox, output_buffer[C0] & 1); diff --git a/portaudio.c b/portaudio.c index 55786c3..f67ad64 100644 --- a/portaudio.c +++ b/portaudio.c @@ -25,6 +25,7 @@ #endif #include "radio.h" #include "receiver.h" +#include "mode.h" #include "portaudio.h" #include "math.h" // for sintab, two-tone generator @@ -390,11 +391,17 @@ void audio_close_output(RECEIVER *rx) { int audio_write (RECEIVER *rx, short r, short l) { PaError err; + int mode=transmitter->mode; + // + // We have to stop the stream here if a CW side tone may occur. + // This might cause underflows, but we cannot use audio_write + // and cw_audio_write simultaneously on the same device. + // Instead, the side tone version will take over. + // If *not* doing CW, the stream continues because we might wish + // to listen to this rx while transmitting. + // + if (rx == active_receiver && isTransmitting() && (mode==modeCWU || mode==modeCWL)) return 0; - // this will cause massive underflow errors, since - // we do not provide any data while transmitting. - // Instead, the side tone version will take over - if (rx == active_receiver && isTransmitting()) return 0; if (rx->playback_handle != NULL && rx->playback_buffer != NULL) { rx->playback_buffer[rx->playback_offset++] = (r + l) *0.000015259; // 65536 --> 1.0 if (rx->playback_offset == audio_buffer_size) { diff --git a/ps_menu.c b/ps_menu.c index 46bee20..670fedc 100644 --- a/ps_menu.c +++ b/ps_menu.c @@ -278,6 +278,7 @@ fprintf(stderr,"ps_menu: entry %d is NULL\n", i); usleep(10000); // 10 ms } gtk_entry_set_text(GTK_ENTRY(entry[15]),""); + return NULL; } static void enable_cb(GtkWidget *widget, gpointer data) { diff --git a/radio.c b/radio.c index 090092a..f0114c5 100644 --- a/radio.c +++ b/radio.c @@ -332,7 +332,11 @@ void reconfigure_radio() { } } +#ifdef SPLIT_RXTX + reconfigure_transmitter(transmitter,rx_height/receivers); +#else reconfigure_transmitter(transmitter,rx_height); +#endif } @@ -518,7 +522,11 @@ fprintf(stderr,"title: length=%d\n", (int)strlen(text)); if(display_sliders) { rx_height-=SLIDERS_HEIGHT; } +#ifdef SPLIT_RXTX + int tx_height=rx_height/receivers; +#else int tx_height=rx_height; +#endif rx_height=rx_height/receivers; @@ -552,10 +560,9 @@ fprintf(stderr,"Create %d receivers: height=%d\n",receivers,rx_height); #ifdef PURESIGNAL tx_set_ps_sample_rate(transmitter,protocol==NEW_PROTOCOL?192000:active_receiver->sample_rate); - if(((protocol==ORIGINAL_PROTOCOL) && (device!=DEVICE_METIS)) || ((protocol==NEW_PROTOCOL) && (device!=NEW_DEVICE_ATLAS))) { - receiver[PS_TX_FEEDBACK]=create_pure_signal_receiver(PS_TX_FEEDBACK, buffer_size,protocol==ORIGINAL_PROTOCOL?active_receiver->sample_rate:192000,display_width); - receiver[PS_RX_FEEDBACK]=create_pure_signal_receiver(PS_RX_FEEDBACK, buffer_size,protocol==ORIGINAL_PROTOCOL?active_receiver->sample_rate:192000,display_width); - } + // DL1YCF: we must create these receivers in ANY case to avoid seg-faults. + receiver[PS_TX_FEEDBACK]=create_pure_signal_receiver(PS_TX_FEEDBACK, buffer_size,protocol==ORIGINAL_PROTOCOL?active_receiver->sample_rate:192000,display_width); + receiver[PS_RX_FEEDBACK]=create_pure_signal_receiver(PS_RX_FEEDBACK, buffer_size,protocol==ORIGINAL_PROTOCOL?active_receiver->sample_rate:192000,display_width); #endif #ifdef AUDIO_WATERFALL @@ -719,7 +726,11 @@ static void rxtx(int state) { tx_feedback->samples=0; #endif +#ifdef SPLIT_RXTX + for(i=0;i<1;i++) { +#else for(i=0;iid,0,i==(receivers-1)); set_displaying(receiver[i],0); if(protocol==NEW_PROTOCOL) { @@ -756,7 +767,11 @@ static void rxtx(int state) { // gtk_widget_hide(audio_waterfall); // } //#endif +#ifdef SPLIT_RXTX + for(i=0;i<1;i++) { +#else for(i=0;ipanel,receiver[i]->x,receiver[i]->y); SetChannelState(receiver[i]->id,1,0); set_displaying(receiver[i],1); @@ -832,7 +847,11 @@ void setTune(int state) { //schedule_general(); } if(tune) { - for(i=0;iid,0,i==(receivers-1)); set_displaying(receiver[i],0); if(protocol==NEW_PROTOCOL) { diff --git a/receiver.c b/receiver.c index 15c7f9c..0405f2c 100644 --- a/receiver.c +++ b/receiver.c @@ -1096,17 +1096,29 @@ void receiver_frequency_changed(RECEIVER *rx) { void receiver_filter_changed(RECEIVER *rx) { int m=vfo[rx->id].mode; - if(m==modeFMN) { - if(rx->deviation==2500) { - set_filter(rx,-4000,4000); - } else { - set_filter(rx,-8000,8000); - } - set_deviation(rx); - } else { - FILTER *mode_filters=filters[m]; - FILTER *filter=&mode_filters[vfo[rx->id].filter]; - set_filter(rx,filter->low,filter->high); + switch (m) { + case modeFMN: + if(rx->deviation==2500) { + set_filter(rx,-4000,4000); + } else { + set_filter(rx,-8000,8000); + } + set_deviation(rx); + break; +#ifdef DIGI_MODES + case modeDIGU: + set_filter(rx,0,3000); + break; + case modeDIGL: + set_filter(rx,-3000,0); + break; +#endif + default: + { + FILTER *mode_filters=filters[m]; + FILTER *filter=&mode_filters[vfo[rx->id].filter]; + set_filter(rx,filter->low,filter->high); + } } } @@ -1197,8 +1209,16 @@ static void process_rx_buffer(RECEIVER *rx) { short left_audio_sample; short right_audio_sample; int i; + int mute=0; + // + // DL1YCF: mute the receiver if we are transmitting on its frequency + // + if (isTransmitting()) { + if (!split && (rx->id == active_receiver->id)) mute=1; + if ( split && (rx->id != active_receiver->id)) mute=1; + } for(i=0;ioutput_samples;i++) { - if(isTransmitting()) { + if(mute) { left_audio_sample=0; right_audio_sample=0; } else { diff --git a/sliders.c b/sliders.c index 1f127db..0981550 100644 --- a/sliders.c +++ b/sliders.c @@ -166,7 +166,12 @@ void set_attenuation_value(double value) { scale_status=ATTENUATION; scale_dialog=gtk_dialog_new_with_buttons(title,GTK_WINDOW(top_window),GTK_DIALOG_DESTROY_WITH_PARENT,NULL,NULL); GtkWidget *content=gtk_dialog_get_content_area(GTK_DIALOG(scale_dialog)); - attenuation_scale=gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL,0.0, 31.0, 1.00); + if (filter_board == CHARLY25) { + // although this slider is hidden, its value range does matter + attenuation_scale=gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL,0.0, 36.0, 1.00); + } else { + attenuation_scale=gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL,0.0, 31.0, 1.00); + } gtk_widget_set_size_request (attenuation_scale, 400, 30); gtk_range_set_value (GTK_RANGE(attenuation_scale),(double)adc_attenuation[active_receiver->adc]); gtk_widget_show(attenuation_scale); @@ -575,7 +580,11 @@ fprintf(stderr,"sliders_init: width=%d height=%d\n", width,height); attenuation_scale=gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL,0.0, 60.0, 1.0); gtk_range_set_value (GTK_RANGE(attenuation_scale),rx_gain_slider[active_receiver->adc]); #else - attenuation_scale=gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL,0.0, 31.0, 1.0); + if (filter_board == CHARLY25) { + attenuation_scale=gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL,0.0, 36.0, 1.0); + } else { + attenuation_scale=gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL,0.0, 31.0, 1.0); + } gtk_range_set_value (GTK_RANGE(attenuation_scale),adc_attenuation[active_receiver->adc]); #endif diff --git a/stemlab_discovery.c b/stemlab_discovery.c index 8d0d845..febb98b 100644 --- a/stemlab_discovery.c +++ b/stemlab_discovery.c @@ -17,230 +17,35 @@ * */ -#ifdef __APPLE__ +// DL1YCF: we provide a stripped-down version not relying on AVAHI. +// this is compiled when defining NO_AVAHI -// -// MacOS has no vahi, but it does have libcurl. -// Therefore we try to start the SDR app on the RedPitaya -// assuming is has the (fixed) ip address which can be -// read from $HOME/.rp.inet, if this does not succeed it -// defaults to 192.168.1.3. -// -// So, on MacOS, just configure your STEMLAB/HAMLAB to this -// fixed IP address and you need not open a browser to start -// SDR *before* you can use piHPSDR. -// -// Sure it's not perfect, but it makes life much easier for me. -// #include #include +#include +#include +#include +#include #include #include #include +#include +#include #include - -extern void status_text(const char *); - -static const char *appid = NULL; - -// -// Extract the list of apps from the JSON answer -// -static size_t app_list_callback(void *buffer, size_t size, size_t nmemb, void *data) { - const gchar *needle; - - needle="\"sdr_receiver_hpsdr\""; - if (g_strstr_len(buffer, size*nmemb, needle) != NULL) { - appid="sdr_receiver_hpsdr"; - } - - needle="\"sdr_transceiver_hpsdr\""; - if (g_strstr_len(buffer, size*nmemb, needle) != NULL) { - appid="sdr_transceiver_hpsdr"; - } - - needle="\"stemlab_sdr_transceiver_hpsdr\""; - if (g_strstr_len(buffer, size*nmemb, needle) != NULL) { - appid="stemlab_sdr_transceiver_hpsdr"; - } - - needle="\"hamlab_sdr_transceiver_hpsdr\""; - if (g_strstr_len(buffer, size*nmemb, needle) != NULL) { - appid="hamlab_sdr_transceiver_hpsdr"; - } - - if (appid) fprintf(stderr,"RedPitay WEB application to start: %s\n", appid); - return size * nmemb; -} - -void stemlab_discovery() { - // this one is used "as the last resort", if nothing else is found. - size_t len; - char inet[20]; - char txt[150]; - CURL *curl_handle; - CURLcode curl_error; - FILE *fpin; - char *p; - - fprintf(stderr,"Stripped-down STEMLAB/HAMLAB discovery...\n"); -// -// Try to read inet addr from $HOME/.rp.inet, otherwise take 192.168.1.3 -// - strcpy(inet,"192,168.1.3"); - p=getenv("HOME"); - if (p) { - strncpy(txt,p, (size_t) 100); // way less than size of txt - } else { - strcpy(txt,"."); - } - strcat(txt,"/.rp.inet"); - fprintf(stderr,"Trying to read inet addr from file=%s\n", txt); - fpin=fopen(txt, "r"); - if (fpin) { - len=100; - p=txt; - len=getline(&p, &len, fpin); - // not txt now contains the trailing newline character - while (*p != 0) { - if (*p == '\n') *p = 0; - p++; - } - if (len < 20) strcpy(inet,txt); - } - fclose(fpin); - fprintf(stderr,"STEMLAB: using inet addr %s\n", inet); -// -// Do a HEAD request (poor curl's ping) to see whether the device is on-line -// allow a 15 sec time-out - status_text("Looking for a STEMLAB web server ..."); - curl_handle = curl_easy_init(); - if (curl_handle == NULL) { - fprintf(stderr, "stemlab_start: Failed to create cURL handle\n"); - return; - } - sprintf(txt,"http://%s",inet); - curl_error = curl_easy_setopt(curl_handle, CURLOPT_URL, txt); - curl_error = curl_easy_setopt(curl_handle, CURLOPT_NOBODY, (long) 1); - curl_error = curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, (long) 15); - 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", inet); - status_text(txt); - fprintf(stderr,"%s\n",txt); - } - if (curl_error != CURLE_OK) { - fprintf(stderr, "STEMLAB ping error: %s\n", curl_easy_strerror(curl_error)); - return; - } - -// -//obtain a list of apps, and choose the right one by looking for the following -//target strings (in that order). Whatever is found first, is started. Then, we rely -//on the original discovery() to discover the device. -// -//hamlab_sdr_transceiver_hpsdr -//stemlab_sdr_transceiver_hpsdr -//sdr_transceiver_hpsdr -//sdr_receiver_hpsdr -// - curl_handle = curl_easy_init(); - if (curl_handle == NULL) { - fprintf(stderr, "stemlab_start: Failed to create cURL handle\n"); - return; - } - sprintf(txt,"http://%s/bazaar?apps=", inet); - curl_error = curl_easy_setopt(curl_handle, CURLOPT_URL, txt); - curl_error = curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, (long) 60); - curl_error = curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, app_list_callback); - curl_error = curl_easy_perform(curl_handle); - curl_easy_cleanup(curl_handle); - if (curl_error == CURLE_OPERATION_TIMEDOUT) { - status_text("No Response from RedPitaya in 60 secs"); - fprintf(stderr,"60-sec TimeOut met when trying to get list of HPSDR apps from RedPitaya\n"); - } - if (curl_error != CURLE_OK) { - fprintf(stderr, "STEMLAB app-list error: %s\n", curl_easy_strerror(curl_error)); - return; - } - -// -// Now we actually start the hpsdr application -// Actually, try to stop it first, then re-start it. -// - if (appid) { - curl_handle = curl_easy_init(); - if (curl_handle == NULL) { - fprintf(stderr, "stemlab_start: Failed to create cURL handle\n"); - return; - } - sprintf(txt,"http://%s/bazaar?stop=%s",inet,appid); - curl_error = curl_easy_setopt(curl_handle, CURLOPT_URL, txt); - curl_error = curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, (long) 60); - curl_error = curl_easy_perform(curl_handle); - if (curl_error == CURLE_OPERATION_TIMEDOUT) { - fprintf(stderr,"60-sec TimeOut met when trying to stop HPSDR app on RedPitaya\n"); - } - if (curl_error != CURLE_OK) { - fprintf(stderr, "STEMLAB app-start error: %s\n", curl_easy_strerror(curl_error)); - } - curl_handle = curl_easy_init(); - if (curl_handle == NULL) { - fprintf(stderr, "stemlab_start: Failed to create cURL handle\n"); - return; - } - sprintf(txt,"http://%s/bazaar?start=%s",inet,appid); - curl_error = curl_easy_setopt(curl_handle, CURLOPT_URL, txt); - curl_error = curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, (long) 60); - curl_error = curl_easy_perform(curl_handle); - if (curl_error == CURLE_OPERATION_TIMEDOUT) { - fprintf(stderr,"60-sec TimeOut met when trying to start HPSDR app on RedPitaya\n"); - } - if (curl_error != CURLE_OK) { - fprintf(stderr, "STEMLAB app-start error: %s\n", curl_easy_strerror(curl_error)); - } - - } - // Whether or net we have successfully started the HPSDR application on the RedPitaya, - // we now return to the regular HPSDR protocol handling code that will eventually detect - // the "board". If this code does not work, you have to open a browser and start the HPSDR - // application manually. -} - -// dummy function -void stemlab_cleanup() { -} - -// dummy function, never called -void stemlab_start_app() { -} - -#else - #include #include -#include -#include -#include -#include #include -#include #include -#include -#include -#include - -#include - -#include - #include "discovered.h" #include "radio.h" -#define ERROR_PREFIX "stemlab_discovery: " +#ifndef NO_AVAHI +#include +#include +#include +#endif // 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. @@ -248,35 +53,16 @@ static bool discovery_done = FALSE; static int pending_callbacks = 0; static struct ifaddrs *ifaddrs = NULL; static bool curl_initialised = FALSE; +extern void status_text(const char *); -static size_t app_list_cb(void *buffer, size_t size, size_t nmemb, void *data) { - // cURL does *not* make any guarantees for this data to be the complete - // However, as the STEMlab answers in one big chunk, we just hope for the - // answer to be the complete json object, and avoid the hassle of manually - // building up our buffer. - int *software_version = (int*) data; - // This is not 100% clean, but avoids requiring in a json library dependency - const gchar *pavel_rx_json = "\"sdr_receiver_hpsdr\":"; - if (g_strstr_len(buffer, size*nmemb, pavel_rx_json) != NULL) { - *software_version |= STEMLAB_PAVEL_RX; - } - const gchar *pavel_trx_json = "\"sdr_transceiver_hpsdr\":"; - if (g_strstr_len(buffer, size*nmemb, pavel_trx_json) != NULL) { - *software_version |= STEMLAB_PAVEL_TRX; - } - const gchar *rp_trx_json = "\"stemlab_sdr_transceiver_hpsdr\":"; - if (g_strstr_len(buffer, size*nmemb, rp_trx_json) != NULL) { - *software_version |= STEMLAB_RP_TRX; - } - const gchar *hamlab_trx_json = "\"hamlab_sdr_transceiver_hpsdr\":"; - if (g_strstr_len(buffer, size*nmemb, hamlab_trx_json) != NULL) { - *software_version |= HAMLAB_RP_TRX; - } - // Returning the total amount of bytes "processed" to signal cURL that we - // are done without any errors - return size * nmemb; -} +#define ERROR_PREFIX "stemlab_discovery: " +// +// A bunch of callback-routines that use avahi, and are only needed by the +// avahi-dependent version of stemlab_discovery(). These are only compiled +// in the avahi case. +// +#ifndef NO_AVAHI static void resolver_found_cb(GaServiceResolver *resolver, AvahiIfIndex if_index, GaProtocol protocol, gchar *name, gchar *service, gchar *domain, gchar *hostname, AvahiAddress *address, gint port, AvahiStringList *txt, @@ -434,7 +220,91 @@ static void cache_exhausted_cb(GaServiceBrowser *browser, gpointer data) { } discovery_done = TRUE; } +#endif +// +// Some callback routines and functions that do not depend on avahi +// and are compiled in either case. +// +static size_t app_list_cb(void *buffer, size_t size, size_t nmemb, void *data) { + // cURL does *not* make any guarantees for this data to be the complete + // However, as the STEMlab answers in one big chunk, we just hope for the + // answer to be the complete json object, and avoid the hassle of manually + // building up our buffer. + int *software_version = (int*) data; + // This is not 100% clean, but avoids requiring in a json library dependency + const gchar *pavel_rx_json = "\"sdr_receiver_hpsdr\":"; + if (g_strstr_len(buffer, size*nmemb, pavel_rx_json) != NULL) { + *software_version |= STEMLAB_PAVEL_RX; + } + const gchar *pavel_trx_json = "\"sdr_transceiver_hpsdr\":"; + if (g_strstr_len(buffer, size*nmemb, pavel_trx_json) != NULL) { + *software_version |= STEMLAB_PAVEL_TRX; + } + const gchar *rp_trx_json = "\"stemlab_sdr_transceiver_hpsdr\":"; + if (g_strstr_len(buffer, size*nmemb, rp_trx_json) != NULL) { + *software_version |= STEMLAB_RP_TRX; + } + const gchar *hamlab_trx_json = "\"hamlab_sdr_transceiver_hpsdr\":"; + if (g_strstr_len(buffer, size*nmemb, hamlab_trx_json) != NULL) { + *software_version |= HAMLAB_RP_TRX; + } + // Returning the total amount of bytes "processed" to signal cURL that we + // are done without any errors + return size * nmemb; +} + +// This is essentially a no-op curl callback +static size_t app_start_callback(void *buffer, size_t size, size_t nmemb, void *data) { + if (strncmp(buffer, "{\"status\":\"OK\"}", size*nmemb) != 0) { + fprintf(stderr, "stemlab_start: Receiver error from STEMlab\n"); + return 0; + } + return size * nmemb; +} + +void stemlab_start_app(const char * const app_id) { + // Dummy string, using the longest possible app id + char app_start_url[] = "http://123.123.123.123/bazaar?start=stemlab_sdr_transceiver_hpsdr"; + sprintf(app_start_url, "http://%s/bazaar?start=%s", + inet_ntoa(radio->info.network.address.sin_addr), + app_id); + CURL *curl_handle = curl_easy_init(); + if (curl_handle == NULL) { + fprintf(stderr, "stemlab_start: Failed to create cURL handle\n"); + exit(-1); + } + CURLcode curl_error = CURLE_OK; +#define check_curl(description) do { \ + if (curl_error != CURLE_OK) { \ + fprintf(stderr, "stemlab_start: " description ": %s\n", \ + curl_easy_strerror(curl_error)); \ + exit(-1); \ + } \ +} while (0); + curl_error = curl_easy_setopt(curl_handle, CURLOPT_URL, app_start_url); + check_curl("Failed setting cURL URL"); + curl_error = curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, app_start_callback); + check_curl("Failed install cURL callback"); + curl_error = curl_easy_perform(curl_handle); + check_curl("Failed to start app"); +#undef check_curl + curl_easy_cleanup(curl_handle); + // Since the SDR application is now running, we can hand it over to the + // regular HPSDR protocol handling code + radio->protocol = ORIGINAL_PROTOCOL; +} + +void stemlab_cleanup(void) { + if (curl_initialised) { + curl_global_cleanup(); + } +} + +#ifndef NO_AVAHI +// +// This is the avahi-dependent version of stemlab_discovery() +// void stemlab_discovery(void) { discovery_done = FALSE; GaClient * const avahi_client = ga_client_new(GA_CLIENT_FLAG_NO_FLAGS); @@ -483,51 +353,146 @@ void stemlab_discovery(void) { g_main_context_iteration(NULL, TRUE); } } +#else +// +// This version of stemlab_discovery() needs libcurl +// but does not need avahi. +// +// Therefore we try to find the SDR apps on the RedPitaya +// assuming is has the (fixed) ip address which can be +// read from $HOME/.rp.inet, if this does not succeed it +// defaults to 192.168.1.3. +// +// So, on MacOS, just configure your STEMLAB/HAMLAB to this +// fixed IP address and you need not open a browser to start +// SDR *before* you can use piHPSDR. +// +// After starting the app in the main discover menu, we +// have to re-discover to get full info and start the radio. +// -// This is essentially a no-op curl callback -static size_t app_start_callback(void *buffer, size_t size, size_t nmemb, void *data) { - if (strncmp(buffer, "{\"status\":\"OK\"}", size*nmemb) != 0) { - fprintf(stderr, "stemlab_start: Receiver error from STEMlab\n"); - return 0; - } - return size * nmemb; -} -void stemlab_start_app(const char * const app_id) { - // Dummy string, using the longest possible app id - char app_start_url[] = "http://123.123.123.123/bazaar?start=stemlab_sdr_transceiver_hpsdr"; - sprintf(app_start_url, "http://%s/bazaar?start=%s", - inet_ntoa(radio->info.network.address.sin_addr), - app_id); - CURL *curl_handle = curl_easy_init(); +void stemlab_discovery() { + size_t len; + char inet[20]; + char txt[150]; + CURL *curl_handle; + CURLcode curl_error; + FILE *fpin; + char *p; + int i; + int app_list; + struct sockaddr_in ip_address; + struct sockaddr_in netmask; + + fprintf(stderr,"Stripped-down STEMLAB/HAMLAB discovery...\n"); +// +// Try to read inet addr from $HOME/.rp.inet, otherwise take 192.168.1.3 +// + strcpy(inet,"192.168.1.3"); + p=getenv("HOME"); + if (p) { + strncpy(txt,p, (size_t) 100); // way less than size of txt + } else { + strcpy(txt,"."); + } + strcat(txt,"/.rp.inet"); + fprintf(stderr,"Trying to read inet addr from file=%s\n", txt); + fpin=fopen(txt, "r"); + if (fpin) { + len=100; + p=txt; + len=getline(&p, &len, fpin); + // not txt now contains the trailing newline character + while (*p != 0) { + if (*p == '\n') *p = 0; + p++; + } + if (len < 20) strcpy(inet,txt); + } + fclose(fpin); + fprintf(stderr,"STEMLAB: using inet addr %s\n", inet); + ip_address.sin_family = AF_INET; + inet_aton(inet, &ip_address.sin_addr); + + netmask.sin_family = AF_INET; + inet_aton("0.0.0.0", &netmask.sin_addr); + + +// +// Do a HEAD request (poor curl's ping) to see whether the device is on-line +// allow a 15 sec time-out +// + curl_handle = curl_easy_init(); if (curl_handle == NULL) { fprintf(stderr, "stemlab_start: Failed to create cURL handle\n"); - exit(-1); + return; } - CURLcode curl_error = CURLE_OK; -#define check_curl(description) do { \ - if (curl_error != CURLE_OK) { \ - fprintf(stderr, "stemlab_start: " description ": %s\n", \ - curl_easy_strerror(curl_error)); \ - exit(-1); \ - } \ -} while (0); - curl_error = curl_easy_setopt(curl_handle, CURLOPT_URL, app_start_url); - check_curl("Failed setting cURL URL"); - curl_error = curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, app_start_callback); - check_curl("Failed install cURL callback"); + sprintf(txt,"http://%s",inet); + curl_error = curl_easy_setopt(curl_handle, CURLOPT_URL, txt); + curl_error = curl_easy_setopt(curl_handle, CURLOPT_NOBODY, (long) 1); + curl_error = curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, (long) 15); curl_error = curl_easy_perform(curl_handle); - check_curl("Failed to start app"); -#undef check_curl curl_easy_cleanup(curl_handle); - // Since the SDR application is now running, we can hand it over to the - // regular HPSDR protocol handling code - radio->protocol = ORIGINAL_PROTOCOL; -} - -void stemlab_cleanup(void) { - if (curl_initialised) { - curl_global_cleanup(); + if (curl_error == CURLE_OPERATION_TIMEDOUT) { + sprintf(txt,"No response from web server at %s", inet); + status_text(txt); + fprintf(stderr,"%s\n",txt); + } + if (curl_error != CURLE_OK) { + fprintf(stderr, "STEMLAB ping error: %s\n", curl_easy_strerror(curl_error)); + return; + } + +// +// Determine which SDR apps are present on the RedPitaya. The list may be empty. +// + curl_handle = curl_easy_init(); + if (curl_handle == NULL) { + fprintf(stderr, "stemlab_start: Failed to create cURL handle\n"); + return; + } + app_list=0; + sprintf(txt,"http://%s/bazaar?apps=", inet); + curl_error = curl_easy_setopt(curl_handle, CURLOPT_URL, txt); + curl_error = curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, (long) 60); + curl_error = curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, app_list_cb); + curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, &app_list); + curl_error = curl_easy_perform(curl_handle); + curl_easy_cleanup(curl_handle); + if (curl_error == CURLE_OPERATION_TIMEDOUT) { + status_text("No Response from RedPitaya in 60 secs"); + fprintf(stderr,"60-sec TimeOut met when trying to get list of HPSDR apps from RedPitaya\n"); } + if (curl_error != CURLE_OK) { + fprintf(stderr, "STEMLAB app-list error: %s\n", curl_easy_strerror(curl_error)); + return; + } + +// +// Constructe "device" descripter. Hi-Jack the software version to +// encode which apps are present. +// What is needed in the interface data is only info.network.address.sin_addr, +// but the address and netmask of the interface must be compatible with this +// address to avoid an error condition upstream. That means +// (addr & mask) == (interface_addr & mask) must be fulfilled. This is easily +// achieved by setting interface_addr = addr and mask = 0. +// + DISCOVERED *device = &discovered[devices++]; + device->protocol = STEMLAB_PROTOCOL; + device->device = DEVICE_METIS; // not used + strcpy(device->name, "STEMlab"); + device->software_version = app_list; // encodes list of SDR apps present + device->status = STATE_AVAILABLE; + memset(device->info.network.mac_address, 0, 6); // not used + device->info.network.address_length = sizeof(struct sockaddr_in); + device->info.network.address.sin_family = AF_INET; + device->info.network.address.sin_addr = ip_address.sin_addr; + device->info.network.address.sin_port = htons(1024); + device->info.network.interface_length = sizeof(struct sockaddr_in); + device->info.network.interface_address = ip_address; // same as RP address + device->info.network.interface_netmask= netmask; // does not matter + strcpy(device->info.network.interface_name, ""); } + #endif diff --git a/transmitter.c b/transmitter.c index baf1453..ba534f5 100644 --- a/transmitter.c +++ b/transmitter.c @@ -422,7 +422,14 @@ static gboolean update_display(gpointer data) { } } +#ifdef SPLIT_RXTX + // If the second RX is active, we rather want to see its S-meter instead of TX data + if (active_receiver == receiver[0]) { + meter_update(active_receiver,POWER,transmitter->fwd,transmitter->rev,transmitter->exciter,transmitter->alc); + } +#else meter_update(active_receiver,POWER,transmitter->fwd,transmitter->rev,transmitter->exciter,transmitter->alc); +#endif return TRUE; // keep going } @@ -541,14 +548,15 @@ fprintf(stderr,"create_transmitter: id=%d buffer_size=%d mic_sample_rate=%d mic_ tx->low_latency=0; + tx->twotone=0; #ifdef PURESIGNAL tx->puresignal=0; tx->feedback=0; - tx->twotone=0; tx->auto_on=0; tx->single_on=0; #endif + tx->attenuation=0; tx->ctcss=0; tx->ctcss_frequency=100.0; @@ -1040,9 +1048,17 @@ void tx_set_ps(TRANSMITTER *tx,int state) { vfo_update(); } +void tx_set_ps_sample_rate(TRANSMITTER *tx,int rate) { + SetPSFeedbackRate (tx->id,rate); +} +#endif + void tx_set_twotone(TRANSMITTER *tx,int state) { transmitter->twotone=state; if(state) { + // DL1YCF: set frequencies and levels + SetTXAPostGenTTFreq(transmitter->id, 900.0, 1700.0); + SetTXAPostGenTTMag (transmitter->id, 0.49, 0.49); SetTXAPostGenMode(transmitter->id, 1); SetTXAPostGenRun(transmitter->id, 1); } else { @@ -1051,10 +1067,6 @@ void tx_set_twotone(TRANSMITTER *tx,int state) { g_idle_add(ext_mox_update,(gpointer)(long)state); } -void tx_set_ps_sample_rate(TRANSMITTER *tx,int rate) { - SetPSFeedbackRate (tx->id,rate); -} -#endif // // This is the old key-down/key-up interface for iambic.c diff --git a/transmitter.h b/transmitter.h index 3b0fb61..4120eaa 100644 --- a/transmitter.h +++ b/transmitter.h @@ -75,9 +75,10 @@ typedef struct _transmitter { int low_latency; +// want to have a two-tone generator in any case + int twotone; #ifdef PURESIGNAL int puresignal; - int twotone; int feedback; int auto_on; int single_on; diff --git a/tx_panadapter.c b/tx_panadapter.c index 43f6e5c..e18d882 100644 --- a/tx_panadapter.c +++ b/tx_panadapter.c @@ -49,6 +49,12 @@ static gfloat hz_per_pixel; static gfloat filter_left; static gfloat filter_right; +#ifdef SPLIT_RXTX +#include "new_menu.h" +#include "ext.h" +#include "sliders.h" +static gboolean making_active = FALSE; +#endif /* Create a new surface of the appropriate size to store our scribbles */ static gboolean @@ -103,6 +109,9 @@ tx_panadapter_button_press_event_cb (GtkWidget *widget, has_moved=FALSE; pressed=TRUE; } +#ifdef SPLIT_RXTX + making_active=(active_receiver != receiver[0]); +#endif return TRUE; } @@ -115,6 +124,15 @@ tx_panadapter_button_release_event_cb (GtkWidget *widget, int display_width=gtk_widget_get_allocated_width (tx->panadapter); int display_height=gtk_widget_get_allocated_height (tx->panadapter); +#ifdef SPLIT_RXTX + if (making_active) { + active_receiver=receiver[0]; + making_active=FALSE; + g_idle_add(menu_active_receiver_changed,NULL); + g_idle_add(ext_vfo_update,NULL); + g_idle_add(sliders_active_receiver_changed,NULL); + } +#endif if(pressed) { int x=(int)event->x; if (event->button == 1) { @@ -139,6 +157,9 @@ tx_panadapter_motion_notify_event_cb (GtkWidget *widget, { int x, y; GdkModifierType state; +#ifdef SPLIT_RXTX + if (!making_active) { +#endif gdk_window_get_device_position (event->window, event->device, &x, @@ -151,6 +172,9 @@ tx_panadapter_motion_notify_event_cb (GtkWidget *widget, last_x=x; has_moved=TRUE; } +#ifdef SPLIT_RXTX + } +#endif return TRUE; } @@ -186,9 +210,16 @@ void tx_panadapter_update(TRANSMITTER *tx) { int display_height=gtk_widget_get_allocated_height (tx->panadapter); int id=0; +#ifdef SPLIT_RXTX + id = active_receiver->id; + if (split) { + id = 1-id; + } +#else if(split) { id=1; } +#endif samples=tx->pixel_samples; //hz_per_pixel=(double)tx->output_rate/(double)display_width; diff --git a/vfo.c b/vfo.c index a279a3a..f25dbab 100644 --- a/vfo.c +++ b/vfo.c @@ -556,6 +556,7 @@ void vfo_update() { int id=active_receiver->id; FILTER* band_filters=filters[vfo[id].mode]; FILTER* band_filter=&band_filters[vfo[id].filter]; + int have_noise=1; if(vfo_surface) { char temp_text[32]; cairo_t *cr; @@ -596,28 +597,45 @@ void vfo_update() { case modeAM: sprintf(temp_text,"%s %s %s",mode_string[vfo[id].mode],band_filter->title,dv); break; +#ifdef DIGI_MODES + case modeDIGU: + case modeDIGL: + // No band filter title + sprintf(temp_text,"%s %s",mode_string[vfo[id].mode],dv); + // used later on NOT to display noise reduction + have_noise=0; + break; +#endif default: sprintf(temp_text,"%s %s",mode_string[vfo[id].mode],band_filter->title); break; } cairo_show_text(cr, temp_text); + // DL1YCF: in what follows, we want to display the VFO frequency + // on which we currently transmit a signal with red colour. + // If it is out-of-band, we display "Out of band" in red. + // Frequencies we are not transmitting on are displayed in green + // (dimmed if the freq. does not belong to the active receiver). + // Depending on which receiver is the active one, and if we use slit, + // the following frequencies are used for transmitting (see old_protocol.c): + // id == 0, split == 0 : TX freq = VFO_A + // id == 0, split == 1 : TX freq = VFO_B + // id == 1, split == 0 : TX freq = VFO_B + // id == 1, split == 1 : TX freq = VFO_A + long long af=vfo[0].frequency+vfo[0].offset; - if(transmitter->out_of_band && !split) { - cairo_set_source_rgb(cr, 1.0, 0.0, 0.0); - sprintf(temp_text,"VFO A: Out of band"); + sprintf(temp_text,"VFO A: %0lld.%06lld",af/(long long)1000000,af%(long long)1000000); + if(isTransmitting() && ((id == 0 && !split) || (id == 1 && split))) { + if (transmitter->out_of_band) sprintf(temp_text,"VFO A: Out of band"); + cairo_set_source_rgb(cr, 1.0, 0.0, 0.0); } else { - sprintf(temp_text,"VFO A: %0lld.%06lld",af/(long long)1000000,af%(long long)1000000); - if(isTransmitting() && !split) { - cairo_set_source_rgb(cr, 1.0, 0.0, 0.0); - } else { - if(active_receiver->id==0) { - cairo_set_source_rgb(cr, 0.0, 1.0, 0.0); - } else { - cairo_set_source_rgb(cr, 0.0, 0.65, 0.0); - } - } + if(id==0) { + cairo_set_source_rgb(cr, 0.0, 1.0, 0.0); + } else { + cairo_set_source_rgb(cr, 0.0, 0.65, 0.0); + } } cairo_move_to(cr, 5, 38); cairo_set_font_size(cr, 22); @@ -625,20 +643,16 @@ void vfo_update() { long long bf=vfo[1].frequency+vfo[1].offset; - if(transmitter->out_of_band && split) { - cairo_set_source_rgb(cr, 1.0, 0.0, 0.0); - sprintf(temp_text,"VFO B: Out of band"); + sprintf(temp_text,"VFO B: %0lld.%06lld",bf/(long long)1000000,bf%(long long)1000000); + if(isTransmitting() && ((id == 0 && split) || (id == 1 && !split))) { + if (transmitter->out_of_band) sprintf(temp_text,"VFO B: Out of band"); + cairo_set_source_rgb(cr, 1.0, 0.0, 0.0); } else { - sprintf(temp_text,"VFO B: %0lld.%06lld",bf/(long long)1000000,bf%(long long)1000000); - if(isTransmitting() && split) { - cairo_set_source_rgb(cr, 1.0, 0.0, 0.0); - } else { - if(active_receiver->id==1) { - cairo_set_source_rgb(cr, 0.0, 1.0, 0.0); - } else { - cairo_set_source_rgb(cr, 0.0, 0.65, 0.0); - } - } + if(id==1) { + cairo_set_source_rgb(cr, 0.0, 1.0, 0.0); + } else { + cairo_set_source_rgb(cr, 0.0, 0.65, 0.0); + } } cairo_move_to(cr, 260, 38); cairo_show_text(cr, temp_text); @@ -662,7 +676,7 @@ void vfo_update() { cairo_show_text(cr, "NB"); cairo_move_to(cr, 175, 50); - if(active_receiver->nb2) { + if(active_receiver->nb2 && have_noise) { cairo_set_source_rgb(cr, 1.0, 1.0, 0.0); } else { cairo_set_source_rgb(cr, 0.7, 0.7, 0.7); @@ -670,7 +684,7 @@ void vfo_update() { cairo_show_text(cr, "NB2"); cairo_move_to(cr, 200, 50); - if(active_receiver->nr) { + if(active_receiver->nr && have_noise) { cairo_set_source_rgb(cr, 1.0, 1.0, 0.0); } else { cairo_set_source_rgb(cr, 0.7, 0.7, 0.7); @@ -678,7 +692,7 @@ void vfo_update() { cairo_show_text(cr, "NR"); cairo_move_to(cr, 225, 50); - if(active_receiver->nr2) { + if(active_receiver->nr2 && have_noise) { cairo_set_source_rgb(cr, 1.0, 1.0, 0.0); } else { cairo_set_source_rgb(cr, 0.7, 0.7, 0.7); @@ -686,7 +700,7 @@ void vfo_update() { cairo_show_text(cr, "NR2"); cairo_move_to(cr, 250, 50); - if(active_receiver->anf) { + if(active_receiver->anf && have_noise) { cairo_set_source_rgb(cr, 1.0, 1.0, 0.0); } else { cairo_set_source_rgb(cr, 0.7, 0.7, 0.7); @@ -694,7 +708,7 @@ void vfo_update() { cairo_show_text(cr, "ANF"); cairo_move_to(cr, 275, 50); - if(active_receiver->snb) { + if(active_receiver->snb && have_noise) { cairo_set_source_rgb(cr, 1.0, 1.0, 0.0); } else { cairo_set_source_rgb(cr, 0.7, 0.7, 0.7); diff --git a/vfo_menu.c b/vfo_menu.c index e47936d..0b50e6e 100644 --- a/vfo_menu.c +++ b/vfo_menu.c @@ -193,7 +193,7 @@ static void enable_freedv_cb(GtkWidget *widget, gpointer data) { } #endif -#ifdef FREEDV +#ifdef PURESIGNAL static void enable_ps_cb(GtkWidget *widget, gpointer data) { tx_set_ps(transmitter,gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))); }