]> git.rkrishnan.org Git - pihpsdr.git/commitdiff
a) fixed seg-faults associated with RX2 panel
authorc vw <dl1ycf@darc.de>
Thu, 30 May 2019 09:59:08 +0000 (11:59 +0200)
committerc vw <dl1ycf@darc.de>
Thu, 30 May 2019 09:59:08 +0000 (11:59 +0200)
b) finalized MIDI
c) reworked PURESIGNAL ADC associations

26 files changed:
README.MIDI
audio.c
ext.c
ext.h
frequency.c
hpsdrsim.c
main.c
midi.h
midi.inp
midi2.c
midi3.c
old_protocol.c
portaudio.c
ps_menu.c
radio.c
radio.h
radio_menu.c
receiver.c
rigctl.c
rx_menu.c
sliders.c
transmitter.c
tx_menu.c
tx_panadapter.c
vfo.c
vox_menu.c

index 4f248df63ca410ff569340dbd8c323cb1950fc55..57a31f996682cee3c60a605ae29adf0197942b29 100644 (file)
@@ -136,33 +136,44 @@ drive could be used with a knob (CTRL but no WHEEL), with a wheel
 
 Here is a list of actions currently implemented, in alphabetical
 order. We also give for which types of MIDI events (KEY, KNOB,
-WHEEL, PITCH) this action is defined
+WHEEL) this action is defined. We further have a "dummy" action
+NONE which means that there is nothing to do.
 
 
 Action         Event                Explanation
 ----------------------------------------------------------------------------------------------
 AFGAIN         KNOB,WHEEL           AF audio volume
 AGC            KNOB,WHEEL           AGC level
+AGCATTACK      KEY                  cycle through AGC settings (fast/slow, etc.)
 ATT            KEY                  cycle  through "ALEX attenuator" settings
 ATT            KNOB,WHEEL           set RX attenuation (0-31dB)
 BANDUP         KEY,WHEEL            cycle through the bands (upwards)
 BANDDOWN       KEY,WHEEL            cycle through the bands (downwards)
-COMPRESS       KNOB,WHEEL           set TX compression level (if compression is activated)
+COMPRESS       KNOB,WHEEL           set TX compression level
+CTUN           KEY                  toggle CTUN mode
 FILTERUP       KEY,WHEEL            cycle through the filters (upwards)
 FILTERDOWN     KEY,WHEEL            cycle through the filster (downwards)
+LOCK           KEY                  lock VFO(s)
 MICGAIN        KNOB,WHEEL           MIC gain
 MODEUP         KEY,WHEEL            cycle through the modes (upwards)
 MODEDOWN       KEY,WHEEL            cycle through the modes (downwards)
 MOX            KEY                  MOX on/off
+NB             KEY                  cycle through NoiseBlanker settings
+NR             KEY                  cycle through NoiseReduction settings
 PANHIGH        WHEEL                change "high" level of current pan-adapter
 PANLOW         WHEEL                change "bottom" level of current pan-adapter
 PREAMP         KEY                  cycle through preamp settings (only available for CHARLY25 filter boards)
-RITTOGGLE      KEY                  RIT on/off
+PURESIGNAL     KEY                  toggle PURESIGNAL (on/off)
+RITCLEAR       KEY                  clear RIT frequency
 RITVAL         WHEEL                change RIT frequency offset
 RFPOWER        KNOB,WHEEL           TX power
+SPLIT          KEY                  toggle Split mode
 SWAPVFO        KEY                  Swap VFO-A/VFO-B
 TUNE           KEY                  Tune on/off
 VFO            WHEEL                change VFO frequency
+VFOA2B         KEY                  frequency VFO A -> VFO B
+VFOB2A         KEY                  frequency VFO B -> VFO A
+VOX            KEY                  toggle VOX (on/off)
  
 
 If you need more or different type of actions, the implementation should be straightforward.
diff --git a/audio.c b/audio.c
index cf49fee0a7927db9c0215f30a0f3a1b66e814846..4c98c8d28a70ba67cd143d5f714972a2ebd8a86f 100644 (file)
--- a/audio.c
+++ b/audio.c
@@ -18,8 +18,8 @@
 */
 
 //
-// DL1YCF: If PortAudio is used instead of ALSO (e.g. on MacOS),
-//         this file is not used (and replaced by portaudio.c).
+// If PortAudio is used instead of ALSA (e.g. on MacOS),
+// this file is not used (and replaced by portaudio.c).
 
 #ifndef PORTAUDIO 
 
diff --git a/ext.c b/ext.c
index c86cd5c73216f5c7fa2ebed7ca2f49bef65e0773..daacc6d848fd525088ed5c971f2464e223f2ccbf 100644 (file)
--- a/ext.c
+++ b/ext.c
@@ -179,6 +179,16 @@ int ext_vfo_a_swap_b(void *data) {
   return 0;
 }
 
