]> git.rkrishnan.org Git - pihpsdr.git/commitdiff
Changes that affect the user interface
authorc vw <dl1ycf@darc.de>
Tue, 24 Jul 2018 08:00:12 +0000 (10:00 +0200)
committerc vw <dl1ycf@darc.de>
Tue, 24 Jul 2018 08:00:12 +0000 (10:00 +0200)
======================================

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)

21 files changed:
Makefile.mac
audio.c
discovery.c
filter_menu.c
mode_menu.c
new_menu.c
new_protocol.c
noise_menu.c
noise_menu.h
old_protocol.c
portaudio.c
ps_menu.c
radio.c
receiver.c
sliders.c
stemlab_discovery.c
transmitter.c
transmitter.h
tx_panadapter.c
vfo.c
vfo_menu.c

index 514ab0355a55035d6cf3960050836f932ddf4e4f..b551b64d3af0c0bd5cd14baf99176de6d93e5569 100644 (file)
@@ -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 277a06aad84b6a925d1564b27430b81fdaf2ce6d..8d9ccf6bae7a1022d99569c3723fe0427fbf6d00 100644 (file)
--- 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;
index f34ea51852bbfa034c9c93f644f79c1b571847b1..c59a6a2ad2fb8d340b9612bc53e28785c93e5635 100644 (file)
@@ -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);
         }
index 092d89060dc0894700da6fa8d35e37494f7e0fb3..cacf9204a98bb1e9989092ed3004026c54658e91 100644 (file)
@@ -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;i<FILTERS-2;i++) {
         FILTER* band_filter=&band_filters[i];
index d40eee339e77c884fb4ef1f8e6bea89331946ec4..006b5d8c63431749f25e6e8e8e1286e42d7a88e1 100644 (file)
@@ -33,6 +33,9 @@
 #include "receiver.h"
 #include "vfo.h"
 #include "button_text.h"
+#ifdef DIGI_MODES
+#include "noise_menu.h"                // for noise-on/off in DIGU/L
+#endif
 
 static GtkWidget *parent_window=NULL;
 
@@ -63,10 +66,17 @@ static gboolean mode_select_cb (GtkWidget *widget, gpointer        data) {
   set_button_text_color(last_mode,"black");
   last_mode=widget;
   set_button_text_color(last_mode,"orange");
+#ifdef DIGI_MODES
+  switch (m) {
+    case modeDIGL:
+    case modeDIGU:
+      noise_off();        // diable noise reduction machine completely for DIGI modes
+      break;
+    default:
+      update_noise();     // set noise reduction to the values stored in the current RECEIVER
+  }
+#endif
   vfo_mode_changed(m);
-  // DL1YCF added return statement to make the compiler happy.
-  // however I am unsure about the correct return value.
-  // I would have coded this as a void function.
   return FALSE;
 }
 
index 7365ae3d652e806c49488d3f524e1f5b29c942e5..dd5fed085333fc38d4cc30e9a9875f60986a509e 100644 (file)
@@ -60,6 +60,7 @@
 #include "vfo_menu.h"
 #include "fft_menu.h"
 #include "main.h"
+#include "button_text.h"
 
 
 static GtkWidget *menu_b=NULL;
@@ -371,6 +372,19 @@ static gboolean ps_cb (GtkWidget *widget, GdkEventButton *event, gpointer data)
   start_ps();
   return TRUE;
 }
+#else
+static gboolean tt_cb (GtkWidget *widget, GdkEventButton *event, gpointer data) {
+  // even without PURESIGNAL, a two-tone generator is nice-to-have
+  // so whe "PS" button now is a "TT" (two-tone) button.
+  int state=transmitter->twotone?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");
index 93d84a9ade31729e58937d59353ed185fbdf5524..a30d2eacd64ba2e6e8782924c013ee116df3e8d0 100644 (file)
@@ -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);
index d26f0d227dcd1f2165e650e38f686f48e75dcda1..a3773321512680613fd134014e7bd0ddb1c4d64b 100644 (file)
@@ -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);
 
index fed2a2e6f05177d51473514bbe6776a0857525ab..bbd684f79b1de63cbfa686df1bac135ea8adc17d 100644 (file)
@@ -18,3 +18,8 @@
 */
 
 extern void noise_menu(GtkWidget *parent);
