]> git.rkrishnan.org Git - pihpsdr.git/commitdiff
MIDI support, and some corrections
authorc vw <dl1ycf@darc.de>
Tue, 23 Apr 2019 17:26:29 +0000 (19:26 +0200)
committerc vw <dl1ycf@darc.de>
Tue, 23 Apr 2019 17:26:29 +0000 (19:26 +0200)
16 files changed:
Makefile.mac
ext.c
ext.h
gpio.c
hpsdrsim.c
mac_midi.c [new file with mode: 0644]
midi.h [new file with mode: 0644]
midi.inp [new file with mode: 0644]
midi2.c [new file with mode: 0644]
midi3.c [new file with mode: 0644]
old_discovery.c
ps_menu.c
radio.c
rigctl.c
sliders.c
sliders.h

index cc5a7c81df9f2c05164c35c0d55ba1a04baece84..45aa79f3196ac25802e82f03488aac2bdc552b99 100644 (file)
@@ -36,6 +36,9 @@ STEMLAB_FIX_OPTION=-DSTEMLAB_FIX
 # uncomment the line below to include support for Pi SDR
 #PI_SDR_INCLUDE=PI_SDR
 
+# uncomment the line below to include MIDI support
+MIDI_INCLUDE=MIDI
+
 #uncomment the line below for the platform being compiled on (actually not used)
 UNAME_N=raspberrypi
 #UNAME_N=odroid
@@ -49,6 +52,14 @@ UNAME_N=raspberrypi
 CC=gcc
 LINK=gcc
 
+ifeq ($(MIDI_INCLUDE),MIDI)
+MIDI_OPTIONS=-D MIDI
+MIDI_SOURCES= mac_midi.c midi2.c midi3.c
+MIDI_HEADERS= midi.h
+MIDI_OBJS= mac_midi.o midi2.o midi3.o
+MIDI_LIBS= -framework CoreMIDI -framework Foundation
+endif
+
 ifeq ($(PURESIGNAL_INCLUDE),PURESIGNAL)
 PURESIGNAL_OPTIONS=-D PURESIGNAL
 PURESIGNAL_SOURCES= \
@@ -187,11 +198,11 @@ GTKLIBS=`pkg-config --libs gtk+-3.0`
 PORTAUDIO_OPTIONS=-DPORTAUDIO
 AUDIO_LIBS=-lportaudio
 
-OPTIONS=-g -Wno-deprecated-declarations $(PURESIGNAL_OPTIONS) $(REMOTE_OPTIONS) $(USBOZY_OPTIONS) $(I2C_OPTIONS) $(GPIO_OPTIONS) $(LIMESDR_OPTIONS) \
+OPTIONS=-g -Wno-deprecated-declarations $(MIDI_OPTIONS) $(PURESIGNAL_OPTIONS) $(REMOTE_OPTIONS) $(USBOZY_OPTIONS) $(I2C_OPTIONS) $(GPIO_OPTIONS) $(LIMESDR_OPTIONS) \
                 $(FREEDV_OPTIONS) $(LOCALCW_OPTIONS) $(RADIOBERRY_OPTIONS) $(PI_SDR_OPTIONS) $(PSK_OPTIONS) $(STEMLAB_OPTIONS) $(STEMLAB_FIX_OPTION) \
                 -D GIT_DATE='"$(GIT_DATE)"' -D GIT_VERSION='"$(GIT_VERSION)"' $(PORTAUDIO_OPTIONS) $(DEBUG_OPTION) -O3
 
-LIBS=-lm -lwdsp -lpthread $(AUDIO_LIBS) $(USBOZY_LIBS) $(PSKLIBS) $(GTKLIBS) $(GPIO_LIBS) $(SOAPYSDRLIBS) $(FREEDVLIBS) $(STEMLAB_LIBS)
+LIBS=-lm -lwdsp -lpthread $(AUDIO_LIBS) $(USBOZY_LIBS) $(PSKLIBS) $(GTKLIBS) $(GPIO_LIBS) $(SOAPYSDRLIBS) $(FREEDVLIBS) $(STEMLAB_LIBS) $(MIDI_LIBS)
 INCLUDES=$(GTKINCLUDES)
 
 COMPILE=$(CC) $(OPTIONS) $(INCLUDES)
@@ -413,10 +424,10 @@ error_handler.o \
 cwramp.o \
 portaudio.o
 
-$(PROGRAM):  $(OBJS) $(REMOTE_OBJS) $(USBOZY_OBJS) $(LIMESDR_OBJS) $(FREEDV_OBJS) $(LOCALCW_OBJS) $(I2C_OBJS) $(GPIO_OBJS) $(PSK_OBJS) $(PURESIGNAL_OBJS) $(STEMLAB_OBJS)
-       $(LINK) -o $(PROGRAM) $(OBJS) $(REMOTE_OBJS) $(USBOZY_OBJS) $(I2C_OBJS) $(GPIO_OBJS) $(LIMESDR_OBJS) $(FREEDV_OBJS) $(LOCALCW_OBJS) $(PSK_OBJS) $(PURESIGNAL_OBJS) $(STEMLAB_OBJS) $(LIBS)
+$(PROGRAM):  $(OBJS) $(REMOTE_OBJS) $(USBOZY_OBJS) $(LIMESDR_OBJS) $(FREEDV_OBJS) $(LOCALCW_OBJS) $(I2C_OBJS) $(GPIO_OBJS) $(PSK_OBJS) $(PURESIGNAL_OBJS) $(MIDI_OBJS) $(STEMLAB_OBJS)
+       $(LINK) -o $(PROGRAM) $(OBJS) $(REMOTE_OBJS) $(USBOZY_OBJS) $(I2C_OBJS) $(GPIO_OBJS) $(LIMESDR_OBJS) $(FREEDV_OBJS) $(LOCALCW_OBJS) $(PSK_OBJS) $(PURESIGNAL_OBJS) $(MIDI_OBJS) $(STEMLAB_OBJS) $(LIBS)
 
-all: prebuild  $(PROGRAM) $(HEADERS) $(REMOTE_HEADERS) $(USBOZY_HEADERS) $(LIMESDR_HEADERS) $(FREEDV_HEADERS) $(LOCALCW_HEADERS) $(I2C_HEADERS) $(GPIO_HEADERS) $(PSK_HEADERS) $(PURESIGNAL_HEADERS) $(STEMLAB_HEADERS) $(SOURCES) $(REMOTE_SOURCES) $(USBOZY_SOURCES) $(LIMESDR_SOURCES) $(FREEDV_SOURCES) $(I2C_SOURCES) $(GPIO_SOURCES) $(PSK_SOURCES) $(PURESIGNAL_SOURCES) $(STEMLAB_SOURCES)
+all: prebuild  $(PROGRAM) $(HEADERS) $(REMOTE_HEADERS) $(USBOZY_HEADERS) $(LIMESDR_HEADERS) $(FREEDV_HEADERS) $(LOCALCW_HEADERS) $(I2C_HEADERS) $(GPIO_HEADERS) $(PSK_HEADERS) $(PURESIGNAL_HEADERS) $(MIDI_HEADERS) $(STEMLAB_HEADERS) $(SOURCES) $(REMOTE_SOURCES) $(USBOZY_SOURCES) $(LIMESDR_SOURCES) $(FREEDV_SOURCES) $(I2C_SOURCES) $(GPIO_SOURCES) $(PSK_SOURCES) $(PURESIGNAL_SOURCES) $(MIDI_SOURCES) $(STEMLAB_SOURCES)
 
 prebuild:
        rm -f version.o
@@ -474,11 +485,11 @@ hpsdrsim:       hpsdrsim.o
 #############################################################################
 app:   $(OBJS) $(REMOTE_OBJS) $(USBOZY_OBJS) $(LIMESDR_OBJS) $(FREEDV_OBJS) \
                $(LOCALCW_OBJS) $(I2C_OBJS) $(GPIO_OBJS) $(PSK_OBJS) \
-               $(PURESIGNAL_OBJS) $(STEMLAB_OBJS)
+               $(PURESIGNAL_OBJS) $(MIDI_OBJS) $(STEMLAB_OBJS)
        $(LINK) -headerpad_max_install_names -o $(PROGRAM) $(OBJS) $(REMOTE_OBJS) \
                $(USBOZY_OBJS) $(I2C_OBJS) $(GPIO_OBJS) $(LIMESDR_OBJS) \
                $(FREEDV_OBJS) $(LOCALCW_OBJS) $(PSK_OBJS) $(PURESIGNAL_OBJS) \
