]> git.rkrishnan.org Git - pihpsdr.git/commitdiff
First set of changes for gpiod. Added new i2c Controller support.
authorG0ORX <john.d.melton@googlemail.com>
Tue, 8 Dec 2020 09:54:34 +0000 (09:54 +0000)
committerG0ORX <john.d.melton@googlemail.com>
Tue, 8 Dec 2020 09:54:34 +0000 (09:54 +0000)
33 files changed:
Makefile
actions.c [new file with mode: 0644]
actions.h [new file with mode: 0644]
agc_menu.c
band_menu.c
bandstack_menu.c
configure.c
discovery.c
encoder_menu.c
exit_menu.c
ext.c
filter_menu.c
gpio.c
gpio.h
i2c.c
i2cEncoderLibV2.c [new file with mode: 0644]
i2cEncoderLibV2.h [new file with mode: 0644]
i2c_controller.c [new file with mode: 0644]
i2c_controller.h [new file with mode: 0644]
i2c_controller_menu.c [new file with mode: 0644]
i2c_controller_menu.h [new file with mode: 0644]
main.c
mode_menu.c
new_menu.c
noise_menu.c
radio.c
radio_menu.c
rx_panadapter.c
switch_menu.c
toolbar.c
tx_panadapter.c
vfo.c
vfo_menu.c

index fe69b75b25f709e758548fdc44419dd50d2088e0..bef62670799e60b51431e77968e9ff39e04a679a 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,9 +2,20 @@
 GIT_DATE := $(firstword $(shell git --no-pager show --date=short --format="%ai" --name-only))
 GIT_VERSION := $(shell git describe --abbrev=0 --tags)
 
+ISSUE := $(shell cat /etc/issue.net)
+ifneq ($(filter %Raspbian,$(ISSUE)),)
+       OSFLAG=-D RASPIAN
+endif
+
+# uncomment the following line to force 480x320 screen
+#SMALL_SCREEN_OPTIONS=-D SMALL_SCREEN
+
 # uncomment the line below to include GPIO (For original piHPSDR Controller and Controller2 with i2c)
 GPIO_INCLUDE=GPIO
 
+# uncomment the following line to include support for the new i2c controller
+#I2C_CONTROLLER_INCLUDE=I2C_CONTROLLER
+
 # uncomment the line below to include USB Ozy support
 # USBOZY_INCLUDE=USBOZY
 
@@ -109,9 +120,23 @@ ifeq ($(PTT_INCLUDE),PTT)
 PTT_OPTIONS=-D PTT
 endif
 
+ifeq ($(I2C_CONTROLLER_INCLUDE),I2C_CONTROLLER)
+  I2C_CONTROLLER_OPTIONS=-D I2C_CONTROLLER
+  I2C_CONTROLLER_LIBS=-lgpiod -li2c
+  I2C_CONTROLLER_SOURCES= \
+  i2c_controller.c \
+  i2c_controller_menu.c
+  I2C_CONTROLLER_HEADERS= \
+  i2c_controller.h \
+  i2c_controller_menu.h
+  I2C_CONTROLLER_OBJS= \
+  i2c_controller.o \
+  i2c_controller_menu.o
+endif
+
 ifeq ($(GPIO_INCLUDE),GPIO)
   GPIO_OPTIONS=-D GPIO
-  GPIO_LIBS=-lwiringPi
+  GPIO_LIBS=-lgpiod -li2c
   GPIO_SOURCES= \
   configure.c \
   i2c.c \
@@ -173,14 +198,14 @@ AUDIO_LIBS=-lasound
 #AUDIO_LIBS=-lsoundio
 
 CFLAGS=        -g -Wno-deprecated-declarations -O3
-OPTIONS=$(MIDI_OPTIONS) $(PURESIGNAL_OPTIONS) $(REMOTE_OPTIONS) $(USBOZY_OPTIONS) \
-       $(GPIO_OPTIONS) $(SOAPYSDR_OPTIONS) $(LOCALCW_OPTIONS) \
+OPTIONS=$(SMALL_SCREEN_OPTIONS) $(I2C_ENCODERS_OPTIONS) $(MIDI_OPTIONS) $(PURESIGNAL_OPTIONS) $(REMOTE_OPTIONS) $(USBOZY_OPTIONS) \
+       $(I2C_CONTROLLER_OPTIONS) $(GPIO_OPTIONS) $(SOAPYSDR_OPTIONS) $(LOCALCW_OPTIONS) \
        $(STEMLAB_OPTIONS) \
         $(PTT_OPTIONS) \
        $(SERVER_OPTIONS) \
-       -D GIT_DATE='"$(GIT_DATE)"' -D GIT_VERSION='"$(GIT_VERSION)"' $(DEBUG_OPTION)
+       -D GIT_DATE='"$(GIT_DATE)"' -D GIT_VERSION='"$(GIT_VERSION)"' $(DEBUG_OPTION) $(OSFLAG)
 
-LIBS=-lrt -lm -lwdsp -lpthread $(AUDIO_LIBS) $(USBOZY_LIBS) $(GTKLIBS) $(GPIO_LIBS) $(SOAPYSDRLIBS) $(STEMLAB_LIBS) $(MIDI_LIBS)
+LIBS=-lrt -lm -lwdsp -lpthread $(AUDIO_LIBS) $(USBOZY_LIBS) $(GTKLIBS) $(I2C_CONTROLLER_LIBS) $(GPIO_LIBS) $(SOAPYSDRLIBS) $(STEMLAB_LIBS) $(MIDI_LIBS)
 INCLUDES=$(GTKINCLUDES)
 
 COMPILE=$(CC) $(CFLAGS) $(OPTIONS) $(INCLUDES)
@@ -255,7 +280,9 @@ led.c \
 ext.c \
 error_handler.c \
 cwramp.c \
-protocols.c
+protocols.c \
+css.c \
+actions.c
 
 
 HEADERS= \
@@ -324,7 +351,9 @@ memory.h \
 led.h \
 ext.h \
 error_handler.h \
-protocols.h
+protocols.h \
+css.h \
+actions.h
 
 
 OBJS= \
@@ -392,21 +421,23 @@ led.o \
 ext.o \
 error_handler.o \
 cwramp.o \
-protocols.o
+protocols.o \
+css.o \
+actions.o
 
 $(PROGRAM):  $(OBJS) $(REMOTE_OBJS) $(USBOZY_OBJS) $(SOAPYSDR_OBJS) \
-               $(LOCALCW_OBJS) $(GPIO_OBJS) $(PURESIGNAL_OBJS) \
+               $(LOCALCW_OBJS) $(I2C_CONTROLLER_OBJS) $(GPIO_OBJS) $(PURESIGNAL_OBJS) \
                $(MIDI_OBJS) $(STEMLAB_OBJS) $(SERVER_OBJS)
-       $(LINK) -o $(PROGRAM) $(OBJS) $(REMOTE_OBJS) $(USBOZY_OBJS) $(GPIO_OBJS) \
+       $(LINK) -o $(PROGRAM) $(OBJS) $(REMOTE_OBJS) $(USBOZY_OBJS) $(I2C_CONTROLLER_OBJS) $(GPIO_OBJS) \
                $(SOAPYSDR_OBJS) $(LOCALCW_OBJS) $(PURESIGNAL_OBJS) \
                $(MIDI_OBJS) $(STEMLAB_OBJS) $(SERVER_OBJS) $(LIBS)
 
 .PHONY:        all
 all:   prebuild  $(PROGRAM) $(HEADERS) $(USBOZY_HEADERS) $(SOAPYSDR_HEADERS) \
-       $(LOCALCW_HEADERS) $(GPIO_HEADERS) \
+       $(LOCALCW_HEADERS) $(I2C_CONTROLLER_HEADERS) $(GPIO_HEADERS) \
        $(PURESIGNAL_HEADERS) $(MIDI_HEADERS) $(STEMLAB_HEADERS) $(SERVER_HEADERS)\
        $(SOURCES) \
-       $(USBOZY_SOURCES) $(SOAPYSDR_SOURCES) $(LOCALCW_SOURCE) $(GPIO_SOURCES) \
+       $(USBOZY_SOURCES) $(SOAPYSDR_SOURCES) $(LOCALCW_SOURCE) $(I2C_CONTROLLER_SOURCES) $(GPIO_SOURCES) \
        $(PURESIGNAL_SOURCES) $(MIDI_SOURCES) $(STEMLAB_SOURCES) $(SERVER_SOURCES)
 
 .PHONY:        prebuild
@@ -425,7 +456,7 @@ CPPINCLUDES:=$(shell echo $(INCLUDES) | sed -e "s/-pthread / /" )
 .PHONY:        cppcheck
 cppcheck:
        cppcheck $(CPPOPTIONS) $(OPTIONS) $(CPPINCLUDES) $(SOURCES) $(REMOTE_SOURCES) \
-       $(USBOZY_SOURCES) $(SOAPYSDR_SOURCES) $(GPIO_SOURCES) \
+       $(USBOZY_SOURCES) $(SOAPYSDR_SOURCES) $(I2C_CONTROLLER_SOURCES) $(GPIO_SOURCES) \
        $(PURESIGNAL_SOURCES) $(MIDI_SOURCES) $(STEMLAB_SOURCES) $(LOCALCW_SOURCES) \
        $(SERVER_SOURCES)
 
diff --git a/actions.c b/actions.c
new file mode 100644 (file)
index 0000000..cb5775b
--- /dev/null
+++ b/actions.c
@@ -0,0 +1,852 @@
+#include <gtk/gtk.h>
+
+#include "main.h"
+#include "discovery.h"
+#include "receiver.h"
+#include "sliders.h"
+#include "toolbar.h"
+#include "band_menu.h"
+#include "diversity_menu.h"
+#include "vfo.h"
+#include "radio.h"
+#include "radio_menu.h"
+#include "new_menu.h"
+#include "new_protocol.h"
+#ifdef PURESIGNAL
+#include "ps_menu.h"
+#endif
+#include "agc.h"
+#include "filter.h"
+#include "mode.h"
+#include "band.h"
+#include "bandstack.h"
+#include "noise_menu.h"
+#include "wdsp.h"
+#ifdef CLIENT_SERVER
+#include "client_server.h"
+#endif
+#include "ext.h"
+#include "zoompan.h"
+#include "actions.h"
+#include "gpio.h"
+
+char *encoder_string[ENCODER_ACTIONS] = {
+  "NO ACTION",
+  "AF GAIN",
+  "AF GAIN RX1",
+  "AF GAIN RX2",
+  "AGC GAIN",
+  "AGC GAIN RX1",
+  "AGC GAIN RX2",
+  "ATTENUATION/RX GAIN",
+  "COMP",
+  "CW FREQUENCY",
+  "CW SPEED",
+  "DIVERSITY GAIN",
+  "DIVERSITY GAIN (coarse)",
+  "DIVERSITY GAIN (fine)",
+  "DIVERSITY PHASE",
+  "DIVERSITY PHASE (coarse)",
+  "DIVERSITY PHASE (fine)",
+  "DRIVE",
+  "IF SHIFT",
+  "IF SHIFT RX1",
+  "IF SHIFT RX2",
+  "IF WIDTH",
+  "IF WIDTH RX1",
+  "IF WIDTH RX2",
+  "MIC GAIN",
+  "PAN",
+  "PANADAPTER HIGH",
+  "PANADAPTER LOW",
+  "PANADAPTER STEP",
+  "RF GAIN",
+  "RF GAIN RX1",
+  "RF GAIN RX2",
+  "RIT",
+  "RIT RX1",
+  "RIT RX2",
+  "SQUELCH",
+  "SQUELCH RX1",
+  "SQUELCH RX2",
+  "TUNE DRIVE",
+  "VFO",
+  "WATERFALL HIGH",
+  "WATERFALL LOW",
+  "XIT",
+  "ZOOM"
+};
+
+char *sw_string[SWITCH_ACTIONS] = {
+  "",
+  "A TO B",
+  "A SWAP B",
+  "AGC",
+  "ANF",
+  "B TO A",
+  "BAND -",
+  "BAND +",
+  "BSTACK -",
+  "BSTACK +",
+  "CTUN",
+  "DIV",
+  "DUPLEX",
+  "FILTER -",
+  "FILTER +",
+  "FUNCTION",
+  "LOCK",
+  "MENU AGC",
+  "MENU BAND",
+  "MENU BSTACK",
+  "MENU DIV",
+  "MENU FILTER",
+  "MENU FREQUENCY",
+  "MENU MEMORY",
+  "MENU MODE",
+  "MENU NOISE",
+  "MENU PS",
+  "MODE -",
+  "MODE +",
+  "MOX",
+  "MUTE",
+  "NB",
+  "NR",
+  "PAN -",
+  "PAN +",
+  "PS",
+  "RIT",
+  "RIT CL",
+  "RIT -",
+  "RIT +",
+  "RSAT",
+  "SAT",
+  "SNB",
+  "SPLIT",
+  "TUNE",
+  "TUNE FULL",
+  "TUNE MEMORY",
+  "TWO TONE",
+  "XIT",
+  "XIT CL",
+  "XIT -",
+  "XIT +",
+  "ZOOM -",
+  "ZOOM +"
+};
+
+char *sw_cap_string[SWITCH_ACTIONS] = {
+  "",
+  "A>B",
+  "A<>B",
+  "AGC",
+  "ANF",
+  "B>A",
+  "BND-",
+  "BND+",
+  "BST-",
+  "BST+",
+  "CTUN",
+  "DIV",
+  "DUP",
+  "FLT-",
+  "FLT+",
+  "FUNC",
+  "LOCK",
+  "AGC",
+  "BAND",
+  "BSTACK",
+  "DIV",
+  "FILTER",
+  "FREQ",
+  "MEM",
+  "MODE",
+  "NOISE",
+  "PS",
+  "MD-",
+  "MD+",
+  "MOX",
+  "MUTE",
+  "NB",
+  "NR",
+  "PAN-",
+  "PAN+",
+  "PS",
+  "RIT",
+  "RIT0",
+  "RIT+",
+  "RIT-",
+  "RSAT",
+  "SAT",
+  "SNB",
+  "SPLIT",
+  "TUNE",
+  "TUN-F",
+  "TUN-M",
+  "2TONE",
+  "XIT",
+  "XIT0",
+  "XIT+",
+  "XIT-",
+  "ZOOM-",
+  "ZOOM+",
+};
+
+
+int encoder_action(void *data) {
+  ENCODER_ACTION *a=(ENCODER_ACTION *)data;
+  double value;
+  int mode;
+  int id;
+  FILTER * band_filters=filters[vfo[active_receiver->id].mode];
+  FILTER *band_filter;
+  FILTER *filter;
+  int new_val;
+
+  switch(a->action) {
+    case ENCODER_VFO:
+      vfo_step(a->val);
+      break;
+    case ENCODER_AF_GAIN:
+      value=active_receiver->volume;
+      value+=a->val/100.0;
+      if(value<0.0) {
+        value=0.0;
+      } else if(value>1.0) {
+        value=1.0;
+      }
+      set_af_gain(active_receiver->id,value);
+      break;
+    case ENCODER_AF_GAIN_RX1:
+      value=receiver[0]->volume;
+      value+=a->val/100.0;
+      if(value<0.0) {
+        value=0.0;
+      } else if(value>1.0) {
+        value=1.0;
+      }
+      set_af_gain(0,value);
+      break;
+    case ENCODER_AF_GAIN_RX2:
+      value=receiver[1]->volume;
+      value+=a->val/100.0;
+      if(value<0.0) {
+        value=0.0;
+      } else if(value>1.0) {
+        value=1.0;
+      }
+      set_af_gain(1,value);
+      break;
+    case ENCODER_RF_GAIN:
+      value=active_receiver->rf_gain;
+      value+=a->val;
+      if(value<0.0) {
+        value=0.0;
+      } else if(value>100.0) {
+        value=100.0;
+      }
+      set_rf_gain(active_receiver->id,value);
+      break;
+    case ENCODER_RF_GAIN_RX1:
+      value=receiver[0]->rf_gain;
+      value+=a->val;
+      if(value<0.0) {
+        value=0.0;
+      } else if(value>100.0) {
+        value=100.0;
+      }
+      set_rf_gain(0,value);
+      break;
+    case ENCODER_RF_GAIN_RX2:
+      value=receiver[1]->rf_gain;
+      value+=a->val;
+      if(value<0.0) {
+        value=0.0;
+      } else if(value>71.0) {
+        value=71.0;
+      }
+      set_rf_gain(1,value);
+      break;
+    case ENCODER_AGC_GAIN:
+      value=active_receiver->agc_gain;
+      value+=a->val;
+      if(value<-20.0) {
+        value=-20.0;
+      } else if(value>120.0) {
+        value=120.0;
+      }
+      set_agc_gain(active_receiver->id,value);
+      break;
+    case ENCODER_AGC_GAIN_RX1:
+      value=receiver[0]->agc_gain;
+      value+=a->val;
+      if(value<-20.0) {
+        value=-20.0;
+      } else if(value>120.0) {
+        value=120.0;
+      }
+      set_agc_gain(0,value);
+      break;
+    case ENCODER_AGC_GAIN_RX2:
+      value=receiver[1]->agc_gain;
+      value+=a->val;
+      if(value<-20.0) {
+        value=-20.0;
+      } else if(value>120.0) {
+        value=120.0;
+      }
+      set_agc_gain(1,value);
+      break;
+    case ENCODER_IF_WIDTH:
+      filter_width_changed(active_receiver->id,a->val);
+      break;
+    case ENCODER_IF_WIDTH_RX1:
+      filter_width_changed(0,a->val);
+      break;
+    case ENCODER_IF_WIDTH_RX2:
+      filter_width_changed(1,a->val);
+      break;
+    case ENCODER_IF_SHIFT:
+      filter_shift_changed(active_receiver->id,a->val);
+      break;
+    case ENCODER_IF_SHIFT_RX1:
+      filter_shift_changed(0,a->val);
+      break;
+    case ENCODER_IF_SHIFT_RX2:
+      filter_shift_changed(1,a->val);
+      break;
+    case ENCODER_ATTENUATION:
+      value=(double)adc_attenuation[active_receiver->adc];
+      value+=(double)a->val;
+      if(have_rx_gain) {
+        if(value<-12.0) {
+          value=-12.0;
+        } else if(value>48.0) {
+          value=48.0;
+        }
+      } else {
+        if(value<0.0) {
+          value=0.0;
+        } else if (value>31.0) {
+          value=31.0;
+        }
+      }
+      set_attenuation_value(value);
+      break;
+    case ENCODER_MIC_GAIN:
+      value=mic_gain;
+      value+=(double)a->val;
+      if(value<-12.0) {
+        value=-12.0;
+      } else if(value>50.0) {
+        value=50.0;
+      }
+      set_mic_gain(value);
+      break;
+    case ENCODER_DRIVE:
+      value=getDrive();
+      value+=(double)a->val;
+      if(value<0.0) {
+        value=0.0;
+      } else if(value>drive_max) {
+        value=drive_max;
+      }
+      set_drive(value);
+      break;
+    case ENCODER_RIT:
+      vfo_rit(active_receiver->id,a->val);
+      break;
+    case ENCODER_RIT_RX1:
+      vfo_rit(receiver[0]->id,a->val);
+      break;
+    case ENCODER_RIT_RX2:
+      vfo_rit(receiver[1]->id,a->val);
+      break;
+    case ENCODER_XIT:
+      value=(double)transmitter->xit;
+      value+=(double)(a->val*rit_increment);
+      if(value<-10000.0) {
+        value=-10000.0;
+      } else if(value>10000.0) {
+        value=10000.0;
+      }
+      transmitter->xit=(int)value;
+      if(protocol==NEW_PROTOCOL) {
+        schedule_high_priority();
+      }
+      g_idle_add(ext_vfo_update,NULL);
+      break;
+    case ENCODER_CW_SPEED:
+      value=(double)cw_keyer_speed;
+      value+=(double)a->val;
+      if(value<1.0) {
+        value=1.0;
+      } else if(value>60.0) {
+        value=60.0;
+      }
+      cw_keyer_speed=(int)value;
+      g_idle_add(ext_vfo_update,NULL);
+      break;
+    case ENCODER_CW_FREQUENCY:
+      value=(double)cw_keyer_sidetone_frequency;
+      value+=(double)a->val;
+      if(value<0.0) {
+        value=0.0;
+      } else if(value>1000.0) {
+        value=1000.0;
+      }
+      cw_keyer_sidetone_frequency=(int)value;
+      g_idle_add(ext_vfo_update,NULL);
+      break;
+    case ENCODER_PANADAPTER_HIGH:
+      value=(double)active_receiver->panadapter_high;
+      value+=(double)a->val;
+      active_receiver->panadapter_high=(int)value;
+      break;
+    case ENCODER_PANADAPTER_LOW:
+      value=(double)active_receiver->panadapter_low;
+      value+=(double)a->val;
+      active_receiver->panadapter_low=(int)value;
+      break;
+    case ENCODER_PANADAPTER_STEP:
+      value=(double)active_receiver->panadapter_step;
+      value+=(double)a->val;
+      active_receiver->panadapter_step=(int)value;
+      break;
+    case ENCODER_WATERFALL_HIGH:
+      value=(double)active_receiver->waterfall_high;
+      value+=(double)a->val;
+      active_receiver->waterfall_high=(int)value;
+      break;
+    case ENCODER_WATERFALL_LOW:
+      value=(double)active_receiver->waterfall_low;
+      value+=(double)a->val;
+      active_receiver->waterfall_low=(int)value;
+      break;
+    case ENCODER_SQUELCH:
+      value=active_receiver->squelch;
+      value+=(double)a->val;
+      if(value<0.0) {
+        value=0.0;
+      } else if(value>100.0) {
+        value=100.0;
+      }
+      active_receiver->squelch=value;
+      set_squelch(active_receiver);
+      break;
+    case ENCODER_SQUELCH_RX1:
+      value=receiver[0]->squelch;
+      value+=(double)a->val;
+      if(value<0.0) {
+        value=0.0;
+      } else if(value>100.0) {
+        value=100.0;
+      }
+      receiver[0]->squelch=value;
+      set_squelch(receiver[0]);
+      break;
+    case ENCODER_SQUELCH_RX2:
+      value=receiver[1]->squelch;
+      value+=(double)a->val;
+      if(value<0.0) {
+        value=0.0;
+      } else if(value>100.0) {
+        value=100.0;
+      }
+      receiver[1]->squelch=value;
+      set_squelch(receiver[1]);
+      break;
+    case ENCODER_COMP:
+      value=(double)transmitter->compressor_level;
+      value+=(double)a->val;
+      if(value<0.0) {
+        value=0.0;
+      } else if(value>20.0) {
+        value=20.0;
+      }
+      transmitter->compressor_level=(int)value;
+      set_compression(transmitter);
+      break;
+    case ENCODER_DIVERSITY_GAIN:
+      update_diversity_gain((double)a->val * 0.5);
+      break;
+    case ENCODER_DIVERSITY_GAIN_COARSE:
+      update_diversity_gain((double)a->val * 2.5);
+      break;
+    case ENCODER_DIVERSITY_GAIN_FINE:
+      update_diversity_gain((double)a->val * 0.1);
+      break;
+    case ENCODER_DIVERSITY_PHASE:
+      update_diversity_phase((double)a->val* 0.5);
+      break;
+    case ENCODER_DIVERSITY_PHASE_COARSE:
+      update_diversity_phase((double)a->val*2.5);
+      break;
+    case ENCODER_DIVERSITY_PHASE_FINE:
+      update_diversity_phase((double)a->val*0.1);
+      break;
+    case ENCODER_ZOOM:
+      update_zoom((double)a->val);
+      break;
+    case ENCODER_PAN:
+      update_pan((double)a->val*100);
+      break;
+  }
+  g_free(data);
+  return 0;
+}
+
+int switch_action(void *data) {
+  SWITCH_ACTION *a=(SWITCH_ACTION *)data;
+  if(a->state==PRESSED) {
+    switch(a->action) {
+      case FUNCTION:
+        if(controller==CONTROLLER1) {
+          function++;
+          if(function>=MAX_FUNCTIONS) {
+            function=0;
+          }
+          switches=switches_controller1[function];
+          update_toolbar_labels();
+        }
+        break;
+      case TUNE:
+        if(getMox()==1) {
+          setMox(0);
+        }
+        if(a->state) {
+          setTune(0);
+          if(canTransmit() || tx_out_of_band) {
+            setTune(1);
+          } else {
+            transmitter_set_out_of_band(transmitter);
+          }
+        } else {
+          setTune(a->state);
+        }
+        g_idle_add(ext_vfo_update,NULL);
+        break;
+      case MOX:
+        if(getTune()==1) {
+          setTune(0);
+        }
+        if(a->state) {
+          if(canTransmit() || tx_out_of_band) {
+            setMox(a->state);
+          } else {
+            transmitter_set_out_of_band(transmitter);
+          }
+        } else {
+          setMox(a->state);
+        }
+        g_idle_add(ext_vfo_update,NULL);
+        break;
+      case PS:
+#ifdef PURESIGNAL
+        if(can_transmit) {
+          if(transmitter->puresignal==0) {
+            tx_set_ps(transmitter,1);
+          } else {
+            tx_set_ps(transmitter,0);
+          }
+        }
+#endif
+        break;
+      case TWO_TONE:
+        if(can_transmit) {
+          int state=transmitter->twotone?0:1;
+          tx_set_twotone(transmitter,state);
+        }
+        break;
+      case NR:
+        if(active_receiver->nr==0 && active_receiver->nr2==0) {
+          active_receiver->nr=1;
+          active_receiver->nr2=0;
+          mode_settings[vfo[active_receiver->id].mode].nr=1;
+          mode_settings[vfo[active_receiver->id].mode].nr2=0;
+        } else if(active_receiver->nr==1 && active_receiver->nr2==0) {
+          active_receiver->nr=0;
+          active_receiver->nr2=1;
+          mode_settings[vfo[active_receiver->id].mode].nr=0;
+          mode_settings[vfo[active_receiver->id].mode].nr2=1;
+        } else if(active_receiver->nr==0 && active_receiver->nr2==1) {
+          active_receiver->nr=0;
+          active_receiver->nr2=0;
+          mode_settings[vfo[active_receiver->id].mode].nr=0;
+          mode_settings[vfo[active_receiver->id].mode].nr2=0;
+        }
+        update_noise();
+        break;
+      case NB:
+        if(active_receiver->nb==0 && active_receiver->nb2==0) {
+          active_receiver->nb=1;
+          active_receiver->nb2=0;
+          mode_settings[vfo[active_receiver->id].mode].nb=1;
+          mode_settings[vfo[active_receiver->id].mode].nb2=0;
+        } else if(active_receiver->nb==1 && active_receiver->nb2==0) {
+          active_receiver->nb=0;
+          active_receiver->nb2=1;
+          mode_settings[vfo[active_receiver->id].mode].nb=0;
+          mode_settings[vfo[active_receiver->id].mode].nb2=1;
+        } else if(active_receiver->nb==0 && active_receiver->nb2==1) {
+          active_receiver->nb=0;
+          active_receiver->nb2=0;
+          mode_settings[vfo[active_receiver->id].mode].nb=0;
+          mode_settings[vfo[active_receiver->id].mode].nb2=0;
+        }
+        update_noise();
+        break;
+      case SNB:
+        if(active_receiver->snb==0) {
+          active_receiver->snb=1;
+          mode_settings[vfo[active_receiver->id].mode].snb=1;
+        } else {
+          active_receiver->snb=0;
+          mode_settings[vfo[active_receiver->id].mode].snb=0;
+        }
+        update_noise();
+        break;
+      case RIT:
+        vfo_rit_update(active_receiver->id);
+        break;
+      case RIT_CLEAR:
+        vfo_rit_clear(active_receiver->id);
+        break;
+      case XIT:
+        if(can_transmit) {
+          transmitter->xit_enabled=transmitter->xit_enabled==1?0:1;
+          if(protocol==NEW_PROTOCOL) {
+            schedule_high_priority();
+          }
+        }
+        g_idle_add(ext_vfo_update, NULL);
+        break;
+      case XIT_CLEAR:
+        if(can_transmit) {
+          transmitter->xit=0;
+          g_idle_add(ext_vfo_update, NULL);
+        }
+        break;
+      case BAND_PLUS:
+        {
+        long long frequency_min=radio->frequency_min;
+        long long frequency_max=radio->frequency_max;
+        int b=vfo[active_receiver->id].band;
+        BAND *band;
+        int found=0;
+        while(!found) {
+          b++;
+          if(b>=BANDS+XVTRS) b=0;
+          band=(BAND*)band_get_band(b);
+          if(strlen(band->title)>0) {
+            if(b<BANDS) {
+              if(!(band->frequencyMin==0.0 && band->frequencyMax==0.0)) {
+                if(band->frequencyMin<frequency_min || band->frequencyMax>frequency_max) {
+                  continue;
+                }
+              }
+            }
+            vfo_band_changed(active_receiver->id,b);
+            found=1;
+          }
+        }
+        }
+        break;
+      case BAND_MINUS:
+        {
+        long long frequency_min=radio->frequency_min;
+        long long frequency_max=radio->frequency_max;
+        int b=vfo[active_receiver->id].band;
+        BAND *band;
+        int found=0;
+        while(!found) {
+          b--;
+          if(b<0) b=BANDS+XVTRS-1;
+          band=(BAND*)band_get_band(b);
+          if(strlen(band->title)>0) {
+            if(b<BANDS) {
+              if(band->frequencyMin<frequency_min || band->frequencyMax>frequency_max) {
+                continue;
+              }
+            }
+            vfo_band_changed(active_receiver->id,b);
+            found=1;
+          }
+        }
+        }
+        break;
+      case BANDSTACK_PLUS:
+        {
+        BAND *band=band_get_band(vfo[active_receiver->id].band);
+        BANDSTACK *bandstack=band->bandstack;
+        int b=vfo[active_receiver->id].bandstack+1;
+        if(b>=bandstack->entries) b=0;
+        vfo_bandstack_changed(b);
+        }
+        break;
+      case BANDSTACK_MINUS:
+        {
+        BAND *band=band_get_band(vfo[active_receiver->id].band);
+        BANDSTACK *bandstack=band->bandstack;
+        int b=vfo[active_receiver->id].bandstack-1;
+        if(b<0) b=bandstack->entries-1;;
+        vfo_bandstack_changed(b);
+        }
+        break;
+      case MODE_PLUS:
+        {
+        int mode=vfo[active_receiver->id].mode;
+        mode++;
+        if(mode>=MODES) mode=0;
+        vfo_mode_changed(mode);
+        }
+        break;
+      case MODE_MINUS:
+        {
+        int mode=vfo[active_receiver->id].mode;
+        mode--;
+        if(mode<0) mode=MODES-1;
+        vfo_mode_changed(mode);
+        }
+        break;
+      case FILTER_PLUS:
+        {
+        int f=vfo[active_receiver->id].filter-1;
+        if(f<0) f=FILTERS-1;
+        vfo_filter_changed(f);
+        }
+        break;
+      case FILTER_MINUS:
+        {
+        int f=vfo[active_receiver->id].filter+1;
+        if(f>=FILTERS) f=0;
+        vfo_filter_changed(f);
+        }
+        break;
+      case A_TO_B:
+        vfo_a_to_b();
+        break;
+      case B_TO_A:
+        vfo_b_to_a();
+        break;
+      case A_SWAP_B:
+        vfo_a_swap_b();
+        break;
+      case LOCK:
+#ifdef CLIENT_SERVER
+        if(radio_is_remote) {
+          send_lock(client_socket,locked==1?0:1);
+        } else {
+#endif
+          locked=locked==1?0:1;
+          g_idle_add(ext_vfo_update, NULL);
+#ifdef CLIENT_SERVER
+        }
+#endif
+        break;
+      case CTUN:
+        vfo[active_receiver->id].ctun=a->state;
+        if(!vfo[active_receiver->id].ctun) {
+          vfo[active_receiver->id].offset=0;
+        }
+        vfo[active_receiver->id].ctun_frequency=vfo[active_receiver->id].frequency;
+        set_offset(receiver[active_receiver->id],vfo[active_receiver->id].offset);
+        break;
+      case AGC:
+        active_receiver->agc++;
+        if(active_receiver->agc>+AGC_LAST) {
+          active_receiver->agc=0;
+        }
+        set_agc(active_receiver, active_receiver->agc);
+        g_idle_add(ext_vfo_update, NULL);
+        break;
+      case SPLIT:
+        if(can_transmit) {
+          split=split==1?0:1;
+          tx_set_mode(transmitter,get_tx_mode());
+          g_idle_add(ext_vfo_update, NULL);
+        }
+        break;
+      case DIVERSITY:
+        diversity_enabled=diversity_enabled==1?0:1;
+        if (protocol == NEW_PROTOCOL) {
+          schedule_high_priority();
+          schedule_receive_specific();
+        }
+        g_idle_add(ext_vfo_update, NULL);
+        break;
+      case SAT:
+        switch(sat_mode) {
+          case SAT_NONE:
+            sat_mode=SAT_MODE;
+            break;
+          case SAT_MODE:
+            sat_mode=RSAT_MODE;
+            break;
+          case RSAT_MODE:
+            sat_mode=SAT_NONE;
+            break;
+        }
+        g_idle_add(ext_vfo_update, NULL);
+        break;
+      case MENU_AGC:
+        start_agc();
+        break;
+      case MENU_BAND:
+        start_band();
+        break;
+      case MENU_BANDSTACK:
+        start_bandstack();
+        break;
+      case MENU_MODE:
+        start_mode();
+        break;
+      case MENU_NOISE:
+        start_noise();
+        break;
+      case MENU_FILTER:
+        start_filter();
+        break;
+      case MENU_FREQUENCY:
+        start_vfo(active_receiver->id);
+        break;
+      case MENU_MEMORY:
+        start_store();
+        break;
+      case MENU_DIVERSITY:
+        start_diversity();
+        break;
+#ifdef PURESIGNAL
+      case MENU_PS:
+        start_ps();
+        break;
+#endif
+      case MUTE:
+        active_receiver->mute_radio=!active_receiver->mute_radio;
+        break;
+      case PAN_MINUS:
+        update_pan(-100.0);
+        break;
+      case PAN_PLUS:
+        update_pan(+100.0);
+        break;
+      case ZOOM_MINUS:
+        update_zoom(-1);
+        break;
+      case ZOOM_PLUS:
+        update_zoom(+1);
+        break;
+      default:
+        g_print("%s: UNKNOWN PRESSED SWITCH ACTION %d\n",__FUNCTION__,a->action);
+        break;
+    }
+  } else if(a->state==RELEASED) {
+    // only switch functions that increment/decrement while pressed
+    switch(a->action) {
+      default:
+        break;
+    }
+  }
+  g_free(data);
+  return 0;
+}
+
diff --git a/actions.h b/actions.h
new file mode 100644 (file)
index 0000000..c0c011a
--- /dev/null
+++ b/actions.h
@@ -0,0 +1,135 @@
+
+enum {
+  ENCODER_NO_ACTION=0,
+  ENCODER_AF_GAIN,
+  ENCODER_AF_GAIN_RX1,
+  ENCODER_AF_GAIN_RX2,
+  ENCODER_AGC_GAIN,
+  ENCODER_AGC_GAIN_RX1,
+  ENCODER_AGC_GAIN_RX2,
+  ENCODER_ATTENUATION,
+  ENCODER_COMP,
+  ENCODER_CW_FREQUENCY,
+  ENCODER_CW_SPEED,
+  ENCODER_DIVERSITY_GAIN,
+  ENCODER_DIVERSITY_GAIN_COARSE,
+  ENCODER_DIVERSITY_GAIN_FINE,
+  ENCODER_DIVERSITY_PHASE,
+  ENCODER_DIVERSITY_PHASE_COARSE,
+  ENCODER_DIVERSITY_PHASE_FINE,
+  ENCODER_DRIVE,
+  ENCODER_IF_SHIFT,
+  ENCODER_IF_SHIFT_RX1,
+  ENCODER_IF_SHIFT_RX2,
+  ENCODER_IF_WIDTH,
+  ENCODER_IF_WIDTH_RX1,
+  ENCODER_IF_WIDTH_RX2,
+  ENCODER_MIC_GAIN,
+  ENCODER_PAN,
+  ENCODER_PANADAPTER_HIGH,
+  ENCODER_PANADAPTER_LOW,
+  ENCODER_PANADAPTER_STEP,
+  ENCODER_RF_GAIN,
+  ENCODER_RF_GAIN_RX1,
+  ENCODER_RF_GAIN_RX2,
+  ENCODER_RIT,
+  ENCODER_RIT_RX1,
+  ENCODER_RIT_RX2,
+  ENCODER_SQUELCH,
+  ENCODER_SQUELCH_RX1,
+  ENCODER_SQUELCH_RX2,
+  ENCODER_TUNE_DRIVE,
+  ENCODER_VFO,
+  ENCODER_WATERFALL_HIGH,
+  ENCODER_WATERFALL_LOW,
+  ENCODER_XIT,
+  ENCODER_ZOOM,
+  ENCODER_ACTIONS
+};
+
+enum {
+  NO_ACTION=0,
+  A_TO_B,
+  A_SWAP_B,
+  AGC,
+  ANF,
+  B_TO_A,
+  BAND_MINUS,
+  BAND_PLUS,
+  BANDSTACK_MINUS,
+  BANDSTACK_PLUS,
+  CTUN,
+  DIVERSITY,
+  DUPLEX,
+  FILTER_MINUS,
+  FILTER_PLUS,
+  FUNCTION,
+  LOCK,
+  MENU_AGC,
+  MENU_BAND,
+  MENU_BANDSTACK,
+  MENU_DIVERSITY,
+  MENU_FILTER,
+  MENU_FREQUENCY,
+  MENU_MEMORY,
+  MENU_MODE,
+  MENU_NOISE,
+  MENU_PS,
+  MODE_MINUS,
+  MODE_PLUS,
+  MOX,
+  MUTE,
+  NB,
+  NR,
+  PAN_MINUS,
+  PAN_PLUS,
+  PS,
+  RIT,
+  RIT_CLEAR,
+  RIT_MINUS,
+  RIT_PLUS,
+  RSAT,
+  SAT,
+  SNB,
+  SPLIT,
+  TUNE,
+  TUNE_FULL,
+  TUNE_MEMORY,
+  TWO_TONE,
+  XIT,
+  XIT_CLEAR,
+  XIT_MINUS,
+  XIT_PLUS,
+  ZOOM_MINUS,
+  ZOOM_PLUS,
+  SWITCH_ACTIONS,
+};
+
+enum {
+  PRESSED,
+  RELEASED
+};
+
+typedef struct _switch_action {
+  gint action;
+  gboolean state;
+} SWITCH_ACTION;
+
+enum {
+  RELATIVE,
+  ABSOLUTE
+};
+
+typedef struct _encoder_action {
+  gint action;
+  gboolean mode;
+  gint val;
+} ENCODER_ACTION;
+
+extern char *encoder_string[ENCODER_ACTIONS];
+extern char *sw_string[SWITCH_ACTIONS];
+extern char *sw_cap_string[SWITCH_ACTIONS];
+
+extern int encoder_action(void *data);
+extern int switch_action(void *data);
+
index 56702189b2298c1e9a53b7ec22c3e5ab8e249a88..36e2caaf096430885e2b0427161712a09e20d90f 100644 (file)
@@ -43,6 +43,7 @@ static void cleanup() {
     gtk_widget_destroy(dialog);
     dialog=NULL;
     sub_menu=NULL;
+    active_menu=NO_MENU;
   }
 }
 
index 30c70b74a87139616ef49620c20e2554a1219289..eb2102dcd1430d61c50a58d6173203b4ab77f151 100644 (file)
@@ -45,6 +45,7 @@ static void cleanup() {
     gtk_widget_destroy(dialog);
     dialog=NULL;
     sub_menu=NULL;
+    active_menu=NO_MENU;
   }
 }
 
@@ -112,7 +113,7 @@ void band_menu(GtkWidget *parent) {
   long long frequency_min=radio->frequency_min;
   long long frequency_max=radio->frequency_max;
 
-g_print("band_menu: min=%lld max=%lld\n",frequency_min,frequency_max);
+  //g_print("band_menu: min=%lld max=%lld\n",frequency_min,frequency_max);
   j=0;
   for(i=0;i<BANDS+XVTRS;i++) {
     band=(BAND*)band_get_band(i);
index 579360bff927c524bba9ca938a3f98868f0c78a7..19152df9e6cc0e54182aa7b45beabd30abc081ec 100644 (file)
@@ -44,6 +44,7 @@ static void cleanup() {
     gtk_widget_destroy(dialog);
     dialog=NULL;
     sub_menu=NULL;
+    active_menu=NO_MENU;
   }
 }
 
index 870187317e69f65888c09293c74bba81ba4ca478..11652bb84c053e7236e5b83fc8f97073bd2b793c 100644 (file)
@@ -18,7 +18,8 @@
 */
 
 #include <gtk/gtk.h>
-#include <gdk/gdk.h>
+#include <glib.h>
+#include <glib/gprintf.h>
 #include <math.h>
 #include <unistd.h>
 #include <stdlib.h>
@@ -30,6 +31,7 @@
 #include "main.h"
 #include "channel.h"
 #include "discovered.h"
+#include "actions.h"
 #include "gpio.h"
 #include "i2c.h"
 
 
 static GtkWidget *dialog;
 
-static GtkWidget *b_enable_vfo_encoder;
-static   GtkWidget *vfo_a_label;
-static   GtkWidget *vfo_a;
-static   GtkWidget *vfo_b_label;
-static   GtkWidget *vfo_b;
-static   GtkWidget *b_enable_vfo_pullup;
-static GtkWidget *b_enable_E2_encoder;
-static   GtkWidget *E2_a_label;
-static   GtkWidget *E2_a;
-static   GtkWidget *E2_b_label;
-static   GtkWidget *E2_b;
-static   GtkWidget *b_enable_E2_pullup;
-static GtkWidget *b_enable_E2_top_encoder;
-static   GtkWidget *E2_top_a_label;
-static   GtkWidget *E2_top_a;
-static   GtkWidget *E2_top_b_label;
-static   GtkWidget *E2_top_b;
-static GtkWidget *E2_sw_label;
-static   GtkWidget *E2_sw;
-static GtkWidget *b_enable_E3_encoder;
-static   GtkWidget *E3_a_label;
-static   GtkWidget *E3_a;
-static   GtkWidget *E3_b_label;
-static   GtkWidget *E3_b;
-static   GtkWidget *b_enable_E3_pullup;
-static GtkWidget *b_enable_E3_top_encoder;
-static   GtkWidget *E3_top_a_label;
-static   GtkWidget *E3_top_a;
-static   GtkWidget *E3_top_b_label;
-static   GtkWidget *E3_top_b;
-static GtkWidget *E3_sw_label;
-static   GtkWidget *E3_sw;
-static GtkWidget *b_enable_E4_encoder;
-static   GtkWidget *E4_a_label;
-static   GtkWidget *E4_a;
-static   GtkWidget *E4_b_label;
-static   GtkWidget *E4_b;
-static   GtkWidget *b_enable_E4_pullup;
-static GtkWidget *b_enable_E4_top_encoder;
-static   GtkWidget *E4_top_a_label;
-static   GtkWidget *E4_top_a;
-static   GtkWidget *E4_top_b_label;
-static   GtkWidget *E4_top_b;
-static GtkWidget *E4_sw_label;
-static   GtkWidget *E4_sw;
-static GtkWidget *b_enable_E5_encoder;
-static   GtkWidget *E5_a_label;
-static   GtkWidget *E5_a;
-static   GtkWidget *E5_b_label;
-static   GtkWidget *E5_b;
-static   GtkWidget *b_enable_E5_pullup;
-static GtkWidget *b_enable_E5_top_encoder;
-static   GtkWidget *E5_top_a_label;
-static   GtkWidget *E5_top_a;
-static   GtkWidget *E5_top_b_label;
-static   GtkWidget *E5_top_b;
-static GtkWidget *E5_sw_label;
-static   GtkWidget *E5_sw;
-
-static GtkWidget *b_enable_mox;
-static   GtkWidget *mox_label;
-static   GtkWidget *mox;
-static GtkWidget *b_enable_S1;
-static   GtkWidget *S1_label;
-static   GtkWidget *S1;
-static GtkWidget *b_enable_S2;
-static   GtkWidget *S2_label;
-static   GtkWidget *S2;
-static GtkWidget *b_enable_S3;
-static   GtkWidget *S3_label;
-static   GtkWidget *S3;
-static GtkWidget *b_enable_S4;
-static   GtkWidget *S4_label;
-static   GtkWidget *S4;
-static GtkWidget *b_enable_S5;
-static   GtkWidget *S5_label;
-static   GtkWidget *S5;
-static GtkWidget *b_enable_S6;
-static   GtkWidget *S6_label;
-static   GtkWidget *S6;
-static GtkWidget *b_enable_function;
-static   GtkWidget *function_label;
-static   GtkWidget *function;
-
-static GtkWidget *i2c_device_text;
-static GtkWidget *i2c_address;
 static GtkWidget *i2c_sw_text[16];
 
-
-#ifdef LOCALCW
-static GtkWidget *cwl_label;
-static GtkWidget *cwl;
-static GtkWidget *cwr_label;
-static GtkWidget *cwr;
-static GtkWidget *cws_label;
-static GtkWidget *cws;
-static GtkWidget *b_enable_cws;
-static GtkWidget *b_enable_cwlr;
-static GtkWidget *b_cw_active_low;
-#endif
-
-#ifdef PTT
-static GtkWidget *ptt_label;
-static GtkWidget *ptt;
-static GtkWidget *b_enable_ptt;
-static GtkWidget *b_ptt_active_low;
-#endif
-
-static gboolean save_cb (GtkWidget *widget, GdkEventButton *event, gpointer data) {
-  if(dialog!=NULL) {
-    ENABLE_VFO_ENCODER=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_vfo_encoder))?1:0;
-    VFO_ENCODER_A=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(vfo_a));
-    VFO_ENCODER_B=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(vfo_b));
-    ENABLE_VFO_PULLUP=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_vfo_pullup))?1:0;
-
-    ENABLE_E2_ENCODER=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_E2_encoder))?1:0;
-    E2_ENCODER_A=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(E2_a));
-    E2_ENCODER_B=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(E2_b));
-    ENABLE_E2_PULLUP=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_E2_pullup))?1:0;
-    E2_FUNCTION=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(E2_sw));
-
-    if(controller==CONTROLLER2_V2) {
-      E2_TOP_ENCODER_A=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(E2_top_a));
-      E2_TOP_ENCODER_B=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(E2_top_b));
-    }
-
-    ENABLE_E3_ENCODER=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_E3_encoder))?1:0;
-    E3_ENCODER_A=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(E3_a));
-    E3_ENCODER_B=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(E3_b));
-    ENABLE_E3_PULLUP=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_E3_pullup))?1:0;
-    E3_FUNCTION=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(E3_sw));
-
-    if(controller==CONTROLLER2_V2) {
-      E3_TOP_ENCODER_A=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(E3_top_a));
-      E3_TOP_ENCODER_B=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(E3_top_b));
-    }
-
-    ENABLE_E4_ENCODER=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_E4_encoder))?1:0;
-    E4_ENCODER_A=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(E4_a));
-    E4_ENCODER_B=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(E4_b));
-    ENABLE_E4_PULLUP=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_E4_pullup))?1:0;
-    E4_FUNCTION=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(E4_sw));
-
-    if(controller==CONTROLLER2_V2) {
-      E4_TOP_ENCODER_A=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(E4_top_a));
-      E4_TOP_ENCODER_B=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(E4_top_b));
-    }
-
-    if(controller==CONTROLLER2_V1 || controller==CONTROLLER2_V2) {
-      ENABLE_E5_ENCODER=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_E5_encoder))?1:0;
-      E5_ENCODER_A=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(E5_a));
-      E5_ENCODER_B=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(E5_b));
-      ENABLE_E5_PULLUP=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_E5_pullup))?1:0;
-      E5_FUNCTION=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(E5_sw));
-
-      if(controller==CONTROLLER2_V2) {
-        E5_TOP_ENCODER_A=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(E5_top_a));
-        E5_TOP_ENCODER_B=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(E5_top_b));
-      }
-
-      const char *temp=gtk_entry_get_text(GTK_ENTRY(i2c_device_text));
-      i2c_device=g_new(char,strlen(temp)+1);
-      strcpy(i2c_device,temp);
-      i2c_address_1=(unsigned int)strtol(gtk_entry_get_text(GTK_ENTRY(i2c_address)),NULL,16);
-      for(int i=0;i<16;i++) {
-        i2c_sw[i]=(unsigned int)strtol(gtk_entry_get_text(GTK_ENTRY(i2c_sw_text[i])),NULL,16);
-      }
-    }
-
-  if(controller==CONTROLLER1) {
-    ENABLE_MOX_BUTTON=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_mox))?1:0;
-    MOX_BUTTON=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(mox));
-
-    ENABLE_S1_BUTTON=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_S1))?1:0;
-    S1_BUTTON=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(S1));
-
-    ENABLE_S2_BUTTON=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_S2))?1:0;
-    S2_BUTTON=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(S2));
-
-    ENABLE_S3_BUTTON=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_S3))?1:0;
-    S3_BUTTON=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(S3));
-
-    ENABLE_S4_BUTTON=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_S4))?1:0;
-    S4_BUTTON=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(S4));
-
-    ENABLE_S5_BUTTON=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_S5))?1:0;
-    S5_BUTTON=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(S5));
-
-    ENABLE_S6_BUTTON=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_S6))?1:0;
-    S6_BUTTON=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(S6));
-
-    ENABLE_FUNCTION_BUTTON=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_function))?1:0;
-    FUNCTION_BUTTON=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(function));
-  }
-
-#ifdef LOCALCW
-    ENABLE_CW_BUTTONS=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_cwlr))?1:0;
-    CW_ACTIVE_LOW=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_cw_active_low))?1:0;
-    CWL_BUTTON=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(cwl));
-    CWR_BUTTON=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(cwr));
-    ENABLE_GPIO_SIDETONE=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_cws))?1:0;
-    SIDETONE_GPIO=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(cws));
-#endif
-
-#ifdef PTT
-    ENABLE_PTT_GPIO=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_ptt))?1:0;
-    PTT_ACTIVE_LOW=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_ptt_active_low))?1:0;
-    PTT_GPIO=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(ptt));
-#endif
-
+static void response_event(GtkWidget *dialog,gint id,gpointer user_data) {
+  g_print("%s: id=%d\n",__FUNCTION__,id);
+  if(id==GTK_RESPONSE_ACCEPT) {
     gpio_save_state();
-    gtk_widget_destroy(dialog);
+    g_print("%s: ACCEPT\n",__FUNCTION__);
   }
-  return TRUE;
-}
-
-static gboolean cancel_cb (GtkWidget *widget, GdkEventButton *event, gpointer data) {
-  if(dialog!=NULL) {
-    gtk_widget_destroy(dialog);
-  }
-  return TRUE;
+  gtk_widget_destroy(dialog);
+  dialog=NULL;
 }
 
 void configure_gpio(GtkWidget *parent) {
-  int row;
+  gint row=0;
+  gint col=0;
+  GtkWidget *widget;
+  int i;
 
   gpio_restore_state();
 
-  dialog=gtk_dialog_new_with_buttons("Configure GPIO (WiringPi pin numbers)",GTK_WINDOW(parent),GTK_DIALOG_DESTROY_WITH_PARENT,NULL,NULL);
-  GtkWidget *content=gtk_dialog_get_content_area(GTK_DIALOG(dialog));
-  GtkWidget *grid=gtk_grid_new();
-  //gtk_grid_set_column_homogeneous(GTK_GRID(grid),TRUE);
-  gtk_grid_set_row_homogeneous(GTK_GRID(grid),TRUE);
+  GtkWidget *dialog=gtk_dialog_new_with_buttons("piHPSDR - GPIO pins (Broadcom Numbers) ",GTK_WINDOW(parent),GTK_DIALOG_DESTROY_WITH_PARENT,("OK"),GTK_RESPONSE_ACCEPT,"Cancel",GTK_RESPONSE_REJECT,NULL);
 
-  GtkWidget *notebook=gtk_notebook_new();
+  g_signal_connect (dialog, "response", G_CALLBACK (response_event), NULL);
 
-  GtkWidget *grid0=gtk_grid_new();
-  gtk_grid_set_column_spacing (GTK_GRID(grid0),10);
+  GtkWidget *content=gtk_dialog_get_content_area(GTK_DIALOG(dialog));
 
-  GtkWidget *save_b=gtk_button_new_with_label("Save");
-  g_signal_connect (save_b, "button_press_event", G_CALLBACK(save_cb), NULL);
-  gtk_grid_attach(GTK_GRID(grid0),save_b,0,0,1,1);
+  GtkWidget *notebook=gtk_notebook_new();
 
-  GtkWidget *cancel_b=gtk_button_new_with_label("Cancel");
-  g_signal_connect (cancel_b, "button_press_event", G_CALLBACK(cancel_cb), NULL);
-  gtk_grid_attach(GTK_GRID(grid0),cancel_b,1,0,1,1);
+  // Encoders
+  gint max_encoders=MAX_ENCODERS;
+  switch(controller) {
+    case NO_CONTROLLER:
+      max_encoders=0;
+      break;
+    case CONTROLLER1:
+      max_encoders=4;
+      break;
+    case CONTROLLER2_V1:
+      max_encoders=5;
+      break;
+    case CONTROLLER2_V2:
+      max_encoders=5;
+      break;
+  }
 
+  GtkWidget *grid=gtk_grid_new();
+  gtk_grid_set_column_homogeneous(GTK_GRID(grid),FALSE);
+  gtk_grid_set_row_homogeneous(GTK_GRID(grid),TRUE);
+  gtk_grid_set_column_spacing (GTK_GRID(grid),2);
+  gtk_grid_set_row_spacing (GTK_GRID(grid),2);
 
-  if(controller!=NO_CONTROLLER) {
 
-    // Encoders
-  
-    GtkWidget *grid1=gtk_grid_new();
-    gtk_grid_set_column_homogeneous(GTK_GRID(grid1),FALSE);
-    gtk_grid_set_row_homogeneous(GTK_GRID(grid1),TRUE);
-    gtk_grid_set_column_spacing (GTK_GRID(grid1),5);
-    row=0;
-  
-    b_enable_vfo_encoder=gtk_check_button_new_with_label("Enable VFO");
-    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_enable_vfo_encoder), ENABLE_VFO_ENCODER);
-    gtk_widget_show(b_enable_vfo_encoder);
-    gtk_grid_attach(GTK_GRID(grid1),b_enable_vfo_encoder,0,row,1,1);
-  
-    vfo_a_label=gtk_label_new("GPIO A:");
-    gtk_widget_show(vfo_a_label);
-    gtk_grid_attach(GTK_GRID(grid1),vfo_a_label,1,row,1,1);
-  
-    vfo_a=gtk_spin_button_new_with_range (0.0,100.0,1.0);
-    gtk_spin_button_set_value (GTK_SPIN_BUTTON(vfo_a),VFO_ENCODER_A);
-    gtk_widget_show(vfo_a);
-    gtk_grid_attach(GTK_GRID(grid1),vfo_a,2,row,1,1);
-  
-    vfo_b_label=gtk_label_new("GPIO B:");
-    gtk_widget_show(vfo_b_label);
-    gtk_grid_attach(GTK_GRID(grid1),vfo_b_label,3,row,1,1);
-  
-    vfo_b=gtk_spin_button_new_with_range (0.0,100.0,1.0);
-    gtk_spin_button_set_value (GTK_SPIN_BUTTON(vfo_b),VFO_ENCODER_B);
-    gtk_widget_show(vfo_b);
-    gtk_grid_attach(GTK_GRID(grid1),vfo_b,4,row,1,1);
-
-    b_enable_vfo_pullup=gtk_check_button_new_with_label("Enable Pull-up");
-    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_enable_vfo_pullup), ENABLE_VFO_PULLUP);
-    gtk_widget_show(b_enable_vfo_pullup);
-    gtk_grid_attach(GTK_GRID(grid1),b_enable_vfo_pullup,7,row,1,1);
-  
-  
-    row++;
-  
-    b_enable_E2_encoder=gtk_check_button_new_with_label("Enable E2");
-    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_enable_E2_encoder), ENABLE_E2_ENCODER);
-    gtk_widget_show(b_enable_E2_encoder);
-    gtk_grid_attach(GTK_GRID(grid1),b_enable_E2_encoder,0,row,1,1);
-  
-    E2_a_label=gtk_label_new("GPIO A:");
-    gtk_widget_show(E2_a_label);
-    gtk_grid_attach(GTK_GRID(grid1),E2_a_label,1,row,1,1);
-  
-    E2_a=gtk_spin_button_new_with_range (0.0,100.0,1.0);
-    gtk_spin_button_set_value (GTK_SPIN_BUTTON(E2_a),E2_ENCODER_A);
-    gtk_widget_show(E2_a);
-    gtk_grid_attach(GTK_GRID(grid1),E2_a,2,row,1,1);
-  
-    E2_b_label=gtk_label_new("GPIO B:");
-    gtk_widget_show(E2_b_label);
-    gtk_grid_attach(GTK_GRID(grid1),E2_b_label,3,row,1,1);
-  
-    E2_b=gtk_spin_button_new_with_range (0.0,100.0,1.0);
-    gtk_spin_button_set_value (GTK_SPIN_BUTTON(E2_b),E2_ENCODER_B);
-    gtk_widget_show(E2_b);
-    gtk_grid_attach(GTK_GRID(grid1),E2_b,4,row,1,1);
-  
-    E2_sw_label=gtk_label_new("SW:");
-    gtk_widget_show(E2_sw_label);
-    gtk_grid_attach(GTK_GRID(grid1),E2_sw_label,5,row,1,1);
-  
-    E2_sw=gtk_spin_button_new_with_range (0.0,100.0,1.0);
-    gtk_spin_button_set_value (GTK_SPIN_BUTTON(E2_sw),E2_FUNCTION);
-    gtk_widget_show(E2_sw);
-    gtk_grid_attach(GTK_GRID(grid1),E2_sw,6,row,1,1);
-  
-    b_enable_E2_pullup=gtk_check_button_new_with_label("Enable Pull-up");
-    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_enable_E2_pullup), ENABLE_E2_PULLUP);
-    gtk_widget_show(b_enable_E2_pullup);
-    gtk_grid_attach(GTK_GRID(grid1),b_enable_E2_pullup,7,row,1,1);
-  
-  
-    row++;
+/*
+  widget=gtk_label_new(NULL);
+  gtk_label_set_markup (GTK_LABEL(widget), "<span foreground=\"#ff0000\"><b>Note: Pin number now use Broadcom GPIO</b></span>");
+  gtk_grid_attach(GTK_GRID(grid),widget,col,row,6,1);
 
-    if(controller==CONTROLLER2_V2) {
-      E2_top_a_label=gtk_label_new("GPIO A:");
-      gtk_widget_show(E2_top_a_label);
-      gtk_grid_attach(GTK_GRID(grid1),E2_top_a_label,1,row,1,1);
+  row++;
+  col=0;
+*/
+  widget=gtk_label_new("");
+  gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
+  col++;
+
+  widget=gtk_label_new(NULL);
+  gtk_label_set_markup (GTK_LABEL(widget), controller==CONTROLLER2_V2?"<b>Bottom Encoder</b>":"<b>Encoder</b>");
+  gtk_grid_attach(GTK_GRID(grid),widget,col,row,2,1);
+  col+=2;
+
+  if(controller==CONTROLLER2_V2) {
+    widget=gtk_label_new(NULL);
+    gtk_label_set_markup (GTK_LABEL(widget), "<b>Top Encoder</b>");
+    gtk_grid_attach(GTK_GRID(grid),widget,col,row,2,1);
+    col+=2;
+  }
 
-      E2_top_a=gtk_spin_button_new_with_range (0.0,100.0,1.0);
-      gtk_spin_button_set_value (GTK_SPIN_BUTTON(E2_top_a),E2_TOP_ENCODER_A);
-      gtk_widget_show(E2_top_a);
-      gtk_grid_attach(GTK_GRID(grid1),E2_top_a,2,row,1,1);
+  widget=gtk_label_new(NULL);
+  gtk_label_set_markup (GTK_LABEL(widget), "<b>Switch</b>");
+  gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
 
-      E2_top_b_label=gtk_label_new("GPIO B:");
-      gtk_widget_show(E2_top_b_label);
-      gtk_grid_attach(GTK_GRID(grid1),E2_top_b_label,3,row,1,1);
+  row++;
+  col=0;
+
+  widget=gtk_label_new(NULL);
+  gtk_label_set_markup (GTK_LABEL(widget), "<b>ID</b>");
+  gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
+  col++;
+
+  widget=gtk_label_new(NULL);
+  gtk_label_set_markup (GTK_LABEL(widget), "<b>Gpio A</b>");
+  gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
+  col++;
+
+  widget=gtk_label_new(NULL);
+  gtk_label_set_markup (GTK_LABEL(widget), "<b>Gpio B</b>");
+  gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
+  col++;
+
+  if(controller==CONTROLLER2_V2) {
+    widget=gtk_label_new(NULL);
+    gtk_label_set_markup (GTK_LABEL(widget), "<b>Gpio A</b>");
+    gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
+    col++;
+
+    widget=gtk_label_new(NULL);
+    gtk_label_set_markup (GTK_LABEL(widget), "<b>Gpio B</b>");
+    gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
+    col++;
+  }
 
-      E2_top_b=gtk_spin_button_new_with_range (0.0,100.0,1.0);
-      gtk_spin_button_set_value (GTK_SPIN_BUTTON(E2_top_b),E2_TOP_ENCODER_B);
-      gtk_widget_show(E2_top_b);
-      gtk_grid_attach(GTK_GRID(grid1),E2_top_b,4,row,1,1);
+  widget=gtk_label_new(NULL);
+  gtk_label_set_markup (GTK_LABEL(widget), "<b>Gpio</b>");
+  gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
+  col++;
 
-      row++;
+  row++;
+  col=0;
+
+  for(i=0;i<max_encoders;i++) {
+    widget=gtk_label_new(NULL);
+    gchar id[16];
+    g_sprintf(id,"<b>%d</b>",i);
+    gtk_label_set_markup (GTK_LABEL(widget), id);
+    gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
+    col++;
+
+    widget=gtk_spin_button_new_with_range (0.0,28.0,1.0);
+    gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget),encoders[i].bottom_encoder_address_a);
+    gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
+    col++;
+    
+    widget=gtk_spin_button_new_with_range (0.0,28.0,1.0);
+    gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget),encoders[i].bottom_encoder_address_b);
+    gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
+    col++;
+    
+    if(controller==CONTROLLER2_V2 && i<(max_encoders-1)) {
+      widget=gtk_spin_button_new_with_range (0.0,28.0,1.0);
+      gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget),encoders[i].top_encoder_address_a);
+      gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
+      col++;
+   
+      widget=gtk_spin_button_new_with_range (0.0,28.0,1.0);
+      gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget),encoders[i].top_encoder_address_b);
+      gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
+      col++;
     }
 
-    b_enable_E3_encoder=gtk_check_button_new_with_label("Enable E3");
-    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_enable_E3_encoder), ENABLE_E3_ENCODER);
-    gtk_widget_show(b_enable_E3_encoder);
-    gtk_grid_attach(GTK_GRID(grid1),b_enable_E3_encoder,0,row,1,1);
-  
-    E3_a_label=gtk_label_new("GPIO A:");
-    gtk_widget_show(E3_a_label);
-    gtk_grid_attach(GTK_GRID(grid1),E3_a_label,1,row,1,1);
-  
-    E3_a=gtk_spin_button_new_with_range (0.0,100.0,1.0);
-    gtk_spin_button_set_value (GTK_SPIN_BUTTON(E3_a),E3_ENCODER_A);
-    gtk_widget_show(E3_a);
-    gtk_grid_attach(GTK_GRID(grid1),E3_a,2,row,1,1);
-  
-    E3_b_label=gtk_label_new("GPIO B:");
-    gtk_widget_show(E3_b_label);
-    gtk_grid_attach(GTK_GRID(grid1),E3_b_label,3,row,1,1);
-  
-    E3_b=gtk_spin_button_new_with_range (0.0,100.0,1.0);
-    gtk_spin_button_set_value (GTK_SPIN_BUTTON(E3_b),E3_ENCODER_B);
-    gtk_widget_show(E3_b);
-    gtk_grid_attach(GTK_GRID(grid1),E3_b,4,row,1,1);
-  
-    E3_sw_label=gtk_label_new("SW:");
-    gtk_widget_show(E3_sw_label);
-    gtk_grid_attach(GTK_GRID(grid1),E3_sw_label,5,row,1,1);
-  
-    E3_sw=gtk_spin_button_new_with_range (0.0,100.0,1.0);
-    gtk_spin_button_set_value (GTK_SPIN_BUTTON(E3_sw),E3_FUNCTION);
-    gtk_widget_show(E3_sw);
-    gtk_grid_attach(GTK_GRID(grid1),E3_sw,6,row,1,1);
-  
-    b_enable_E3_pullup=gtk_check_button_new_with_label("Enable Pull-up");
-    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_enable_E3_pullup), ENABLE_E3_PULLUP);
-    gtk_widget_show(b_enable_E3_pullup);
-    gtk_grid_attach(GTK_GRID(grid1),b_enable_E3_pullup,7,row,1,1);
-  
-    row++;
-
-    if(controller==CONTROLLER2_V2) {
-      E3_top_a_label=gtk_label_new("GPIO A:");
-      gtk_widget_show(E3_top_a_label);
-      gtk_grid_attach(GTK_GRID(grid1),E3_top_a_label,1,row,1,1);
-
-      E3_top_a=gtk_spin_button_new_with_range (0.0,100.0,1.0);
-      gtk_spin_button_set_value (GTK_SPIN_BUTTON(E3_top_a),E3_TOP_ENCODER_A);
-      gtk_widget_show(E3_top_a);
-      gtk_grid_attach(GTK_GRID(grid1),E3_top_a,2,row,1,1);
-
-      E3_top_b_label=gtk_label_new("GPIO B:");
-      gtk_widget_show(E3_top_b_label);
-      gtk_grid_attach(GTK_GRID(grid1),E3_top_b_label,3,row,1,1);
-
-      E3_top_b=gtk_spin_button_new_with_range (0.0,100.0,1.0);
-      gtk_spin_button_set_value (GTK_SPIN_BUTTON(E3_top_b),E3_TOP_ENCODER_B);
-      gtk_widget_show(E3_top_b);
-      gtk_grid_attach(GTK_GRID(grid1),E3_top_b,4,row,1,1);
-
-      row++;
+    if(i<(max_encoders-1)) {
+      widget=gtk_spin_button_new_with_range (0.0,28.0,1.0);
+      gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget),encoders[i].switch_address);
+      gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
+      col++;
     }
 
-    b_enable_E4_encoder=gtk_check_button_new_with_label("Enable E4");
-    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_enable_E4_encoder), ENABLE_E4_ENCODER);
-    gtk_widget_show(b_enable_E4_encoder);
-    gtk_grid_attach(GTK_GRID(grid1),b_enable_E4_encoder,0,row,1,1);
-  
-    E4_a_label=gtk_label_new("GPIO A:");
-    gtk_widget_show(E4_a_label);
-    gtk_grid_attach(GTK_GRID(grid1),E4_a_label,1,row,1,1);
-  
-    E4_a=gtk_spin_button_new_with_range (0.0,100.0,1.0);
-    gtk_spin_button_set_value (GTK_SPIN_BUTTON(E4_a),E4_ENCODER_A);
-    gtk_widget_show(E4_a);
-    gtk_grid_attach(GTK_GRID(grid1),E4_a,2,row,1,1);
-  
-    E4_b_label=gtk_label_new("GPIO B:");
-    gtk_widget_show(E4_b_label);
-    gtk_grid_attach(GTK_GRID(grid1),E4_b_label,3,row,1,1);
-  
-    E4_b=gtk_spin_button_new_with_range (0.0,100.0,1.0);
-    gtk_spin_button_set_value (GTK_SPIN_BUTTON(E4_b),E4_ENCODER_B);
-    gtk_widget_show(E4_b);
-    gtk_grid_attach(GTK_GRID(grid1),E4_b,4,row,1,1);
-  
-    E4_sw_label=gtk_label_new("SW:");
-    gtk_widget_show(E4_sw_label);
-    gtk_grid_attach(GTK_GRID(grid1),E4_sw_label,5,row,1,1);
-  
-    E4_sw=gtk_spin_button_new_with_range (0.0,100.0,1.0);
-    gtk_spin_button_set_value (GTK_SPIN_BUTTON(E4_sw),E4_FUNCTION);
-    gtk_widget_show(E4_sw);
-    gtk_grid_attach(GTK_GRID(grid1),E4_sw,6,row,1,1);
-  
-    b_enable_E4_pullup=gtk_check_button_new_with_label("Enable Pull-up");
-    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_enable_E4_pullup), ENABLE_E4_PULLUP);
-    gtk_widget_show(b_enable_E4_pullup);
-    gtk_grid_attach(GTK_GRID(grid1),b_enable_E4_pullup,7,row,1,1);
-  
     row++;
+    col=0;
+  }
+  gtk_notebook_append_page(GTK_NOTEBOOK(notebook),grid,gtk_label_new("Encoders"));
 
-    if(controller==CONTROLLER2_V2)
-    {
-      E4_top_a_label=gtk_label_new("GPIO A:");
-      gtk_widget_show(E4_top_a_label);
-      gtk_grid_attach(GTK_GRID(grid1),E4_top_a_label,1,row,1,1);
-
-      E4_top_a=gtk_spin_button_new_with_range (0.0,100.0,1.0);
-      gtk_spin_button_set_value (GTK_SPIN_BUTTON(E4_top_a),E4_TOP_ENCODER_A);
-      gtk_widget_show(E4_top_a);
-      gtk_grid_attach(GTK_GRID(grid1),E4_top_a,2,row,1,1);
-
-      E4_top_b_label=gtk_label_new("GPIO B:");
-      gtk_widget_show(E4_top_b_label);
-      gtk_grid_attach(GTK_GRID(grid1),E4_top_b_label,3,row,1,1);
-
-      E4_top_b=gtk_spin_button_new_with_range (0.0,100.0,1.0);
-      gtk_spin_button_set_value (GTK_SPIN_BUTTON(E4_top_b),E4_TOP_ENCODER_B);
-      gtk_widget_show(E4_top_b);
-      gtk_grid_attach(GTK_GRID(grid1),E4_top_b,4,row,1,1);
-
-      row++;
-    }
 
-    if(controller==CONTROLLER2_V1 || controller==CONTROLLER2_V2) {
-      b_enable_E5_encoder=gtk_check_button_new_with_label("Enable E5");
-      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_enable_E5_encoder), ENABLE_E5_ENCODER);
-      gtk_widget_show(b_enable_E5_encoder);
-      gtk_grid_attach(GTK_GRID(grid1),b_enable_E5_encoder,0,row,1,1);
-
-      E5_a_label=gtk_label_new("GPIO A:");
-      gtk_widget_show(E5_a_label);
-      gtk_grid_attach(GTK_GRID(grid1),E5_a_label,1,row,1,1);
-
-      E5_a=gtk_spin_button_new_with_range (0.0,100.0,1.0);
-      gtk_spin_button_set_value (GTK_SPIN_BUTTON(E5_a),E5_ENCODER_A);
-      gtk_widget_show(E5_a);
-      gtk_grid_attach(GTK_GRID(grid1),E5_a,2,row,1,1);
-
-      E5_b_label=gtk_label_new("GPIO B:");
-      gtk_widget_show(E5_b_label);
-      gtk_grid_attach(GTK_GRID(grid1),E5_b_label,3,row,1,1);
-
-      E5_b=gtk_spin_button_new_with_range (0.0,100.0,1.0);
-      gtk_spin_button_set_value (GTK_SPIN_BUTTON(E5_b),E5_ENCODER_B);
-      gtk_widget_show(E5_b);
-      gtk_grid_attach(GTK_GRID(grid1),E5_b,4,row,1,1);
-
-      E5_sw_label=gtk_label_new("SW:");
-      gtk_widget_show(E5_sw_label);
-      gtk_grid_attach(GTK_GRID(grid1),E5_sw_label,5,row,1,1);
-
-      E5_sw=gtk_spin_button_new_with_range (0.0,100.0,1.0);
-      gtk_spin_button_set_value (GTK_SPIN_BUTTON(E5_sw),E5_FUNCTION);
-      gtk_widget_show(E5_sw);
-      gtk_grid_attach(GTK_GRID(grid1),E5_sw,6,row,1,1);
-
-      b_enable_E5_pullup=gtk_check_button_new_with_label("Enable Pull-up");
-      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_enable_E5_pullup), ENABLE_E5_PULLUP);
-      gtk_widget_show(b_enable_E5_pullup);
-      gtk_grid_attach(GTK_GRID(grid1),b_enable_E5_pullup,7,row,1,1);
-
-      if(controller==CONTROLLER2_V2) {
-        row++;
-
-        E5_top_a_label=gtk_label_new("GPIO A:");
-        gtk_widget_show(E5_top_a_label);
-        gtk_grid_attach(GTK_GRID(grid1),E5_top_a_label,1,row,1,1);
-
-        E5_top_a=gtk_spin_button_new_with_range (0.0,100.0,1.0);
-        gtk_spin_button_set_value (GTK_SPIN_BUTTON(E5_top_a),E5_TOP_ENCODER_A);
-        gtk_widget_show(E5_top_a);
-        gtk_grid_attach(GTK_GRID(grid1),E5_top_a,2,row,1,1);
-
-        E5_top_b_label=gtk_label_new("GPIO B:");
-        gtk_widget_show(E5_top_b_label);
-        gtk_grid_attach(GTK_GRID(grid1),E5_top_b_label,3,row,1,1);
-
-        E5_top_b=gtk_spin_button_new_with_range (0.0,100.0,1.0);
-        gtk_spin_button_set_value (GTK_SPIN_BUTTON(E5_top_b),E5_TOP_ENCODER_B);
-        gtk_widget_show(E5_top_b);
-        gtk_grid_attach(GTK_GRID(grid1),E5_top_b,4,row,1,1);
-      }
+  // switches
+  if(controller==CONTROLLER1) {
+    gint max_switches=MAX_SWITCHES;
+    switch(controller) {
+      case NO_CONTROLLER:
+        max_switches=0;
+        break;
+      case CONTROLLER1:
+        max_switches=8;
+        break;
+      case CONTROLLER2_V1:
+        max_switches=0;
+        break;
+      case CONTROLLER2_V2:
+        max_switches=0;
+        break;
     }
   
-    gtk_notebook_append_page(GTK_NOTEBOOK(notebook),grid1,gtk_label_new("Encoders"));
-  
-    // Switches
-  
-    GtkWidget *grid2=gtk_grid_new();
-    gtk_grid_set_column_spacing (GTK_GRID(grid2),10);
-    row=0;
-
-
-    if(controller==CONTROLLER1) {
-      b_enable_mox=gtk_check_button_new_with_label("Enable MOX/TUN");
-      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_enable_mox), ENABLE_MOX_BUTTON);
-      gtk_widget_show(b_enable_mox);
-      gtk_grid_attach(GTK_GRID(grid2),b_enable_mox,0,row,1,1);
-  
-      mox_label=gtk_label_new("GPIO:");
-      gtk_widget_show(mox_label);
-      gtk_grid_attach(GTK_GRID(grid2),mox_label,1,row,1,1);
-  
-      mox=gtk_spin_button_new_with_range (0.0,100.0,1.0);
-      gtk_spin_button_set_value (GTK_SPIN_BUTTON(mox),MOX_BUTTON);
-      gtk_widget_show(mox);
-      gtk_grid_attach(GTK_GRID(grid2),mox,2,row,1,1);
-
-      row++;
-  
-      b_enable_S1=gtk_check_button_new_with_label("Enable S1");
-      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_enable_S1), ENABLE_S1_BUTTON);
-      gtk_widget_show(b_enable_S1);
-      gtk_grid_attach(GTK_GRID(grid2),b_enable_S1,0,row,1,1);
-  
-      S1_label=gtk_label_new("GPIO:");
-      gtk_widget_show(S1_label);
-      gtk_grid_attach(GTK_GRID(grid2),S1_label,1,row,1,1);
-  
-      S1=gtk_spin_button_new_with_range (0.0,100.0,1.0);
-      gtk_spin_button_set_value (GTK_SPIN_BUTTON(S1),S1_BUTTON);
-      gtk_widget_show(S1);
-      gtk_grid_attach(GTK_GRID(grid2),S1,2,row,1,1);
-
-      row++;
+    grid=gtk_grid_new();
+    gtk_grid_set_column_homogeneous(GTK_GRID(grid),FALSE);
+    gtk_grid_set_row_homogeneous(GTK_GRID(grid),TRUE);
+    gtk_grid_set_column_spacing (GTK_GRID(grid),2);
+    gtk_grid_set_row_spacing (GTK_GRID(grid),2);
 
-      b_enable_S2=gtk_check_button_new_with_label("Enable S2");
-      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_enable_S2), ENABLE_S2_BUTTON);
-      gtk_widget_show(b_enable_S2);
-      gtk_grid_attach(GTK_GRID(grid),b_enable_S2,0,row,1,1);
-    
-      S2_label=gtk_label_new("GPIO:");
-      gtk_widget_show(S2_label);
-      gtk_grid_attach(GTK_GRID(grid),S2_label,1,row,1,1);
-  
-      S2=gtk_spin_button_new_with_range (0.0,100.0,1.0);
-      gtk_spin_button_set_value (GTK_SPIN_BUTTON(S2),S2_BUTTON);
-      gtk_widget_show(S2);
-      gtk_grid_attach(GTK_GRID(grid),S2,2,row,1,1);
+    row=0;
+    col=0;
   
-      row++;
+/*
+    widget=gtk_label_new(NULL);
+    gtk_label_set_markup (GTK_LABEL(widget), "<span foreground=\"#ff0000\"><b>Note: Pin number now use Broadcom GPIO</b></span>");
+    gtk_grid_attach(GTK_GRID(grid),widget,col,row,6,1);
   
-      b_enable_S3=gtk_check_button_new_with_label("Enable S3");
-      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_enable_S3), ENABLE_S3_BUTTON);
-      gtk_widget_show(b_enable_S3);
-      gtk_grid_attach(GTK_GRID(grid),b_enable_S3,0,row,1,1);
-    
-      S3_label=gtk_label_new("GPIO:");
-      gtk_widget_show(S3_label);
-      gtk_grid_attach(GTK_GRID(grid),S3_label,1,row,1,1);
-    
-      S3=gtk_spin_button_new_with_range (0.0,100.0,1.0);
-      gtk_spin_button_set_value (GTK_SPIN_BUTTON(S3),S3_BUTTON);
-      gtk_widget_show(S3);
-      gtk_grid_attach(GTK_GRID(grid),S3,2,row,1,1);
-
-      row++;
-
-      b_enable_S4=gtk_check_button_new_with_label("Enable S4");
-      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_enable_S4), ENABLE_S4_BUTTON);
-      gtk_widget_show(b_enable_S4);
-      gtk_grid_attach(GTK_GRID(grid2),b_enable_S4,0,row,1,1);
-    
-      S4_label=gtk_label_new("GPIO:");
-      gtk_widget_show(S4_label);
-      gtk_grid_attach(GTK_GRID(grid2),S4_label,1,row,1,1);
-    
-      S4=gtk_spin_button_new_with_range (0.0,100.0,1.0);
-      gtk_spin_button_set_value (GTK_SPIN_BUTTON(S4),S4_BUTTON);
-      gtk_widget_show(S4);
-      gtk_grid_attach(GTK_GRID(grid2),S4,2,row,1,1);
-    
-      row++;
+    row++;
+    col=0;
+*/
+    for(i=0;i<max_switches/8;i++) {
+      widget=gtk_label_new(NULL);
+      gtk_label_set_markup (GTK_LABEL(widget), "<b>ID</b>");
+      gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
+      col++;
     
-      b_enable_S5=gtk_check_button_new_with_label("Enable S5");
-      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_enable_S5), ENABLE_S5_BUTTON);
-      gtk_widget_show(b_enable_S5);
-      gtk_grid_attach(GTK_GRID(grid2),b_enable_S5,0,row,1,1);
+      widget=gtk_label_new(NULL);
+      gtk_label_set_markup (GTK_LABEL(widget), "<b>Gpio</b>");
+      gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
+      col++;
+    }
   
-      S5_label=gtk_label_new("GPIO:");
-      gtk_widget_show(S5_label);
-      gtk_grid_attach(GTK_GRID(grid2),S5_label,1,row,1,1);
-    
-      S5=gtk_spin_button_new_with_range (0.0,100.0,1.0);
-      gtk_spin_button_set_value (GTK_SPIN_BUTTON(S5),S5_BUTTON);
-      gtk_widget_show(S5);
-      gtk_grid_attach(GTK_GRID(grid2),S5,2,row,1,1);
-    
-      row++;
-    
-      b_enable_S6=gtk_check_button_new_with_label("Enable S6");
-      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_enable_S6), ENABLE_S6_BUTTON);
-      gtk_widget_show(b_enable_S6);
-      gtk_grid_attach(GTK_GRID(grid2),b_enable_S6,0,row,1,1);
-    
-      S6_label=gtk_label_new("GPIO:");
-      gtk_widget_show(S6_label);
-      gtk_grid_attach(GTK_GRID(grid2),S6_label,1,row,1,1);
-    
-      S6=gtk_spin_button_new_with_range (0.0,100.0,1.0);
-      gtk_spin_button_set_value (GTK_SPIN_BUTTON(S6),S6_BUTTON);
-      gtk_widget_show(S6);
-      gtk_grid_attach(GTK_GRID(grid2),S6,2,row,1,1);
-    
-      row++;
-    
-      b_enable_function=gtk_check_button_new_with_label("Enable Function");
-      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_enable_function), ENABLE_FUNCTION_BUTTON);
-      gtk_widget_show(b_enable_function);
-      gtk_grid_attach(GTK_GRID(grid2),b_enable_function,0,row,1,1);
-    
-      function_label=gtk_label_new("GPIO:");
-      gtk_widget_show(function_label);
-      gtk_grid_attach(GTK_GRID(grid2),function_label,1,row,1,1);
+    row++;
+    col=0;
+  
+    for(i=0;i<max_switches;i++) {
+      widget=gtk_label_new(NULL);
+      gchar id[16];
+      g_sprintf(id,"<b>%d</b>",i);
+      gtk_label_set_markup (GTK_LABEL(widget), id);
+      gtk_grid_attach(GTK_GRID(grid),widget,(i/8)*2,(row+(i%8)),1,1);
+  
+      widget=gtk_spin_button_new_with_range (0.0,28.0,1.0);
+      gtk_spin_button_set_value (GTK_SPIN_BUTTON(widget),switches[i].switch_address);
+      gtk_grid_attach(GTK_GRID(grid),widget,((i/8)*2)+1,(row+(i%8)),1,1);
+    }
     
-      function=gtk_spin_button_new_with_range (0.0,100.0,1.0);
-      gtk_spin_button_set_value (GTK_SPIN_BUTTON(function),FUNCTION_BUTTON);
-      gtk_widget_show(function);
-      gtk_grid_attach(GTK_GRID(grid2),function,2,row,1,1);
-
-      gtk_notebook_append_page(GTK_NOTEBOOK(notebook),grid2,gtk_label_new("Switches"));
-    } else {
-      char text[16];
-      GtkWidget *grid2=gtk_grid_new();
-      gtk_grid_set_column_spacing (GTK_GRID(grid2),10);
-      row=0;
-  
-      GtkWidget *label=gtk_label_new("I2C Device:");
-      gtk_widget_show(label);
-      gtk_grid_attach(GTK_GRID(grid2),label,0,row,1,1);
-  
-      i2c_device_text=gtk_entry_new();
-      gtk_widget_show(i2c_device_text);
-      gtk_entry_set_text (GTK_ENTRY(i2c_device_text),i2c_device);
-      gtk_grid_attach(GTK_GRID(grid2),i2c_device_text,1,row,1,1);
-     
-      label=gtk_label_new("I2C Address:");
-      gtk_widget_show(label);
-      gtk_grid_attach(GTK_GRID(grid2),label,2,row,1,1);
-  
-      i2c_address=gtk_entry_new();
-      sprintf(text,"0x%02X",i2c_address_1);
-      gtk_entry_set_text (GTK_ENTRY(i2c_address),text);
-      gtk_widget_show(i2c_address);
-      gtk_grid_attach(GTK_GRID(grid2),i2c_address,3,row,1,1);
+    gtk_notebook_append_page(GTK_NOTEBOOK(notebook),grid,gtk_label_new("switches"));
+  }
 
-      row++;
+  if(controller==CONTROLLER2_V1 || controller==CONTROLLER2_V2) {
+    grid=gtk_grid_new();
+    gtk_grid_set_column_homogeneous(GTK_GRID(grid),FALSE);
+    gtk_grid_set_row_homogeneous(GTK_GRID(grid),TRUE);
+    gtk_grid_set_column_spacing (GTK_GRID(grid),2);
+    gtk_grid_set_row_spacing (GTK_GRID(grid),2);
 
-      for(int i=0;i<8;i++) {
-        sprintf(text,"SW_%d",i+2);
-        label=gtk_label_new(text);
-        gtk_widget_show(label);
-        gtk_grid_attach(GTK_GRID(grid2),label,0,row,1,1);
+    row=0;
+    col=0;
+    char text[16];
+    grid=gtk_grid_new();
+    gtk_grid_set_column_spacing (GTK_GRID(grid),10);
+
+    widget=gtk_label_new(NULL);
+    gtk_label_set_markup(GTK_LABEL(widget),"<b>I2C Device</b>");
+    gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
+    col++;
+
+    widget=gtk_entry_new();
+    gtk_entry_set_text(GTK_ENTRY(widget),i2c_device);
+    gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
+    col++;
+
+    widget=gtk_label_new(NULL);
+    gtk_label_set_markup(GTK_LABEL(widget),"<b>I2C Address</b>");
+    gtk_widget_show(widget);
+    gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
+    col++;
+
+    widget=gtk_entry_new();
+    sprintf(text,"0x%02X",i2c_address_1);
+    gtk_entry_set_text(GTK_ENTRY(widget),text);
+    gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
 
-        i2c_sw_text[i]=gtk_entry_new();
-        sprintf(text,"0x%04X",i2c_sw[i]);
-        gtk_entry_set_text (GTK_ENTRY(i2c_sw_text[i]),text);
-        gtk_widget_show(i2c_sw_text[i]);
-        gtk_grid_attach(GTK_GRID(grid2),i2c_sw_text[i],1,row,1,1);
+    row++;
+    col=0;
 
-        sprintf(text,"SW_%d",i+10);
-        label=gtk_label_new(text);
-        gtk_widget_show(label);
-        gtk_grid_attach(GTK_GRID(grid2),label,2,row,1,1);
+    for(int i=0;i<8;i++) {
+      widget=gtk_label_new(NULL);
+      sprintf(text,"<b>SW_%d</b>",i+2);
+      gtk_label_set_markup(GTK_LABEL(widget),text);
+      gtk_grid_attach(GTK_GRID(grid),widget,0,row,1,1);
 
-        i2c_sw_text[i+8]=gtk_entry_new();
-        sprintf(text,"0x%04X",i2c_sw[i+8]);
-        gtk_entry_set_text (GTK_ENTRY(i2c_sw_text[i+8]),text);
-        gtk_widget_show(i2c_sw_text[i+8]);
-        gtk_grid_attach(GTK_GRID(grid2),i2c_sw_text[i+8],3,row,1,1);
+      i2c_sw_text[i]=gtk_entry_new();
+      sprintf(text,"0x%04X",i2c_sw[i]);
+      gtk_entry_set_text (GTK_ENTRY(i2c_sw_text[i]),text);
+      gtk_grid_attach(GTK_GRID(grid),i2c_sw_text[i],1,row,1,1);
 
-        row++;
+      widget=gtk_label_new(NULL);
+      sprintf(text,"<b>SW_%d</b>",i+10);
+      gtk_label_set_markup(GTK_LABEL(widget),text);
+      gtk_grid_attach(GTK_GRID(grid),widget,2,row,1,1);
 
-      }
+      i2c_sw_text[i+8]=gtk_entry_new();
+      sprintf(text,"0x%04X",i2c_sw[i+8]);
+      gtk_entry_set_text (GTK_ENTRY(i2c_sw_text[i+8]),text);
+      gtk_grid_attach(GTK_GRID(grid),i2c_sw_text[i+8],3,row,1,1);
 
-      gtk_notebook_append_page(GTK_NOTEBOOK(notebook),grid2,gtk_label_new("I2C"));
+      row++;
     }
-
+    
+    gtk_notebook_append_page(GTK_NOTEBOOK(notebook),grid,gtk_label_new("i2c"));
   }
 
-#ifdef LOCALCW
-  // CW
-
-  GtkWidget *grid3=gtk_grid_new();
-  gtk_grid_set_column_spacing (GTK_GRID(grid3),10);
-  row=0;
-
-  cwl_label=gtk_label_new("CWL GPIO:");
-  gtk_widget_show(cwl_label);
-  gtk_grid_attach(GTK_GRID(grid3),cwl_label,0,row,1,1);
-
-  cwl=gtk_spin_button_new_with_range (0.0,100.0,1.0);
-  gtk_spin_button_set_value (GTK_SPIN_BUTTON(cwl),CWL_BUTTON);
-  gtk_widget_show(cwl);
-  gtk_grid_attach(GTK_GRID(grid3),cwl,1,row,1,1);
-
-  b_enable_cwlr=gtk_check_button_new_with_label("CWLR Enable");
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_enable_cwlr), ENABLE_CW_BUTTONS);
-  gtk_widget_show(b_enable_cwlr);
-  gtk_grid_attach(GTK_GRID(grid3),b_enable_cwlr,2,row,1,1);
-
-  row++;
-
-  cwr_label=gtk_label_new("CWR GPIO:");
-  gtk_widget_show(cwr_label);
-  gtk_grid_attach(GTK_GRID(grid3),cwr_label,0,row,1,1);
-
-  cwr=gtk_spin_button_new_with_range (0.0,100.0,1.0);
-  gtk_spin_button_set_value (GTK_SPIN_BUTTON(cwr),CWR_BUTTON);
-  gtk_widget_show(cwr);
-  gtk_grid_attach(GTK_GRID(grid3),cwr,1,row,1,1);
-
-  b_cw_active_low=gtk_check_button_new_with_label("CWLR active-low");
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_cw_active_low), CW_ACTIVE_LOW);
-  gtk_widget_show(b_cw_active_low);
-  gtk_grid_attach(GTK_GRID(grid3),b_cw_active_low,2,row,1,1);
-
-  row++;
-
-  cws_label=gtk_label_new("  SideTone GPIO:");
-  gtk_widget_show(cws_label);
-  gtk_grid_attach(GTK_GRID(grid3),cws_label,0,row,1,1);
-
-  cws=gtk_spin_button_new_with_range (0.0,100.0,1.0);
-  gtk_spin_button_set_value (GTK_SPIN_BUTTON(cws),SIDETONE_GPIO);
-  gtk_widget_show(cws);
-  gtk_grid_attach(GTK_GRID(grid3),cws,1,row,1,1);
-
-  b_enable_cws=gtk_check_button_new_with_label("Enable");
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_enable_cws), ENABLE_GPIO_SIDETONE);
-  gtk_widget_show(b_enable_cws);
-  gtk_grid_attach(GTK_GRID(grid3),b_enable_cws,2,row,1,1);
-
-  gtk_notebook_append_page(GTK_NOTEBOOK(notebook),grid3,gtk_label_new("CW"));
-#endif
-
-#ifdef PTT
-  GtkWidget *grid4=gtk_grid_new();
-  gtk_grid_set_column_spacing (GTK_GRID(grid4),10);
-  row=0;
-
-  b_enable_ptt=gtk_check_button_new_with_label("PTT Enable");
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_enable_ptt), ENABLE_PTT_GPIO);
-  gtk_widget_show(b_enable_ptt);
-  gtk_grid_attach(GTK_GRID(grid4),b_enable_ptt,0,row,1,1);
-
-  row++;
-
-  ptt_label=gtk_label_new("PTT GPIO:");
-  gtk_widget_show(ptt_label);
-  gtk_grid_attach(GTK_GRID(grid4),ptt_label,0,row,1,1);
-
-  ptt=gtk_spin_button_new_with_range (0.0,100.0,1.0);
-  gtk_spin_button_set_value (GTK_SPIN_BUTTON(ptt),CWR_BUTTON);
-  gtk_widget_show(ptt);
-  gtk_grid_attach(GTK_GRID(grid4),ptt,1,row,1,1);
-
-  row++;
-
-  b_ptt_active_low=gtk_check_button_new_with_label("PTT active-low");
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_ptt_active_low), PTT_ACTIVE_LOW);
-  gtk_widget_show(b_ptt_active_low);
-  gtk_grid_attach(GTK_GRID(grid4),b_ptt_active_low,0,row,1,1);
-
-  gtk_notebook_append_page(GTK_NOTEBOOK(notebook),grid4,gtk_label_new("PTT"));
-#endif
-
-  gtk_grid_attach(GTK_GRID(grid0),notebook,0,1,6,1);
-  gtk_container_add(GTK_CONTAINER(content),grid0);
+  gtk_container_add(GTK_CONTAINER(content),notebook);
 
   gtk_widget_show_all(dialog);
   gtk_dialog_run(GTK_DIALOG(dialog));
-
 }
 #endif
 
index 234086e8317a74cd2a26b50b9ffd43827360db19..6110e3c33c9549a453663fa4a3f261c2646428ff 100644 (file)
@@ -47,6 +47,7 @@
 #endif
 #include "ext.h"
 #ifdef GPIO
+#include "actions.h"
 #include "gpio.h"
 #include "configure.h"
 #endif
index bde18bfe37b58bc58aed7bcebc54951e16519113..44876eb3db0ff8e608062950bf5a96afe9cbaa12 100644 (file)
@@ -18,6 +18,7 @@
 */
 
 #include <gtk/gtk.h>
+#include <glib/gprintf.h>
 #include <stdio.h>
 #include <string.h>
 
 #include "receiver.h"
 #include "vfo.h"
 #include "button_text.h"
+#include "actions.h"
 #include "gpio.h"
 #include "i2c.h"
 
-static GtkWidget *parent_window=NULL;
-
-static GtkWidget *dialog=NULL;
-
-static GtkWidget *b_af_gain_rx1;
-static GtkWidget *b_af_gain_rx2;
-static GtkWidget *b_agc_gain_rx1;
-static GtkWidget *b_agc_gain_rx2;
-static GtkWidget *b_attenuation;
-static GtkWidget *b_mic_gain;
-static GtkWidget *b_drive;
-static GtkWidget *b_tune_drive;
-static GtkWidget *b_rit_rx1;
-static GtkWidget *b_rit_rx2;
-static GtkWidget *b_xit;
-static GtkWidget *b_cw_speed;
-static GtkWidget *b_cw_frequency;
-static GtkWidget *b_panadapter_high;
-static GtkWidget *b_panadapter_low;
-static GtkWidget *b_squelch;
-static GtkWidget *b_compression;
-
-static GtkWidget *b_top_af_gain_rx1;
-static GtkWidget *b_top_af_gain_rx2;
-static GtkWidget *b_top_agc_gain_rx1;
-static GtkWidget *b_top_agc_gain_rx2;
-static GtkWidget *b_top_attenuation;
-static GtkWidget *b_top_mic_gain;
-static GtkWidget *b_top_drive;
-static GtkWidget *b_top_tune_drive;
-static GtkWidget *b_top_rit_rx1;
-static GtkWidget *b_top_rit_rx2;
-static GtkWidget *b_top_xit;
-static GtkWidget *b_top_cw_speed;
-static GtkWidget *b_top_cw_frequency;
-static GtkWidget *b_top_panadapter_high;
-static GtkWidget *b_top_panadapter_low;
-static GtkWidget *b_top_squelch;
-static GtkWidget *b_top_compression;
-
-enum {
-  ENC2,
-  ENC2_TOP,
-  ENC2_SW,
-  ENC3,
-  ENC3_TOP,
-  ENC3_SW,
-  ENC4,
-  ENC4_TOP,
-  ENC4_SW,
-  ENC5,
-  ENC5_TOP,
-  ENC5_SW,
-};
-
 typedef struct _choice {
   int id;
   int action;
   GtkWidget *button;
 } CHOICE;
 
-static int encoder;
+static GtkWidget *parent_window=NULL;
+
+static GtkWidget *dialog=NULL;
 
 static void cleanup() {
   if(dialog!=NULL) {
@@ -116,49 +65,36 @@ static gboolean delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_d
   return FALSE;
 }
 
-static void enc_select_cb(GtkWidget *widget,gpointer data) {
+static void encoder_bottom_select_cb(GtkWidget *widget,gpointer data) {
   CHOICE *choice=(CHOICE *)data;
-  switch(choice->id) {
-    case ENC2:
-      e2_encoder_action=choice->action;
-      break;
-    case ENC2_TOP:
-      e2_top_encoder_action=choice->action;
-      break;
-    case ENC3:
-      e3_encoder_action=choice->action;
-      break;
-    case ENC3_TOP:
-      e3_top_encoder_action=choice->action;
-      break;
-    case ENC4:
-      e4_encoder_action=choice->action;
-      break;
-    case ENC4_TOP:
-      e4_top_encoder_action=choice->action;
-      break;
-    case ENC5:
-      e5_encoder_action=choice->action;
-      break;
-    case ENC5_TOP:
-      e5_top_encoder_action=choice->action;
-      break;
-  }
+  encoders[choice->id].bottom_encoder_function=choice->action;
+  gtk_button_set_label(GTK_BUTTON(choice->button),encoder_string[choice->action]);
+}
+
+static void encoder_top_select_cb(GtkWidget *widget,gpointer data) {
+  CHOICE *choice=(CHOICE *)data;
+  encoders[choice->id].top_encoder_function=choice->action;
   gtk_button_set_label(GTK_BUTTON(choice->button),encoder_string[choice->action]);
 }
 
-static gboolean enc_cb(GtkWidget *widget, GdkEvent *event, gpointer data) {
-  int enc=GPOINTER_TO_INT(data);
+static void encoder_switch_select_cb(GtkWidget *widget,gpointer data) {
+  CHOICE *choice=(CHOICE *)data;
+  encoders[choice->id].switch_function=choice->action;
+  gtk_button_set_label(GTK_BUTTON(choice->button),sw_string[choice->action]);
+}
+
+static gboolean encoder_bottom_cb(GtkWidget *widget, GdkEvent *event, gpointer data) {
+  int encoder=GPOINTER_TO_INT(data);
   int i;
 
   GtkWidget *menu=gtk_menu_new();
   for(i=0;i<ENCODER_ACTIONS;i++) {
     GtkWidget *menu_item=gtk_menu_item_new_with_label(encoder_string[i]);
     CHOICE *choice=g_new0(CHOICE,1);
-    choice->id=enc;
+    choice->id=encoder;
     choice->action=i;
     choice->button=widget;
-    g_signal_connect(menu_item,"activate",G_CALLBACK(enc_select_cb),choice);
+    g_signal_connect(menu_item,"activate",G_CALLBACK(encoder_bottom_select_cb),choice);
     gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
   }
   gtk_widget_show_all(menu);
@@ -169,41 +105,46 @@ static gboolean enc_cb(GtkWidget *widget, GdkEvent *event, gpointer data) {
 #else
   gtk_menu_popup(GTK_MENU(menu),NULL,NULL,NULL,NULL,0,gtk_get_current_event_time());
 #endif
-  
   return TRUE;
 }
 
-static void sw_select_cb(GtkWidget *widget,gpointer data) {
-  CHOICE *choice=(CHOICE *)data;
-  switch(choice->id) {
-    case ENC2_SW:
-      e2_sw_action=choice->action;
-      break;
-    case ENC3_SW:
-      e3_sw_action=choice->action;
-      break;
-    case ENC4_SW:
-      e4_sw_action=choice->action;
-      break;
-    case ENC5_SW:
-      e5_sw_action=choice->action;
-      break;
+static gboolean encoder_top_cb(GtkWidget *widget, GdkEvent *event, gpointer data) {
+  int encoder=GPOINTER_TO_INT(data);
+  int i;
+
+  GtkWidget *menu=gtk_menu_new();
+  for(i=0;i<ENCODER_ACTIONS;i++) {
+    GtkWidget *menu_item=gtk_menu_item_new_with_label(encoder_string[i]);
+    CHOICE *choice=g_new0(CHOICE,1);
+    choice->id=encoder;
+    choice->action=i;
+    choice->button=widget;
+    g_signal_connect(menu_item,"activate",G_CALLBACK(encoder_top_select_cb),choice);
+    gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
   }
-  gtk_button_set_label(GTK_BUTTON(choice->button),sw_string[choice->action]);
+  gtk_widget_show_all(menu);
+#if GTK_CHECK_VERSION(3,22,0)
+  gtk_menu_popup_at_pointer(GTK_MENU(menu),(GdkEvent *)event);
+// the following line of code is to work around the problem of the popup menu not having scroll bars.
+  gtk_menu_reposition(GTK_MENU(menu));
+#else
+  gtk_menu_popup(GTK_MENU(menu),NULL,NULL,NULL,NULL,0,gtk_get_current_event_time());
+#endif
+  return TRUE;
 }
 
-static gboolean sw_cb(GtkWidget *widget, GdkEvent *event, gpointer data) {
-  int sw=GPOINTER_TO_INT(data);
+static gboolean encoder_switch_cb(GtkWidget *widget, GdkEvent *event, gpointer data) {
+  int encoder=GPOINTER_TO_INT(data);
   int i;
 
   GtkWidget *menu=gtk_menu_new();
   for(i=0;i<SWITCH_ACTIONS;i++) {
     GtkWidget *menu_item=gtk_menu_item_new_with_label(sw_string[i]);
     CHOICE *choice=g_new0(CHOICE,1);
-    choice->id=sw;
+    choice->id=encoder;
     choice->action=i;
     choice->button=widget;
-    g_signal_connect(menu_item,"activate",G_CALLBACK(sw_select_cb),choice);
+    g_signal_connect(menu_item,"activate",G_CALLBACK(encoder_switch_select_cb),choice);
     gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
   }
   gtk_widget_show_all(menu);
@@ -214,420 +155,28 @@ static gboolean sw_cb(GtkWidget *widget, GdkEvent *event, gpointer data) {
 #else
   gtk_menu_popup(GTK_MENU(menu),NULL,NULL,NULL,NULL,0,gtk_get_current_event_time());
 #endif
-
   return TRUE;
 }
 
-GtkWidget* getRadioButton(int action) {
-  GtkWidget* button;
-  switch(action) {
-    case ENCODER_AF_GAIN_RX1:
-      button=b_af_gain_rx1;
-      break;
-    case ENCODER_AF_GAIN_RX2:
-      button=b_af_gain_rx2;
-      break;
-    case ENCODER_AGC_GAIN_RX1:
-      button=b_agc_gain_rx1;
-      break;
-    case ENCODER_AGC_GAIN_RX2:
-      button=b_agc_gain_rx2;
-      break;
-    case ENCODER_ATTENUATION:
-      button=b_attenuation;
-      break;
-    case ENCODER_MIC_GAIN:
-      button=b_mic_gain;
-      break;
-    case ENCODER_DRIVE:
-      button=b_drive;
-      break;
-    case ENCODER_TUNE_DRIVE:
-      button=b_tune_drive;
-      break;
-    case ENCODER_RIT_RX1:
-      button=b_rit_rx1;
-      break;
-    case ENCODER_RIT_RX2:
-      button=b_rit_rx2;
-      break;
-    case ENCODER_XIT:
-      button=b_xit;
-      break;
-    case ENCODER_CW_SPEED:
-      button=b_cw_speed;
-      break;
-    case ENCODER_CW_FREQUENCY:
-      button=b_cw_frequency;
-      break;
-    case ENCODER_PANADAPTER_HIGH:
-      button=b_panadapter_high;
-      break;
-    case ENCODER_PANADAPTER_LOW:
-      button=b_panadapter_low;
-      break;
-    case ENCODER_SQUELCH:
-      button=b_squelch;
-      break;
-    case ENCODER_COMP:
-      button=b_compression;
-      break;
-  }
-  return button;
-}
-
-GtkWidget* getTopRadioButton(int action) {
-  GtkWidget* button;
-  switch(action) {
-    case ENCODER_AF_GAIN_RX1:
-      button=b_top_af_gain_rx1;
-      break;
-    case ENCODER_AF_GAIN_RX2:
-      button=b_top_af_gain_rx2;
-      break;
-    case ENCODER_AGC_GAIN_RX1:
-      button=b_top_agc_gain_rx1;
-      break;
-    case ENCODER_AGC_GAIN_RX2:
-      button=b_top_agc_gain_rx2;
-      break;
-    case ENCODER_ATTENUATION:
-      button=b_top_attenuation;
-      break;
-    case ENCODER_MIC_GAIN:
-      button=b_top_mic_gain;
-      break;
-    case ENCODER_DRIVE:
-      button=b_top_drive;
-      break;
-/*
-    case ENCODER_TUNE_DRIVE:
-      button=b_top_tune_drive;
-      break;
-*/
-    case ENCODER_RIT_RX1:
-      button=b_top_rit_rx1;
-      break;
-    case ENCODER_RIT_RX2:
-      button=b_top_rit_rx2;
-      break;
-    case ENCODER_XIT:
-      button=b_top_xit;
-      break;
-    case ENCODER_CW_SPEED:
-      button=b_top_cw_speed;
-      break;
-    case ENCODER_CW_FREQUENCY:
-      button=b_top_cw_frequency;
-      break;
-    case ENCODER_PANADAPTER_HIGH:
-      button=b_top_panadapter_high;
-      break;
-    case ENCODER_PANADAPTER_LOW:
-      button=b_top_panadapter_low;
-      break;
-    case ENCODER_SQUELCH:
-      button=b_top_squelch;
-      break;
-    case ENCODER_COMP:
-      button=b_top_compression;
-      break;
-  }
-  return button;
-}
-
-static gboolean select_cb (GtkWidget *widget, gpointer data) {
-  GtkWidget *button;
-  int action;
-
-  switch(encoder) {
-    case 2:
-      action=e2_encoder_action;
-      break;
-    case 3:
-      action=e3_encoder_action;
-      break;
-    case 4:
-      action=e4_encoder_action;
-      break;
-    case 5:
-      action=e5_encoder_action;
-      break;
-  }
-  button=getRadioButton(action);
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
-}
-
-static gboolean top_select_cb (GtkWidget *widget, gpointer data) {
-  GtkWidget *button;
-  int action;
-
-  switch(encoder) {
-    case 2:
-      action=e2_top_encoder_action;
-      break;
-    case 3:
-      action=e3_top_encoder_action;
-      break;
-    case 4:
-      action=e4_top_encoder_action;
-      break;
-    case 5:
-      action=e5_top_encoder_action;
-      break;
-  }
-  button=getTopRadioButton(action);
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
-}
-
-void encoder_select(int pos) {
-  int action;
-  GtkWidget *button;
-  switch(encoder) {
-    case 2:
-        if(pos>0) {
-          e2_encoder_action--;
-          if(e2_encoder_action<0) {
-            e2_encoder_action=ENCODER_ACTIONS-1;
-          }
-        } if(pos<0) {
-          e2_encoder_action++;
-          if(e2_encoder_action>=ENCODER_ACTIONS) {
-            e2_encoder_action=0;
-          }
-        }
-        action=e2_encoder_action;
-      break;
-    case 3:
-        if(pos>0) {
-          e3_encoder_action--;
-          if(e3_encoder_action<0) {
-            e3_encoder_action=ENCODER_ACTIONS-1;
-          }
-        } if(pos<0) {
-          e3_encoder_action++;
-          if(e3_encoder_action>=ENCODER_ACTIONS) {
-            e3_encoder_action=0;
-          }
-        }
-        action=e3_encoder_action;
-      break;
-    case 4:
-        if(pos>0) {
-          e4_encoder_action--;
-          if(e4_encoder_action<0) {
-            e4_encoder_action=ENCODER_ACTIONS-1;
-          }
-        } if(pos<0) {
-          e4_encoder_action++;
-          if(e4_encoder_action>=ENCODER_ACTIONS) {
-            e4_encoder_action=0;
-          }
-        }
-        action=e4_encoder_action;
-      break;
-  }
-
-  button=getRadioButton(action);
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
-
-}
-
-void top_encoder_select(int pos) {
-  int action;
-  GtkWidget *button;
-  switch(encoder) {
-    case 2:
-        if(pos>0) {
-          e2_top_encoder_action--;
-          if(e2_top_encoder_action<0) {
-            e2_top_encoder_action=ENCODER_ACTIONS-1;
-          }
-        } if(pos<0) {
-          e2_top_encoder_action++;
-          if(e2_top_encoder_action>=ENCODER_ACTIONS) {
-            e2_top_encoder_action=0;
-          }
-        }
-        action=e2_top_encoder_action;
-      break;
-    case 3:
-        if(pos>0) {
-          e3_top_encoder_action--;
-          if(e3_top_encoder_action<0) {
-            e3_top_encoder_action=ENCODER_ACTIONS-1;
-          }
-        } if(pos<0) {
-          e3_top_encoder_action++;
-          if(e3_top_encoder_action>=ENCODER_ACTIONS) {
-            e3_top_encoder_action=0;
-          }
-        }
-        action=e3_top_encoder_action;
-      break;
-    case 4:
-        if(pos>0) {
-          e4_top_encoder_action--;
-          if(e4_top_encoder_action<0) {
-            e4_top_encoder_action=ENCODER_ACTIONS-1;
-          }
-        } if(pos<0) {
-          e4_top_encoder_action++;
-          if(e4_top_encoder_action>=ENCODER_ACTIONS) {
-            e4_top_encoder_action=0;
-          }
-        }
-        action=e4_top_encoder_action;
-      break;
-    case 5:
-        if(pos>0) {
-          e5_top_encoder_action--;
-          if(e5_top_encoder_action<0) {
-            e5_top_encoder_action=ENCODER_ACTIONS-1;
-          }
-        } if(pos<0) {
-          e5_top_encoder_action++;
-          if(e5_top_encoder_action>=ENCODER_ACTIONS) {
-            e5_top_encoder_action=0;
-          }
-        }
-        action=e5_top_encoder_action;
-      break;
-  }
-
-  button=getTopRadioButton(action);
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
-
-}
-
-  static gboolean action_select_cb (GtkWidget *widget, gpointer data) {
-    int action=(int)data;
-    switch(encoder) {
-      case 2:
-        e2_encoder_action=action;
-        break;
-      case 3:
-        e3_encoder_action=action;
-        break;
-      case 4:
-        e4_encoder_action=action;
-        break;
-      case 5:
-        e5_encoder_action=action;
-        break;
-    }
-  }
-
-  static gboolean top_action_select_cb (GtkWidget *widget, gpointer data) {
-    int action=(int)data;
-    switch(encoder) {
-      case 2:
-        e2_top_encoder_action=action;
-        break;
-      case 3:
-        e3_top_encoder_action=action;
-        break;
-      case 4:
-        e4_top_encoder_action=action;
-        break;
-      case 5:
-        e5_top_encoder_action=action;
-        break;
-    }
-  }
-
-  static gboolean enc2_cb(GtkWidget *widget, gpointer data) {
-    int i=gtk_combo_box_get_active (GTK_COMBO_BOX(widget));
-    e2_encoder_action=i;
-    return TRUE;
-  }
-
-  static gboolean enc2_sw_cb(GtkWidget *widget, gpointer data) {
-    int i=gtk_combo_box_get_active (GTK_COMBO_BOX(widget));
-    e2_sw_action=i;
-    return TRUE;
-  }
-
-  static gboolean enc3_cb(GtkWidget *widget, gpointer data) {
-    int i=gtk_combo_box_get_active (GTK_COMBO_BOX(widget));
-    e3_encoder_action=i;
-    return TRUE;
-  }
-
-  static gboolean enc3_sw_cb(GtkWidget *widget, gpointer data) {
-    int i=gtk_combo_box_get_active (GTK_COMBO_BOX(widget));
-    e3_sw_action=i;
-    return TRUE;
-  }
-
-  static gboolean enc4_cb(GtkWidget *widget, gpointer data) {
-    int i=gtk_combo_box_get_active (GTK_COMBO_BOX(widget));
-    e4_encoder_action=i;
-    return TRUE;
-  }
-
-  static gboolean enc4_sw_cb(GtkWidget *widget, gpointer data) {
-    int i=gtk_combo_box_get_active (GTK_COMBO_BOX(widget));
-    e4_sw_action=i;
-    return TRUE;
-  }
-
-  static gboolean enc2_top_cb(GtkWidget *widget, gpointer data) {
-    int i=gtk_combo_box_get_active (GTK_COMBO_BOX(widget));
-    e2_top_encoder_action=i;
-    return TRUE;
-  }
-
-  static gboolean enc3_top_cb(GtkWidget *widget, gpointer data) {
-    int i=gtk_combo_box_get_active (GTK_COMBO_BOX(widget));
-    e3_top_encoder_action=i;
-    return TRUE;
-  }
-
-  static gboolean enc4_top_cb(GtkWidget *widget, gpointer data) {
-    int i=gtk_combo_box_get_active (GTK_COMBO_BOX(widget));
-    e4_top_encoder_action=i;
-    return TRUE;
-  }
-
-  static gboolean enc5_cb(GtkWidget *widget, gpointer data) {
-    int i=gtk_combo_box_get_active (GTK_COMBO_BOX(widget));
-    e5_encoder_action=i;
-    return TRUE;
-  }
-  static gboolean enc5_sw_cb(GtkWidget *widget, gpointer data) {
-    int i=gtk_combo_box_get_active (GTK_COMBO_BOX(widget));
-    e5_sw_action=i;
-    return TRUE;
-  }
-
-
-  static gboolean enc5_top_cb(GtkWidget *widget, gpointer data) {
-    int i=gtk_combo_box_get_active (GTK_COMBO_BOX(widget));
-    e5_top_encoder_action=i;
-    return TRUE;
-  }
 
 void encoder_menu(GtkWidget *parent) {
-  int row=0;
-  int col=0;
+  gint row=0;
+  gint col=0;
+  char label[32];
 
   dialog=gtk_dialog_new();
-  gtk_window_set_transient_for(GTK_WINDOW(dialog),GTK_WINDOW(parent_window));
+  gtk_window_set_transient_for(GTK_WINDOW(dialog),GTK_WINDOW(parent));
   //gtk_window_set_decorated(GTK_WINDOW(dialog),FALSE);
   char title[32];
-  sprintf(title,"piHPSDR - Encoder Actions:");
+  sprintf(title,"piHPSDR - Encoder Actions");
   gtk_window_set_title(GTK_WINDOW(dialog),title);
   g_signal_connect (dialog, "delete_event", G_CALLBACK (delete_event), NULL);
 
   GtkWidget *content=gtk_dialog_get_content_area(GTK_DIALOG(dialog));
-
   GtkWidget *grid=gtk_grid_new();
 
-  gtk_grid_set_column_homogeneous(GTK_GRID(grid),FALSE);
+  gtk_grid_set_column_homogeneous(GTK_GRID(grid),TRUE);
   gtk_grid_set_row_homogeneous(GTK_GRID(grid),TRUE);
-  gtk_grid_set_column_spacing (GTK_GRID(grid),2);
-  gtk_grid_set_row_spacing (GTK_GRID(grid),2);
 
   GtkWidget *close_b=gtk_button_new_with_label("Close");
   g_signal_connect (close_b, "pressed", G_CALLBACK(close_cb), NULL);
@@ -635,126 +184,80 @@ void encoder_menu(GtkWidget *parent) {
 
   row++;
   col=0;
-  GtkWidget *label_encoder=gtk_label_new(NULL);
-  gtk_label_set_markup(GTK_LABEL(label_encoder), "<b>Encoder</b>");
-  gtk_grid_attach(GTK_GRID(grid),label_encoder,col,row,1,1);
-  col++;
-  if(controller==CONTROLLER2_V2) {
-    GtkWidget *label_bottom=gtk_label_new(NULL);
-    gtk_label_set_markup(GTK_LABEL(label_bottom), "<b>Bottom</b>");
-    gtk_grid_attach(GTK_GRID(grid),label_bottom,col,row,1,1);
-    col++;
-    GtkWidget *label_top=gtk_label_new(NULL);
-    gtk_label_set_markup(GTK_LABEL(label_top), "<b>Top</b>");
-    gtk_grid_attach(GTK_GRID(grid),label_top,col,row,1,1);
-    col++;
-  } else {
-    GtkWidget *label_bottom=gtk_label_new(NULL);
-    gtk_label_set_markup(GTK_LABEL(label_bottom), "<b>Encoder</b>");
-    gtk_grid_attach(GTK_GRID(grid),label_bottom,col,row,1,1);
-    col++;
-  }
-  GtkWidget *label_switch=gtk_label_new(NULL);
-  gtk_label_set_markup(GTK_LABEL(label_switch), "<b>Switch</b>");
-  gtk_grid_attach(GTK_GRID(grid),label_switch,col,row,1,1);
-  col++;
 
-  row++;
-  col=0;
-
-  GtkWidget *enc2_title=gtk_label_new(NULL);
-  gtk_label_set_markup(GTK_LABEL(enc2_title), "<b>ENC2: </b>");
-  gtk_grid_attach(GTK_GRID(grid),enc2_title,col,row,1,1);
-  col++;
-
-  GtkWidget *enc2=gtk_button_new_with_label(encoder_string[e2_encoder_action]);
-  gtk_grid_attach(GTK_GRID(grid),enc2,col,row,1,1);
-  g_signal_connect(enc2,"button_press_event",G_CALLBACK(enc_cb),GINT_TO_POINTER(ENC2));
-  col++;
-  
-  if(controller==CONTROLLER2_V2) {
-    GtkWidget *enc2_top=gtk_button_new_with_label(encoder_string[e2_top_encoder_action]);
-    gtk_grid_attach(GTK_GRID(grid),enc2_top,col,row,1,1);
-    g_signal_connect(enc2_top,"button_press_event",G_CALLBACK(enc_cb),GINT_TO_POINTER(ENC2_TOP));
-    col++;
+  gint max_encoders=MAX_ENCODERS;
+  switch(controller) {
+    case NO_CONTROLLER:
+      max_encoders=0;
+      break;
+    case CONTROLLER1:
+      max_encoders=4;
+      break;
+    case CONTROLLER2_V1:
+      max_encoders=5;
+      break;
+    case CONTROLLER2_V2:
+      max_encoders=5;
+      break;
   }
 
-  GtkWidget *enc2_sw=gtk_button_new_with_label(sw_string[e2_sw_action]);
-  gtk_grid_attach(GTK_GRID(grid),enc2_sw,col,row,1,1);
-  g_signal_connect(enc2_sw,"button_press_event",G_CALLBACK(sw_cb),GINT_TO_POINTER(ENC2_SW));
-
-  row++;
-  col=0;
-
-  GtkWidget *enc3_title=gtk_label_new(NULL);
-  gtk_label_set_markup(GTK_LABEL(enc3_title), "<b>ENC3: </b>");
-  gtk_grid_attach(GTK_GRID(grid),enc3_title,col,row,1,1);
-  col++;
-
-  GtkWidget *enc3=gtk_button_new_with_label(encoder_string[e3_encoder_action]);
-  gtk_grid_attach(GTK_GRID(grid),enc3,col,row,1,1);
-  g_signal_connect(enc3,"button_press_event",G_CALLBACK(enc_cb),GINT_TO_POINTER(ENC3));
+  GtkWidget *widget=gtk_label_new("");
+  gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
   col++;
-  
-  if(controller==CONTROLLER2_V2) {
-    GtkWidget *enc3_top=gtk_button_new_with_label(encoder_string[e3_top_encoder_action]);
-    gtk_grid_attach(GTK_GRID(grid),enc3_top,col,row,1,1);
-    g_signal_connect(enc3_top,"button_press_event",G_CALLBACK(enc_cb),GINT_TO_POINTER(ENC3_TOP));
-    col++;
-  }
-
-  GtkWidget *enc3_sw=gtk_button_new_with_label(sw_string[e3_sw_action]);
-  gtk_grid_attach(GTK_GRID(grid),enc3_sw,col,row,1,1);
-  g_signal_connect(enc3_sw,"button_press_event",G_CALLBACK(sw_cb),GINT_TO_POINTER(ENC3_SW));
-
-  row++;
-  col=0;
 
-  GtkWidget *enc4_title=gtk_label_new(NULL);
-  gtk_label_set_markup(GTK_LABEL(enc4_title), "<b>ENC4: </b>");
-  gtk_grid_attach(GTK_GRID(grid),enc4_title,col,row,1,1);
+  widget=gtk_label_new(NULL);
+  gtk_label_set_markup (GTK_LABEL(widget), controller==CONTROLLER2_V2?"<b>Bottom Encoder</b>":"<b>Encoder</b>");
+  gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
   col++;
 
-  GtkWidget *enc4=gtk_button_new_with_label(encoder_string[e4_encoder_action]);
-  gtk_grid_attach(GTK_GRID(grid),enc4,col,row,1,1);
-  g_signal_connect(enc4,"button_press_event",G_CALLBACK(enc_cb),GINT_TO_POINTER(ENC4));
-  col++;
-  
   if(controller==CONTROLLER2_V2) {
-    GtkWidget *enc4_top=gtk_button_new_with_label(encoder_string[e4_top_encoder_action]);
-    gtk_grid_attach(GTK_GRID(grid),enc4_top,col,row,1,1);
-    g_signal_connect(enc4_top,"button_press_event",G_CALLBACK(enc_cb),GINT_TO_POINTER(ENC4_TOP));
+    widget=gtk_label_new(NULL);
+    gtk_label_set_markup (GTK_LABEL(widget), "<b>Top Encoder</b>");
+    gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
     col++;
   }
 
-  GtkWidget *enc4_sw=gtk_button_new_with_label(sw_string[e4_sw_action]);
-  gtk_grid_attach(GTK_GRID(grid),enc4_sw,col,row,1,1);
-  g_signal_connect(enc4_sw,"button_press_event",G_CALLBACK(sw_cb),GINT_TO_POINTER(ENC4_SW));
+  widget=gtk_label_new(NULL);
+  gtk_label_set_markup (GTK_LABEL(widget), "<b>Switch</b>");
+  gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
 
   row++;
   col=0;
 
-  if(controller==CONTROLLER2_V1 || controller==CONTROLLER2_V2) {
-    GtkWidget *enc5_title=gtk_label_new(NULL);
-    gtk_label_set_markup(GTK_LABEL(enc5_title), "<b>ENC5: </b>");
-    gtk_grid_attach(GTK_GRID(grid),enc5_title,col,row,1,1);
+  for(int i=0;i<max_encoders;i++) {
+    widget=gtk_label_new(NULL);
+    g_sprintf(label,"<b>%d</b>",i);
+    gtk_label_set_markup (GTK_LABEL(widget), label);
+    gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
     col++;
 
-    GtkWidget *enc5=gtk_button_new_with_label(encoder_string[e5_encoder_action]);
-    gtk_grid_attach(GTK_GRID(grid),enc5,col,row,1,1);
-    g_signal_connect(enc5,"button_press_event",G_CALLBACK(enc_cb),GINT_TO_POINTER(ENC5));
+    if(i==(max_encoders-1)) {
+      widget=gtk_label_new(NULL);
+      g_sprintf(label,"<b>%s</b>",encoder_string[encoders[i].bottom_encoder_function]);
+      gtk_label_set_markup (GTK_LABEL(widget), label);
+    } else {
+      widget=gtk_button_new_with_label(encoder_string[encoders[i].bottom_encoder_function]);
+      g_signal_connect(widget,"button_press_event",G_CALLBACK(encoder_bottom_cb),GINT_TO_POINTER(i));
+    }
+    gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
     col++;
-  
+
     if(controller==CONTROLLER2_V2) {
-      GtkWidget *enc5_top=gtk_button_new_with_label(encoder_string[e5_top_encoder_action]);
-      gtk_grid_attach(GTK_GRID(grid),enc5_top,col,row,1,1);
-      g_signal_connect(enc5_top,"button_press_event",G_CALLBACK(enc_cb),GINT_TO_POINTER(ENC5_TOP));
+      widget=gtk_button_new_with_label(encoder_string[encoders[i].top_encoder_function]);
+      g_signal_connect(widget,"button_press_event",G_CALLBACK(encoder_top_cb),GINT_TO_POINTER(i));
+      gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
       col++;
     }
 
-    GtkWidget *enc5_sw=gtk_button_new_with_label(sw_string[e5_sw_action]);
-    gtk_grid_attach(GTK_GRID(grid),enc5_sw,col,row,1,1);
-    g_signal_connect(enc5_sw,"button_press_event",G_CALLBACK(sw_cb),GINT_TO_POINTER(ENC5_SW));
+    if(i!=(max_encoders-1)) {
+      widget=gtk_button_new_with_label(sw_string[encoders[i].switch_function]);
+      g_signal_connect(widget,"button_press_event",G_CALLBACK(encoder_switch_cb),GINT_TO_POINTER(i));
+      gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
+      col++;
+    }
+    
+    row++;
+    col=0;
   }
 
   gtk_container_add(GTK_CONTAINER(content),grid);
index ece8880dca6c0248bdf0712fed57fef2f9673aeb..2c24ce0815bf85277d07856a6c824d1b11315601 100644 (file)
@@ -32,6 +32,7 @@
 #ifdef SOAPYSDR
 #include "soapy_protocol.h"
 #endif
+#include "actions.h"
 #ifdef GPIO
 #include "gpio.h"
 #endif
diff --git a/ext.c b/ext.c
index 7804134b5e4ae1d60f4478aa60ba6d85a0974509..fc57b0b8985a8abf8e9451a37a374f734fa2a62a 100644 (file)
--- a/ext.c
+++ b/ext.c
@@ -159,6 +159,7 @@ int ext_noise_update(void *data) {
 }
 
 int ext_mox_update(void *data) {
+g_print("%s\n",__FUNCTION__);
   mox_update(GPOINTER_TO_INT(data));
   return 0;
 }
@@ -266,6 +267,13 @@ int ext_set_mic_gain(void * data) {
   return 0;
 }
 
+int ext_set_af_gain(void *data) {
+  double d=*(double *)data;
+  set_af_gain(active_receiver->id,d);
+  free(data);
+  return 0;
+}
+
 int ext_set_agc_gain(void *data) {
   double d=*(double *)data;
   set_agc_gain(active_receiver->id,d);
index 3cd5711fa82fd8ec323a349f510b80102c430254..a9beb2d9e29cb2cd29333ca9dbecb9222a166695 100644 (file)
@@ -44,6 +44,7 @@ static void cleanup() {
     gtk_widget_destroy(dialog);
     dialog=NULL;
     sub_menu=NULL;
+    active_menu=NO_MENU;
   }
 }
 
diff --git a/gpio.c b/gpio.c
index 9fb48e12e05cb42618be39f97e7cf1708c5e31c6..73f21fc7e721348e0872fe5f72946b749f05db7e 100644 (file)
--- a/gpio.c
+++ b/gpio.c
@@ -1,5 +1,5 @@
 /* Copyright (C)
-* 2015 - John Melton, G0ORX/N6LYT
+* 2020 - John Melton, G0ORX/N6LYT
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 *
 */
 
+// Rewrite to use gpiod rather than wiringPi
+// Note that all pin numbers are now the Broadcom GPIO
+
+
 #include <gtk/gtk.h>
 
 #include <stdio.h>
 #include <fcntl.h>
 #include <poll.h>
 #include <sched.h>
-#include <wiringPi.h>
-#include <semaphore.h>
+
+#include <gpiod.h>
+#include <linux/i2c-dev.h>
+#include <i2c/smbus.h>
+#include <sys/ioctl.h>
 
 #include "band.h"
 #include "channel.h"
@@ -38,7 +45,6 @@
 #include "filter.h"
 #include "bandstack.h"
 #include "toolbar.h"
-#include "gpio.h"
 #include "radio.h"
 #include "toolbar.h"
 #include "main.h"
@@ -48,6 +54,7 @@
 #include "new_menu.h"
 #include "encoder_menu.h"
 #include "diversity_menu.h"
+#include "actions.h"
 #include "gpio.h"
 #include "i2c.h"
 #include "ext.h"
 #endif
 #include "zoompan.h"
 
-// debounce settle time in ms
-#define DEFAULT_SETTLE_TIME 50
-
-int settle_time=DEFAULT_SETTLE_TIME;
-static gint release_timer=-1;
-
-int controller;
-
-int I2C_INTERRUPT=16;
-
-// uses wiringpi pin numbers
-int ENABLE_VFO_ENCODER;
-int ENABLE_VFO_PULLUP;
-int VFO_ENCODER_A;
-int VFO_ENCODER_B;
-int ENABLE_E2_ENCODER;
-int ENABLE_E2_PULLUP;
-int E2_ENCODER_A;
-int E2_ENCODER_B;
-int ENABLE_E2_TOP_ENCODER;
-int E2_TOP_ENCODER_A;
-int E2_TOP_ENCODER_B;
-int E2_FUNCTION;
-int ENABLE_E3_ENCODER;
-int ENABLE_E3_PULLUP;
-int E3_ENCODER_A;
-int E3_ENCODER_B;
-int ENABLE_E3_TOP_ENCODER;
-int E3_TOP_ENCODER_A;
-int E3_TOP_ENCODER_B;
-int E3_FUNCTION;
-int ENABLE_E4_ENCODER;
-int ENABLE_E4_PULLUP;
-int E4_ENCODER_A;
-int E4_ENCODER_B;
-int ENABLE_E4_TOP_ENCODER;
-int E4_TOP_ENCODER_A;
-int E4_TOP_ENCODER_B;
-int E4_FUNCTION;
-int ENABLE_E5_ENCODER;
-int ENABLE_E5_PULLUP;
-int E5_ENCODER_A;
-int E5_ENCODER_B;
-int ENABLE_E5_TOP_ENCODER;
-int E5_TOP_ENCODER_A;
-int E5_TOP_ENCODER_B;
-int E5_FUNCTION;
-
-int ENABLE_S1_BUTTON;
-int S1_BUTTON;
-int ENABLE_S2_BUTTON;
-int S2_BUTTON;
-int ENABLE_S3_BUTTON;
-int S3_BUTTON;
-int ENABLE_S4_BUTTON;
-int S4_BUTTON;
-int ENABLE_S5_BUTTON;
-int S5_BUTTON;
-int ENABLE_S6_BUTTON;
-int S6_BUTTON;
-int ENABLE_MOX_BUTTON;
-int MOX_BUTTON;
-int ENABLE_FUNCTION_BUTTON;
-int FUNCTION_BUTTON;
-
-#ifdef LOCALCW
-//
-// WiringPi pins #12, 13, 14 are not used
-// by Controller1 and Controller2_V1
-// (and keep #8,9 reserved for I2C extensions)
-//
-int CWL_BUTTON=13;
-int CWR_BUTTON=14;
-int SIDETONE_GPIO=12;
-int ENABLE_GPIO_SIDETONE=0;
-int ENABLE_CW_BUTTONS=1;
-int CW_ACTIVE_LOW=1;
-#endif
-
-#ifdef PTT
-int ENABLE_PTT_GPIO=1;
-int PTT_GPIO=15;
-int PTT_ACTIVE_LOW=1;
-#endif
+enum {
+  TOP_ENCODER,
+  BOTTOM_ENCODER
+};
 
-int vfoEncoderPos;
-int vfoFunction;
-
-int e2EncoderPos;
-int e2_sw_action;
-int e2_encoder_action;
-int e3EncoderPos;
-int e3_sw_action;
-int e3_encoder_action;
-int e4EncoderPos;
-int e4_sw_action;
-int e4_encoder_action;
-int e5EncoderPos;
-int e5_sw_action;
-int e5_encoder_action;
-
-int e2TopEncoderPos;
-int e2_top_encoder_action;
-int e3TopEncoderPos;
-int e3_top_encoder_action;
-int e4TopEncoderPos;
-int e4_top_encoder_action;
-int e5TopEncoderPos;
-int e5_top_encoder_action;
-
-static volatile int function_state;
-static volatile int band_state;
-static volatile int bandstack_state;
-static volatile int mode_state;
-static volatile int filter_state;
-static volatile int noise_state;
-static volatile int agc_state;
-static volatile int mox_state;
-static volatile int lock_state;
-
-static gpointer rotary_encoder_thread(gpointer data);
-static GThread *rotary_encoder_thread_id;
+enum {
+  A,
+  B
+};
 
-static int previous_function_button=0;
-static int band_button=0;
-static int previous_band_button=0;
-static int bandstack_button=0;
-static int previous_bandstack_button=0;
-static int mode_button=0;
-static int previous_mode_button=0;
-static int filter_button=0;
-static int previous_filter_button=0;
-static int noise_button=0;
-static int previous_noise_button=0;
-static int agc_button=0;
-static int previous_agc_button=0;
-static int mox_button=0;
-static int previous_mox_button=0;
+char *consumer="pihpsdr";
+
+char *gpio_device="/dev/gpiochip0";
+
+static struct gpiod_chip *chip=NULL;
+//static struct gpiod_line *line=NULL;
+
+static GMutex encoder_mutex;
+static GThread *monitor_thread_id;
+
+int controller=NO_CONTROLLER;
+
+int I2C_INTERRUPT=15;
+
+#define MAX_LINES 32
+int monitor_lines[MAX_LINES];
+int lines=0;
+
+long settle_time=150;  // ms
+
+// VFO Encoder is always last
+
+ENCODER encoders_no_controller[MAX_ENCODERS]={
+  {FALSE,TRUE,0,0,0,0,0,0,FALSE,TRUE,0,0,0,0,0,0,FALSE,TRUE,0,0},
+  {FALSE,TRUE,0,0,0,0,0,0,FALSE,TRUE,0,0,0,0,0,0,FALSE,TRUE,0,0},
+  {FALSE,TRUE,0,0,0,0,0,0,FALSE,TRUE,0,0,0,0,0,0,FALSE,TRUE,0,0},
+  {FALSE,TRUE,0,0,0,0,0,0,FALSE,TRUE,0,0,0,0,0,0,FALSE,TRUE,0,0},
+  {FALSE,TRUE,0,0,0,0,0,0,FALSE,TRUE,0,0,0,0,0,0,FALSE,TRUE,0,0},
+  };
+
+ENCODER encoders_controller1[MAX_ENCODERS]={
+  {TRUE,TRUE,20,1,26,1,0,ENCODER_AF_GAIN,FALSE,TRUE,0,0,0,0,0,0,TRUE,TRUE,25,MENU_BAND},
+  {TRUE,TRUE,16,1,19,1,0,ENCODER_AGC_GAIN,FALSE,TRUE,0,0,0,0,0,0,TRUE,TRUE,8,MENU_BANDSTACK},
+  {TRUE,TRUE,4,1,21,1,0,ENCODER_DRIVE,FALSE,TRUE,0,0,0,0,0,0,TRUE,TRUE,7,MENU_MODE},
+  {TRUE,TRUE,18,1,17,1,0,ENCODER_VFO,FALSE,TRUE,0,0,0,0,0,0,FALSE,TRUE,0,0},
+  {FALSE,TRUE,0,1,0,0,1,0,FALSE,TRUE,0,0,0,0,0,0,FALSE,TRUE,0,0},
+  };
+
+ENCODER encoders_controller2_v1[MAX_ENCODERS]={
+  {TRUE,TRUE,20,1,26,1,0,ENCODER_AF_GAIN,FALSE,TRUE,0,0,0,0,0,0,TRUE,TRUE,22,MENU_BAND},
+  {TRUE,TRUE,4,1,21,1,0,ENCODER_AGC_GAIN,FALSE,TRUE,0,0,0,0,0,0,TRUE,TRUE,27,MENU_BANDSTACK},
+  {TRUE,TRUE,16,1,19,1,0,ENCODER_IF_WIDTH,FALSE,TRUE,0,0,0,0,0,0,TRUE,TRUE,23,MENU_MODE},
+  {TRUE,TRUE,25,1,8,1,0,ENCODER_RIT,FALSE,TRUE,0,0,0,0,0,0,TRUE,TRUE,24,MENU_FREQUENCY},
+  {TRUE,TRUE,18,1,17,1,0,ENCODER_VFO,FALSE,TRUE,0,0,0,0,0,0,FALSE,TRUE,0,0},
+  };
+
+ENCODER encoders_controller2_v2[MAX_ENCODERS]={
+  {TRUE,TRUE,5,1,6,1,0,ENCODER_RF_GAIN,TRUE,TRUE,26,1,20,1,0,ENCODER_AF_GAIN,TRUE,TRUE,22,MENU_BAND},
+  {TRUE,TRUE,9,1,7,1,0,ENCODER_ATTENUATION,TRUE,TRUE,21,1,4,1,0,ENCODER_AGC_GAIN,TRUE,TRUE,27,MENU_MODE},
+  {TRUE,TRUE,11,1,10,1,0,ENCODER_IF_WIDTH,TRUE,TRUE,19,1,16,1,0,ENCODER_IF_SHIFT,TRUE,TRUE,23,MENU_FILTER},
+  {TRUE,TRUE,13,1,12,1,0,ENCODER_XIT,TRUE,TRUE,8,1,25,1,0,ENCODER_RIT,TRUE,TRUE,24,MENU_FREQUENCY},
+  {TRUE,TRUE,18,1,17,1,0,ENCODER_VFO,FALSE,TRUE,0,0,0,0,0,0,FALSE,TRUE,0,0},
+  };
+
+ENCODER *encoders=encoders_no_controller;
+
+SWITCH switches_no_controller[MAX_SWITCHES]={
+  {FALSE,FALSE,0,NO_ACTION},
+  {FALSE,FALSE,0,NO_ACTION},
+  {FALSE,FALSE,0,NO_ACTION},
+  {FALSE,FALSE,0,NO_ACTION},
+  {FALSE,FALSE,0,NO_ACTION},
+  {FALSE,FALSE,0,NO_ACTION},
+  {FALSE,FALSE,0,NO_ACTION},
+  {FALSE,FALSE,0,NO_ACTION},
+  {FALSE,FALSE,0,NO_ACTION},
+  {FALSE,FALSE,0,NO_ACTION},
+  {FALSE,FALSE,0,NO_ACTION},
+  {FALSE,FALSE,0,NO_ACTION},
+  {FALSE,FALSE,0,NO_ACTION},
+  {FALSE,FALSE,0,NO_ACTION},
+  {FALSE,FALSE,0,NO_ACTION},
+  {FALSE,FALSE,0,NO_ACTION}
+  };
+
+SWITCH switches_controller1[MAX_FUNCTIONS][MAX_SWITCHES]={
+  {{TRUE,TRUE,27,MOX},
+   {TRUE,TRUE,13,MENU_BAND},
+   {TRUE,TRUE,12,MENU_BANDSTACK},
+   {TRUE,TRUE,6,MENU_MODE},
+   {TRUE,TRUE,5,MENU_FILTER},
+   {TRUE,TRUE,24,NR},
+   {TRUE,TRUE,23,AGC},
+   {TRUE,TRUE,22,FUNCTION},
+   {FALSE,FALSE,0,NO_ACTION},
+   {FALSE,FALSE,0,NO_ACTION},
+   {FALSE,FALSE,0,NO_ACTION},
+   {FALSE,FALSE,0,NO_ACTION},
+   {FALSE,FALSE,0,NO_ACTION},
+   {FALSE,FALSE,0,NO_ACTION},
+   {FALSE,FALSE,0,NO_ACTION},
+   {FALSE,FALSE,0,NO_ACTION}},
+  {{TRUE,TRUE,27,MOX},
+   {TRUE,TRUE,13,LOCK},
+   {TRUE,TRUE,12,CTUN},
+   {TRUE,TRUE,6,A_TO_B},
+   {TRUE,TRUE,5,B_TO_A},
+   {TRUE,TRUE,24,A_SWAP_B},
+   {TRUE,TRUE,23,SPLIT},
+   {TRUE,TRUE,22,FUNCTION},
+   {FALSE,FALSE,0,NO_ACTION},
+   {FALSE,FALSE,0,NO_ACTION},
+   {FALSE,FALSE,0,NO_ACTION},
+   {FALSE,FALSE,0,NO_ACTION},
+   {FALSE,FALSE,0,NO_ACTION},
+   {FALSE,FALSE,0,NO_ACTION},
+   {FALSE,FALSE,0,NO_ACTION},
+   {FALSE,FALSE,0,NO_ACTION}},
+  {{TRUE,TRUE,27,MOX},
+   {TRUE,TRUE,13,MENU_FREQUENCY},
+   {TRUE,TRUE,12,MENU_MEMORY},
+   {TRUE,TRUE,6,RIT},
+   {TRUE,TRUE,5,RIT_PLUS},
+   {TRUE,TRUE,24,RIT_MINUS},
+   {TRUE,TRUE,23,RIT_CLEAR},
+   {TRUE,TRUE,22,FUNCTION},
+   {FALSE,FALSE,0,NO_ACTION},
+   {FALSE,FALSE,0,NO_ACTION},
+   {FALSE,FALSE,0,NO_ACTION},
+   {FALSE,FALSE,0,NO_ACTION},
+   {FALSE,FALSE,0,NO_ACTION},
+   {FALSE,FALSE,0,NO_ACTION},
+   {FALSE,FALSE,0,NO_ACTION},
+   {FALSE,FALSE,0,NO_ACTION}},
+  {{TRUE,TRUE,27,MOX},
+   {TRUE,TRUE,13,MENU_FREQUENCY},
+   {TRUE,TRUE,12,MENU_MEMORY},
+   {TRUE,TRUE,6,XIT},
+   {TRUE,TRUE,5,XIT_PLUS},
+   {TRUE,TRUE,24,XIT_MINUS},
+   {TRUE,TRUE,23,XIT_CLEAR},
+   {TRUE,TRUE,22,FUNCTION},
+   {FALSE,FALSE,0,NO_ACTION},
+   {FALSE,FALSE,0,NO_ACTION},
+   {FALSE,FALSE,0,NO_ACTION},
+   {FALSE,FALSE,0,NO_ACTION},
+   {FALSE,FALSE,0,NO_ACTION},
+   {FALSE,FALSE,0,NO_ACTION},
+   {FALSE,FALSE,0,NO_ACTION},
+   {FALSE,FALSE,0,NO_ACTION}},
+  {{TRUE,TRUE,27,MOX},
+   {TRUE,TRUE,13,MENU_FREQUENCY},
+   {TRUE,TRUE,12,SPLIT},
+   {TRUE,TRUE,6,DUPLEX},
+   {TRUE,TRUE,5,SAT},
+   {TRUE,TRUE,24,RSAT},
+   {TRUE,TRUE,23,NO_ACTION},
+   {TRUE,TRUE,22,FUNCTION},
+   {FALSE,FALSE,0,NO_ACTION},
+   {FALSE,FALSE,0,NO_ACTION},
+   {FALSE,FALSE,0,NO_ACTION},
+   {FALSE,FALSE,0,NO_ACTION},
+   {FALSE,FALSE,0,NO_ACTION},
+   {FALSE,FALSE,0,NO_ACTION},
+   {FALSE,FALSE,0,NO_ACTION},
+   {FALSE,FALSE,0,NO_ACTION}},
+  {{TRUE,TRUE,27,MOX},
+   {TRUE,TRUE,13,TUNE},
+   {TRUE,TRUE,12,TUNE_FULL},
+   {TRUE,TRUE,6,TUNE_MEMORY},
+   {TRUE,TRUE,5,MENU_BAND},
+   {TRUE,TRUE,24,MENU_MODE},
+   {TRUE,TRUE,23,MENU_FILTER},
+   {TRUE,TRUE,22,FUNCTION},
+   {FALSE,FALSE,0,NO_ACTION},
+   {FALSE,FALSE,0,NO_ACTION},
+   {FALSE,FALSE,0,NO_ACTION},
+   {FALSE,FALSE,0,NO_ACTION},
+   {FALSE,FALSE,0,NO_ACTION},
+   {FALSE,FALSE,0,NO_ACTION},
+   {FALSE,FALSE,0,NO_ACTION},
+   {FALSE,FALSE,0,NO_ACTION}},
+
+  };
+
+SWITCH switches_controller2_v1[MAX_SWITCHES]={
+  {FALSE,FALSE,0,MOX},
+  {FALSE,FALSE,0,TUNE},
+  {FALSE,FALSE,0,PS},
+  {FALSE,FALSE,0,TWO_TONE},
+  {FALSE,FALSE,0,NR},
+  {FALSE,FALSE,0,A_TO_B},
+  {FALSE,FALSE,0,B_TO_A},
+  {FALSE,FALSE,0,MODE_MINUS},
+  {FALSE,FALSE,0,BAND_MINUS},
+  {FALSE,FALSE,0,MODE_PLUS},
+  {FALSE,FALSE,0,BAND_PLUS},
+  {FALSE,FALSE,0,XIT},
+  {FALSE,FALSE,0,NB},
+  {FALSE,FALSE,0,SNB},
+  {FALSE,FALSE,0,LOCK},
+  {FALSE,FALSE,0,CTUN}
+  };
+
+SWITCH switches_controller2_v2[MAX_SWITCHES]={
+  {FALSE,FALSE,0,MOX},
+  {FALSE,FALSE,0,TUNE},
+  {FALSE,FALSE,0,PS},
+  {FALSE,FALSE,0,TWO_TONE},
+  {FALSE,FALSE,0,NR},
+  {FALSE,FALSE,0,A_TO_B},
+  {FALSE,FALSE,0,B_TO_A},
+  {FALSE,FALSE,0,MODE_MINUS},
+  {FALSE,FALSE,0,BAND_MINUS},
+  {FALSE,FALSE,0,MODE_PLUS},
+  {FALSE,FALSE,0,BAND_PLUS},
+  {FALSE,FALSE,0,XIT},
+  {FALSE,FALSE,0,NB},
+  {FALSE,FALSE,0,SNB},
+  {FALSE,FALSE,0,LOCK},
+  {FALSE,FALSE,0,CTUN}
+  };
+
+SWITCH *switches=switches_no_controller;
 
 static int running=0;
 
+/*
 char *encoder_string[ENCODER_ACTIONS] = {
   "NO ACTION",
   "AF GAIN",
@@ -239,6 +333,7 @@ char *encoder_string[ENCODER_ACTIONS] = {
   "SQUELCH RX1",
   "SQUELCH RX2",
   "TUNE DRIVE",
+  "VFO",
   "WATERFALL HIGH",
   "WATERFALL LOW",
   "XIT",
@@ -246,7 +341,7 @@ char *encoder_string[ENCODER_ACTIONS] = {
 };
 
 char *sw_string[SWITCH_ACTIONS] = {
-  "",
+  "NO ACTION",
   "A TO B",
   "A SWAP B",
   "AGC",
@@ -258,10 +353,12 @@ char *sw_string[SWITCH_ACTIONS] = {
   "BSTACK +",
   "CTUN",
   "DIV",
+  "DUPLEX",
   "FILTER -",
   "FILTER +",
   "FUNCTION",
   "LOCK",
+  "MENU AGC",
   "MENU BAND",
   "MENU BSTACK",
   "MENU DIV",
@@ -269,6 +366,7 @@ char *sw_string[SWITCH_ACTIONS] = {
   "MENU FREQUENCY",
   "MENU MEMORY",
   "MENU MODE",
+  "MENU NOISE",
   "MENU PS",
   "MODE -",
   "MODE +",
@@ -281,2089 +379,671 @@ char *sw_string[SWITCH_ACTIONS] = {
   "PS",
   "RIT",
   "RIT CL",
+  "RIT +",
+  "RIT -",
+  "RSAT",
   "SAT",
   "SNB",
   "SPLIT",
   "TUNE",
+  "TUNE FULL",
+  "TUNE MEM",
   "TWO TONE",
   "XIT",
   "XIT CL",
+  "XIT +",
+  "XIT -",
   "ZOOM -",
   "ZOOM +",
 };
 
-int *sw_action=NULL;
-
-static int mox_pressed(void *data) {
-  if(running) sim_mox_cb(NULL,NULL);
-  return 0;
-}
-
-static int s1_pressed(void *data) {
-  if(running) sim_s1_pressed_cb(NULL,NULL);
-  return 0;
-}
-
-static int s1_released(void *data) {
-  if(running) sim_s1_released_cb(NULL,NULL);
-  return 0;
-}
-
-static int s2_pressed(void *data) {
-  if(running) sim_s2_pressed_cb(NULL,NULL);
-  return 0;
-}
-
-static int s2_released(void *data) {
-  if(running) sim_s2_released_cb(NULL,NULL);
-  return 0;
-}
-
-static int s3_pressed(void *data) {
-  if(running) sim_s3_pressed_cb(NULL,NULL);
-  return 0;
-}
-
-static int s3_released(void *data) {
-  if(running) sim_s3_released_cb(NULL,NULL);
-  return 0;
-}
+char *sw_cap_string[SWITCH_ACTIONS] = {
+  "",
+  "A>B",
+  "A<>B",
+  "AGC",
+  "ANF",
+  "B>A",
+  "BND-",
+  "BND+",
+  "BST-",
+  "BST+",
+  "CTUN",
+  "DIV",
+  "DUP",
+  "FLT-",
+  "FLT+",
+  "FUNC",
+  "LOCK",
+  "AGC",
+  "BAND",
+  "BSTACK",
+  "DIV",
+  "FILTER",
+  "FREQ",
+  "MEM",
+  "MODE",
+  "NOISE",
+  "PS",
+  "MD-",
+  "MD+",
+  "MOX",
+  "MUTE",
+  "NB",
+  "NR",
+  "PAN-",
+  "PAN+",
+  "PS",
+  "RIT",
+  "RIT0",
+  "RIT+",
+  "RIT-",
+  "RSAT",
+  "SAT",
+  "SNB",
+  "SPLIT",
+  "TUNE",
+  "TUN-F",
+  "TUN-M",
+  "2TONE",
+  "XIT",
+  "XIT0",
+  "XIT+",
+  "XIT-",
+  "ZOOM-",
+  "ZOOM+",
+};
+*/
 
-static int s4_pressed(void *data) {
-  if(running) sim_s4_pressed_cb(NULL,NULL);
-  return 0;
-}
+int *sw_action=NULL;
 
-static int s4_released(void *data) {
-  if(running) sim_s4_released_cb(NULL,NULL);
-  return 0;
-}
+static GThread *rotary_encoder_thread_id;
 
-static int s5_pressed(void *data) {
-  if(running) sim_s5_pressed_cb(NULL,NULL);
-  return 0;
-}
+static uint64_t epochMilli;
 
-static int s5_released(void *data) {
-  if(running) sim_s5_released_cb(NULL,NULL);
-  return 0;
-}
+static void initialiseEpoch() {
+  struct timespec ts ;
 
-static int s6_pressed(void *data) {
-  if(running) sim_s6_pressed_cb(NULL,NULL);
-  return 0;
+  clock_gettime (CLOCK_MONOTONIC_RAW, &ts) ;
+  epochMilli = (uint64_t)ts.tv_sec * (uint64_t)1000    + (uint64_t)(ts.tv_nsec / 1000000L) ;
 }
 
-static int s6_released(void *data) {
-  if(running) sim_s6_released_cb(NULL,NULL);
-  return 0;
+static unsigned int millis () {
+  uint64_t now ;
+  struct  timespec ts ;
+  clock_gettime (CLOCK_MONOTONIC_RAW, &ts) ;
+  now  = (uint64_t)ts.tv_sec * (uint64_t)1000 + (uint64_t)(ts.tv_nsec / 1000000L) ;
+  return (uint32_t)(now - epochMilli) ;
 }
 
-static int function_pressed(void *data) {
-  if(running) sim_function_cb(NULL,NULL);
-  return 0;
-}
+static gpointer rotary_encoder_thread(gpointer data) {
+  ENCODER_ACTION *a;
+  int i;
 
-static int vfo_function_pressed(void *data) {
-  RECEIVER *rx;
-  if(receivers==2) {
-    if(active_receiver==receiver[0]) {
-      rx=receiver[1];
-    } else {
-      rx=receiver[0];
+  sleep(2);
+  while(TRUE) {
+    g_mutex_lock(&encoder_mutex);
+    for(i=0;i<MAX_ENCODERS;i++) {
+      if(encoders[i].bottom_encoder_enabled && encoders[i].bottom_encoder_pos!=0) {
+        a=g_new(ENCODER_ACTION,1);
+        a->action=encoders[i].bottom_encoder_function;
+        a->mode=RELATIVE;
+        a->val=encoders[i].bottom_encoder_pos;
+        g_idle_add(encoder_action,a);
+        encoders[i].bottom_encoder_pos=0;
+      }
+      if(encoders[i].top_encoder_enabled && encoders[i].top_encoder_pos!=0) {
+        a=g_new(ENCODER_ACTION,1);
+        a->action=encoders[i].bottom_encoder_function;
+        a->mode=RELATIVE;
+        a->val=encoders[i].bottom_encoder_pos;
+        g_idle_add(encoder_action,a);
+        encoders[i].top_encoder_pos=0;
+      }
     }
-    active_receiver=rx;
-    g_idle_add(menu_active_receiver_changed,NULL);
-    g_idle_add(ext_vfo_update,NULL);
-    g_idle_add(sliders_active_receiver_changed,NULL);
+    g_mutex_unlock(&encoder_mutex);
+    usleep(100000); // sleep for 100ms
   }
-  return 0;
-}
-
-static int vfo_function_released(void *data) {
-  return 0;
 }
 
-#ifdef PTT
-static int ptt_pressed(void *data) {
-g_print("ptt_pressed\n");
-  if(can_transmit) g_idle_add(ext_mox_update,GINT_TO_POINTER(1));
-  return 0;
-}
-
-static int ptt_released(void *data) {
-g_print("ptt_released\n");
-  if(can_transmit) g_idle_add(ext_mox_update,GINT_TO_POINTER(0));
+int process_function_switch(void *data) {
+  function++;
+  if(function>=MAX_FUNCTIONS) {
+    function=0;
+  }
+  switches=switches_controller1[function];
+  update_toolbar_labels();
   return 0;
 }
-#endif
 
-static int e_function_pressed(void *data) {
-  int action=(int)data;
-g_print("e_function_pressed: %d\n",action);
-  switch(action) {
-    case TUNE:
-      if(can_transmit) g_idle_add(ext_tune_update,NULL);
-      break;
-    case MOX:
-      if(can_transmit) g_idle_add(ext_mox_update,NULL);
-      break;
-    case PS:
-#ifdef PURESIGNAL
-      if(can_transmit) g_idle_add(ext_ps_update,NULL);
-#endif
-      break;
-    case TWO_TONE:
-      if(can_transmit) g_idle_add(ext_two_tone,NULL);
-      break;
-    case NR:
-      g_idle_add(ext_nr_update,NULL);
-      break;
-    case NB:
-      g_idle_add(ext_nb_update,NULL);
-      break;
-    case SNB:
-      g_idle_add(ext_snb_update,NULL);
-      break;
-    case RIT:
-      g_idle_add(ext_rit_update,NULL);
-      break;
-    case RIT_CLEAR:
-      g_idle_add(ext_rit_clear,NULL);
-      break;
-    case XIT:
-      if(can_transmit) g_idle_add(ext_xit_update,NULL);
-      break;
-    case XIT_CLEAR:
-      if(can_transmit) g_idle_add(ext_xit_clear,NULL);
-      break;
-    case BAND_PLUS:
-      g_idle_add(ext_band_plus,NULL);
-      break;
-    case BAND_MINUS:
-      g_idle_add(ext_band_minus,NULL);
-      break;
-    case BANDSTACK_PLUS:
-      g_idle_add(ext_bandstack_plus,NULL);
-      break;
-    case BANDSTACK_MINUS:
-      g_idle_add(ext_bandstack_minus,NULL);
-      break;
-    case MODE_PLUS:
-      g_idle_add(ext_mode_plus,NULL);
-      break;
-    case MODE_MINUS:
-      g_idle_add(ext_mode_minus,NULL);
-      break;
-    case FILTER_PLUS:
-      g_idle_add(ext_filter_plus,NULL);
-      break;
-    case FILTER_MINUS:
-      g_idle_add(ext_filter_minus,NULL);
-      break;
-    case A_TO_B:
-      g_idle_add(ext_vfo_a_to_b,NULL);
-      break;
-    case B_TO_A:
-      g_idle_add(ext_vfo_b_to_a,NULL);
-      break;
-    case A_SWAP_B:
-      g_idle_add(ext_vfo_a_swap_b,NULL);
-      break;
-    case LOCK:
-      g_idle_add(ext_lock_update,NULL);
-      break;
-    case CTUN:
-      g_idle_add(ext_ctun_update,NULL);
-      break;
-    case AGC:
-      g_idle_add(ext_agc_update,NULL);
-      break;
-    case SPLIT:
-      if(can_transmit) g_idle_add(ext_split_toggle,NULL);
-      break;
-    case DIVERSITY:
-      g_idle_add(ext_diversity_update,GINT_TO_POINTER(0));
-      break;
-    case SAT:
-      if(can_transmit) g_idle_add(ext_sat_update,NULL);
-      break;
-    case MENU_BAND:
-      g_idle_add(ext_band_update,NULL);
-      break;
-    case MENU_BANDSTACK:
-      g_idle_add(ext_bandstack_update,NULL);
-      break;
-    case MENU_MODE:
-      g_idle_add(ext_mode_update,NULL);
-      break;
-    case MENU_FILTER:
-      g_idle_add(ext_filter_update,NULL);
-      break;
-    case MENU_FREQUENCY:
-      g_idle_add(ext_frequency_update,NULL);
+static unsigned long switch_debounce;
+
+static void process_encoder(int e,int l,int addr,int val) {
+//  g_print("%s: encoder=%d level=%d addr=0x%02X val=%d\n",__FUNCTION__,e,l,addr,val);
+  g_mutex_lock(&encoder_mutex);
+  switch(l) {
+    case BOTTOM_ENCODER:
+      switch(addr) {
+        case A:
+          encoders[e].bottom_encoder_a_value=val;
+          if(encoders[e].bottom_encoder_a_value==encoders[e].bottom_encoder_b_value) {
+            encoders[e].bottom_encoder_pos++;
+          } else {
+            encoders[e].bottom_encoder_pos--;
+          }
+          //g_print("%s: %s BOTTOM pos=%d\n",__FUNCTION__,encoder_string[encoders[e].bottom_encoder_function],encoders[e].bottom_encoder_pos);
+          break;
+        case B:
+          encoders[e].bottom_encoder_b_value=val;
+          break;
+      }
       break;
-    case MENU_MEMORY:
-      g_idle_add(ext_memory_update,NULL);
+    case TOP_ENCODER:
+      switch(addr) {
+        case A:
+          encoders[e].top_encoder_a_value=val;
+          if(encoders[e].top_encoder_a_value==encoders[e].top_encoder_b_value) {
+            encoders[e].top_encoder_pos++;
+          } else {
+            encoders[e].top_encoder_pos--;
+          }
+          g_print("%s: %s TOP pos=%d\n",__FUNCTION__,encoder_string[encoders[e].top_encoder_function],encoders[e].bottom_encoder_pos);
+          break;
+        case B:
+          encoders[e].top_encoder_b_value=val;
+          break;
+      }
       break;
-    case MENU_DIVERSITY:
-      g_idle_add(ext_diversity_update,GINT_TO_POINTER(1));
+  }
+  g_mutex_unlock(&encoder_mutex);
+}
+
+static void process_edge(int offset,int value) {
+  gint i;
+  gint t;
+  gboolean found;
+  // check encoders
+  found=FALSE;
+  for(i=0;i<MAX_ENCODERS;i++) {
+    if(encoders[i].bottom_encoder_enabled && encoders[i].bottom_encoder_address_a==offset) {
+      //g_print("%s: found %d encoder %d bottom A\n",__FUNCTION__,offset,i);
+      process_encoder(i,BOTTOM_ENCODER,A,value);
+      found=TRUE;
+      break;
+    } else if(encoders[i].bottom_encoder_enabled && encoders[i].bottom_encoder_address_b==offset) {
+      //g_print("%s: found %d encoder %d bottom B\n",__FUNCTION__,offset,i);
+      process_encoder(i,BOTTOM_ENCODER,B,value);
+      found=TRUE;
+      break;
+    } else if(encoders[i].top_encoder_enabled && encoders[i].top_encoder_address_a==offset) {
+      //g_print("%s: found %d encoder %d top A\n",__FUNCTION__,offset,i);
+      process_encoder(i,TOP_ENCODER,A,value);
+      found=TRUE;
+      break;
+    } else if(encoders[i].top_encoder_enabled && encoders[i].top_encoder_address_b==offset) {
+      //g_print("%s: found %d encoder %d top B\n",__FUNCTION__,offset,i);
+      process_encoder(i,TOP_ENCODER,B,value);
+      found=TRUE;
+      break;
+    } else if(encoders[i].switch_enabled && encoders[i].switch_address==offset) {
+      g_print("%s: found %d encoder %d switch\n",__FUNCTION__,offset,i);
+      SWITCH_ACTION *a=g_new(SWITCH_ACTION,1);
+      a->action=encoders[i].switch_function;
+      a->state=value;
+      g_idle_add(switch_action,a);
+      found=TRUE;
       break;
-#ifdef PURESIGNAL
-    case MENU_PS:
-      g_idle_add(ext_start_ps,NULL);
+    }
+  }
+
+  if(!found) {
+    for(i=0;i<MAX_SWITCHES;i++) {
+      if(switches[i].switch_enabled && switches[i].switch_address==offset) {
+        t=millis();
+        g_print("%s: found %d switch %d value=%d t=%d\n",__FUNCTION__,offset,i,value,t);
+        found=TRUE;
+        if(t<switch_debounce) {
+          return;
+        }
+        switch_debounce=t+settle_time;
+        SWITCH_ACTION *a=g_new(SWITCH_ACTION,1);
+        a->action=switches[i].switch_function;
+        a->state=value;
+        g_idle_add(switch_action,a);
+        break;
+      }
+    }
+  }
+  if(!found) {
+    g_print("%s: could not find %d\n",__FUNCTION__,offset);
+  }
+}
+
+static int interrupt_cb(int event_type, unsigned int line, const struct timespec *timeout, void* data) {
+  //g_print("%s: event=%d line=%d\n",__FUNCTION__,event_type,line);
+  switch(event_type) {
+    case GPIOD_CTXLESS_EVENT_CB_TIMEOUT:
+      // timeout - ignore
+      //g_print("%s: Ignore timeout\n",__FUNCTION__);
       break;
-#endif
-    case FUNCTION:
-      g_idle_add(ext_function_update,NULL);
+    case GPIOD_CTXLESS_EVENT_CB_RISING_EDGE:
+      //g_print("%s: Ignore RISING EDGE\n",__FUNCTION__);
+      process_edge(line,RELEASED);
       break;
-    case MUTE:
-      g_idle_add(ext_mute_update,NULL);
+    case GPIOD_CTXLESS_EVENT_CB_FALLING_EDGE:
+      //g_print("%s: Process FALLING EDGE\n",__FUNCTION__);
+      process_edge(line,PRESSED);
       break;
-    case PAN_MINUS:
-      g_idle_add(ext_pan_update,GINT_TO_POINTER(-100));
+  }
+  return GPIOD_CTXLESS_EVENT_CB_RET_OK;
+}
+
+void gpio_set_defaults(int ctrlr) {
+  int i;
+  g_print("%s: %d\n",__FUNCTION__,ctrlr);
+  switch(ctrlr) {
+    case NO_CONTROLLER:
+      encoders=encoders_no_controller;
+      switches=switches_no_controller;
       break;
-    case PAN_PLUS:
-      g_idle_add(ext_pan_update,GINT_TO_POINTER(100));
+    case CONTROLLER1:
+      encoders=encoders_controller1;
+      switches=switches_controller1[0];
       break;
-    case ZOOM_MINUS:
-      g_idle_add(ext_zoom_update,GINT_TO_POINTER(-1));
+    case CONTROLLER2_V1:
+      encoders=encoders_controller2_v1;
+      switches=switches_controller2_v1;
       break;
-    case ZOOM_PLUS:
-      g_idle_add(ext_zoom_update,GINT_TO_POINTER(1));
+    case CONTROLLER2_V2:
+      encoders=encoders_controller2_v2;
+      switches=switches_controller2_v2;
       break;
   }
-  return 0;
 }
 
-static unsigned long e2debounce=0;
+void gpio_restore_state() {
+  char* value;
+  char name[80];
 
-static void e2FunctionAlert() {
-    int level=digitalRead(E2_FUNCTION);
-    if(level==0) {
-      if(running) g_idle_add(e_function_pressed,(gpointer)e2_sw_action);
-    }
-}
+  loadProperties("gpio.props");
+  controller=NO_CONTROLLER;
+  value=getProperty("controller");
+  if(value) controller=atoi(value);
+  gpio_set_defaults(controller);
 
-static unsigned long e3debounce=0;
+  for(int i=0;i<MAX_ENCODERS;i++) {
+    sprintf(name,"encoders[%d].bottom_encoder_enabled",i);
+    value=getProperty(name);
+    if(value) encoders[i].bottom_encoder_enabled=atoi(value);
+    sprintf(name,"encoders[%d].bottom_encoder_pullup",i);
+    value=getProperty(name);
+    if(value) encoders[i].bottom_encoder_pullup=atoi(value);
+    sprintf(name,"encoders[%d].bottom_encoder_address_a",i);
+    value=getProperty(name);
+    if(value) encoders[i].bottom_encoder_address_a=atoi(value);
+    sprintf(name,"encoders[%d].bottom_encoder_address_b",i);
+    value=getProperty(name);
+    if(value) encoders[i].bottom_encoder_address_b=atoi(value);
+    sprintf(name,"encoders[%d].bottom_encoder_address_b",i);
+    value=getProperty(name);
+    sprintf(name,"encoders[%d].top_encoder_enabled",i);
+    value=getProperty(name);
+    if(value) encoders[i].top_encoder_enabled=atoi(value);
+    sprintf(name,"encoders[%d].top_encoder_pullup",i);
+    value=getProperty(name);
+    if(value) encoders[i].top_encoder_pullup=atoi(value);
+    sprintf(name,"encoders[%d].top_encoder_address_a",i);
+    value=getProperty(name);
+    if(value) encoders[i].top_encoder_address_a=atoi(value);
+    sprintf(name,"encoders[%d].top_encoder_address_b",i);
+    value=getProperty(name);
+    if(value) encoders[i].top_encoder_address_b=atoi(value);
+    sprintf(name,"encoders[%d].switch_enabled",i);
+    value=getProperty(name);
+    if(value) encoders[i].switch_enabled=atoi(value);
+    sprintf(name,"encoders[%d].switch_pullup",i);
+    value=getProperty(name);
+    if(value) encoders[i].switch_pullup=atoi(value);
+    sprintf(name,"encoders[%d].switch_address",i);
+    value=getProperty(name);
+    if(value) encoders[i].switch_address=atoi(value);
+  }
 
-static void e3FunctionAlert() {
-    int level=digitalRead(E3_FUNCTION);
-    if(level==0) {
-      if(running) g_idle_add(e_function_pressed,(gpointer)e3_sw_action);
+  if(controller==CONTROLLER1) {
+    for(int f=0;f<MAX_FUNCTIONS;f++) {
+      for(int i=0;i<MAX_SWITCHES;i++) {
+        sprintf(name,"switches[%d,%d].switch_enabled",f,i);
+        value=getProperty(name);
+        if(value) switches_controller1[f][i].switch_enabled=atoi(value);
+        sprintf(name,"switches[%d,%d].switch_pullup",f,i);
+        value=getProperty(name);
+        if(value) switches_controller1[f][i].switch_pullup=atoi(value);
+        sprintf(name,"switches[%d,%d].switch_address",f,i);
+        value=getProperty(name);
+        if(value) switches_controller1[f][i].switch_address=atoi(value);
+      }
     }
-}
-
-static unsigned long e4debounce=0;
-
-static void e4FunctionAlert() {
-    int level=digitalRead(E4_FUNCTION);
-    if(level==0) {
-      if(running) g_idle_add(e_function_pressed,(gpointer)e4_sw_action);
+  } else {
+    for(int i=0;i<MAX_SWITCHES;i++) {
+      sprintf(name,"switches[%d].switch_enabled",i);
+      value=getProperty(name);
+      if(value) switches[i].switch_enabled=atoi(value);
+      sprintf(name,"switches[%d].switch_pullup",i);
+      value=getProperty(name);
+      if(value) switches[i].switch_pullup=atoi(value);
+      sprintf(name,"switches[%d].switch_address",i);
+      value=getProperty(name);
+      if(value) switches[i].switch_address=atoi(value);
     }
-}
-
-static unsigned long e5debounce=0;
+  }
 
-static void e5FunctionAlert() {
-    int level=digitalRead(E5_FUNCTION);
-    if(level==0) {
-      if(running) g_idle_add(e_function_pressed,(gpointer)e5_sw_action);
-    }
 }
 
-static int function_level=1;
-static unsigned long function_debounce=0;
+void gpio_save_state() {
+  char value[80];
+  char name[80];
 
-static void functionAlert() {
-    int t=millis();
-    if(millis()<function_debounce) {
-      return;
-    }
-    int level=digitalRead(FUNCTION_BUTTON);
-    if(level!=function_level) {
-      if(level==0) {
-        if(running) g_idle_add(function_pressed,NULL);
-      }
-      function_level=level;
-      function_debounce=t+settle_time;
-    }
-}
+  clearProperties();
+  sprintf(value,"%d",controller);
+  setProperty("controller",value);
 
-static int s1_level=1;
-static unsigned long s1_debounce=0;
+  for(int i=0;i<MAX_ENCODERS;i++) {
+    sprintf(name,"encoders[%d].bottom_encoder_enabled",i);
+    sprintf(value,"%d",encoders[i].bottom_encoder_enabled);
+    setProperty(name,value);
+    sprintf(name,"encoders[%d].bottom_encoder_pullup",i);
+    sprintf(value,"%d",encoders[i].bottom_encoder_pullup);
+    setProperty(name,value);
+    sprintf(name,"encoders[%d].bottom_encoder_address_a",i);
+    sprintf(value,"%d",encoders[i].bottom_encoder_address_a);
+    setProperty(name,value);
+    sprintf(name,"encoders[%d].bottom_encoder_address_b",i);
+    sprintf(value,"%d",encoders[i].bottom_encoder_address_b);
+    setProperty(name,value);
+    sprintf(name,"encoders[%d].bottom_encoder_address_b",i);
+    sprintf(value,"%d",encoders[i].bottom_encoder_address_b);
+    setProperty(name,value);
+    sprintf(name,"encoders[%d].top_encoder_enabled",i);
+    sprintf(value,"%d",encoders[i].top_encoder_enabled);
+    setProperty(name,value);
+    sprintf(name,"encoders[%d].top_encoder_pullup",i);
+    sprintf(value,"%d",encoders[i].top_encoder_pullup);
+    setProperty(name,value);
+    sprintf(name,"encoders[%d].top_encoder_address_a",i);
+    sprintf(value,"%d",encoders[i].top_encoder_address_a);
+    setProperty(name,value);
+    sprintf(name,"encoders[%d].top_encoder_address_b",i);
+    sprintf(value,"%d",encoders[i].top_encoder_address_b);
+    setProperty(name,value);
+    sprintf(name,"encoders[%d].top_encoder_address_b",i);
+    sprintf(value,"%d",encoders[i].top_encoder_address_b);
+    setProperty(name,value);
+    sprintf(name,"encoders[%d].switch_enabled",i);
+    sprintf(value,"%d",encoders[i].switch_enabled);
+    setProperty(name,value);
+    sprintf(name,"encoders[%d].switch_pullup",i);
+    sprintf(value,"%d",encoders[i].switch_pullup);
+    setProperty(name,value);
+    sprintf(name,"encoders[%d].switch_address",i);
+    sprintf(value,"%d",encoders[i].switch_address);
+    setProperty(name,value);
+  }
 
-static void s1Alert() {
-    int t=millis();
-    if(millis()<s1_debounce) {
-      return;
-    }
-    int level=digitalRead(S1_BUTTON);
-    if(level!=s1_level) {
-      if(level==0) {
-        if(running) g_idle_add(s1_pressed,NULL);
-      } else {
-        if(running) g_idle_add(s1_released,NULL);
+  if(controller==CONTROLLER1) {
+    for(int f=0;f<MAX_FUNCTIONS;f++) {
+      for(int i=0;i<MAX_SWITCHES;i++) {
+        sprintf(name,"switches[%d,%d].switch_enabled",f,i);
+        sprintf(value,"%d",switches_controller1[f][i].switch_enabled);
+        setProperty(name,value);
+        sprintf(name,"switches[%d,%d].switch_pullup",f,i);
+        sprintf(value,"%d",switches_controller1[f][i].switch_pullup);
+        setProperty(name,value);
+        sprintf(name,"switches[%d,%d].switch_address",f,i);
+        sprintf(value,"%d",switches_controller1[f][i].switch_address);
+        setProperty(name,value);
       }
-      s1_level=level;
-      s1_debounce=t+settle_time;
     }
+  } else {
+    for(int i=0;i<MAX_SWITCHES;i++) {
+      sprintf(name,"switches[%d].switch_enabled",i);
+      sprintf(value,"%d",switches[i].switch_enabled);
+      setProperty(name,value);
+      sprintf(name,"switches[%d].switch_pullup",i);
+      sprintf(value,"%d",switches[i].switch_pullup);
+      setProperty(name,value);
+      sprintf(name,"switches[%d].switch_address",i);
+      sprintf(value,"%d",switches[i].switch_address);
+      setProperty(name,value);
+    }
+  }
+
+  saveProperties("gpio.props");
 }
 
-static int s2_level=1;
-static unsigned long s2_debounce=0;
+void gpio_restore_actions() {
+  char name[80];
+  char *value;
+  for(int i=0;i<MAX_ENCODERS;i++) {
+    sprintf(name,"encoders[%d].bottom_encoder_function",i);
+    value=getProperty(name);
+    if(value) encoders[i].bottom_encoder_function=atoi(value);
+    sprintf(name,"encoders[%d].top_encoder_function",i);
+    value=getProperty(name);
+    if(value) encoders[i].top_encoder_function=atoi(value);
+    sprintf(name,"encoders[%d].switch_function",i);
+    value=getProperty(name);
+    if(value) encoders[i].switch_function=atoi(value);
+  }
 
-static void s2Alert() {
-    int t=millis();
-    if(millis()<s2_debounce) {
-      return;
-    }
-    int level=digitalRead(S2_BUTTON);
-    if(level!=s2_level) {
-      if(level==0) {
-        if(running) g_idle_add(s2_pressed,NULL);
-      } else {
-        if(running) g_idle_add(s2_released,NULL);
+  if(controller==CONTROLLER1) {
+    for(int f=0;f<MAX_FUNCTIONS;f++) {
+      for(int i=0;i<MAX_SWITCHES;i++) {
+        sprintf(name,"switches[%d,%d].switch_function",f,i);
+        value=getProperty(name);
+        if(value) switches_controller1[f][i].switch_function=atoi(value);
       }
-      s2_level=level;
-      s2_debounce=t+settle_time;
     }
+  } else {
+    for(int i=0;i<MAX_SWITCHES;i++) {
+      sprintf(name,"switches[%d].switch_function",i);
+      value=getProperty(name);
+      if(value) switches[i].switch_function=atoi(value);
+    }
+  }
 }
 
-static int s3_level=1;
-static unsigned long s3_debounce=0;
+void gpio_save_actions() {
+  char value[80];
+  char name[80];
+  for(int i=0;i<MAX_ENCODERS;i++) {
+    sprintf(name,"encoders[%d].bottom_encoder_function",i);
+    sprintf(value,"%d",encoders[i].bottom_encoder_function);
+    setProperty(name,value);
+    sprintf(name,"encoders[%d].top_encoder_function",i);
+    sprintf(value,"%d",encoders[i].top_encoder_function);
+    setProperty(name,value);
+    sprintf(name,"encoders[%d].switch_function",i);
+    sprintf(value,"%d",encoders[i].switch_function);
+    setProperty(name,value);
+  }
 
-static void s3Alert() {
-    int t=millis();
-    if(millis()<s3_debounce) {
-      return;
-    }
-    int level=digitalRead(S3_BUTTON);
-    if(level!=s3_level) {
-      if(level==0) {
-        if(running) g_idle_add(s3_pressed,NULL);
-      } else {
-        if(running) g_idle_add(s3_released,NULL);
+  if(controller==CONTROLLER1) {
+    for(int f=0;f<MAX_FUNCTIONS;f++) {
+      for(int i=0;i<MAX_SWITCHES;i++) {
+        sprintf(name,"switches[%d,%d].switch_function",f,i);
+        sprintf(value,"%d",switches_controller1[f][i].switch_function);
+        setProperty(name,value);
       }
-      s3_level=level;
-      s3_debounce=t+settle_time;
     }
+  } else {
+    for(int i=0;i<MAX_SWITCHES;i++) {
+      sprintf(name,"switches[%d].switch_function",i);
+      sprintf(value,"%d",switches[i].switch_function);
+      setProperty(name,value);
+    }
+  }
 }
 
-static int s4_level=1;
-static unsigned long s4_debounce=0;
+static gpointer monitor_thread(gpointer arg) {
+  struct timespec t;
 
-static void s4Alert() {
-    int t=millis();
-    if(millis()<s4_debounce) {
-      return;
-    }
-    int level=digitalRead(S4_BUTTON);
-    if(level!=s4_level) {
-      if(level==0) {
-        if(running) g_idle_add(s4_pressed,NULL);
-      } else {
-        if(running) g_idle_add(s4_released,NULL);
-      }
-      s4_level=level;
-      s4_debounce=t+settle_time;
-    }
+  // thread to monitor gpio events
+  g_print("%s: start event monitor lines=%d\n",__FUNCTION__,lines);
+  g_print("%s:",__FUNCTION__);
+  for(int i=0;i<lines;i++) {
+    g_print(" %d",monitor_lines[i]);
+  }
+  g_print("\n");
+  t.tv_sec=60;
+  t.tv_nsec=0;
+
+  int ret=gpiod_ctxless_event_monitor_multiple(
+                       gpio_device, GPIOD_CTXLESS_EVENT_BOTH_EDGES,
+                       monitor_lines, lines, FALSE,
+                       consumer, &t, NULL, interrupt_cb,NULL);
+  if (ret<0) {
+    g_print("%s: ctxless event monitor failed: %s\n",__FUNCTION__,g_strerror(errno));
+  }
+
+  g_print("%s: exit\n",__FUNCTION__);
+  return NULL;
 }
 
-static int s5_level=1;
-static unsigned long s5_debounce=0;
+static int setup_line(struct gpiod_chip *chip, int offset, gboolean pullup) {
+  int ret;
+  struct gpiod_line_request_config config;
 
-static void s5Alert() {
-    int t=millis();
-    if(millis()<s5_debounce) {
-      return;
-    }
-    int level=digitalRead(S5_BUTTON);
-    if(level!=s5_level) {
-      if(level==0) {
-        if(running) g_idle_add(s5_pressed,NULL);
-      } else {
-        if(running) g_idle_add(s5_released,NULL);
-      }
-      s5_level=level;
-      s5_debounce=t+settle_time;
-    }
-}
+  g_print("%s: %d\n",__FUNCTION__,offset);
+  struct gpiod_line *line=gpiod_chip_get_line(chip, offset);
+  if (!line) {
+    g_print("%s: get line %d failed: %s\n",__FUNCTION__,offset,g_strerror(errno));
+    return -1;
+  }
 
-static int s6_level=1;
-static unsigned long s6_debounce=0;
+  config.consumer=consumer;
+  config.request_type=GPIOD_LINE_REQUEST_DIRECTION_INPUT | GPIOD_LINE_REQUEST_EVENT_BOTH_EDGES;
+#ifdef RASPIAN
+  config.flags=pullup?GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW:0;
+#else
+  config.flags=pullup?GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP:GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN;
+#endif
+  ret=gpiod_line_request(line,&config,1);
+  if (ret<0) {
+    g_print("%s: line %d gpiod_line_request failed: %s\n",__FUNCTION__,offset,g_strerror(errno));
+    return ret;
+  }
 
-static void s6Alert() {
-    int t=millis();
-    if(millis()<s6_debounce) {
-      return;
-    }
-    int level=digitalRead(S6_BUTTON);
-    if(level!=s6_level) {
-      if(level==0) {
-        if(running) g_idle_add(s6_pressed,NULL);
-      } else {
-        if(running) g_idle_add(s6_released,NULL);
-      }
-      s6_level=level;
-      s6_debounce=t+settle_time;
-    }
+  gpiod_line_release(line);
+
+  monitor_lines[lines]=offset;
+  lines++;
+  return 0;
 }
 
-static int mox_level=1;
-static unsigned long mox_debounce=0;
+int gpio_init() {
+  int ret=0;
 
-static void moxAlert() {
-    int t=millis();
-    if(millis()<mox_debounce) {
-      return;
-    }
-    int level=digitalRead(MOX_BUTTON);
-    if(level!=mox_level) {
-      if(level==0) {
-        if(running) g_idle_add(mox_pressed,NULL);
-      }
-      mox_level=level;
-      mox_debounce=t+settle_time;
-    }
-}
+  initialiseEpoch();
+  switch_debounce=millis();
 
+  g_mutex_init(&encoder_mutex);
 
+  gpio_set_defaults(controller);
+
+  chip=NULL;
 
-#ifdef VFO_HAS_FUNCTION
-static unsigned long vfo_debounce=0;
+//g_print("%s: open gpio 0\n",__FUNCTION__);
+  chip=gpiod_chip_open_by_number(0);
+  if(chip==NULL) {
+    g_print("%s: open chip failed: %s\n",__FUNCTION__,g_strerror(errno));
+    ret=-1;
+    goto err;
+  }
 
-static void vfoFunctionAlert() {
-    if(t-vfo_debounce > settle_time) {
-      int level=digitalRead(VFO_FUNCTION);
-      if(level==0) {
-        if(running) g_idle_add(vfo_function_pressed,NULL);
-      } else {
-        if(running) g_idle_add(vfo_function_released,NULL);
+  // setup encoders
+  g_print("%s: setup encoders\n",__FUNCTION__);
+  for(int i=0;i<MAX_ENCODERS;i++) {
+    if(encoders[i].bottom_encoder_enabled) {
+      if(setup_line(chip,encoders[i].bottom_encoder_address_a,encoders[i].bottom_encoder_pullup)<0) {
+        continue;
+      }
+      if(setup_line(chip,encoders[i].bottom_encoder_address_b,encoders[i].bottom_encoder_pullup)<0) {
+        continue;
       }
-      vfo_debounce=t;
     }
-}
-#endif
 
-static void vfoEncoderInt() {
-  static int vfoA=1;
-  int levelA=digitalRead(VFO_ENCODER_A);
-  int levelB=digitalRead(VFO_ENCODER_B);
+    if(encoders[i].top_encoder_enabled) {
+      if(setup_line(chip,encoders[i].top_encoder_address_a,encoders[i].top_encoder_pullup)<0) {
+        continue;
+      }
+      if(setup_line(chip,encoders[i].top_encoder_address_b,encoders[i].top_encoder_pullup)<0) {
+        continue;
+      }
+    }
 
-  if(levelA!=vfoA) {
-    if(levelA==levelB) ++vfoEncoderPos;
-    if(levelA!=levelB) --vfoEncoderPos;
-    vfoA=levelA;
+    if(encoders[i].switch_enabled) {
+      if(setup_line(chip,encoders[i].switch_address,encoders[i].switch_pullup)<0) {
+        continue;
+      }
+    }
   }
-}
 
-static void e2EncoderInt() {
-  static int e2CurrentA=1;
-  int levelA=digitalRead(E2_ENCODER_A);
-  int levelB=digitalRead(E2_ENCODER_B);
+  // setup switches
+  g_print("%s: setup switches\n",__FUNCTION__);
+  for(int i=0;i<MAX_SWITCHES;i++) {
+    if(switches[i].switch_enabled) {
+      if(setup_line(chip,switches[i].switch_address,switches[i].switch_pullup)<0) {
+        continue;
+      }
+    }
+  }
 
-  if(levelA!=e2CurrentA) {
-    if(levelA==levelB) ++e2EncoderPos;
-    if(levelA!=levelB) --e2EncoderPos;
-    e2CurrentA=levelA;
+  if(controller==CONTROLLER2_V1 || controller==CONTROLLER2_V2) {
+    g_print("%s: setup i2c interrupt %d\n",__FUNCTION__,I2C_INTERRUPT);
+    if((ret=setup_line(chip,I2C_INTERRUPT,TRUE))<0) {
+      goto err;
+    }
   }
-}
 
-static void e2TopEncoderInt() {
-  static int e2TopCurrentA=1;
-  int levelA=digitalRead(E2_TOP_ENCODER_A);
-  int levelB=digitalRead(E2_TOP_ENCODER_B);
+  monitor_thread_id = g_thread_new( "gpiod monitor", monitor_thread, NULL);
+  if(!monitor_thread_id ) {
+    g_print("%s: g_thread_new failed for monitor_thread\n",__FUNCTION__);
+  }
 
-  if(levelA!=e2TopCurrentA) {
-    if(levelA==levelB) ++e2TopEncoderPos;
-    if(levelA!=levelB) --e2TopEncoderPos;
-    e2TopCurrentA=levelA;
+  rotary_encoder_thread_id = g_thread_new( "encoders", rotary_encoder_thread, NULL);
+  if(!rotary_encoder_thread_id ) {
+    g_print("%s: g_thread_new failed on rotary_encoder_thread\n",__FUNCTION__);
+    exit( -1 );
   }
-}
+  g_print("%s: rotary_encoder_thread: id=%p\n",__FUNCTION__,rotary_encoder_thread_id);
 
-static void e3EncoderInt() {
-  static int e3CurrentA=1;
-  int levelA=digitalRead(E3_ENCODER_A);
-  int levelB=digitalRead(E3_ENCODER_B);
+  return 0;
 
-  if(levelA!=e3CurrentA) {
-    if(levelA==levelB) ++e3EncoderPos;
-    if(levelA!=levelB) --e3EncoderPos;
-    e3CurrentA=levelA;
+err:
+g_print("%s: err\n",__FUNCTION__);
+  if(chip!=NULL) {
+    gpiod_chip_close(chip);
+    chip=NULL;
   }
+  return ret;
 }
 
-static void e3TopEncoderInt() {
-  static int e3TopCurrentA=1;
-  int levelA=digitalRead(E3_TOP_ENCODER_A);
-  int levelB=digitalRead(E3_TOP_ENCODER_B);
-
+void gpio_close() {
+  if(chip!=NULL) gpiod_chip_close(chip);
+}
 
-  if(levelA!=e3TopCurrentA) {
-    if(levelA==levelB) ++e3TopEncoderPos;
-    if(levelA!=levelB) --e3TopEncoderPos;
-    e3TopCurrentA=levelA;
-  }
+#ifdef LOCALCW
+void gpio_cw_sidetone_set(int level) {
 }
 
-static void e4EncoderInt() {
-  static int e4CurrentA=1;
-  int levelA=digitalRead(E4_ENCODER_A);
-  int levelB=digitalRead(E4_ENCODER_B);
+int  gpio_left_cw_key() {
+}
 
-  if(levelA!=e4CurrentA) {
-    if(levelA==levelB) ++e4EncoderPos;
-    if(levelA!=levelB) --e4EncoderPos;
-    e4CurrentA=levelA;
-  }
+int  gpio_right_cw_key() {
 }
 
-static void e4TopEncoderInt() {
-  static int e4TopCurrentA=1;
-  int levelA=digitalRead(E4_TOP_ENCODER_A);
-  int levelB=digitalRead(E4_TOP_ENCODER_B);
+int  gpio_cw_sidetone_enabled() {
+}
 
-  if(levelA!=e4TopCurrentA) {
-    if(levelA==levelB) ++e4TopEncoderPos;
-    if(levelA!=levelB) --e4TopEncoderPos;
-    e4TopCurrentA=levelA;
-  }
-}
-
-static void e5EncoderInt() {
-  static int e5CurrentA=1;
-  int levelA=digitalRead(E5_ENCODER_A);
-  int levelB=digitalRead(E5_ENCODER_B);
-
-
-  if(levelA!=e5CurrentA) {
-    if(levelA==levelB) ++e5EncoderPos;
-    if(levelA!=levelB) --e5EncoderPos;
-    e5CurrentA=levelA;
-  }
-}
-
-static void e5TopEncoderInt() {
-  static int e5TopCurrentA=1;
-  int levelA=digitalRead(E5_TOP_ENCODER_A);
-  int levelB=digitalRead(E5_TOP_ENCODER_B);
-
-  if(levelA!=e5TopCurrentA) {
-    if(levelA==levelB) ++e5TopEncoderPos;
-    if(levelA!=levelB) --e5TopEncoderPos;
-    e5TopCurrentA=levelA;
-  }
-}
-
-
-static void pI2CInterrupt() {
-    int level=digitalRead(I2C_INTERRUPT);
-    if(level==0) {
-      i2c_interrupt();
-    }
-}
-
-#ifdef PTT
-static int ptt_level=1;
-static unsigned long ptt_debounce=0;
-
-static void pttAlert() {
-    int t=millis();
-    if(millis()<ptt_debounce) {
-      return;
-    }
-    int level=digitalRead(PTT_GPIO);
-    if(level!=ptt_level) {
-      if(level==0) {
-        if(running) g_idle_add(ptt_pressed,NULL);
-      } else {
-        if(running) g_idle_add(ptt_released,NULL);
-      }
-      ptt_level=level;
-      ptt_debounce=t+settle_time;
-    }
-}
-#endif
-
-void gpio_set_defaults(int ctrlr) {
-g_print("gpio_set_defaults: %d\n",ctrlr);
-  if(sw_action!=NULL) {
-    g_free(sw_action);
-    sw_action=NULL;
-  }
-  switch(ctrlr) {
-    case NO_CONTROLLER:
-      ENABLE_VFO_ENCODER=0;
-      ENABLE_E2_ENCODER=0;
-      ENABLE_E3_ENCODER=0;
-      ENABLE_E4_ENCODER=0;
-      ENABLE_S1_BUTTON=0;
-      ENABLE_S2_BUTTON=0;
-      ENABLE_S3_BUTTON=0;
-      ENABLE_S4_BUTTON=0;
-      ENABLE_S5_BUTTON=0;
-      ENABLE_S6_BUTTON=0;
-      ENABLE_MOX_BUTTON=0;
-      ENABLE_FUNCTION_BUTTON=0;
-      ENABLE_E5_ENCODER=0;
-      ENABLE_E2_TOP_ENCODER=0;
-      ENABLE_E3_TOP_ENCODER=0;
-      ENABLE_E4_TOP_ENCODER=0;
-      ENABLE_E5_TOP_ENCODER=0;
-      break;
-    case CONTROLLER1:
-      sw_action=g_new(int,CONTROLLER1_SWITCHES);
-      ENABLE_VFO_ENCODER=1;
-      ENABLE_VFO_PULLUP=1;
-      VFO_ENCODER_A=1;
-      VFO_ENCODER_B=0;
-      ENABLE_E2_ENCODER=1;
-      ENABLE_E2_PULLUP=0;
-      E2_ENCODER_A=28;
-      E2_ENCODER_B=25;
-      E2_FUNCTION=6;
-      ENABLE_E3_ENCODER=1;
-      ENABLE_E3_PULLUP=0;
-      E3_ENCODER_A=27;
-      E3_ENCODER_B=24;
-      E3_FUNCTION=10;
-      ENABLE_E4_ENCODER=1;
-      ENABLE_E4_PULLUP=0;
-      E4_ENCODER_A=7;
-      E4_ENCODER_B=29;
-      E4_FUNCTION=11;
-      ENABLE_S1_BUTTON=1;
-      S1_BUTTON=23;
-      ENABLE_S2_BUTTON=1;
-      S2_BUTTON=26;
-      ENABLE_S3_BUTTON=1;
-      S3_BUTTON=22;
-      ENABLE_S4_BUTTON=1;
-      S4_BUTTON=21;
-      ENABLE_S5_BUTTON=1;
-      S5_BUTTON=5;
-      ENABLE_S6_BUTTON=1;
-      S6_BUTTON=4;
-      ENABLE_MOX_BUTTON=1;
-      MOX_BUTTON=2;
-      ENABLE_FUNCTION_BUTTON=1;
-      FUNCTION_BUTTON=3;
-      ENABLE_E5_ENCODER=0;
-      ENABLE_E2_TOP_ENCODER=0;
-      ENABLE_E3_TOP_ENCODER=0;
-      ENABLE_E4_TOP_ENCODER=0;
-      ENABLE_E5_TOP_ENCODER=0;
-      e2_sw_action=MENU_BAND;
-      e2_encoder_action=ENCODER_AF_GAIN;
-      e3_sw_action=MENU_BANDSTACK;
-      e3_encoder_action=ENCODER_AGC_GAIN;
-      e4_sw_action=MENU_MODE;
-      e4_encoder_action=ENCODER_DRIVE;
-      e2_top_encoder_action=ENCODER_NO_ACTION;
-      e3_top_encoder_action=ENCODER_NO_ACTION;
-      e4_top_encoder_action=ENCODER_NO_ACTION;
-      e5_encoder_action=ENCODER_NO_ACTION;
-      e5_top_encoder_action=ENCODER_NO_ACTION;
-      break;
-    case CONTROLLER2_V1:
-      // uses wiringpi pin numbers
-      ENABLE_VFO_ENCODER=1;
-      ENABLE_VFO_PULLUP=1;
-      VFO_ENCODER_A=1;
-      VFO_ENCODER_B=0;
-      ENABLE_E2_ENCODER=1;
-      ENABLE_E2_PULLUP=1;
-      E2_ENCODER_A=28;
-      E2_ENCODER_B=25;
-      E2_FUNCTION=3;
-      ENABLE_E3_ENCODER=1;
-      ENABLE_E3_PULLUP=1;
-      E3_ENCODER_A=7;
-      E3_ENCODER_B=29;
-      E3_FUNCTION=2;
-      ENABLE_E4_ENCODER=1;
-      ENABLE_E4_PULLUP=1;
-      E4_ENCODER_A=27;
-      E4_ENCODER_B=24;
-      E4_FUNCTION=4;
-      ENABLE_E5_ENCODER=1;
-      ENABLE_E5_PULLUP=1;
-      E5_ENCODER_A=6;
-      E5_ENCODER_B=10;
-      E5_FUNCTION=5;
-      ENABLE_S1_BUTTON=0;
-      ENABLE_S2_BUTTON=0;
-      ENABLE_S3_BUTTON=0;
-      ENABLE_S4_BUTTON=0;
-      ENABLE_S5_BUTTON=0;
-      ENABLE_S6_BUTTON=0;
-      ENABLE_E2_TOP_ENCODER=0;
-      ENABLE_E3_TOP_ENCODER=0;
-      ENABLE_E4_TOP_ENCODER=0;
-      ENABLE_E5_TOP_ENCODER=0;
-      sw_action=g_new(int,CONTROLLER2_SWITCHES);
-      sw_action[0]=MOX;
-      sw_action[1]=TUNE;
-      sw_action[2]=PS;
-      sw_action[3]=TWO_TONE;
-      sw_action[4]=NR;
-      sw_action[5]=A_TO_B;
-      sw_action[6]=B_TO_A;
-      sw_action[7]=MODE_MINUS;
-      sw_action[8]=BAND_MINUS;
-      sw_action[9]=MODE_PLUS;
-      sw_action[10]=BAND_PLUS;
-      sw_action[11]=XIT;
-      sw_action[12]=NB;
-      sw_action[13]=SNB;
-      sw_action[14]=LOCK;
-      sw_action[15]=CTUN;
-      e2_sw_action=MENU_BAND;
-      e2_encoder_action=ENCODER_AF_GAIN;
-      e3_sw_action=MENU_BANDSTACK;
-      e3_encoder_action=ENCODER_AGC_GAIN;
-      e4_sw_action=MENU_MODE;
-      e4_encoder_action=ENCODER_IF_WIDTH;
-      e5_sw_action=MENU_FREQUENCY;
-      e5_encoder_action=ENCODER_RIT;
-      e2_top_encoder_action=ENCODER_NO_ACTION;
-      e3_top_encoder_action=ENCODER_NO_ACTION;
-      e4_top_encoder_action=ENCODER_NO_ACTION;
-      e5_top_encoder_action=ENCODER_NO_ACTION;
-      break;
-    case CONTROLLER2_V2:
-      // uses wiringpi pin numbers
-      ENABLE_VFO_ENCODER=1;
-      ENABLE_VFO_PULLUP=0;
-      VFO_ENCODER_A=1;
-      VFO_ENCODER_B=0;
-      ENABLE_E2_ENCODER=1;
-      ENABLE_E2_PULLUP=1;
-      E2_ENCODER_A=21;
-      E2_ENCODER_B=22;
-      ENABLE_E2_TOP_ENCODER=1;
-      E2_TOP_ENCODER_A=25;
-      E2_TOP_ENCODER_B=28;
-      E2_FUNCTION=3;
-      ENABLE_E3_ENCODER=1;
-      ENABLE_E3_PULLUP=1;
-      E3_ENCODER_A=13;
-      E3_ENCODER_B=11;
-      ENABLE_E3_TOP_ENCODER=1;
-      E3_TOP_ENCODER_A=29;
-      E3_TOP_ENCODER_B=7;
-      E3_FUNCTION=2;
-      ENABLE_E4_ENCODER=1;
-      ENABLE_E4_PULLUP=1;
-      E4_ENCODER_A=14;
-      E4_ENCODER_B=12;
-      ENABLE_E4_TOP_ENCODER=1;
-      E4_TOP_ENCODER_A=24;
-      E4_TOP_ENCODER_B=27;
-      E4_FUNCTION=4;
-      ENABLE_E5_ENCODER=1;
-      ENABLE_E5_PULLUP=1;
-      E5_ENCODER_A=23;
-      E5_ENCODER_B=26;
-      ENABLE_E5_TOP_ENCODER=1;
-      E5_TOP_ENCODER_A=10;
-      E5_TOP_ENCODER_B=6;
-      E5_FUNCTION=5;
-      ENABLE_S1_BUTTON=0;
-      ENABLE_S2_BUTTON=0;
-      ENABLE_S3_BUTTON=0;
-      ENABLE_S4_BUTTON=0;
-      ENABLE_S5_BUTTON=0;
-      ENABLE_S6_BUTTON=0;
-      sw_action=g_new(int,CONTROLLER2_SWITCHES);
-      sw_action[0]=MOX;
-      sw_action[1]=TUNE;
-      sw_action[2]=PS;
-      sw_action[3]=TWO_TONE;
-      sw_action[4]=NR;
-      sw_action[5]=A_TO_B;
-      sw_action[6]=B_TO_A;
-      sw_action[7]=MODE_MINUS;
-      sw_action[8]=BAND_MINUS;
-      sw_action[9]=MODE_PLUS;
-      sw_action[10]=BAND_PLUS;
-      sw_action[11]=XIT;
-      sw_action[12]=NB;
-      sw_action[13]=SNB;
-      sw_action[14]=LOCK;
-      sw_action[15]=CTUN;
-      e2_sw_action=MENU_BAND;
-      e2_top_encoder_action=ENCODER_AF_GAIN;
-      e2_encoder_action=ENCODER_RF_GAIN;
-      e3_sw_action=MENU_MODE;
-      e3_top_encoder_action=ENCODER_AGC_GAIN;
-      e3_encoder_action=ENCODER_ATTENUATION;
-      e4_sw_action=MENU_FILTER;
-      e4_top_encoder_action=ENCODER_IF_SHIFT;
-      e4_encoder_action=ENCODER_IF_WIDTH;
-      e5_sw_action=MENU_FREQUENCY;
-      e5_top_encoder_action=ENCODER_RIT;
-      e5_encoder_action=ENCODER_XIT;
-      break;
-    default:
-      break;
-  }
-}
-
-void gpio_restore_actions() {
-  char* value;
-  char name[80];
-  int i;
-
-  if(sw_action!=NULL) {
-    g_free(sw_action);
-    sw_action=NULL;
-  }
-
-  gpio_set_defaults(controller);
-  
-  value=getProperty("settle_time");
-  if(value) settle_time=atoi(value);
-
-  value=getProperty("e2_encoder_action");
-  if(value) e2_encoder_action=atoi(value);
-  value=getProperty("e2_sw_action");
-  if(value) e2_sw_action=atoi(value);
-  value=getProperty("e3_encoder_action");
-  if(value) e3_encoder_action=atoi(value);
-  value=getProperty("e3_sw_action");
-  if(value) e3_sw_action=atoi(value);
-  value=getProperty("e4_encoder_action");
-  if(value) e4_encoder_action=atoi(value);
-  value=getProperty("e4_sw_action");
-  if(value) e4_sw_action=atoi(value);
-  value=getProperty("e2_top_encoder_action");
-  if(value) e2_top_encoder_action=atoi(value);
-  value=getProperty("e3_top_encoder_action");
-  if(value) e3_top_encoder_action=atoi(value);
-  value=getProperty("e4_top_encoder_action");
-  if(value) e4_top_encoder_action=atoi(value);
-  value=getProperty("e5_encoder_action");
-  if(value) e5_encoder_action=atoi(value);
-  value=getProperty("e5_top_encoder_action");
-  if(value) e5_top_encoder_action=atoi(value);
-  value=getProperty("e5_sw_action");
-  if(value) e5_sw_action=atoi(value);
-
-  int switches=0;
-  switch(controller) {
-    case CONTROLLER1:
-      //switches=CONTROLLER1_SWITCHES;
-      switches=0;
-      break;
-    case CONTROLLER2_V1:
-    case CONTROLLER2_V2:
-      switches=CONTROLLER2_SWITCHES;
-      break;
-    default:
-      switches=0;
-      break;
-  }
-
-  for(i=0;i<switches;i++) {
-    sprintf(name,"sw_action[%d]",i);
-    value=getProperty(name);           
-    if(value) sw_action[i]=atoi(value);                
-  }
-}
-
-void gpio_restore_state() {
-  char* value;
-  char name[80];
-
-  loadProperties("gpio.props");
-  value=getProperty("controller");
-  if(value) controller=atoi(value);
-  value=getProperty("ENABLE_VFO_ENCODER");
-  if(value) ENABLE_VFO_ENCODER=atoi(value);
-  value=getProperty("ENABLE_VFO_PULLUP");
-  if(value) ENABLE_VFO_PULLUP=atoi(value);
-  value=getProperty("VFO_ENCODER_A");
-  if(value) VFO_ENCODER_A=atoi(value);
-  value=getProperty("VFO_ENCODER_B");
-  if(value) VFO_ENCODER_B=atoi(value);
-  value=getProperty("ENABLE_E2_ENCODER");
-  if(value) ENABLE_E2_ENCODER=atoi(value);
-  value=getProperty("ENABLE_E2_PULLUP");
-  if(value) ENABLE_E2_PULLUP=atoi(value);
-  value=getProperty("E2_ENCODER_A");
-  if(value) E2_ENCODER_A=atoi(value);
-  value=getProperty("E2_ENCODER_B");
-  if(value) E2_ENCODER_B=atoi(value);
-  value=getProperty("E2_TOP_ENCODER_A");
-  if(value) E2_TOP_ENCODER_A=atoi(value);
-  value=getProperty("E2_TOP_ENCODER_B");
-  if(value) E2_TOP_ENCODER_B=atoi(value);
-  value=getProperty("ENABLE_E3_ENCODER");
-  if(value) ENABLE_E3_ENCODER=atoi(value);
-  value=getProperty("ENABLE_E3_PULLUP");
-  if(value) ENABLE_E3_PULLUP=atoi(value);
-  value=getProperty("E3_ENCODER_A");
-  if(value) E3_ENCODER_A=atoi(value);
-  value=getProperty("E3_ENCODER_B");
-  if(value) E3_ENCODER_B=atoi(value);
-  value=getProperty("E3_TOP_ENCODER_A");
-  if(value) E3_TOP_ENCODER_A=atoi(value);
-  value=getProperty("E3_TOP_ENCODER_B");
-  if(value) E3_TOP_ENCODER_B=atoi(value);
-  value=getProperty("ENABLE_E4_ENCODER");
-  if(value) ENABLE_E4_ENCODER=atoi(value);
-  value=getProperty("ENABLE_E4_PULLUP");
-  if(value) ENABLE_E4_PULLUP=atoi(value);
-  value=getProperty("E4_ENCODER_A");
-  if(value) E4_ENCODER_A=atoi(value);
-  value=getProperty("E4_ENCODER_B");
-  if(value) E4_ENCODER_B=atoi(value);
-  value=getProperty("E4_TOP_ENCODER_A");
-  if(value) E4_TOP_ENCODER_A=atoi(value);
-  value=getProperty("E4_TOP_ENCODER_B");
-  if(value) E4_TOP_ENCODER_B=atoi(value);
-  value=getProperty("ENABLE_E5_ENCODER");
-  if(value) ENABLE_E5_ENCODER=atoi(value);
-  value=getProperty("ENABLE_E5_PULLUP");
-  if(value) ENABLE_E5_PULLUP=atoi(value);
-  value=getProperty("E5_ENCODER_A");
-  if(value) E5_ENCODER_A=atoi(value);
-  value=getProperty("E5_ENCODER_B");
-  if(value) E5_ENCODER_B=atoi(value);
-  value=getProperty("E5_TOP_ENCODER_A");
-  if(value) E5_TOP_ENCODER_A=atoi(value);
-  value=getProperty("E5_TOP_ENCODER_B");
-  if(value) E5_TOP_ENCODER_B=atoi(value);
-  value=getProperty("ENABLE_S1_BUTTON");
-  if(value) ENABLE_S1_BUTTON=atoi(value);
-  value=getProperty("S1_BUTTON");
-  if(value) S1_BUTTON=atoi(value);
-  value=getProperty("ENABLE_S2_BUTTON");
-  if(value) ENABLE_S2_BUTTON=atoi(value);
-  value=getProperty("S2_BUTTON");
-  if(value) S2_BUTTON=atoi(value);
-  value=getProperty("ENABLE_S3_BUTTON");
-  if(value) ENABLE_S3_BUTTON=atoi(value);
-  value=getProperty("S3_BUTTON");
-  if(value) S3_BUTTON=atoi(value);
-  value=getProperty("ENABLE_S4_BUTTON");
-  if(value) ENABLE_S4_BUTTON=atoi(value);
-  value=getProperty("S4_BUTTON");
-  if(value) S4_BUTTON=atoi(value);
-  value=getProperty("ENABLE_S5_BUTTON");
-  if(value) ENABLE_S5_BUTTON=atoi(value);
-  value=getProperty("S5_BUTTON");
-  if(value) S5_BUTTON=atoi(value);
-  value=getProperty("ENABLE_S6_BUTTON");
-  if(value) ENABLE_S6_BUTTON=atoi(value);
-  value=getProperty("S6_BUTTON");
-  if(value) S6_BUTTON=atoi(value);
-  value=getProperty("ENABLE_FUNCTION_BUTTON");
-  if(value) ENABLE_FUNCTION_BUTTON=atoi(value);
-  value=getProperty("FUNCTION_BUTTON");
-  if(value) FUNCTION_BUTTON=atoi(value);
-  value=getProperty("ENABLE_MOX_BUTTON");
-  if(value) ENABLE_MOX_BUTTON=atoi(value);
-  value=getProperty("MOX_BUTTON");
-  if(value) MOX_BUTTON=atoi(value);
-
-  value=getProperty("E2_FUNCTION");
-  if(value) E2_FUNCTION=atoi(value);
-  value=getProperty("E3_FUNCTION");
-  if(value) E3_FUNCTION=atoi(value);
-  value=getProperty("E4_FUNCTION");
-  if(value) E4_FUNCTION=atoi(value);
-  value=getProperty("E5_FUNCTION");
-  if(value) E5_FUNCTION=atoi(value);
-
-#ifdef LOCALCW         
-  value=getProperty("ENABLE_CW_BUTTONS");              
-  if(value) ENABLE_CW_BUTTONS=atoi(value);             
-  value=getProperty("CW_ACTIVE_LOW");          
-  if(value) CW_ACTIVE_LOW=atoi(value);         
-  value=getProperty("CWL_BUTTON");             
-  if(value) CWL_BUTTON=atoi(value);            
-  value=getProperty("CWR_BUTTON");             
-  if(value) CWR_BUTTON=atoi(value);            
-  value=getProperty("SIDETONE_GPIO");          
-  if(value) SIDETONE_GPIO=atoi(value);         
-  value=getProperty("ENABLE_GPIO_SIDETONE");           
-  if(value) ENABLE_GPIO_SIDETONE=atoi(value);          
-#endif
-
-#ifdef PTT
-  switch(controller) {
-    case NO_CONTROLLER:
-      PTT_GPIO=12;
-      break;
-    case CONTROLLER1:
-      PTT_GPIO=12;
-      break;
-    case CONTROLLER2_V1:
-      PTT_GPIO=15;
-      break;
-    case CONTROLLER2_V2:
-      PTT_GPIO=15;
-      break;
-  }
-  value=getProperty("ENABLE_PTT_GPIO");                
-  if(value) ENABLE_PTT_GPIO=atoi(value);               
-  value=getProperty("PTT_GPIO");               
-  if(value) PTT_GPIO=atoi(value);              
-  value=getProperty("PTT_ACTIVE_LOW");         
-  if(value) PTT_ACTIVE_LOW=atoi(value);                
-#endif
-
-  if(controller!=CONTROLLER1) {
-    value=getProperty("i2c_device");
-    if(value) {
-      i2c_device=g_new(char,strlen(value)+1);
-      strcpy(i2c_device,value);
-    }
-    for(int i=0;i<16;i++) {
-      sprintf(name,"i2c_sw[%d]",i);
-      value=getProperty(name);
-      if(value) i2c_sw[i]=atoi(value);
-    }
-  }
-
-#ifdef LOCALCW
-  if(controller==CONTROLLER2_V2) {
-    //
-    // In Controller2 V2, no 'free' GPIO pins
-    // are available, so one cannot use any of
-    // of these for CW in the standard setup
-    //
-    ENABLE_CW_BUTTONS=0;
-    ENABLE_GPIO_SIDETONE=0;
-  }
-#endif
-
-
-}
-
-void gpio_save_actions() {
-  int i;
-  char name[80];
-  char value[80];
-
-  sprintf(value,"%d",settle_time);
-  setProperty("settle_time",value);
-  sprintf(value,"%d",e2_sw_action);
-  setProperty("e2_sw_action",value);
-  sprintf(value,"%d",e2_encoder_action);
-  setProperty("e2_encoder_action",value);
-  sprintf(value,"%d",e3_sw_action);
-  setProperty("e3_sw_action",value);
-  sprintf(value,"%d",e3_encoder_action);
-  setProperty("e3_encoder_action",value);
-  sprintf(value,"%d",e4_sw_action);
-  setProperty("e4_sw_action",value);
-  sprintf(value,"%d",e4_encoder_action);
-  setProperty("e4_encoder_action",value);
-  sprintf(value,"%d",e5_sw_action);
-  setProperty("e5_sw_action",value);
-  sprintf(value,"%d",e5_encoder_action);
-  setProperty("e5_encoder_action",value);
-  sprintf(value,"%d",e2_top_encoder_action);
-  setProperty("e2_top_encoder_action",value);
-  sprintf(value,"%d",e3_top_encoder_action);
-  setProperty("e3_top_encoder_action",value);
-  sprintf(value,"%d",e4_top_encoder_action);
-  setProperty("e4_top_encoder_action",value);
-  sprintf(value,"%d",e5_top_encoder_action);
-  setProperty("e5_top_encoder_action",value);
-  int switches=0;
-  switch(controller) {
-    case CONTROLLER1:
-      //switches=CONTROLLER1_SWITCHES;
-      switches=0;
-      break;
-    case CONTROLLER2_V1:
-    case CONTROLLER2_V2:
-      switches=CONTROLLER2_SWITCHES;
-      break;
-    default:
-      switches=0;
-      break;
-  }
-  if(sw_action!=NULL) {
-    for(i=0;i<switches;i++) {
-      sprintf(name,"sw_action[%d]",i);
-      sprintf(value,"%d",sw_action[i]);
-      setProperty(name,value);         
-    }
-  }
-  
-}
-
-void gpio_save_state() {
-  char value[80];
-  char name[80];
-
-  clearProperties();
-  sprintf(value,"%d",controller);
-  setProperty("controller",value);
-  sprintf(value,"%d",ENABLE_VFO_ENCODER);
-  setProperty("ENABLE_VFO_ENCODER",value);
-  sprintf(value,"%d",ENABLE_VFO_PULLUP);
-  setProperty("ENABLE_VFO_PULLUP",value);
-  sprintf(value,"%d",VFO_ENCODER_A);
-  setProperty("VFO_ENCODER_A",value);
-  sprintf(value,"%d",VFO_ENCODER_B);
-  setProperty("VFO_ENCODER_B",value);
-  sprintf(value,"%d",ENABLE_E2_ENCODER);
-  setProperty("ENABLE_E2_ENCODER",value);
-  sprintf(value,"%d",ENABLE_E2_PULLUP);
-  setProperty("ENABLE_E2_PULLUP",value);
-  sprintf(value,"%d",E2_ENCODER_A);
-  setProperty("E2_ENCODER_A",value);
-  sprintf(value,"%d",E2_ENCODER_B);
-  setProperty("E2_ENCODER_B",value);
-  sprintf(value,"%d",E2_TOP_ENCODER_A);
-  setProperty("E2_TOP_ENCODER_A",value);
-  sprintf(value,"%d",E2_TOP_ENCODER_B);
-  setProperty("E2_TOP_ENCODER_B",value);
-  sprintf(value,"%d",ENABLE_E3_ENCODER);
-  setProperty("ENABLE_E3_ENCODER",value);
-  sprintf(value,"%d",ENABLE_E3_PULLUP);
-  setProperty("ENABLE_E3_PULLUP",value);
-  sprintf(value,"%d",E3_ENCODER_A);
-  setProperty("E3_ENCODER_A",value);
-  sprintf(value,"%d",E3_ENCODER_B);
-  setProperty("E3_ENCODER_B",value);
-  sprintf(value,"%d",E3_TOP_ENCODER_A);
-  setProperty("E3_TOP_ENCODER_A",value);
-  sprintf(value,"%d",E3_TOP_ENCODER_B);
-  setProperty("E3_TOP_ENCODER_B",value);
-  sprintf(value,"%d",ENABLE_E4_ENCODER);
-  setProperty("ENABLE_E4_ENCODER",value);
-  sprintf(value,"%d",ENABLE_E4_PULLUP);
-  setProperty("ENABLE_E4_PULLUP",value);
-  sprintf(value,"%d",E4_ENCODER_A);
-  setProperty("E4_ENCODER_A",value);
-  sprintf(value,"%d",E4_ENCODER_B);
-  setProperty("E4_ENCODER_B",value);
-  sprintf(value,"%d",E4_TOP_ENCODER_A);
-  setProperty("E4_TOP_ENCODER_A",value);
-  sprintf(value,"%d",E4_TOP_ENCODER_B);
-  setProperty("E4_TOP_ENCODER_B",value);
-  sprintf(value,"%d",ENABLE_E5_ENCODER);
-  setProperty("ENABLE_E5_ENCODER",value);
-  sprintf(value,"%d",ENABLE_E5_PULLUP);
-  setProperty("ENABLE_E5_PULLUP",value);
-  sprintf(value,"%d",E5_ENCODER_A);
-  setProperty("E5_ENCODER_A",value);
-  sprintf(value,"%d",E5_ENCODER_B);
-  setProperty("E5_ENCODER_B",value);
-  sprintf(value,"%d",E5_TOP_ENCODER_A);
-  setProperty("E5_TOP_ENCODER_A",value);
-  sprintf(value,"%d",E5_TOP_ENCODER_B);
-  setProperty("E5_TOP_ENCODER_B",value);
-  sprintf(value,"%d",ENABLE_S1_BUTTON);
-  setProperty("ENABLE_S1_BUTTON",value);
-  sprintf(value,"%d",S1_BUTTON);
-  setProperty("S1_BUTTON",value);
-  sprintf(value,"%d",ENABLE_S2_BUTTON);
-  setProperty("ENABLE_S2_BUTTON",value);
-  sprintf(value,"%d",S2_BUTTON);
-  setProperty("S2_BUTTON",value);
-  sprintf(value,"%d",ENABLE_S3_BUTTON);
-  setProperty("ENABLE_S3_BUTTON",value);
-  sprintf(value,"%d",S3_BUTTON);
-  setProperty("S3_BUTTON",value);
-  sprintf(value,"%d",ENABLE_S4_BUTTON);
-  setProperty("ENABLE_S4_BUTTON",value);
-  sprintf(value,"%d",S4_BUTTON);
-  setProperty("S4_BUTTON",value);
-  sprintf(value,"%d",ENABLE_S5_BUTTON);
-  setProperty("ENABLE_S5_BUTTON",value);
-  sprintf(value,"%d",S5_BUTTON);
-  setProperty("S5_BUTTON",value);
-  sprintf(value,"%d",ENABLE_S6_BUTTON);
-  setProperty("ENABLE_S6_BUTTON",value);
-  sprintf(value,"%d",S6_BUTTON);
-  setProperty("S6_BUTTON",value);
-  sprintf(value,"%d",ENABLE_FUNCTION_BUTTON);
-  setProperty("ENABLE_FUNCTION_BUTTON",value);
-  sprintf(value,"%d",FUNCTION_BUTTON);
-  setProperty("FUNCTION_BUTTON",value);
-  sprintf(value,"%d",ENABLE_MOX_BUTTON);
-  setProperty("ENABLE_MOX_BUTTON",value);
-  sprintf(value,"%d",MOX_BUTTON);
-  setProperty("MOX_BUTTON",value);
-
-  sprintf(value,"%d",E2_FUNCTION);
-  setProperty("E2_FUNCTION",value);
-  sprintf(value,"%d",E3_FUNCTION);
-  setProperty("E3_FUNCTION",value);
-  sprintf(value,"%d",E4_FUNCTION);
-  setProperty("E4_FUNCTION",value);
-  sprintf(value,"%d",E5_FUNCTION);
-  setProperty("E5_FUNCTION",value);
-
-  if(controller!=CONTROLLER1) {
-    setProperty("i2c_device",i2c_device);              
-    sprintf(value,"%ud",i2c_address_1);
-    setProperty("i2c_address_1",value);                
-    for(int i=0;i<16;i++) {
-      sprintf(name,"i2c_sw[%d]",i);
-      sprintf(value,"%ud",i2c_sw[i]);
-      setProperty(name,value);         
-    }
-
-  }
-
-#ifdef LOCALCW         
-  sprintf(value,"%d",ENABLE_CW_BUTTONS);               
-  setProperty("ENABLE_CW_BUTTONS",value);              
-  sprintf(value,"%d",CW_ACTIVE_LOW);           
-  setProperty("CW_ACTIVE_LOW",value);          
-  sprintf(value,"%d",CWL_BUTTON);              
-  setProperty("CWL_BUTTON",value);             
-  sprintf(value,"%d",CWR_BUTTON);              
-  setProperty("CWR_BUTTON",value);             
-  sprintf(value,"%d",SIDETONE_GPIO);           
-  setProperty("SIDETONE_GPIO",value);          
-  sprintf(value,"%d",ENABLE_GPIO_SIDETONE);            
-  setProperty("ENABLE_GPIO_SIDETONE",value);           
-#endif
-
-#ifdef PTT
-  sprintf(value,"%d",ENABLE_PTT_GPIO);         
-  setProperty("ENABLE_PTT_GPIO",value);                
-  sprintf(value,"%d",PTT_GPIO);                
-  setProperty("PTT_GPIO",value);               
-  sprintf(value,"%d",PTT_ACTIVE_LOW);          
-  setProperty("PTT_ACTIVE_LOW",value);         
-#endif
-  saveProperties("gpio.props");
-
-}
-
-static void setup_pin(int pin, int up_down, void(*pAlert)(void)) {
-  int rc;
-g_print("setup_pin: pin=%d up_down=%d\n",pin,up_down);
-  pinMode(pin,GPIO);
-  pinMode(pin,INPUT);
-  pullUpDnControl(pin,up_down);
-  usleep(10000);
-  rc=wiringPiISR(pin,INT_EDGE_BOTH,pAlert);
-  if(rc<0) {
-    fprintf(stderr,"wirngPiISR returned %d\n",rc);
-  }
-}
-
-
-static void setup_encoder_pin(int pin, int up_down, void(*pAlert)(void)) {
-  int rc;
-  pinMode(pin,GPIO);
-  pinMode(pin,INPUT);
-  pullUpDnControl(pin,up_down);
-  usleep(10000);
-  if(pAlert!=NULL) {
-    rc=wiringPiISR(pin,INT_EDGE_BOTH,pAlert);
-    if(rc<0) {
-      fprintf(stderr,"wirngPiISR returned %d\n",rc);
-    }
-  }
-}
-
-#ifdef LOCALCW
-
-//
-// We generate interrupts only on falling edge
-//
-
-static void setup_cw_pin(int pin, void(*pAlert)(void)) {
-  int rc;
-  pinMode(pin,INPUT);
-  pullUpDnControl(pin,PUD_UP);
-  usleep(10000);
-  rc=wiringPiISR(pin,INT_EDGE_BOTH,pAlert);
-  if(rc<0) {
-    fprintf(stderr,"wirngPiISR returned %d\n",rc);
-  }
-}
-
-static void cwAlert_left() {
-    int level;
-    if (cw_keyer_internal != 0) return; // as quickly as possible
-    level=digitalRead(CWL_BUTTON);
-    //fprintf(stderr,"cwl button : level=%d \n",level);
-    //the second parameter of keyer_event ("state") is TRUE on key-down
-    keyer_event(1, CW_ACTIVE_LOW ? (level==0) : level);
-}
-
-static void cwAlert_right() {
-    int level;
-    if (cw_keyer_internal != 0) return; // as quickly as possible
-    level=digitalRead(CWR_BUTTON);
-    //fprintf(stderr,"cwr button : level=%d \n",level);
-     keyer_event(0, CW_ACTIVE_LOW ? (level==0) : level);
-}
-
-//
-// The following functions are an interface for
-// other parts to access CW gpio functions
-// (query left and right paddle, set sidetone output)
-//
-int gpio_left_cw_key() {
-  int val=digitalRead(CWL_BUTTON);
-  return CW_ACTIVE_LOW? (val==0) : val;
-}
-
-int gpio_right_cw_key() {
-  int val=digitalRead(CWR_BUTTON);
-  return CW_ACTIVE_LOW? (val==0) : val;
-}
-
-int gpio_cw_sidetone_enabled() {
-  return ENABLE_GPIO_SIDETONE;
-}
-
-void gpio_cw_sidetone_set(int level) {
-  if (ENABLE_GPIO_SIDETONE) {
-    digitalWrite(SIDETONE_GPIO, level);
-  }
-}
-#endif
-
-int gpio_init() {
-
-  fprintf(stderr,"gpio_wiringpi: gpio_init\n");
-
-  gpio_restore_state();
-
-  wiringPiSetup(); // use WiringPi pin numbers
-
-  if(ENABLE_VFO_ENCODER) {
-#ifdef VFO_HAS_FUNCTION
-    setup_pin(VFO_FUNCTION, PUD_UP, &vfoFunctionAlert);
-    vfoFunction=0;
-#endif
-    setup_encoder_pin(VFO_ENCODER_A,ENABLE_VFO_PULLUP?PUD_UP:PUD_DOWN,&vfoEncoderInt);
-    setup_encoder_pin(VFO_ENCODER_B,ENABLE_VFO_PULLUP?PUD_UP:PUD_DOWN,NULL);
-    vfoEncoderPos=0;
-  }
-
-  if(ENABLE_E2_ENCODER) {
-    setup_pin(E2_FUNCTION, PUD_UP, &e2FunctionAlert);
-         
-    setup_encoder_pin(E2_ENCODER_A,ENABLE_E2_PULLUP?PUD_UP:PUD_OFF,&e2EncoderInt);
-    setup_encoder_pin(E2_ENCODER_B,ENABLE_E2_PULLUP?PUD_UP:PUD_OFF,NULL);
-    e2EncoderPos=0;
-
-
-    if(controller==CONTROLLER2_V2) {
-      setup_encoder_pin(E2_TOP_ENCODER_A,ENABLE_E2_PULLUP?PUD_UP:PUD_OFF,&e2TopEncoderInt);
-      setup_encoder_pin(E2_TOP_ENCODER_B,ENABLE_E2_PULLUP?PUD_UP:PUD_OFF,NULL);
-      e2TopEncoderPos=0;
-    }
-  }
-
-  if(ENABLE_E3_ENCODER) {
-    setup_pin(E3_FUNCTION, PUD_UP, &e3FunctionAlert);
-       
-    setup_encoder_pin(E3_ENCODER_A,ENABLE_E3_PULLUP?PUD_UP:PUD_OFF,&e3EncoderInt);
-    setup_encoder_pin(E3_ENCODER_B,ENABLE_E3_PULLUP?PUD_UP:PUD_OFF,NULL);
-    e3EncoderPos=0;
-
-    if(controller==CONTROLLER2_V2) {
-      setup_encoder_pin(E3_TOP_ENCODER_A,ENABLE_E3_PULLUP?PUD_UP:PUD_OFF,&e3TopEncoderInt);
-      setup_encoder_pin(E3_TOP_ENCODER_B,ENABLE_E3_PULLUP?PUD_UP:PUD_OFF,NULL);
-      e3TopEncoderPos=0;
-    }
-  }
-
-
-  if(ENABLE_E4_ENCODER) {
-    setup_pin(E4_FUNCTION, PUD_UP, &e4FunctionAlert);
-         
-    setup_encoder_pin(E4_ENCODER_A,ENABLE_E4_PULLUP?PUD_UP:PUD_OFF,&e4EncoderInt);
-    setup_encoder_pin(E4_ENCODER_B,ENABLE_E4_PULLUP?PUD_UP:PUD_OFF,NULL);
-    e4EncoderPos=0;
-         
-    if(controller==CONTROLLER2_V2) {
-      setup_encoder_pin(E4_TOP_ENCODER_A,ENABLE_E4_PULLUP?PUD_UP:PUD_OFF,&e4TopEncoderInt);
-      setup_encoder_pin(E4_TOP_ENCODER_B,ENABLE_E4_PULLUP?PUD_UP:PUD_OFF,NULL);
-      e4TopEncoderPos=0;
-    }
-  }
-
-  if(controller==CONTROLLER2_V1 || controller==CONTROLLER2_V2) {
-    if(ENABLE_E5_ENCODER) {
-      setup_pin(E5_FUNCTION, PUD_UP, &e5FunctionAlert);
-
-      setup_encoder_pin(E5_ENCODER_A,ENABLE_E5_PULLUP?PUD_UP:PUD_OFF,&e5EncoderInt);
-      setup_encoder_pin(E5_ENCODER_B,ENABLE_E5_PULLUP?PUD_UP:PUD_OFF,NULL);
-      e5EncoderPos=0;
-
-      if(controller==CONTROLLER2_V2) {
-        setup_encoder_pin(E5_TOP_ENCODER_A,ENABLE_E5_PULLUP?PUD_UP:PUD_OFF,&e5TopEncoderInt);
-        setup_encoder_pin(E5_TOP_ENCODER_B,ENABLE_E5_PULLUP?PUD_UP:PUD_OFF,NULL);
-        e5TopEncoderPos=0;
-      }
-    }
-  }
-
-  if(controller==CONTROLLER1){
-    if(ENABLE_FUNCTION_BUTTON) {
-      setup_pin(FUNCTION_BUTTON, PUD_UP, &functionAlert);
-    }
-  
-    if(ENABLE_MOX_BUTTON) {
-      setup_pin(MOX_BUTTON, PUD_UP, &moxAlert);
-    }
-  
-    if(ENABLE_S1_BUTTON) {
-      setup_pin(S1_BUTTON, PUD_UP, &s1Alert);
-    }
-  
-    if(ENABLE_S2_BUTTON) {
-      setup_pin(S2_BUTTON, PUD_UP, &s2Alert);
-    }
-  
-    if(ENABLE_S3_BUTTON) {
-      setup_pin(S3_BUTTON, PUD_UP, &s3Alert);
-    }
-  
-    if(ENABLE_S4_BUTTON) {
-      setup_pin(S4_BUTTON, PUD_UP, &s4Alert);
-    }
-  
-    if(ENABLE_S5_BUTTON) {
-      setup_pin(S5_BUTTON, PUD_UP, &s5Alert);
-    }
-  
-    if(ENABLE_S6_BUTTON) {
-      setup_pin(S6_BUTTON, PUD_UP, &s6Alert);
-    }
-  }
-
-  rotary_encoder_thread_id = g_thread_new( "encoders", rotary_encoder_thread, NULL);
-  if( ! rotary_encoder_thread_id )
-  {
-    fprintf(stderr,"g_thread_new failed on rotary_encoder_thread\n");
-    exit( -1 );
-  }
-  fprintf(stderr, "rotary_encoder_thread: id=%p\n",rotary_encoder_thread_id);
-
-  if(controller==CONTROLLER2_V1 || controller==CONTROLLER2_V2) {
-    // setup i2c
-    i2c_init();
-
-    // setup interrupt pin
-    fprintf(stderr,"setup i2c interrupt: pin=%d\n",I2C_INTERRUPT);
-    pinMode(I2C_INTERRUPT,INPUT);
-    pullUpDnControl(I2C_INTERRUPT,PUD_UP);
-    usleep(10000);
-    wiringPiISR(I2C_INTERRUPT,INT_EDGE_BOTH,pI2CInterrupt);
-  }
-
-#ifdef LOCALCW
-  fprintf(stderr,"GPIO: ENABLE_CW_BUTTONS=%d  CWL_BUTTON=%d CWR_BUTTON=%d\n", ENABLE_CW_BUTTONS, CWL_BUTTON, CWR_BUTTON);
-  if(ENABLE_CW_BUTTONS) {      
-    setup_cw_pin(CWL_BUTTON, cwAlert_left);
-    setup_cw_pin(CWR_BUTTON, cwAlert_right);
-  }
-  if (ENABLE_GPIO_SIDETONE) {
-//
-//  use this pin as an output pin and
-//  set its value to LOW
-//
-    pinMode(SIDETONE_GPIO, OUTPUT);
-    digitalWrite(SIDETONE_GPIO, 0);
-  }
-#endif
-
-#ifdef PTT
-  if(ENABLE_PTT_GPIO) {
-g_print("PTT Enabled: setup pin %d active_low=%d\n",PTT_GPIO,PTT_ACTIVE_LOW);
-    setup_pin(PTT_GPIO,PTT_ACTIVE_LOW?PUD_UP:PUD_DOWN,pttAlert);
-  }
-#endif
-
-  return 0;
-}
-
-void gpio_close() {
-    running=0;
-}
-
-int vfo_encoder_get_pos() {
-  int pos=vfoEncoderPos;
-
-  if(vfo_encoder_divisor>1) {
-    if(pos<0 && pos>-vfo_encoder_divisor) {
-        pos=0;
-    } else if(pos>0 && pos<vfo_encoder_divisor) {
-        pos=0;
-    }
-    pos=pos/vfo_encoder_divisor;
-    vfoEncoderPos=vfoEncoderPos-(pos*vfo_encoder_divisor);
-  } else {
-    vfoEncoderPos=0;
-  }
-  return pos;
-}
-
-int e2_encoder_get_pos() {
-    int pos=e2EncoderPos;
-    e2EncoderPos=0;
-    return pos;
-}
-
-int e3_encoder_get_pos() {
-    int pos=e3EncoderPos;
-    e3EncoderPos=0;
-    return pos;
-}
-
-int e4_encoder_get_pos() {
-    int pos=e4EncoderPos;
-    e4EncoderPos=0;
-    return pos;
-}
-
-int e5_encoder_get_pos() {
-    int pos=e5EncoderPos;
-    e5EncoderPos=0;
-    return pos;
-}
-
-int e4_function_get_state() {
-    return e4_sw_action;
-}
-
-int e2_top_encoder_get_pos() {
-    int pos=e2TopEncoderPos;
-    e2TopEncoderPos=0;
-    return pos;
-}
-
-int e3_top_encoder_get_pos() {
-    int pos=e3TopEncoderPos;
-    e3TopEncoderPos=0;
-    return pos;
-}
-
-int e4_top_encoder_get_pos() {
-    int pos=e4TopEncoderPos;
-    e4TopEncoderPos=0;
-    return pos;
-}
-
-int e5_top_encoder_get_pos() {
-    int pos=e5TopEncoderPos;
-    e5TopEncoderPos=0;
-    return pos;
-}
-
-int function_get_state() {
-    return function_state;
-}
-
-int band_get_state() {
-    return band_state;
-}
-
-int bandstack_get_state() {
-    return bandstack_state;
-}
-
-int mode_get_state() {
-    return mode_state;
-}
-
-int filter_get_state() {
-    return filter_state;
-}
-
-int noise_get_state() {
-    return noise_state;
-}
-
-int agc_get_state() {
-    return agc_state;
-}
-
-int mox_get_state() {
-    return mox_state;
-}
-
-int lock_get_state() {
-    return lock_state;
-}
-
-
-static int vfo_encoder_changed(void *data) {
-  if(!locked) {
-    int pos=(int)data;
-    vfo_step(pos);
-  }
-  //free(data);
-  return 0;
-}
-
-static void encoder_changed(int action,int pos) {
-  double value;
-  int mode;
-  int id;
-  FILTER * band_filters=filters[vfo[active_receiver->id].mode];
-  FILTER *band_filter;
-  FILTER *filter;
-  int new_val;
-
-  switch(action) {
-    case ENCODER_AF_GAIN:
-      value=active_receiver->volume;
-      value+=(double)pos/100.0;
-      if(value<0.0) {
-        value=0.0;
-      } else if(value>1.0) {
-        value=1.0;
-      }
-      set_af_gain(active_receiver->id,value);
-      break;
-    case ENCODER_AF_GAIN_RX1:
-      value=receiver[0]->volume;
-      value+=(double)pos/100.0;
-      if(value<0.0) {
-        value=0.0;
-      } else if(value>1.0) {
-        value=1.0;
-      }
-      set_af_gain(0,value);
-      break;
-    case ENCODER_AF_GAIN_RX2:
-      value=receiver[1]->volume;
-      value+=(double)pos/100.0;
-      if(value<0.0) {
-        value=0.0;
-      } else if(value>1.0) {
-        value=1.0;
-      }
-      set_af_gain(1,value);
-      break;
-    case ENCODER_RF_GAIN:
-      value=active_receiver->rf_gain;
-      value+=(double)pos;
-      if(value<0.0) {
-        value=0.0;
-      } else if(value>100.0) {
-        value=100.0;
-      }
-      set_rf_gain(active_receiver->id,value);
-      break;
-    case ENCODER_RF_GAIN_RX1:
-      value=receiver[0]->rf_gain;
-      value+=(double)pos;
-      if(value<0.0) {
-        value=0.0;
-      } else if(value>100.0) {
-        value=100.0;
-      }
-      set_rf_gain(0,value);
-      break;
-    case ENCODER_RF_GAIN_RX2:
-      value=receiver[1]->rf_gain;
-      value+=(double)pos;
-      if(value<0.0) {
-        value=0.0;
-      } else if(value>71.0) {
-        value=71.0;
-      }
-      set_rf_gain(1,value);
-      break;
-    case ENCODER_AGC_GAIN:
-      value=active_receiver->agc_gain;
-      value+=(double)pos;
-      if(value<-20.0) {
-        value=-20.0;
-      } else if(value>120.0) {
-        value=120.0;
-      }
-      set_agc_gain(active_receiver->id,value);
-      break;
-    case ENCODER_AGC_GAIN_RX1:
-      value=receiver[0]->agc_gain;
-      value+=(double)pos;
-      if(value<-20.0) {
-        value=-20.0;
-      } else if(value>120.0) {
-        value=120.0;
-      }
-      set_agc_gain(0,value);
-      break;
-    case ENCODER_AGC_GAIN_RX2:
-      value=receiver[1]->agc_gain;
-      value+=(double)pos;
-      if(value<-20.0) {
-        value=-20.0;
-      } else if(value>120.0) {
-        value=120.0;
-      }
-      set_agc_gain(1,value);
-      break;
-    case ENCODER_IF_WIDTH:
-      filter_width_changed(active_receiver->id,pos);
-      break;
-    case ENCODER_IF_WIDTH_RX1:
-      filter_width_changed(0,pos);
-      break;
-    case ENCODER_IF_WIDTH_RX2:
-      filter_width_changed(1,pos);
-      break;
-    case ENCODER_IF_SHIFT:
-      filter_shift_changed(active_receiver->id,pos);
-      break;
-    case ENCODER_IF_SHIFT_RX1:
-      filter_shift_changed(0,pos);
-      break;
-    case ENCODER_IF_SHIFT_RX2:
-      filter_shift_changed(1,pos);
-      break;
-    case ENCODER_ATTENUATION:
-      value=(double)adc_attenuation[active_receiver->adc];
-      value+=(double)pos;
-      if(have_rx_gain) {
-        if(value<-12.0) {
-          value=-12.0;
-        } else if(value>48.0) {
-          value=48.0;
-        }
-      } else {
-        if(value<0.0) {
-          value=0.0;
-        } else if (value>31.0) {
-          value=31.0;
-        }      
-      }
-      set_attenuation_value(value);
-      break;
-    case ENCODER_MIC_GAIN:
-      value=mic_gain;
-      value+=(double)pos;
-      if(value<-12.0) {
-        value=-12.0;
-      } else if(value>50.0) {
-        value=50.0;
-      }
-      set_mic_gain(value);
-      break;
-    case ENCODER_DRIVE:
-      value=getDrive();
-      value+=(double)pos;
-      if(value<0.0) {
-        value=0.0;
-      } else if(value>drive_max) {
-        value=drive_max;
-      }
-      set_drive(value);
-      break;
-    case ENCODER_RIT:
-      vfo_rit(active_receiver->id,pos);
-      break;
-    case ENCODER_RIT_RX1:
-      vfo_rit(receiver[0]->id,pos);
-      break;
-    case ENCODER_RIT_RX2:
-      vfo_rit(receiver[1]->id,pos);
-      break;
-    case ENCODER_XIT:
-      value=(double)transmitter->xit;
-      value+=(double)(pos*rit_increment);
-      if(value<-10000.0) {
-        value=-10000.0;
-      } else if(value>10000.0) {
-        value=10000.0;
-      }
-      transmitter->xit=(int)value;
-      if(protocol==NEW_PROTOCOL) {
-        schedule_high_priority();
-      }
-      g_idle_add(ext_vfo_update,NULL);
-      break;
-    case ENCODER_CW_SPEED:
-      value=(double)cw_keyer_speed;
-      value+=(double)pos;
-      if(value<1.0) {
-        value=1.0;
-      } else if(value>60.0) {
-        value=60.0;
-      }
-      cw_keyer_speed=(int)value;
-      g_idle_add(ext_vfo_update,NULL);
-      break;
-    case ENCODER_CW_FREQUENCY:
-      value=(double)cw_keyer_sidetone_frequency;
-      value+=(double)pos;
-      if(value<0.0) {
-        value=0.0;
-      } else if(value>1000.0) {
-        value=1000.0;
-      }
-      cw_keyer_sidetone_frequency=(int)value;
-      g_idle_add(ext_vfo_update,NULL);
-      break;
-    case ENCODER_PANADAPTER_HIGH:
-      value=(double)active_receiver->panadapter_high;
-      value+=(double)pos;
-      active_receiver->panadapter_high=(int)value;
-      break;
-    case ENCODER_PANADAPTER_LOW:
-      value=(double)active_receiver->panadapter_low;
-      value+=(double)pos;
-      active_receiver->panadapter_low=(int)value;
-      break;
-    case ENCODER_PANADAPTER_STEP:
-      value=(double)active_receiver->panadapter_step;
-      value+=(double)pos;
-      active_receiver->panadapter_step=(int)value;
-      break;
-    case ENCODER_WATERFALL_HIGH:
-      value=(double)active_receiver->waterfall_high;
-      value+=(double)pos;
-      active_receiver->waterfall_high=(int)value;
-      break;
-    case ENCODER_WATERFALL_LOW:
-      value=(double)active_receiver->waterfall_low;
-      value+=(double)pos;
-      active_receiver->waterfall_low=(int)value;
-      break;
-    case ENCODER_SQUELCH:
-      value=active_receiver->squelch;
-      value+=(double)pos;
-      if(value<0.0) {
-        value=0.0;
-      } else if(value>100.0) {
-        value=100.0;
-      }
-      active_receiver->squelch=value;
-      set_squelch(active_receiver);
-      break;
-    case ENCODER_SQUELCH_RX1:
-      value=receiver[0]->squelch;
-      value+=(double)pos;
-      if(value<0.0) {
-        value=0.0;
-      } else if(value>100.0) {
-        value=100.0;
-      }
-      receiver[0]->squelch=value;
-      set_squelch(receiver[0]);
-      break;
-    case ENCODER_SQUELCH_RX2:
-      value=receiver[1]->squelch;
-      value+=(double)pos;
-      if(value<0.0) {
-        value=0.0;
-      } else if(value>100.0) {
-        value=100.0;
-      }
-      receiver[1]->squelch=value;
-      set_squelch(receiver[1]);
-      break;
-    case ENCODER_COMP:
-      value=(double)transmitter->compressor_level;
-      value+=(double)pos;
-      if(value<0.0) {
-        value=0.0;
-      } else if(value>20.0) {
-        value=20.0;
-      }
-      transmitter->compressor_level=(int)value;
-      set_compression(transmitter);
-      break;
-    case ENCODER_DIVERSITY_GAIN:
-      update_diversity_gain((double)pos * 0.5);
-      break;
-    case ENCODER_DIVERSITY_GAIN_COARSE:
-      update_diversity_gain((double)pos * 2.5);
-      break;
-    case ENCODER_DIVERSITY_GAIN_FINE:
-      update_diversity_gain((double)pos * 0.1);
-      break;
-    case ENCODER_DIVERSITY_PHASE:
-      update_diversity_phase((double)pos* 0.5);
-      break;
-    case ENCODER_DIVERSITY_PHASE_COARSE:
-      update_diversity_phase((double)pos*2.5);
-      break;
-    case ENCODER_DIVERSITY_PHASE_FINE:
-      update_diversity_phase((double)pos*0.1);
-      break;
-    case ENCODER_ZOOM:
-      update_zoom((double)pos);
-      break;
-    case ENCODER_PAN:
-      update_pan((double)pos*100);
-      break;
-  }
-}
-
-static int e2_encoder_changed(void *data) {
-  int pos=(int)data;
-  if(active_menu==E2_MENU) {
-    encoder_select(pos);
-  } else {
-    encoder_changed(e2_encoder_action,pos);
-  }
-  return 0;
-}
-
-static int e3_encoder_changed(void *data) {
-  int pos=(int)data;
-  if(active_menu==E3_MENU) {
-    encoder_select(pos);
-  } else {
-    encoder_changed(e3_encoder_action,pos);
-  }
-  return 0;
-}
-
-static int e4_encoder_changed(void *data) {
-  int pos=(int)data;
-  if(active_menu==E4_MENU) {
-    encoder_select(pos);
-  } else {
-    encoder_changed(e4_encoder_action,pos);
-  }
-  return 0;
-}
-
-static int e5_encoder_changed(void *data) {
-  int pos=(int)data;
-  if(active_menu==E5_MENU) {
-    encoder_select(pos);
-  } else {
-    encoder_changed(e5_encoder_action,pos);
-  }
-  return 0;
-}
-
-
-static int e2_top_encoder_changed(void *data) {
-  int pos=(int)data;
-  if(active_menu==E2_MENU) {
-    encoder_select(pos);
-  } else {
-    encoder_changed(e2_top_encoder_action,pos);
-  }
-  return 0;
-}
-
-static int e3_top_encoder_changed(void *data) {
-  int pos=(int)data;
-  if(active_menu==E3_MENU) {
-    encoder_select(pos);
-  } else {
-    encoder_changed(e3_top_encoder_action,pos);
-  }
-  return 0;
-}
-
-static int e4_top_encoder_changed(void *data) {
-  int pos=(int)data;
-  if(active_menu==E4_MENU) {
-    encoder_select(pos);
-  } else {
-    encoder_changed(e4_top_encoder_action,pos);
-  }
-  return 0;
-}
-
-static int e5_top_encoder_changed(void *data) {
-  int pos=(int)data;
-  if(active_menu==E5_MENU) {
-    encoder_select(pos);
-  } else {
-    encoder_changed(e5_top_encoder_action,pos);
-  }
-  return 0;
-}
-
-static gpointer rotary_encoder_thread(gpointer data) {
-    int pos;
-
-    sleep(2);
-
-    running=1;
-    while(1) {
-
-        pos=vfo_encoder_get_pos();
-        if(pos!=0) {
-            g_idle_add(vfo_encoder_changed,(gpointer)pos);
-        }
-
-        pos=e2_encoder_get_pos();
-        if(pos!=0) {
-            g_idle_add(e2_encoder_changed,(gpointer)pos);
-        }
-
-        pos=e3_encoder_get_pos();
-        if(pos!=0) {
-            g_idle_add(e3_encoder_changed,(gpointer)pos);
-        }
-
-        pos=e4_encoder_get_pos();
-        if(pos!=0) {
-            g_idle_add(e4_encoder_changed,(gpointer)pos);
-        }
-
-        if(controller==CONTROLLER2_V1 || controller==CONTROLLER2_V2) {
-          pos=e5_encoder_get_pos();
-          if(pos!=0) {
-              g_idle_add(e5_encoder_changed,(gpointer)pos);
-          }
-        }
-
-         
-        if(controller==CONTROLLER2_V2) {
-          pos=e2_top_encoder_get_pos();
-          if(pos!=0) {
-              g_idle_add(e2_top_encoder_changed,(gpointer)pos);
-          }
-  
-          pos=e3_top_encoder_get_pos();
-          if(pos!=0) {
-              g_idle_add(e3_top_encoder_changed,(gpointer)pos);
-          }
-  
-          pos=e4_top_encoder_get_pos();
-          if(pos!=0) {
-              g_idle_add(e4_top_encoder_changed,(gpointer)pos);
-          }
-  
-          pos=e5_top_encoder_get_pos();
-          if(pos!=0) {
-            g_idle_add(e5_top_encoder_changed,(gpointer)pos);
-          }
-        }
-
-#ifdef sx1509
-        // buttons only generate interrupt when
-        // pushed onODER_AF_GAIN = 0,
-        function_state = 0;
-        band_state = 0;
-        bandstack_state = 0;
-        mode_state = 0;
-        filter_state = 0;
-        noise_state = 0;
-        agc_state = 0;
-        mox_state = 0;
-        lock_state = 0;
 #endif
-        if(running==0) {
-          fprintf(stderr,"gpio_thread: quitting (running==0)\n");
-          g_thread_exit(NULL);
-        }
-        usleep(100000);
-
-    }
-    return NULL;
-}
diff --git a/gpio.h b/gpio.h
index b15d8a0e15ad46ef0753de4b4f63c76665d9253e..855984e9cf2a68de2a22dfca94b3174813e35ee5 100644 (file)
--- a/gpio.h
+++ b/gpio.h
 #ifndef _GPIO_H
 #define _GPIO_H
 
+#define MAX_ENCODERS 5
+#define MAX_SWITCHES 16
+#define MAX_FUNCTIONS 6
+
 enum {
   NO_CONTROLLER=0,
   CONTROLLER1,
@@ -29,228 +33,50 @@ enum {
 
 extern int controller;
   
-enum {
-  ENCODER_NO_ACTION=0,
-  ENCODER_AF_GAIN,
-  ENCODER_AF_GAIN_RX1,
-  ENCODER_AF_GAIN_RX2,
-  ENCODER_AGC_GAIN,
-  ENCODER_AGC_GAIN_RX1,
-  ENCODER_AGC_GAIN_RX2,
-  ENCODER_ATTENUATION,
-  ENCODER_COMP,
-  ENCODER_CW_FREQUENCY,
-  ENCODER_CW_SPEED,
-  ENCODER_DIVERSITY_GAIN,
-  ENCODER_DIVERSITY_GAIN_COARSE,
-  ENCODER_DIVERSITY_GAIN_FINE,
-  ENCODER_DIVERSITY_PHASE,
-  ENCODER_DIVERSITY_PHASE_COARSE,
-  ENCODER_DIVERSITY_PHASE_FINE,
-  ENCODER_DRIVE,
-  ENCODER_IF_SHIFT,
-  ENCODER_IF_SHIFT_RX1,
-  ENCODER_IF_SHIFT_RX2,
-  ENCODER_IF_WIDTH,
-  ENCODER_IF_WIDTH_RX1,
-  ENCODER_IF_WIDTH_RX2,
-  ENCODER_MIC_GAIN,
-  ENCODER_PAN,
-  ENCODER_PANADAPTER_HIGH,
-  ENCODER_PANADAPTER_LOW,
-  ENCODER_PANADAPTER_STEP,
-  ENCODER_RF_GAIN,
-  ENCODER_RF_GAIN_RX1,
-  ENCODER_RF_GAIN_RX2,
-  ENCODER_RIT,
-  ENCODER_RIT_RX1,
-  ENCODER_RIT_RX2,
-  ENCODER_SQUELCH,
-  ENCODER_SQUELCH_RX1,
-  ENCODER_SQUELCH_RX2,
-  ENCODER_TUNE_DRIVE,
-  ENCODER_WATERFALL_HIGH,
-  ENCODER_WATERFALL_LOW,
-  ENCODER_XIT,
-  ENCODER_ZOOM,
-  ENCODER_ACTIONS
-};
-
-extern char *encoder_string[ENCODER_ACTIONS];
-
-enum {
-  NO_ACTION=0,
-  A_TO_B,
-  A_SWAP_B,
-  AGC,
-  ANF,
-  B_TO_A,
-  BAND_MINUS,
-  BAND_PLUS,
-  BANDSTACK_MINUS,
-  BANDSTACK_PLUS,
-  CTUN,
-  DIVERSITY,
-  FILTER_MINUS,
-  FILTER_PLUS,
-  FUNCTION,
-  LOCK,
-  MENU_BAND,
-  MENU_BANDSTACK,
-  MENU_DIVERSITY,
-  MENU_FILTER,
-  MENU_FREQUENCY,
-  MENU_MEMORY,
-  MENU_MODE,
-  MENU_PS,
-  MODE_MINUS,
-  MODE_PLUS,
-  MOX,
-  MUTE,
-  NB,
-  NR,
-  PAN_MINUS,
-  PAN_PLUS,
-  PS,
-  RIT,
-  RIT_CLEAR,
-  SAT,
-  SNB,
-  SPLIT,
-  TUNE,
-  TWO_TONE,
-  XIT,
-  XIT_CLEAR,
-  ZOOM_MINUS,
-  ZOOM_PLUS,
-  SWITCH_ACTIONS
-};
-
-extern char *sw_string[SWITCH_ACTIONS];
-
-
-enum {
-  CONTROLLER1_SW1=0,
-  CONTROLLER1_SW2,
-  CONTROLLER1_SW3,
-  CONTROLLER1_SW4,
-  CONTROLLER1_SW5,
-  CONTROLLER1_SW6,
-  CONTROLLER1_SW7,
-  CONTROLLER1_SW8,
-  CONTROLLER1_SWITCHES
-};
-
-enum {
-  CONTROLLER2_SW2=0,
-  CONTROLLER2_SW3,
-  CONTROLLER2_SW4,
-  CONTROLLER2_SW5,
-  CONTROLLER2_SW6,
-  CONTROLLER2_SW7,
-  CONTROLLER2_SW8,
-  CONTROLLER2_SW9,
-  CONTROLLER2_SW10,
-  CONTROLLER2_SW11,
-  CONTROLLER2_SW12,
-  CONTROLLER2_SW13,
-  CONTROLLER2_SW14,
-  CONTROLLER2_SW15,
-  CONTROLLER2_SW16,
-  CONTROLLER2_SW17,
-  CONTROLLER2_SWITCHES
-};
+typedef struct _encoder {
+  gboolean bottom_encoder_enabled;
+  gboolean bottom_encoder_pullup;
+  gint bottom_encoder_address_a;
+  gint bottom_encoder_a_value;
+  gint bottom_encoder_address_b;
+  gint bottom_encoder_b_value;
+  gint bottom_encoder_pos;
+  gint bottom_encoder_function;
+  gint top_encoder_enabled;
+  gboolean top_encoder_pullup;
+  gint top_encoder_address_a;
+  gint top_encoder_a_value;
+  gint top_encoder_address_b;
+  gint top_encoder_b_value;
+  gint top_encoder_pos;
+  gint top_encoder_function;
+  gboolean switch_enabled;
+  gboolean switch_pullup;
+  gint switch_address;
+  gint switch_function;
+} ENCODER;
+
+extern ENCODER *encoders;
+
+typedef struct _switch {
+  gboolean switch_enabled;
+  gboolean switch_pullup;
+  gint switch_address;
+  gint switch_function;
+} SWITCH;
+
+extern SWITCH switches_no_controller[MAX_SWITCHES];
+extern SWITCH switches_controller1[MAX_FUNCTIONS][MAX_SWITCHES];
+extern SWITCH switches_controller2_v1[MAX_SWITCHES];
+extern SWITCH switches_controller2_v2[MAX_SWITCHES];
+
+extern SWITCH *switches;
 
 extern int *sw_action;
 
-extern int settle_time;
-
-
-extern int e2_encoder_action;
-extern int e3_encoder_action;
-extern int e4_encoder_action;
-extern int e5_encoder_action;
-
-extern int e2_top_encoder_action;
-extern int e3_top_encoder_action;
-extern int e4_top_encoder_action;
-extern int e5_top_encoder_action;
-
-extern int e2_sw_action;
-extern int e3_sw_action;
-extern int e4_sw_action;
-extern int e5_sw_action;
-
-// uses wiringpi pin numbers
-extern int ENABLE_VFO_ENCODER;
-extern int ENABLE_VFO_PULLUP;
-extern int VFO_ENCODER_A;
-extern int VFO_ENCODER_B;
-extern int ENABLE_E2_ENCODER;
-extern int ENABLE_E2_PULLUP;
-extern int E2_ENCODER_A;
-extern int E2_ENCODER_B;
-extern int E2_TOP_ENCODER_A;
-extern int E2_TOP_ENCODER_B;
-extern int E2_FUNCTION;
-extern int ENABLE_E3_ENCODER;
-extern int ENABLE_E3_PULLUP;
-extern int E3_ENCODER_A;
-extern int E3_ENCODER_B;
-extern int E3_TOP_ENCODER_A;
-extern int E3_TOP_ENCODER_B;
-extern int E3_FUNCTION;
-extern int ENABLE_E4_ENCODER;
-extern int ENABLE_E4_PULLUP;
-extern int E4_ENCODER_A;
-extern int E4_ENCODER_B;
-extern int E4_TOP_ENCODER_A;
-extern int E4_TOP_ENCODER_B;
-extern int E4_FUNCTION;
-extern int ENABLE_E5_ENCODER;
-extern int ENABLE_E5_PULLUP;
-extern int E5_ENCODER_A;
-extern int E5_ENCODER_B;
-extern int E5_TOP_ENCODER_A;
-extern int E5_TOP_ENCODER_B;
-extern int E5_FUNCTION;
-
-extern int ENABLE_S1_BUTTON;
-extern int S1_BUTTON;
-extern int ENABLE_S2_BUTTON;
-extern int S2_BUTTON;
-extern int ENABLE_S3_BUTTON;
-extern int S3_BUTTON;
-extern int ENABLE_S4_BUTTON;
-extern int S4_BUTTON;
-extern int ENABLE_S5_BUTTON;
-extern int S5_BUTTON;
-extern int ENABLE_S6_BUTTON;
-extern int S6_BUTTON;
-
-extern int ENABLE_MOX_BUTTON;
-extern int MOX_BUTTON;
-extern int ENABLE_FUNCTION_BUTTON;
-extern int FUNCTION_BUTTON;
-#ifdef LOCALCW
-extern int CWL_BUTTON;
-extern int CWR_BUTTON;
-extern int SIDETONE_GPIO;
-extern int ENABLE_GPIO_SIDETONE;
-extern int ENABLE_CW_BUTTONS;
-extern int CW_ACTIVE_LOW;
-extern void gpio_cw_sidetone_set(int level);
-extern int  gpio_left_cw_key();
-extern int  gpio_right_cw_key();
-extern int  gpio_cw_sidetone_enabled();
-#endif
-
-#ifdef PTT
-extern int ENABLE_PTT_GPIO;
-extern int PTT_GPIO;
-extern int PTT_ACTIVE_LOW;
-#endif
+extern long settle_time;
 
+extern int process_function_switch(void *data);
 extern void gpio_set_defaults(int ctrlr);
 extern void gpio_restore_actions();
 extern void gpio_restore_state();
@@ -258,16 +84,4 @@ extern void gpio_save_state();
 extern void gpio_save_actions();
 extern int gpio_init();
 extern void gpio_close();
-extern int vfo_encoder_get_pos();
-extern int af_encoder_get_pos();
-extern int af_function_get_state();
-extern int rf_encoder_get_pos();
-extern int rf_function_get_state();
-extern int function_get_state();
-extern int band_get_state();
-extern int mode_get_state();
-extern int filter_get_state();
-extern int noise_get_state();
-extern int mox_get_state();
-
 #endif
diff --git a/i2c.c b/i2c.c
index 7798b8e61264531657f67f676e067b41fb7398b1..b17659b13304474675dc048d556e46da73544d55 100644 (file)
--- a/i2c.c
+++ b/i2c.c
@@ -4,13 +4,13 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <linux/i2c-dev.h>
-//#include <i2c/smbus.h>
+#include <i2c/smbus.h>
 #include <sys/ioctl.h>
 #include <fcntl.h>
 
 #include <gtk/gtk.h>
-//#include "i2c.h"
-#include "wiringPiI2C.h"
+#include "i2c.h"
+#include "actions.h"
 #include "gpio.h"
 #include "band.h"
 #include "band_menu.h"
@@ -47,28 +47,28 @@ unsigned int i2c_sw[16]=
     { SW_2,SW_3,SW_4,SW_5,SW_6,SW_7,SW_8,SW_9,
       SW_10,SW_11,SW_12,SW_13,SW_14,SW_15,SW_16,SW_17 };
 
-static int write_byte_data(unsigned char addr,unsigned char reg, unsigned char data) {
+static int write_byte_data(unsigned char reg, unsigned char data) {
   int rc;
 
-  rc=wiringPiI2CWriteReg8(fd,reg,data);
+  if(i2c_smbus_write_byte_data(fd,reg,data&0xFF)<0) {
+    g_print("%s: write REG_GCONF config failed: addr=%02X %s\n",__FUNCTION__,i2c_address_1,g_strerror(errno));
+  }
   
-  return 0;
+  return rc;
 }
 
-static unsigned char read_byte_data(unsigned char addr,unsigned char reg) {
-  int rc;
-
-  rc=wiringPiI2CReadReg8(fd,reg);
+static unsigned char read_byte_data(unsigned char reg) {
+  __s32 data;
 
-  return rc;
+  data=i2c_smbus_read_byte_data(fd,reg);
+  return data&0xFF;
 }
 
-static unsigned int read_word_data(unsigned char addr,unsigned char reg) {
-  int rc;
-
-  rc=wiringPiI2CReadReg16(fd,reg);
+static unsigned int read_word_data(unsigned char reg) {
+  __s32 data;
 
-  return rc;
+  data=i2c_smbus_read_word_data(fd,reg);
+  return data&0xFFFF;
 }
 
 
@@ -81,9 +81,9 @@ void i2c_interrupt() {
   unsigned int ints;
 
   do {
-    flags=read_word_data(i2c_address_1,0x0E);
+    flags=read_word_data(0x0E);
     if(flags) {
-      ints=read_word_data(i2c_address_1,0x10);
+      ints=read_word_data(0x10);
 //g_print("i2c_interrupt: flags=%04X ints=%04X\n",flags,ints);
       if(ints) {
         int i;
@@ -242,56 +242,61 @@ void i2c_init() {
 
   int flags, ints;
 
-fprintf(stderr,"i2c_init: %s\n",i2c_device);
-
-  fd=wiringPiI2CSetupInterface(i2c_device, i2c_address_1);
+  g_print("%s: open i2c device %s\n",__FUNCTION__,i2c_device);
+  fd=open(i2c_device, O_RDWR);
   if(fd<0) {
-    g_print("i2c_init failed: fd=%d\n",fd);
+    g_print("%s: open i2c device %s failed: %s\n",__FUNCTION__,i2c_device,g_strerror(errno));
+    return;
+  }
+  g_print("%s: open i2c device %s fd=%d\n",__FUNCTION__,i2c_device,fd);
+
+  if (ioctl(fd, I2C_SLAVE, i2c_address_1) < 0) {
+    g_print("%s: ioctl i2c slave %d failed: %s\n",__FUNCTION__,i2c_address_1,g_strerror(errno));
     return;
   }
 
   // setup i2c
-  if(write_byte_data(i2c_address_1,0x0A,0x44)<0) return;
-  if(write_byte_data(i2c_address_1,0x0B,0x44)<0) return;
+  if(write_byte_data(0x0A,0x44)<0) return;
+  if(write_byte_data(0x0B,0x44)<0) return;
 
   // disable interrupt
-  if(write_byte_data(i2c_address_1,0x04,0x00)<0) return;
-  if(write_byte_data(i2c_address_1,0x05,0x00)<0) return;
+  if(write_byte_data(0x04,0x00)<0) return;
+  if(write_byte_data(0x05,0x00)<0) return;
 
   // clear defaults
-  if(write_byte_data(i2c_address_1,0x06,0x00)<0) return;
-  if(write_byte_data(i2c_address_1,0x07,0x00)<0) return;
+  if(write_byte_data(0x06,0x00)<0) return;
+  if(write_byte_data(0x07,0x00)<0) return;
 
   // OLAT
-  if(write_byte_data(i2c_address_1,0x14,0x00)<0) return;
-  if(write_byte_data(i2c_address_1,0x15,0x00)<0) return;
+  if(write_byte_data(0x14,0x00)<0) return;
+  if(write_byte_data(0x15,0x00)<0) return;
 
   // set GPIOA for pullups
-  if(write_byte_data(i2c_address_1,0x0C,0xFF)<0) return;
-  if(write_byte_data(i2c_address_1,0x0D,0xFF)<0) return;
+  if(write_byte_data(0x0C,0xFF)<0) return;
+  if(write_byte_data(0x0D,0xFF)<0) return;
 
   // reverse polarity
-  if(write_byte_data(i2c_address_1,0x02,0xFF)<0) return;
-  if(write_byte_data(i2c_address_1,0x03,0xFF)<0) return;
+  if(write_byte_data(0x02,0xFF)<0) return;
+  if(write_byte_data(0x03,0xFF)<0) return;
 
   // set GPIOA/B for input
-  if(write_byte_data(i2c_address_1,0x00,0xFF)<0) return;
-  if(write_byte_data(i2c_address_1,0x01,0xFF)<0) return;
+  if(write_byte_data(0x00,0xFF)<0) return;
+  if(write_byte_data(0x01,0xFF)<0) return;
 
   // INTCON
-  if(write_byte_data(i2c_address_1,0x08,0x00)<0) return;
-  if(write_byte_data(i2c_address_1,0x09,0x00)<0) return;
+  if(write_byte_data(0x08,0x00)<0) return;
+  if(write_byte_data(0x09,0x00)<0) return;
 
   // setup for an MCP23017 interrupt
-  if(write_byte_data(i2c_address_1,0x04,0xFF)<0) return;
-  if(write_byte_data(i2c_address_1,0x05,0xFF)<0) return;
+  if(write_byte_data(0x04,0xFF)<0) return;
+  if(write_byte_data(0x05,0xFF)<0) return;
 
   // flush any interrupts
   int count=0;
   do {
-    flags=read_word_data(i2c_address_1,0x0E);
+    flags=read_word_data(0x0E);
     if(flags) {
-      ints=read_word_data(i2c_address_1,0x10);
+      ints=read_word_data(0x10);
       fprintf(stderr,"flush interrupt: flags=%04X ints=%04X\n",flags,ints);
       count++;
       if(count==10) {
diff --git a/i2cEncoderLibV2.c b/i2cEncoderLibV2.c
new file mode 100644 (file)
index 0000000..254e473
--- /dev/null
@@ -0,0 +1,915 @@
+//
+//    FILE: i2cEncoderLibV2.h
+// VERSION: 0.1..
+// PURPOSE: Library for I2C Encoder V2 board with Arduino
+// LICENSE: GPL v3 (http://www.gnu.org/licenses/gpl.html)
+//
+// DATASHEET:
+//
+//     URL:
+//
+// AUTHOR:
+//  by Simone Caron
+// Adapted from C++ to C for use on PSOC:
+//  by Rudy De Volder
+
+#include "i2cEncoderLibV2.h"
+#include "CyLib.h"
+#include <project.h>
+#include <stdio.h>
+
+const int max_idx = MAX_IDX;   //Memory reserved for max. xx encoders
+
+struct i2cEnc_         i2cEnc[MAX_IDX];
+uint32_t               last_status;
+
+static char Buffer[120];       //      UART line buffer
+
+       
+uint32_t last_status; // status of last I2C transmission   
+
+// *********************************** Private functions *************************************/
+
+    uint8_t readEncoderByte(uint8_t reg);
+       int16_t readEncoderInt(uint8_t reg);
+       int32_t readEncoderLong(uint8_t reg);
+       float   readEncoderFloat(uint8_t reg);
+    
+       void    writeEncoderByte(uint8_t reg, uint8_t data);
+    
+       void    writeEncoderLong(uint8_t reg, int32_t data);
+       void    writeEncoderFloat(uint8_t reg, float data);
+       void    writeEncoder24bit(uint8_t reg, uint32_t data);
+
+// *********************************** Public functions *************************************/
+
+/* */
+       
+       uint8_t encoder_last_idx  = 0x00;   //Index of the last added encoder
+    uint8_t encoder_activated = 0;   //Index of the current encoder_activated encoder  
+       
+// Constructor:                                       //
+// !!! Call only once to construct the Encoder !!!    //
+bool i2cEnc__init(uint8_t add) {    
+       if (encoder_last_idx < max_idx) {
+               i2cEnc[encoder_last_idx]._add   = add;
+               i2cEnc[encoder_last_idx]._stat  = 0x00;
+               i2cEnc[encoder_last_idx]._stat2 = 0x00;
+               i2cEnc[encoder_last_idx]._gconf = 0x00;
+               // set callback pointers to NULL:
+        for (int event = 0; event < EV_Range; event++) {
+            i2cEnc[encoder_last_idx].call_back[event] = NULL;
+        }
+               encoder_activated   = encoder_last_idx;
+        encoder_last_idx++;
+        return true;
+       } else return false;
+}
+
+// Used for initialize the encoder //
+void i2cEnc__begin(uint8_t conf) {
+
+       writeEncoderByte(REG_GCONF, (uint8_t) conf);
+       i2cEnc[encoder_activated]._gconf = conf;
+}
+
+void i2cEnc__reset(void) {
+       writeEncoderByte(REG_GCONF, (uint8_t) 0x80);
+    CyDelay(1); // Reset takes 400 microseconds to execute
+}
+
+void i2cEnc__SetEvent(int EventType, Callback event) {
+       i2cEnc[encoder_activated].call_back[EventType] = *event;
+}
+
+
+void eventCaller(int EventType) {
+    Callback *event;
+       *event = (Callback) i2cEnc[encoder_activated].call_back[EventType];
+       if (*event != NULL) {
+               (*event) (NULL) ;
+       }       
+}
+
+
+// Return true if the status of the enconder changed, otherwise return false. 
+// It's also calls the callback, when attached //
+bool i2cEnc__updateStatus(void) {
+    
+    //sprintf (Buffer, "\n\rKnob %d: activated", encoder_activated);     
+    //UART_UartPutString(Buffer); 
+    
+    i2cEnc[encoder_activated]._stat = readEncoderByte((uint8_t)REG_ESTATUS);
+       i2cEnc[encoder_activated]._stat2 = 0;
+    //UART_UartPutChar('A');
+       if (i2cEnc[encoder_activated]._stat == 0) {
+        //UART_UartPutChar('B');
+               return false;
+       } else {
+        //UART_UartPutChar('C');
+        sprintf (Buffer, "\n\rDecoder %d: activated", encoder_activated);     
+        UART_UartPutString(Buffer); 
+        //UART_UartPutChar('*');   
+    }
+    //UART_UartPutChar('D');
+    if (i2cEnc[encoder_activated]._stat & PUSHP) {
+               eventCaller (EV_ButtonPush);
+       }
+       if (i2cEnc[encoder_activated]._stat & PUSHR) {
+               eventCaller (EV_ButtonRelease);
+       }
+       if (i2cEnc[encoder_activated]._stat & PUSHD) {
+               eventCaller (EV_ButtonDoublePush);
+       }
+       if (i2cEnc[encoder_activated]._stat & RINC) {
+        
+               eventCaller (EV_Increment);
+               eventCaller (EV_Change);
+       }
+       if (i2cEnc[encoder_activated]._stat & RDEC) {
+               
+        eventCaller (EV_Decrement);
+               eventCaller (EV_Change);
+       }
+       if (i2cEnc[encoder_activated]._stat & RMAX) {
+               eventCaller (EV_Max);
+               eventCaller (EV_MinMax);
+       }
+       if (i2cEnc[encoder_activated]._stat & RMIN) {
+               eventCaller (EV_Min);
+               eventCaller (EV_MinMax);
+       }
+
+       if ((i2cEnc[encoder_activated]._stat & INT_2) != 0) {
+               i2cEnc[encoder_activated]._stat2 = readEncoderByte(REG_I2STATUS);
+               if (i2cEnc[encoder_activated]._stat2 == 0) {
+                       return true;
+               }
+
+               if (i2cEnc[encoder_activated]._stat2 & GP1_POS) {
+                       eventCaller (EV_GP1Rise);
+               }
+               if (i2cEnc[encoder_activated]._stat2 & GP1_NEG) {
+                       eventCaller (EV_GP1Fall);
+               }
+               if (i2cEnc[encoder_activated]._stat2 & GP2_POS) {
+                       eventCaller (EV_GP2Rise);
+               }
+               if (i2cEnc[encoder_activated]._stat2 & GP2_NEG) {
+                       eventCaller (EV_GP2Fall);
+               }
+               if (i2cEnc[encoder_activated]._stat2 & GP3_POS) {
+                       eventCaller (EV_GP3Rise);
+               }
+               if (i2cEnc[encoder_activated]._stat2 & GP3_NEG) {
+                       eventCaller (EV_GP3Fall);
+               }
+               if (i2cEnc[encoder_activated]._stat2 & FADE_INT) {
+                       eventCaller (EV_FadeProcess);
+               }
+       }
+       
+       return true;
+}
+
+// ********************************* Read functions *********************************** //
+
+// Return the GP1 Configuration//
+uint8_t i2cEnc__readGP1conf(void) {
+       return (readEncoderByte(REG_GP1CONF));
+}
+
+// Return the GP1 Configuration//
+uint8_t i2cEnc__readGP2conf(void) {
+       return (readEncoderByte(REG_GP2CONF));
+}
+
+// Return the GP1 Configuration//
+uint8_t i2cEnc__readGP3conf(void) {
+       return (readEncoderByte(REG_GP3CONF));
+}
+
+// Return the INT pin configuration//
+uint8_t i2cEnc__readInterruptConfig(void) {
+       return (readEncoderByte(REG_INTCONF));
+}
+
+// Check if a particular status match, return true is match otherwise false. Before require updateStatus() //
+bool i2cEnc__readStatus_match(enum Int_Status s) {
+       if ((i2cEnc[encoder_activated]._stat & s) != 0) {
+               return true;
+       }
+       return false;
+}
+
+// Return the status of the encoder //
+uint8_t i2cEnc__readStatus(void) {
+       return i2cEnc[encoder_activated]._stat;
+}
+
+// Check if a particular status of the Int2 match, return true is match otherwise false. Before require updateStatus() //
+bool i2cEnc__readInt2_match(Int2_Status s) {
+       if ((i2cEnc[encoder_activated]._stat2 & s) != 0) {
+               return true;
+       }
+       return false;
+}
+
+// Return the Int2 status of the encoder. Before require updateStatus()  //
+uint8_t i2cEnc__readInt2(void) {
+       return i2cEnc[encoder_activated]._stat2;
+}
+
+// Return Fade process status  //
+uint8_t i2cEnc__readFadeStatus(void) {
+       return readEncoderByte(REG_FSTATUS);
+}
+
+// Check if a particular status of the Fade process match, return true is match otherwise false. //
+bool i2cEnc__readFadeStatus_match(Fade_Status s) {
+       if ((readEncoderByte(REG_FSTATUS) & s) == 1)
+               return true;
+
+       return false;
+}
+
+// Return the PWM LED R value  //
+uint8_t i2cEnc__readLEDR(void) {
+       return ((uint8_t) readEncoderByte(REG_RLED));
+}
+
+// Return the PWM LED G value  //
+uint8_t i2cEnc__readLEDG(void) {
+       return ((uint8_t) readEncoderByte(REG_GLED));
+}
+
+// Return the PWM LED B value  //
+uint8_t i2cEnc__readLEDB(void) {
+       return ((uint8_t) readEncoderByte(REG_BLED));
+}
+
+// Return the 32 bit value of the encoder counter  //
+float i2cEnc__readCounterFloat(void) {
+       return (readEncoderFloat(REG_CVALB4));
+}
+
+// Return the 32 bit value of the encoder counter  //
+int32_t i2cEnc__readCounterLong(void) {
+       return ((int32_t) readEncoderLong(REG_CVALB4));
+}
+
+// Return the 16 bit value of the encoder counter  //
+int16_t i2cEnc__readCounterInt(void) {
+       return ((int16_t) readEncoderInt(REG_CVALB2));
+}
+
+// Return the 8 bit value of the encoder counter  //
+int8_t i2cEnc__readCounterByte(void) {
+       return ((int8_t) readEncoderByte(REG_CVALB1));
+}
+
+// Return the Maximum threshold of the counter //
+int32_t i2cEnc__readMax(void) {
+       return ((int32_t) readEncoderLong(REG_CMAXB4));
+}
+
+// Return the Minimum threshold of the counter //
+int32_t i2cEnc__readMin(void) {
+       return ((int32_t) readEncoderLong(REG_CMINB4));
+}
+
+// Return the Maximum threshold of the counter //
+float i2cEnc__readMaxFloat(void) {
+       return (readEncoderFloat(REG_CMAXB4));
+}
+
+// Return the Minimum threshold of the counter //
+float i2cEnc__readMinFloat(void) {
+       return (readEncoderFloat(REG_CMINB4));
+
+}
+
+// Return the Steps increment //
+int32_t i2cEnc__readStep(void) {
+       return (readEncoderInt(REG_ISTEPB4));
+}
+
+// Return the Steps increment, in float variable //
+float i2cEnc__readStepFloat(void) {
+       return (readEncoderFloat(REG_ISTEPB4));
+
+}
+
+// Read GP1 register value //
+uint8_t i2cEnc__readGP1(void) {
+       return (readEncoderByte(REG_GP1REG));
+}
+
+// Read GP2 register value //
+uint8_t i2cEnc__readGP2(void) {
+       return (readEncoderByte(REG_GP2REG));
+}
+
+// Read GP3 register value //
+uint8_t i2cEnc__readGP3(void) {
+       return (readEncoderByte(REG_GP3REG));
+}
+
+// Read Anti-bouncing period register //
+uint8_t i2cEnc__readAntibouncingPeriod(void) {
+       return (readEncoderByte(REG_ANTBOUNC));
+}
+
+// Read Double push period register //
+uint8_t i2cEnc__readDoublePushPeriod(void) {
+       return (readEncoderByte(REG_DPPERIOD));
+}
+
+// Read the fade period of the RGB LED//
+uint8_t i2cEnc__readFadeRGB(void) {
+       return (readEncoderByte(REG_FADERGB));
+}
+
+// Read the fade period of the GP LED//
+uint8_t i2cEnc__readFadeGP(void) {
+       return (readEncoderByte(REG_FADEGP));
+}
+
+// Read the EEPROM memory//
+uint8_t i2cEnc__readEEPROM(uint8_t add) {
+       if (add <= 0x7f) {
+               if ((i2cEnc[encoder_activated]._gconf & EEPROM_BANK1) != 0) {
+                       i2cEnc[encoder_activated]._gconf = i2cEnc[encoder_activated]._gconf & 0xBF;
+                       writeEncoderByte(REG_GCONF, i2cEnc[encoder_activated]._gconf);
+               }
+               return (readEncoderByte((REG_EEPROMS + add)));
+       } else {
+               if ((i2cEnc[encoder_activated]._gconf & EEPROM_BANK1) == 0) {
+                       i2cEnc[encoder_activated]._gconf = i2cEnc[encoder_activated]._gconf | 0x40;
+                       writeEncoderByte(REG_GCONF, i2cEnc[encoder_activated]._gconf);
+               }
+               return (readEncoderByte(add));
+       }
+}
+
+// ********************************* Write functions *********************************** //
+// Write the GP1 configuration//
+void i2cEnc__writeGP1conf(uint8_t gp1) {
+       writeEncoderByte(REG_GP1CONF, (uint8_t) gp1);
+}
+
+// Write the GP2 configuration//
+void i2cEnc__writeGP2conf(uint8_t gp2) {
+       writeEncoderByte(REG_GP2CONF, (uint8_t) gp2);
+}
+
+// Write the GP3 configuration//
+void i2cEnc__writeGP3conf(uint8_t gp3) {
+       writeEncoderByte(REG_GP3CONF, (uint8_t) gp3);
+}
+
+// Write the interrupt configuration //
+void i2cEnc__writeInterruptConfig(uint8_t interrupt) {
+       writeEncoderByte(REG_INTCONF, (uint8_t) interrupt);
+}
+
+
+// Check if there is some attached callback and enable the corresponding interrupt //
+void i2cEnc__autoconfigInterrupt(void) {
+       uint8_t reg = 0;
+
+       if (i2cEnc[encoder_activated].call_back[EV_ButtonRelease] != NULL)
+               reg |= PUSHR;
+
+       if (i2cEnc[encoder_activated].call_back[EV_ButtonPush] != NULL)
+               reg |= PUSHP;
+
+       if (i2cEnc[encoder_activated].call_back[EV_ButtonDoublePush] != NULL)
+               reg |= PUSHD;
+
+       if (i2cEnc[encoder_activated].call_back[EV_Increment] != NULL)
+               reg |= RINC;
+
+       if (i2cEnc[encoder_activated].call_back[EV_Decrement] != NULL)
+               reg |= RDEC;
+
+       if (i2cEnc[encoder_activated].call_back[EV_Change] != NULL) {
+               reg |= RINC;
+               reg |= RDEC;
+       }
+
+       if (i2cEnc[encoder_activated].call_back[EV_Max] != NULL)
+               reg |= RMAX;
+
+       if (i2cEnc[encoder_activated].call_back[EV_Min] != NULL)
+               reg |= RMIN;
+
+       if (i2cEnc[encoder_activated].call_back[EV_MinMax] != NULL) {
+               reg |= RMAX;
+               reg |= RMIN;
+       }
+
+       if (i2cEnc[encoder_activated].call_back[EV_GP1Rise] != NULL)
+               reg |= INT_2;
+
+       if (i2cEnc[encoder_activated].call_back[EV_GP1Fall] != NULL)
+               reg |= INT_2;
+
+       if (i2cEnc[encoder_activated].call_back[EV_GP2Rise] != NULL)
+               reg |= INT_2;
+
+       if (i2cEnc[encoder_activated].call_back[EV_GP2Fall] != NULL)
+               reg |= INT_2;
+
+       if (i2cEnc[encoder_activated].call_back[EV_GP3Rise] != NULL)
+               reg |= INT_2;
+
+       if (i2cEnc[encoder_activated].call_back[EV_GP3Fall] != NULL)
+               reg |= INT_2;
+
+       if (i2cEnc[encoder_activated].call_back[EV_FadeProcess] != NULL)
+               reg |= INT_2;
+
+       writeEncoderByte(REG_INTCONF, (uint8_t) reg);
+
+}
+
+
+// Write the counter value //
+void i2cEnc__writeCounter_i(int32_t value) {
+       writeEncoderLong(REG_CVALB4, value);
+}
+
+// Write the counter value //
+void i2cEnc__writeCounter_f(float value) {
+       writeEncoderFloat(REG_CVALB4, value);
+}
+
+// Write the maximum threshold value //
+void i2cEnc__writeMax_i(int32_t max) {
+       writeEncoderLong(REG_CMAXB4, max);
+}
+
+// Write the maximum threshold value //
+void i2cEnc__writeMax_f(float max) {
+       writeEncoderFloat(REG_CMAXB4, max);
+}
+
+// Write the minimum threshold value //
+void i2cEnc__writeMin_i(int32_t min) {
+       writeEncoderLong(REG_CMINB4, min);
+}
+
+// Write the minimum threshold value //
+void i2cEnc__writeMin_f(float min) {
+       writeEncoderFloat(REG_CMINB4, min);
+}
+
+// Write the Step increment value //
+void i2cEnc__writeStep_i(int32_t step) {
+       writeEncoderLong(REG_ISTEPB4, step);
+}
+
+// Write the Step increment value //
+void i2cEnc__writeStep_f(float step) {
+       writeEncoderFloat(REG_ISTEPB4, step);
+}
+
+// Write the PWM value of the RGB LED red //
+void i2cEnc__writeLEDR(uint8_t rled) {
+       writeEncoderByte(REG_RLED, rled);
+}
+
+// Write the PWM value of the RGB LED green //
+void i2cEnc__writeLEDG(uint8_t gled) {
+       writeEncoderByte(REG_GLED, gled);
+}
+
+// Write the PWM value of the RGB LED blue //
+void i2cEnc__writeLEDB(uint8_t bled) {
+       writeEncoderByte(REG_BLED, bled);
+}
+
+// Write 24bit color code //
+void i2cEnc__writeRGBCode(uint32_t rgb) {
+       writeEncoder24bit(REG_RLED, rgb);
+}
+
+// Write GP1 register, used when GP1 is set to output or PWM //
+void i2cEnc__writeGP1(uint8_t gp1) {
+       writeEncoderByte(REG_GP1REG, gp1);
+}
+
+// Write GP2 register, used when GP2 is set to output or PWM //
+void i2cEnc__writeGP2(uint8_t gp2) {
+       writeEncoderByte(REG_GP2REG, gp2);
+}
+
+// Write GP3 register, used when GP3 is set to output or PWM //
+void i2cEnc__writeGP3(uint8_t gp3) {
+       writeEncoderByte(REG_GP3REG, gp3);
+}
+
+// Write Anti-bouncing period register //
+void i2cEnc__writeAntibouncingPeriod(uint8_t bounc) {
+       writeEncoderByte(REG_ANTBOUNC, bounc);
+}
+
+// Write Anti-bouncing period register //
+void i2cEnc__writeDoublePushPeriod(uint8_t dperiod) {
+       writeEncoderByte(REG_DPPERIOD, dperiod);
+}
+
+// Write Fade timing in ms //
+void i2cEnc__writeFadeRGB(uint8_t fade) {
+       writeEncoderByte(REG_FADERGB, fade);
+}
+
+// Write Fade timing in ms //
+void i2cEnc__writeFadeGP(uint8_t fade) {
+       writeEncoderByte(REG_FADEGP, fade);
+}
+
+// Write the EEPROM memory//
+void i2cEnc__writeEEPROM(uint8_t add, uint8_t data) {
+
+       if (add <= 0x7f) {
+               if ((i2cEnc[encoder_activated]._gconf & EEPROM_BANK1) != 0) {
+                       i2cEnc[encoder_activated]._gconf = i2cEnc[encoder_activated]._gconf & 0xBF;
+                       writeEncoderByte(REG_GCONF, i2cEnc[encoder_activated]._gconf);
+               }
+               writeEncoderByte((REG_EEPROMS + add), data);
+       } else {
+               if ((i2cEnc[encoder_activated]._gconf & EEPROM_BANK1) == 0) {
+                       i2cEnc[encoder_activated]._gconf = i2cEnc[encoder_activated]._gconf | 0x40;
+                       writeEncoderByte(REG_GCONF, i2cEnc[encoder_activated]._gconf);
+               }
+               writeEncoderByte(add, data);
+       }
+
+       CyDelay(5);
+}
+
+
+
+
+// *************************************************************************************** //
+// ********************************* Private functions *********************************** //
+// *************************************************************************************** //
+
+
+
+
+// *************************** Read function to the encoder ****************************** //
+// Read 1 byte from the encoder 
+uint8_t readEncoderByte(uint8_t reg) {
+    uint8_t data[4];
+    uint16_t value = 0;
+    
+    last_status = TRANSFER_ERROR;
+    
+    (void) I2C_I2CMasterClearStatus();
+
+    last_status = I2C_I2CMasterSendStart( (uint32_t)i2cEnc[encoder_activated]._add, I2C_I2C_WRITE_XFER_MODE, I2C_TIMEOUT );
+    if( I2C_I2C_MSTR_NO_ERROR == last_status )
+    {
+        last_status = I2C_I2CMasterWriteByte( (uint32_t)reg, I2C_TIMEOUT );
+        /* Transfer succeeds send stop and return Success */
+        if((I2C_I2C_MSTR_NO_ERROR == last_status)      ||
+           (I2C_I2C_MASTER_CMD_M_NACK == last_status))
+        {
+            if(I2C_I2CMasterSendStop(I2C_TIMEOUT) == I2C_I2C_MSTR_NO_ERROR)
+            {
+                /* High level I2C: */
+                last_status = I2C_I2CMasterReadBuf((uint32_t)i2cEnc[encoder_activated]._add, data, 01u, I2C_I2C_MODE_COMPLETE_XFER);
+                if(I2C_I2C_MSTR_NO_ERROR == last_status)
+                {
+                    // If I2C read started without errors, wait until master complete read transfer
+                    while (0u == (I2C_I2CMasterStatus() & I2C_I2C_MSTAT_RD_CMPLT)) { }
+                    // Display transfer status
+                    if (0u == (I2C_I2C_MSTAT_ERR_XFER & I2C_I2CMasterStatus())) {
+                        last_status = TRANSFER_CMPLT;
+                    }
+                }
+            }
+        }
+        else
+            I2C_I2CMasterSendStop(I2C_TIMEOUT);
+    }
+    else
+        I2C_I2CMasterSendStop(I2C_TIMEOUT);
+       
+       value = data[0];
+    
+       return value;
+}
+
+
+// Read a 16-bit register
+int16_t readEncoderInt(uint8_t reg) { //uint16_t Encoder_readReg16Bit(uint8_t reg) {
+    uint8_t data[4];
+    uint16_t value = 0;
+    
+    last_status = TRANSFER_ERROR;
+    
+    (void) I2C_I2CMasterClearStatus();
+    
+
+    last_status = I2C_I2CMasterSendStart( (uint32_t)i2cEnc[encoder_activated]._add, I2C_I2C_WRITE_XFER_MODE, I2C_TIMEOUT );
+    if( I2C_I2C_MSTR_NO_ERROR == last_status )
+    {
+        last_status = I2C_I2CMasterWriteByte( (uint32_t)reg, I2C_TIMEOUT );
+        /* Transfer succeeds send stop and return Success */
+        if((I2C_I2C_MSTR_NO_ERROR == last_status)      ||
+           (I2C_I2C_MASTER_CMD_M_NACK == last_status))
+        {
+            if(I2C_I2CMasterSendStop(I2C_TIMEOUT) == I2C_I2C_MSTR_NO_ERROR)
+            {
+                /* High level I2C: */
+                last_status = I2C_I2CMasterReadBuf((uint32_t)i2cEnc[encoder_activated]._add, data, 02u, I2C_I2C_MODE_COMPLETE_XFER);
+                if(I2C_I2C_MSTR_NO_ERROR == last_status)
+                {
+                    // If I2C read started without errors, wait until master complete read transfer
+                    while (0u == (I2C_I2CMasterStatus() & I2C_I2C_MSTAT_RD_CMPLT)) { }
+                    // Display transfer status
+                    if (0u == (I2C_I2C_MSTAT_ERR_XFER & I2C_I2CMasterStatus())) {
+                        last_status = TRANSFER_CMPLT;
+                    }
+                }
+            }
+        }
+        else
+            I2C_I2CMasterSendStop(I2C_TIMEOUT);
+    }
+    else
+        I2C_I2CMasterSendStop(I2C_TIMEOUT);
+       
+
+    value  = ((uint16_t)data[0]&0xff)<<8;    // data high byte
+       value |= ((uint16_t)data[1]&0xff);       // data low byte
+                       
+       return value;
+}
+
+
+// Read 4 bytes from the encoder //
+int32_t readEncoderLong(uint8_t reg) { //uint32_t Encoder_readReg32Bit(uint8_t reg) {
+    uint8_t data[4];
+    //uint32_t value = 0;
+    
+    last_status = TRANSFER_ERROR;
+    
+    (void) I2C_I2CMasterClearStatus();
+    
+
+    last_status = I2C_I2CMasterSendStart( (uint32_t)i2cEnc[encoder_activated]._add, I2C_I2C_WRITE_XFER_MODE, I2C_TIMEOUT );
+    if( I2C_I2C_MSTR_NO_ERROR == last_status )
+    {
+        last_status = I2C_I2CMasterWriteByte( (uint32_t)reg, I2C_TIMEOUT );
+        /* Transfer succeeds send stop and return Success */
+        if((I2C_I2C_MSTR_NO_ERROR == last_status)      ||
+           (I2C_I2C_MASTER_CMD_M_NACK == last_status))
+        {
+            if(I2C_I2CMasterSendStop(I2C_TIMEOUT) == I2C_I2C_MSTR_NO_ERROR)
+            {
+                /* High level I2C: */
+                last_status = I2C_I2CMasterReadBuf((uint32_t)i2cEnc[encoder_activated]._add, data, 04u, I2C_I2C_MODE_COMPLETE_XFER);
+                if(I2C_I2C_MSTR_NO_ERROR == last_status)
+                {
+                    // If I2C read started without errors, wait until master complete read transfer
+                    while (0u == (I2C_I2CMasterStatus() & I2C_I2C_MSTAT_RD_CMPLT)) { }
+                    // Display transfer status
+                    if (0u == (I2C_I2C_MSTAT_ERR_XFER & I2C_I2CMasterStatus())) {
+                        last_status = TRANSFER_CMPLT;
+                    }
+                }
+            }
+        }
+        else
+            I2C_I2CMasterSendStop(I2C_TIMEOUT);
+    }
+    else
+        I2C_I2CMasterSendStop(I2C_TIMEOUT);
+        
+       i2cEnc[encoder_activated]._tem_data.bval[3] = data[0];
+               i2cEnc[encoder_activated]._tem_data.bval[2] = data[1];
+               i2cEnc[encoder_activated]._tem_data.bval[1] = data[2];
+               i2cEnc[encoder_activated]._tem_data.bval[0] = data[3];
+       return ((int32_t) i2cEnc[encoder_activated]._tem_data.val);    
+}
+
+// Read 4 bytes from the encoder //
+float readEncoderFloat(uint8_t reg) {
+    uint8_t data[4];
+    //int32_t value = 0;
+    last_status = TRANSFER_ERROR;
+    
+    (void) I2C_I2CMasterClearStatus();
+    
+
+    last_status = I2C_I2CMasterSendStart( (uint32_t)i2cEnc[encoder_activated]._add, I2C_I2C_WRITE_XFER_MODE, I2C_TIMEOUT );
+    if( I2C_I2C_MSTR_NO_ERROR == last_status )
+    {
+        last_status = I2C_I2CMasterWriteByte( (uint32_t)reg, I2C_TIMEOUT );
+        /* Transfer succeeds send stop and return Success */
+        if((I2C_I2C_MSTR_NO_ERROR == last_status)      ||
+           (I2C_I2C_MASTER_CMD_M_NACK == last_status))
+        {
+            if(I2C_I2CMasterSendStop(I2C_TIMEOUT) == I2C_I2C_MSTR_NO_ERROR)
+            {
+                /* High level I2C: */
+                last_status = I2C_I2CMasterReadBuf((uint32_t)i2cEnc[encoder_activated]._add, data, 04u, I2C_I2C_MODE_COMPLETE_XFER);
+                if(I2C_I2C_MSTR_NO_ERROR == last_status)
+                {
+                    // If I2C read started without errors, wait until master complete read transfer
+                    while (0u == (I2C_I2CMasterStatus() & I2C_I2C_MSTAT_RD_CMPLT)) { }
+                    // Display transfer status
+                    if (0u == (I2C_I2C_MSTAT_ERR_XFER & I2C_I2CMasterStatus())) {
+                        last_status = TRANSFER_CMPLT;
+                    }
+                }
+            }
+        }
+        else
+            I2C_I2CMasterSendStop(I2C_TIMEOUT);
+    }
+    else
+        I2C_I2CMasterSendStop(I2C_TIMEOUT);
+        
+        i2cEnc[encoder_activated]._tem_data.bval[3] = data[0];
+               i2cEnc[encoder_activated]._tem_data.bval[2] = data[1];
+               i2cEnc[encoder_activated]._tem_data.bval[1] = data[2];
+               i2cEnc[encoder_activated]._tem_data.bval[0] = data[3];
+       return ((float) i2cEnc[encoder_activated]._tem_data.fval);   
+}
+
+// *************************** Write function to the encoder ****************************** //
+// Send to the encoder 1 byte //
+void writeEncoderByte(uint8_t reg, uint8_t data) { //void Encoder_writeReg(uint8_t reg, uint8_t data)
+    uint8_t buf[2];
+    buf[0] = reg;
+    buf[1] = data;
+    I2C_I2CMasterClearStatus();
+    I2C_I2CMasterWriteBuf((uint32_t)i2cEnc[encoder_activated]._add, buf, 02u, I2C_I2C_MODE_COMPLETE_XFER);
+    for(;;)
+    {
+        if(0u != (I2C_I2CMasterStatus() & I2C_I2C_MSTAT_WR_CMPLT))
+        {
+            /* Transfer complete. Check Master status to make sure that transfer
+            completed without errors. */
+        break;
+        }
+    }
+}
+
+
+// Send to the encoder 4 byte 
+void writeEncoderLong(uint8_t reg, int32_t data) {  //void Encoder_writeReg32Bit(uint8_t reg, uint32_t data) {
+    uint8_t buf[5];
+    i2cEnc[encoder_activated]._tem_data.val = data;
+    buf[0] = reg;
+    /*
+    buf[1] = (uint8_t)((data >> 24) & 0xFF);
+    buf[2] = (uint8_t)((data >> 16) & 0xFF);
+    buf[3] = (uint8_t)((data >> 8) & 0xFF);
+    buf[4] = (uint8_t)(data  & 0xFF); */
+       buf[1] = i2cEnc[encoder_activated]._tem_data.bval[3];
+       buf[2] = i2cEnc[encoder_activated]._tem_data.bval[2];
+       buf[3] = i2cEnc[encoder_activated]._tem_data.bval[1];
+       buf[4] = i2cEnc[encoder_activated]._tem_data.bval[0];
+    I2C_I2CMasterClearStatus();
+    I2C_I2CMasterWriteBuf((uint32_t)i2cEnc[encoder_activated]._add, buf, 05u, I2C_I2C_MODE_COMPLETE_XFER);
+    for(;;)
+    {
+        if(0u != (I2C_I2CMasterStatus() & I2C_I2C_MSTAT_WR_CMPLT))
+        {
+            /* Transfer complete. Check Master status to make sure that transfer
+            completed without errors. */
+        break;
+        }
+    }
+}
+// Send to the encoder 4 byte for floating number //
+void writeEncoderFloat(uint8_t reg, float data) {
+    uint8_t buf[5];
+    buf[0] = reg;
+    i2cEnc[encoder_activated]._tem_data.fval = data;
+       buf[1] = i2cEnc[encoder_activated]._tem_data.bval[3];
+       buf[2] = i2cEnc[encoder_activated]._tem_data.bval[2];
+       buf[3] = i2cEnc[encoder_activated]._tem_data.bval[1];
+       buf[4] = i2cEnc[encoder_activated]._tem_data.bval[0];    
+    I2C_I2CMasterClearStatus();
+    I2C_I2CMasterWriteBuf((uint32_t)i2cEnc[encoder_activated]._add, buf, 05u, I2C_I2C_MODE_COMPLETE_XFER);
+    for(;;)
+    {
+        if(0u != (I2C_I2CMasterStatus() & I2C_I2C_MSTAT_WR_CMPLT))
+        {
+            /* Transfer complete. Check Master status to make sure that transfer
+            completed without errors. */
+        break;
+        }
+    }
+}
+
+
+// Send to the encoder 3 byte 
+void writeEncoder24bit(uint8_t reg, uint32_t data) {
+    uint8_t buf[4];
+    i2cEnc[encoder_activated]._tem_data.val = data;
+    buf[0] = reg;
+       buf[1] = i2cEnc[encoder_activated]._tem_data.bval[2];
+       buf[2] = i2cEnc[encoder_activated]._tem_data.bval[1];
+       buf[3] = i2cEnc[encoder_activated]._tem_data.bval[0];
+    I2C_I2CMasterClearStatus();
+    I2C_I2CMasterWriteBuf((uint32_t)i2cEnc[encoder_activated]._add, buf, 05u, I2C_I2C_MODE_COMPLETE_XFER);
+    for(;;)
+    {
+        if(0u != (I2C_I2CMasterStatus() & I2C_I2C_MSTAT_WR_CMPLT))
+        {
+            /* Transfer complete. Check Master status to make sure that transfer
+            completed without errors. */
+        break;
+        }
+    }
+}
+
+/* ******************************************************************************************************** */
+
+
+
+/*
+// Write a 16-bit register
+void Encoder_writeReg16Bit(uint8_t reg, uint16_t data) {
+    uint8_t buf[3];
+    buf[0] = reg;
+    buf[1] = (uint8_t)((data >> 8) & 0xFF);
+    buf[2] = (uint8_t)(data  & 0xFF);
+    I2C_I2CMasterClearStatus();
+    I2C_I2CMasterWriteBuf((uint32_t)_add, buf, 03u, I2C_I2C_MODE_COMPLETE_XFER);
+    for(;;)
+    {
+        if(0u != (I2C_I2CMasterStatus() & I2C_I2C_MSTAT_WR_CMPLT))
+        {
+            // Transfer complete. Check Master status to make sure that transfer completed without errors.
+        break;
+        }
+    }
+} */
+
+
+
+/*
+
+
+// Write an arbitrary number of bytes from the given array to the sensor,
+// starting at the given register
+void Encoder_writeMulti(uint8_t reg, uint8_t const * src, uint8_t count) {
+       uint8_t buf[64];
+
+       memcpy(&buf[1] , src, count);
+       buf[0] = reg;
+       
+    
+    I2C_I2CMasterClearStatus();
+    I2C_I2CMasterWriteBuf((uint32)_add, buf, (uint32)(count+1), I2C_I2C_MODE_COMPLETE_XFER);
+    for(;;)
+    {
+        if(0u != (I2C_I2CMasterStatus() & I2C_I2C_MSTAT_WR_CMPLT))
+        {
+            // Transfer complete. Check Master status to make sure that transfer completed without errors.
+        break;
+        }
+    }    
+    
+}
+
+// Read an arbitrary number of bytes from the sensor, starting at the given
+// register, into the given array
+void Encoder_readMulti(uint8_t reg, uint8_t *dst, uint8_t count)
+{
+    last_status = I2C_I2CMasterSendStart( _add, I2C_I2C_WRITE_XFER_MODE );
+    if( I2C_I2C_MSTR_NO_ERROR == last_status )
+    {
+        last_status = I2C_I2CMasterWriteByte( (uint32_t)reg );   
+        if( I2C_I2C_MSTR_NO_ERROR == last_status )
+        {
+            I2C_I2CMasterClearStatus();
+            last_status = I2C_I2CMasterReadBuf( (uint32_t)_add, dst, (uint32_t)count, I2C_I2C_MODE_REPEAT_START);
+            for(;;)
+            {
+                if(0u != (I2C_I2CMasterStatus() & I2C_I2C_MSTAT_RD_CMPLT))
+                {
+                    // Transfer complete. Check Master status to make sure that transfer completed without errors.
+                break;
+                }
+            }
+        }
+        else
+            I2C_I2CMasterSendStop();
+    }
+    else
+        I2C_I2CMasterSendStop();    
+        
+}
+
+*/
\ No newline at end of file
diff --git a/i2cEncoderLibV2.h b/i2cEncoderLibV2.h
new file mode 100644 (file)
index 0000000..1f36055
--- /dev/null
@@ -0,0 +1,339 @@
+//
+//    FILE: i2cEncoderLibV2
+// VERSION: 0.1..
+// PURPOSE: Library for the i2c encoder board with PSOC
+// LICENSE: GPL v3 (http://www.gnu.org/licenses/gpl.html)
+//
+// DATASHEET:
+//
+//     URL:
+//
+// AUTHOR:
+// Original Arduino-version: Simone Caron
+//
+
+#ifndef i2cEncoderLibV2
+#define i2cEncoderLibV2
+       
+#define MAX_IDX 2  // Equals nr of I2C_Encoders -1
+
+/* I2C Status */
+#define TRANSFER_CMPLT      (0x00u)
+#define TRANSFER_ERROR      (0xFFu)
+#define READ_CMPLT          (TRANSFER_CMPLT)    
+/* Timeout */
+#define I2C_TIMEOUT         (100u)    
+
+#include <stdbool.h>
+#include <stdint.h>
+    
+//#define NULL 0
+#define HIGH 1
+#define LOW  0
+
+    
+/* I2C Slave Address */
+#define I2C_SLAVE_ADDR      (0x04u)    
+       
+typedef unsigned char byte;
+typedef void (*Callback) (void (*ptr));
+    
+/* Global variables */
+extern uint8_t encoder_last_idx;   //Index of the last added encoder
+extern uint8_t encoder_activated;  //Index of the current encoder_activated encoder
+
+enum EventsType {
+       EV_ButtonRelease,
+       EV_ButtonPush,
+       EV_ButtonDoublePush,
+       EV_Increment,
+       EV_Decrement,
+       EV_Change,
+       EV_Max,
+       EV_Min,
+       EV_MinMax,
+       EV_GP1Rise,
+       EV_GP1Fall,
+       EV_GP2Rise,
+       EV_GP2Fall,
+       EV_GP3Rise,
+       EV_GP3Fall,
+       EV_FadeProcess, EV_Range
+};
+
+       //Callback onIncrement;
+    
+/*  
+    
+// Constructors & Destructors: 
+// =========================== 
+struct  i2cEnc_* i2cEnc__create();          //Empty constructor
+void    i2cEnc__init(struct i2cEnc_ *self); //re-init
+void    i2cEnc__destroy();                          //destructor
+
+// Member FUNCTIONS: 
+// ================= 
+        //  RGB LED Functions  //
+       void i2cEnc__writeLEDR(struct i2cEnc_ *self, uint8_t rled);
+       void i2cEnc__writeLEDG(struct i2cEnc_ *self, uint8_t gled);
+       void i2cEnc__writeLEDB(struct i2cEnc_ *self, uint8_t bled);
+       void i2cEnc__writeRGBCode(struct i2cEnc_ *self, uint32_t rgb);
+*/
+
+
+/* Original: class i2cEnc_ {
+public: */
+//struct i2cEnc_; //C: Struct instead of class     
+
+    enum I2C_Register {
+               REG_GCONF    = 0x00,
+               REG_GP1CONF  = 0x01,
+               REG_GP2CONF  = 0x02,
+               REG_GP3CONF  = 0x03,
+               REG_INTCONF  = 0x04,
+               REG_ESTATUS  = 0x05,
+               REG_I2STATUS = 0x06,
+               REG_FSTATUS  = 0x07,
+               REG_CVALB4   = 0x08,
+               REG_CVALB3   = 0x09,
+               REG_CVALB2   = 0x0A,
+               REG_CVALB1   = 0x0B,
+               REG_CMAXB4   = 0x0C,
+               REG_CMAXB3   = 0x0D,
+               REG_CMAXB2   = 0x0E,
+               REG_CMAXB1   = 0x0F,
+               REG_CMINB4   = 0x10,
+               REG_CMINB3   = 0x11,
+               REG_CMINB2   = 0x12,
+               REG_CMINB1   = 0x13,
+               REG_ISTEPB4  = 0x14,
+               REG_ISTEPB3  = 0x15,
+               REG_ISTEPB2  = 0x16,
+               REG_ISTEPB1  = 0x17,
+               REG_RLED     = 0x18,
+               REG_GLED     = 0x19,
+               REG_BLED     = 0x1A,
+               REG_GP1REG   = 0x1B,
+               REG_GP2REG   = 0x1C,
+               REG_GP3REG   = 0x1D,
+               REG_ANTBOUNC = 0x1E,
+               REG_DPPERIOD = 0x1F,
+               REG_FADERGB  = 0x20,
+               REG_FADEGP   = 0x21,
+               REG_EEPROMS  = 0x80,
+       };
+    
+        //  Encoder configuration bit. Use with GCONF   // 
+       enum GCONF_PARAMETER {
+               FLOAT_DATA       = 0x01,
+               INT_DATA         = 0x00,
+               WRAP_ENABLE  = 0x02,
+               WRAP_DISABLE = 0x00,
+               DIRE_LEFT        = 0x04,
+               DIRE_RIGHT       = 0x00,
+               IPUP_DISABLE = 0x08,
+               IPUP_ENABLE  = 0x00,
+               RMOD_X2          = 0x10,
+               RMOD_X1          = 0x00,
+               RGB_ENCODER  = 0x20,
+               STD_ENCODER  = 0x00,
+               EEPROM_BANK1 = 0x40,
+               EEPROM_BANK2 = 0x00,
+               RESET            = 0x80,
+       };
+
+        //  Encoder status bits and setting. Use with: INTCONF for set and with ESTATUS for read the bits    // 
+       enum Int_Status {
+               PUSHR = 0x01,
+               PUSHP = 0x02,
+               PUSHD = 0x04,
+               RINC = 0x08,
+               RDEC = 0x10,
+               RMAX = 0x20,
+               RMIN = 0x40,
+               INT_2 = 0x80,
+
+       };
+
+        //  Encoder Int2 bits. Use to read the bits of I2STATUS    // 
+       typedef enum {
+               GP1_POS = 0x01,
+               GP1_NEG = 0x02,
+               GP2_POS = 0x04,
+               GP2_NEG = 0x08,
+               GP3_POS = 0x10,
+               GP3_NEG = 0x20,
+               FADE_INT = 0x40,
+       } Int2_Status;
+
+        //  Encoder Fade status bits. Use to read the bits of FSTATUS    // 
+       typedef enum {
+               FADE_R = 0x01,
+               FADE_G = 0x02,
+               FADE_B = 0x04,
+               FADES_GP1 = 0x08,
+               FADES_GP2 = 0x10,
+               FADES_GP3 = 0x20,
+       } Fade_Status;
+
+        //  GPIO Configuration. Use with GP1CONF,GP2CONF,GP3CONF   // 
+       enum GP_PARAMETER {
+               GP_PWM = 0x00,
+               GP_OUT = 0x01,
+               GP_AN = 0x02,
+               GP_IN = 0x03,
+               GP_PULL_EN = 0x04,
+               GP_PULL_DI = 0x00,
+               GP_INT_DI = 0x00,
+               GP_INT_PE = 0x08,
+               GP_INT_NE = 0x10,
+               GP_INT_BE = 0x18,
+       };
+    
+
+       union Data_v {
+               float fval;
+               int32_t val;
+               uint8_t bval[4];
+       };
+
+
+    /* Struct definition: */
+    struct i2cEnc_{    // Encoder register definition //
+       //enum I2C_Register I2C_Reg;
+       uint8_t _add;   //Address
+       uint8_t _stat;
+       uint8_t _stat2;
+       uint8_t _gconf;
+       union Data_v _tem_data;
+       // Event callback pointers stored in an array //
+               Callback call_back[EV_Range];
+    };
+    
+      
+        //  Configuration methods  //
+    
+    bool i2cEnc__init(uint8_t add);    // Init + address of the Encoder => false when not enough memory in the array
+    void i2cEnc__begin(uint8_t conf);  // Used for initialize the encoder
+    void i2cEnc__reset(void);
+       void i2cEnc__SetEvent(int EventType, Callback event);
+
+    void i2cEnc__autoconfigInterrupt();
+    
+        //     Read functions    //
+       uint8_t i2cEnc__readGP1conf(void);
+       uint8_t i2cEnc__readGP2conf(void);
+       uint8_t i2cEnc__readGP3conf(void);
+       uint8_t i2cEnc__readInterruptConfig(void);
+    
+    
+        //  Status function  //
+       bool    i2cEnc__updateStatus(void);
+    
+       bool    i2cEnc__readStatus_match(enum Int_Status s); //C: must use enum
+       uint8_t i2cEnc__readStatus(void);
+
+       bool    i2cEnc__readInt2_match(Int2_Status s);
+       uint8_t i2cEnc__readInt2(void);
+
+       bool    i2cEnc__readFadeStatus_match(Fade_Status s);
+       uint8_t i2cEnc__readFadeStatus(void);
+    
+    
+        //  Encoder functions  //
+       float   i2cEnc__readCounterFloat(void);
+       int32_t i2cEnc__readCounterLong(void);
+       int16_t i2cEnc__readCounterInt(void);
+       int8_t  i2cEnc__readCounterByte(void);
+
+       int32_t i2cEnc__readMax(void);
+       float   i2cEnc__readMaxFloat(void);
+
+       int32_t i2cEnc__readMin(void);
+       float   i2cEnc__readMinFloat(void);
+
+       int32_t i2cEnc__readStep(void);
+       float   i2cEnc__readStepFloat(void);
+
+        //  RGB LED Functions  //
+       uint8_t i2cEnc__readLEDR(void);
+       uint8_t i2cEnc__readLEDG(void);
+       uint8_t i2cEnc__readLEDB(void);
+
+        //  GP LED Functions  //
+       uint8_t i2cEnc__readGP1(void);
+       uint8_t i2cEnc__readGP2(void);
+       uint8_t i2cEnc__readGP3(void);
+
+        //  Timing registers  //
+       uint8_t i2cEnc__readAntibouncingPeriod(void);
+       uint8_t i2cEnc__readDoublePushPeriod(void);
+       uint8_t i2cEnc__readFadeRGB(void);
+       uint8_t i2cEnc__readFadeGP(void);
+
+        //  EEPROM register  //
+       uint8_t i2cEnc__readEEPROM(uint8_t add);
+
+        // ****    Write functions   ****** //
+       void i2cEnc__writeGP1conf(uint8_t gp1);
+       void i2cEnc__writeGP2conf(uint8_t gp2);
+       void i2cEnc__writeGP3conf(uint8_t gp3);
+       void i2cEnc__writeInterruptConfig(uint8_t interrupt);
+
+    
+        //  Encoder functions  //
+       void i2cEnc__writeCounter_i(int32_t counter);
+       void i2cEnc__writeCounter_f(float counter);
+
+       void i2cEnc__writeMax_i(int32_t max);
+       void i2cEnc__writeMax_f(float max);
+
+       void i2cEnc__writeMin_i(int32_t min);
+       void i2cEnc__writeMin_f(float min);
+
+       void i2cEnc__writeStep_i(int32_t step);
+       void i2cEnc__writeStep_f(float step);
+    
+
+        //  RGB LED Functions  //
+       void i2cEnc__writeLEDR(uint8_t rled);
+       void i2cEnc__writeLEDG(uint8_t gled);
+       void i2cEnc__writeLEDB(uint8_t bled);
+       void i2cEnc__writeRGBCode(uint32_t rgb);
+
+        //  GP LED Functions  //
+       void i2cEnc__writeGP1(uint8_t gp1);
+       void i2cEnc__writeGP2(uint8_t gp2);
+       void i2cEnc__writeGP3(uint8_t gp3);
+
+        //  Timing registers  //
+       void i2cEnc__writeAntibouncingPeriod(uint8_t bounc);
+       void i2cEnc__writeDoublePushPeriod(uint8_t dperiod);
+       void i2cEnc__writeFadeRGB(uint8_t fade);
+       void i2cEnc__writeFadeGP(uint8_t fade);
+
+        //  EEPROM register  //
+       void i2cEnc__writeEEPROM(uint8_t add, uint8_t data);
+
+//private:
+    
+    
+    /*
+       void eventCaller(Callback *event);
+       */
+    /*
+    uint8_t readEncoderByte(uint8_t reg);
+       int16_t readEncoderInt(uint8_t reg);
+       int32_t readEncoderLong(uint8_t reg);
+       float readEncoderFloat(uint8_t reg);
+       void writeEncoderByte(uint8_t reg, uint8_t data);
+       void writeEncoderInt(uint8_t reg, int32_t data);
+       void writeEncoderFloat(uint8_t reg, float data);
+       void writeEncoder24bit(uint8_t reg, uint32_t data);
+    */
+    /*
+}; endof class i2cEnc_ */ 
+
+       
+       
+#endif
diff --git a/i2c_controller.c b/i2c_controller.c
new file mode 100644 (file)
index 0000000..a589e65
--- /dev/null
@@ -0,0 +1,548 @@
+/* Copyright (C)
+* 2020 - John Melton, G0ORX/N6LYT
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*
+*/
+
+#include <gtk/gtk.h>
+#include <errno.h>
+#include <gpiod.h>
+#include <sys/time.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <linux/i2c-dev.h>
+#include <i2c/smbus.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include "i2c_controller.h"
+#include "vfo.h"
+#include "radio.h"
+#include "ext.h"
+#include "sliders.h"
+#include "new_menu.h"
+
+
+char *encoder_string[ENCODER_ACTIONS] = {
+  "NO ACTION",
+  "AF GAIN",
+  "AF GAIN RX1",
+  "AF GAIN RX2",
+  "AGC GAIN",
+  "AGC GAIN RX1",
+  "AGC GAIN RX2",
+  "ATTENUATION/RX GAIN",
+  "COMP",
+  "CW FREQUENCY",
+  "CW SPEED",
+  "DIVERSITY GAIN",
+  "DIVERSITY GAIN (coarse)",
+  "DIVERSITY GAIN (fine)",
+  "DIVERSITY PHASE",
+  "DIVERSITY PHASE (coarse)",
+  "DIVERSITY PHASE (fine)",
+  "DRIVE",
+  "IF SHIFT",
+  "IF SHIFT RX1",
+  "IF SHIFT RX2",
+  "IF WIDTH",
+  "IF WIDTH RX1",
+  "IF WIDTH RX2",
+  "MIC GAIN",
+  "PAN",
+  "PANADAPTER HIGH",
+  "PANADAPTER LOW",
+  "PANADAPTER STEP",
+  "RF GAIN",
+  "RF GAIN RX1",
+  "RF GAIN RX2",
+  "RIT",
+  "RIT RX1",
+  "RIT RX2",
+  "SQUELCH",
+  "SQUELCH RX1",
+  "SQUELCH RX2",
+  "TUNE DRIVE",
+  "VFO",
+  "WATERFALL HIGH",
+  "WATERFALL LOW",
+  "XIT",
+  "ZOOM",
+};
+
+char *sw_string[SWITCH_ACTIONS] = {
+  "NO ACTION",
+  "A TO B",
+  "A SWAP B",
+  "AGC",
+  "ANF",
+  "B TO A",
+  "BAND -",
+  "BAND +",
+  "BSTACK -",
+  "BSTACK +",
+  "CTUN",
+  "DIV",
+  "FILTER -",
+  "FILTER +",
+  "FUNCTION",
+  "LOCK",
+  "MENU BAND",
+  "MENU BSTACK",
+  "MENU DIV",
+  "MENU FILTER",
+  "MENU FREQUENCY",
+  "MENU MEMORY",
+  "MENU MODE",
+  "MENU PS",
+  "MODE -",
+  "MODE +",
+  "MOX",
+  "MUTE",
+  "NB",
+  "NR",
+  "PAN -",
+  "PAN +",
+  "PS",
+  "RIT",
+  "RIT CL",
+  "SAT",
+  "SNB",
+  "SPLIT",
+  "TUNE",
+  "TWO TONE",
+  "XIT",
+  "XIT CL",
+  "ZOOM -",
+  "ZOOM +",
+};
+
+ENCODER encoder[MAX_ENCODERS]=
+{
+  {TRUE,0x11,0,ENCODER_AF_GAIN,TRUE,MODE_MENU,FALSE,NO_ACTION,FALSE,NO_ACTION,FALSE,NO_ACTION},
+  {TRUE,0x12,0,ENCODER_AGC_GAIN,TRUE,FILTER_MENU,FALSE,NO_ACTION,FALSE,NO_ACTION,FALSE,NO_ACTION},
+  {TRUE,0x13,0,ENCODER_RIT,FALSE,NO_ACTION,FALSE,NO_ACTION,FALSE,NO_ACTION,FALSE,NO_ACTION},
+  {TRUE,0x14,0,ENCODER_DRIVE,FALSE,NO_ACTION,FALSE,NO_ACTION,FALSE,NO_ACTION,FALSE,NO_ACTION},
+  {TRUE,0x15,0,ENCODER_IF_SHIFT,FALSE,NO_ACTION,FALSE,NO_ACTION,FALSE,NO_ACTION,FALSE,NO_ACTION},
+  {TRUE,0x16,0,ENCODER_IF_WIDTH,FALSE,NO_ACTION,FALSE,NO_ACTION,FALSE,NO_ACTION,FALSE,NO_ACTION},
+  {TRUE,0x10,0,ENCODER_VFO,TRUE,MENU_BAND,FALSE,NO_ACTION,FALSE,NO_ACTION,FALSE,NO_ACTION},
+};
+
+char *gpio_device="/dev/gpiochip0";
+int new_i2c_interrupt=4;
+
+static struct gpiod_chip *chip=NULL;
+static struct gpiod_line *line=NULL;
+
+static GMutex encoder_mutex;
+static GThread *monitor_thread_id;
+
+char *i2c_device="/dev/i2c-1";
+
+static int fd=-1;
+
+static GThread *rotary_encoder_thread_id;
+
+static int vfo_encoder_changed(void *data) {
+  if(!locked) {
+    gint pos=(gint)data;
+    vfo_step(pos);
+  }
+  return 0;
+}
+
+static gpointer rotary_encoder_thread(gpointer data) {
+  while(1) {
+    g_mutex_lock(&encoder_mutex);
+    for(int i=0;i<MAX_ENCODERS;i++) {
+      if(encoder[i].enabled) {
+        if(encoder[i].pos!=0) {
+          switch(encoder[i].encoder_function) {
+            case ENCODER_VFO:
+              if(active_menu==BAND_MENU) {
+                // move to next/previous band
+              } else {
+                g_idle_add(vfo_encoder_changed,(gpointer)encoder[i].pos);
+              }
+              break;
+            case ENCODER_AF_GAIN:
+              {
+              double af_gain=active_receiver->volume;
+              af_gain+=((double)encoder[i].pos/100.0);
+              if(af_gain<0.0) af_gain=0.0;
+              if(af_gain>1.0) af_gain=1.0;
+              double *dp=g_new(double,1);
+              *dp=af_gain;
+              g_idle_add(ext_set_af_gain,(gpointer)dp);
+              }
+              break;
+            case ENCODER_AGC_GAIN:
+              {
+              double agc_gain=active_receiver->agc_gain;
+              agc_gain+=(double)encoder[i].pos;
+              if(agc_gain<-20.0) agc_gain=-20.0;
+              if(agc_gain>120.0) agc_gain=120.0;
+              double *dp=g_new(double,1);
+              *dp=agc_gain;
+              g_idle_add(ext_set_agc_gain,(gpointer)dp);
+              }
+              break;
+            case ENCODER_DRIVE:
+              {
+              double drive=getDrive();
+              drive+=(double)encoder[i].pos;
+              if(drive<0.0) drive=0.0;
+              if(drive>drive_max) drive=drive_max;
+              double *dp=g_new(double,1);
+              *dp=drive;
+              g_idle_add(ext_set_drive,(gpointer)dp);
+              }
+              break;
+          }
+        }
+        encoder[i].pos=0;
+      }
+    }
+    g_mutex_unlock(&encoder_mutex);
+    usleep(100000);
+  }
+}
+
+int i2c_init() {
+  int ret=0;
+
+  g_mutex_init(&encoder_mutex);
+
+  g_print("%s: open i2c device %s\n",__FUNCTION__,i2c_device);
+  fd=open(i2c_device, O_RDWR);
+  if(fd<0) {
+    g_print("%s: open i2c device %s failed: %s\n",__FUNCTION__,i2c_device,g_strerror(errno));
+    goto end;
+  }
+  g_print("%s: open i2c device %s fd=%d\n",__FUNCTION__,i2c_device,fd);
+
+  for(int i=0;i<MAX_ENCODERS;i++) {
+    if(encoder[i].enabled) {
+      if (ioctl(fd, I2C_SLAVE, encoder[i].address) < 0) {
+        g_print("%s: ioctl i2c slave %d failed: %s\n",__FUNCTION__,encoder[i].address,g_strerror(errno));
+        encoder[i].enabled=FALSE;
+        continue;
+      }
+  
+      //g_print("%s: write config\n",__FUNCTION__);
+      unsigned int config=INT_DATA | WRAP_DISABLE | DIRE_LEFT | IPUP_ENABLE | REL_MODE_DISABLE | RMOD_X1;
+      if(i2c_smbus_write_byte_data(fd,REG_GCONF,config&0xFF)<0) {
+        g_print("%s: write REG_GCONF config failed: addr=%02X %s\n",__FUNCTION__,encoder[i].address,g_strerror(errno));
+        encoder[i].enabled=FALSE;
+        continue;
+      }
+      if(i2c_smbus_write_byte_data(fd,REG_GCONF2,(config>>8)&0xFF)<0) {
+        g_print("%s: write REG_GCONF2 config failed: addr=%02X %s\n",__FUNCTION__,encoder[i].address,g_strerror(errno));
+        encoder[i].enabled=FALSE;
+        continue;
+      }
+
+      int v=0; // initial value
+
+      //g_print("%s: write counter value\n",__FUNCTION__);
+      if(i2c_smbus_write_i2c_block_data(fd, REG_CVALB4, 4, (const __u8 *)&v)<0) {
+        g_print("%s: counter CVALB1 config failed: %s\n",__FUNCTION__,g_strerror(errno));
+        encoder[i].enabled=FALSE;
+        continue;
+      }
+
+      v=1024; // max value
+
+      //g_print("%s: write max value\n",__FUNCTION__);
+      if(i2c_smbus_write_i2c_block_data(fd, REG_CMAXB4, 4, (const __u8 *)&v)<0) {
+        g_print("%s: counter CMAXB1 config failed: %s\n",__FUNCTION__,g_strerror(errno));
+        encoder[i].enabled=FALSE;
+        continue;
+      }
+
+      v=-1024; // min value
+
+      //g_print("%s: write min value\n",__FUNCTION__);
+      if(i2c_smbus_write_i2c_block_data(fd, REG_CMINB4, 4, (const __u8 *)&v)<0) {
+        g_print("%s: counter CMINB1 config failed: %s\n",__FUNCTION__,g_strerror(errno));
+        encoder[i].enabled=FALSE;
+        continue;
+      }
+
+      v=1; // step value
+
+      //g_print("%s: write step value\n",__FUNCTION__);
+      if(i2c_smbus_write_i2c_block_data(fd, REG_ISTEPB4, 4, (const __u8 *)&v)<0) {
+        g_print("%s: counter CISTEPB4 config failed: %s\n",__FUNCTION__,g_strerror(errno));
+        encoder[i].enabled=FALSE;
+        continue;
+      }
+
+      v=8;
+
+      //g_print("%s: write antibounce value\n",__FUNCTION__);
+      if(i2c_smbus_write_byte_data(fd, REG_ANTBOUNC, v&0xFF)<0) {
+        g_print("%s: counter REG_ANTBOUNC config failed: %s\n",__FUNCTION__,g_strerror(errno));
+        encoder[i].enabled=FALSE;
+        continue;
+      }
+
+      v=30;
+
+      //g_print("%s: write double push value\n",__FUNCTION__);
+      if(i2c_smbus_write_byte_data(fd, REG_DPPERIOD, v&0xFF)<0) {
+        g_print("%s: counter REG_DPPERIOD config failed: %s\n",__FUNCTION__,g_strerror(errno));
+        encoder[i].enabled=FALSE;
+        continue;
+      }
+
+      v=PUSHR | PUSHP | PUSHD | RINC | RDEC /*| RMAX | RMIN | INT_2*/; 
+      //g_print("%s: write interrupt config %02X\n",__FUNCTION__, v&0xFF);
+      if(i2c_smbus_write_byte_data(fd,REG_INTCONF,v&0xFF)<0) {
+        g_print("%s: counter CMINB1 config failed: %s\n",__FUNCTION__,g_strerror(errno));
+        encoder[i].enabled=FALSE;
+        continue;
+      }
+
+      //g_print("%s: write interrupt config %02X\n",__FUNCTION__, v&0xFF);
+      if(i2c_smbus_write_byte_data(fd,REG_INTCONF,v&0xFF)<0) {
+        g_print("%s: counter CMINB1 config failed: %s\n",__FUNCTION__,g_strerror(errno));
+        encoder[i].enabled=FALSE;
+        continue;
+      }
+
+      __s32 id=i2c_smbus_read_byte_data(fd,REG_IDCODE);
+      g_print("%s: board addr=%02X id=%02X\n",__FUNCTION__,encoder[i].address,id&0xFF);
+
+      __s32 ver=i2c_smbus_read_byte_data(fd,REG_VERSION);
+      g_print("%s: board addr=%02X version=%02X\n",__FUNCTION__,encoder[i].address,ver&0xFF);
+    }
+  }
+
+  rotary_encoder_thread_id = g_thread_new( "encoders", rotary_encoder_thread, NULL);
+  if(!rotary_encoder_thread_id ) {
+    g_print("%s: g_thread_new failed on rotary_encoder_thread\n",__FUNCTION__);
+    ret=-1;
+    goto error;
+  }
+
+  goto end;
+
+error:
+  if(fd>=0) {
+    close(fd);
+    fd=-1;
+  }
+
+end:
+  return ret;
+}
+
+void i2c_close() {
+  if(fd>0) {
+    close(fd);
+    fd=-1;
+  }
+}
+
+static void encoder_switch_pushed(int i) {
+  switch(encoder[i].push_sw_function) {
+    case MENU_BAND:
+      g_idle_add(ext_band_update,NULL);
+      break;
+  }
+}
+
+void i2c_interrupt(int line) {
+  int length;
+
+  g_print("%s: line=%d fd=%d\n",__FUNCTION__,line,fd);
+  if(fd!=-1) {
+    g_mutex_lock(&encoder_mutex);
+    for(int i=0;i<MAX_ENCODERS;i++) {
+      if(encoder[i].enabled) {
+        if (ioctl(fd, I2C_SLAVE, encoder[i].address) < 0) {
+          g_print("%s: ioctl i2c slave %d failed: %s\n",__FUNCTION__,encoder[i].address,g_strerror(errno));
+          continue;
+        }
+        
+        __s32 status=i2c_smbus_read_byte_data(fd,REG_ESTATUS);
+        g_print("%s: address=%02X status=%02X\n",__FUNCTION__,encoder[i].address,status&0xFF);
+
+
+        if(status&PUSHR) {
+          //g_print("%s: PUSHR\n",__FUNCTION__);
+          if(encoder[i].push_sw_enabled) {
+            encoder_switch_pushed(i);
+          }
+        }
+        if(status&PUSHP) {
+          //g_print("%s: PUSHP\n",__FUNCTION__);
+        }
+        if(status&PUSHD) {
+          //g_print("%s: PUSHD\n",__FUNCTION__);
+        }
+        if(status&RINC) {
+          g_print("%s: RINC from %02X\n",__FUNCTION__,encoder[i].address);
+          encoder[i].pos++;
+/*
+          __s32 v;
+          __s32 bytes=i2c_smbus_read_i2c_block_data(fd, REG_CVALB4, 4, (__u8 *)&v);
+          g_print("%s: val=%d\n",__FUNCTION__,v);
+*/
+        }
+        if(status&RDEC) {
+          g_print("%s: RDEC from %02X\n",__FUNCTION__,encoder[i].address);
+          encoder[i].pos--;
+/*
+          __s32 v;
+          __s32 bytes=i2c_smbus_read_i2c_block_data(fd, REG_CVALB4, 4, (__u8 *)&v);
+          g_print("%s: val=%d\n",__FUNCTION__,v);
+*/
+        }
+        if(status&RMAX) {
+          //g_print("%s: RMAX\n",__FUNCTION__);
+        }
+        if(status&RMIN) {
+          //g_print("%s: RMIN\n",__FUNCTION__);
+        }
+        if(status&INT_2) {
+          //g_print("%s: INT_2\n",__FUNCTION__);
+          __s32 i2status=i2c_smbus_read_byte_data(fd,REG_I2STATUS);
+          //g_print("%s: i2status=%02X\n",__FUNCTION__,status&0xFF);
+        }
+      }
+    }
+    g_mutex_unlock(&encoder_mutex);
+  }
+  //g_print("%s: exit\n",__FUNCTION__);
+}
+
+static int interrupt_cb(int event_type, unsigned int line, const struct timespec *timeout, void* data) {
+  g_print("%s: event=%d line=%d\n",__FUNCTION__,event_type,line);
+  switch(event_type) {
+    case GPIOD_CTXLESS_EVENT_CB_TIMEOUT:
+      // timeout - ignore
+      //g_print("%s: Ignore timeout\n",__FUNCTION__);
+      break;
+    case GPIOD_CTXLESS_EVENT_CB_RISING_EDGE:
+      // not expected
+      //g_print("%s: Ignore RISING EDGE\n",__FUNCTION__);
+      break;
+    case GPIOD_CTXLESS_EVENT_CB_FALLING_EDGE:
+      // process
+      //g_print("%s: Process FALLING EDGE\n",__FUNCTION__);
+      i2c_interrupt(line);
+      break;
+  }
+  return GPIOD_CTXLESS_EVENT_CB_RET_OK;
+}
+
+static gpointer monitor_thread(gpointer arg) {
+  struct timespec t;
+
+  // thread to monitor gpio events
+  g_print("%s: start event monitor\n",__FUNCTION__);
+  t.tv_sec=60;
+  t.tv_nsec=0;
+
+  int ret=gpiod_ctxless_event_monitor(gpio_device,GPIOD_CTXLESS_EVENT_FALLING_EDGE,new_i2c_interrupt,FALSE,"encoder",&t,NULL,interrupt_cb,NULL);
+  if (ret<0) {
+    g_print("%s: ctxless event monitor failed: %s\n",__FUNCTION__,g_strerror(errno));
+  }
+
+  g_print("%s: exit\n",__FUNCTION__);
+  return NULL;
+}
+
+int gpio_init() {
+  int ret=0;
+
+
+  chip=NULL;
+  line=NULL;
+
+//g_print("%s: open gpio 0\n",__FUNCTION__);
+  chip=gpiod_chip_open_by_number(0);
+  if(chip==NULL) {
+    g_print("%s: open chip failed: %s\n",__FUNCTION__,g_strerror(errno));
+    ret=1;
+    goto end;
+  }
+
+//g_print("%s: get line %d\n",__FUNCTION__,new_i2c_interrupt);
+  line = gpiod_chip_get_line(chip, new_i2c_interrupt);
+  if (!line) {
+    g_print("%s: get line failed: %s\n",__FUNCTION__,g_strerror(errno));
+    ret = -1;
+    goto end;
+  }
+
+//g_print("%s: line request falling edge\n",__FUNCTION__);
+  ret=gpiod_line_request_falling_edge_events(line,"encoder");
+  if (ret<0) {
+    g_print("%s: line request falling edge events failed: %s\n",__FUNCTION__,g_strerror(errno));
+    ret = -1;
+    goto end;
+  }
+  if(line!=NULL) {
+    gpiod_line_release(line);
+    line=NULL;
+  }
+  if(chip!=NULL) {
+    gpiod_chip_close(chip);
+    chip=NULL;
+  }
+
+  monitor_thread_id = g_thread_new( "gpiod monitor", monitor_thread, NULL);
+  if(!monitor_thread_id ) {
+    g_print("%s: g_thread_new failed for monitor_thread\n",__FUNCTION__);
+  }
+  return 0;
+
+g_print("%s: end\n",__FUNCTION__);
+end:
+  if(line!=NULL) {
+    gpiod_line_release(line);
+    line=NULL;
+   }
+  if(chip!=NULL) {
+    gpiod_chip_close(chip);
+    chip=NULL;
+  }
+  return ret;
+}
+
+void gpio_close() {
+  if(line!=NULL) gpiod_line_release(line);
+  if(chip!=NULL) gpiod_chip_close(chip);
+}
+
+
+
+int i2c_controller_init() {
+  int rc=0;
+
+  rc=gpio_init();
+  if(rc<0) goto end;
+
+  rc=i2c_init();
+
+end:
+  return rc;
+}
diff --git a/i2c_controller.h b/i2c_controller.h
new file mode 100644 (file)
index 0000000..e104e1c
--- /dev/null
@@ -0,0 +1,264 @@
+/* Copyright (C)
+* 2020 - John Melton, G0ORX/N6LYT
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*
+*/
+
+#ifndef I2C_CONTROLLER_H
+#define I2C_CONTROLLER_H
+
+
+// Encoder register definition
+#define REG_GCONF 0x00
+#define REG_GP1CONF 0x01
+#define REG_GP2CONF 0x02
+#define REG_GP3CONF 0x03
+#define REG_INTCONF 0x04
+#define REG_ESTATUS 0x05
+#define REG_I2STATUS 0x06
+#define REG_FSTATUS 0x07
+#define REG_CVALB4 0x08
+#define REG_CVALB3 0x09
+#define REG_CVALB2 0x0A
+#define REG_CVALB1 0x0B
+#define REG_CMAXB4 0x0C
+#define REG_CMAXB3 0x0D
+#define REG_CMAXB2 0x0E
+#define REG_CMAXB1 0x0F
+#define REG_CMINB4 0x10
+#define REG_CMINB3 0x11
+#define REG_CMINB2 0x12
+#define REG_CMINB1 0x13
+#define REG_ISTEPB4 0x14
+#define REG_ISTEPB3 0x15
+#define REG_ISTEPB2 0x16
+#define REG_ISTEPB1 0x17
+#define REG_RLED 0x18
+#define REG_GLED 0x19
+#define REG_BLED 0x1A
+#define REG_GP1REG 0x1B
+#define REG_GP2REG 0x1C
+#define REG_GP3REG 0x1D
+#define REG_ANTBOUNC 0x1E
+#define REG_DPPERIOD 0x1F
+#define REG_FADERGB 0x20
+#define REG_FADEGP 0x21
+#define REG_GAMRLED 0x27
+#define REG_GAMGLED 0x28
+#define REG_GAMBLED 0x29
+#define REG_GAMMAGP1 0x2A
+#define REG_GAMMAGP2 0x2B
+#define REG_GAMMAGP3 0x2C
+#define REG_GCONF2 0x30
+#define REG_IDCODE 0x70
+#define REG_VERSION 0x71
+#define REG_EEPROMS 0x80
+
+
+// Encoder configuration bit. Use with GCONF
+#define FLOAT_DATA 0x0001
+#define INT_DATA 0x0000
+#define WRAP_ENABLE 0x0002
+#define WRAP_DISABLE 0x0000
+#define DIRE_LEFT 0x0004
+#define DIRE_RIGHT 0x0000
+#define IPUP_DISABLE 0x0008
+#define IPUP_ENABLE 0x0000
+#define RMOD_X2 0x0010
+#define RMOD_X1 0x0000
+#define RGB_ENCODER 0x0020
+#define STD_ENCODER 0x0000
+#define EEPROM_BANK1 0x0040
+#define EEPROM_BANK2 0x0000
+#define RESET 0x0080
+#define CLK_STRECH_ENABLE 0x0100
+#define CLK_STRECH_DISABLE 0x0000
+#define REL_MODE_ENABLE 0x0200
+#define REL_MODE_DISABLE 0x0000
+
+// Encoder status bits and setting. Use with: INTCONF for set and with ESTATUS for read the bits
+#define PUSHR 0x01
+#define PUSHP 0x02
+#define PUSHD 0x04
+#define RINC 0x08
+#define RDEC 0x10
+#define RMAX 0x20
+#define RMIN 0x40
+#define INT_2 0x80
+
+// Encoder Int2 bits. Use to read the bits of I2STATUS 
+#define GP1_POS 0x01
+#define GP1_NEG 0x02
+#define GP2_POS 0x04
+#define GP2_NEG 0x08
+#define GP3_POS 0x10
+#define GP3_NEG 0x20
+#define FADE_INT 0x40
+
+// Encoder Fade status bits. Use to read the bits of FSTATUS 
+#define FADE_R 0x01
+#define FADE_G 0x02
+#define FADE_B 0x04
+#define FADE_GP1 0x08
+#define FADE_GP2 0x10
+#define FADE_GP3 0x20
+
+// GPIO Configuration. USe with GP1CONF,GP2CONF,GP3CONF
+#define GP_PWM 0x00
+#define GP_OUT 0x01
+#define GP_AN 0x02
+#define GP_IN 0x03
+
+#define GP_PULL_EN 0x04
+#define GP_PULL_DI 0x00
+
+#define GP_INT_DI 0x00
+#define GP_INT_PE 0x08
+#define GP_INT_NE 0x10
+#define GP_INT_BE 0x18
+
+// Gamma configuration
+
+#define GAMMA_OFF 0
+#define GAMMA_1 1,
+#define GAMMA_1_8 2
+#define GAMMA_2 3
+#define GAMMA_2_2 4
+#define GAMMA_2_4 5
+#define GAMMA_2_6 6
+#define GAMMA_2_8 7
+
+enum {
+  ENCODER_NO_ACTION=0,
+  ENCODER_AF_GAIN,
+  ENCODER_AF_GAIN_RX1,
+  ENCODER_AF_GAIN_RX2,
+  ENCODER_AGC_GAIN,
+  ENCODER_AGC_GAIN_RX1,
+  ENCODER_AGC_GAIN_RX2,
+  ENCODER_ATTENUATION,
+  ENCODER_COMP,
+  ENCODER_CW_FREQUENCY,
+  ENCODER_CW_SPEED,
+  ENCODER_DIVERSITY_GAIN,
+  ENCODER_DIVERSITY_GAIN_COARSE,
+  ENCODER_DIVERSITY_GAIN_FINE,
+  ENCODER_DIVERSITY_PHASE,
+  ENCODER_DIVERSITY_PHASE_COARSE,
+  ENCODER_DIVERSITY_PHASE_FINE,
+  ENCODER_DRIVE,
+  ENCODER_IF_SHIFT,
+  ENCODER_IF_SHIFT_RX1,
+  ENCODER_IF_SHIFT_RX2,
+  ENCODER_IF_WIDTH,
+  ENCODER_IF_WIDTH_RX1,
+  ENCODER_IF_WIDTH_RX2,
+  ENCODER_MIC_GAIN,
+  ENCODER_PAN,
+  ENCODER_PANADAPTER_HIGH,
+  ENCODER_PANADAPTER_LOW,
+  ENCODER_PANADAPTER_STEP,
+  ENCODER_RF_GAIN,
+  ENCODER_RF_GAIN_RX1,
+  ENCODER_RF_GAIN_RX2,
+  ENCODER_RIT,
+  ENCODER_RIT_RX1,
+  ENCODER_RIT_RX2,
+  ENCODER_SQUELCH,
+  ENCODER_SQUELCH_RX1,
+  ENCODER_SQUELCH_RX2,
+  ENCODER_TUNE_DRIVE,
+  ENCODER_VFO,
+  ENCODER_WATERFALL_HIGH,
+  ENCODER_WATERFALL_LOW,
+  ENCODER_XIT,
+  ENCODER_ZOOM,
+  ENCODER_ACTIONS
+};
+
+extern char *encoder_string[ENCODER_ACTIONS];
+
+enum {
+  NO_ACTION=0,
+  A_TO_B,
+  A_SWAP_B,
+  AGC,
+  ANF,
+  B_TO_A,
+  BAND_MINUS,
+  BAND_PLUS,
+  BANDSTACK_MINUS,
+  BANDSTACK_PLUS,
+  CTUN,
+  DIVERSITY,
+  FILTER_MINUS,
+  FILTER_PLUS,
+  FUNCTION,
+  LOCK,
+  MENU_BAND,
+  MENU_BANDSTACK,
+  MENU_DIVERSITY,
+  MENU_FILTER,
+  MENU_FREQUENCY,
+  MENU_MEMORY,
+  MENU_MODE,
+  MENU_PS,
+  MODE_MINUS,
+  MODE_PLUS,
+  MOX,
+  MUTE,
+  NB,
+  NR,
+  PAN_MINUS,
+  PAN_PLUS,
+  PS,
+  RIT,
+  RIT_CLEAR,
+  SAT,
+  SNB,
+  SPLIT,
+  TUNE,
+  TWO_TONE,
+  XIT,
+  XIT_CLEAR,
+  ZOOM_MINUS,
+  ZOOM_PLUS,
+  SWITCH_ACTIONS
+};
+
+extern char *sw_string[SWITCH_ACTIONS];
+
+typedef struct _encoder {
+  gboolean enabled;
+  gint address;
+  gint pos;
+  gint encoder_function;
+  gboolean push_sw_enabled;
+  gint push_sw_function;
+  gboolean gp1_enabled; 
+  gint gp1_function;
+  gboolean gp2_enabled; 
+  gint gp2_function;
+  gboolean gp3_enabled; 
+  gint gp3_function;
+} ENCODER;
+
+#define MAX_ENCODERS 7
+
+extern ENCODER encoder[MAX_ENCODERS];
+
+extern int i2c_controller_init();
+#endif
diff --git a/i2c_controller_menu.c b/i2c_controller_menu.c
new file mode 100644 (file)
index 0000000..963162c
--- /dev/null
@@ -0,0 +1,170 @@
+#include <gtk/gtk.h>
+#include <glib.h>
+#include <glib/gprintf.h>
+
+#include "i2c_controller.h"
+#include "main.h"
+#include "new_menu.h"
+
+typedef struct _choice {
+  int id;
+  int action;
+  GtkWidget *button;
+} CHOICE;
+
+static void response_event(GtkWidget *dialog,gint id,gpointer user_data) {
+  g_print("%s: id=%d\n",__FUNCTION__,id);
+  if(id==GTK_RESPONSE_ACCEPT) {
+    g_print("%s: ACCEPT\n",__FUNCTION__);
+  }
+  gtk_widget_destroy(dialog);
+  dialog=NULL;
+  active_menu=NO_MENU;
+  sub_menu=NULL;
+}
+
+static void encoder_select_cb(GtkWidget *widget,gpointer data) {
+  CHOICE *choice=(CHOICE *)data;
+  encoder[choice->id].encoder_function=choice->action;
+  gtk_button_set_label(GTK_BUTTON(choice->button),encoder_string[choice->action]);
+}
+
+static gboolean encoder_cb(GtkWidget *widget, GdkEvent *event, gpointer data) {
+  int encoder=GPOINTER_TO_INT(data);
+  int i;
+
+  GtkWidget *menu=gtk_menu_new();
+  for(i=0;i<ENCODER_ACTIONS;i++) {
+    GtkWidget *menu_item=gtk_menu_item_new_with_label(encoder_string[i]);
+    CHOICE *choice=g_new0(CHOICE,1);
+    choice->id=encoder;
+    choice->action=i;
+    choice->button=widget;
+    g_signal_connect(menu_item,"activate",G_CALLBACK(encoder_select_cb),choice);
+    gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
+  }
+  gtk_widget_show_all(menu);
+#if GTK_CHECK_VERSION(3,22,0)
+  gtk_menu_popup_at_pointer(GTK_MENU(menu),(GdkEvent *)event);
+// the following line of code is to work around the problem of the popup menu not having scroll bars.
+  gtk_menu_reposition(GTK_MENU(menu));
+#else
+  gtk_menu_popup(GTK_MENU(menu),NULL,NULL,NULL,NULL,0,gtk_get_current_event_time());
+#endif
+
+  return TRUE;
+}
+
+static void push_sw_select_cb(GtkWidget *widget, gpointer data) {
+  CHOICE *choice=(CHOICE *)data;
+  encoder[choice->id].push_sw_function=choice->action;
+  gtk_button_set_label(GTK_BUTTON(choice->button),sw_string[choice->action]);
+}
+
+static gboolean push_sw_cb(GtkWidget *widget, GdkEvent *event, gpointer data) {
+  int sw=GPOINTER_TO_INT(data);
+  int i;
+
+  GtkWidget *menu=gtk_menu_new();
+  for(i=0;i<SWITCH_ACTIONS;i++) {
+    GtkWidget *menu_item=gtk_menu_item_new_with_label(sw_string[i]);
+    CHOICE *choice=g_new0(CHOICE,1);
+    choice->id=sw;
+    choice->action=i;
+    choice->button=widget;
+    g_signal_connect(menu_item,"activate",G_CALLBACK(push_sw_select_cb),choice);
+    gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
+fprintf(stderr,"%d=%s\n",i,sw_string[i]);
+  }
+  gtk_widget_show_all(menu);
+#if GTK_CHECK_VERSION(3,22,0)
+  gtk_menu_popup_at_pointer(GTK_MENU(menu),(GdkEvent *)event);
+// the following line of code is to work around the problem of the popup menu not having scroll bars.
+  gtk_menu_reposition(GTK_MENU(menu));
+#else
+  gtk_menu_popup(GTK_MENU(menu),NULL,NULL,NULL,NULL,0,gtk_get_current_event_time());
+#endif
+  return TRUE;
+}
+
+void i2c_controller_menu(GtkWidget *parent_window) {
+  gint row=0;
+  gint col=0;
+
+  GtkWidget *dialog=gtk_dialog_new_with_buttons("piHPSDR - I2C Controller",GTK_WINDOW(parent_window),GTK_DIALOG_DESTROY_WITH_PARENT,("OK"),GTK_RESPONSE_ACCEPT,"Cancel",GTK_RESPONSE_REJECT,NULL);
+
+  g_signal_connect (dialog, "response", G_CALLBACK (response_event), NULL);
+
+  GtkWidget *content=gtk_dialog_get_content_area(GTK_DIALOG(dialog));
+
+  GtkWidget *notebook=gtk_notebook_new();
+
+
+  // Encoders
+  GtkWidget *grid=gtk_grid_new();
+
+  gtk_grid_set_column_homogeneous(GTK_GRID(grid),FALSE);
+  gtk_grid_set_row_homogeneous(GTK_GRID(grid),TRUE);
+  gtk_grid_set_column_spacing (GTK_GRID(grid),2);
+  gtk_grid_set_row_spacing (GTK_GRID(grid),2);
+
+  for(int i=0;i<MAX_ENCODERS;i++) {
+    row=i%3;
+    col=(i/3)*4;
+
+    GtkWidget *address=gtk_label_new(NULL);
+    gchar addr[16];
+    g_sprintf(addr,"<b>0X%02X</b>",encoder[i].address);
+    gtk_label_set_markup (GTK_LABEL(address), addr);
+    gtk_grid_attach(GTK_GRID(grid),address,col,row,1,1);
+    col++;
+
+    GtkWidget *enable=gtk_check_button_new_with_label("Enable");
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (enable), encoder[i].enabled);
+    gtk_grid_attach(GTK_GRID(grid),enable,col,row,1,1);
+    col++;
+
+    GtkWidget *function=gtk_button_new_with_label(encoder_string[encoder[i].encoder_function]);
+    g_signal_connect(function,"button_press_event",G_CALLBACK(encoder_cb),GINT_TO_POINTER(i));
+    gtk_grid_attach(GTK_GRID(grid),function,col,row,1,1);
+    col++;
+  }
+  gtk_notebook_append_page(GTK_NOTEBOOK(notebook),grid,gtk_label_new("Encoders"));
+
+  // Encoder Push buttons
+  grid=gtk_grid_new();
+
+  gtk_grid_set_column_homogeneous(GTK_GRID(grid),FALSE);
+  gtk_grid_set_row_homogeneous(GTK_GRID(grid),TRUE);
+  gtk_grid_set_column_spacing (GTK_GRID(grid),2);
+  gtk_grid_set_row_spacing (GTK_GRID(grid),2);
+
+  for(int i=0;i<MAX_ENCODERS;i++) {
+    row=i%3;
+    col=(i/3)*4;
+
+    GtkWidget *address=gtk_label_new(NULL);
+    gchar addr[16];
+    g_sprintf(addr,"<b>0X%02X</b>",encoder[i].address);
+    gtk_label_set_markup (GTK_LABEL(address), addr);
+    gtk_grid_attach(GTK_GRID(grid),address,col,row,1,1);
+    col++;
+
+    GtkWidget *push_sw_enable=gtk_check_button_new();
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (push_sw_enable), encoder[i].push_sw_enabled);
+    gtk_grid_attach(GTK_GRID(grid),push_sw_enable,col,row,1,1);
+    col++;
+
+    GtkWidget *push_sw_function=gtk_button_new_with_label(sw_string[encoder[i].push_sw_function]);
+    g_signal_connect(push_sw_function,"button_press_event",G_CALLBACK(push_sw_cb),GINT_TO_POINTER(i));
+    gtk_grid_attach(GTK_GRID(grid),push_sw_function,col,row,1,1);
+    col++;
+  }
+  gtk_notebook_append_page(GTK_NOTEBOOK(notebook),grid,gtk_label_new("Encoder Switches"));
+
+  gtk_container_add(GTK_CONTAINER(content),notebook);
+
+  sub_menu=dialog;
+  gtk_widget_show_all(dialog);
+}
+
diff --git a/i2c_controller_menu.h b/i2c_controller_menu.h
new file mode 100644 (file)
index 0000000..9a4718f
--- /dev/null
@@ -0,0 +1,3 @@
+
+extern void i2c_controller_menu(GtkWidget *parent);
+
diff --git a/main.c b/main.c
index bc292043d2efedb86266ee70610bf9813f2a96ea..ac59cd922cebb3d2cfc9b798dedbc987a2f39b43 100644 (file)
--- a/main.c
+++ b/main.c
 #include "channel.h"
 #include "discovered.h"
 #include "configure.h"
+#include "actions.h"
+#ifdef GPIO
 #include "gpio.h"
+#endif
 #include "wdsp.h"
 #include "new_menu.h"
 #include "radio.h"
index 7f5e910f76cbd068745a4372d13ea6b21ebc7ec8..b992d82ef65ef7f53159a13314f06e53c7e6f82f 100644 (file)
@@ -45,6 +45,7 @@ static void cleanup() {
     gtk_widget_destroy(dialog);
     dialog=NULL;
     sub_menu=NULL;
+    active_menu=NO_MENU;
   }
 }
 
index 0bf1aeb7156b6fefd0336bc297e8a7359bb3f630..b827564a17b804bad3672ce18cae6f0576254c05 100644 (file)
 #include "vfo_menu.h"
 #include "fft_menu.h"
 #include "main.h"
+#include "actions.h"
+#ifdef GPIO
 #include "gpio.h"
+#endif
 #include "old_protocol.h"
 #include "new_protocol.h"
 #ifdef CLIENT_SERVER
 #include "server_menu.h"
 #endif
+#ifdef I2C_CONTROLLER
+#include "i2c_controller_menu.h"
+#endif
 
 
 static GtkWidget *menu_b=NULL;
@@ -468,6 +474,18 @@ static gboolean server_cb (GtkWidget *widget, GdkEventButton *event, gpointer da
 }
 #endif
 
+#ifdef I2C_CONTROLLER
+void start_i2c_controller() {
+  cleanup();
+  i2c_controller_menu(top_window);
+}
+
+static gboolean i2c_controller_cb (GtkWidget *widget, GdkEventButton *event, gpointer data) {
+  start_i2c_controller();
+  return TRUE;
+}
+#endif
+
 void new_menu()
 {
   int i;
@@ -616,12 +634,12 @@ void new_menu()
     i++;
 
 #ifdef GPIO
-    GtkWidget *encoders_b=gtk_button_new_with_label("Encoders");
-    g_signal_connect (encoders_b, "button-press-event", G_CALLBACK(encoder_cb), NULL);
-    gtk_grid_attach(GTK_GRID(grid),encoders_b,(i%5),i/5,1,1);
-    i++;
+    if(controller!=NO_CONTROLLER) {
+      GtkWidget *encoders_b=gtk_button_new_with_label("Encoders");
+      g_signal_connect (encoders_b, "button-press-event", G_CALLBACK(encoder_cb), NULL);
+      gtk_grid_attach(GTK_GRID(grid),encoders_b,(i%5),i/5,1,1);
+      i++;
 
-    if(controller==CONTROLLER2_V1 || controller==CONTROLLER2_V2) {
       GtkWidget *switches_b=gtk_button_new_with_label("Switches");
       g_signal_connect (switches_b, "button-press-event", G_CALLBACK(switch_cb), NULL);
       gtk_grid_attach(GTK_GRID(grid),switches_b,(i%5),i/5,1,1);
@@ -629,6 +647,13 @@ void new_menu()
     }
 #endif
 
+#ifdef I2C_CONTROLLER
+    GtkWidget *i2c_controller_b=gtk_button_new_with_label("I2C Controller");
+    g_signal_connect (i2c_controller_b, "button-press-event", G_CALLBACK(i2c_controller_cb), NULL);
+    gtk_grid_attach(GTK_GRID(grid),i2c_controller_b,(i%5),i/5,1,1);
+    i++;
+#endif
+
 //
 //  We need at least two receivers and two ADCs to do DIVERSITY
 //
index f426b977d2c1c80632090b7f822d95816beb3adb..433faa992577012b95017746966b5ff3a06a66cc 100644 (file)
@@ -47,6 +47,7 @@ static void cleanup() {
     gtk_widget_destroy(dialog);
     dialog=NULL;
     sub_menu=NULL;
+    active_menu=NO_MENU;
   }
 }
 
diff --git a/radio.c b/radio.c
index 4f2d660831032935d60e080f733acd6238148f6d..b445769234b4a3a41daaf92392511cc1a63d3cac 100644 (file)
--- a/radio.c
+++ b/radio.c
 #ifdef SOAPYSDR
 #include "soapy_protocol.h"
 #endif
+#include "actions.h"
 #ifdef GPIO
 #include "gpio.h"
 #endif
+#ifdef I2C_CONTROLLER
+#include "i2c_controller.h"
+#endif
 #include "vfo.h"
 #include "vox.h"
 #include "meter.h"
@@ -107,10 +111,12 @@ static GtkWidget *panadapter;
 static GtkWidget *waterfall;
 static GtkWidget *audio_waterfall;
 
+/*
 #ifdef GPIO
 static GtkWidget *encoders;
 static cairo_surface_t *encoders_surface = NULL;
 #endif
+*/
        gint sat_mode;
 
        int region=REGION_OTHER;
@@ -597,6 +603,12 @@ if(!radio_is_remote) {
 #endif
   }
 
+#ifdef I2C_CONTROLLER
+  if(i2c_controller_init()<0) {
+    g_print("%s: I2C_CONTROLLER failed to initialize i2c\n", __FUNCTION__);
+  }
+#endif
+
 #ifdef LOCALCW
   // init local keyer if enabled
   if (cw_keyer_internal == 0) {
index 25f07b41a01f808c1304afe4d83613e1b2786da8..75a3cdbb4c26d7091e70320af0bb8d1e6654b5df 100644 (file)
 #ifdef SOAPYSDR
 #include "soapy_protocol.h"
 #endif
+#include "actions.h"
+#ifdef GPIO
 #include "gpio.h"
+#endif
 #include "vfo.h"
 #include "ext.h"
 #ifdef CLIENT_SERVER
index ece8eb77e22dd58128de6ddc090f7d8caf6ede4b..cb4b68d05e83458290de78fc179f63c73fc8ae1d 100644 (file)
@@ -38,6 +38,7 @@
 #include "rx_panadapter.h"
 #include "vfo.h"
 #include "mode.h"
+#include "actions.h"
 #ifdef GPIO
 #include "gpio.h"
 #endif
@@ -573,6 +574,7 @@ void rx_panadapter_update(RECEIVER *rx) {
     cairo_pattern_destroy(gradient);
   }
 
+/*
 #ifdef GPIO
   if(rx->id==0 && controller==CONTROLLER1) {
 
@@ -597,7 +599,7 @@ void rx_panadapter_update(RECEIVER *rx) {
     }
   }
 #endif
-
+*/
   if(display_sequence_errors) {
     if(sequence_errors!=0) {
       cairo_move_to(cr,100.0,50.0);
index 14f722e86be48aabecdd731e99dc9fd45c46f77d..02e740b7038dd28493cace85d1ec775ef4bd4fb4 100644 (file)
@@ -18,6 +18,7 @@
 */
 
 #include <gtk/gtk.h>
+#include <glib/gprintf.h>
 #include <stdio.h>
 #include <string.h>
 
@@ -31,6 +32,8 @@
 #include "receiver.h"
 #include "vfo.h"
 #include "button_text.h"
+#include "toolbar.h"
+#include "actions.h"
 #include "gpio.h"
 #include "i2c.h"
 
@@ -44,6 +47,8 @@ static GtkWidget *parent_window=NULL;
 
 static GtkWidget *dialog=NULL;
 
+static SWITCH *temp_switches;
+
 
 static void cleanup() {
   if(dialog!=NULL) {
@@ -64,17 +69,22 @@ static gboolean delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_d
   return FALSE;
 }
 
+void switch_page_cb(GtkNotebook *notebook,GtkWidget *page,guint page_num,gpointer user_data) {
+  g_print("%s: page %d\n",__FUNCTION__,page_num);
+  temp_switches=switches_controller1[page_num];
+}
 
-static void sw_select_cb(GtkWidget *widget, gpointer data) {
+static void switch_select_cb(GtkWidget *widget, gpointer data) {
   char text[128];
   CHOICE *choice=(CHOICE *)data;
-  sw_action[choice->sw]=choice->action;
+  temp_switches[choice->sw].switch_function=choice->action;
   GtkWidget *label=gtk_bin_get_child(GTK_BIN(choice->button));
   sprintf(text,"<span size=\"smaller\">%s</span>",sw_string[choice->action]);
   gtk_label_set_markup (GTK_LABEL(label), text);
+  update_toolbar_labels();
 }
 
-static gboolean sw_cb(GtkWidget *widget, GdkEvent *event, gpointer data) {
+static gboolean switch_cb(GtkWidget *widget, GdkEvent *event, gpointer data) {
   int sw=GPOINTER_TO_INT(data);
   int i;
 
@@ -85,9 +95,8 @@ static gboolean sw_cb(GtkWidget *widget, GdkEvent *event, gpointer data) {
     choice->sw=sw;
     choice->action=i;
     choice->button=widget;
-    g_signal_connect(menu_item,"activate",G_CALLBACK(sw_select_cb),choice);
+    g_signal_connect(menu_item,"activate",G_CALLBACK(switch_select_cb),choice);
     gtk_menu_shell_append(GTK_MENU_SHELL(menu),menu_item);
-fprintf(stderr,"%d=%s\n",i,sw_string[i]);
   }
   gtk_widget_show_all(menu);
 #if GTK_CHECK_VERSION(3,22,0)
@@ -100,293 +109,114 @@ fprintf(stderr,"%d=%s\n",i,sw_string[i]);
   return TRUE;
 }
 
+static void response_event(GtkWidget *dialog,gint id,gpointer user_data) {
+  g_print("%s: id=%d\n",__FUNCTION__,id);
+  if(id==GTK_RESPONSE_ACCEPT) {
+    g_print("%s: ACCEPT\n",__FUNCTION__);
+  }
+  gtk_widget_destroy(dialog);
+  dialog=NULL;
+  active_menu=NO_MENU;
+  sub_menu=NULL;
+}
+
 void switch_menu(GtkWidget *parent) {
-  int row=0;
-  int col=0;
-  char label[64];
-  int i;
+  gint row;
+  gint col;
+  gchar label[64];
+  GtkWidget *notebook;
+  GtkWidget *grid;
+  gint function=0;
 
-  dialog=gtk_dialog_new();
-  gtk_window_set_transient_for(GTK_WINDOW(dialog),GTK_WINDOW(parent_window));
-  //gtk_window_set_decorated(GTK_WINDOW(dialog),FALSE);
-  char title[32];
-  sprintf(title,"piHPSDR - Encoder Actions:");
-  gtk_window_set_title(GTK_WINDOW(dialog),title);
-  g_signal_connect (dialog, "delete_event", G_CALLBACK (delete_event), NULL);
+
+  dialog=gtk_dialog_new_with_buttons("piHPSDR - Switch Actions",GTK_WINDOW(parent),GTK_DIALOG_DESTROY_WITH_PARENT,("OK"),GTK_RESPONSE_ACCEPT,NULL);
+  g_signal_connect (dialog, "response", G_CALLBACK (response_event), NULL);
 
   GtkWidget *content=gtk_dialog_get_content_area(GTK_DIALOG(dialog));
 
-  GtkWidget *grid=gtk_grid_new();
+  function=0;
+
+  if(controller==CONTROLLER1) {
+    notebook=gtk_notebook_new();
+  }
+next_function_set:
 
+  grid=gtk_grid_new();
   gtk_grid_set_column_homogeneous(GTK_GRID(grid),FALSE);
   gtk_grid_set_row_homogeneous(GTK_GRID(grid),FALSE);
   gtk_grid_set_column_spacing (GTK_GRID(grid),2);
   gtk_grid_set_row_spacing (GTK_GRID(grid),2);
 
-  GtkWidget *close_b=gtk_button_new_with_label("Close");
-  GtkWidget *close_label=gtk_bin_get_child(GTK_BIN(close_b));
-  sprintf(label,"<span size=\"smaller\">Close</span>");
-  gtk_label_set_markup (GTK_LABEL(close_label), label);
-  g_signal_connect (close_b, "pressed", G_CALLBACK(close_cb), NULL);
-  gtk_grid_attach(GTK_GRID(grid),close_b,col,row,1,1);
 
-  row++;
+  row=0;
   col=0;
 
+  gint max_switches=MAX_SWITCHES;
   switch(controller) {
-    default:
-      {
-      GtkWidget *sw7_title=gtk_label_new("SW7: ");
-      gtk_grid_attach(GTK_GRID(grid),sw7_title,col,row,1,1);
-      col++;
-
-      GtkWidget *sw7_combo_box=gtk_combo_box_text_new();
-      for(i=0;i<SWITCH_ACTIONS;i++) {
-        gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(sw7_combo_box),NULL,sw_string[i]);
-      }
-      gtk_combo_box_set_active(GTK_COMBO_BOX(sw7_combo_box),sw_action[6]);
-      g_signal_connect(sw7_combo_box,"changed",G_CALLBACK(sw_cb),GINT_TO_POINTER(CONTROLLER1_SW7));
-      gtk_grid_attach(GTK_GRID(grid),sw7_combo_box,col,row,1,1);
-      col++;
-
-      GtkWidget *sw1_title=gtk_label_new("SW1: ");
-      gtk_grid_attach(GTK_GRID(grid),sw1_title,col,row,1,1);
-      col++;
-
-      GtkWidget *sw1_combo_box=gtk_combo_box_text_new();
-      for(i=0;i<SWITCH_ACTIONS;i++) {
-        gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(sw1_combo_box),NULL,sw_string[i]);
-      }
-      gtk_combo_box_set_active(GTK_COMBO_BOX(sw1_combo_box),sw_action[0]);
-      g_signal_connect(sw1_combo_box,"changed",G_CALLBACK(sw_cb),GINT_TO_POINTER(CONTROLLER1_SW1));
-      gtk_grid_attach(GTK_GRID(grid),sw1_combo_box,col,row,1,1);
-      row++;
-      col=0;
-
-      GtkWidget *sw2_title=gtk_label_new("SW2: ");
-      gtk_grid_attach(GTK_GRID(grid),sw2_title,col,row,1,1);
-      col++;
-
-      GtkWidget *sw2_combo_box=gtk_combo_box_text_new();
-      for(i=0;i<SWITCH_ACTIONS;i++) {
-        gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(sw2_combo_box),NULL,sw_string[i]);
-      }
-      gtk_combo_box_set_active(GTK_COMBO_BOX(sw2_combo_box),sw_action[1]);
-      g_signal_connect(sw2_combo_box,"changed",G_CALLBACK(sw_cb),GINT_TO_POINTER(CONTROLLER1_SW2));
-      gtk_grid_attach(GTK_GRID(grid),sw2_combo_box,col,row,1,1);
-      col++;
-
-      GtkWidget *sw3_title=gtk_label_new("SW3: ");
-      gtk_grid_attach(GTK_GRID(grid),sw3_title,col,row,1,1);
-      col++;
-
-      GtkWidget *sw3_combo_box=gtk_combo_box_text_new();
-      for(i=0;i<SWITCH_ACTIONS;i++) {
-        gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(sw3_combo_box),NULL,sw_string[i]);
-      }
-      gtk_combo_box_set_active(GTK_COMBO_BOX(sw3_combo_box),sw_action[2]);
-      g_signal_connect(sw3_combo_box,"changed",G_CALLBACK(sw_cb),GINT_TO_POINTER(CONTROLLER1_SW3));
-      gtk_grid_attach(GTK_GRID(grid),sw3_combo_box,col,row,1,1);
-      row++;
-      col=0;
-
-      GtkWidget *sw4_title=gtk_label_new("SW4: ");
-      gtk_grid_attach(GTK_GRID(grid),sw4_title,col,row,1,1);
-      col++;
-
-      GtkWidget *sw4_combo_box=gtk_combo_box_text_new();
-      for(i=0;i<SWITCH_ACTIONS;i++) {
-        gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(sw4_combo_box),NULL,sw_string[i]);
-      }
-      gtk_combo_box_set_active(GTK_COMBO_BOX(sw4_combo_box),sw_action[3]);
-      g_signal_connect(sw4_combo_box,"changed",G_CALLBACK(sw_cb),GINT_TO_POINTER(CONTROLLER1_SW4));
-      gtk_grid_attach(GTK_GRID(grid),sw4_combo_box,col,row,1,1);
-      col++;
-
-      GtkWidget *sw5_title=gtk_label_new("SW5: ");
-      gtk_grid_attach(GTK_GRID(grid),sw5_title,col,row,1,1);
-      col++;
-
-      GtkWidget *sw5_combo_box=gtk_combo_box_text_new();
-      for(i=0;i<SWITCH_ACTIONS;i++) {
-        gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(sw5_combo_box),NULL,sw_string[i]);
-      }
-      gtk_combo_box_set_active(GTK_COMBO_BOX(sw5_combo_box),sw_action[4]);
-      g_signal_connect(sw5_combo_box,"changed",G_CALLBACK(sw_cb),GINT_TO_POINTER(CONTROLLER1_SW5));
-      gtk_grid_attach(GTK_GRID(grid),sw5_combo_box,col,row,1,1);
-      row++;
-      col=0;
-
-      GtkWidget *sw6_title=gtk_label_new("SW6: ");
-      gtk_grid_attach(GTK_GRID(grid),sw6_title,col,row,1,1);
-      col++;
-
-      GtkWidget *sw6_combo_box=gtk_combo_box_text_new();
-      for(i=0;i<SWITCH_ACTIONS;i++) {
-        gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(sw6_combo_box),NULL,sw_string[i]);
-      }
-      gtk_combo_box_set_active(GTK_COMBO_BOX(sw6_combo_box),sw_action[5]);
-      g_signal_connect(sw6_combo_box,"changed",G_CALLBACK(sw_cb),GINT_TO_POINTER(CONTROLLER1_SW6));
-      gtk_grid_attach(GTK_GRID(grid),sw6_combo_box,col,row,1,1);
-      col++;
-
-      GtkWidget *sw8_title=gtk_label_new("SW8: ");
-      gtk_grid_attach(GTK_GRID(grid),sw8_title,col,row,1,1);
-      col++;
-
-      GtkWidget *sw8_combo_box=gtk_combo_box_text_new();
-      for(i=0;i<SWITCH_ACTIONS;i++) {
-        gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(sw8_combo_box),NULL,sw_string[i]);
-      }
-      gtk_combo_box_set_active(GTK_COMBO_BOX(sw8_combo_box),sw_action[7]);
-      g_signal_connect(sw8_combo_box,"changed",G_CALLBACK(sw_cb),GINT_TO_POINTER(CONTROLLER1_SW8));
-      gtk_grid_attach(GTK_GRID(grid),sw8_combo_box,col,row,1,1);
-      col++;
-      }
+    case NO_CONTROLLER:
+      max_switches=0;
+      temp_switches=switches_no_controller;
+      break;
+    case CONTROLLER1:
+      max_switches=8;
+      temp_switches=switches_controller1[function];
       break;
-
     case CONTROLLER2_V1:
+      max_switches=16;
+      temp_switches=switches_controller2_v1;
+      break;
     case CONTROLLER2_V2:
-      {
-      col=8;
-
-      GtkWidget *sw13=gtk_button_new_with_label(sw_string[sw_action[CONTROLLER2_SW13]]);
-      GtkWidget *sw13_label=gtk_bin_get_child(GTK_BIN(sw13));
-      sprintf(label,"<span size=\"smaller\">%s</span>",sw_string[sw_action[CONTROLLER2_SW13]]);
-      gtk_label_set_markup (GTK_LABEL(sw13_label), label);
-      gtk_grid_attach(GTK_GRID(grid),sw13,col,row,1,1);
-      g_signal_connect (sw13, "button_press_event", G_CALLBACK(sw_cb), GINT_TO_POINTER(CONTROLLER2_SW13));
-      row++;
-      col=7;
-
-      GtkWidget *sw12=gtk_button_new_with_label(sw_string[sw_action[CONTROLLER2_SW12]]);
-      GtkWidget *sw12_label=gtk_bin_get_child(GTK_BIN(sw12));
-      sprintf(label,"<span size=\"smaller\">%s</span>",sw_string[sw_action[CONTROLLER2_SW12]]);
-      gtk_label_set_markup (GTK_LABEL(sw12_label), label);
-      gtk_grid_attach(GTK_GRID(grid),sw12,col,row,1,1);
-      g_signal_connect (sw12, "button_press_event", G_CALLBACK(sw_cb), GINT_TO_POINTER(CONTROLLER2_SW12));
-      col++;
-
-      GtkWidget *sw11=gtk_button_new_with_label(sw_string[sw_action[CONTROLLER2_SW11]]);
-      GtkWidget *sw11_label=gtk_bin_get_child(GTK_BIN(sw11));
-      sprintf(label,"<span size=\"smaller\">%s</span>",sw_string[sw_action[CONTROLLER2_SW11]]);
-      gtk_label_set_markup (GTK_LABEL(sw11_label), label);
-      gtk_grid_attach(GTK_GRID(grid),sw11,col,row,1,1);
-      g_signal_connect (sw11, "button_press_event", G_CALLBACK(sw_cb), GINT_TO_POINTER(CONTROLLER2_SW11));
-      row++;
-      col=7;
-
-      GtkWidget *sw10=gtk_button_new_with_label(sw_string[sw_action[CONTROLLER2_SW10]]);
-      GtkWidget *sw10_label=gtk_bin_get_child(GTK_BIN(sw10));
-      sprintf(label,"<span size=\"smaller\">%s</span>",sw_string[sw_action[CONTROLLER2_SW10]]);
-      gtk_label_set_markup (GTK_LABEL(sw10_label), label);
-      gtk_grid_attach(GTK_GRID(grid),sw10,col,row,1,1);
-      g_signal_connect (sw10, "button_press_event", G_CALLBACK(sw_cb), GINT_TO_POINTER(CONTROLLER2_SW10));
-      col++;
-
-      GtkWidget *sw9=gtk_button_new_with_label(sw_string[sw_action[CONTROLLER2_SW9]]);
-      GtkWidget *sw9_label=gtk_bin_get_child(GTK_BIN(sw9));
-      sprintf(label,"<span size=\"smaller\">%s</span>",sw_string[sw_action[CONTROLLER2_SW9]]);
-      gtk_label_set_markup (GTK_LABEL(sw9_label), label);
-      gtk_grid_attach(GTK_GRID(grid),sw9,col,row,1,1);
-      g_signal_connect (sw9, "button_press_event", G_CALLBACK(sw_cb), GINT_TO_POINTER(CONTROLLER2_SW9));
-      row++;
-      col=7;
-
-      GtkWidget *sw7=gtk_button_new_with_label(sw_string[sw_action[CONTROLLER2_SW7]]);
-      GtkWidget *sw7_label=gtk_bin_get_child(GTK_BIN(sw7));
-      sprintf(label,"<span size=\"smaller\">%s</span>",sw_string[sw_action[CONTROLLER2_SW7]]);
-      gtk_label_set_markup (GTK_LABEL(sw7_label), label);
-      gtk_grid_attach(GTK_GRID(grid),sw7,col,row,1,1);
-      g_signal_connect (sw7, "button_press_event", G_CALLBACK(sw_cb), GINT_TO_POINTER(CONTROLLER2_SW7));
-      col++;
-
-      GtkWidget *sw8=gtk_button_new_with_label(sw_string[sw_action[CONTROLLER2_SW8]]);
-      GtkWidget *sw8_label=gtk_bin_get_child(GTK_BIN(sw8));
-      sprintf(label,"<span size=\"smaller\">%s</span>",sw_string[sw_action[CONTROLLER2_SW8]]);
-      gtk_label_set_markup (GTK_LABEL(sw8_label), label);
-      gtk_grid_attach(GTK_GRID(grid),sw8,col,row,1,1);
-      g_signal_connect (sw8, "button_press_event", G_CALLBACK(sw_cb), GINT_TO_POINTER(CONTROLLER2_SW8));
-      row++;
-      col=7;
-
-      GtkWidget *sw16=gtk_button_new_with_label(sw_string[sw_action[CONTROLLER2_SW16]]);
-      GtkWidget *sw16_label=gtk_bin_get_child(GTK_BIN(sw16));
-      sprintf(label,"<span size=\"smaller\">%s</span>",sw_string[sw_action[CONTROLLER2_SW16]]);
-      gtk_label_set_markup (GTK_LABEL(sw16_label), label);
-      gtk_grid_attach(GTK_GRID(grid),sw16,col,row,1,1);
-      g_signal_connect (sw16, "button_press_event", G_CALLBACK(sw_cb), GINT_TO_POINTER(CONTROLLER2_SW16));
-      col++;
-
-      GtkWidget *sw17=gtk_button_new_with_label(sw_string[sw_action[CONTROLLER2_SW17]]);
-      GtkWidget *sw17_label=gtk_bin_get_child(GTK_BIN(sw17));
-      sprintf(label,"<span size=\"smaller\">%s</span>",sw_string[sw_action[CONTROLLER2_SW17]]);
-      gtk_label_set_markup (GTK_LABEL(sw17_label), label);
-      gtk_grid_attach(GTK_GRID(grid),sw17,col,row,1,1);
-      g_signal_connect (sw17, "button_press_event", G_CALLBACK(sw_cb), GINT_TO_POINTER(CONTROLLER2_SW17));
-      row++;
-      col=0;
-
-      GtkWidget *sw2=gtk_button_new_with_label(sw_string[sw_action[CONTROLLER2_SW2]]);
-      GtkWidget *sw2_label=gtk_bin_get_child(GTK_BIN(sw2));
-      sprintf(label,"<span size=\"smaller\">%s</span>",sw_string[sw_action[CONTROLLER2_SW2]]);
-      gtk_label_set_markup (GTK_LABEL(sw2_label), label);
-      gtk_grid_attach(GTK_GRID(grid),sw2,col,row,1,1);
-      g_signal_connect (sw2, "button_press_event", G_CALLBACK(sw_cb), GINT_TO_POINTER(CONTROLLER2_SW2));
-      col++;
-  
-      GtkWidget *sw3=gtk_button_new_with_label(sw_string[sw_action[CONTROLLER2_SW3]]);
-      GtkWidget *sw3_label=gtk_bin_get_child(GTK_BIN(sw3));
-      sprintf(label,"<span size=\"smaller\">%s</span>",sw_string[sw_action[CONTROLLER2_SW3]]);
-      gtk_label_set_markup (GTK_LABEL(sw3_label), label);
-      gtk_grid_attach(GTK_GRID(grid),sw3,col,row,1,1);
-      g_signal_connect (sw3, "button_press_event", G_CALLBACK(sw_cb), GINT_TO_POINTER(CONTROLLER2_SW3));
-      col++;
-  
-      GtkWidget *sw4=gtk_button_new_with_label(sw_string[sw_action[CONTROLLER2_SW4]]);
-      GtkWidget *sw4_label=gtk_bin_get_child(GTK_BIN(sw4));
-      sprintf(label,"<span size=\"smaller\">%s</span>",sw_string[sw_action[CONTROLLER2_SW4]]);
-      gtk_label_set_markup (GTK_LABEL(sw4_label), label);
-      gtk_grid_attach(GTK_GRID(grid),sw4,col,row,1,1);
-      g_signal_connect (sw4, "button_press_event", G_CALLBACK(sw_cb), GINT_TO_POINTER(CONTROLLER2_SW4));
-      col++;
-  
-      GtkWidget *sw5=gtk_button_new_with_label(sw_string[sw_action[CONTROLLER2_SW5]]);
-      GtkWidget *sw5_label=gtk_bin_get_child(GTK_BIN(sw5));
-      sprintf(label,"<span size=\"smaller\">%s</span>",sw_string[sw_action[CONTROLLER2_SW5]]);
-      gtk_label_set_markup (GTK_LABEL(sw5_label), label);
-      gtk_grid_attach(GTK_GRID(grid),sw5,col,row,1,1);
-      g_signal_connect (sw5, "button_press_event", G_CALLBACK(sw_cb), GINT_TO_POINTER(CONTROLLER2_SW5));
-      col++;
-  
-      GtkWidget *sw6=gtk_button_new_with_label(sw_string[sw_action[CONTROLLER2_SW6]]);
-      GtkWidget *sw6_label=gtk_bin_get_child(GTK_BIN(sw6));
-      sprintf(label,"<span size=\"smaller\">%s</span>",sw_string[sw_action[CONTROLLER2_SW6]]);
-      gtk_label_set_markup (GTK_LABEL(sw6_label), label);
-      gtk_grid_attach(GTK_GRID(grid),sw6,col,row,1,1);
-      g_signal_connect (sw6, "button_press_event", G_CALLBACK(sw_cb), GINT_TO_POINTER(CONTROLLER2_SW6));
-      col++;
-  
-      GtkWidget *sw14=gtk_button_new_with_label(sw_string[sw_action[CONTROLLER2_SW14]]);
-      GtkWidget *sw14_label=gtk_bin_get_child(GTK_BIN(sw14));
-      sprintf(label,"<span size=\"smaller\">%s</span>",sw_string[sw_action[CONTROLLER2_SW14]]);
-      gtk_label_set_markup (GTK_LABEL(sw14_label), label);
-      gtk_grid_attach(GTK_GRID(grid),sw14,col,row,1,1);
-      g_signal_connect (sw14, "button_press_event", G_CALLBACK(sw_cb), GINT_TO_POINTER(CONTROLLER2_SW14));
-      col++;
-  
-      GtkWidget *sw15=gtk_button_new_with_label(sw_string[sw_action[CONTROLLER2_SW15]]);
-      GtkWidget *sw15_label=gtk_bin_get_child(GTK_BIN(sw15));
-      sprintf(label,"<span size=\"smaller\">%s</span>",sw_string[sw_action[CONTROLLER2_SW15]]);
-      gtk_label_set_markup (GTK_LABEL(sw15_label), label);
-      gtk_grid_attach(GTK_GRID(grid),sw15,col,row,1,1);
-      g_signal_connect (sw15, "button_press_event", G_CALLBACK(sw_cb), GINT_TO_POINTER(CONTROLLER2_SW15));
-      col++;
-      }
+      max_switches=16;
+      temp_switches=switches_controller2_v2;
       break;
   }
 
-  gtk_container_add(GTK_CONTAINER(content),grid);
+  GtkWidget *widget=gtk_label_new(NULL);
+  gtk_label_set_markup(GTK_LABEL(widget),"<b>Switch</b>");
+  gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
+  col++;
+
+  widget=gtk_label_new(NULL);
+  gtk_label_set_markup(GTK_LABEL(widget),"<b>Function</b>");
+  gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
+
+  row++;
+  col=0;
+
+  for(int i=0;i<max_switches;i++) {
+    widget=gtk_label_new(NULL);
+    g_sprintf(label,"<b>%d</b>",i);
+    gtk_label_set_markup (GTK_LABEL(widget), label);
+    gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
+    col++;
+
+    if(controller==CONTROLLER1 && (i==0 || i==(max_switches-1))) {
+      widget=gtk_label_new(NULL);
+      g_sprintf(label,"<b>%s</b>",sw_string[temp_switches[i].switch_function]);
+      gtk_label_set_markup (GTK_LABEL(widget), label);
+    } else {
+      widget=gtk_button_new_with_label(sw_string[temp_switches[i].switch_function]);
+      g_signal_connect(widget,"button_press_event",G_CALLBACK(switch_cb),GINT_TO_POINTER(i));
+    }
+    gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1);
+
+    row++;
+    col=0;
+  }
+
+  if(controller==CONTROLLER1) {
+    g_sprintf(label,"Function %d",function);
+    gtk_notebook_append_page(GTK_NOTEBOOK(notebook),grid,gtk_label_new(label));
+    function++;
+    if(function<MAX_FUNCTIONS) {
+      goto next_function_set;
+    }
+    gtk_container_add(GTK_CONTAINER(content),notebook);
+    g_signal_connect (notebook, "switch-page",G_CALLBACK(switch_page_cb),NULL);
+  } else {
+    gtk_container_add(GTK_CONTAINER(content),grid);
+  }
 
   sub_menu=dialog;
 
index fa0805627322d065064702c2001cab26a50924db..1ed7d6fd93a08e0f744111c459157ffe011dcaad 100644 (file)
--- a/toolbar.c
+++ b/toolbar.c
@@ -24,6 +24,7 @@
 #include <stdlib.h>
 #include <string.h>
 #ifdef GPIO
+#include "actions.h"
 #include "gpio.h"
 #endif
 #include "toolbar.h"
@@ -102,121 +103,14 @@ static gboolean xit_timer_cb(gpointer data) {
 }
 
 void update_toolbar_labels() {
-  switch(function) {
-    case 0:
-      if(can_transmit) {
-        gtk_button_set_label(GTK_BUTTON(sim_mox),"Mox");
-      } else {
-        gtk_button_set_label(GTK_BUTTON(sim_mox),"");
-      }
-      gtk_button_set_label(GTK_BUTTON(sim_s1),"Band");
-      gtk_button_set_label(GTK_BUTTON(sim_s2),"BStack");
-      gtk_button_set_label(GTK_BUTTON(sim_s3),"Mode");
-      gtk_button_set_label(GTK_BUTTON(sim_s4),"Filter");
-      gtk_button_set_label(GTK_BUTTON(sim_s5),"Noise");
-      gtk_button_set_label(GTK_BUTTON(sim_s6),"AGC");
-      set_button_text_color(sim_s1,"black");
-      set_button_text_color(sim_s2,"black");
-      break;
-    case 1:
-      if(can_transmit) {
-        gtk_button_set_label(GTK_BUTTON(sim_mox),"Mox");
-      } else {
-        gtk_button_set_label(GTK_BUTTON(sim_mox),"");
-      }
-      gtk_button_set_label(GTK_BUTTON(sim_s1),"Lock");
-      gtk_button_set_label(GTK_BUTTON(sim_s2),"CTUN");
-      gtk_button_set_label(GTK_BUTTON(sim_s3),"A>B");
-      gtk_button_set_label(GTK_BUTTON(sim_s4),"A<B");
-      gtk_button_set_label(GTK_BUTTON(sim_s5),"A<>B");
-      if(can_transmit) {
-        gtk_button_set_label(GTK_BUTTON(sim_s6),"Split");
-      } else {
-        gtk_button_set_label(GTK_BUTTON(sim_s6),"");
-      }
-      break;
-    case 2:
-      if(can_transmit) {
-        gtk_button_set_label(GTK_BUTTON(sim_mox),"Mox");
-      } else {
-        gtk_button_set_label(GTK_BUTTON(sim_mox),"");
-      }
-      gtk_button_set_label(GTK_BUTTON(sim_s1),"Freq");
-      gtk_button_set_label(GTK_BUTTON(sim_s2),"Mem");
-      gtk_button_set_label(GTK_BUTTON(sim_s3),"RIT");
-      gtk_button_set_label(GTK_BUTTON(sim_s4),"RIT+");
-      gtk_button_set_label(GTK_BUTTON(sim_s5),"RIT-");
-      gtk_button_set_label(GTK_BUTTON(sim_s6),"RIT CL");
-      break;
-    case 3:
-      if(can_transmit) {
-        gtk_button_set_label(GTK_BUTTON(sim_mox),"Mox");
-      } else {
-        gtk_button_set_label(GTK_BUTTON(sim_mox),"");
-      }
-      gtk_button_set_label(GTK_BUTTON(sim_s1),"Freq");
-      gtk_button_set_label(GTK_BUTTON(sim_s2),"Mem");
-      if(can_transmit) {
-        gtk_button_set_label(GTK_BUTTON(sim_s3),"XIT");
-        gtk_button_set_label(GTK_BUTTON(sim_s4),"XIT+");
-        gtk_button_set_label(GTK_BUTTON(sim_s5),"XIT-");
-        gtk_button_set_label(GTK_BUTTON(sim_s6),"XIT CL");
-      } else {
-        gtk_button_set_label(GTK_BUTTON(sim_s3),"");
-        gtk_button_set_label(GTK_BUTTON(sim_s4),"");
-        gtk_button_set_label(GTK_BUTTON(sim_s5),"");
-        gtk_button_set_label(GTK_BUTTON(sim_s6),"");
-      }
-      break;
-    case 4:
-      if(can_transmit) {
-        gtk_button_set_label(GTK_BUTTON(sim_mox),"Mox");
-      } else {
-        gtk_button_set_label(GTK_BUTTON(sim_mox),"");
-      }
-      gtk_button_set_label(GTK_BUTTON(sim_s1),"Freq");
-      if(can_transmit) {
-        gtk_button_set_label(GTK_BUTTON(sim_s2),"Split");
-        gtk_button_set_label(GTK_BUTTON(sim_s3),"Duplex");
-        gtk_button_set_label(GTK_BUTTON(sim_s4),"SAT");
-        gtk_button_set_label(GTK_BUTTON(sim_s5),"RSAT");
-      } else {
-        gtk_button_set_label(GTK_BUTTON(sim_s2),"");
-        gtk_button_set_label(GTK_BUTTON(sim_s3),"");
-        gtk_button_set_label(GTK_BUTTON(sim_s4),"");
-        gtk_button_set_label(GTK_BUTTON(sim_s5),"");
-      }
-      gtk_button_set_label(GTK_BUTTON(sim_s6),"");
-      break;
-    case 5:
-      if(can_transmit) {
-        gtk_button_set_label(GTK_BUTTON(sim_mox),"Tune");
-        if(OCtune!=0 && OCfull_tune_time!=0) {
-          gtk_button_set_label(GTK_BUTTON(sim_s1),"Full");
-        } else {
-          gtk_button_set_label(GTK_BUTTON(sim_s1),"");
-        }
-      } else {
-        gtk_button_set_label(GTK_BUTTON(sim_mox),"");
-        gtk_button_set_label(GTK_BUTTON(sim_s1),"");
-      }
-      if(OCtune!=0 && OCmemory_tune_time!=0) {
-        gtk_button_set_label(GTK_BUTTON(sim_s2),"Memory");
-      } else {
-        gtk_button_set_label(GTK_BUTTON(sim_s2),"");
-      }
-      gtk_button_set_label(GTK_BUTTON(sim_s3),"Band");
-      gtk_button_set_label(GTK_BUTTON(sim_s4),"Mode");
-      gtk_button_set_label(GTK_BUTTON(sim_s5),"Filter");
-      gtk_button_set_label(GTK_BUTTON(sim_s6),"");
-      if(full_tune) {
-        set_button_text_color(sim_s1,"red");
-      }
-      if(memory_tune) {
-        set_button_text_color(sim_s2,"red");
-      }
-      break;
-  }
+  gtk_button_set_label(GTK_BUTTON(sim_mox),sw_cap_string[switches[0].switch_function]);
+  gtk_button_set_label(GTK_BUTTON(sim_s1),sw_cap_string[switches[1].switch_function]);
+  gtk_button_set_label(GTK_BUTTON(sim_s2),sw_cap_string[switches[2].switch_function]);
+  gtk_button_set_label(GTK_BUTTON(sim_s3),sw_cap_string[switches[3].switch_function]);
+  gtk_button_set_label(GTK_BUTTON(sim_s4),sw_cap_string[switches[4].switch_function]);
+  gtk_button_set_label(GTK_BUTTON(sim_s5),sw_cap_string[switches[5].switch_function]);
+  gtk_button_set_label(GTK_BUTTON(sim_s6),sw_cap_string[switches[6].switch_function]);
+  gtk_button_set_label(GTK_BUTTON(sim_function),sw_cap_string[switches[7].switch_function]);
 }
 
 static void close_cb(GtkWidget *widget, gpointer data) {
@@ -606,7 +500,29 @@ void tune_update(int state) {
   g_idle_add(ext_vfo_update,NULL);
 }
 
+void switch_pressed_cb(GtkWidget *widget, gpointer data) {
+  gint i=GPOINTER_TO_INT(data);
+  SWITCH_ACTION *a=g_new(SWITCH_ACTION,1);
+  a->action=switches[i].switch_function;
+  a->state=PRESSED;
+  g_idle_add(switch_action,a);
+}
+
+void switch_released_cb(GtkWidget *widget, gpointer data) {
+  gint i=GPOINTER_TO_INT(data);
+  SWITCH_ACTION *a=g_new(SWITCH_ACTION,1);
+  a->action=switches[i].switch_function;
+  a->state=RELEASED;
+  g_idle_add(switch_action,a);
+}
+
+#ifdef OLD_SWITCHES
 void sim_s1_pressed_cb(GtkWidget *widget, gpointer data) {
+  ACTION *a=g_new(ACTION,1);
+  a->action=switches[1].switch_function;
+  a->val=0;
+  g_idle_add(switch_action,a);
+/*
   switch(function) {
     case 0:
       band_cb(widget,data);
@@ -633,9 +549,11 @@ void sim_s1_pressed_cb(GtkWidget *widget, gpointer data) {
       }
       break;
   }
+*/
 }
 
 void sim_s1_released_cb(GtkWidget *widget, gpointer data) {
+/*
   switch(function) {
     case 0:
       break;
@@ -650,9 +568,15 @@ void sim_s1_released_cb(GtkWidget *widget, gpointer data) {
     case 5:
       break;
   }
+*/
 }
 
 void sim_s2_pressed_cb(GtkWidget *widget, gpointer data) {
+  ACTION *a=g_new(ACTION,1);
+  a->action=switches[2].switch_function;
+  a->val=0;
+  g_idle_add(switch_action,a);
+/*
   switch(function) {
     case 0:
       bandstack_cb(widget,data);
@@ -679,9 +603,11 @@ void sim_s2_pressed_cb(GtkWidget *widget, gpointer data) {
       }
       break;
   }
+*/
 }
 
 void sim_s2_released_cb(GtkWidget *widget, gpointer data) {
+/*
   switch(function) {
     case 0:
       break;
@@ -696,10 +622,16 @@ void sim_s2_released_cb(GtkWidget *widget, gpointer data) {
     case 5:
       break;
   }
+*/
 }
 
 
 void sim_s3_pressed_cb(GtkWidget *widget, gpointer data) {
+  SWITCH_ACTION *a=g_new(SWITCH_ACTION,1);
+  a->action=switches[3].switch_function;
+  a->state=PRESSED;
+  g_idle_add(action,a);
+/*
   switch(function) {
     case 0:
       mode_cb(widget,data);
@@ -721,9 +653,11 @@ void sim_s3_pressed_cb(GtkWidget *widget, gpointer data) {
       band_cb(widget,data);
       break;
   }
+*/
 }
 
 void sim_s3_released_cb(GtkWidget *widget, gpointer data) {
+/*
   switch(function) {
     case 0:
       break;
@@ -738,9 +672,15 @@ void sim_s3_released_cb(GtkWidget *widget, gpointer data) {
     case 5:
       break;
   }
+*/
 }
 
 void sim_s4_pressed_cb(GtkWidget *widget, gpointer data) {
+  SWITCH_ACTION *a=g_new(SWITCH_ACTION,1);
+  a->action=switches[4].switch_function;
+  a->state=PRESSED;
+  g_idle_add(action,a);
+/*
   switch(function) {
     case 0:
       filter_cb(widget,data);
@@ -766,9 +706,11 @@ void sim_s4_pressed_cb(GtkWidget *widget, gpointer data) {
       mode_cb(widget,data);
       break;
   }
+*/
 }
 
 void sim_s4_released_cb(GtkWidget *widget, gpointer data) {
+/*
   switch(function) {
     case 0:
       break;
@@ -791,9 +733,15 @@ void sim_s4_released_cb(GtkWidget *widget, gpointer data) {
     case 5:
       break;
   }
+*/
 }
 
 void sim_s5_pressed_cb(GtkWidget *widget, gpointer data) {
+  SWITCH_ACTION *a=g_new(SWITCH_ACTION,1);
+  a->action=switches[5].switch_function;
+  a->state=PRESSED;
+  g_idle_add(switch_action,a);
+/*
   switch(function) {
     case 0:
       noise_cb(widget,data);
@@ -819,9 +767,11 @@ void sim_s5_pressed_cb(GtkWidget *widget, gpointer data) {
       filter_cb(widget,data);
       break;
   }
+*/
 }
 
 void sim_s5_released_cb(GtkWidget *widget, gpointer data) {
+/*
   switch(function) {
     case 0:
       break;
@@ -844,9 +794,14 @@ void sim_s5_released_cb(GtkWidget *widget, gpointer data) {
     case 5:
       break;
   }
+*/
 }
 
 void sim_s6_pressed_cb(GtkWidget *widget, gpointer data) {
+  SWITCH_ACTION *a=g_new(SWITCH_ACTION,1);
+  a->action=switches[6].switch_function;
+  a->state=PRESSED;
+  g_idle_add(switch_action,a);
   switch(function) {
     case 0:
       agc_cb(widget,data);
@@ -868,6 +823,7 @@ void sim_s6_pressed_cb(GtkWidget *widget, gpointer data) {
 }
 
 void sim_s6_released_cb(GtkWidget *widget, gpointer data) {
+/*
   switch(function) {
     case 0:
       break;
@@ -882,9 +838,15 @@ void sim_s6_released_cb(GtkWidget *widget, gpointer data) {
     case 5:
       break;
   }
+*/
 }
 
-void sim_mox_cb(GtkWidget *widget, gpointer data) {
+void sim_s0_cb(GtkWidget *widget, gpointer data) {
+  SWITCH_ACTION *a=g_new(SWITCH_ACTION,1);
+  a->action=switches[0].switch_function;
+  a->state=PRESSED;
+  g_idle_add(switch_action,a);
+/*
   switch(function) {
     case 0:
     case 1:
@@ -897,16 +859,19 @@ void sim_mox_cb(GtkWidget *widget, gpointer data) {
       tune_cb((GtkWidget *)NULL, (gpointer)NULL);
       break;
   }
+*/
 }
 
-void sim_function_cb(GtkWidget *widget, gpointer data) {
-  function++;
-  if(function>MAX_FUNCTION) {
-    function=0;
-  }
-  update_toolbar_labels();
-  g_idle_add(ext_vfo_update,NULL);
+void sim_s7_cb(GtkWidget *widget, gpointer data) {
+  SWITCH_ACTION *a=g_new(SWITCH_ACTION,1);
+  a->action=switches[7].switch_function;
+  a->state=PRESSED;
+  g_idle_add(switch_action,a);
+/*
+  g_idle_add(process_function_switch,NULL);
+*/
 }
+#endif
 
 GtkWidget *toolbar_init(int my_width, int my_height, GtkWidget* parent) {
     width=my_width;
@@ -931,60 +896,46 @@ GtkWidget *toolbar_init(int my_width, int my_height, GtkWidget* parent) {
     gtk_widget_set_size_request (toolbar, width, height);
     gtk_grid_set_column_homogeneous(GTK_GRID(toolbar),TRUE);
 
-    if(can_transmit) {
-      sim_mox=gtk_button_new_with_label("Mox");
-    } else {
-      sim_mox=gtk_button_new_with_label("");
-    }
-    //gtk_widget_override_font(sim_mox, pango_font_description_from_string("Sans 11"));
-    g_signal_connect(G_OBJECT(sim_mox),"clicked",G_CALLBACK(sim_mox_cb),NULL);
+    sim_mox=gtk_button_new_with_label(sw_cap_string[switches[0].switch_function]);
+    g_signal_connect(G_OBJECT(sim_mox),"pressed",G_CALLBACK(switch_pressed_cb),GINT_TO_POINTER(0));
     gtk_grid_attach(GTK_GRID(toolbar),sim_mox,0,0,4,1);
 
-    sim_s1=gtk_button_new_with_label("Band");
+    sim_s1=gtk_button_new_with_label(sw_cap_string[switches[1].switch_function]);
     gtk_widget_set_size_request (sim_s1, button_width, 0);
-    //gtk_widget_override_font(sim_s1, pango_font_description_from_string("Sans 11"));
-    g_signal_connect(G_OBJECT(sim_s1),"pressed",G_CALLBACK(sim_s1_pressed_cb),NULL);
-    g_signal_connect(G_OBJECT(sim_s1),"released",G_CALLBACK(sim_s1_released_cb),NULL);
+    g_signal_connect(G_OBJECT(sim_s1),"pressed",G_CALLBACK(switch_pressed_cb),GINT_TO_POINTER(1));
+    g_signal_connect(G_OBJECT(sim_s1),"released",G_CALLBACK(switch_released_cb),GINT_TO_POINTER(1));
     gtk_grid_attach(GTK_GRID(toolbar),sim_s1,4,0,4,1);
 
-    sim_s2=gtk_button_new_with_label("BStack");
+    sim_s2=gtk_button_new_with_label(sw_cap_string[switches[2].switch_function]);
     gtk_widget_set_size_request (sim_s2, button_width, 0);
-    //gtk_widget_override_font(sim_s2, pango_font_description_from_string("Sans 11"));
-    g_signal_connect(G_OBJECT(sim_s2),"pressed",G_CALLBACK(sim_s2_pressed_cb),NULL);
-    g_signal_connect(G_OBJECT(sim_s2),"released",G_CALLBACK(sim_s2_released_cb),NULL);
+    g_signal_connect(G_OBJECT(sim_s2),"pressed",G_CALLBACK(switch_pressed_cb),GINT_TO_POINTER(2));
+    g_signal_connect(G_OBJECT(sim_s2),"released",G_CALLBACK(switch_released_cb),GINT_TO_POINTER(2));
     gtk_grid_attach(GTK_GRID(toolbar),sim_s2,8,0,4,1);
 
-    sim_s3=gtk_button_new_with_label("Mode");
-    //gtk_widget_override_font(sim_s3, pango_font_description_from_string("Sans 11"));
-    g_signal_connect(G_OBJECT(sim_s3),"pressed",G_CALLBACK(sim_s3_pressed_cb),NULL);
-    g_signal_connect(G_OBJECT(sim_s3),"released",G_CALLBACK(sim_s3_released_cb),NULL);
+    sim_s3=gtk_button_new_with_label(sw_cap_string[switches[3].switch_function]);
+    g_signal_connect(G_OBJECT(sim_s3),"pressed",G_CALLBACK(switch_pressed_cb),GINT_TO_POINTER(3));
+    g_signal_connect(G_OBJECT(sim_s3),"released",G_CALLBACK(switch_released_cb),GINT_TO_POINTER(3));
     gtk_grid_attach(GTK_GRID(toolbar),sim_s3,12,0,4,1);
 
-    sim_s4=gtk_button_new_with_label("Filter");
-    //gtk_widget_override_font(sim_s4, pango_font_description_from_string("Sans 11"));
-    g_signal_connect(G_OBJECT(sim_s4),"pressed",G_CALLBACK(sim_s4_pressed_cb),NULL);
-    g_signal_connect(G_OBJECT(sim_s4),"released",G_CALLBACK(sim_s4_released_cb),NULL);
+    sim_s4=gtk_button_new_with_label(sw_cap_string[switches[4].switch_function]);
+    g_signal_connect(G_OBJECT(sim_s4),"pressed",G_CALLBACK(switch_pressed_cb),GINT_TO_POINTER(4));
+    g_signal_connect(G_OBJECT(sim_s4),"released",G_CALLBACK(switch_released_cb),GINT_TO_POINTER(4));
     gtk_grid_attach(GTK_GRID(toolbar),sim_s4,16,0,4,1);
 
-    sim_s5=gtk_button_new_with_label("Noise");
-    //gtk_widget_override_font(sim_s5, pango_font_description_from_string("Sans 11"));
-    g_signal_connect(G_OBJECT(sim_s5),"pressed",G_CALLBACK(sim_s5_pressed_cb),NULL);
-    g_signal_connect(G_OBJECT(sim_s5),"released",G_CALLBACK(sim_s5_released_cb),NULL);
+    sim_s5=gtk_button_new_with_label(sw_cap_string[switches[5].switch_function]);
+    g_signal_connect(G_OBJECT(sim_s5),"pressed",G_CALLBACK(switch_pressed_cb),GINT_TO_POINTER(5));
+    g_signal_connect(G_OBJECT(sim_s5),"released",G_CALLBACK(switch_released_cb),GINT_TO_POINTER(5));
     gtk_grid_attach(GTK_GRID(toolbar),sim_s5,20,0,4,1);
 
-    sim_s6=gtk_button_new_with_label("AGC");
-    //gtk_widget_override_font(sim_s6, pango_font_description_from_string("Sans 11"));
-    g_signal_connect(G_OBJECT(sim_s6),"pressed",G_CALLBACK(sim_s6_pressed_cb),NULL);
-    g_signal_connect(G_OBJECT(sim_s6),"released",G_CALLBACK(sim_s6_released_cb),NULL);
+    sim_s6=gtk_button_new_with_label(sw_cap_string[switches[6].switch_function]);
+    g_signal_connect(G_OBJECT(sim_s6),"pressed",G_CALLBACK(switch_pressed_cb),GINT_TO_POINTER(6));
+    g_signal_connect(G_OBJECT(sim_s6),"released",G_CALLBACK(switch_released_cb),GINT_TO_POINTER(6));
     gtk_grid_attach(GTK_GRID(toolbar),sim_s6,24,0,4,1);
 
-    sim_function=gtk_button_new_with_label("Function");
-    //gtk_widget_override_font(sim_function, pango_font_description_from_string("Sans 11"));
-    g_signal_connect(G_OBJECT(sim_function),"clicked",G_CALLBACK(sim_function_cb),NULL);
+    sim_function=gtk_button_new_with_label(sw_cap_string[switches[7].switch_function]);
+    g_signal_connect(G_OBJECT(sim_function),"pressed",G_CALLBACK(switch_pressed_cb),GINT_TO_POINTER(7));
     gtk_grid_attach(GTK_GRID(toolbar),sim_function,28,0,4,1);
 
-    //update_toolbar_labels();
-
     last_dialog=NULL;
 
     gtk_widget_show_all(toolbar);
index f4b5a67338f5026d16719d1e51f28ba8877574b2..8fb179be2d828a13dcd4f67626b8bfd5aaa07c26 100644 (file)
@@ -35,6 +35,7 @@
 #include "tx_panadapter.h"
 #include "vfo.h"
 #include "mode.h"
+#include "actions.h"
 #ifdef GPIO
 #include "gpio.h"
 #endif
@@ -350,6 +351,7 @@ void tx_panadapter_update(TRANSMITTER *tx) {
   cairo_set_line_width(cr, 1.0);
   cairo_stroke(cr);
 
+/*
 #ifdef GPIO
   if(controller==CONTROLLER1 && !duplex) {
     char text[64];
@@ -375,7 +377,7 @@ void tx_panadapter_update(TRANSMITTER *tx) {
     }
   }
 #endif
-
+*/
 
 #ifdef PURESIGNAL
   if(tx->puresignal) {
diff --git a/vfo.c b/vfo.c
index 7bd21794fe5c9ea5323e28ef36333cf95ef6bcce..6388ec657d8c7089cf0dadc684cb221cda825fe9 100644 (file)
--- a/vfo.c
+++ b/vfo.c
@@ -911,7 +911,8 @@ void vfo_update() {
         cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
         cairo_paint (cr);
 
-        cairo_select_font_face(cr, "FreeMono",
+        //cairo_select_font_face(cr, "FreeMono",
+        cairo_select_font_face(cr, "FreeSans",
             CAIRO_FONT_SLANT_NORMAL,
             CAIRO_FONT_WEIGHT_BOLD);
 
index c8689895ff1fb28b28fd7eb7f4b542b4bcb8ea0c..b7eba43818f8affcea68913ea3199349616e9398 100644 (file)
@@ -58,6 +58,7 @@ static void cleanup() {
     gtk_widget_destroy(dialog);
     dialog=NULL;
     sub_menu=NULL;
+    active_menu=NO_MENU;
   }
 }