]> git.rkrishnan.org Git - pihpsdr.git/commitdiff
Intermediat commit to make it visible to someone asking for this
authorc vw <dl1ycf@darc.de>
Wed, 15 May 2019 08:26:24 +0000 (10:26 +0200)
committerc vw <dl1ycf@darc.de>
Wed, 15 May 2019 08:26:24 +0000 (10:26 +0200)
12 files changed:
discovered.h
mac_midi.c
midi2.c
midi3.c
old_discovery.c
old_protocol.c
ps_menu.c
radio.c
receiver.c
receiver.h
rx_menu.c
sliders.c

index 7e66b5b14ecb03edf5aa33e3017a42cdb37bbb60..7c14ec0ad0c884a56461ca04920e5bd5888c22be 100644 (file)
@@ -34,7 +34,7 @@
 #define DEVICE_ANGELIA 4
 #define DEVICE_ORION 5
 #define DEVICE_HERMES_LITE 6
-// 8000DLE uses 10 as the device type in old protocol
+// ANAN 7000DLE and 8000DLE uses 10 as the device type in old protocol
 #define DEVICE_ORION2 10 
 // Newer STEMlab hpsdr emulators use 100 instead of 1
 #define DEVICE_STEMLAB 100
index ad9885b872dfbd6be7882d4bb2c611fa570b520b..06c84ca106de0bcf59cb56a935baf00ef7fad7f0 100644 (file)
@@ -5,13 +5,21 @@
  * This is the "Layer-1" for Apple Macintosh.
  *
  * This file implements the function register_midi_device,
- * which is called with the name of a supported MIDI device and
- * the number of characters in the name that must be equal to
- * the name of the MIDI device as known in the operating system.
+ * which is called with the name of a supported MIDI device.
+ * This name may be truncated:  For example, the call
+ * register_midi_device("COMPANY MIDI")
+ * will accept both "COMPANY MIDI X" and "COMPANY MIDI Y" devices.
  *
- * For example, the call
- * register_midi_device("COMPANY MIDI X",13)
- * will also use a MIDI device named "COMPANY MIDI Y".
+ * If more than one MIDI device matches the name, the LAST ONE
+ * found will be taken. This may not be predictable, so it is
+ * better to say that one of the matching MIDI devices will be taken.
+ * It is easy to change the code such that ALL devices matching the
+ * name will be taken. But who cares? Normally there will only be a
+ * single MIDI controller connected to the computer running the SDR
+ * program.
+ *
+ * The name is actually specified by the user in the midi.inp file
+ * (see midi2.c)
  *
  * This file must generate calls to Layer-2 NewMidiEvent().
  * Some type of messages are not consideres (pressure change, etc.),
 
 #ifdef __APPLE__
 
+/*
+ * For MacOS, things are easy:
+ * The OS takes care of everything, we only have to register a callback
+ * routine.
+ */
+
 #include <Carbon/Carbon.h>
 
 #include <CoreMIDI/MIDIServices.h>
@@ -31,6 +45,9 @@
 
 //
 // MIDI callback function