-               $(STEMLAB_OBJS) $(LIBS)
+               $(MIDI_OBJS) $(STEMLAB_OBJS) $(LIBS)
        @rm -rf pihpsdr.app
        @mkdir -p pihpsdr.app/Contents/MacOS
        @mkdir -p pihpsdr.app/Contents/Frameworks
@@ -497,11 +508,13 @@ app:      $(OBJS) $(REMOTE_OBJS) $(USBOZY_OBJS) $(LIMESDR_OBJS) $(FREEDV_OBJS) \
          install_name_tool -change "$$lib" "@executable_path/../Frameworks/$$libfn" pihpsdr.app/Contents/MacOS/pihpsdr-bin; \
        done
 #
-# Make "app" and copy wdspWisdom and props file to app bundle
+# Make "app" and copy local files app bundle
 #
 localapp:      app
        cp wdspWisdom pihpsdr.app/Contents/Resources
        cp *.props    pihpsdr.app/Contents/Resources
+       cp midi.inp   pihpsdr.app/Contents/Resources
+       cp ip.addr    pihpsdr.app/Contents/Resources
 
 #############################################################################
 
diff --git a/ext.c b/ext.c
index 6550d12a6e6cc23090d7874986cef445c704aaa0..0838bcb1e377a3efd4a4ff6e13cc53d7db692455 100644 (file)
--- a/ext.c
+++ b/ext.c
@@ -60,7 +60,7 @@ int ext_vfo_update(void *data) {
 }
 
 int ext_vfo_filter_changed(void *data) {
-  vfo_filter_changed((uintptr_t)data);
+  vfo_filter_changed((int)(uintptr_t)data);
   return 0;
 }
 
@@ -75,39 +75,36 @@ int ext_band_update(void *data) {
 
 int ext_mode_update(void *data) {
   start_mode();
-  // DL1YCF added return statement
   return 0;
 }
 
 int ext_filter_update(void *data) {
   start_filter();
-  // DL1YCF added return statement
   return 0;
 }
 
 int ext_noise_update(void *data) {
   start_noise();
-  // DL1YCF added return statement
   return 0;
 }
 
 int ext_ptt_update(void *data) {
-  ptt_update((uintptr_t)data);
+  ptt_update((int)(uintptr_t)data);
   return 0;
 }
 
 int ext_mox_update(void *data) {
-  mox_update((uintptr_t)data);
+  mox_update((int)(uintptr_t)data);
   return 0;
 }
 
 int ext_tune_update(void *data) {
-  tune_update((uintptr_t)data);
+  tune_update((int)(uintptr_t)data);
   return 0;
 }
 
 int ext_vox_changed(void *data) {
-  vox_changed((uintptr_t)data);
+  vox_changed((int)(uintptr_t)data);
   return 0;
 }
 
@@ -128,17 +125,17 @@ int ext_calc_drive_level(void *data) {
 }
 
 int ext_vfo_band_changed(void *data) {
-  vfo_band_changed((uintptr_t)data);
+  vfo_band_changed((int)(uintptr_t)data);
   return 0;
 }
 
 int ext_radio_change_sample_rate(void *data) {
-  radio_change_sample_rate((uintptr_t)data);
+  radio_change_sample_rate((int)(uintptr_t)data);
   return 0;
 }
 
 int ext_update_squelch(void *data) {
-  set_squelch(active_receiver);
+  set_squelch();
   return 0;
 }
 
@@ -160,3 +157,47 @@ int ext_vfo_step(void *data) {
   vfo_step(step);
   return 0;
 }
+
+int ext_set_mic_gain(void * data) {
+  double d=*(double *)data;
+  set_mic_gain(d);
+  free(data);
+  return 0;
+}
+
+int ext_set_agc_gain(void *data) {
+  double d=*(double *)data;
+  set_agc_gain(d);
+  free(data);
+  return 0;
+}
+int ext_set_drive(void *data) {
+  double d=*(double *)data;
+  set_drive(d);
+  free(data);
+  return 0;
+}
+
+int ext_vfo_a_swap_b(void *data) {
+  vfo_a_swap_b();
+  return 0;
+}
+
+int ext_update_att_preamp(void *data) {
+  update_att_preamp();
+  return 0;
+}
+
+int ext_set_alex_attenuation(void *data) {
+  int val=(int)(uintptr_t)data;
+  set_alex_attenuation(val);
+  return 0;
+}
+
+int ext_set_attenuation_value(void *data) {
+  double d=*(double *)data;
+  set_attenuation_value(d);
+  free(data);
+  return 0;
+}
diff --git a/ext.h b/ext.h
index 1b850db404191362157e0cfab432eaefeb578ac9..070a21544f61247901ba75efa6762bea75de9901 100644 (file)
--- a/ext.h
+++ b/ext.h
 */
 
 
+//
 // The following calls functions can be called usig g_idle_add
+// Use these calls from within the rigclt daemon, or the GPIO or MIDI stuff
+//
 
 extern int ext_discovery(void *data);
 extern int ext_vfo_update(void *data);
@@ -52,5 +55,14 @@ extern int ext_noise_update(void *data);
 extern int ext_tx_set_ps(void *data);
 extern int ext_ps_twotone(void *data);
 #endif
+
 int ext_vfo_step(void *data);
 int ext_vfo_mode_changed(void *data);
+int ext_set_af_gain(void *data);
+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_update_att_preamp(void *data);
+int ext_set_alex_attenuation(void *data);
+int ext_set_attenuation_value(void *data);
diff --git a/gpio.c b/gpio.c
index b00a0c42d0f53c91dcccfdac1cf23791a05d024f..a34510d797288f959baf22fb5fa93f97185bb111 100644 (file)
--- a/gpio.c
+++ b/gpio.c
@@ -1407,7 +1407,7 @@ static void encoder_changed(int action,int pos) {
         value=100.0;
       }
       active_receiver->squelch=value;
-      set_squelch(active_receiver);
+      set_squelch();
       break;
     case ENCODER_COMP:
       value=(double)transmitter->compressor_level;
index 7f49b1dc10228e5fa48446c8958b84903f67b229..786057771761694c66d65bdbd89707b678a75a9f 100755 (executable)
  * RF3 respects the "TX drive" and "TX ATT" settings
  * RF4 is the TX signal multiplied with 0.4 (ignores TX_DRIVE and TX_ATT).
  *
- * We support 4 receivers, they see
- * RX1:  RF1
- * RX2:  RF2 while receiving, RF3 while transmitting/48000
- * RX3:  RF2 while receiving, RF3 while transmitting/48000
- * RX4:  RF3 
+ * 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, 
  *
- * RX5 to RX8: no signal
- * 
- * This is the setting for PURESIGNAL with HERMES boards.
- * To simulate Orion2 boards (Anan7000 etc), we should connect RX4 with RF2 and RX5 with RF3.
+ * The connection upon transmitting depends on the DEVICE, namely
+ *
+ * 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)
  *
+ * Note that currently, RF3 and RF4 only exist when using 48000 Hz sample rate. 
+ * 
  */
 #include <stdio.h>
 #include <errno.h>
@@ -66,75 +69,75 @@ static int sock_TCP_Client = -1;
  * Whenevery they are changed, this is reported.
  */
 