+int ext_vfo_a_to_b(void *data) {
+  vfo_a_to_b();
+  return 0;
+}
+
+int ext_vfo_b_to_a(void *data) {
+  vfo_b_to_a();
+  return 0;
+}
+
 int ext_update_att_preamp(void *data) {
   update_att_preamp();
   return 0;
diff --git a/ext.h b/ext.h
index 070a21544f61247901ba75efa6762bea75de9901..c3c9710b4c9cec0b4d91a240deef44ae081ce09c 100644 (file)
--- a/ext.h
+++ b/ext.h
@@ -63,6 +63,8 @@ int ext_set_mic_gain(void *data);
 int ext_set_agc_gain(void *data);
 int ext_set_drive(void *data);
 int ext_vfo_a_swap_b(void *data);
+int ext_vfo_a_to_b(void *data);
+int ext_vfo_b_to_a(void *data);
 int ext_update_att_preamp(void *data);
 int ext_set_alex_attenuation(void *data);
 int ext_set_attenuation_value(void *data);
index 8c9eca26a2c3684c019377fbf397f8922f889e35..d69fe76d58e09194ebfcbde842df12694e6315eb 100644 (file)
@@ -436,7 +436,7 @@ char* getFrequencyInfo(long long frequency,int filter_low,int filter_high) {
             break;
         } else if ((info->maxFrequency +1) == ((info+1)->minFrequency) &&
                    flow>=info->minFrequency && fhigh <= (info+1)->maxFrequency) {
-            // DL1YCF:
+            //
            // Sometimes in DigiMode operation, the nominal USB TX channel crosses
            // a sub-band boundary. Example: FT8 on 17m, VFO set to 18099 kHz because
            // FT8 signal is generated at 18100.8 kHz with an AF signal of 1800 Hz.
@@ -445,6 +445,7 @@ char* getFrequencyInfo(long long frequency,int filter_low,int filter_high) {
            // either sub-band. We can return the info for the lower sub-band if
            // the band and transmit data is the same in both cases. If they are
            // different, we have found no match so far.
+           //
            if ((info->band == (info+1)->band) && (info->transmit == (info+1)->transmit)) {
                result = info->info;
                break;
index 6ecf73c46168f011d9e251bdd220b1592da58d99..c267d14cf375b5f72f6a46c7b08537dc7065020d 100644 (file)
  *
  * RF1: ADC noise (16-bit ADC) plus a  800 Hz signal at -100dBm
  * RF2: ADC noise (16-bit ADC) plus a 2000 Hz signal at - 80dBm
- * RF3: TX feedback signal with some distortion. Signal strength
- *      according to the "TX drive" and "TX ATT" settings.
- * RF4: normalized undistorted TX signal with a peak value of 0.400
+ * RF3: TX feedback signal with some distortion.
+ * RF4: normalized undistorted TX signal with a peak value of 0.407
  *
- * RF1 and RF2 respect the Preamp and Attenuator settings
+ * RF1 and RF2 signal strenght vary according to Preamp and Attenuator settings
+ * RF3 signal strength varies according to TX-drive and TX-ATT settings
+ * RF4 signal strength is normalized to amplitude of 0.407
  *
- * Depending on the device type, the receivers see different signals
- * (This is necessary for PURESIGNAL). We chose the association such that
- * it works both with and without PURESIGNAL. Upon receiving, the association
- * is as follows:
- * RX1=RF1, RX2=RF2, RX3=RF2, 
+ * RF1 and RF2 are associated with ADC1 and ADC2.
+ * RF3 also goes to ADC1 upon TX
+ * RF4 is the TX DAC signal. Upon TX, it goes to RX2 for Metis, RX4 for Hermes, and RX5 beyond.
  *
- * The connection upon transmitting depends on the DEVICE, namely
+ * The SDR application has to make the proper ADC settings!
  *
- * DEVICE=METIS:    RX1=RF3, RX2=RF4
- * DEVICE=HERMES:   RX3=RF3, RX4=RF4  (also for DEVICE=StemLab)
- * DEVICE=ORION2:   RX4=RF3, RX5=RF5  (also for DEVICE=ANGELIA and ORION)
+ * Without PURESIGNAL, the standard association is:
+ * RX1=ADC1, RX2=ADC2  (ADC2 not present for METIS and ANAN-10/10E/100)
  *
+ * When using PURESIGNAL, the standard association is:
+ *
+ * DEVICE=METIS:  RX1=ADC1, RX2=TX-DAC
+ * DEVICE=HERMES: RX1=ADC1, RX2=ADC1, RX3=ADC2, RX4=TX-DAC
+ * DEVICE=ORION:  RX1=ADC1, RX2=ADC1, RX3=ADC3, RX4=ADC1, RX5=TX-DAC (also for ANGELIA and ORION2)
+ *
+ * Note that for STEMlab (RedPitaya) based SDRs, there is usually a fixed association
+ *
+ * RX1=ADC1, RX2=ADC2, RX3=ADC2, RX4=TX-DAC
+ *
+ * And this setting is NOT AFFECTED by the ADC settings in the HPSDR protocol.
  *
  * Audio sent to the "radio" is played via the first available output channel.
  * This works on MacOS (PORTAUDIO) and Linux (ALSA).
@@ -131,7 +140,7 @@ static int          lna6m=-1;
 static int             alexTRdisable=-1;
 static int             vna=-1;
 static int             c25_ext_board_i2c_data=-1;
-static int             rx_adc[7]={0,1,1,2,-1,-1,-1};
+static int             rx_adc[7]={-1,-1,-1,-1,-1,-1,-1};
 static int             cw_hang = -1;
 static int             cw_reversed = -1;
 static int             cw_speed = -1;
@@ -262,7 +271,7 @@ int main(int argc, char *argv[])
            if (!strncmp(argv[1],"-orion2" ,7))  DEVICE=10;   // Anan7000 in old protocol
            if (!strncmp(argv[1],"-c25"    ,8))  DEVICE=100;  // the same as hermes
         }
-       ismetis=ishermes=isorion=isc25;
+       ismetis=ishermes=isorion=isc25=0;
        switch (DEVICE) {
            case   0: fprintf(stderr,"DEVICE is METIS\n");   ismetis=1;  break;
            case   1: fprintf(stderr,"DEVICE is HERMES\n");  ishermes=1; break;
@@ -855,6 +864,12 @@ void process_ep2(uint8_t *frame)
             chk_data((frame[2] & 0x30) >> 4, rx_adc[6], "RX7 ADC");
            chk_data((frame[3] & 0x1f), txatt, "TX ATT");
            txatt_dbl=pow(10.0, -0.05*(double) txatt);
+           if (isc25) {
+               // RedPitaya: Hard-wired ADC settings.
+               rx_adc[0]=0;
+               rx_adc[1]=1;
+               rx_adc[2]=1;
+           }
            break;
 
        case 30:
@@ -1009,81 +1024,61 @@ void *handler_ep6(void *arg)
                    pointer += 8;
                    memset(pointer, 0, 504);
                    for (j=0; j<n; j++) {
-                       //
-                       // Define samples of our sources RF1 through RF4
-                       //
-                       rf1isample= noiseItab[noiseIQpt] * 8388607.0;                   // Noise
-                       rf1isample += T0800Itab[pt0800] * 83.886070 *rxatt_dbl[0];      // tone 100 dB below peak
-                       rf1qsample=noiseQtab[noiseIQpt] * 8388607.0;
-                       rf1qsample += T0800Qtab[pt0800] * 83.886070 *rxatt_dbl[0];
-                       //
+                       // ADC1: noise + weak tone on RX, feedback sig. on TX
+                       if (ptt) {
+                         i1=isample[rxptr]*txdrv_dbl;
+                         q1=qsample[rxptr]*txdrv_dbl;
+                         fac=IM3a+IM3b*(i1*i1+q1*q1);
+                         rf1isample= (txatt_dbl*i1*fac+noiseItab[noiseIQpt]) * 8388607.0;
+                         rf1qsample= (txatt_dbl*q1*fac+noiseItab[noiseIQpt]) * 8388607.0;
+                       } else {
+                         rf1isample= noiseItab[noiseIQpt] * 8388607.0;                 // Noise
+                         rf1isample += T0800Itab[pt0800] * 83.886070 *rxatt_dbl[0];    // tone 100 dB below peak
+                         rf1qsample=noiseQtab[noiseIQpt] * 8388607.0;
+                         rf1qsample += T0800Qtab[pt0800] * 83.886070 *rxatt_dbl[0];
+                       }
                        rf2isample= noiseItab[noiseIQpt] * 8388607.0;                   // Noise
                        rf2isample += T2000Itab[pt2000] * 838.86070 * rxatt_dbl[1];     // tone 80 dB below peak
                        rf2qsample=noiseQtab[noiseIQpt] * 8388607.0;
                        rf2qsample += T2000Qtab[pt2000] * 838.86070 * rxatt_dbl[1];
                        //
-                       // RF3: TX signal distorted, with some ADC noise
-                       //
-                       i1=isample[rxptr]*txdrv_dbl;
-                       q1=qsample[rxptr]*txdrv_dbl;
-                       fac=IM3a+IM3b*(i1*i1+q1*q1);
-                       rf3isample= (txatt_dbl*i1*fac+noiseItab[noiseIQpt]) * 8388607.0;
-                       rf3qsample= (txatt_dbl*q1*fac+noiseItab[noiseIQpt]) * 8388607.0;
-                       //
                        // RF4: TX signal with peak=0.4
                        //
                        rf4isample= isample[rxptr] * 0.400 * 8388607.0;
                        rf4qsample= qsample[rxptr] * 0.400 * 8388607.0;
 
-
-
                        for (k=0; k< receivers; k++) {
                            myisample=0;
                            myqsample=0;
-                           switch (k) {
-                             case 0: // RX1
-                               if (ptt && ismetis) {
-                                   myisample=rf3isample;
-                                   myqsample=rf3qsample;
-                               } else {
-                                   myisample=rf1isample;
-                                   myqsample=rf1qsample;
-                               }
-                               break;
-                             case 1: // RX2
-                               if (ptt && ismetis) {
-                                   myisample=rf4isample;
-                                   myqsample=rf4qsample;
-                               } else {
-                                   myisample=rf2isample;
-                                   myqsample=rf2qsample;
-                               }
+                           switch (rx_adc[k]) {
+                             case 0: // ADC1
+                               myisample=rf1isample;
+                               myqsample=rf1qsample;
                                break;
-                             case 2:
-                                if (ptt && ishermes) {
-                                   myisample=rf3isample;
-                                   myqsample=rf3qsample;
-                                } else {
-                                   myisample=rf2isample;
-                                   myqsample=rf2qsample;
-                               }
+                             case 1: // ADC2
+                               myisample=rf2isample;
+                               myqsample=rf2qsample;
                                break;
-                             case 3: // RX4
-                               if (ptt && ishermes) {
-                                   myisample=rf4isample;
-                                   myqsample=rf4qsample;
-                                       } else if (ptt && isorion) {
-                                   myisample=rf3isample;
-                                   myqsample=rf3qsample;
-                               }
-                               break;
-                             case 4: // RX5
-                                       if (ptt && isorion) {
-                                   myisample=rf4isample;
-                                   myqsample=rf4qsample;
-                               }
+                             default:
+                               myisample=0;
+                               myqsample=0;
                                break;
                            }
+                           if (ismetis && ptt && (k==1)) {
+                               // METIS: TX DAC signal goes to RX2 when TXing
+                               myisample=rf4isample;
+                               myqsample=rf4qsample;
+                           }
+                           if (ishermes && ptt && (k==3)) {
+                               // HERMES: TX DAC signal goes to RX4 when TXing
+                               myisample=rf4isample;
+                               myqsample=rf4qsample;
+                           }
+                           if (isorion && ptt && (k==4)) {
+                               // ANGELIA and beyond: TX DAC signal goes to RX5 when TXing
+                               myisample=rf4isample;
+                               myqsample=rf4qsample;
+                           }
                            *pointer++ = (myisample >> 16) & 0xFF;
                            *pointer++ = (myisample >>  8) & 0xFF;
                            *pointer++ = (myisample >>  0) & 0xFF;
diff --git a/main.c b/main.c
index ffb0242cd06a10ea19caae15c7e62de3b0280836..55c9708ec57b85eba27ddf3669dcd8059176167c 100644 (file)
--- a/main.c
+++ b/main.c
@@ -152,7 +152,7 @@ static int init(void *data) {
   char wisdom_directory[1024];
   int rc;
 
-  fprintf(stderr,"init\n");
+  //fprintf(stderr,"init\n");
 
   audio_get_cards();
 
@@ -221,17 +221,17 @@ fprintf(stderr,"width=%d height=%d\n", display_width, display_height);
 
 fprintf(stderr,"display_width=%d display_height=%d\n", display_width, display_height);
 
-  fprintf(stderr,"create top level window\n");
+  //fprintf(stderr,"create top level window\n");
   top_window = gtk_application_window_new (app);
   if(full_screen) {
-fprintf(stderr,"full screen\n");
+    fprintf(stderr,"full screen\n");
     gtk_window_fullscreen(GTK_WINDOW(top_window));
   }
   gtk_widget_set_size_request(top_window, display_width, display_height);
   gtk_window_set_title (GTK_WINDOW (top_window), "piHPSDR");
   gtk_window_set_position(GTK_WINDOW(top_window),GTK_WIN_POS_CENTER_ALWAYS);
   gtk_window_set_resizable(GTK_WINDOW(top_window), FALSE);
-  fprintf(stderr,"setting top window icon\n");
+  //fprintf(stderr,"setting top window icon\n");
   GError *error;
   if(!gtk_window_set_icon_from_file (GTK_WINDOW(top_window), "hpsdr.png", &error)) {
     fprintf(stderr,"Warning: failed to set icon for top_window\n");
@@ -253,41 +253,41 @@ fprintf(stderr,"full screen\n");
   //fixed=gtk_fixed_new();
   //gtk_container_add(GTK_CONTAINER(top_window), fixed);
 
-fprintf(stderr,"create grid\n");
+//fprintf(stderr,"create grid\n");
   grid = gtk_grid_new();
   gtk_widget_set_size_request(grid, display_width, display_height);
   gtk_grid_set_row_homogeneous(GTK_GRID(grid),FALSE);
   gtk_grid_set_column_homogeneous(GTK_GRID(grid),FALSE);
-fprintf(stderr,"add grid\n");
+//fprintf(stderr,"add grid\n");
   gtk_container_add (GTK_CONTAINER (top_window), grid);
 
-fprintf(stderr,"create image\n");
+//fprintf(stderr,"create image\n");
   GtkWidget  *image=gtk_image_new_from_file("hpsdr.png");
-fprintf(stderr,"add image to grid\n");
+//fprintf(stderr,"add image to grid\n");
   gtk_grid_attach(GTK_GRID(grid), image, 0, 0, 1, 4);
 
-fprintf(stderr,"create pi label\n");
+//fprintf(stderr,"create pi label\n");
   char build[64];
   sprintf(build,"build: %s %s",build_date, version);
   GtkWidget *pi_label=gtk_label_new("piHPSDR by John Melton g0orx/n6lyt");
   gtk_label_set_justify(GTK_LABEL(pi_label),GTK_JUSTIFY_LEFT);
   gtk_widget_show(pi_label);
-fprintf(stderr,"add pi label to grid\n");
+//fprintf(stderr,"add pi label to grid\n");
   gtk_grid_attach(GTK_GRID(grid),pi_label,1,0,1,1);
 
-fprintf(stderr,"create build label\n");
+//fprintf(stderr,"create build label\n");
   GtkWidget *build_date_label=gtk_label_new(build);
   gtk_label_set_justify(GTK_LABEL(build_date_label),GTK_JUSTIFY_LEFT);
   gtk_widget_show(build_date_label);
-fprintf(stderr,"add build label to grid\n");
+//fprintf(stderr,"add build label to grid\n");
   gtk_grid_attach(GTK_GRID(grid),build_date_label,1,1,1,1);
 
-fprintf(stderr,"create status\n");
+//fprintf(stderr,"create status\n");
   status=gtk_label_new("");
   gtk_label_set_justify(GTK_LABEL(status),GTK_JUSTIFY_LEFT);
   //gtk_widget_override_font(status, pango_font_description_from_string("FreeMono 18"));
   gtk_widget_show(status);
-fprintf(stderr,"add status to grid\n");
+//fprintf(stderr,"add status to grid\n");
   gtk_grid_attach(GTK_GRID(grid), status, 1, 3, 1, 1);
 
 /*
@@ -315,12 +315,12 @@ int main(int argc,char **argv) {
 
   sprintf(name,"org.g0orx.pihpsdr.pid%d",getpid());
 
-fprintf(stderr,"gtk_application_new: %s\n",name);
+//fprintf(stderr,"gtk_application_new: %s\n",name);
 
   pihpsdr=gtk_application_new(name, G_APPLICATION_FLAGS_NONE);
   g_signal_connect(pihpsdr, "activate", G_CALLBACK(activate_pihpsdr), NULL);
   status=g_application_run(G_APPLICATION(pihpsdr), argc, argv);
-fprintf(stderr,"exiting ...\n");
+  fprintf(stderr,"exiting ...\n");
   g_object_unref(pihpsdr);
   return status;
 }
diff --git a/midi.h b/midi.h
index 98a6191d87b728ceb199334028ebac773559dd50..50915a7c3c717ea640bdcd1209da508a4f2a7fac 100644 (file)
--- a/midi.h
+++ b/midi.h
 
 //
 // MIDIaction encodes the "action" to be taken in Layer3
+// (sorted alphabetically)
 //
 enum MIDIaction {
-  ACTION_NONE=0,
-  VFO,
-  TUNE,
-  MOX,
-  AF_GAIN,
-  MIC_VOLUME,
-  TX_DRIVE,
-  ATT,
-  PRE,
-  AGC,
-  COMPRESS,
-  RIT_ONOFF,
-  RIT_VAL,
-  PAN_HIGH,
-  PAN_LOW,
-  BAND_UP,
-  BAND_DOWN,
-  FILTER_UP,
-  FILTER_DOWN,
-  MODE_UP,
-  MODE_DOWN,
-  SWAP_VFO
+  ACTION_NONE=0,       // No-Op (unassigned key)
+  AGC,                 // AGC level
+  AGCATTACK,           // AGC ATTACK (cycle fast/med/slow etc.)
+  ATT,                 // Step attenuator or Programmable attenuator
+  AF_GAIN,             // AF gain
+  BAND_DOWN,           // cycle through bands downwards
+  BAND_UP,             // cycle through bands upwards
+  COMPRESS,            // TX compressor value
+  CTUN,                        // CTUN on/off
+  FILTER_UP,           // cycle through filters upwards
+  FILTER_DOWN,         // cycle through filters downwards
+  MIC_VOLUME,          // MIC gain
+  LOCK,                        // disable frequency changes
+  MODE_UP,             // cycle through modes upwards
+  MODE_DOWN,           // cycle through modes downwards
+  MOX,                 // toggle "mox" state
+  NB,                  // cycle through NoiseBlanker states (none, NB, NB2)
+  NR,                  // cycle through NoiseReduction states (none, NR, NR2)
+  PRE,                 // preamp on/off
+  PAN_HIGH,            // "high" value of current panadapter
+  PAN_LOW,             // "low" value of current panadapter
+  PS,                  // PURESIGNAL on/off
+  RIT_CLEAR,           // clear RIT value
+  RIT_VAL,             // change RIT value
+  SPLIT,               // Split on/off
+  SWAP_VFO,            // swap VFO A/B frequency
+  TUNE,                        // toggle "tune" state
+  TX_DRIVE,            // RF output power
+  VFO,                 // change VFO frequency
+  VFO_A2B,             // VFO A -> B
+  VFO_B2A,             // VFO B -> A
+  VOX                  // VOX on/off
 };
 
 //
@@ -153,9 +164,9 @@ struct desc {
    int               up_thr1;     // Wheel only: If controller value is <= this value, generate "          up  "
    int               up_thr2;     // Wheel only: If controller value is <= this value, generate "     fast up  "
    int               up_thr3;     // Wheel only: If controller value is <= this value, generate "very fast up  "
-   int              delay;       // Wheel only: delay (msec)
+   int              delay;       // Wheel only: delay (msec) before next message is given upstream
    enum MIDIaction   action;     // SDR "action" to generate
-   struct desc       *next;       // Next defined action for a controller/key with that note value.
+   struct desc       *next;       // Next defined action for a controller/key with that note value (NULL for end of list)
 };
 
 struct {
@@ -186,7 +197,8 @@ void MIDIstartup();
 //
 // Layer-3 entry point (called by Layer2). In Layer-3, all the pihpsdr
 // actions (such as changing the VFO frequency) are performed.
-// The implementation of DoTheMIDI is tightly bound to pihpsr.
+// The implementation of DoTheMIDI is tightly bound to pihpsr and contains
+// tons of invocations of g_idle_add with routines from ext.c
 //
 
 void DoTheMidi(enum MIDIaction code, enum MIDItype type, int val);
index 0e6ebcafadbd551f723b01ca88b3ff4dec59cfd2..cb0ddceae5ad8f87c9c75faecdf8fae22bb19b9e 100644 (file)
--- a/midi.inp
+++ b/midi.inp
@@ -3,31 +3,72 @@
 #
 # Note that the Attenuator is implemented twice, as a key and as a wheel
 # The key is suitable for radios with a step (ALEX) attenuator, the wheel
-# fits best for radios with a programmable attenuator (0-31 dB)
+# fits best for radios with a programmable attenuator (0-31 dB).
+# The button (Key 2) also works for STEMlab and CHARLY25
+#
+# The preamp button (Key 1) only has function with STEMlab and CHARLY25
+#
+# Do not assign the "Key" with number 31. You will unintentionally
+# "push" it most of the times you change the VFO frequency.
+#
+# NOTE: we could just leave out all lines with ACTION=NONE. In this case
+#       a diagnostic message ("unknown MIDI event") is printed to stderr.
 #
 DEVICE=CMD PL-1
+#
+# Big Wheel and Big Slider
+#
 CTRL=31 WHEEL THR=59 61 63 65 67 69 ACTION=VFO           # Big wheel:    : main VFO knob
+KEY=31 ACTION=NONE                                       # Button integrated in the big wheel (do not assign)
 PITCH ACTION=AFGAIN                                      # Big slider    : AF gain
+#
+# 8 Knobs (top left).
+# Note that you can push each knob and this generates
+# Note On/Off messages for KEY=0...8 which we do not
+# assign: we want to glue labels on the Controller and therefore
+# we do not have two labels per knob.
+#
+CTRL=0 WHEEL THR=-1 -1 63 65 128 128 ACTION=ATT          # Knob 1        : RX att
+KEY=0                                ACTION=NONE         # Push Knob 1   : (unassigned)
+CTRL=1 WHEEL THR=-1 -1 63 65 128 128 ACTION=COMPRESS     # Knob 2        : TX compression
+KEY=1                                ACTION=NONE         # Push Knob 1   : (unassigned)
+CTRL=2 WHEEL THR=-1 -1 63 65 128 128 ACTION=RITVAL       # Knob 3        : RIT value
+KEY=2                                ACTION=NONE         # Push Knob 1   : (unassigned)
+CTRL=3 WHEEL THR=-1 -1 63 65 128 128 ACTION=PANLOW       # Knob 4        : Panadapter low
+KEY=4                                ACTION=NONE         # Push Knob 1   : (unassigned)
+CTRL=4 WHEEL THR=-1 -1 63 65 128 128 ACTION=AGC          # Knob 5        : AGC
+KEY=4                                ACTION=NONE         # Push Knob 1   : (unassigned)
+CTRL=5 WHEEL THR=-1 -1 63 65 128 128 ACTION=MICGAIN      # Knob 6        : MIC gain
+KEY=5                                ACTION=NONE         # Push Knob 1   : (unassigned)
+CTRL=6 WHEEL THR=-1 -1 63 65 128 128 ACTION=RFPOWER      # Knob 7        : TX drive
+KEY=6                                ACTION=NONE         # Push Knob 1   : (unassigned)
+CTRL=7 WHEEL THR=-1 -1 63 65 128 128 ACTION=FILTERUP     # Knob 8        : cycle through the filters
+KEY=7                                ACTION=NONE         # Push Knob 1   : (unassigned)
+#
+# 8 Keys (below the 8 Knobs)
+#
 KEY=16 ACTION=PREAMP                                    # Key 1         : Cycle through Preamp settings
 KEY=17 ACTION=ATT                                       # Key 2         : Cycle through ATT (Alex ATT) settings
-KEY=18 ACTION=RITTOGGLE                                         # Key 3         : RIT on/off
-KEY=19 ACTION=NONE                                      # Key 4         :
-KEY=20 ACTION=NONE                                      # Key 5         :
-KEY=21 ACTION=NONE                                      # Key 6         :
-KEY=22 ACTION=NONE                                      # Key 7         :
-KEY=23 ACTION=NONE                                      # Key 8         :
+KEY=18 ACTION=RITCLEAR                                          # Key 3         : Clear RIT value and disable RIT
+KEY=19 ACTION=CTUN                                      # Key 4         : toggle CTUN
+KEY=20 ACTION=NOISEBLANKER                              # Key 5         : cycle through NB settings
+KEY=21 ACTION=NOISEREDUCTION                            # Key 6         : cycle through NR settings
+KEY=22 ACTION=VOX                                       # Key 7         : toggle VOX
+KEY=23 ACTION=AGCATTACK                                         # Key 8         : cycle AGC fast/medium/slow
+#
+# "other" keys
+# Note that the "DECK" key switches the MIDI channel of the device.
+#
 KEY=24 ACTION=TUNE                                       # LOAD    button: TUNE on/off
+KEY=25 ACTION=LOCK                                       # LOCK    button: Lock VFO(s)
+KEY=26 ACTION=PURESIGNAL                                 # DECK    button: toggle PURESIGNAL
 KEY=27 ACTION=SWAPVFO                                   # SCRATCH button: Swap VFOs A and B
+KEY=31 ACTION=NONE                                       # Button integrated in the big wheel (do not assign)
+KEY=32 ACTION=VFOA2B                                     # SYNC    button: Frequency VFO A -> VFO B
+KEY=33 ACTION=VFOB2A                                     # TAP     button: Frequency VFO B -> VFO A
 KEY=34 ACTION=MOX                                        # CUE     button: MOX on/off
+KEY=35 ACTION=SPLIT                                      # >||     button: toggle Split
 KEY=36 ACTION=MODEDOWN                                  # <<      button: Mode down
 KEY=37 ACTION=MODEUP                                    # >>      button: Mode up
 KEY=38 ACTION=BANDDOWN                                  # -       button: Band down
 KEY=39 ACTION=BANDUP                                    # +       button: Band up
-CTRL=0 WHEEL THR=-1 -1 63 65 128 128 ACTION=ATT          # Knob 1        : RX att
-CTRL=1 WHEEL THR=-1 -1 63 65 128 128 ACTION=COMPRESS     # Knob 2        : TX compression
-CTRL=2 WHEEL THR=-1 -1 63 65 128 128 ACTION=RITVAL       # Knob 3        : RIT value
-CTRL=3 WHEEL THR=-1 -1 63 65 128 128 ACTION=PANLOW       # Knob 4        : Panadapter low
-CTRL=4 WHEEL THR=-1 -1 63 65 128 128 ACTION=AGC          # Knob 5        : AGC
-CTRL=5 WHEEL THR=-1 -1 63 65 128 128 ACTION=MICGAIN      # Knob 6        : MIC gain
-CTRL=6 WHEEL THR=-1 -1 63 65 128 128 ACTION=RFPOWER      # Knob 7        : TX drive
-CTRL=7 WHEEL THR=-1 -1 63 65 128 128 ACTION=FILTERUP     # Knob 8        : cycle through the filters
diff --git a/midi2.c b/midi2.c
index 0d4d300f1747b930178963597d0a97e1c659fca2..9145137817638733b4002a37ac80f3706252ad3a 100644 (file)
--- a/midi2.c
+++ b/midi2.c
@@ -63,7 +63,6 @@ void NewMidiEvent(enum MIDIevent event, int channel, int note, int val) {
                    if (desc->type == MIDI_KNOB) {
                        // normalize value to 0 - 100
                        new = (val*100)/16383;
-                       fprintf(stderr,"PITCH calc: val=%d new=%d\n", val,new);
                        DoTheMidi(desc->action, desc->type, new);
                    }
                    break;
@@ -75,6 +74,12 @@ void NewMidiEvent(enum MIDIevent event, int channel, int note, int val) {
            desc=desc->next;
        }
     }
+    if (!desc) {
+      // Nothing found. This is nothing to worry about, but log the key to stderr
+      if (event == MIDI_PITCH) fprintf(stderr, "Unassigned PitchBend Value=%d\n", val);
+      if (event == MIDI_NOTE ) fprintf(stderr, "Unassigned Key Note=%d Val=%d\n", note, val);
+      if (event == MIDI_CTRL ) fprintf(stderr, "Unassigned Controller Ctl=%d Val=%d\n", note, val);
+    }
 }
 
 /*
@@ -86,27 +91,38 @@ static struct {
   enum MIDIaction action;
   const char *str;
 } ActionTable[] = {
-        { VFO,          "VFO"},
-        { TUNE,         "TUNE"},
-        { MOX,          "MOX"},
         { AF_GAIN,      "AFGAIN"},
-        { MIC_VOLUME,   "MICGAIN"},
-        { TX_DRIVE,     "RFPOWER"},
-        { ATT,          "ATT"},
-        { PRE,          "PREAMP"},
         { AGC,          "AGC"},
-        { COMPRESS,     "COMPRESS"},
-        { RIT_ONOFF,    "RITTOGGLE"},
-        { RIT_VAL,      "RITVAL"},
-        { PAN_HIGH,     "PANHIGH"},
-        { PAN_LOW,      "PANLOW"},
-        { BAND_UP,      "BANDUP"},
+       { AGCATTACK,    "AGCATTACK"},
+        { ATT,          "ATT"},
         { BAND_DOWN,    "BANDDOWN"},
-        { FILTER_UP,    "FILTERUP"},
+        { BAND_UP,      "BANDUP"},
+        { COMPRESS,     "COMPRESS"},
+       { CTUN,         "CTUN"},
         { FILTER_DOWN,  "FILTERDOWN"},
-       { MODE_UP,      "MODEUP"},
+        { FILTER_UP,    "FILTERUP"},
+       { LOCK,         "LOCK"},
+        { MIC_VOLUME,   "MICGAIN"},
        { MODE_DOWN,    "MODEDOWN"},
+       { MODE_UP,      "MODEUP"},
+        { MOX,          "MOX"},
+       { NB,           "NOISEBLANKER"},
+       { NR,           "NOISEREDUCTION"},
+        { PAN_HIGH,     "PANHIGH"},
+        { PAN_LOW,      "PANLOW"},
+        { PRE,          "PREAMP"},
+       { PS,           "PURESIGNAL"},
+        { RIT_CLEAR,    "RITCLEAR"},
+        { RIT_VAL,      "RITVAL"},
+       { SPLIT,        "SPLIT"},
        { SWAP_VFO,     "SWAPVFO"},
+        { TUNE,         "TUNE"},
+        { TX_DRIVE,     "RFPOWER"},
+        { VFO,          "VFO"},
+       { VFO_A2B,      "VFOA2B"},
+       { VFO_B2A,      "VFOB2A"},
+       { VOX,          "VOX"},
+        { ACTION_NONE,  "NONE"},
         { ACTION_NONE,  NULL}
 };
 
@@ -118,7 +134,10 @@ static enum MIDIaction keyword2action(char *s) {
     int i=0;
 
     for (i=0; 1; i++) {
-       if (ActionTable[i].str == NULL) return ACTION_NONE;
+       if (ActionTable[i].str == NULL) {
+         fprintf(stderr,"MIDI: action keyword %s NOT FOUND.\n", s);
+         return ACTION_NONE;
+       }
        if (!strcmp(s, ActionTable[i].str)) return ActionTable[i].action;
    }
    /* NOTREACHED */
@@ -170,8 +189,8 @@ void MIDIstartup() {
         continue; // nothing more in this line
       }
       chan=-1;  // default: any channel
-      lt3=lt2=lt1=0;
-      ut3=ut2=ut1=127;
+      lt3=lt2=lt1=-1;
+      ut3=ut2=ut1=128;
       onoff=0;
       event=EVENT_NONE;
       type=TYPE_NONE;
diff --git a/midi3.c b/midi3.c
index 8e0c33f5dcc3b6096deb800ce51c40a69c0f6df2..d654dca08701e728afcd925f052e7d85b8f2a6ac 100644 (file)
--- a/midi3.c
+++ b/midi3.c
@@ -18,6 +18,7 @@
 #include "new_menu.h"
 #include "sliders.h"
 #include "ext.h"
+#include "agc.h"
 #include "midi.h"
 
 void DoTheMidi(enum MIDIaction action, enum MIDItype type, int val) {
@@ -33,7 +34,9 @@ void DoTheMidi(enum MIDIaction action, enum MIDItype type, int val) {
            }
            break;    
        case VFO: // only wheel supported
-           if (type == MIDI_WHEEL) g_idle_add(ext_vfo_step, (gpointer)(uintptr_t) val);
+           if (type == MIDI_WHEEL) {
+               g_idle_add(ext_vfo_step, (gpointer)(uintptr_t) val);
+           }
            break;
        case TUNE: // only key supported
            if (type == MIDI_KEY) {
@@ -150,18 +153,23 @@ void DoTheMidi(enum MIDIaction action, enum MIDItype type, int val) {
                }
            }
            break;
-       case RIT_ONOFF:  // only key supported
+       case RIT_CLEAR:  // only key supported
            if (type == MIDI_KEY) {
-               vfo[active_receiver->id].rit_enabled = !vfo[active_receiver->id].rit_enabled;
+               // this clears the RIT value and disables RIT
+               vfo[active_receiver->id].rit = new;
+               vfo[active_receiver->id].rit_enabled = 0;
                g_idle_add(ext_vfo_update, NULL);
            }
            break;
        case RIT_VAL:   // only wheel supported
            if (type == MIDI_WHEEL) {
+               // This changes the RIT value. If a value of 0 is reached,
+               // RIT is disabled
                new = vfo[active_receiver->id].rit + val*rit_increment;
                if (new >  9999) new= 9999;
                if (new < -9999) new=-9999;
                vfo[active_receiver->id].rit = new;
+               vfo[active_receiver->id].rit_enabled = (new != 0);
                g_idle_add(ext_vfo_update, NULL);
            }
            break;
@@ -196,6 +204,8 @@ void DoTheMidi(enum MIDIaction action, enum MIDItype type, int val) {
                }
                g_idle_add(ext_update_att_preamp, NULL);
            } else {
+               // Note that these preamps are not present in most
+               // SDR hardware.
                new=active_receiver->preamp+1;
                if (new > 1) new=0;
                active_receiver->preamp= (new == 1);
@@ -227,8 +237,104 @@ void DoTheMidi(enum MIDIaction action, enum MIDItype type, int val) {
            }
            break;
        case COMPRESS:
+           // Use values in the range 0 ... 20
+           if (type == MIDI_WHEEL) {
+              dnew=transmitter->compressor_level + val;
+             if (dnew > 20.0) dnew=20.0;
+             if (dnew < 0 ) dnew=0;
+           } else if (type == MIDI_KNOB){
+             dnew=(20.0*val)/100.0;
+           } else {
+               break;
+           }
+           transmitter->compressor_level=dnew;
+           if (dnew < 0.5) transmitter->compressor=0;
+           if (dnew > 0.5) transmitter->compressor=1;
+           g_idle_add(ext_vfo_update, NULL);
+           break;
+       case NB:
+           // cycle through NoiseBlanker settings
+           if (active_receiver->nb) {
+               active_receiver->nb = 0;
+               active_receiver->nb2= 1;
+           } else if (active_receiver->nb2) {
+               active_receiver->nb = 0;
+               active_receiver->nb2= 0;
+           } else {
+               active_receiver->nb = 1;
+               active_receiver->nb2= 0;
+           }
+           g_idle_add(ext_vfo_update, NULL);
+           break;
+       case NR:
+           // cycle through NoiseReduction settings
+           if (active_receiver->nr) {
+               active_receiver->nr = 0;
+               active_receiver->nr2= 1;
+           } else if (active_receiver->nr2) {
+               active_receiver->nr = 0;
+               active_receiver->nr2= 0;
+           } else {
+               active_receiver->nr = 1;
+               active_receiver->nr2= 0;
+           }
+           g_idle_add(ext_vfo_update, NULL);
+           break;
+       case VOX:
+           // toggle VOX
+           vox_enabled = !vox_enabled;
+           g_idle_add(ext_vfo_update, NULL);
+           break;
+       case CTUN:
+           // toggle CTUN
+           new=active_receiver->id;
+           if(!vfo[new].ctun) {
+               vfo[new].ctun=1;
+               vfo[new].offset=0;
+           } else {
+               vfo[new].ctun=0;
+           }
+           vfo[new].ctun_frequency=vfo[new].frequency;
+           set_offset(active_receiver,vfo[new].offset);
+           g_idle_add(ext_vfo_update, NULL);
+           break;
+       case PS:
+           // toggle PURESIGNAL
+           new=!(transmitter->puresignal);
+           g_idle_add(ext_tx_set_ps,(gpointer) (uintptr_t) new);
+           break;
+       case SPLIT:
+           // toggle split mode
+           if(!split) {
+               split=1;
+               tx_set_mode(transmitter,vfo[VFO_B].mode);
+           } else {
+               split=0;
+               tx_set_mode(transmitter,vfo[VFO_A].mode);
+           }
+           g_idle_add(ext_vfo_update, NULL);
+           break;
+       case VFO_A2B:
+           g_idle_add(ext_vfo_a_to_b, NULL);
+           break;
+       case VFO_B2A:
+           g_idle_add(ext_vfo_b_to_a, NULL);
+           break;
+       case LOCK:
+           locked=!locked;
+           g_idle_add(ext_vfo_update, NULL);
+           break;
+       case AGCATTACK:
+           new=active_receiver->agc + 1;
+           if (new > AGC_FAST) new=0;
+           active_receiver->agc=new;
+           g_idle_add(ext_vfo_update, NULL);
+           break;
        case ACTION_NONE:
-            fprintf(stderr,"Unimplemented in DoTheMidi: A=%d T=%d val=%d\n", action, type, val);
+           // No error message, this is the "official" action for un-used controller buttons.
            break;
+       default:
+           // This means we have forgotten to implement an action
+           fprintf(stderr,"Unimplemented MIDI action: A=%d\n", (int) action);
     }
 }
index 3ef7d433bf6dfa6e2c398833731299a14593b586..b4a65a3e3712f3fb10e910f2ec1769f8a3245e86 100644 (file)
@@ -565,7 +565,6 @@ static void process_ozy_input_buffer(unsigned char  *buffer) {
   int nreceivers;
 
 #ifdef PURESIGNAL
-    // 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.
@@ -849,7 +848,6 @@ void ozy_send_buffer() {
   int nreceivers;
 
 #ifdef PURESIGNAL
-    // 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.
@@ -957,22 +955,23 @@ void ozy_send_buffer() {
     // 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
+    // If feedback is to the second ADC, leave RX1 ANT settings untouched
     //
-    if (isTransmitting() && transmitter->puresignal) i=receiver[PS_RX_FEEDBACK]->feedback_antenna;
+    if (isTransmitting() && transmitter->puresignal && receiver[PS_RX_FEEDBACK]->adc == 0) i=receiver[PS_RX_FEEDBACK]->feedback_antenna;
 #endif
     switch(i) {
-      case 3:  // Alex: RX2 IN, ANAN: EXT1, ANAN7000: EXT
-        output_buffer[C3]|=0xC0;
+      case 3:  // Alex: RX2 IN, ANAN: EXT1, ANAN7000: still uses internal feedback 
+        output_buffer[C3]|=0x80;
         break;
       case 4:  // Alex: RX1 IN, ANAN: EXT2, ANAN7000: RX BYPASS
         output_buffer[C3]|=0xA0;
         break;
       default:
+       // RX1_OUT and RX1_ANT bits remain zero
         break;
     }
 
 
-// TODO - add Alex TX relay, duplex, receivers Mercury board frequency
     output_buffer[C4]=0x04;  // duplex
 
     // 0 ... 7 maps on 1 ... 8 receivers
@@ -1051,8 +1050,8 @@ void ozy_send_buffer() {
           output_buffer[C0]=0x04+(current_rx*2);
 #ifdef PURESIGNAL
           int v=receiver[current_rx/2]->id;
-         // DL1YCF: for the "last" receiver, v is out of range. In this case,
-         //         use TX frequency also while receiving
+         // for the "last" receiver, v is out of range. In this case,
+         // use TX frequency also while receiving
           if((isTransmitting() && transmitter->puresignal) || (v >= MAX_VFOS)) {
             long long txFrequency;
             if(active_receiver->id==VFO_A) {
@@ -1178,7 +1177,7 @@ void ozy_send_buffer() {
         output_buffer[C4]=0x00;
   
         if(radio->device==DEVICE_HERMES || radio->device==DEVICE_ANGELIA || radio->device==DEVICE_ORION || radio->device==DEVICE_ORION2) {
-         // DL1YCF: if attenuation is zero, then disable attenuator
+         // if attenuation is zero, then disable attenuator
          i = adc_attenuation[receiver[0]->adc] & 0x1F;
           if (i >0) output_buffer[C4]=0x20| i;
         } else {
@@ -1193,7 +1192,7 @@ void ozy_send_buffer() {
         output_buffer[C1]=0x00;
         if(receivers==2) {
           if(radio->device==DEVICE_HERMES || radio->device==DEVICE_ANGELIA || radio->device==DEVICE_ORION || radio->device==DEVICE_ORION2) {
-           // DL1YCF: if attenuation is zero, then disable attenuator
+           // if attenuation is zero, then disable attenuator
            i = adc_attenuation[receiver[1]->adc] & 0x1F;
             if (i > 0) output_buffer[C1]=0x20|i;
           }
@@ -1209,33 +1208,20 @@ void ozy_send_buffer() {
         // need to add tx attenuation and rx ADC selection
         output_buffer[C0]=0x1C;
         output_buffer[C1]=0x00;
+        output_buffer[C2]=0x00;
 #ifdef PURESIGNAL
-
-       // 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?
+        // if n_adc == 1, there is only a single ADC, so we can leave everything
+        // set to zero
+       if (n_adc  > 1) {
+           // Angelia, Orion, Orion2 have two ADCs, so we use the ADC settings from the menu
+            output_buffer[C1]|=receiver[0]->adc;                       // RX1 bound to ADC of first receiver
+            output_buffer[C1]|=(receiver[1]->adc<<2);                  // RX2 actually unsused with PURESIGNAL
+            output_buffer[C1]|=receiver[1]->adc<<4;                    // RX3 bound to ADC of second receiver
+            output_buffer[C1]|=(receiver[PS_RX_FEEDBACK]->adc<<6);     // RX4 is PS_RX_Feedbacka
+                                                                       // Usually ADC0, but if feedback is to
+                                                                       // RX2 input it must be ADC1 (see ps_menu.c)
+           // RX5 is hard-wired to the TX DAC and needs no ADC setting.
        }
-        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
         output_buffer[C1]|=receiver[0]->adc;
         output_buffer[C1]|=(receiver[1]->adc<<2);
@@ -1282,8 +1268,19 @@ void ozy_send_buffer() {
       case 10:
         output_buffer[C0]=0x24;
         output_buffer[C1]=0x00;
+
         if(isTransmitting()) {
-          output_buffer[C1]|=0x80; // ground RX2 on transmit, bit0-6 are Alex2 filters
+#ifdef PURESIGNAL
+         // If we are using the RX2 jack for PURESIGNAL RX feedback, then we MUST NOT ground
+         // the ADC2 input upon TX.
+         if (transmitter->puresignal && receiver[PS_RX_FEEDBACK]->adc == 1) {
+           // Note that this statement seems to have no effect since
+           // one cannot goto to "manual filter setting" for the ALEX2 board individually
+            output_buffer[C1]|=0x40; // Set ADC2 filter board to "ByPass"
+         } else
+#endif
+
+            output_buffer[C1]|=0x80; // ground RX2 on transmit, bit0-6 are Alex2 filters
         }
         output_buffer[C2]=0x00;
         if(receiver[0]->alex_antenna==5) { // XVTR
@@ -1453,7 +1450,7 @@ static void metis_restart() {
   current_rx=0;
   command=1;
 #else
-  // DL1YCF this is the original code, which does not do what it pretends ....
+  // DL1YCF: this is the original code, which does not do what it pretends ....
   // send commands twice
   command=1;
   do {
index bd0b987452f1b5772adac3a48e435e873769991a..a1ece79c6d42b53777e116e62479ee83640fed85 100644 (file)
@@ -1,9 +1,12 @@
 #ifdef PORTAUDIO
 //
-// DL1YCF: if PortAudio is NOT used, this file is empty, and audio.c
-//         is used instead.
-//         Here we also implement two (hopefully useful) functions:
-//         - a dummy two-tone 'Microphone' device
+// Contribution from DL1YCF (Christoph van Wullen)
+//
+// Alternate "audio" module using PORTAUDIO instead of ALSA
+// (e.g. on MacOS)
+//
+// If PortAudio is NOT used, this file is empty, and audio.c
+// is used instead.
 //
 
 #include <gtk/gtk.h>
index 5008ff0cbc91d0ff52beb8ea454b3fc536b56061..5213ed3646e0a669863b7bd38256835cf84fb761 100644 (file)
--- a/ps_menu.c
+++ b/ps_menu.c
@@ -106,15 +106,8 @@ static gboolean delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_d
 }
 
 //
-//
-// DL1YCF: had repeated seg-faults, possibly this is not thread-safe.
-//         executing it at regular intervals in the glib main loop
-//         does the same thing.
-//         We now call this function every 100 msec, therefore we can
-//         adjust the tx attenuation upon each invocation.
-//         The massive alloc/free of the label is completely unnecessary
-//         and has been removed, the small string to be displayed is
-//         prepeared in "label".
+// This is called every 100 msec and therefore
+// must be a state machine
 //
 static int info_thread(gpointer arg) {
   static int info[INFO_SIZE];
@@ -264,9 +257,24 @@ static int info_thread(gpointer arg) {
     return TRUE;
 }
 
+//
+// Set "RX1 ANT", "RX1 OUT", and ADC settings for the PS feedback signal
+//
 static void ps_ant_cb(GtkWidget *widget, gpointer data) {
+  int val = (int) (uintptr_t) data;
   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
-    receiver[PS_RX_FEEDBACK]->feedback_antenna = (int) (uintptr_t) data;
+    switch (val) {
+      case 0:  // AUTO (Internal), feedback goes to first ADC
+      case 3:  // EXT1,            feedback goes to first ADC
+      case 4:  // EXT2,            feedback goes to first ADC
+       receiver[PS_RX_FEEDBACK]->feedback_antenna = (int) (uintptr_t) data;
+       receiver[PS_RX_FEEDBACK]->adc              = 0;
+       break;
+      case 99: // RX2,              feedback goes to second ADC
+       receiver[PS_RX_FEEDBACK]->feedback_antenna = 0;
+       receiver[PS_RX_FEEDBACK]->adc              = 1;
+       break;
+    }
   }
 }
 
@@ -276,6 +284,7 @@ static void enable_cb(GtkWidget *widget, gpointer data) {
 
 static void auto_cb(GtkWidget *widget, gpointer data) {
   transmitter->auto_on=gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
+  // switching OFF auto sets the attenuation to zero
   if(!transmitter->auto_on) {
     transmitter->attenuation=0;
   }
@@ -283,6 +292,13 @@ static void auto_cb(GtkWidget *widget, gpointer data) {
 }
 
 static void resume_cb(GtkWidget *widget, gpointer data) {
+  // Set the attenuation to zero if auto-adjusting and resuming.
+  // A very high attenuation value here could lead to no PS calculation
+  // done in WDSP, and hence no attenuation adjustment.
+  // If not auto-adjusting, do not change attenuation value.
+  if(transmitter->auto_on) {
+    transmitter->attenuation=0;
+  }
   SetPSControl(transmitter->id, 0, 0, 1, 0);
 }
 
@@ -297,7 +313,6 @@ static void feedback_cb(GtkWidget *widget, gpointer data) {
 }
 
 static void reset_cb(GtkWidget *widget, gpointer data) {
-  transmitter->attenuation=0;
   SetPSControl(transmitter->id, 1, 0, 0, 0);
 }
 
@@ -398,6 +413,14 @@ void ps_menu(GtkWidget *parent) {
   row++;
   col=0;
 
+  //
+  // Selection of feedback path for PURESIGNAL
+  //
+  // AUTO              Using internal feedback (to ADC0)
+  // EXT1              Using EXT1 jacket (to ADC0), ANAN-7000: still uses AUTO
+  // EXT2              Using EXT2 jacket (to ADC0), ANAN-7000: "EXT2 is called RX Bypass"
+  // RX2               Using RX2  jacket (to ADC1)
+  //
   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);
@@ -405,26 +428,39 @@ void ps_menu(GtkWidget *parent) {
 
   GtkWidget *ps_ant_auto=gtk_radio_button_new_with_label(NULL,"AUTO");
   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ps_ant_auto), 
-    (receiver[PS_RX_FEEDBACK]->feedback_antenna!=3) && (receiver[PS_RX_FEEDBACK]->feedback_antenna!=4));
+    (receiver[PS_RX_FEEDBACK]->feedback_antenna == 0) && (receiver[PS_RX_FEEDBACK]->adc == 0));
   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_toggle_button_set_active (GTK_TOGGLE_BUTTON (ps_ant_ext1), receiver[PS_RX_FEEDBACK]->feedback_antenna==3);
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ps_ant_ext1),
+    (receiver[PS_RX_FEEDBACK]->feedback_antenna==3) && (receiver[PS_RX_FEEDBACK]->adc == 0));
   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_toggle_button_set_active (GTK_TOGGLE_BUTTON (ps_ant_ext2), receiver[PS_RX_FEEDBACK]->feedback_antenna==4);
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ps_ant_ext2),
+    (receiver[PS_RX_FEEDBACK]->feedback_antenna==4) && (receiver[PS_RX_FEEDBACK]->adc == 0));
   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);
+  col++;
+
+  if (n_adc > 1) {
+    // If there are two ADCs, we may choose to use the second ADC for PS_RX_FEEDBACK
+    GtkWidget *ps_ant_rx2=gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(ps_ant_auto),"RX2");
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ps_ant_rx2), receiver[PS_RX_FEEDBACK]->adc==1);
+    gtk_widget_show(ps_ant_rx2);
+    gtk_grid_attach(GTK_GRID(grid), ps_ant_rx2, col, row, 1, 1);
+    g_signal_connect(ps_ant_rx2,"toggled", G_CALLBACK(ps_ant_cb), (gpointer) (long) 99);
+  }
 
   row++;
+
   col=0;
   feedback_l=gtk_label_new("Feedback Lvl");
   gtk_widget_show(feedback_l);
@@ -518,9 +554,11 @@ void ps_menu(GtkWidget *parent) {
 
 // DL1YCF: This is not the default setting,
 // but in my experience in behaves better in difficult situations.
-  ints=8;
-  spi=512;
-  ampdelay=100e-9;
+// This is commented out because it is not recommended by the
+// WDSP manual.
+//  ints=8;
+//  spi=512;
+//  ampdelay=100e-9;
 
   SetPSIntsAndSpi(transmitter->id, ints, spi);
   SetPSStabilize(transmitter->id, stbl);
diff --git a/radio.c b/radio.c
index 74a4445fa3e10b99fe03244d8d616898455d4072..b646170f99c41d65a1936da1d8abeec8c0932162 100644 (file)
--- a/radio.c
+++ b/radio.c
@@ -294,6 +294,7 @@ double vox_hang=250.0;
 int vox=0;
 int CAT_cw_is_active=0;
 int cw_key_hit=0;
+int n_adc=1;
 
 int diversity_enabled=0;
 double i_rotate[2]={1.0,1.0};
@@ -327,8 +328,8 @@ void reconfigure_radio() {
     } else {
       gtk_fixed_move(GTK_FIXED(fixed),sliders,0,y);
     }
-    gtk_widget_show_all(sliders);  // DL1YCF this shows both C25 and Alex ATT/Preamp sliders
-    att_type_changed();            // DL1YCF added here to hide the â€žwrong“ ones.
+    gtk_widget_show_all(sliders);  // ... this shows both C25 and Alex ATT/Preamp sliders
+    att_type_changed();            // ... and this hides the â€žwrong“ ones.
   } else {
     if(sliders!=NULL) {
       gtk_container_remove(GTK_CONTAINER(fixed),sliders); 
@@ -421,7 +422,7 @@ void start_radio() {
                           radio->info.network.mac_address[5],
                           radio->info.network.interface_name);
 
-fprintf(stderr,"title: length=%d\n", (int)strlen(text));
+//fprintf(stderr,"title: length=%d\n", (int)strlen(text));
 
   gtk_window_set_title (GTK_WINDOW (top_window), text);
 
@@ -482,6 +483,41 @@ fprintf(stderr,"title: length=%d\n", (int)strlen(text));
       break;
   }
  
+  // Code moved here from rx_menu because n_adc is of general interest:
+  // Determine Number of ADCs.
+  switch(protocol) {
+    case ORIGINAL_PROTOCOL:
+      switch(device) {
+        case DEVICE_METIS:
+          n_adc=1;  // No support for multiple MERCURY cards on a single ATLAS bus.
+          break;
+        case DEVICE_HERMES:
+        case DEVICE_HERMES_LITE:
+          n_adc=1;
+          break;
+        default:
+          n_adc=2;
+          break;
+      }
+      break;
+    case NEW_PROTOCOL:
+      switch(device) {
+        case NEW_DEVICE_ATLAS:
+          n_adc=1; // No support for multiple MERCURY cards on a single ATLAS bus.
+          break;
+        case NEW_DEVICE_HERMES:
+        case NEW_DEVICE_HERMES2:
+        case NEW_DEVICE_HERMES_LITE:
+          n_adc=1;
+          break;
+        default:
+          n_adc=2;
+          break;
+      }
+      break;
+    default:
+      break;
+  }
 
   adc_attenuation[0]=0;
   adc_attenuation[1]=0;
@@ -531,15 +567,22 @@ fprintf(stderr,"title: length=%d\n", (int)strlen(text));
   rx_height=rx_height/receivers;
 
 
-fprintf(stderr,"Create %d receivers: height=%d\n",receivers,rx_height);
+//fprintf(stderr,"Create %d receivers: height=%d\n",receivers,rx_height);
   for(i=0;i<RECEIVERS;i++) {
-    receiver[i]=create_receiver(i, buffer_size, fft_size, display_width, updates_per_second, display_width, rx_height);
-    setSquelch(receiver[i]);
+    // A receiver may be un-unsed upon program start, but can be activated through the radio menu later.
+    // Create it here with height 0. Make sure to call g_object_ref for this one as well,
+    // this cures the seg-faults observed when switching beteen 1 and 2 RX in the radio menu.
     if(i<receivers) {
-      receiver[i]->x=0;
-      receiver[i]->y=y;
-      gtk_fixed_put(GTK_FIXED(fixed),receiver[i]->panel,0,y);
-      g_object_ref((gpointer)receiver[i]->panel);
+      receiver[i]=create_receiver(i, buffer_size, fft_size, display_width, updates_per_second, display_width, rx_height);
+    } else {
+      receiver[i]=create_receiver(i, buffer_size, fft_size, display_width, updates_per_second, display_width, 0        );
+    }
+    setSquelch(receiver[i]);
+    receiver[i]->x=0;
+    receiver[i]->y=y;
+    gtk_fixed_put(GTK_FIXED(fixed),receiver[i]->panel,0,y);
+    g_object_ref((gpointer)receiver[i]->panel);
+    if (i<receivers) {
       set_displaying(receiver[i],1);
       y+=rx_height;
     } else {
@@ -553,7 +596,7 @@ fprintf(stderr,"Create %d receivers: height=%d\n",receivers,rx_height);
 
   active_receiver=receiver[0];
 
-  fprintf(stderr,"Create transmitter\n");
+  //fprintf(stderr,"Create transmitter\n");
   transmitter=create_transmitter(CHANNEL_TX, buffer_size, fft_size, updates_per_second, display_width, tx_height);
   transmitter->x=0;
   transmitter->y=VFO_HEIGHT;
@@ -604,7 +647,7 @@ fprintf(stderr,"Create %d receivers: height=%d\n",receivers,rx_height);
 //#endif
 
   if(display_sliders) {
-fprintf(stderr,"create sliders\n");
+//fprintf(stderr,"create sliders\n");
     sliders = sliders_init(display_width,SLIDERS_HEIGHT);
     gtk_fixed_put(GTK_FIXED(fixed),sliders,0,y);
     y+=SLIDERS_HEIGHT;
@@ -664,20 +707,21 @@ void disable_rigctl() {
  
 
 void radio_change_receivers(int r) {
+  // The button in the radio menu will call this function even if the
+  // number of receivers has not changed.
+  if (receivers == r) return;
   fprintf(stderr,"radio_change_receivers: from %d to %d\n",receivers,r);
   switch(r) {
     case 1:
-      if(receivers==2) {
-        set_displaying(receiver[1],0);
-        gtk_container_remove(GTK_CONTAINER(fixed),receiver[1]->panel);
-      }
-      receivers=1;
-      break;
+       set_displaying(receiver[1],0);
+       gtk_container_remove(GTK_CONTAINER(fixed),receiver[1]->panel);
+       receivers=1;
+       break;
     case 2:
-      gtk_fixed_put(GTK_FIXED(fixed),receiver[1]->panel,0,0);
-      set_displaying(receiver[1],1);
-      receivers=2;
-      break;
+       gtk_fixed_put(GTK_FIXED(fixed),receiver[1]->panel,0,0);
+       set_displaying(receiver[1],1);
+       receivers=2;
+       break;
   }
   reconfigure_radio();
   active_receiver=receiver[0];
@@ -688,16 +732,21 @@ void radio_change_receivers(int r) {
 
 void radio_change_sample_rate(int rate) {
   int i;
+  
   switch(protocol) {
     case ORIGINAL_PROTOCOL:
-      old_protocol_stop();
-      for(i=0;i<receivers;i++) {
-        receiver_change_sample_rate(receiver[i],rate);
-      }
-      old_protocol_set_mic_sample_rate(rate);
-      old_protocol_run();
+      // The radio menu calls this function even if the sample rate
+      // has not changed. Do nothing in this case.
+      if (receiver[0]->sample_rate != rate) {
+        old_protocol_stop();
+        for(i=0;i<receivers;i++) {
+          receiver_change_sample_rate(receiver[i],rate);
+        }
+        old_protocol_set_mic_sample_rate(rate);
+        old_protocol_run();
 #ifdef PURESIGNAL
-      tx_set_ps_sample_rate(transmitter,rate);
+        tx_set_ps_sample_rate(transmitter,rate);
+      }
 #endif
       break;
 #ifdef LIMESDR
@@ -876,10 +925,11 @@ void setTune(int state) {
       }
       pre_tune_mode=mode;
 
-      // DL1YCF: in USB/DIGU/DSB, tune 1000 Hz above carrier
-      //         in LSB/DIGL,     tune 1000 Hz below carrier
-      //         all other (CW, AM, FM): tune on carrier freq.
-      //         Note: do not look at CW sidetone freq here.
+      //
+      // in USB/DIGU/DSB, tune 1000 Hz above carrier
+      // in LSB/DIGL,     tune 1000 Hz below carrier
+      // all other (CW, AM, FM): tune on carrier freq.
+      //
       switch(mode) {
         case modeLSB:
         case modeDIGL:
@@ -1524,7 +1574,7 @@ void calculate_display_average(RECEIVER *rx) {
 void set_filter_type(int filter_type) {
   int i;
 
-  fprintf(stderr,"set_filter_type: %d\n",filter_type);
+  //fprintf(stderr,"set_filter_type: %d\n",filter_type);
   for(i=0;i<RECEIVERS;i++) {
     receiver[i]->low_latency=filter_type;
     RXASetMP(receiver[i]->id, filter_type);
@@ -1536,7 +1586,7 @@ void set_filter_type(int filter_type) {
 void set_filter_size(int filter_size) {
   int i;
 
-  fprintf(stderr,"set_filter_size: %d\n",filter_size);
+  //fprintf(stderr,"set_filter_size: %d\n",filter_size);
   for(i=0;i<RECEIVERS;i++) {
     receiver[i]->fft_size=filter_size;
     RXASetNC(receiver[i]->id, filter_size);
diff --git a/radio.h b/radio.h
index 8a7656d43ac980d4e3ddff5fc6373d4eb9b59101..8e8c3492fd15a0b2d6982b6198d39654ed031d10 100644 (file)
--- a/radio.h
+++ b/radio.h
@@ -244,6 +244,7 @@ extern double vox_hang;
 extern int vox;
 extern int CAT_cw_is_active;
 extern int cw_key_hit;
+extern int n_adc;
 
 extern int diversity_enabled;
 extern double i_rotate[2];
index 05cb830e26b3972650646bb781a3d36a94458b86..9d40fdb12fde0af5c401644286560d0509f109a7 100644 (file)
@@ -101,14 +101,14 @@ static void load_filters(void) {
 
   if(filter_board==ALEX || filter_board==APOLLO) {
     BAND *band=band_get_current_band();
-    BANDSTACK_ENTRY* entry=bandstack_entry_get_current();
-    setFrequency(entry->frequency);
+    // mode and filters have nothing to do with the filter board
+    //BANDSTACK_ENTRY* entry=bandstack_entry_get_current();
+    //setFrequency(entry->frequency);
     //setMode(entry->mode);
-    set_mode(active_receiver,entry->mode);
-    FILTER* band_filters=filters[entry->mode];
-    FILTER* band_filter=&band_filters[entry->filter];
-    //setFilter(band_filter->low,band_filter->high);
-    set_filter(active_receiver,band_filter->low,band_filter->high);
+    //set_mode(active_receiver,entry->mode);
+    //FILTER* band_filters=filters[entry->mode];
+    //FILTER* band_filter=&band_filters[entry->filter];
+    //set_filter(active_receiver,band_filter->low,band_filter->high);
     if(active_receiver->id==0) {
       set_alex_rx_antenna(band->alexRxAntenna);
       set_alex_tx_antenna(band->alexTxAntenna);
index bdaf835eaa4dd1941aabd7114930ece79b96332b..9a1ed097c1a020a792fbb8af052e35700e52bdb2 100644 (file)
@@ -480,7 +480,7 @@ fprintf(stderr,"reconfigure_receiver: panadapter_init: width:%d height:%d\n",rx-
       gtk_fixed_put(GTK_FIXED(rx->panel),rx->panadapter,0,y);
     } else {
        // set the size
-fprintf(stderr,"reconfigure_receiver: panadapter set_size_request: width:%d height:%d\n",rx->width,height);
+//fprintf(stderr,"reconfigure_receiver: panadapter set_size_request: width:%d height:%d\n",rx->width,height);
       gtk_widget_set_size_request(rx->panadapter, rx->width, height);
       // move the current one
       gtk_fixed_move(GTK_FIXED(rx->panel),rx->panadapter,0,y);
index 81b40dc9810c3dd74dac6af0a32617b1ac517845..052218f52d4c9e80f5429f05c2a526f5a62cd537 100644 (file)
--- a/rigctl.c
+++ b/rigctl.c
@@ -2216,7 +2216,7 @@ void parse_cmd ( char * cmd_input,int len,int client_sock) {
         else if((strcmp(cmd_str,"KY")==0) && (zzid_flag == 0))
                                    { 
                                        if (cw_busy < 0) cat_cw_seen=1;
-                                       // DL1YCF:
+                                       //
                                        // Hamlib produces timeout errors if we are busy here for
                                        // seconds. Therefore we just move the data into a buffer
                                        // that is processed by a separate thread.
@@ -2228,9 +2228,10 @@ void parse_cmd ( char * cmd_input,int len,int client_sock) {
                                        //  - if we can accept new data (buffer space available) : "KY0;"
                                        //  - if buffer is full: "KY1;"
                                        //
-                                       // Note: cw_buse == -1 indicates a "purge KY" situation, where
+                                       // Note: cw_busy == -1 indicates a "purge KY" situation, where
                                        //       all KY commands are accepted and data is discared silently
                                        //       In this case cw_busy is left untouched here.
+                                       //
                                         if (len <= 2) {
                                            if (cw_busy == 1) {
                                                send_resp(client_sock,"KY1;");
index 54f7e0e1567bd84d68c74cb2e058a1edaef8f09d..4cff08f7be0bbe956444a86e7f2388b4815a4637 100644 (file)
--- a/rx_menu.c
+++ b/rx_menu.c
@@ -112,7 +112,6 @@ static void mute_radio_cb(GtkWidget *widget, gpointer data) {
 }
 
 //
-// DL1YCF:
 // possible the device has been changed:
 // call audo_close_output with old device, audio_open_output with new one
 //
@@ -290,45 +289,8 @@ 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;  // No support for multiple MERCURY cards on a single ATLAS bus.
-          break;
-        case DEVICE_HERMES:
-        case DEVICE_HERMES_LITE:
-          n_adc=1;
-          break;
-        default: 
-          n_adc=2;
-          break;
-      }
-      break;
-    case NEW_PROTOCOL:
-      switch(device) {
-        case NEW_DEVICE_ATLAS:
-          n_adc=1; // No support for multiple MERCURY cards on a single ATLAS bus.
-          break;
-        case NEW_DEVICE_HERMES:
-        case NEW_DEVICE_HERMES2:
-        case NEW_DEVICE_HERMES_LITE:
-          n_adc=1;
-          break;
-        default:
-          n_adc=2;
-          break;
-      }
-      break;
-    default:
-      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.
+  // with the current receiver.
   if(n_adc>1) {
     for(i=0;i<n_adc;i++) {
       sprintf(label,"ADC-%d",i);
index 5193be6aeae87820e716a6a97680acfc5ca608a9..d1b7a1c7be3c6cae95ff5821d6eccdfe49568bc3 100644 (file)
--- a/sliders.c
+++ b/sliders.c
@@ -230,8 +230,8 @@ static gboolean load_att_type_cb(gpointer data) {
 static void c25_att_combobox_changed(GtkWidget *widget, gpointer data) {
   int val = atoi(gtk_combo_box_get_active_id(GTK_COMBO_BOX(widget)));
   if (active_receiver->id == 0) {
-    //DL1YCF: this button is only valid for the first receiver
-    //        store attenuation, such that in meter.c the correct level is displayed
+    // this button is only valid for the first receiver
+    // store attenuation, such that in meter.c the correct level is displayed
     adc_attenuation[active_receiver->adc] = 12*val;
     set_alex_attenuation(val);
   } else {
@@ -245,9 +245,9 @@ static void c25_att_combobox_changed(GtkWidget *widget, gpointer data) {
 static void c25_preamp_combobox_changed(GtkWidget *widget, gpointer data) {
   int val = atoi(gtk_combo_box_get_active_id(GTK_COMBO_BOX(widget)));
   if (active_receiver->id == 0) {
-    //DL1YCF: This button is only valid for the first receiver
-    //        dither and preamp are "misused" to store the PreAmp value.
-    //        this has to be exploited in meter.c
+    // This button is only valid for the first receiver
+    // dither and preamp are "misused" to store the PreAmp value.
+    // this has to be exploited in meter.c
     active_receiver->dither = (val >= 2);  // second preamp ON
     active_receiver->preamp = (val >= 1);  // first  preamp ON
   } else{
index 465ec9f89e60f6f2b23c902569c9d7ff66dcb071..00d5e4e61f2695a0159279219fab7a200d2a07dd 100644 (file)
@@ -173,6 +173,9 @@ void transmitter_save_state(TRANSMITTER *tx) {
   sprintf(name,"transmitter.%d.feedback",tx->id);
   sprintf(value,"%d",tx->feedback);
   setProperty(name,value);
+  sprintf(name,"transmitter.%d.attenuation",tx->id);
+  sprintf(value,"%d",tx->attenuation);
+  setProperty(name,value);
 #endif
   sprintf(name,"transmitter.%d.ctcss",tx->id);
   sprintf(value,"%d",tx->ctcss);
@@ -259,6 +262,9 @@ void transmitter_restore_state(TRANSMITTER *tx) {
   sprintf(name,"transmitter.%d.feedback",tx->id);
   value=getProperty(name);
   if(value) tx->feedback=atoi(value);
+  sprintf(name,"transmitter.%d.attenuation",tx->id);
+  value=getProperty(name);
+  if(value) tx->attenuation=atoi(value);
 #endif
   sprintf(name,"transmitter.%d.ctcss",tx->id);
   value=getProperty(name);
@@ -1087,19 +1093,23 @@ void tx_set_displaying(TRANSMITTER *tx,int state) {
 
 #ifdef PURESIGNAL
 void tx_set_ps(TRANSMITTER *tx,int state) {
-  tx->puresignal=state;
   if(state) {
+    tx->puresignal=1;
     SetPSControl(tx->id, 0, 0, 1, 0);
   } else {
     SetPSControl(tx->id, 1, 0, 0, 0);
+    // wait a moment for PS to shut down
+    usleep(100000);
+    tx->puresignal=0;
   }
   vfo_update();
 }
 
 void tx_set_twotone(TRANSMITTER *tx,int state) {
+  fprintf(stderr,"TX TWO TONE new state=%d\n", state);
   transmitter->twotone=state;
   if(state) {
-    // DL1YCF: set frequencies and levels
+    // set frequencies and levels
     switch(tx->mode) {
       case modeCWL:
       case modeLSB:
@@ -1130,13 +1140,13 @@ void tx_set_ps_sample_rate(TRANSMITTER *tx,int rate) {
 //
 void cw_hold_key(int state) {
   if (state) {
-    cw_key_down = 4800000;    // up to 100 sec
+    cw_key_down = 480000;    // up to 10 sec
   } else {
     cw_key_down = 0;
   }
 }
 
-// DL1YCF:
+// Sine tone generator:
 // somewhat improved, and provided two siblings
 // for generating side tones simultaneously on the
 // HPSDR board and local audio.
index 7e08fc9993b681dd6712ce90fbf27dac96489532..895bce0407dc6be23f2b6b7f7ddae621923c6ea9 100644 (file)
--- a/tx_menu.c
+++ b/tx_menu.c
@@ -59,10 +59,12 @@ static gboolean delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_d
 
 static void comp_enable_cb(GtkWidget *widget, gpointer data) {
   transmitter->compressor=gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
+  g_idle_add(ext_vfo_update, NULL);
 }
 
 static void comp_cb(GtkWidget *widget, gpointer data) {
   transmitter_set_compressor_level(transmitter,gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget)));
+  g_idle_add(ext_vfo_update, NULL);
 }
 
 static void tx_spin_low_cb (GtkWidget *widget, gpointer data) {
@@ -160,9 +162,6 @@ static void local_input_changed_cb(GtkWidget *widget, gpointer data) {
 static gboolean emp_cb (GtkWidget *widget, gpointer data) {
   pre_emphasize=gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
   tx_set_pre_emphasize(transmitter,pre_emphasize);
-  // 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 7a8d590daaf123c3d724e116af9a0060ddfd5f69..e9690f720943dc5f5e664b6de98351b31b191270 100644 (file)
@@ -164,9 +164,6 @@ tx_panadapter_scroll_event_cb (GtkWidget      *widget,
   } else {
     vfo_move(-step);
   }
-  // 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;
 }
 
diff --git a/vfo.c b/vfo.c
index 20ead0caf4c3fb32768092c1263e8a32749ac9ea..997b4ec41fb2c039c495cf60702d3aa253b7ec27 100644 (file)
--- a/vfo.c
+++ b/vfo.c
@@ -687,7 +687,7 @@ void vfo_update() {
         }
         cairo_show_text(cr, temp_text);
 
-       // DL1YCF: in what follows, we want to display the VFO frequency
+       // 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
@@ -742,39 +742,34 @@ void vfo_update() {
         cairo_set_font_size(cr, 12);
         cairo_show_text(cr, temp_text);
 
+       // NB and NB2 are mutually exclusive, therefore
+       // they are put to the same place
         cairo_move_to(cr, 150, 50);
         if(active_receiver->nb) {
           cairo_set_source_rgb(cr, 1.0, 1.0, 0.0);
-        } else {
-          cairo_set_source_rgb(cr, 0.7, 0.7, 0.7);
-        }
-        cairo_show_text(cr, "NB");
-
-        cairo_move_to(cr, 175, 50);
-        if(active_receiver->nb2) {
+          cairo_show_text(cr, "NB");
+        } else if (active_receiver->nb2) {
           cairo_set_source_rgb(cr, 1.0, 1.0, 0.0);
-        } else {
+          cairo_show_text(cr, "NB2");
+       } else {
           cairo_set_source_rgb(cr, 0.7, 0.7, 0.7);
+          cairo_show_text(cr, "NB");
         }
-        cairo_show_text(cr, "NB2");
 
-        cairo_move_to(cr, 200, 50);  
+       // NR and NR2 are mutually exclusive
+        cairo_move_to(cr, 180, 50);  
         if(active_receiver->nr) {
           cairo_set_source_rgb(cr, 1.0, 1.0, 0.0);
-        } else {
-          cairo_set_source_rgb(cr, 0.7, 0.7, 0.7);
-        }
-        cairo_show_text(cr, "NR");
-
-        cairo_move_to(cr, 225, 50);  
-        if(active_receiver->nr2) {
+          cairo_show_text(cr, "NR");
+        } else if (active_receiver->nr2) {
           cairo_set_source_rgb(cr, 1.0, 1.0, 0.0);
-        } else {
+          cairo_show_text(cr, "NR2");
+       } else {
           cairo_set_source_rgb(cr, 0.7, 0.7, 0.7);
+          cairo_show_text(cr, "NR2");
         }
-        cairo_show_text(cr, "NR2");
 
-        cairo_move_to(cr, 250, 50);  
+        cairo_move_to(cr, 210, 50);  
         if(active_receiver->anf) {
           cairo_set_source_rgb(cr, 1.0, 1.0, 0.0);
         } else {
@@ -782,7 +777,7 @@ void vfo_update() {
         }
         cairo_show_text(cr, "ANF");
 
-        cairo_move_to(cr, 275, 50);  
+        cairo_move_to(cr, 240, 50);  
         if(active_receiver->snb) {
           cairo_set_source_rgb(cr, 1.0, 1.0, 0.0);
         } else {
@@ -790,7 +785,7 @@ void vfo_update() {
         }
         cairo_show_text(cr, "SNB");
 
-        cairo_move_to(cr, 350, 50);  
+        cairo_move_to(cr, 300, 50);  
         switch(active_receiver->agc) {
           case AGC_OFF:
             cairo_set_source_rgb(cr, 0.7, 0.7, 0.7);
@@ -806,7 +801,7 @@ void vfo_update() {
             break;
           case AGC_MEDIUM:
             cairo_set_source_rgb(cr, 1.0, 1.0, 0.0);
-            cairo_show_text(cr, "AGC MEDIUM");
+            cairo_show_text(cr, "AGC MED");
             break;
           case AGC_FAST:
             cairo_set_source_rgb(cr, 1.0, 1.0, 0.0);
@@ -814,6 +809,20 @@ void vfo_update() {
             break;
         }
 
+       //
+       // Since we can now change it by a MIDI controller,
+       // we should display the compressor (level)
+       //
+        cairo_move_to(cr, 400, 50);  
+       if (transmitter->compressor) {
+           sprintf(temp_text,"CMPR %d dB",(int) transmitter->compressor_level);
+            cairo_set_source_rgb(cr, 1.0, 1.0, 0.0);
+            cairo_show_text(cr, temp_text);
+       } else {
+            cairo_set_source_rgb(cr, 0.7, 0.7, 0.7);
+            cairo_show_text(cr, "CMPR OFF");
+       }
+
         int s=0;
         while(steps[s]!=step && steps[s]!=0) {
           s++;
index e14d5f2cbf73924be62803c22d6bc19c55cfe957..ff418a5fc65dd8502f98b831016d3d4bfd4e853f 100644 (file)
@@ -91,7 +91,6 @@ static gpointer level_thread(gpointer arg) {
     g_idle_add(level_update,NULL);
     usleep(100000); // 100ms
   }
-  // DL1YCF added return statement to make compilers happy.
   return NULL;
 }