+// called by MacOSX when data from the specified MIDI device arrives.
+// We process *all* data but only generate calls to layer-2 for Note On/Off
+// and ControllerChange events.
 //
 static void ReadMIDIdevice(const MIDIPacketList *pktlist, void *refCon, void *connRefCon) {
     int i,j,k,command,chan;
@@ -49,12 +66,12 @@ static void ReadMIDIdevice(const MIDIPacketList *pktlist, void *refCon, void *co
                 switch (command & 0xF0) {
                   case 0x80:  // Note off
                        NewMidiEvent(MIDI_NOTE, chan, packet->data[i+1], 0);
-                       fprintf(stderr,"NOTE OFF: Note=%d Chan=%d Vel=%d\n", packet->data[i+1], chan, packet->data[i+2]);
+                       //fprintf(stderr,"NOTE OFF: Note=%d Chan=%d Vel=%d\n", packet->data[i+1], chan, packet->data[i+2]);
                        i +=3;
                        break;
                   case 0x90:  // Note on
                        NewMidiEvent(MIDI_NOTE, chan, packet->data[i+1], 1);
-                       fprintf(stderr,"NOTE ON : Note=%d Chan=%d Vel=%d\n", packet->data[i+1], chan, packet->data[i+2]);
+                       //fprintf(stderr,"NOTE ON : Note=%d Chan=%d Vel=%d\n", packet->data[i+1], chan, packet->data[i+2]);
                        i +=3;
                        break;
                   case 0xA0:  // Polyph. Press.
@@ -63,7 +80,7 @@ static void ReadMIDIdevice(const MIDIPacketList *pktlist, void *refCon, void *co
                        break;
                   case 0xB0:  // Control change
                        NewMidiEvent(MIDI_CTRL, chan, packet->data[i+1], packet->data[i+2]);
-                       fprintf(stderr,"CtlChang: Ctrl=%d Chan=%d Val=%d\n", packet->data[i+1], chan, packet->data[i+2]);
+                       //fprintf(stderr,"CtlChang: Ctrl=%d Chan=%d Val=%d\n", packet->data[i+1], chan, packet->data[i+2]);
                        i +=3;
                        break;
                   case 0xC0:  // Program change
@@ -76,7 +93,7 @@ static void ReadMIDIdevice(const MIDIPacketList *pktlist, void *refCon, void *co
                        break;
                   case 0xE0:  // Pitch Bend
                        NewMidiEvent(MIDI_PITCH, chan, 0, packet->data[i+1] + 128*packet->data[i+2]);
-                       fprintf(stderr,"Pitch   : val =%d Chan=%d\n", packet->data[i+1] + 128*packet->data[i+2], chan);
+                       //fprintf(stderr,"Pitch   : val =%d Chan=%d\n", packet->data[i+1] + 128*packet->data[i+2], chan);
                        i +=3;
                        break;
                   case 0xF0:  
@@ -120,7 +137,6 @@ void register_midi_device(char *myname) {
                FoundMIDIref=i;
                fprintf(stderr,"MIDI device found and selected: >>>%s<<<\n", name);
            } else {
-               fprintf(stderr,"MIDI device we were looking for   : >>>%s<<<\n", myname);
                fprintf(stderr,"MIDI device found BUT NOT SELECTED: >>>%s<<<\n", name);
            }
        }
diff --git a/midi2.c b/midi2.c
index 1e737c12e78a52a84428e1f8b92fe9c7906e3092..377a86efc546494c25ec67212b8591fc882fe194 100644 (file)
--- a/midi2.c
+++ b/midi2.c
@@ -67,7 +67,7 @@ void NewMidiEvent(enum MIDIevent event, int channel, int note, int val) {
                        DoTheMidi(desc->action, desc->type, new);
                    }
                    break;
-               default:
+               case EVENT_NONE:
                    break;
            }
            break;
diff --git a/midi3.c b/midi3.c
index f3989d0bca24681d84a6f0cbf993f1abbbe34c58..8e0c33f5dcc3b6096deb800ce51c40a69c0f6df2 100644 (file)
--- a/midi3.c
+++ b/midi3.c
@@ -226,7 +226,8 @@ void DoTheMidi(enum MIDIaction action, enum MIDItype type, int val) {
                    break;
            }
            break;
-       default:
+       case COMPRESS:
+       case ACTION_NONE:
             fprintf(stderr,"Unimplemented in DoTheMidi: A=%d T=%d val=%d\n", action, type, val);
            break;
     }
index 235ca122ad543f9b74ca29e0defbaff5f52c4f1d..3704bb52c6ca344fa3f7be2486419a122ced84dd 100644 (file)
@@ -32,6 +32,7 @@
 #include <string.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <sys/select.h>
 
 #include "discovered.h"
 #include "discovery.h"
@@ -56,6 +57,11 @@ static void discover(struct ifaddrs* iface) {
     struct sockaddr_in to_addr={0};
     int flags;
     struct timeval tv;
+    int optval;
+    socklen_t optlen;
+    fd_set fds;
+    unsigned char buffer[1032];
+    int i, len;
 
     if (iface == NULL) {
        //
@@ -80,20 +86,59 @@ static void discover(struct ifaddrs* iface) {
             return;
        }
        //
-       // We make a time-out of 3 secs, otherwise we might "hang" in connect()
+       // Here I tried a bullet-proof approach to connect() such that the program
+        // does not "hang" under any circumstances.
+       // - First, one makes the socket non-blocking. Then, the connect() will
+        //   immediately return with error EINPROGRESS.
+       // - Then, one uses select() to look for *writeability* and check
+       //   the socket error if everything went right. Since one calls select()
+        //   with a time-out, one either succeed within this time or gives up.
+        // - Do not forget to make the socket blocking again.
        //
+        // Step 1. Make socket non-blocking and connect()
        flags=fcntl(discovery_socket, F_GETFL, 0);
        fcntl(discovery_socket, F_SETFL, flags | O_NONBLOCK);
+       rc=connect(discovery_socket, (const struct sockaddr *)&to_addr, sizeof(to_addr));
+        if ((errno != EINPROGRESS) && (rc < 0)) {
+            perror("discover: connect() failed for TCP discovery_socket:");
+           close(discovery_socket);
+           return;
+       }
+       // Step 2. Use select to wait for the connection
         tv.tv_sec=3;
        tv.tv_usec=0;
-       setsockopt(discovery_socket, SOL_SOCKET, SO_RCVTIMEO, (void *)&tv, sizeof(tv));
-       
-
-        if (connect(discovery_socket, (const struct sockaddr *)&to_addr, sizeof(to_addr)) < 0) {
-            perror("discover: connect() failed for TCP discovery_socket:");
+       FD_ZERO(&fds);
+       FD_SET(discovery_socket, &fds);
+       rc=select(discovery_socket+1, NULL, &fds, NULL, &tv);
+        if (rc < 0) {
+            perror("discover: select() failed on TCP discovery_socket:");
+           close(discovery_socket);
+           return;
+        }
+       // If no connection occured, return
+       if (rc == 0) {
+           // select timed out
+           fprintf(stderr,"discover: select() timed out on TCP discovery socket\n");
            close(discovery_socket);
            return;
        }
+       // Step 3. select() succeeded. Check success of connect()
+       optlen=sizeof(int);
+       rc=getsockopt(discovery_socket, SOL_SOCKET, SO_ERROR, &optval, &optlen);
+       if (rc < 0) {
+           // this should very rarely happen
+            perror("discover: getsockopt() failed on TCP discovery_socket:");
+           close(discovery_socket);
+           return;
+       }
+       if (optval != 0) {
+           // connect did not succeed
+           fprintf(stderr,"discover: connect() on TCP socket did not succeed\n");
+           close(discovery_socket);
+           return;
+       }
+       // Step 4. reset the socket to normal (blocking) mode
+       fcntl(discovery_socket, F_SETFL, flags &  ~O_NONBLOCK);
     } else {
 
         strcpy(interface_name,iface->ifa_name);
@@ -135,7 +180,7 @@ static void discover(struct ifaddrs* iface) {
         to_addr.sin_port=htons(DISCOVERY_PORT);
         to_addr.sin_addr.s_addr=htonl(INADDR_BROADCAST);
     }
-    int optval = 1;
+    optval = 1;
     setsockopt(discovery_socket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
     setsockopt(discovery_socket, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval));
 
@@ -152,13 +197,11 @@ static void discover(struct ifaddrs* iface) {
 
     // send discovery packet
     // If this is a TCP connection, send a "long" packet
-    unsigned char buffer[1032];
-    int len=63;
+    len=63;
     if (iface == NULL) len=1032;
     buffer[0]=0xEF;
     buffer[1]=0xFE;
     buffer[2]=0x02;
-    int i;
     for(i=3;i<len;i++) {
         buffer[i]=0x00;
     }
index 4a5a6fb8801d1537e810ab89410019efac9a5560..c12a7b19ce72931cd44da0c0fa33df893781946f 100644 (file)
 #define SPEED_384K                0x03
 #define MODE_CLASS_E              0x01
 #define MODE_OTHERS               0x00
-#define ALEX_ATTENUATION_0DB      0x00
-#define ALEX_ATTENUATION_10DB     0x01
-#define ALEX_ATTENUATION_20DB     0x02
-#define ALEX_ATTENUATION_30DB     0x03
 #define LT2208_GAIN_OFF           0x00
 #define LT2208_GAIN_ON            0x04
 #define LT2208_DITHER_OFF         0x00
@@ -627,7 +623,13 @@ static void process_ozy_input_buffer(unsigned char  *buffer) {
 
 
 #ifdef PURESIGNAL
-    nreceivers=(RECEIVERS*2)+1;
+    // DL1YCF:
+    // for PureSignal, the number of receivers needed is hard-coded below.
+    // we need at least 3 (for RX), and up to 5 for Orion2 boards, since
+    // the TX DAC channel is hard-wired to RX5.
+    nreceivers=3;
+    if (device == DEVICE_HERMES) nreceivers=4;
+    if (device == DEVICE_ANGELIA || device == DEVICE_ORION || device == DEVICE_ORION2) nreceivers=5;
 #else
        #if defined(RADIOBERRY) || defined(PI_SDR)
                nreceivers = receivers;
@@ -853,6 +855,9 @@ void ozy_send_buffer() {
   output_buffer[SYNC2]=SYNC;
 
   if(metis_offset==8) {
+    //
+    // Every second packet is a "C0=0" packet
+    //
     output_buffer[C0]=0x00;
     output_buffer[C1]=0x00;
     switch(active_receiver->sample_rate) {
@@ -912,7 +917,6 @@ void ozy_send_buffer() {
       output_buffer[C2]|=band->OCrx<<1;
     }
 
-// TODO - add Alex Antenna
     output_buffer[C3] = (receiver[0]->alex_attenuation) & 0x03;  // do not set higher bits
     if(active_receiver->random) {
       output_buffer[C3]|=LT2208_RANDOM_ON;
@@ -933,19 +937,25 @@ void ozy_send_buffer() {
       output_buffer[C3]|=LT2208_GAIN_ON;
     }
 
-    switch(receiver[0]->alex_antenna) {
+    i=receiver[0]->alex_antenna;
+#ifdef PURESIGNAL
+    //
+    // Upon TX, we might have to activate a different RX path for the
+    // attenuated feedback signal. Use feedback_antenna == 0, if
+    // the feedback signal is routed automatically/internally (e.g.
+    // ANAN-7000DLE, when using the internal feedback path).
+    //
+    if (isTransmitting() && transmitter->puresignal) i=receiver[PS_RX_FEEDBACK]->feedback_antenna;
+#endif
+    switch(i) {
       case 0:  // ANT 1
-        break;
       case 1:  // ANT 2
-        break;
       case 2:  // ANT 3
         break;
-      case 3:  // EXT 1
-        //output_buffer[C3]|=0xA0;
+      case 3:  // Alex: RX2 IN, ANAN: EXT1, ANAN7000: EXT
         output_buffer[C3]|=0xC0;
         break;
-      case 4:  // EXT 2
-        //output_buffer[C3]|=0xC0;
+      case 4:  // Alex: RX1 IN, ANAN: EXT2, ANAN7000: RX BYPASS
         output_buffer[C3]|=0xA0;
         break;
       case 5:  // XVTR
@@ -959,8 +969,10 @@ void ozy_send_buffer() {
 // TODO - add Alex TX relay, duplex, receivers Mercury board frequency
     output_buffer[C4]=0x04;  // duplex
 #ifdef PURESIGNAL
-    nreceivers=(RECEIVERS*2)-1;
-    nreceivers+=1; // for PS TX Feedback
+    // DL1YCF: see comment on "nreceivers" above. The number is reduced by 1 here
+    nreceivers=2;
+    if (device == DEVICE_HERMES) nreceivers=3;
+    if (device == DEVICE_ANGELIA || device == DEVICE_ORION || device == DEVICE_ORION2) nreceivers=4;
 #else
        #ifdef RADIOBERRY
                nreceivers = receivers-1;
@@ -969,6 +981,7 @@ void ozy_send_buffer() {
        #endif
 #endif
 
+    // 0 ... 7 maps on 1 ... 8 receivers
     output_buffer[C4]|=nreceivers<<3;
     
     if(isTransmitting()) {
@@ -1014,6 +1027,10 @@ void ozy_send_buffer() {
       }
     }
   } else {
+    //
+    // metis_offset !=8: send "command" C&C packets in round-robin
+    // using the value of "command" from 1 to 10,
+    // and "command==2" packets are repeated for each RX
     switch(command) {
       case 1: // tx frequency
         output_buffer[C0]=0x02;
@@ -1038,7 +1055,10 @@ void ozy_send_buffer() {
         break;
       case 2: // rx frequency
 #ifdef PURESIGNAL
-        nreceivers=(RECEIVERS*2)+1;
+       // DL1YCF: see comment on "nreceivers" above.
+       nreceivers=3;
+       if (device == DEVICE_HERMES) nreceivers=4;
+       if (device == DEVICE_ANGELIA || device == DEVICE_ORION || device == DEVICE_ORION2) nreceivers=5;
 #else
                #ifdef RADIOBERRY
                        nreceivers = receivers;
@@ -1175,28 +1195,30 @@ void ozy_send_buffer() {
         }
 #endif
         output_buffer[C3]=0x00;
+        output_buffer[C4]=0x00;
   
         if(radio->device==DEVICE_HERMES || radio->device==DEVICE_ANGELIA || radio->device==DEVICE_ORION || radio->device==DEVICE_ORION2) {
-          output_buffer[C4]=0x20|adc_attenuation[receiver[0]->adc];
+         // DL1YCF: if attenuation is zero, then disable attenuator
+         i = adc_attenuation[receiver[0]->adc] & 0x1F;
+          if (i >0) output_buffer[C4]=0x20| i;
         } else {
 #ifdef RADIOBERRY
-                 int att = 63 - rx_gain_slider[active_receiver->adc];
+         int att = 63 - rx_gain_slider[active_receiver->adc];
           output_buffer[C4]=0x20|att;
-#else
-                 output_buffer[C4]=0x00;
 #endif
         }
         break;
       case 5:
-        // need to add adc 2 and 3 attenuation
         output_buffer[C0]=0x16;
         output_buffer[C1]=0x00;
         if(receivers==2) {
           if(radio->device==DEVICE_HERMES || radio->device==DEVICE_ANGELIA || radio->device==DEVICE_ORION || radio->device==DEVICE_ORION2) {
-            output_buffer[C1]=0x20|adc_attenuation[receiver[1]->adc];
+           // DL1YCF: if attenuation is zero, then disable attenuator
+           i = adc_attenuation[receiver[1]->adc] & 0x1F;
+            if (i > 0) output_buffer[C1]=0x20|i;
           }
         }
-        output_buffer[C2]=0x00;
+        output_buffer[C2]=0x00; // ADC3 attenuator disabled.
         if(cw_keys_reversed!=0) {
           output_buffer[C2]|=0x40;
         }
@@ -1208,12 +1230,30 @@ void ozy_send_buffer() {
         output_buffer[C0]=0x1C;
         output_buffer[C1]=0x00;
 #ifdef PURESIGNAL
-        output_buffer[C1]|=receiver[0]->adc;
-        output_buffer[C1]|=(receiver[0]->adc<<2);
-        output_buffer[C1]|=receiver[1]->adc<<4;
-        output_buffer[C1]|=(receiver[1]->adc<<6);
+
+       // The whole setup here implicitly assumes
+       // that receiver[0]->adc is 0 and receiver[1]->adc is 1
+
+       // This is the correct setting for DEVICE_METIS and DEVICE_HERMES
+        output_buffer[C1]|=receiver[0]->adc;           // RX1 bound to ADC0
+        output_buffer[C1]|=(receiver[0]->adc<<2);      // RX2 bound to ADC0
+        output_buffer[C1]|=receiver[1]->adc<<4;                // RX3 bound to ADC1
+
+       // DL1YCF:
+       // For Orion, Angelia and OrionMk2 RX4 must show the FeedBack signal.
+        // In most cases this is routed back to RX1 so we need ADC0 for RX4
+       // Since I could test this only on my ANAN7000, I changed to code
+       // to associate RX4 with ADC0 only on Orion2 -- but I guess this will
+       // be necessary for other SDRs as well.
+
+        if (device == DEVICE_ORION2) {
+          output_buffer[C1]|=(receiver[0]->adc<<6);   // This works on ANAN7000
+       } else {
+          output_buffer[C1]|=(receiver[1]->adc<<6);   // Does this work for somebody?
+       }
         output_buffer[C2]=0x00;
         if(transmitter->puresignal) {
+         // This should not be necessary since RX5 is hard-wired to the TX DAC on TX
           output_buffer[C2]|=receiver[2]->adc;
         }
 #else
@@ -1263,14 +1303,14 @@ void ozy_send_buffer() {
         output_buffer[C0]=0x24;
         output_buffer[C1]=0x00;
         if(isTransmitting()) {
-          output_buffer[C1]|=0x80; // ground RX1 on transmit
+          output_buffer[C1]|=0x80; // ground RX2 on transmit, bit0-6 are Alex2 filters
         }
         output_buffer[C2]=0x00;
         if(receiver[0]->alex_antenna==5) { // XVTR
-          output_buffer[C2]=0x02;
+          output_buffer[C2]=0x02;          // Alex2 XVTR enable
         }
-        output_buffer[C3]=0x00;
-        output_buffer[C4]=0x00;
+        output_buffer[C3]=0x00;            // Alex2 filters
+        output_buffer[C4]=0x00;            // Alex2 filters
         break;
     }
 
index d6d5924a5c438a5d1bb0a49761c67e4011c87289..9312459f21a1b2e191f996bba0e4b9032ee20431 100644 (file)
--- a/ps_menu.c
+++ b/ps_menu.c
@@ -227,11 +227,12 @@ static int info_thread(gpointer arg) {
       switch(state) {
         case 0:
           if(newcal && (info[4]>181 || (info[4]<=128 && transmitter->attenuation>0))) {
-            ddb= 20.0 * log10((double)info[4]/152.293);
-            if(isnan(ddb)) {
-               // this means feedback lvl is < 1, switch OFF attenuation
-                ddb=-100.0;
-            }
+           if (info[4] > 0) {
+              ddb= 20.0 * log10((double)info[4]/152.293);
+           } else {
+             // This happens when the "Drive" slider is moved to zero
+             ddb= -100.0;
+           }
             new_att=transmitter->attenuation + (int)ddb;
            // keep new value of attenuation in allowed range
            if (new_att <  0) new_att= 0;
@@ -263,6 +264,12 @@ static int info_thread(gpointer arg) {
     return TRUE;
 }
 
+static void ps_ant_cb(GtkWidget *widget, gpointer data) {
+  if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
+    receiver[PS_RX_FEEDBACK]->feedback_antenna = (int) (uintptr_t) data;
+  }
+}
+
 static void enable_cb(GtkWidget *widget, gpointer data) {
   g_idle_add(ext_tx_set_ps,(gpointer)(long)gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)));
 }
@@ -358,7 +365,6 @@ void ps_menu(GtkWidget *parent) {
     set_button_text_color(twotone_b,"red");
   }
 
-  
   col++;
 
   GtkWidget *auto_b=gtk_check_button_new_with_label("Auto Attenuate");
@@ -392,6 +398,30 @@ void ps_menu(GtkWidget *parent) {
   row++;
   col=0;
 
+  GtkWidget *ps_ant_label=gtk_label_new("PS FeedBk ANT:");
+  gtk_widget_show(ps_ant_label);
+  gtk_grid_attach(GTK_GRID(grid), ps_ant_label, col, row, 1, 1);
+  col++;
+
+  GtkWidget *ps_ant_auto=gtk_radio_button_new_with_label(NULL,"AUTO");
+  gtk_widget_show(ps_ant_auto);
+  gtk_grid_attach(GTK_GRID(grid), ps_ant_auto, col, row, 1, 1);
+  g_signal_connect(ps_ant_auto,"toggled", G_CALLBACK(ps_ant_cb), (gpointer) (long) 0);
+  col++;
+
+  GtkWidget *ps_ant_ext1=gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(ps_ant_auto),"EXT1");
+  gtk_widget_show(ps_ant_ext1);
+  gtk_grid_attach(GTK_GRID(grid), ps_ant_ext1, col, row, 1, 1);
+  g_signal_connect(ps_ant_ext1,"toggled", G_CALLBACK(ps_ant_cb), (gpointer) (long) 3);
+  col++;
+
+  GtkWidget *ps_ant_ext2=gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(ps_ant_auto),"EXT2");
+  gtk_widget_show(ps_ant_ext2);
+  gtk_grid_attach(GTK_GRID(grid), ps_ant_ext2, col, row, 1, 1);
+  g_signal_connect(ps_ant_ext2,"toggled", G_CALLBACK(ps_ant_cb), (gpointer) (long) 4);
+
+  row++;
+  col=0;
   feedback_l=gtk_label_new("Feedback Lvl");
   gtk_widget_show(feedback_l);
   gtk_grid_attach(GTK_GRID(grid),feedback_l,col,row,1,1);
diff --git a/radio.c b/radio.c
index b47623e27686c25f7b0073c2b78569c1bbec07ff..b4ccf889e3e7cf9eb99331ae7d8f5063d9d2c03b 100644 (file)
--- a/radio.c
+++ b/radio.c
@@ -352,7 +352,7 @@ static gboolean minimize_cb (GtkWidget *widget, GdkEventButton *event, gpointer
 }
 
 static gboolean menu_cb (GtkWidget *widget, GdkEventButton *event, gpointer data) {
-  new_menu(top_window);
+  new_menu();
   return TRUE;
 }
 
@@ -1014,6 +1014,21 @@ static int calcLevel(double d) {
 
   level=(int)(actual_volts*255.0);
 
+#ifdef __APPLE__
+#ifdef PURESIGNAL
+//
+//  DL1YCF: I do not know exactly why: if the drive level
+//          is set to zero while PS is active, the program
+//          reproducably crashes when the drive is set from 1 Watt
+//          to 0 Watt, possibly a division by zero or the evaluation
+//          of a logarithm within WDSP.
+//          QuickAndDirty Fix: use "1" as minimum drive level
+//          which corresponds to a fraction of a Watt.
+//
+  if (level < 1) level=1;
+#endif
+#endif
 //fprintf(stderr,"calcLevel: %f calib=%f level=%d\n",d, gbb, level);
   return level;
 }
@@ -1482,6 +1497,11 @@ void radioSaveState() {
     for(i=0;i<receivers;i++) {
       receiver_save_state(receiver[i]);
     }
+#ifdef PURESIGNAL
+    // There is little to save.
+    // An exception is the feedback_antenna stored in PS_RX_FEEDBACK
+    receiver_save_state(receiver[PS_RX_FEEDBACK]);
+#endif
     transmitter_save_state(transmitter);
 #ifdef FREEDV
     freedv_save_state();
index 28176026d450a33251a36c42e6b9e4bbb942f5f7..bdaf835eaa4dd1941aabd7114930ece79b96332b 100644 (file)
@@ -125,14 +125,15 @@ gboolean receiver_motion_notify_event(GtkWidget *widget, GdkEventMotion *event,
   int x, y;
   GdkModifierType state;
   RECEIVER *rx=(RECEIVER *)data;
-  if(!making_active) {
+  // DL1YCF: if !pressed, we may come from the destruction
+  //         of a menu, and should not move the VFO.
+  if(!making_active && pressed) {
     gdk_window_get_device_position (event->window,
                                 event->device,
                                 &x,
                                 &y,
                                 &state);
-    // DL1YCF added a pair of () to fix an error
-    if(((state & GDK_BUTTON1_MASK) == GDK_BUTTON1_MASK) || pressed) {
+    if(state & GDK_BUTTON1_MASK) {
       int moved=last_x-x;
       vfo_move((long long)((float)moved*rx->hz_per_pixel));
       last_x=x;
@@ -198,6 +199,11 @@ void receiver_save_state(RECEIVER *rx) {
   sprintf(value,"%d",rx->waterfall_automatic);
   setProperty(name,value);
   
+#ifdef PURESIGNAL
+  sprintf(name,"receiver.%d.feedback_antenna",rx->id);
+  sprintf(value,"%d",rx->feedback_antenna);
+  setProperty(name,value);
+#endif
   sprintf(name,"receiver.%d.alex_antenna",rx->id);
   sprintf(value,"%d",rx->alex_antenna);
   setProperty(name,value);
@@ -306,15 +312,9 @@ fprintf(stderr,"receiver_restore_state: id=%d\n",rx->id);
   sprintf(name,"receiver.%d.sample_rate",rx->id);
   value=getProperty(name);
   if(value) rx->sample_rate=atoi(value);
-#ifdef STEMLAB_FIX
-  // HPSDR apps on the RedPitay have hard-wired connections
-  // that should not be changed
-  fprintf(stderr,"STEMLAB: ignoring ADC settings for RX%d\n",rx->id);
-#else
   sprintf(name,"receiver.%d.adc",rx->id);
   value=getProperty(name);
   if(value) rx->adc=atoi(value);
-#endif
   sprintf(name,"receiver.%d.filter_low",rx->id);
   value=getProperty(name);
   if(value) rx->filter_low=atoi(value);
@@ -360,6 +360,11 @@ fprintf(stderr,"receiver_restore_state: id=%d\n",rx->id);
   value=getProperty(name);
   if(value) rx->waterfall_automatic=atoi(value);
 
+#ifdef PURESIGNAL
+  sprintf(name,"receiver.%d.feedback_antenna",rx->id);
+  value=getProperty(name);
+  if(value) rx->feedback_antenna=atoi(value);
+#endif
   sprintf(name,"receiver.%d.alex_antenna",rx->id);
   value=getProperty(name);
   if(value) rx->alex_antenna=atoi(value);
@@ -774,6 +779,9 @@ fprintf(stderr,"create_pure_signal_receiver: id=%d buffer_size=%d\n",id,buffer_s
 
   rx->volume=0.0;
 
+  rx->squelch_enable=0;
+  rx->squelch=0;
+
   rx->dither=0;
   rx->random=0;
   rx->preamp=0;
@@ -790,6 +798,7 @@ fprintf(stderr,"create_pure_signal_receiver: id=%d buffer_size=%d\n",id,buffer_s
   rx->nr2_npe_method=0;
   rx->nr2_ae=1;
   
+  rx->feedback_antenna=0;
   rx->alex_antenna=0;
   rx->alex_attenuation=0;
 
@@ -808,6 +817,9 @@ fprintf(stderr,"create_pure_signal_receiver: id=%d buffer_size=%d\n",id,buffer_s
 
   rx->low_latency=0;
 
+  // not much to be restored, except feedback_antenna
+  if (id == PS_RX_FEEDBACK) receiver_restore_state(rx);
+
   int result;
   XCreateAnalyzer(rx->id, &result, 262144, 1, 1, "");
   if(result != 0) {
@@ -867,12 +879,6 @@ fprintf(stderr,"create_receiver: id=%d buffer_size=%d fft_size=%d pixels=%d fps=
           }
           break;
       }
-#ifdef STEMLAB_FIX
-//
-//    RedPitaya based HPSDR apps have hard-wired adc settings
-//
-      if (id == 1) rx->adc=1;
-#endif
   }
 fprintf(stderr,"create_receiver: id=%d default ddc=%d adc=%d\n",rx->id, rx->ddc, rx->adc);
   rx->sample_rate=48000;
@@ -925,6 +931,10 @@ fprintf(stderr,"create_receiver: id=%d default ddc=%d adc=%d\n",rx->id, rx->ddc,
   rx->nr2_npe_method=0;
   rx->nr2_ae=1;
   
+#ifdef PURESIGNAL
+  rx->feedback_antenna=0;
+#endif
+
   BAND *b=band_get_band(vfo[rx->id].band);
   rx->alex_antenna=b->alexRxAntenna;
   rx->alex_attenuation=b->alexAttenuation;
index 39bf084e1683160bdb01052e5d36d09b3f0fecd2..52970caf996afec2fa2f305fed0e1b828153043e 100644 (file)
@@ -89,6 +89,13 @@ typedef struct _receiver {
   int alex_antenna;
   int alex_attenuation;
 
+#ifdef PURESIGNAL
+  // indicates to which ALEX RX antenna the attenuated feedback
+  // signal from the PA goes. The coding is the same as for alex_antenna,
+  // except that this connector is only used when transmitting.
+  int feedback_antenna;
+#endif
+
   int filter_low;
   int filter_high;
 
index 528284aa1831daa0decc78b68b30935cea32e105..2445bdf06f9c70b87bc1828e3304a84fcc001732 100644 (file)
--- a/rx_menu.c
+++ b/rx_menu.c
@@ -59,7 +59,6 @@ static gboolean delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_d
 
 static void dither_cb(GtkWidget *widget, gpointer data) {
   active_receiver->dither=active_receiver->dither==1?0:1;
-  update_att_preamp();
 }
 
 static void random_cb(GtkWidget *widget, gpointer data) {
@@ -68,7 +67,6 @@ static void random_cb(GtkWidget *widget, gpointer data) {
 
 static void preamp_cb(GtkWidget *widget, gpointer data) {
   active_receiver->preamp=active_receiver->preamp==1?0:1;
-  update_att_preamp();
 }
 
 static void alex_att_cb(GtkWidget *widget, gpointer data) {
@@ -238,9 +236,17 @@ void rx_menu(GtkWidget *parent) {
       break;
 #endif
   }
-
+  //
   // The CHARLY25 board (with RedPitaya) has no support for dither or random,
-  // so those are left out. PreAmps and Alex Attenuator are controlled via sliders.
+  // so those are left out. For Charly25, PreAmps and Alex Attenuator are controlled via
+  // the sliders menu.
+  // On SDRs other than CHARLY25, preamps or Alex attenuators may be present or not, and we
+  // do not try to find out whether they are. This would overload the code, and we then
+  // also must have a menu to check e.g. which ANAN model is actually present.
+  // Instead, we offer these checkboxes in either case and must rely on the user
+  // not playing around with features that are not there.
+  //
   if (filter_board != CHARLY25) {
     switch(protocol) {
       case ORIGINAL_PROTOCOL:
@@ -256,17 +262,11 @@ void rx_menu(GtkWidget *parent) {
           gtk_grid_attach(GTK_GRID(grid),random_b,x,3,1,1);
           g_signal_connect(random_b,"toggled",G_CALLBACK(random_cb),NULL);
 
-          if((protocol==ORIGINAL_PROTOCOL && device==DEVICE_METIS) ||
-#ifdef USBOZY
-              (protocol==ORIGINAL_PROTOCOL && device==DEVICE_OZY) ||
-#endif
-              (protocol==NEW_PROTOCOL && device==NEW_DEVICE_ATLAS)) {
+          GtkWidget *preamp_b=gtk_check_button_new_with_label("Preamp");
+          gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (preamp_b), active_receiver->preamp);
+          gtk_grid_attach(GTK_GRID(grid),preamp_b,x,4,1,1);
+          g_signal_connect(preamp_b,"toggled",G_CALLBACK(preamp_cb),NULL);
 
-            GtkWidget *preamp_b=gtk_check_button_new_with_label("Preamp");
-            gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (preamp_b), active_receiver->preamp);
-            gtk_grid_attach(GTK_GRID(grid),preamp_b,x,4,1,1);
-            g_signal_connect(preamp_b,"toggled",G_CALLBACK(preamp_cb),NULL);
-          }
           GtkWidget *alex_att_label=gtk_label_new("Alex Attenuator");
           gtk_grid_attach(GTK_GRID(grid), alex_att_label, x, 5, 1, 1);
           GtkWidget *last_alex_att_b = NULL;
@@ -287,12 +287,13 @@ void rx_menu(GtkWidget *parent) {
     }
   }
 
+  // Number of ADCs. 
   int n_adc=1;
   switch(protocol) {
     case ORIGINAL_PROTOCOL:
       switch(device) {
         case DEVICE_METIS:
-          n_adc=1;  // FIX for multiple Mercury cards
+          n_adc=1;  // No support for multiple MERCURY cards on a single ATLAS bus.
           break;
         case DEVICE_HERMES:
         case DEVICE_HERMES_LITE:
@@ -306,7 +307,7 @@ void rx_menu(GtkWidget *parent) {
     case NEW_PROTOCOL:
       switch(device) {
         case NEW_DEVICE_ATLAS:
-          n_adc=1; // FIX for multiple Mercury cards
+          n_adc=1; // No support for multiple MERCURY cards on a single ATLAS bus.
           break;
         case NEW_DEVICE_HERMES:
         case NEW_DEVICE_HERMES2:
@@ -322,6 +323,9 @@ void rx_menu(GtkWidget *parent) {
       break;
   }
 
+  // If there is more than one ADC, let the user associate an ADC
+  // with the current receiver. Note: for PURESIGNAL, ADC0 has to
+  // be associated with the first receiver.
   if(n_adc>1) {
     for(i=0;i<n_adc;i++) {
       sprintf(label,"ADC-%d",i);
index 8c71cae3a8beeb0470cf7dc0d860096522f5c245..5193be6aeae87820e716a6a97680acfc5ca608a9 100644 (file)
--- a/sliders.c
+++ b/sliders.c
@@ -202,8 +202,6 @@ void update_att_preamp(void) {
     gtk_combo_box_set_active_id(GTK_COMBO_BOX(c25_att_combobox), id);
     sprintf(id, "%d", active_receiver->preamp + active_receiver->dither);
     gtk_combo_box_set_active_id(GTK_COMBO_BOX(c25_preamp_combobox), id);
-  } else {
-    adc_attenuation[active_receiver->adc] = 10*active_receiver->alex_attenuation;
   }
 }