-int            AlexTXrel = -1;
-int            alexRXout = -1;
-int            alexRXant = -1;
-int            MicTS = -1;
-int            duplex = -1;
-int            receivers = -1;
-int            rate = -1;
-int             preamp = -1;
-int            LTdither = -1;
-int            LTrandom = -1;
-int            AlexRXant = -1;
-int            AlexRXout = -1;
-int             ref10 = -1;
-int            src122 = -1;
-int            PMconfig = -1;
-int            MicSrc = -1;
-int            txdrive = 0;
-int            txatt = 0;
-int            sidetone_volume = -1;
-int            cw_internal = -1;
-int            rx_att[2] = {-1,-1};
-int            rx1_attE = -1;
-int             rx_preamp[4] = {-1,-1,-1,-1};
-int            MerTxATT0 = -1;
-int            MerTxATT1 = -1;
-int            MetisDB9 = -1;
-int            PeneSel = -1;
-int            PureSignal = -1;
-int            LineGain = -1;
-int            MicPTT = -1;
-int            tip_ring = -1;
-int            MicBias = -1;
-int            ptt=-1;
-int            att=-1;
-int            TX_class_E = -1;
-int            OpenCollectorOutputs=-1;
-long           tx_freq=-1;
-long           rx_freq[7] = {-1,-1,-1,-1,-1,-1,-1};
-int            hermes_config=-1;
-int            alex_lpf=-1;
-int            alex_hpf=-1;
-int            c25_ext_board_i2c_data=-1;
-int            rx_adc[7]={0,1,1,2,-1,-1,-1};
-int            cw_hang = -1;
-int            cw_reversed = -1;
-int            cw_speed = -1;
-int            cw_mode = -1;
-int            cw_weight = -1;
-int            cw_spacing = -1;
-int            cw_delay = -1;
-int            CommonMercuryFreq = -1;
-int             freq=-1;
+static int             AlexTXrel = -1;
+static int             alexRXout = -1;
+static int             alexRXant = -1;
+static int             MicTS = -1;
+static int             duplex = -1;
+static int             receivers = -1;
+static int             rate = -1;
+static int             preamp = -1;
+static int             LTdither = -1;
+static int             LTrandom = -1;
+static int             AlexRXant = -1;
+static int             AlexRXout = -1;
+static int             ref10 = -1;
+static int             src122 = -1;
+static int             PMconfig = -1;
+static int             MicSrc = -1;
+static int             txdrive = 0;
+static int             txatt = 0;
+static int             sidetone_volume = -1;
+static int             cw_internal = -1;
+static int             rx_att[2] = {-1,-1};
+static int             rx1_attE = -1;
+static int              rx_preamp[4] = {-1,-1,-1,-1};
+static int             MerTxATT0 = -1;
+static int             MerTxATT1 = -1;
+static int             MetisDB9 = -1;
+static int             PeneSel = -1;
+static int             PureSignal = -1;
+static int             LineGain = -1;
+static int             MicPTT = -1;
+static int             tip_ring = -1;
+static int             MicBias = -1;
+static int             ptt=-1;
+static int             att=-1;
+static int             TX_class_E = -1;
+static int             OpenCollectorOutputs=-1;
+static long            tx_freq=-1;
+static long            rx_freq[7] = {-1,-1,-1,-1,-1,-1,-1};
+static int             hermes_config=-1;
+static int             alex_lpf=-1;
+static int             alex_hpf=-1;
+static int             c25_ext_board_i2c_data=-1;
+static int             rx_adc[7]={0,1,1,2,-1,-1,-1};
+static int             cw_hang = -1;
+static int             cw_reversed = -1;
+static int             cw_speed = -1;
+static int             cw_mode = -1;
+static int             cw_weight = -1;
+static int             cw_spacing = -1;
+static int             cw_delay = -1;
+static int             CommonMercuryFreq = -1;
+static int             freq=-1;
 
 
 // floating-point represeners of TX att, RX att, and RX preamp settings
 
-double txdrv_dbl = 1.0;
-double txatt_dbl = 1.0;
-double rxatt_dbl[4] = {1.0, 1.0, 1.0, 1.0};   // this reflects both ATT and PREAMP
+static double txdrv_dbl = 1.0;
+static double txatt_dbl = 1.0;
+static double rxatt_dbl[4] = {1.0, 1.0, 1.0, 1.0};   // this reflects both ATT and PREAMP
 
-int sock_ep2;
+static int sock_ep2;
 
-struct sockaddr_in addr_ep6;
+static struct sockaddr_in addr_ep6;
 
 /*
  * These two variables monitor whether the TX thread is active
  */
-int enable_thread = 0;
-int active_thread = 0;
+static int enable_thread = 0;
+static int active_thread = 0;
 
 void process_ep2(uint8_t *frame);
 void *handler_ep6(void *arg);
@@ -146,10 +149,12 @@ void *handler_ep6(void *arg);
 
 // 63 * 130,  RTXLEN must be an even multiple of 63!
 #define RTXLEN 8190