+
+#ifdef DIGI_MODES
+extern void noise_off();
+extern void update_noise();
+#endif
index 99814a0108de95479b221f6b8a022a21fc10c1df..06105d0ef53683be92ef1c949501eeb33d662538 100644 (file)
@@ -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);
index 55786c38f513bf9cc3335d65096761894a209ff5..f67ad64a30ffaa9c1f09c088679468db6881911d 100644 (file)
@@ -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) {
index 46bee201672f07dd9d4ceae222cd2e2344dc0320..670fedc012477a68e49442e8ccadce40f4c32135 100644 (file)
--- 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 090092a34edd89600e817b9204fecac09dceb329..f0114c5384cb7d02b93aca2e069e09272031da09 100644 (file)
--- 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;i<receivers;i++) {
+#endif
       SetChannelState(receiver[i]->id,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;i<receivers;i++) {
+#endif
       gtk_fixed_put(GTK_FIXED(fixed),receiver[i]->panel,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;i<receivers;i++) {
+#ifdef SPLIT_RXTX
+        for(i=0;i<1;i++) {
+#else
+        for(i=0;i<receivers;i++) {
+#endif
         SetChannelState(receiver[i]->id,0,i==(receivers-1));
         set_displaying(receiver[i],0);
         if(protocol==NEW_PROTOCOL) {
index 15c7f9c2bc25ed43ddd87f8243b7c340b967b1a5..0405f2c0837a259ab325be927966d9a9ce97ab9e 100644 (file)
@@ -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;i<rx->output_samples;i++) {
-    if(isTransmitting()) {
+    if(mute) {
       left_audio_sample=0;
       right_audio_sample=0;
     } else {
index 1f127dbbeb71d79d75f150f57ec27afb969214ec..0981550eaf553fb63c815f611adbe14e614492d1 100644 (file)
--- 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
   
index 8d0d8456756926295a2838f80309e1576f3d8dae..febb98ba331b4bfe8858e47261f8baf52e1b9107 100644 (file)
 *
 */
 
-#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 <stdio.h>
 #include <stdlib.h>
+#include <stdbool.h>
+#include <ifaddrs.h>
+#include <net/if.h>
+#include <arpa/inet.h>
 #include <string.h>
 #include <unistd.h>
 #include <curl/curl.h>
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
 #include <glib.h>
-
-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 <errno.h>
 #include <ifaddrs.h>
-#include <net/if.h>
-#include <arpa/inet.h>
-#include <stdbool.h>
-#include <stddef.h>
 #include <stdint.h>
-#include <stdio.h>
 #include <string.h>
 
-#include <avahi-gobject/ga-client.h>
-#include <avahi-gobject/ga-service-browser.h>
-#include <avahi-gobject/ga-service-resolver.h>
-
-#include <curl/curl.h>
-
-#include <glib.h>
-
 #include "discovered.h"
 #include "radio.h"
 
-#define ERROR_PREFIX "stemlab_discovery: "
+#ifndef NO_AVAHI
+#include <avahi-gobject/ga-client.h>
+#include <avahi-gobject/ga-service-browser.h>
+#include <avahi-gobject/ga-service-resolver.h>
+#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
index baf145321edf5e56236c4ba8749e2d3518d909f4..ba534f55fb87ac29d0137806d1ded857d030b1b4 100644 (file)
@@ -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
index 3b0fb613deccfeb1cc90afcc69541c1f40dca84d..4120eaa5325094a0182ddae223be58fc1509e82c 100644 (file)
@@ -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;
index 43f6e5cc4ad865a1376905885760eeae21ed530c..e18d882b4fd1cf394178c41142fa09ff8f375b24 100644 (file)
@@ -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 a279a3a4ef5be8f6f622d3cb87cb6742806b7086..f25dbab8783c41214d6e0665f8941e652b1ae08f 100644 (file)
--- 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);
index e47936d27128dc4427d728591b8b83ef5b288a2d..0b50e6e7e5301983b58ea50f1368850bb1b14a26 100644 (file)
@@ -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)));
 }