-double  isample[RTXLEN];
-double  qsample[RTXLEN];
-int  txptr=0;
-int  rxptr=0;
+static double  isample[RTXLEN];
+static double  qsample[RTXLEN];
+static int  txptr=0;
+static int  rxptr=0;
+
+static int ismetis,isorion,ishermes,isc25;
 
 int main(int argc, char *argv[])
 {
@@ -157,6 +162,7 @@ int main(int argc, char *argv[])
        struct sched_param param;
        pthread_attr_t attr;
        pthread_t thread;
+        int DEVICE;
 
        uint8_t reply[11] = { 0xef, 0xfe, 2, 0, 0, 0, 0, 0, 0, 32, 1 };
 
@@ -179,6 +185,31 @@ int main(int argc, char *argv[])
        int bytes_read, bytes_left;
        uint32_t *code0 = (uint32_t *) buffer;  // fast access to code of first buffer
 
+/*
+ *      Examples for METIS:    ANAN10E, ANAN100B
+ *      Examples for HERMES:   HERMES, ANAN10, ANAN100
+ *     Examples for ORION:     ANAN100D, ANAN200D
+ *     Examples for ORION2:    ANAN7000D, ANAN8000D
+ */
+
+       DEVICE=1; // default is Hermes
+        if (argc > 1) {
+           if (!strncmp(argv[1],"-metis"  ,6))  DEVICE=0;
+           if (!strncmp(argv[1],"-hermes" ,7))  DEVICE=1;
+           if (!strncmp(argv[1],"-orion" , 6))  DEVICE=5;
+           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;
+       switch (DEVICE) {
+           case   0: fprintf(stderr,"DEVICE is METIS\n");   ismetis=1;  break;
+           case   1: fprintf(stderr,"DEVICE is HERMES\n");  ishermes=1; break;
+           case   5: fprintf(stderr,"DEVICE is ORION\n");   isorion=1;  break;
+           case  10: fprintf(stderr,"DEVICE is ORION2\n");  isorion=1;  break;
+           case 100: fprintf(stderr,"DEVICE is StemLab\n"); ishermes=1;  isc25=1; break;
+       }
+       reply[10]=DEVICE;
+
        if ((sock_ep2 = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
        {
                perror("socket");
@@ -422,11 +453,6 @@ int main(int argc, char *argv[])
                                memset(buffer, 0, 60);
                                memcpy(buffer, reply, 11);
 
-                               // ab-use some of the "unused" bytes in the reply block to indicate we can do TCP
-                               // This information can be used by SDR programs
-                               buffer[11]='T';
-                               buffer[12]='C';
-                               buffer[13]='P';
                                if (sock_TCP_Client > -1)
                                {
                                        // We will get into trouble if we respond via TCP while the radio is
@@ -568,8 +594,8 @@ void process_ep2(uint8_t *frame)
 
           chk_data((frame[3] & 0x03) >> 0, att, "ALEX Attenuator");
           chk_data((frame[3] & 0x04) >> 2, preamp, "ALEX preamp");
-          chk_data((frame[3] & 0x08) >> 2, LTdither, "LT2208 Dither");
-          chk_data((frame[3] & 0x10) >> 2, LTrandom, "LT2208 Random");
+          chk_data((frame[3] & 0x08) >> 3, LTdither, "LT2208 Dither");
+          chk_data((frame[3] & 0x10) >> 4, LTrandom, "LT2208 Random");
           chk_data((frame[3] & 0x60) >> 5, alexRXant, "ALEX RX ant");
           chk_data((frame[3] & 0x80) >> 7, alexRXout, "ALEX RX out");
 
@@ -578,6 +604,13 @@ void process_ep2(uint8_t *frame)
           chk_data(((frame[4] >> 3) & 7) + 1, receivers, "RECEIVERS");
           chk_data(((frame[4] >> 6) & 1), MicTS, "TimeStampMic");
           chk_data(((frame[4] >> 7) & 1), CommonMercuryFreq,"Common Mercury Freq");
+
+         if (isc25) {
+             // Charly25: has two 18-dB preamps that are switched with "preamp" and "dither"
+             //           and a step-attenuator triggered by Alex ATT ONLY RX1!
+               rxatt_dbl[0]=pow(10.0, -0.05*(12*att-18*LTdither-18*preamp));
+               rxatt_dbl[1]=1.0;
+          }
          break;
 
         case 2:
@@ -651,11 +684,13 @@ void process_ep2(uint8_t *frame)
           chk_data((frame[4] & 0x1F) >> 0, rx_att[0], "RX1 ATT");
           chk_data((frame[4] & 0x20) >> 5, rx1_attE, "RX1 ATT enable");
 
-          // Set RX amplification factors. Assume 20 dB preamps
-           rxatt_dbl[0]=pow(10.0, -0.05*(rx_att[0]-20*rx_preamp[0]));
-           rxatt_dbl[1]=pow(10.0, -0.05*(rx_att[1]-20*rx_preamp[1]));
-           rxatt_dbl[2]=pow(10.0, (double) rx_preamp[2]);
-           rxatt_dbl[3]=pow(10.0, (double) rx_preamp[3]);
+          if (!isc25) {
+            // Set RX amplification factors. Assume 20 dB preamps
+             rxatt_dbl[0]=pow(10.0, -0.05*(rx_att[0]-20*rx_preamp[0]));
+             rxatt_dbl[1]=pow(10.0, -0.05*(rx_att[1]-20*rx_preamp[1]));
+             rxatt_dbl[2]=pow(10.0, (double) rx_preamp[2]);
+             rxatt_dbl[3]=pow(10.0, (double) rx_preamp[3]);
+          }
           break;
 
        case 22:
@@ -740,7 +775,13 @@ void *handler_ep6(void *arg)
                127, 127, 127, 24, 0, 0, 0, 0,
                127, 127, 127, 32, 66, 66, 66, 66
        };
-        int32_t sample;
+        int32_t rf1isample,rf1qsample;
+        int32_t rf2isample,rf2qsample;
+        int32_t rf3isample,rf3qsample;
+        int32_t rf4isample,rf4qsample;
+
+       int32_t myisample,myqsample;
+
         struct timespec delay;
 #ifdef __APPLE__
        struct timespec now;
@@ -834,80 +875,87 @@ 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];
+                       //
+                       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
+                       //
+                       i1=isample[rxptr]*txdrv_dbl;
+                       q1=qsample[rxptr]*txdrv_dbl;
+                       fac=IM3a+IM3b*(i1*i1+q1*q1);
+                       rf3isample= txatt_dbl*i1*fac * 8388607.0;
+                       rf3qsample= txatt_dbl*q1*fac * 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 sees RF1
-                                   //
-                                   // RF1: noise + weak 800 Hz tone
-                                   //
-                                   sample= noiseItab[noiseIQpt] * 8388607.0;
-                                   sample += T0800Itab[pt0800] * 83.886070 *rxatt_dbl[0];  // 100 dB below peak
-                                   *pointer++ = (sample >> 16) & 0xFF;
-                                   *pointer++ = (sample >>  8) & 0xFF;
-                                   *pointer++ = (sample >>  0) & 0xFF;
-                                   sample=noiseQtab[noiseIQpt] * 8388607.0;
-                                   sample += T0800Qtab[pt0800] * 83.886070 *rxatt_dbl[0];  // 100 dB below peak
-                                   *pointer++ = (sample >> 16) & 0xFF;
-                                   *pointer++ = (sample >>  8) & 0xFF;
-                                   *pointer++ = (sample >>  0) & 0xFF;
-                                   break;
-                               case 1: // RX2 and RX3 see RF2 upon receiving, RF3 upon transmitting
-                               case 2:
-                                    if (rate == 0 && ptt) {
-                                       //
-                                       // RF3:
-                                       // Distorted (feed-back) TX signal
-                                       // Note we first add distortion, then adjust level
-                                       // Therefore we first multiply with txdrv_dbl, then
-                                       // distort, and then attenuate with txatt_dbl.
-                                       //
-                                        i1=isample[rxptr]*txdrv_dbl;
-                                        q1=qsample[rxptr]*txdrv_dbl;
-                                        fac=IM3a+IM3b*(i1*i1+q1*q1);
-                                        sample= txatt_dbl*i1*fac * 8388607.0;
-                                        *pointer++ = (sample >> 16) & 0xFF;
-                                        *pointer++ = (sample >>  8) & 0xFF;
-                                        *pointer++ = (sample >>  0) & 0xFF;
-                                        sample= txatt_dbl*q1*fac * 8388607.0;
-                                        *pointer++ = (sample >> 16) & 0xFF;
-                                        *pointer++ = (sample >>  8) & 0xFF;
-                                        *pointer++ = (sample >>  0) & 0xFF;
-                                    } else {
-                                       //
-                                       // RF2: noise + weak 2000 Hz tone
-                                       //
-                                       sample= noiseItab[noiseIQpt] * 8388607.0;
-                                       sample += T2000Itab[pt2000] * 838.86070 * rxatt_dbl[1];  // 80 dB below peak
-                                       *pointer++ = (sample >> 16) & 0xFF;
-                                       *pointer++ = (sample >>  8) & 0xFF;
-                                       *pointer++ = (sample >>  0) & 0xFF;
-                                       sample=noiseQtab[noiseIQpt] * 8388607.0;
-                                       sample += T2000Qtab[pt2000] * 838.86070 * rxatt_dbl[1];  // 80 dB below peak
-                                       *pointer++ = (sample >> 16) & 0xFF;
-                                       *pointer++ = (sample >>  8) & 0xFF;
-                                       *pointer++ = (sample >>  0) & 0xFF;
-                                   }
-                                   break;
-                               case 3: // RX4 sees TX outgoing signal (no distortion, no attenuation)
-                                   //
-                                   // RF4: TX signal with HWPeak = 0.4
-                                   //
-                                   if (rate == 0 && ptt) {
-                                       sample= isample[rxptr] * 0.400 * 8388607.0;
-                                       *pointer++ = (sample >> 16) & 0xFF;
-                                       *pointer++ = (sample >>  8) & 0xFF;
-                                       *pointer++ = (sample >>  0) & 0xFF;
-                                       sample= qsample[rxptr] * 0.400 * 8388607.0;
-                                       *pointer++ = (sample >> 16) & 0xFF;
-                                       *pointer++ = (sample >>  8) & 0xFF;
-                                       *pointer++ = (sample >>  0) & 0xFF;
-                                           } else {
-                                       pointer +=6;
-                                   }
-                                   break;
-                               default:
-                                   pointer +=6;
+                             case 0: // RX1
+                               if (rate == 0 && ptt && ismetis) {
+                                   myisample=rf3isample;
+                                   myqsample=rf3qsample;
+                               } else {
+                                   myisample=rf1isample;
+                                   myqsample=rf1qsample;
+                               }
+                               break;
+                             case 1: // RX2
+                               if (rate == 0 && ptt && ismetis) {
+                                   myisample=rf4isample;
+                                   myqsample=rf4qsample;
+                               } else {
+                                   myisample=rf2isample;
+                                   myqsample=rf2qsample;
+                               }
+                               break;
+                             case 2:
+                                if (rate == 0 && ptt && ishermes) {
+                                   myisample=rf3isample;
+                                   myqsample=rf3qsample;
+                                } else {
+                                   myisample=rf2isample;
+                                   myqsample=rf2qsample;
+                               }
+                               break;
+                             case 3: // RX4
+                               if (rate == 0 && ptt && ishermes) {
+                                   myisample=rf4isample;
+                                   myqsample=rf4qsample;
+                                       } else if (rate == 0 && ptt && isorion) {
+                                   myisample=rf3isample;
+                                   myqsample=rf3qsample;
+                               }
+                               break;
+                             case 4: // RX5
+                                       if (rate == 0 && ptt && isorion) {
+                                   myisample=rf4isample;
+                                   myqsample=rf4qsample;
+                               }
+                               break;
                            }
+                           *pointer++ = (myisample >> 16) & 0xFF;
+                           *pointer++ = (myisample >>  8) & 0xFF;
+                           *pointer++ = (myisample >>  0) & 0xFF;
+                           *pointer++ = (myqsample >> 16) & 0xFF;
+                           *pointer++ = (myqsample >>  8) & 0xFF;
+                           *pointer++ = (myqsample >>  0) & 0xFF;
                        }
                        // Microphone samples: silence
                        pointer += 2;
diff --git a/mac_midi.c b/mac_midi.c
new file mode 100644 (file)
index 0000000..ad9885b
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * MIDI support for pihpsdr
+ * (C) Christoph van Wullen, DL1YCF.
+ *
+ * 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.
+ *
+ * For example, the call
+ * register_midi_device("COMPANY MIDI X",13)
+ * will also use a MIDI device named "COMPANY MIDI Y".
+ *
+ * This file must generate calls to Layer-2 NewMidiEvent().
+ * Some type of messages are not consideres (pressure change, etc.),
+ * they are silently dropped but must be processed.
+ *
+ */
+
+#include "midi.h"
+
+#ifdef __APPLE__
+
+#include <Carbon/Carbon.h>
+
+#include <CoreMIDI/MIDIServices.h>
+#include <CoreAudio/HostTime.h>
+#include <CoreAudio/CoreAudio.h>
+
+//
+// MIDI callback function
+//
+static void ReadMIDIdevice(const MIDIPacketList *pktlist, void *refCon, void *connRefCon) {
+    int i,j,k,command,chan;
+    MIDIPacket *packet = (MIDIPacket *)pktlist->packet;
+       
+       
+    // loop through all packets in the current list
+    for (j=0; j < pktlist->numPackets; ++j) {
+        if (packet->length > 0) { 
+           for ( i = 0; i<(packet->length); ) {
+               command=packet->data[i];
+                if ((command & 128) != 128) continue;
+                
+                chan = command & 0x0F;
+
+                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]);
+                       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]);
+                       i +=3;
+                       break;
+                  case 0xA0:  // Polyph. Press.
+                       fprintf(stderr,"PolPress: Note=%d Chan=%d Prs=%d\n", packet->data[i+1], chan, packet->data[i+2]);
+                       i +=3;
+                       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]);
+                       i +=3;
+                       break;
+                  case 0xC0:  // Program change
+                       fprintf(stderr,"PgmChang: Prog=%d Chan=%d\n", packet->data[i+1], chan);
+                       i +=2;
+                       break;
+                  case 0xD0:  // Channel Pressure
+                       fprintf(stderr, "ChanPres: Pres=%d Chan=%d\n", packet->data[i+1], chan);
+                       i +=2;
+                       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);
+                       i +=3;
+                       break;
+                  case 0xF0:  
+                       fprintf(stderr, "System  : %x", command);
+                        while ((command = (packet->data[++i]) & 128) != 128) {
+                          fprintf(stderr," %x",command);
+                        }
+                        fprintf(stderr,"\n");
+                       break;
+                }
+           } // i-loop through the packet
+           packet = MIDIPacketNext(packet);
+        } // if packet length > 1
+    } // j-loop through the list of packets
+}
+
+
+void register_midi_device(char *myname) {
+    unsigned long nDevices;
+    int i;
+    CFStringRef pname;
+    char name[100];
+    int FoundMIDIref=-1;
+    int mylen=strlen(myname);
+
+
+//
+// Go through the list of MIDI devices and
+// look whether the one we are looking for is there
+//
+
+    nDevices=MIDIGetNumberOfSources();
+    for (i=0; i<nDevices; i++) {
+       MIDIEndpointRef dev = MIDIGetSource(i);
+       if (dev != 0) {
+           MIDIObjectGetStringProperty(dev, kMIDIPropertyName, &pname);
+           CFStringGetCString(pname, name, sizeof(name), 0);
+           CFRelease(pname);
+           fprintf(stderr,"MIDI device found: >>>%s<<<\n", name);
+           if (!strncmp(name, myname, mylen)) {
+               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);
+           }
+       }
+    }
+
+//
+// If we found "our" device, register a callback routine
+//
+
+    if (FoundMIDIref >= 0) {
+        MIDIClientRef client = 0;
+        MIDIPortRef myMIDIport = 0;
+        //Create client
+        MIDIClientCreate(CFSTR("piHPSDR"),NULL,NULL, &client);
+        MIDIInputPortCreate(client, CFSTR("FromMIDI"), ReadMIDIdevice, NULL, &myMIDIport);
+        MIDIPortConnectSource(myMIDIport,MIDIGetSource(FoundMIDIref), NULL);
+    }
+}
+#endif
diff --git a/midi.h b/midi.h
new file mode 100644 (file)
index 0000000..98a6191
--- /dev/null
+++ b/midi.h
@@ -0,0 +1,192 @@
+/*
+ * MIDI support for pihpsdr
+ *
+ * (C) Christoph van Wullen, DL1YCF.
+ *
+ * Midi support works in three layers
+ *
+ * Layer-1: hardware specific
+ * --------------------------
+ *
+ * Layer1 either implements a callback function (if the operating system
+ * supports MIDI) or a separate thread polling MIDI data. Whenever a
+ * MIDI command arrives, such as Note on/off or Midi-Controller value
+ * changed, it calls Layer 2.
+ *
+ * Layer-2: MIDI device specific
+ * ----------------------------- 
+ *
+ * Layer2 translates MIDI commands into pihpsdr actions. This is done with
+ * a table-driven algorithm, such that the same translator can be used for
+ * any MIDI device provided the tables have been set up correctly.
+ * It seems overly complicated to create a user interface for setting up
+ * these tables, instead a standard text file describing the MIDI device
+ * is read and the tables are set up.
+ * Layer-2 has SDR applications in mind, but is not necessarily specific
+ * to pihpsr. It calls the Layer-3 function.
+ *
+ * Layer-3: pihpsdr specific
+ * -------------------------
+ *
+ * Layer 3, finally, implements all the "actions" we can make, such as TUNE
+ * or VFO. This Layer calls pihpsdr functions.
+ *
+ * One word to MIDI channels. Usually, a MIDI device can be configured to use
+ * a specific channel, such that different keyboards use different channels.
+ * The Layer-2 tables can either specify that the MIDI command has to come from
+ * a specific channel, or can specify that the action will be taken not matter which
+ * channel the MIDI message comes from. The latter case should be the default, but
+ * if we want to connect more than one MIDI device, we need to speficy the channel.
+ *
+ * In principle this supports more than one MIDI device, but in this case they
+ * must generate MIDI events on different channels
+ */
+
+//
+// MIDIaction encodes the "action" to be taken in Layer3
+//
+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
+};
+
+//
+// MIDItype encodes the type of MIDI control. This info
+// is passed from Layer-2 to Layer-3
+//
+// MIDI_KEY has no parameters and indicates that some
+// button has been pressed.
+//
+// MIDI_KNOB has a "value" parameter (between 0 and 100)
+// and indicates that some knob has been set to a specific
+// position.
+//
+// MIDI_WHEEL has a "direction" parameter and indicates that
+// some knob has been turned left/down or right/ip. The  value
+// can be
+//
+// -100 very fast going down
+//  -10 fast going down
+//   -1 going down
+//    1 going up
+//   10 fast going up
+//  100 very fast going up
+//
+
+enum MIDItype {
+ TYPE_NONE=0,
+ MIDI_KEY,          // Button (press event)
+ MIDI_KNOB,         // Knob   (value between 0 and 100)
+ MIDI_WHEEL         // Wheel  (direction and speed)
+};
+
+//
+// MIDIevent encodes the actual MIDI event "seen" in Layer-1 and
+// passed to Layer-2. MIDI_NOTE events end up as MIDI_KEY and
+// MIDI_PITCH as MIDI_KNOB, while MIDI_CTRL can end up both as
+// MIDI_KNOB or MIDI_WHEEL, depending on the device description.
+//
+enum MIDIevent {
+ EVENT_NONE=0,
+ MIDI_NOTE,
+ MIDI_CTRL,
+ MIDI_PITCH
+};
+
+//
+// Data structure for Layer-2
+//
+
+//
+// There is linked list of all specified MIDI events for a given "Note" value,
+// which contains the defined actions for all MIDI_NOTE and MIDI_CTRL events
+// with that given note and for all channels
+// Note on wheel delay:
+// If using a wheel for cycling through a menu, it is difficult to "hit" the correct
+// menu item if wheel events are generated at a very high rate. Therefore we can define
+// a delay: once a wheel event is reported upstream, any such events are suppressed during
+// the delay.
+// 
+// Note that with a MIDI KEY, you can choose that an action is
+// generated only for a NOTE_ON event or both for NOTE_ON and
+// NOTE_OFF. In the first case, if the key is associated to MOX,
+// then MOX is toggled each time the key is pressed. This behaves
+// very much like point-and-clicking the MOX buttion in the GUI.
+//
+// If an action is generated both on NOTE_ON and NOTE_OFF,
+// then MOX is engaged when pressing the key and disengaged
+// when releasing it. For MOX this makes little send but you
+// might want to configure the TUNE button this way.
+// The latter behaviour is triggered when the line assigning the key
+// or "NOTE OFF". The table speficying the behaviour of layer-2 thus
+// contains the key word "ONOFF". This is stored in the field "onoff"
+// in struct desc.
+
+struct desc {
+   int               channel;     // -1 for ANY channel
+   enum MIDIevent    event;      // type of event (NOTE on/off, Controller change, Pitch value)
+   int               onoff;       // 1: generate upstream event both for Note-on and Note-off
+   enum MIDItype     type;        // Key, Knob, or Wheel
+   int               low_thr3;    // Wheel only: If controller value is <= this value, generate "very fast down"
+   int               low_thr2;    // Wheel only: If controller value is <= this value, generate "     fast down"
+   int               low_thr1;    // Wheel only: If controller value is <= this value, generate "          down"
+   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)
+   enum MIDIaction   action;     // SDR "action" to generate
+   struct desc       *next;       // Next defined action for a controller/key with that note value.
+};
+
+struct {
+   struct desc *desc[128];    // description for Note On/Off and ControllerChange
+   struct desc *pitch;        // description for PitchChanges
+} MidiCommandsTable;
+
+//
+// Layer-1 entry point, called once for all the MIDI devices
+// that have been defined. This is called upon startup by
+// Layer-2 through the function MIDIstartup.
+//
+void register_midi_device(char *name);
+
+//
+// Layer-2 entry point (called by Layer1)
+// 
+// When Layer-1 has received a MIDI message, it calls
+// NewMidiEvent.
+//
+// MIDIstartup looks for files containing descriptions for MIDI
+// devices and calls the Layer-1 function register_midi_device
+// for each device description that was successfully read.
+
+void NewMidiEvent(enum MIDIevent event, int channel, int note, int val);
+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.
+//
+
+void DoTheMidi(enum MIDIaction code, enum MIDItype type, int val);
diff --git a/midi.inp b/midi.inp
new file mode 100644 (file)
index 0000000..88076ce
--- /dev/null
+++ b/midi.inp
@@ -0,0 +1,33 @@
+#
+# Sample midi.inp file, suitable for a Behringer CMD PL-1 MIDI controller
+#
+# 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)
+#
+DEVICE=CMD PL 1
+CTRL=31 WHEEL THR=59 61 63 65 67 69 ACTION=VFO           # Big wheel:    : main VFO knob
+PITCH ACTION=AFGAIN                                      # Big slider    : AF gain
+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=24 ACTION=TUNE                                       # LOAD    button: TUNE on/off
+KEY=27 ACTION=SWAPVFO                                   # SCRATCH button: Swap VFOs A and B
+KEY=34 ACTION=MOX                                        # CUE     button: MOX on/off
+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
new file mode 100644 (file)
index 0000000..1e737c1
--- /dev/null
+++ b/midi2.c
@@ -0,0 +1,257 @@
+/*
+ * Layer-2 of MIDI support
+ *
+ * (C) Christoph van Wullen, DL1YCF
+ *
+ * Using the data in MIDICommandsTable, this subroutine translates the low-level
+ * MIDI events into MIDI actions in the SDR console.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include "midi.h"
+
+void NewMidiEvent(enum MIDIevent event, int channel, int note, int val) {
+
+    struct desc *desc;
+    int new;
+    static enum MIDIaction last_wheel_action;
+    static struct timespec tp, last_wheel_tp={0,0};
+    long delta;
+
+    if (event == MIDI_PITCH) {
+       desc=MidiCommandsTable.pitch;
+    } else {
+       desc=MidiCommandsTable.desc[note];
+    }
+    while (desc) {
+       if ((desc->channel == channel || desc->channel == -1) && (desc->event == event)) {
+           // Found matching entry
+           switch (desc->event) {
+               case MIDI_NOTE:
+                   if ((val == 1 || (val == 0 && desc->onoff == 1)) && desc->type == MIDI_KEY) {
+                       DoTheMidi(desc->action, desc->type, 0);
+                   }
+                   break;
+               case MIDI_CTRL:
+                   if (desc->type == MIDI_KNOB) {
+                       // normalize value to range 0 - 100
+                       new = (val*100)/127;
+                       DoTheMidi(desc->action, desc->type, new);
+                   } else if (desc->type == MIDI_WHEEL) {
+                       if (desc->delay > 0) {
+                         clock_gettime(CLOCK_MONOTONIC, &tp);
+                         delta=1000*(tp.tv_sec - last_wheel_tp.tv_sec);
+                         delta += (tp.tv_nsec - last_wheel_tp.tv_nsec)/1000000;
+                         if (delta < desc->delay) break;
+                         last_wheel_tp = tp;
+                       }
+                       // translate value to direction
+                       if (val <= desc->low_thr1) new=-1;
+                       if (val <= desc->low_thr2) new=-10;
+                       if (val <= desc->low_thr3) new=-100;
+                       if (val >= desc->up_thr1 ) new=1;
+                       if (val >= desc->up_thr2 ) new=10;
+                       if (val >= desc->up_thr3 ) new=100;
+                       DoTheMidi(desc->action, desc->type, new);
+                       last_wheel_action=desc->action;
+                   }
+                   break;
+               case MIDI_PITCH:
+                   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;
+               default:
+                   break;
+           }
+           break;
+       } else {
+           desc=desc->next;
+       }
+    }
+}
+
+/*
+ * This data structre connects names as used in the midi.inp file with
+ * our MIDIaction enum values
+ */
+
+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"},
+        { BAND_DOWN,    "BANDDOWN"},
+        { FILTER_UP,    "FILTERUP"},
+        { FILTER_DOWN,  "FILTERDOWN"},
+       { MODE_UP,      "MODEUP"},
+       { MODE_DOWN,    "MODEDOWN"},
+       { SWAP_VFO,     "SWAPVFO"},
+        { ACTION_NONE,  NULL}
+};
+
+/*
+ * Translation from keyword in midi.inp file to MIDIaction
+ */
+
+static enum MIDIaction keyword2action(char *s) {
+    int i=0;
+
+    for (i=0; 1; i++) {
+       if (ActionTable[i].str == NULL) return ACTION_NONE;
+       if (!strcmp(s, ActionTable[i].str)) return ActionTable[i].action;
+   }
+   /* NOTREACHED */
+}
+
+/*
+ * Here we read in a MIDI description file "midi.def" and fill the MidiCommandsTable
+ * data structure
+ */
+
+void MIDIstartup() {
+    FILE *fpin,*fpout;
+    char zeile[255];
+    char *cp,*cq;
+    int key;
+    enum MIDIaction action;
+    int chan;
+    int is_wheel;
+    int lt3,lt2,lt1,ut1,ut2,ut3;
+    int onoff, delay;
+    struct desc *desc,*dp;
+    enum MIDItype type;
+    enum MIDIevent event;
+    int i;
+
+    for (i=0; i<128; i++) MidiCommandsTable.desc[i]=NULL;
+    MidiCommandsTable.pitch=NULL;
+
+    fpin=fopen("midi.inp", "r");
+    fpout=stderr;
+    if (!fpin) return;
+
+    for (;;) {
+      if (fgets(zeile, 255, fpin) == NULL) break;
+
+      // ignore comments
+      cp=index(zeile,'#');
+      if (cp == zeile) continue;   // comment line
+      if (cp) *cp=0;               // ignore trailing comment
+
+      if ((cp = strstr(zeile, "DEVICE="))) {
+        // Delete trailing blanks and newlines
+       cq=cp+7;
+        while (*cq != 0 && *cq != '\n' && *cq != ' ' && *cq != '\t') cq++;
+       *cq=0;
+       register_midi_device(cp+7);
+        continue; // nothing more in this line
+      }
+      chan=-1;  // default: any channel
+      lt3=lt2=lt1=0;
+      ut3=ut2=ut1=127;
+      onoff=0;
+      event=EVENT_NONE;
+      type=TYPE_NONE;
+      key=0;
+      delay=0;
+
+      if ((cp = strstr(zeile, "KEY="))) {
+        sscanf(cp+4, "%d", &key);
+        event=MIDI_NOTE;
+       type=MIDI_KEY;
+      }
+      if ((cp = strstr(zeile, "CTRL="))) {
+        sscanf(cp+5, "%d", &key);
+       event=MIDI_CTRL;
+       type=MIDI_KNOB;
+      }
+      if ((cp = strstr(zeile, "PITCH "))) {
+        event=MIDI_PITCH;
+       type=MIDI_KNOB;
+      }
+      if ((cp = strstr(zeile, "CHAN="))) {
+        sscanf(cp+5, "%d", &chan);
+       chan--;
+        if (chan<0 || chan>15) chan=-1;
+      }
+      if ((cp = strstr(zeile, "WHEEL"))) {
+       // change type from MIDI_KNOB to MIDI_WHEEL
+        type=MIDI_WHEEL;
+      }
+      if ((cp = strstr(zeile, "ONOFF"))) {
+        onoff=1;
+      }
+      if ((cp = strstr(zeile, "DELAY="))) {
+        sscanf(cp+6, "%d", &delay);
+      }
+      if ((cp = strstr(zeile, "THR="))) {
+        sscanf(cp+4, "%d %d %d %d %d %d", &lt3, &lt2, &lt1, &ut1, &ut2, &ut3);
+        is_wheel=1;
+      }
+      if ((cp = strstr(zeile, "ACTION="))) {
+        // cut zeile at the first blank character following
+        cq=cp+7;
+        while (*cq != 0 && *cq != '\n' && *cq != ' ' && *cq != '\t') cq++;
+       *cq=0;
+        action=keyword2action(cp+7);
+      }
+      if (event == EVENT_NONE || type == TYPE_NONE || key < 0 || key > 127) continue;
+      // Now all entries of the line have been read. Construct descriptor
+      fprintf(fpout,"K=%d C=%d T=%d E=%d A=%d OnOff=%d THRs=%d %d %d %d %d %d\n",
+        key,chan,type, event, action, onoff, lt3,lt2,lt1,ut1,ut2,ut3);
+      desc = (struct desc *) malloc(sizeof(struct desc));
+      desc->next = NULL;
+      desc->action = action;
+      desc->type = type;
+      desc->event = event;
+      desc->onoff = onoff;
+      desc->delay = delay;
+      desc->low_thr3 = lt3;
+      desc->low_thr2 = lt2;
+      desc->low_thr1 = lt1;
+      desc->up_thr1  = ut1;
+      desc->up_thr2  = ut2;
+      desc->up_thr3  = ut3;
+      desc->channel  = chan;
+      // insert descriptor
+      if (event == MIDI_PITCH) {
+       dp = MidiCommandsTable.pitch;
+       if (dp == NULL) {
+         MidiCommandsTable.pitch = desc;
+       } else {
+         while (dp->next != NULL) dp=dp->next;
+         dp->next=desc;
+       }
+      }
+      if (event == MIDI_KEY || event == MIDI_CTRL) {
+       dp = MidiCommandsTable.desc[key];
+       if (dp == NULL) {
+         MidiCommandsTable.desc[key]=desc;
+       } else {
+         while (dp->next != NULL) dp=dp->next;
+         dp->next=desc;
+       }
+      }
+    }
+}
diff --git a/midi3.c b/midi3.c
new file mode 100644 (file)
index 0000000..f3989d0
--- /dev/null
+++ b/midi3.c
@@ -0,0 +1,233 @@
+/*
+ * Layer-3 of MIDI support
+ * 
+ * (C) Christoph van Wullen, DL1YCF
+ *
+ *
+ * In most cases, a certain action only makes sense for a specific
+ * type. For example, changing the VFO frequency will only be implemeted
+ * for MIDI_WHEEL, and TUNE off/on only with MIDI_KNOB.
+ *
+ * However, changing the volume makes sense both with MIDI_KNOB and MIDI_WHEEL.
+ */
+#include "radio.h"
+#include "vfo.h"
+#include "filter.h"
+#include "band.h"
+#include "mode.h"
+#include "new_menu.h"
+#include "sliders.h"
+#include "ext.h"
+#include "midi.h"
+
+void DoTheMidi(enum MIDIaction action, enum MIDItype type, int val) {
+
+    int new;
+    double dnew;
+    double *dp;
+
+    switch (action) {
+       case SWAP_VFO:  // only key supported
+           if (type == MIDI_KEY) {
+               g_idle_add(ext_vfo_a_swap_b,NULL);
+           }
+           break;    
+       case VFO: // only wheel supported
+           if (type == MIDI_WHEEL) g_idle_add(ext_vfo_step, (gpointer)(uintptr_t) val);
+           break;
+       case TUNE: // only key supported
+           if (type == MIDI_KEY) {
+               new = !tune;
+               g_idle_add(ext_tune_update, (gpointer)(long) new);
+           }
+           break;    
+       case MOX: // only key supported
+           if (type == MIDI_KEY) {
+               new = !mox;
+               g_idle_add(ext_mox_update, (gpointer)(long) new);
+           }
+           break;    
+       case AF_GAIN: // knob or wheel supported
+           if (type == MIDI_KNOB) {
+               active_receiver->volume = 0.01*val;
+           } else  if (type == MIDI_WHEEL) {
+               dnew=active_receiver->volume += 0.01*val;
+               if (dnew < 0.0) dnew=0.0; if (dnew > 1.0) dnew=1.0;
+               active_receiver->volume = dnew;
+           } else {
+               break;
+           }
+           g_idle_add(ext_update_af_gain, NULL);
+           break;
+       case MIC_VOLUME: // knob or wheel supported
+           if (type == MIDI_KNOB) {
+               dnew=-10.0 + 0.6*val;
+           } else if (type == MIDI_WHEEL) {
+               dnew = mic_gain + val;
+               if (dnew < -10.0) dnew=-10.0; if (dnew > 50.0) dnew=50.0;
+           } else {
+               break;
+           }
+           dp=malloc(sizeof(double));
+           *dp=dnew;
+           g_idle_add(ext_set_mic_gain, (gpointer) dp);
+           break;
+       case AGC: // knob or wheel supported
+           if (type == MIDI_KNOB) {
+               dnew = -20.0 + 1.4*val;
+           } else if (type == MIDI_WHEEL) {
+               dnew=active_receiver->agc_gain + val;
+               if (dnew < -20.0) dnew=-20.0; if (dnew > 120.0) dnew=120.0;
+           } else {
+               break;
+           }
+           dp=malloc(sizeof(double));
+           *dp=dnew;
+           g_idle_add(ext_set_agc_gain, (gpointer) dp);
+           break;
+       case TX_DRIVE: // knob or wheel supported
+           if (type == MIDI_KNOB) {
+               dnew = val;
+           } else if (type == MIDI_WHEEL) {
+               dnew=transmitter->drive + val;
+               if (dnew < 0.0) dnew=0.0; if (dnew > 100.0) dnew=100.0;
+           } else {
+               break;
+           }
+           dp=malloc(sizeof(double));
+           *dp=dnew;
+           g_idle_add(ext_set_drive, (gpointer) dp);
+           break;
+       case BAND_UP:     // key or wheel supported
+       case BAND_DOWN:   // key or wheel supported
+           if (type == MIDI_KEY) {
+               new=(action == BAND_UP) ? 1 : -1;
+           } else if (type == MIDI_WHEEL) {
+               new=val;
+           } else {
+               break;
+           }
+            new+=vfo[active_receiver->id].band;
+            if (new >= BANDS) new=0;
+            if (new < 0) new=BANDS-1;
+           g_idle_add(ext_vfo_band_changed, (gpointer) (uintptr_t) new);
+           break;
+       case FILTER_UP:      // key or wheel supported
+       case FILTER_DOWN:    // key or wheel supported
+           if (type == MIDI_KEY) {
+               new=(action == FILTER_UP) ? 1 : -1;
+           } else if (type == MIDI_WHEEL) {
+               new=val;
+           } else {
+               break;
+           }
+           new+=vfo[active_receiver->id].filter;
+           if (new >= FILTERS) new=0;
+           if (new <0) new=FILTERS-1;
+           g_idle_add(ext_vfo_filter_changed, (gpointer) (uintptr_t) new);
+           break;
+       case MODE_UP:      // key or wheel supported
+       case MODE_DOWN:    // key or wheel supported
+           if (type == MIDI_KEY) {
+               new=(action == MODE_UP) ? 1 : -1;
+           } else if (type == MIDI_WHEEL) {
+               new=val;
+           } else {
+               break;
+           }
+           new+=vfo[active_receiver->id].mode;
+           if (new >= MODES) new=0;
+           if (new <0) new=MODES-1;
+           g_idle_add(ext_vfo_mode_changed, (gpointer) (uintptr_t) new);
+           break;
+       case PAN_LOW:  // only wheel supported
+           if (type == MIDI_WHEEL) {
+               if (isTransmitting()) {
+                   // TX panadapter affected
+                   transmitter->panadapter_low += val;
+               } else {
+                   active_receiver->panadapter_low += val;
+               }
+           }
+           break;
+       case RIT_ONOFF:  // only key supported
+           if (type == MIDI_KEY) {
+               vfo[active_receiver->id].rit_enabled = !vfo[active_receiver->id].rit_enabled;
+               g_idle_add(ext_vfo_update, NULL);
+           }
+           break;
+       case RIT_VAL:   // only wheel supported
+           if (type == MIDI_WHEEL) {
+               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;
+               g_idle_add(ext_vfo_update, NULL);
+           }
+           break;
+       case PAN_HIGH:  // only wheel supported
+           if (type == MIDI_WHEEL) {
+               if (mox) {
+                   // TX panadapter affected
+                   transmitter->panadapter_high += val;
+               } else {
+                   active_receiver->panadapter_high += val;
+               }
+           }
+           break;
+       case PRE:       // only key supported
+           if (filter_board == CHARLY25) {
+               new = active_receiver->preamp + active_receiver->dither;
+               new++;
+               if (new >2) new=0;
+               switch (new) {
+                   case 0:
+                       active_receiver->preamp=0;
+                       active_receiver->dither=0;
+                       break;
+                   case 1:
+                       active_receiver->preamp=1;
+                       active_receiver->dither=0;
+                       break;
+                   case 2:
+                       active_receiver->preamp=1;
+                       active_receiver->dither=1;
+                       break;
+               }
+               g_idle_add(ext_update_att_preamp, NULL);
+           } else {
+               new=active_receiver->preamp+1;
+               if (new > 1) new=0;
+               active_receiver->preamp= (new == 1);
+           }
+           break;
+       case ATT:       // Key for ALEX attenuator, wheel or knob for slider
+           switch(type) {
+               case MIDI_KEY:
+                   new=active_receiver->alex_attenuation + 1;
+                   if (new > 3) new=0;
+                   g_idle_add(ext_set_alex_attenuation, (gpointer)(uintptr_t)new);
+                   g_idle_add(ext_update_att_preamp, NULL);
+                   break;
+               case MIDI_WHEEL:
+               case MIDI_KNOB:
+                   if (type == MIDI_WHEEL) {
+                     new=adc_attenuation[active_receiver->adc] + val;
+                     if (new > 31) new=31;
+                     if (new < 0 ) new=0;
+                   } else {
+                     new=(31*val)/100;
+                   }
+                   dp=malloc(sizeof(double));
+                   *dp=new;
+                   g_idle_add(ext_set_attenuation_value,(gpointer) dp);
+                   break;
+               default:
+                   break;
+           }
+           break;
+       default:
+            fprintf(stderr,"Unimplemented in DoTheMidi: A=%d T=%d val=%d\n", action, type, val);
+           break;
+    }
+}
index 024f99e1d16cb265a683eef5851d2756330ac381..235ca122ad543f9b74ca29e0defbaff5f52c4f1d 100644 (file)
@@ -31,6 +31,7 @@
 #include <ifaddrs.h>
 #include <string.h>
 #include <errno.h>
+#include <fcntl.h>
 
 #include "discovered.h"
 #include "discovery.h"
@@ -81,9 +82,12 @@ static void discover(struct ifaddrs* iface) {
        //
        // We make a time-out of 3 secs, otherwise we might "hang" in connect()
        //
+       flags=fcntl(discovery_socket, F_GETFL, 0);
+       fcntl(discovery_socket, F_SETFL, flags | O_NONBLOCK);
         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:");
index 37a5c609c3329969ae093bba073c12e713ecfe81..d6d5924a5c438a5d1bb0a49761c67e4011c87289 100644 (file)
--- a/ps_menu.c
+++ b/ps_menu.c
@@ -221,7 +221,7 @@ static int info_thread(gpointer arg) {
 
     if (transmitter->auto_on) {
       double ddb;
-      int new_att;
+      static int new_att;
       int newcal=info[5]!=old5_2;
       old5_2=info[5];
       switch(state) {
@@ -244,6 +244,7 @@ static int info_thread(gpointer arg) {
            // Actually, we first adjust the attenuation (state=0),
            // then do a PS reset (state=1), and then restart PS (state=2).
             if (transmitter->attenuation != new_att) {
+              SetPSControl(transmitter->id, 1, 0, 0, 0);
              transmitter->attenuation=new_att;
               state=1;
            }
@@ -268,11 +269,10 @@ 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));
-  if(transmitter->auto_on) {
-    transmitter->attenuation=31;
-  } else {
+  if(!transmitter->auto_on) {
     transmitter->attenuation=0;
   }
+
 }
 
 static void resume_cb(GtkWidget *widget, gpointer data) {
diff --git a/radio.c b/radio.c
index c9bb32c00fcafcf0d8f40877951539f165a4f4ba..b47623e27686c25f7b0073c2b78569c1bbec07ff 100644 (file)
--- a/radio.c
+++ b/radio.c
@@ -69,6 +69,9 @@
 #ifdef LOCALCW
 #include "iambic.h"
 #endif
+#ifdef MIDI
+#include "midi.h"
+#endif
 
 #define min(x,y) (x<y?x:y)
 #define max(x,y) (x<y?y:x)
@@ -361,6 +364,11 @@ void start_radio() {
   gdk_window_set_cursor(gtk_widget_get_window(top_window),gdk_cursor_new(GDK_WATCH));
 
   int rc;
+
+#ifdef MIDI
+  MIDIstartup();
+#endif
+
 #ifdef __APPLE__
   property_sem=sem_open("PROPERTY", O_CREAT, 0700, 0);
   rc=(property_sem == SEM_FAILED);
index 442611a6e1fca9129997d3207f787f10797435d8..f60f5db7b0d87105948f730193823d84f77de2e6 100644 (file)
--- a/rigctl.c
+++ b/rigctl.c
@@ -2445,10 +2445,9 @@ void parse_cmd ( char * cmd_input,int len,int client_sock) {
                                                       } else {
                                                          int tval = atoi(&cmd_input[2]);                
                                                          new_vol = (double) (tval * 60/100) - 10; 
-                                                         //set_mic_gain(new_vol); 
                                                          double *p_mic_gain=malloc(sizeof(double));
                                                          *p_mic_gain=new_vol;
-                                                         g_idle_add(update_mic_gain,(void *)p_mic_gain);
+                                                         g_idle_add(ext_set_mic_gain,(void *)p_mic_gain);
                                                       }
                                                    } else {
                                                       if(len <=2) {
@@ -2459,7 +2458,7 @@ void parse_cmd ( char * cmd_input,int len,int client_sock) {
                                                           if((new_vol >= -10) && (new_vol <= 50)) {
                                                             double *p_mic_gain=malloc(sizeof(double));
                                                             *p_mic_gain=new_vol;
-                                                            g_idle_add(update_mic_gain,(void *)p_mic_gain);
+                                                            g_idle_add(ext_set_mic_gain,(void *)p_mic_gain);
                                                           } else {
                                                              send_resp(client_sock,"?;");
                                                           }
index c31afefa8f962a57944f83f6d1d670d4e850f062..8c71cae3a8beeb0470cf7dc0d860096522f5c245 100644 (file)
--- a/sliders.c
+++ b/sliders.c
@@ -188,12 +188,22 @@ void set_attenuation_value(double value) {
 
 void update_att_preamp(void) {
   // CHARLY25: update the ATT/Pre buttons to the values of the active RX
+  // We should also set the attenuation for use in meter.c
   if (filter_board == CHARLY25) {
     char id[] = "x";
+    if (active_receiver->id != 0) {
+      active_receiver->alex_attenuation=0;
+      active_receiver->preamp=0;
+      active_receiver->dither=0;
+      adc_attenuation[active_receiver->adc] = 0;
+    }
     sprintf(id, "%d", active_receiver->alex_attenuation);
+    adc_attenuation[active_receiver->adc] = 12*active_receiver->alex_attenuation;
     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;
   }
 }
 
@@ -385,12 +395,6 @@ void set_mic_gain(double value) {
   }
 }
 
-int update_mic_gain(void *data) {
-  set_mic_gain(*(double*)data);
-  free(data);
-  return 0;
-}
-
 void set_linein_gain(int value) {
   linein_gain=value;
   if(display_sliders) {
@@ -489,7 +493,7 @@ static void compressor_enable_cb(GtkWidget *widget, gpointer data) {
   transmitter_set_compressor(transmitter,gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)));
 }
 
-void set_squelch(RECEIVER* rx) {
+void set_squelch() {
   setSquelch(active_receiver);
   if(display_sliders) {
     gtk_range_set_value (GTK_RANGE(squelch_scale),active_receiver->squelch);
index 87904f74119d630b0c10764570a4ee72253439c9..a33ac7f5a33ccff6ce3a00d783be19bf2b8789a1 100644 (file)
--- a/sliders.h
+++ b/sliders.h
@@ -43,7 +43,7 @@ extern GtkWidget *sliders_init(int my_width, int my_height);
 
 extern void sliders_update();
 
-extern void set_squelch(RECEIVER* rx);
+extern void set_squelch();
 extern void set_compression(TRANSMITTER *tx);
 
 #endif