From e707ee87316654be9ade1a8f84e2946d767719fb Mon Sep 17 00:00:00 2001 From: c vw Date: Mon, 17 May 2021 09:21:34 +0200 Subject: [PATCH] Initial stage of manual merge with John's gpiod branch --- Makefile | 264 ++-- actions.c | 931 ++++++++++++++ actions.h | 137 +++ adc.h | 4 +- alsa_midi.c | 256 ++-- alsa_midi.h | 11 + configure.c | 1021 ++++------------ css.c | 26 + dac.h | 2 +- discovered.h | 5 + discovery.c | 107 -- encoder_menu.c | 711 ++--------- ext.c | 56 + ext.h | 2 + gpio.c | 3043 ++++++++++++++-------------------------------- gpio.h | 287 +---- i2c.c | 243 +--- iambic.c | 11 +- mac_midi.c | 225 +++- main.h | 9 + midi.h | 92 +- midi2.c | 387 +++--- midi3.c | 473 ++++--- midi_menu.c | 1782 +++++++++++++++++++++++++++ midi_menu.h | 24 + new_menu.c | 23 + radio.c | 318 +++-- radio.h | 3 +- radio_menu.c | 74 +- rx_panadapter.c | 27 +- sliders.c | 27 +- soapy_protocol.c | 133 +- soapy_protocol.h | 4 +- switch_menu.c | 433 +++---- toolbar.c | 2 + toolbar.h | 2 + transmitter.c | 5 + tx_menu.c | 28 +- tx_panadapter.c | 11 +- vfo.c | 15 +- vfo.h | 3 + 41 files changed, 6052 insertions(+), 5165 deletions(-) create mode 100644 actions.c create mode 100644 actions.h create mode 100644 alsa_midi.h create mode 100644 css.c create mode 100644 midi_menu.c create mode 100644 midi_menu.h diff --git a/Makefile b/Makefile index 96695a1..a596532 100644 --- a/Makefile +++ b/Makefile @@ -1,21 +1,35 @@ +# get the OS Name +UNAME_S := $(shell uname -s) + # Get git commit version and date GIT_DATE := $(firstword $(shell git --no-pager show --date=short --format="%ai" --name-only)) GIT_VERSION := $(shell git describe --abbrev=0 --tags) -# uncomment the line below to include GPIO (For original piHPSDR Controller and Controller2 with i2c) -GPIO_INCLUDE=GPIO +# uncomment the following line to force 480x320 screen +#SMALL_SCREEN_OPTIONS=-D SMALL_SCREEN -# uncomment the line below to include USB Ozy support -# USBOZY_INCLUDE=USBOZY +# uncomment the line below to include GPIO +# For support of: +# CONTROLLER1 (Original Controller) +# CONTROLLER2_V1 single encoders with MCP23017 switches +# CONTROLLER2_V2 dual encoders with MCP23017 switches +# +#GPIO_INCLUDE=GPIO # uncomment the line below to include Pure Signal support PURESIGNAL_INCLUDE=PURESIGNAL +# uncomment the line below to include MIDI support +MIDI_INCLUDE=MIDI + +# uncomment the line below to include USB Ozy support +# USBOZY_INCLUDE=USBOZY + # uncomment the line to below include support local CW keyer -#LOCALCW_INCLUDE=LOCALCW +LOCALCW_INCLUDE=LOCALCW # uncomment the line below for SoapySDR -#SOAPYSDR_INCLUDE=SOAPYSDR +SOAPYSDR_INCLUDE=SOAPYSDR # uncomment the line to below include support for sx1509 i2c expander #SX1509_INCLUDE=sx1509 @@ -24,10 +38,8 @@ PURESIGNAL_INCLUDE=PURESIGNAL #STEMLAB_DISCOVERY=STEMLAB_DISCOVERY # uncomment the line below to include support for STEMlab discovery (WITHOUT AVAHI) -#STEMLAB_DISCOVERY=STEMLAB_DISCOVERY_NOAVAHI +STEMLAB_DISCOVERY=STEMLAB_DISCOVERY_NOAVAHI -# uncomment the line below to include MIDI support -#MIDI_INCLUDE=MIDI # uncomment the line below for various debug facilities #DEBUG_OPTION=-D DEBUG @@ -37,16 +49,23 @@ PURESIGNAL_INCLUDE=PURESIGNAL # very early code not included yet #SERVER_INCLUDE=SERVER -CC=gcc -LINK=gcc +CFLAGS?= -O -Wno-deprecated-declarations +PKG_CONFIG = pkg-config ifeq ($(MIDI_INCLUDE),MIDI) MIDI_OPTIONS=-D MIDI -MIDI_SOURCES= alsa_midi.c midi2.c midi3.c -MIDI_HEADERS= midi.h -MIDI_OBJS= alsa_midi.o midi2.o midi3.o +MIDI_HEADERS= midi.h midi_menu.h alsa_midi.h +ifeq ($(UNAME_S), Darwin) +MIDI_SOURCES= mac_midi.c midi2.c midi3.c midi_menu.c +MIDI_OBJS= mac_midi.o midi2.o midi3.o midi_menu.o +MIDI_LIBS= -framework CoreMIDI -framework Foundation +endif +ifeq ($(UNAME_S), Linux) +MIDI_SOURCES= alsa_midi.c midi2.c midi3.c midi_menu.c +MIDI_OBJS= alsa_midi.o midi2.o midi3.o midi_menu.o MIDI_LIBS= -lasound endif +endif ifeq ($(PURESIGNAL_INCLUDE),PURESIGNAL) PURESIGNAL_OPTIONS=-D PURESIGNAL @@ -82,7 +101,6 @@ USBOZY_OBJS= \ ozyio.o endif - ifeq ($(SOAPYSDR_INCLUDE),SOAPYSDR) SOAPYSDR_OPTIONS=-D SOAPYSDR SOAPYSDRLIBS=-lSoapySDR @@ -97,34 +115,30 @@ soapy_discovery.o \ soapy_protocol.o endif - -ifeq ($(LOCALCW_INCLUDE),LOCALCW) -LOCALCW_OPTIONS=-D LOCALCW -LOCALCW_SOURCES= iambic.c -LOCALCW_HEADERS= iambic.h -LOCALCW_OBJS = iambic.o -endif - ifeq ($(PTT_INCLUDE),PTT) PTT_OPTIONS=-D PTT endif ifeq ($(GPIO_INCLUDE),GPIO) - GPIO_OPTIONS=-D GPIO - GPIO_LIBS=-lwiringPi - GPIO_SOURCES= \ +GPIOD_VERSION=$(shell pkg-config --modversion libgpiod) +ifeq ($(GPIOD_VERSION),1.2) +GPIOD_OPTIONS=-D OLD_GPIOD +endif +GPIO_OPTIONS=-D GPIO +GPIO_LIBS=-lgpiod -li2c +GPIO_SOURCES= \ configure.c \ i2c.c \ gpio.c \ encoder_menu.c \ switch_menu.c - GPIO_HEADERS= \ +GPIO_HEADERS= \ configure.h \ i2c.h \ gpio.h \ encoder_menu.h \ switch_menu.h - GPIO_OBJS= \ +GPIO_OBJS= \ configure.o \ i2c.o \ gpio.o \ @@ -132,6 +146,13 @@ ifeq ($(GPIO_INCLUDE),GPIO) switch_menu.o endif +ifeq ($(LOCALCW_INCLUDE),LOCALCW) +LOCALCW_OPTIONS=-D LOCALCW +LOCALCW_SOURCES= iambic.c +LOCALCW_HEADERS= iambic.h +LOCALCW_OBJS = iambic.o +endif + # # We have two versions of STEMLAB_DISCOVERY here, # the second one has to be used @@ -140,17 +161,17 @@ endif # ifeq ($(STEMLAB_DISCOVERY), STEMLAB_DISCOVERY) STEMLAB_OPTIONS=-D STEMLAB_DISCOVERY \ - `pkg-config --cflags avahi-gobject` \ - `pkg-config --cflags libcurl` -STEMLAB_LIBS=`pkg-config --libs avahi-gobject` `pkg-config --libs libcurl` + $(shell $(PKG_CONFIG) --cflags avahi-gobject) \ + $(shell $(PKG_CONFIG) --cflags libcurl) +STEMLAB_LIBS=$(shell $(PKG_CONFIG) --libs avahi-gobject --libs libcurl) STEMLAB_SOURCES=stemlab_discovery.c STEMLAB_HEADERS=stemlab_discovery.h STEMLAB_OBJS=stemlab_discovery.o endif ifeq ($(STEMLAB_DISCOVERY), STEMLAB_DISCOVERY_NOAVAHI) -STEMLAB_OPTIONS=-D STEMLAB_DISCOVERY -D NO_AVAHI `pkg-config --cflags libcurl` -STEMLAB_LIBS=`pkg-config --libs libcurl` +STEMLAB_OPTIONS=-D STEMLAB_DISCOVERY -D NO_AVAHI $(shell $(PKG_CONFIG) --cflags libcurl) +STEMLAB_LIBS=$(shell $(PKG_CONFIG) --libs libcurl) STEMLAB_SOURCES=stemlab_discovery.c STEMLAB_HEADERS=stemlab_discovery.h STEMLAB_OBJS=stemlab_discovery.o @@ -166,21 +187,38 @@ SERVER_OBJS= \ client_server.o server_menu.o endif -GTKINCLUDES=`pkg-config --cflags gtk+-3.0` -GTKLIBS=`pkg-config --libs gtk+-3.0` +GTKINCLUDES=$(shell $(PKG_CONFIG) --cflags gtk+-3.0) +GTKLIBS=$(shell $(PKG_CONFIG) --libs gtk+-3.0) -AUDIO_LIBS=-lasound -#AUDIO_LIBS=-lsoundio +ifeq ($(UNAME_S), Linux) +#AUDIO_LIBS=-lpulse-simple -lpulse -lpulse-mainloop-glib +#AUDIO_SOURCES=pulseaudio.c +#AUDIO_OBJS=pulseaudio.o +AUDIO_LIBS= +AUDIO_SOURCES=audio.c +AUDIO_OBJS=audio.o +endif +ifeq ($(UNAME_S), Darwin) +AUDIO_OPTIONS=-DPORTAUDIO $(shell $(PKG_CONFIG) --cflags portaudio-2.0) +AUDIO_LIBS=$(shell $(PKG_CONFIG) --libs portaudio-2.0) +AUDIO_SOURCES=portaudio.c +AUDIO_OBJS=portaudio.o +endif -CFLAGS= -g -Wno-deprecated-declarations -O3 -OPTIONS=$(MIDI_OPTIONS) $(PURESIGNAL_OPTIONS) $(REMOTE_OPTIONS) $(USBOZY_OPTIONS) \ - $(GPIO_OPTIONS) $(SOAPYSDR_OPTIONS) $(LOCALCW_OPTIONS) \ - $(STEMLAB_OPTIONS) \ - $(PTT_OPTIONS) \ - $(SERVER_OPTIONS) \ +ifeq ($(UNAME_S), Linux) +SYSLIBS=-lrt +endif +ifeq ($(UNAME_S), Darwin) +SYSLIBS=-framework IOkit +endif + +OPTIONS=$(SMALL_SCREEN_OPTIONS) $(MIDI_OPTIONS) $(PURESIGNAL_OPTIONS) $(REMOTE_OPTIONS) $(USBOZY_OPTIONS) \ + $(GPIO_OPTIONS) $(GPIOD_OPTIONS) $(SOAPYSDR_OPTIONS) $(LOCALCW_OPTIONS) \ + $(STEMLAB_OPTIONS) $(PTT_OPTIONES) $(SERVER_OPTIONS) $(AUDIO_OPTIONS) \ -D GIT_DATE='"$(GIT_DATE)"' -D GIT_VERSION='"$(GIT_VERSION)"' $(DEBUG_OPTION) -LIBS=-lrt -lm -lwdsp -lpthread $(AUDIO_LIBS) $(USBOZY_LIBS) $(GTKLIBS) $(GPIO_LIBS) $(SOAPYSDRLIBS) $(STEMLAB_LIBS) $(MIDI_LIBS) +LIBS= -lm -lwdsp -lpthread $(SYSLIBS) $(AUDIO_LIBS) $(USBOZY_LIBS) $(GTKLIBS) \ + $(GPIO_LIBS) $(SOAPYSDRLIBS) $(STEMLAB_LIBS) $(MIDI_LIBS) INCLUDES=$(GTKINCLUDES) COMPILE=$(CC) $(CFLAGS) $(OPTIONS) $(INCLUDES) @@ -191,7 +229,7 @@ COMPILE=$(CC) $(CFLAGS) $(OPTIONS) $(INCLUDES) PROGRAM=pihpsdr SOURCES= \ -audio.c \ +MacOS.c \ band.c \ discovered.c \ discovery.c \ @@ -255,11 +293,17 @@ led.c \ ext.c \ error_handler.c \ cwramp.c \ -protocols.c +protocols.c \ +css.c \ +actions.c \ +i2c.c \ +gpio.c \ +encoder_menu.c \ +switch_menu.c HEADERS= \ -audio.h \ +MacOS.h \ agc.h \ alex.h \ band.h \ @@ -324,11 +368,18 @@ memory.h \ led.h \ ext.h \ error_handler.h \ -protocols.h +protocols.h \ +css.h \ +actions.h \ +configure.h \ +i2c.h \ +gpio.h \ +encoder_menu.h \ +switch_menu.h OBJS= \ -audio.o \ +MacOS.o \ band.o \ discovered.o \ discovery.o \ @@ -392,24 +443,31 @@ led.o \ ext.o \ error_handler.o \ cwramp.o \ -protocols.o - -$(PROGRAM): $(OBJS) $(REMOTE_OBJS) $(USBOZY_OBJS) $(SOAPYSDR_OBJS) \ - $(LOCALCW_OBJS) $(GPIO_OBJS) $(PURESIGNAL_OBJS) \ +protocols.o \ +css.o \ +actions.o \ +configure.o \ +i2c.o \ +gpio.o \ +encoder_menu.o \ +switch_menu.o + +$(PROGRAM): $(OBJS) $(AUDIO_OBJS) $(REMOTE_OBJS) $(USBOZY_OBJS) $(SOAPYSDR_OBJS) \ + $(LOCALCW_OBJS) $(PURESIGNAL_OBJS) \ $(MIDI_OBJS) $(STEMLAB_OBJS) $(SERVER_OBJS) - $(LINK) -o $(PROGRAM) $(OBJS) $(REMOTE_OBJS) $(USBOZY_OBJS) $(GPIO_OBJS) \ + $(CC) -o $(PROGRAM) $(OBJS) $(AUDIO_OBJS) $(REMOTE_OBJS) $(USBOZY_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) \ - $(PURESIGNAL_HEADERS) $(MIDI_HEADERS) $(STEMLAB_HEADERS) $(SERVER_HEADERS)\ - $(SOURCES) \ - $(USBOZY_SOURCES) $(SOAPYSDR_SOURCES) $(LOCALCW_SOURCE) $(GPIO_SOURCES) \ + $(MIDI_OBJS) $(STEMLAB_OBJS) $(SERVER_OBJS) $(LIBS) $(LDFLAGS) + +.PHONY: all +all: prebuild $(PROGRAM) $(HEADERS) $(AUDIO_HEADERS) $(USBOZY_HEADERS) $(SOAPYSDR_HEADERS) \ + $(LOCALCW_HEADERS) \ + $(PURESIGNAL_HEADERS) $(MIDI_HEADERS) $(STEMLAB_HEADERS) $(SERVER_HEADERS) \ + $(AUDIO_SOURCES) $(SOURCES) \ + $(USBOZY_SOURCES) $(SOAPYSDR_SOURCES) $(LOCALCW_SOURCE) \ $(PURESIGNAL_SOURCES) $(MIDI_SOURCES) $(STEMLAB_SOURCES) $(SERVER_SOURCES) -.PHONY: prebuild +.PHONY: prebuild prebuild: rm -f version.o @@ -419,47 +477,47 @@ prebuild: # Therefore, correct this here. Furthermore, we can add additional options to CPP # in the variable CPPOPTIONS # -CPPOPTIONS= --enable=all --suppress=shadowVariable --suppress=variableScope +CPPOPTIONS= --enable=all --suppress=shadowVariable --suppress=variableScope -D__APPLE__ CPPINCLUDES:=$(shell echo $(INCLUDES) | sed -e "s/-pthread / /" ) .PHONY: cppcheck cppcheck: cppcheck $(CPPOPTIONS) $(OPTIONS) $(CPPINCLUDES) $(SOURCES) $(REMOTE_SOURCES) \ - $(USBOZY_SOURCES) $(SOAPYSDR_SOURCES) $(GPIO_SOURCES) \ - $(PURESIGNAL_SOURCES) $(MIDI_SOURCES) $(STEMLAB_SOURCES) $(LOCALCW_SOURCES) \ - $(SERVER_SOURCES) + $(USBOZY_SOURCES) $(SOAPYSDR_SOURCES) $(SERVER_SOURCES) \ + $(PURESIGNAL_SOURCES) $(MIDI_SOURCES) $(STEMLAB_SOURCES) $(LOCALCW_SOURCES) -.PHONY: clean +.PHONY: clean clean: -rm -f *.o -rm -f $(PROGRAM) hpsdrsim + -rm -rf $(PROGRAM).app -.PHONY: install +.PHONY: install install: $(PROGRAM) - cp $(PROGRAM) /usr/local/bin + cp $(PROGRAM) $(DESTDIR)/usr/local/bin -.PHONY: release +.PHONY: release release: $(PROGRAM) cp $(PROGRAM) release/pihpsdr cd release; tar cvf pihpsdr.tar pihpsdr cd release; tar cvf pihpsdr-$(GIT_VERSION).tar pihpsdr -.PHONY: nocontroller +.PHONY: nocontroller nocontroller: clean controller1 $(PROGRAM) cp $(PROGRAM) release/pihpsdr cd release; tar cvf pihpsdr-nocontroller.$(GIT_VERSION).tar pihpsdr -.PHONY: controller1 +.PHONY: controller1 controller1: clean $(PROGRAM) cp $(PROGRAM) release/pihpsdr cd release; tar cvf pihpsdr-controller1.$(GIT_VERSION).tar pihpsdr -.PHONY: controller2v1 +.PHONY: controller2v1 controller2v1: clean $(PROGRAM) cp $(PROGRAM) release/pihpsdr cd release; tar cvf pihpsdr-controller2-v1.$(GIT_VERSION).tar pihpsdr -.PHONY: controller2v2 +.PHONY: controller2v2 controller2v2: clean $(PROGRAM) cp $(PROGRAM) release/pihpsdr cd release; tar cvf pihpsdr-controller2-v2.$(GIT_VERSION).tar pihpsdr @@ -474,15 +532,14 @@ controller2v2: clean $(PROGRAM) # ############################################################################# -hpsdrsim.o: hpsdrsim.c hpsdrsim.h - $(CC) -c -O -DALSASOUND hpsdrsim.c - +hpsdrsim.o: hpsdrsim.c hpsdrsim.h + $(CC) -c -O $(AUDIO_OPTIONS) hpsdrsim.c + newhpsdrsim.o: newhpsdrsim.c hpsdrsim.h $(CC) -c -O newhpsdrsim.c -hpsdrsim: hpsdrsim.o newhpsdrsim.o - $(LINK) -o hpsdrsim hpsdrsim.o newhpsdrsim.o -lasound -lm -lpthread - +hpsdrsim: hpsdrsim.o newhpsdrsim.o + $(CC) -o hpsdrsim $(AUDIO_LIBS) hpsdrsim.o newhpsdrsim.o -lportaudio -lm -lpthread debian: cp $(PROGRAM) pkg/pihpsdr/usr/local/bin @@ -492,3 +549,48 @@ debian: cp release/pihpsdr/pihpsdr.desktop pkg/pihpsdr/usr/share/applications cd pkg; dpkg-deb --build pihpsdr +############################################################################# +# +# This is for MacOS "app" creation ONLY +# +# The piHPSDR working directory is +# $HOME -> Application Support -> piHPSDR +# +# That is the directory where the WDSP wisdom file (created upon first +# start of piHPSDR) but also the radio settings and the midi.props file +# are stored. +# +# ONLY the wdsp library is bundled with the app, all others, including +# the SoapySDR support modules, must be installed separatedly. +# +############################################################################# + +.PHONY: app +app: $(OBJS) $(REMOTE_OBJS) \ + $(USBOZY_OBJS) $(SOAPYSDR_OBJS) \ + $(LOCALCW_OBJS) $(PURESIGNAL_OBJS) \ + $(MIDI_OBJS) $(STEMLAB_OBJS) $(SERVER_OBJS) + $(CC) -headerpad_max_install_names -o $(PROGRAM) $(OBJS) $(REMOTE_OBJS) \ + $(USBOZY_OBJS) $(SOAPYSDR_OBJS) \ + $(LOCALCW_OBJS) $(PURESIGNAL_OBJS) \ + $(MIDI_OBJS) $(STEMLAB_OBJS) $(SERVER_OBJS) $(LIBS) $(LDFLAGS) + @rm -rf pihpsdr.app + @mkdir -p pihpsdr.app/Contents/MacOS + @mkdir -p pihpsdr.app/Contents/Frameworks + @mkdir -p pihpsdr.app/Contents/Resources + @cp pihpsdr pihpsdr.app/Contents/MacOS/pihpsdr + @cp MacOS/PkgInfo pihpsdr.app/Contents + @cp MacOS/Info.plist pihpsdr.app/Contents + @cp MacOS/hpsdr.icns pihpsdr.app/Contents/Resources/hpsdr.icns + @cp MacOS/hpsdr.png pihpsdr.app/Contents/Resources +# +# Copy the WDSP library into the executable +# + @lib=`otool -L pihpsdr.app/Contents/MacOS/pihpsdr | grep libwdsp | sed -e "s/ (.*//" | sed -e 's/ //'`; \ + libfn=`basename $$lib`; \ + cp "$$lib" "pihpsdr.app/Contents/Frameworks/$$libfn"; \ + chmod u+w "pihpsdr.app/Contents/Frameworks/$$libfn"; \ + install_name_tool -id "@executable_path/../Frameworks/$$libfn" "pihpsdr.app/Contents/Frameworks/$$libfn"; \ + install_name_tool -change "$$lib" "@executable_path/../Frameworks/$$libfn" pihpsdr.app/Contents/MacOS/pihpsdr +# +############################################################################# diff --git a/actions.c b/actions.c new file mode 100644 index 0000000..4614b72 --- /dev/null +++ b/actions.c @@ -0,0 +1,931 @@ +#include + +#include "main.h" +#include "discovery.h" +#include "receiver.h" +#include "sliders.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" +#include "toolbar.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", + "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 +", + "FUNCT", + "LOCK", + "AGC", + "BAND", + "BSTACK", + "DIV", + "FILTER", + "FREQUENCY", + "MEMORY", + "MODE", + "NOISE", + "PS", + "MODE -", + "MODE +", + "MOX", + "MUTE", + "NB", + "NR", + "PAN -", + "PAN +", + "PS", + "RIT", + "RIT CL", + "RIT -", + "RIT +", + "RSAT", + "SAT", + "SNB", + "SPLIT", + "TUN", + "TUNE FULL", + "TUNE MEM", + "TWO TONE", + "VFOSTEP +", + "VFOSTEP -", + "XIT", + "XIT CL", + "XIT -", + "XIT +", + "ZOOM -", + "ZOOM +" +}; + +char *sw_cap_string[SWITCH_ACTIONS] = { + "", + "A>B", + "A<>B", + "AGC", + "ANF", + "B>A", + "BAND -", + "BAND +", + "BST-", + "BST+", + "CTUN", + "DIV", + "DUP", + "FILT -", + "FILT +", + "FUNC", + "LOCK", + "AGC", + "BAND", + "BSTACK", + "DIV", + "FILTER", + "FREQ", + "MEM", + "MODE", + "NOISE", + "PS", + "MODE -", + "MODE +", + "MOX", + "MUTE", + "NB", + "NR", + "PAN-", + "PAN+", + "PS", + "RIT", + "RIT CL", + "RIT -", + "RIT +", + "RSAT", + "SAT", + "SNB", + "SPLIT", + "TUNE", + "TUN-F", + "TUN-M", + "2TONE", + "STEP+", + "STEP-", + "XIT", + "XIT CL", + "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->gain; + value=adc[active_receiver->id].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=adc[receiver[0]->id].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=adc[receiver[1]->id].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[active_receiver->adc].attenuation; + 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) { + int i; + SWITCH_ACTION *a=(SWITCH_ACTION *)data; + if(a->state==PRESSED) { + switch(a->action) { + case FUNCTION: + switch(controller) { + case NO_CONTROLLER: + case CONTROLLER1: + function++; + if(function>=MAX_FUNCTIONS) { + function=0; + } + toolbar_switches=switches_controller1[function]; + switches=switches_controller1[function]; + update_toolbar_labels(); + break; + case CONTROLLER2_V1: + case CONTROLLER2_V2: + function++; + if(function>=MAX_FUNCTIONS) { + function=0; + } + toolbar_switches=switches_controller1[function]; + update_toolbar_labels(); + break; + } + break; + case TUNE: + if(getMox()==1) { + setMox(0); + } + if(getTune()==0) { + if(canTransmit() || tx_out_of_band) { + setTune(1); + } else { + transmitter_set_out_of_band(transmitter); + } + } else { + setTune(0); + } + g_idle_add(ext_vfo_update,NULL); + break; + case MOX: + if(getTune()==1) { + setTune(0); + } + if(getMox()==0) { + if(canTransmit() || tx_out_of_band) { + setMox(1); + } else { + transmitter_set_out_of_band(transmitter); + } + } else { + setMox(0); + } + 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 VFOSTEP_PLUS: + for(i=0;i=STEPS) i=0; + i++; + if(i>=STEPS) i=0; + step=steps[i]; + g_idle_add(ext_vfo_update, NULL); + break; + case VFOSTEP_MINUS: + for(i=0;i=STEPS) i=0; + i--; + if(i<0) i=STEPS-1; + step=steps[i]; + g_idle_add(ext_vfo_update, NULL); + 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 RIT_MINUS: + vfo_rit(active_receiver->id,-1); + break; + case RIT_PLUS: + vfo_rit(active_receiver->id,1); + 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 XIT_MINUS: + if(can_transmit) { + double value=(double)transmitter->xit; + value-=(double)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 XIT_PLUS: + if(can_transmit) { + double value=(double)transmitter->xit; + value+=(double)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 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(bfrequencyMin==0.0 && band->frequencyMax==0.0)) { + if(band->frequencyMinfrequencyMax>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(bfrequencyMinfrequencyMax>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=!vfo[active_receiver->id].ctun; + 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); + g_idle_add(ext_vfo_update, NULL); + 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 index 0000000..b48c5b3 --- /dev/null +++ b/actions.h @@ -0,0 +1,137 @@ + +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, + VFOSTEP_PLUS, + VFOSTEP_MINUS, + 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); + diff --git a/adc.h b/adc.h index c1ab51d..f0a14b4 100644 --- a/adc.h +++ b/adc.h @@ -65,8 +65,10 @@ typedef struct _adc { gboolean preamp; gint attenuation; gboolean enable_step_attenuation; + gdouble gain; + gdouble min_gain; + gdouble max_gain; #ifdef SOAPYSDR - gint *rx_gain; gboolean agc; #endif } ADC; diff --git a/alsa_midi.c b/alsa_midi.c index bf12420..d05ad69 100644 --- a/alsa_midi.c +++ b/alsa_midi.c @@ -18,14 +18,27 @@ * program amidi.c in alsautils. */ +#include #include "midi.h" +#include "midi_menu.h" +#include "alsa_midi.h" #ifndef __APPLE__ #include #include -static pthread_t midi_thread_id; +MIDI_DEVICE midi_devices[MAX_MIDI_DEVICES]; +int n_midi_devices; + +// +// The following must not reside in midi_devices since it +// needs special #includes +// +static pthread_t midi_thread_id[MAX_MIDI_DEVICES]; +static char *midi_port[MAX_MIDI_DEVICES]; +static snd_rawmidi_t *midi_input[MAX_MIDI_DEVICES]; + static void* midi_thread(void *); static enum { @@ -41,9 +54,18 @@ static enum { CMD_PITCH, } command; -static void *midi_thread(void *data) { +static gboolean configure=FALSE; + +void configure_midi_device(gboolean state) { + configure=state; +} + +static void *midi_thread(void *arg) { + int index = (int) arg; + snd_rawmidi_t *input=midi_input[index]; + char *port=midi_port[index]; + int ret; - snd_rawmidi_t *input; int npfds; struct pollfd *pfds; unsigned char buf[32]; @@ -51,20 +73,15 @@ static void *midi_thread(void *data) { unsigned short revents; int i; int chan,arg1,arg2; - char *portname = (char *) data; - - if ((ret = snd_rawmidi_open(&input, NULL, portname, SND_RAWMIDI_NONBLOCK)) < 0) { - fprintf(stderr,"cannot open port \"%s\": %s\n", portname, snd_strerror(ret)); - free(portname); - return NULL; - } - snd_rawmidi_read(input, NULL, 0); /* trigger reading */ + + npfds = snd_rawmidi_poll_descriptors_count(input); pfds = alloca(npfds * sizeof(struct pollfd)); snd_rawmidi_poll_descriptors(input, pfds, npfds); for (;;) { ret = poll(pfds, npfds, 250); + if (!midi_devices[index].active) break; if (ret < 0) { fprintf(stderr,"poll failed: %s\n", strerror(errno)); // Do not give up, but also do not fire too rapidly @@ -81,7 +98,7 @@ static void *midi_thread(void *data) { ret = snd_rawmidi_read(input, buf, 64); if (ret == 0) continue; if (ret < 0) { - fprintf(stderr,"cannot read from port \"%s\": %s\n", portname, snd_strerror(ret)); + fprintf(stderr,"cannot read from port \"%s\": %s\n", port, snd_strerror(ret)); continue; } // process bytes in buffer. Since they no not necessarily form complete messages @@ -129,19 +146,39 @@ static void *midi_thread(void *data) { // messages with velocity == 0 when releasing // a push-button if (arg2 == 0) { - NewMidiEvent(MIDI_EVENT_NOTE, chan, arg1, 0); + if(configure) { + NewMidiConfigureEvent(MIDI_EVENT_NOTE, chan, arg1, 0); + } else { + NewMidiEvent(MIDI_EVENT_NOTE, chan, arg1, 0); + } } else { - NewMidiEvent(MIDI_EVENT_NOTE, chan, arg1, 1); + if(configure) { + NewMidiConfigureEvent(MIDI_EVENT_NOTE, chan, arg1, 1); + } else { + NewMidiEvent(MIDI_EVENT_NOTE, chan, arg1, 1); + } } break; case CMD_NOTEOFF: - NewMidiEvent(MIDI_EVENT_NOTE, chan, arg1, 0); + if(configure) { + NewMidiConfigureEvent(MIDI_EVENT_NOTE, chan, arg1, 0); + } else { + NewMidiEvent(MIDI_EVENT_NOTE, chan, arg1, 0); + } break; case CMD_CTRL: - NewMidiEvent(MIDI_EVENT_CTRL, chan, arg1, arg2); + if(configure) { + NewMidiConfigureEvent(MIDI_EVENT_CTRL, chan, arg1, arg2); + } else { + NewMidiEvent(MIDI_EVENT_CTRL, chan, arg1, arg2); + } break; case CMD_PITCH: - NewMidiEvent(MIDI_EVENT_PITCH, chan, 0, arg1+128*arg2); + if(configure) { + NewMidiConfigureEvent(MIDI_EVENT_PITCH, chan, 0, arg1+128*arg2); + } else { + NewMidiEvent(MIDI_EVENT_PITCH, chan, 0, arg1+128*arg2); + } break; } state=STATE_SKIP; @@ -149,42 +186,96 @@ static void *midi_thread(void *data) { } } } + return NULL; +} + +void register_midi_device(int index) { + int i; + int ret=0; + + if (index < 0 || index > MAX_MIDI_DEVICES) return; + + g_print("%s: open MIDI device %d\n", __FUNCTION__, index); + + if ((ret = snd_rawmidi_open(&midi_input[index], NULL, midi_port[index], SND_RAWMIDI_NONBLOCK)) < 0) { + fprintf(stderr,"cannot open port \"%s\": %s\n", midi_port[index], snd_strerror(ret)); + return; + } + snd_rawmidi_read(midi_input[index], NULL, 0); /* trigger reading */ + + + ret = pthread_create(&midi_thread_id[index], NULL, midi_thread, (void *) index); + if (ret < 0) { + g_print("%s: Failed to create MIDI read thread\n",__FUNCTION__); + if((ret = snd_rawmidi_close(midi_input[index])) < 0) { + g_print("%s: cannot close port: %s\n",__FUNCTION__, snd_strerror(ret)); + } + return; + } + midi_devices[index].active=1; + return; } -void register_midi_device(char *myname) { +void close_midi_device(int index) { + int ret; + + if (index < 0 || index > MAX_MIDI_DEVICES) return; + if (midi_devices[index].active == 0) return; + + // + // Note that if this is called from get_midi_devices(), + // the port and device names do exist but may be wrong. + // + // Tell thread to stop + // + midi_devices[index].active=0; + // + // wait for thread to complete + // + ret=pthread_join(midi_thread_id[index], NULL); + if (ret != 0) { + g_print("%s: cannot join: %s\n", __FUNCTION__, strerror(ret)); + } + // + // Close MIDI device + if((ret = snd_rawmidi_close(midi_input[index])) < 0) { + g_print("%s: cannot close port: %s\n",__FUNCTION__, snd_strerror(ret)); + } +} + +void get_midi_devices() { - int mylen=strlen(myname); snd_ctl_t *ctl; snd_rawmidi_info_t *info; int card, device, subs, sub, ret; const char *devnam, *subnam; int found=0; - char name[64]; - char *portname; + char portname[64]; + n_midi_devices=0; card=-1; if ((ret = snd_card_next(&card)) < 0) { fprintf(stderr,"cannot determine card number: %s\n", snd_strerror(ret)); return; } while (card >= 0) { - fprintf(stderr,"Found Sound Card=%d\n",card); - sprintf(name,"hw:%d", card); - if ((ret = snd_ctl_open(&ctl, name, 0)) < 0) { + //fprintf(stderr,"Found Sound Card=%d\n",card); + sprintf(portname,"hw:%d", card); + if ((ret = snd_ctl_open(&ctl, portname, 0)) < 0) { fprintf(stderr,"cannot open control for card %d: %s\n", card, snd_strerror(ret)); return; } - device = -1; - // loop through devices of the card - for (;;) { - if ((ret = snd_ctl_rawmidi_next_device(ctl, &device)) < 0) { + device = -1; + // loop through devices of the card + for (;;) { + if ((ret = snd_ctl_rawmidi_next_device(ctl, &device)) < 0) { fprintf(stderr,"cannot determine device number: %s\n", snd_strerror(ret)); break; } - if (device < 0) break; - fprintf(stderr,"Found Device=%d on Card=%d\n", device, card); - // found sub-device - snd_rawmidi_info_alloca(&info); + if (device < 0) break; + //fprintf(stderr,"Found Device=%d on Card=%d\n", device, card); + // found sub-device + snd_rawmidi_info_alloca(&info); snd_rawmidi_info_set_device(info, device); snd_rawmidi_info_set_stream(info, SND_RAWMIDI_STREAM_INPUT); ret = snd_ctl_rawmidi_info(ctl, info); @@ -192,10 +283,10 @@ void register_midi_device(char *myname) { subs = snd_rawmidi_info_get_subdevices_count(info); } else { subs = 0; - } - fprintf(stderr,"Number of MIDI input devices: %d\n", subs); - if (!subs) break; - // subs: number of sub-devices to device on card + } + //fprintf(stderr,"Number of MIDI input devices: %d\n", subs); + if (!subs) break; + // subs: number of sub-devices to device on card for (sub = 0; sub < subs; ++sub) { snd_rawmidi_info_set_stream(info, SND_RAWMIDI_STREAM_INPUT); snd_rawmidi_info_set_subdevice(info, sub); @@ -205,47 +296,70 @@ void register_midi_device(char *myname) { card, device, sub, snd_strerror(ret)); break; } - devnam = snd_rawmidi_info_get_name(info); - subnam = snd_rawmidi_info_get_subdevice_name(info); - if (!strncmp(myname, devnam, mylen)) { - found=1; - // free() portname at the end of midi_thread - portname=malloc(64); - // If there is only one sub-device and it has no name, we use - // devnam for comparison and make a portname of form "hw:x,y", - // else we use subnam for comparison and make a portname of form "hw:x,y,z". - if (sub == 0 && subnam[0] == '\0') { - sprintf(portname,"hw:%d,%d", card, device); - } else { - sprintf(portname,"hw:%d,%d,%d", card, device, sub); - devnam=subnam; - } - fprintf(stderr,"MIDI device >%s< selected (PortName=>%s<)\n", devnam, portname); - } else { - fprintf(stderr,"MIDI device >%s< not matching >%s<\n", devnam, myname); - } if (found) break; - } - if (found) break; - } - snd_ctl_close(ctl); - if (found) break; - // next card + devnam = snd_rawmidi_info_get_name(info); + subnam = snd_rawmidi_info_get_subdevice_name(info); + // If there is only one sub-device and it has no name, we use + // devnam for comparison and make a portname of form "hw:x,y", + // else we use subnam for comparison and make a portname of form "hw:x,y,z". + if (sub == 0 && subnam[0] == '\0') { + sprintf(portname,"hw:%d,%d", card, device); + } else { + sprintf(portname,"hw:%d,%d,%d", card, device, sub); + devnam=subnam; + } + // + // If the name was already present at the same position, just keep + // it and do nothing. + // If the names do not match and the slot is occupied by a opened device, + // close it first + // + int match = 1; + if (midi_devices[n_midi_devices].name == NULL) { + midi_devices[n_midi_devices].name=g_new(gchar,strlen(devnam)+1); + strcpy(midi_devices[n_midi_devices].name, devnam); + match = 0; + } else { + if (strcmp(devnam, midi_devices[n_midi_devices].name)) { + g_free(midi_devices[n_midi_devices].name); + midi_devices[n_midi_devices].name=g_new(gchar,strlen(devnam)+1); + strcpy(midi_devices[n_midi_devices].name, devnam); + match = 0; + } + } + if (midi_port[n_midi_devices] == NULL) { + midi_port[n_midi_devices]=g_new(gchar,strlen(portname)+1); + strcpy(midi_port[n_midi_devices], portname); + match = 0; + } else { + if (strcmp(midi_port[n_midi_devices], portname)) { + g_free(midi_port[n_midi_devices]); + midi_port[n_midi_devices]=g_new(gchar,strlen(portname)+1); + strcpy(midi_port[n_midi_devices], portname); + match = 0; + } + } + // + // Close MIDI device if it was open, except if the device is + // the same as before. In this case, just let the thread + // proceed + // + if (match == 0 && midi_devices[n_midi_devices].active) { + close_midi_device(n_midi_devices); + } + n_midi_devices++; + } + } + snd_ctl_close(ctl); + // next card if ((ret = snd_card_next(&card)) < 0) { fprintf(stderr,"cannot determine card number: %s\n", snd_strerror(ret)); break; } } - if (!found) { - fprintf(stderr,"MIDI device %s NOT FOUND!\n", myname); - return; - } - // Found our MIDI input device. Spawn off a thread reading data - // (use the same variable midi_thread_id for all MIDI threads - // since it is not used again). - ret = pthread_create(&midi_thread_id, NULL, midi_thread, portname); - if (ret < 0) { - fprintf(stderr,"Failed to create MIDI read thread\n"); + + for(int i=0;i -#include +#include +#include #include #include #include @@ -30,6 +31,7 @@ #include "main.h" #include "channel.h" #include "discovered.h" +#include "actions.h" #include "gpio.h" #include "i2c.h" @@ -38,830 +40,301 @@ 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), "Note: Pin number now use Broadcom GPIO"); + 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?"Bottom Encoder":"Encoder"); + 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), "Top Encoder"); + 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), "Switch"); + 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), "ID"); + gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1); + col++; + + widget=gtk_label_new(NULL); + gtk_label_set_markup (GTK_LABEL(widget), "Gpio A"); + gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1); + col++; + + widget=gtk_label_new(NULL); + gtk_label_set_markup (GTK_LABEL(widget), "Gpio 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), "Gpio A"); + gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1); + col++; + + widget=gtk_label_new(NULL); + gtk_label_set_markup (GTK_LABEL(widget), "Gpio 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), "Gpio"); + gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1); + col++; - row++; + row++; + col=0; + + for(i=0;i%d",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), "Note: Pin number now use Broadcom GPIO"); + 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;iID"); + 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), "Gpio"); + 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%d",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),"I2C Device"); + 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),"I2C Address"); + 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,"SW_%d",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,"SW_%d",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 diff --git a/css.c b/css.c new file mode 100644 index 0000000..c8b9ae3 --- /dev/null +++ b/css.c @@ -0,0 +1,26 @@ +#include + +char *css= +" #small {\n" +" padding: 0;\n" +" font-family: Sans;\n" +" font-size: 12px;\n" +" }\n" +; + +void load_css() { + GtkCssProvider *provider; + GdkDisplay *display; + GdkScreen *screen; + + g_print("%s\n",__FUNCTION__); + provider = gtk_css_provider_new (); + display = gdk_display_get_default (); + screen = gdk_display_get_default_screen (display); + gtk_style_context_add_provider_for_screen (screen, + GTK_STYLE_PROVIDER(provider), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + + gtk_css_provider_load_from_data(provider, css, -1, NULL); + g_object_unref (provider); +} diff --git a/dac.h b/dac.h index 5bd9ad4..a08135f 100644 --- a/dac.h +++ b/dac.h @@ -22,7 +22,7 @@ typedef struct _dac { gint antenna; - gint *tx_gain; + gdouble gain; } DAC; #endif diff --git a/discovered.h b/discovered.h index dc71bfc..2764b83 100644 --- a/discovered.h +++ b/discovered.h @@ -117,6 +117,7 @@ struct _DISCOVERED { char hardware_key[64]; char driver_key[64]; int rtlsdr_count; + int sdrplay_count; int sample_rate; size_t rx_channels; size_t rx_gains; @@ -132,6 +133,10 @@ struct _DISCOVERED { SoapySDRRange *tx_range; size_t tx_antennas; char **tx_antenna; + size_t sensors; + char **sensor; + gboolean has_temp; + char address[64]; } soapy; #endif } info; diff --git a/discovery.c b/discovery.c index 8cd3f44..5966027 100644 --- a/discovery.c +++ b/discovery.c @@ -27,10 +27,6 @@ #include #include #include -#ifdef MIDI -#include -#include -#endif #include "discovered.h" #include "old_discovery.h" @@ -120,103 +116,6 @@ static gboolean start_cb (GtkWidget *widget, GdkEventButton *event, gpointer dat return TRUE; } -#ifdef MIDI -// -// This is a file open dialog. If we choose a readable file here, it is just copied -// to file "midi.props" in the local directory -// -static gboolean midi_cb(GtkWidget *widget, GdkEventButton *event, gpointer data) { - GtkWidget *opfile,*message; - GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN; - gint res; - int fdin, fdout; - size_t len,bytes_read,bytes_written; - - opfile = gtk_file_chooser_dialog_new ("Import MIDI description", - GTK_WINDOW(top_window), - action, - "Cancel", - GTK_RESPONSE_CANCEL, - "Open", - GTK_RESPONSE_ACCEPT, - NULL); - - res = gtk_dialog_run (GTK_DIALOG (opfile)); - if (res == GTK_RESPONSE_ACCEPT) { - char *filename, *cp; - struct stat statbuf; - GtkFileChooser *chooser = GTK_FILE_CHOOSER (opfile); - char *contents = NULL; - filename = gtk_file_chooser_get_filename (chooser); - fdin =open(filename, O_RDONLY); - bytes_read = bytes_written = 0; - if (fdin >= 0) { - fstat(fdin, &statbuf); - len=statbuf.st_size; - // - // Now first read the whole contents of the file, and then write it out. - // This is for new-bees trying to import the midi.props in the working dir - // - contents=g_new(char, len); - bytes_read = bytes_written = 0; - if (contents) { - bytes_read=read(fdin, contents, len); - } - close(fdin); - } - fdout=0; - if (contents && bytes_read == len) { - // should this file exist as a link or symlink, or should it - // be read-only, remove it first - unlink("midi.props"); - fdout=open("midi.props", O_WRONLY | O_CREAT, 0644); - if (fdout >= 0) { - bytes_written=write(fdout, contents, len); - close(fdout); - g_free(contents); - } - } - if (fdin < 0 || bytes_read < len) { - message = gtk_message_dialog_new (GTK_WINDOW(top_window), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_ERROR, - GTK_BUTTONS_CLOSE, - "Cannot read input file!\n"); - gtk_dialog_run (GTK_DIALOG (message)); - gtk_widget_destroy(message); - } else if (fdout < 0 || bytes_written < len) { - message = gtk_message_dialog_new (GTK_WINDOW(top_window), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_ERROR, - GTK_BUTTONS_CLOSE, - "Cannot write MIDI settings!\n"); - gtk_dialog_run (GTK_DIALOG (message)); - gtk_widget_destroy(message); - } else { - // only show basename in the message - cp = filename + strlen(filename); - while (cp >= filename) { - if (*cp == '/') { - cp++; - break; - } - cp--; - } - message = gtk_message_dialog_new (GTK_WINDOW(top_window), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_ERROR, - GTK_BUTTONS_CLOSE, - "MIDI import: %ld Bytes read from file %s\n",len,cp); - gtk_dialog_run (GTK_DIALOG (message)); - gtk_widget_destroy(message); - } - g_free(filename); - } - gtk_widget_destroy (opfile); - return TRUE; -} -#endif - static gboolean protocols_cb (GtkWidget *widget, GdkEventButton *event, gpointer data) { configure_protocols(discovery_dialog); return TRUE; @@ -599,12 +498,6 @@ fprintf(stderr,"%p Protocol=%d name=%s\n",d,d->protocol,d->name); g_signal_connect (protocols_b, "button-press-event", G_CALLBACK(protocols_cb), NULL); gtk_grid_attach(GTK_GRID(grid),protocols_b,2,row,1,1); -#ifdef MIDI - GtkWidget *midi_b=gtk_button_new_with_label("ImportMIDI"); - g_signal_connect (midi_b, "button-press-event", G_CALLBACK(midi_cb), NULL); - gtk_grid_attach(GTK_GRID(grid),midi_b,3,row,1,1); -#endif - row++; #ifdef GPIO diff --git a/encoder_menu.c b/encoder_menu.c index 9a81678..44876eb 100644 --- a/encoder_menu.c +++ b/encoder_menu.c @@ -18,6 +18,7 @@ */ #include +#include #include #include @@ -31,71 +32,19 @@ #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;iid=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;iid=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;iid=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=GPOINTER_TO_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=GPOINTER_TO_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), "Encoder"); - 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), "Bottom"); - 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), "Top"); - 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), "Encoder"); - 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), "Switch"); - 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), "ENC2: "); - 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), "ENC3: "); - 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), "ENC4: "); - 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?"Bottom Encoder":"Encoder"); + 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), "Top Encoder"); + 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), "Switch"); + 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), "ENC5: "); - gtk_grid_attach(GTK_GRID(grid),enc5_title,col,row,1,1); + for(int i=0;i%d",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,"%s",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); diff --git a/ext.c b/ext.c index 7334a88..366b2df 100644 --- a/ext.c +++ b/ext.c @@ -76,6 +76,8 @@ // - band_minus(int id) // Move VFO #id to next lower band // - ctun_update(int id, int state) // set CTUN state of VFO #id // - set_split(int state) // Set split mode to state +// - num_pad(int val) // enter VFO frequency +// - update_vfo_step(int direction) // cycle throught VFO step sizes // void set_frequency(int v,long long f) { @@ -160,6 +162,60 @@ void set_split(int val) { } } +void num_pad(int val) { + RECEIVER *rx=active_receiver; + if(!vfo[rx->id].entering_frequency) { + vfo[rx->id].entered_frequency=0; + vfo[rx->id].entering_frequency=TRUE; + } + switch(val) { + case -1: // clear + vfo[rx->id].entered_frequency=0; + vfo[rx->id].entering_frequency=FALSE; + break; + case -2: // enter + if(vfo[rx->id].entered_frequency!=0) { + vfo[rx->id].frequency=vfo[rx->id].entered_frequency; + if(vfo[rx->id].ctun) { + vfo[rx->id].ctun=FALSE; + vfo[rx->id].offset=0; + vfo[rx->id].ctun_frequency=vfo[rx->id].frequency; + } + } + vfo[rx->id].entering_frequency=FALSE; + break; + default: + vfo[rx->id].entered_frequency=(vfo[rx->id].entered_frequency*10)+val; + break; + } + vfo_update(); +} + +void update_vfo_step(int direction) { + int i=0; + while(steps[i]!=step && steps[i]!=0) { + i++; + } + + if(steps[i]!=0) { + // current step size is in slot #i. + if(direction>0) { + // move to next slot (if it exists) + i++; + if(steps[i]!=0) { + step=steps[i]; + } + } else { + // move to previous slot (if it exists) + i--; + if(i>=0) { + step=steps[i]; + } + } + } + vfo_update(); +} + // // Functions to be invoked through the GTK idle queue, // still in use diff --git a/ext.h b/ext.h index 306bf8a..66c74f9 100644 --- a/ext.h +++ b/ext.h @@ -148,3 +148,5 @@ extern void set_frequency(int v,long long f); extern void ctun_update(int id,int state); extern void band_plus(int id); extern void band_minus(int id); +extern void num_pad(int num); +extern void update_vfo_step(int direction); diff --git a/gpio.c b/gpio.c index d62e604..2ef989f 100644 --- a/gpio.c +++ b/gpio.c @@ -1,6 +1,6 @@ /* 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 * as published by the Free Software Foundation; either version 2 @@ -17,6 +17,10 @@ * */ +// Rewrite to use gpiod rather than wiringPi +// Note that all pin numbers are now the Broadcom GPIO + + #include #include @@ -28,8 +32,13 @@ #include #include #include -#include -#include + +#ifdef GPIO +#include +#include +#include +#include +#endif #include "band.h" #include "channel.h" @@ -38,7 +47,6 @@ #include "filter.h" #include "bandstack.h" #include "toolbar.h" -#include "gpio.h" #include "radio.h" #include "toolbar.h" #include "main.h" @@ -48,90 +56,24 @@ #include "new_menu.h" #include "encoder_menu.h" #include "diversity_menu.h" +#include "actions.h" #include "gpio.h" #include "i2c.h" #include "ext.h" #include "sliders.h" #include "new_protocol.h" +#include "zoompan.h" #ifdef LOCALCW #include "iambic.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 +// Broadcom pins #9, 10, 11 are not used // by Controller1 and Controller2_V1 -// (and keep #8,9 reserved for I2C extensions) +// (and keep #2,3 reserved for I2C extensions) // -int CWL_BUTTON=13; -int CWR_BUTTON=14; -int SIDETONE_GPIO=12; +int CWL_BUTTON=9; +int CWR_BUTTON=11; +int SIDETONE_GPIO=10; int ENABLE_GPIO_SIDETONE=0; int ENABLE_CW_BUTTONS=1; int CW_ACTIVE_LOW=1; @@ -139,2231 +81,1026 @@ int CW_ACTIVE_LOW=1; #ifdef PTT int ENABLE_PTT_GPIO=1; -int PTT_GPIO=15; +int PTT_GPIO=14; int PTT_ACTIVE_LOW=1; #endif -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; - -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; - -static int running=0; +enum { + TOP_ENCODER, + BOTTOM_ENCODER +}; -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", - "WATERFALL HIGH", - "WATERFALL LOW", - "XIT", - "ZOOM", +enum { + A, + B }; -char *sw_string[SWITCH_ACTIONS] = { - "", - "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 state table +#define R_START 0x0 +#define R_CW_FINAL 0x1 +#define R_CW_BEGIN 0x2 +#define R_CW_NEXT 0x3 +#define R_CCW_BEGIN 0x4 +#define R_CCW_FINAL 0x5 +#define R_CCW_NEXT 0x6 + +#define DIR_NONE 0x0 +// Clockwise step. +#define DIR_CW 0x10 +// Anti-clockwise step. +#define DIR_CCW 0x20 + +guchar encoder_state_table[7][4] = { + // R_START + {R_START, R_CW_BEGIN, R_CCW_BEGIN, R_START}, + // R_CW_FINAL + {R_CW_NEXT, R_START, R_CW_FINAL, R_START | DIR_CW}, + // R_CW_BEGIN + {R_CW_NEXT, R_CW_BEGIN, R_START, R_START}, + // R_CW_NEXT + {R_CW_NEXT, R_CW_BEGIN, R_CW_FINAL, R_START}, + // R_CCW_BEGIN + {R_CCW_NEXT, R_START, R_CCW_BEGIN, R_START}, + // R_CCW_FINAL + {R_CCW_NEXT, R_CCW_FINAL, R_START, R_START | DIR_CCW}, + // R_CCW_NEXT + {R_CCW_NEXT, R_CCW_FINAL, R_CCW_BEGIN, R_START}, }; -int *sw_action=NULL; +#ifdef GPIO +char *consumer="pihpsdr"; -static int mox_pressed(void *data) { - if(running) sim_mox_cb(NULL,NULL); - return 0; -} +char *gpio_device="/dev/gpiochip0"; -static int s1_pressed(void *data) { - if(running) sim_s1_pressed_cb(NULL,NULL); - return 0; -} +static struct gpiod_chip *chip=NULL; +#endif -static int s1_released(void *data) { - if(running) sim_s1_released_cb(NULL,NULL); - return 0; -} +static GMutex encoder_mutex; +static GThread *monitor_thread_id; + +int I2C_INTERRUPT=15; + +#define MAX_LINES 32 +int monitor_lines[MAX_LINES]; +int lines=0; + +long settle_time=50; // ms + +// VFO Encoder is always last + +ENCODER encoders_no_controller[MAX_ENCODERS]={ + {FALSE,TRUE,0,0,0,0,0,0,R_START,FALSE,TRUE,0,0,0,0,0,0,R_START,FALSE,TRUE,0,0,0L}, + {FALSE,TRUE,0,0,0,0,0,0,R_START,FALSE,TRUE,0,0,0,0,0,0,R_START,FALSE,TRUE,0,0,0L}, + {FALSE,TRUE,0,0,0,0,0,0,R_START,FALSE,TRUE,0,0,0,0,0,0,R_START,FALSE,TRUE,0,0,0L}, + {FALSE,TRUE,0,0,0,0,0,0,R_START,FALSE,TRUE,0,0,0,0,0,0,R_START,FALSE,TRUE,0,0,0L}, + {FALSE,TRUE,0,0,0,0,0,0,R_START,FALSE,TRUE,0,0,0,0,0,0,R_START,FALSE,TRUE,0,0,0L}, + }; + +ENCODER encoders_controller1[MAX_ENCODERS]={ + {TRUE,TRUE,20,1,26,1,0,ENCODER_AF_GAIN,R_START,FALSE,TRUE,0,0,0,0,0,0,R_START,TRUE,TRUE,25,MENU_BAND,0L}, + {TRUE,TRUE,16,1,19,1,0,ENCODER_AGC_GAIN,R_START,FALSE,TRUE,0,0,0,0,0,0,R_START,TRUE,TRUE,8,MENU_BANDSTACK,0L}, + {TRUE,TRUE,4,1,21,1,0,ENCODER_DRIVE,R_START,FALSE,TRUE,0,0,0,0,0,0,R_START,TRUE,TRUE,7,MENU_MODE,0L}, + {TRUE,TRUE,18,1,17,1,0,ENCODER_VFO,R_START,FALSE,TRUE,0,0,0,0,0,0,R_START,FALSE,TRUE,0,0,0L}, + {FALSE,TRUE,0,1,0,0,1,0,R_START,FALSE,TRUE,0,0,0,0,0,0,R_START,FALSE,TRUE,0,0,0L}, + }; + +ENCODER encoders_controller2_v1[MAX_ENCODERS]={ + {TRUE,TRUE,20,1,26,1,0,ENCODER_AF_GAIN,R_START,FALSE,TRUE,0,0,0,0,0,0,R_START,TRUE,TRUE,22,MENU_BAND,0L}, + {TRUE,TRUE,4,1,21,1,0,ENCODER_AGC_GAIN,R_START,FALSE,TRUE,0,0,0,0,0,0,R_START,TRUE,TRUE,27,MENU_BANDSTACK,0L}, + {TRUE,TRUE,16,1,19,1,0,ENCODER_IF_WIDTH,R_START,FALSE,TRUE,0,0,0,0,0,0,R_START,TRUE,TRUE,23,MENU_MODE,0L}, + {TRUE,TRUE,25,1,8,1,0,ENCODER_RIT,R_START,FALSE,TRUE,0,0,0,0,0,0,R_START,TRUE,TRUE,24,MENU_FREQUENCY,0L}, + {TRUE,TRUE,18,1,17,1,0,ENCODER_VFO,R_START,FALSE,TRUE,0,0,0,0,0,0,R_START,FALSE,TRUE,0,0,0L}, + }; + +ENCODER encoders_controller2_v2[MAX_ENCODERS]={ + {TRUE,TRUE,5,1,6,1,0,ENCODER_RF_GAIN,R_START,TRUE,TRUE,26,1,20,1,0,ENCODER_AF_GAIN,R_START,TRUE,TRUE,22,MENU_BAND,0L}, + {TRUE,TRUE,9,1,7,1,0,ENCODER_ATTENUATION,R_START,TRUE,TRUE,21,1,4,1,0,ENCODER_AGC_GAIN,R_START,TRUE,TRUE,27,MENU_MODE,0L}, + {TRUE,TRUE,11,1,10,1,0,ENCODER_IF_WIDTH,R_START,TRUE,TRUE,19,1,16,1,0,ENCODER_IF_SHIFT,R_START,TRUE,TRUE,23,MENU_FILTER,0L}, + {TRUE,TRUE,13,1,12,1,0,ENCODER_XIT,R_START,TRUE,TRUE,8,1,25,1,0,ENCODER_RIT,R_START,TRUE,TRUE,24,MENU_FREQUENCY,0L}, + {TRUE,TRUE,18,1,17,1,0,ENCODER_VFO,R_START,FALSE,TRUE,0,0,0,0,0,0,R_START,FALSE,TRUE,0,0,0L}, + }; + +ENCODER *encoders=encoders_no_controller; + +SWITCH switches_no_controller[MAX_SWITCHES]={ + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L} + }; + +SWITCH switches_controller1[MAX_FUNCTIONS][MAX_SWITCHES]={ + {{TRUE,TRUE,27,MOX,0L}, + {TRUE,TRUE,13,MENU_BAND,0L}, + {TRUE,TRUE,12,MENU_BANDSTACK,0L}, + {TRUE,TRUE,6,MENU_MODE,0L}, + {TRUE,TRUE,5,MENU_FILTER,0L}, + {TRUE,TRUE,24,NR,0L}, + {TRUE,TRUE,23,AGC,0L}, + {TRUE,TRUE,22,FUNCTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}}, + {{TRUE,TRUE,27,MOX,0L}, + {TRUE,TRUE,13,LOCK,0L}, + {TRUE,TRUE,12,CTUN,0L}, + {TRUE,TRUE,6,A_TO_B,0L}, + {TRUE,TRUE,5,B_TO_A,0L}, + {TRUE,TRUE,24,A_SWAP_B,0L}, + {TRUE,TRUE,23,SPLIT,0L}, + {TRUE,TRUE,22,FUNCTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}}, + {{TRUE,TRUE,27,MOX,0L}, + {TRUE,TRUE,13,MENU_FREQUENCY,0L}, + {TRUE,TRUE,12,MENU_MEMORY,0L}, + {TRUE,TRUE,6,RIT,0L}, + {TRUE,TRUE,5,RIT_PLUS,0L}, + {TRUE,TRUE,24,RIT_MINUS,0L}, + {TRUE,TRUE,23,RIT_CLEAR,0L}, + {TRUE,TRUE,22,FUNCTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}}, + {{TRUE,TRUE,27,MOX,0L}, + {TRUE,TRUE,13,MENU_FREQUENCY,0L}, + {TRUE,TRUE,12,MENU_MEMORY,0L}, + {TRUE,TRUE,6,XIT,0L}, + {TRUE,TRUE,5,XIT_PLUS,0L}, + {TRUE,TRUE,24,XIT_MINUS,0L}, + {TRUE,TRUE,23,XIT_CLEAR,0L}, + {TRUE,TRUE,22,FUNCTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}}, + {{TRUE,TRUE,27,MOX,0L}, + {TRUE,TRUE,13,MENU_FREQUENCY,0L}, + {TRUE,TRUE,12,SPLIT,0L}, + {TRUE,TRUE,6,DUPLEX,0L}, + {TRUE,TRUE,5,SAT,0L}, + {TRUE,TRUE,24,RSAT,0L}, + {TRUE,TRUE,23,NO_ACTION,0L}, + {TRUE,TRUE,22,FUNCTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}}, + {{TRUE,TRUE,27,MOX,0L}, + {TRUE,TRUE,13,TUNE,0L}, + {TRUE,TRUE,12,TUNE_FULL,0L}, + {TRUE,TRUE,6,TUNE_MEMORY,0L}, + {TRUE,TRUE,5,MENU_BAND,0L}, + {TRUE,TRUE,24,MENU_MODE,0L}, + {TRUE,TRUE,23,MENU_FILTER,0L}, + {TRUE,TRUE,22,FUNCTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}, + {FALSE,FALSE,0,NO_ACTION,0L}}, + + }; + +SWITCH switches_controller2_v1[MAX_SWITCHES]={ + {FALSE,FALSE,0,MOX,0L}, + {FALSE,FALSE,0,TUNE,0L}, + {FALSE,FALSE,0,PS,0L}, + {FALSE,FALSE,0,TWO_TONE,0L}, + {FALSE,FALSE,0,NR,0L}, + {FALSE,FALSE,0,A_TO_B,0L}, + {FALSE,FALSE,0,B_TO_A,0L}, + {FALSE,FALSE,0,MODE_MINUS,0L}, + {FALSE,FALSE,0,BAND_MINUS,0L}, + {FALSE,FALSE,0,MODE_PLUS,0L}, + {FALSE,FALSE,0,BAND_PLUS,0L}, + {FALSE,FALSE,0,XIT,0L}, + {FALSE,FALSE,0,NB,0L}, + {FALSE,FALSE,0,SNB,0L}, + {FALSE,FALSE,0,LOCK,0L}, + {FALSE,FALSE,0,CTUN,0L} + }; + +SWITCH switches_controller2_v2[MAX_SWITCHES]={ + {FALSE,FALSE,0,MOX,0L}, + {FALSE,FALSE,0,TUNE,0L}, + {FALSE,FALSE,0,PS,0L}, + {FALSE,FALSE,0,TWO_TONE,0L}, + {FALSE,FALSE,0,NR,0L}, + {FALSE,FALSE,0,A_TO_B,0L}, + {FALSE,FALSE,0,B_TO_A,0L}, + {FALSE,FALSE,0,MODE_MINUS,0L}, + {FALSE,FALSE,0,BAND_MINUS,0L}, + {FALSE,FALSE,0,MODE_PLUS,0L}, + {FALSE,FALSE,0,BAND_PLUS,0L}, + {FALSE,FALSE,0,XIT,0L}, + {FALSE,FALSE,0,NB,0L}, + {FALSE,FALSE,0,SNB,0L}, + {FALSE,FALSE,0,LOCK,0L}, + {FALSE,FALSE,0,CTUN,0L} + }; + +SWITCH *switches=switches_controller1[0]; -static int s2_pressed(void *data) { - if(running) sim_s2_pressed_cb(NULL,NULL); - return 0; -} +static int running=0; -static int s2_released(void *data) { - if(running) sim_s2_released_cb(NULL,NULL); - return 0; -} +static GThread *rotary_encoder_thread_id; -static int s3_pressed(void *data) { - if(running) sim_s3_pressed_cb(NULL,NULL); - return 0; -} +static uint64_t epochMilli; -static int s3_released(void *data) { - if(running) sim_s3_released_cb(NULL,NULL); - return 0; -} +static void initialiseEpoch() { + struct timespec ts ; -static int s4_pressed(void *data) { - if(running) sim_s4_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 s4_released(void *data) { - if(running) sim_s4_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 s5_pressed(void *data) { - if(running) sim_s5_pressed_cb(NULL,NULL); - return 0; -} +static gpointer rotary_encoder_thread(gpointer data) { + ENCODER_ACTION *a; + int i; -static int s5_released(void *data) { - if(running) sim_s5_released_cb(NULL,NULL); - return 0; + usleep(250000); + g_print("%s\n",__FUNCTION__); + while(TRUE) { + g_mutex_lock(&encoder_mutex); + for(i=0;iaction=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) { + //g_print("%s: TOP encoder %d pos=%d\n",__FUNCTION__,i,encoders[i].top_encoder_pos); + a=g_new(ENCODER_ACTION,1); + a->action=encoders[i].top_encoder_function; + a->mode=RELATIVE; + a->val=encoders[i].top_encoder_pos; + g_idle_add(encoder_action,a); + encoders[i].top_encoder_pos=0; + } + } + g_mutex_unlock(&encoder_mutex); + usleep(100000); // sleep for 100ms + } } -static int s6_pressed(void *data) { - if(running) sim_s6_pressed_cb(NULL,NULL); +int process_function_switch(void *data) { + function++; + if(function>=MAX_FUNCTIONS) { + function=0; + } + switches=switches_controller1[function]; + update_toolbar_labels(); return 0; } -static int s6_released(void *data) { - if(running) sim_s6_released_cb(NULL,NULL); - return 0; -} +#ifdef GPIO +static unsigned long switch_debounce; + +static void process_encoder(int e,int l,int addr,int val) { + guchar pinstate; + //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; + pinstate=(encoders[e].bottom_encoder_b_value<<1) | encoders[e].bottom_encoder_a_value; + encoders[e].bottom_encoder_state=encoder_state_table[encoders[e].bottom_encoder_state&0xf][pinstate]; + //g_print("%s: state=%02X\n",__FUNCTION__,encoders[e].bottom_encoder_state); + switch(encoders[e].bottom_encoder_state&0x30) { + case DIR_NONE: + break; + case DIR_CW: + encoders[e].bottom_encoder_pos++; + break; + case DIR_CCW: + encoders[e].bottom_encoder_pos--; + break; + default: + break; + } -static int function_pressed(void *data) { - if(running) sim_function_cb(NULL,NULL); - return 0; + //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; + pinstate=(encoders[e].bottom_encoder_b_value<<1) | encoders[e].bottom_encoder_a_value; + encoders[e].bottom_encoder_state=encoder_state_table[encoders[e].bottom_encoder_state&0xf][pinstate]; + //g_print("%s: state=%02X\n",__FUNCTION__,encoders[e].bottom_encoder_state); + switch(encoders[e].bottom_encoder_state&0x30) { + case DIR_NONE: + break; + case DIR_CW: + encoders[e].bottom_encoder_pos++; + break; + case DIR_CCW: + encoders[e].bottom_encoder_pos--; + break; + default: + break; + } + + //g_print("%s: %s BOTTOM pos=%d\n",__FUNCTION__,encoder_string[encoders[e].bottom_encoder_function],encoders[e].bottom_encoder_pos); + + break; + } + break; + case TOP_ENCODER: + switch(addr) { + case A: + encoders[e].top_encoder_a_value=val; + pinstate=(encoders[e].top_encoder_b_value<<1) | encoders[e].top_encoder_a_value; + encoders[e].top_encoder_state=encoder_state_table[encoders[e].top_encoder_state&0xf][pinstate]; + //g_print("%s: state=%02X\n",__FUNCTION__,encoders[e].top_encoder_state); + switch(encoders[e].top_encoder_state&0x30) { + case DIR_NONE: + break; + case DIR_CW: + encoders[e].top_encoder_pos++; + break; + case DIR_CCW: + encoders[e].top_encoder_pos--; + break; + default: + break; + } + //g_print("%s: %s TOP pos=%d\n",__FUNCTION__,encoder_string[encoders[e].top_encoder_function],encoders[e].top_encoder_pos); + break; + case B: + encoders[e].top_encoder_b_value=val; + pinstate=(encoders[e].top_encoder_b_value<<1) | encoders[e].top_encoder_a_value; + encoders[e].top_encoder_state=encoder_state_table[encoders[e].top_encoder_state&0xf][pinstate]; + //g_print("%s: state=%02X\n",__FUNCTION__,encoders[e].top_encoder_state); + switch(encoders[e].top_encoder_state&0x30) { + case DIR_NONE: + break; + case DIR_CW: + encoders[e].top_encoder_pos++; + break; + case DIR_CCW: + encoders[e].top_encoder_pos--; + break; + default: + break; + } + //g_print("%s: %s TOP pos=%d\n",__FUNCTION__,encoder_string[encoders[e].top_encoder_function],encoders[e].top_encoder_pos); + + break; + } + break; + } + g_mutex_unlock(&encoder_mutex); } -static int vfo_function_pressed(void *data) { - RECEIVER *rx; - if(receivers==2) { - if(active_receiver==receiver[0]) { - rx=receiver[1]; - } else { - rx=receiver[0]; +static void process_edge(int offset,int value) { + gint i; + gint t; + gboolean found; + + //g_print("%s: offset=%d value=%d\n",__FUNCTION__,offset,value); + found=FALSE; +#ifdef LOCALCW + if(ENABLE_CW_BUTTONS) { + if(offset==CWL_BUTTON) { + keyer_event(1, CW_ACTIVE_LOW ? (value==PRESSED) : value); + found=TRUE; + } else if(offset==CWR_BUTTON) { + keyer_event(1, CW_ACTIVE_LOW ? (value==PRESSED) : value); + found=TRUE; + } + } + if(found) return; +#endif + // check encoders + for(i=0;iaction=encoders[i].switch_function; + a->state=value; + g_idle_add(switch_action,a); + found=TRUE; + break; } - 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); } - return 0; -} -static int vfo_function_released(void *data) { - return 0; -} + if(controller==CONTROLLER2_V1 || controller==CONTROLLER2_V2) { + if(I2C_INTERRUPT==offset) { + if(value==PRESSED) { + i2c_interrupt(); + } + found=TRUE; + } + } -#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; -} + if(!found) { + for(i=0;iaction=switches[i].switch_function; + a->state=value; + g_idle_add(switch_action,a); + break; + } + } + } -static int ptt_released(void *data) { -g_print("ptt_released\n"); - if(can_transmit) g_idle_add(ext_mox_update,GINT_TO_POINTER(0)); - return 0; + + if(!found) { + g_print("%s: could not find %d\n",__FUNCTION__,offset); + } } -#endif -static int e_function_pressed(void *data) { - int action=GPOINTER_TO_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); +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 BAND_PLUS: - g_idle_add(ext_band_plus,NULL); + case GPIOD_CTXLESS_EVENT_CB_RISING_EDGE: + //g_print("%s: Ignore RISING EDGE\n",__FUNCTION__); + process_edge(line,RELEASED); 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); - break; - case MENU_MEMORY: - g_idle_add(ext_memory_update,NULL); - break; - case MENU_DIVERSITY: - g_idle_add(ext_diversity_update,GINT_TO_POINTER(1)); - break; -#ifdef PURESIGNAL - case MENU_PS: - g_idle_add(ext_start_ps,NULL); + case GPIOD_CTXLESS_EVENT_CB_FALLING_EDGE: + //g_print("%s: Process FALLING EDGE\n",__FUNCTION__); + process_edge(line,PRESSED); break; + } + return GPIOD_CTXLESS_EVENT_CB_RET_OK; +} #endif - case FUNCTION: - g_idle_add(ext_function_update,NULL); - break; - case MUTE: - g_idle_add(ext_mute_update,NULL); - break; - case PAN_MINUS: - g_idle_add(ext_pan_update,GINT_TO_POINTER(-100)); + +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_controller1[0]; 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,GINT_TO_POINTER(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 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); - } - vfo_debounce=t; - } + g_print("%s: exit\n",__FUNCTION__); + return NULL; } -#endif -static void vfoEncoderInt() { - static int vfoA=1; - int levelA=digitalRead(VFO_ENCODER_A); - int levelB=digitalRead(VFO_ENCODER_B); +static int setup_line(struct gpiod_chip *chip, int offset, gboolean pullup) { + int ret; + struct gpiod_line_request_config config; - if(levelA!=vfoA) { - if(levelA==levelB) ++vfoEncoderPos; - if(levelA!=levelB) --vfoEncoderPos; - vfoA=levelA; + 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 void e2EncoderInt() { - static int e2CurrentA=1; - int levelA=digitalRead(E2_ENCODER_A); - int levelB=digitalRead(E2_ENCODER_B); - - if(levelA!=e2CurrentA) { - if(levelA==levelB) ++e2EncoderPos; - if(levelA!=levelB) --e2EncoderPos; - e2CurrentA=levelA; + config.consumer=consumer; + config.request_type=GPIOD_LINE_REQUEST_DIRECTION_INPUT | GPIOD_LINE_REQUEST_EVENT_BOTH_EDGES; +#ifdef OLD_GPIOD + 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 e2TopEncoderInt() { - static int e2TopCurrentA=1; - int levelA=digitalRead(E2_TOP_ENCODER_A); - int levelB=digitalRead(E2_TOP_ENCODER_B); + gpiod_line_release(line); - if(levelA!=e2TopCurrentA) { - if(levelA==levelB) ++e2TopEncoderPos; - if(levelA!=levelB) --e2TopEncoderPos; - e2TopCurrentA=levelA; - } + monitor_lines[lines]=offset; + lines++; + return 0; } -static void e3EncoderInt() { - static int e3CurrentA=1; - int levelA=digitalRead(E3_ENCODER_A); - int levelB=digitalRead(E3_ENCODER_B); +static int setup_output_line(struct gpiod_chip *chip, int offset, int _initial_value) { + int ret; + struct gpiod_line_request_config config; - if(levelA!=e3CurrentA) { - if(levelA==levelB) ++e3EncoderPos; - if(levelA!=levelB) --e3EncoderPos; - e3CurrentA=levelA; + 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 void e3TopEncoderInt() { - static int e3TopCurrentA=1; - int levelA=digitalRead(E3_TOP_ENCODER_A); - int levelB=digitalRead(E3_TOP_ENCODER_B); - - if(levelA!=e3TopCurrentA) { - if(levelA==levelB) ++e3TopEncoderPos; - if(levelA!=levelB) --e3TopEncoderPos; - e3TopCurrentA=levelA; + config.consumer=consumer; + config.request_type=GPIOD_LINE_REQUEST_DIRECTION_OUTPUT; + 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 e4EncoderInt() { - static int e4CurrentA=1; - int levelA=digitalRead(E4_ENCODER_A); - int levelB=digitalRead(E4_ENCODER_B); - if(levelA!=e4CurrentA) { - if(levelA==levelB) ++e4EncoderPos; - if(levelA!=levelB) --e4EncoderPos; - e4CurrentA=levelA; - } -} + // write initial value + -static void e4TopEncoderInt() { - static int e4TopCurrentA=1; - int levelA=digitalRead(E4_TOP_ENCODER_A); - int levelB=digitalRead(E4_TOP_ENCODER_B); + gpiod_line_release(line); - if(levelA!=e4TopCurrentA) { - if(levelA==levelB) ++e4TopEncoderPos; - if(levelA!=levelB) --e4TopEncoderPos; - e4TopCurrentA=levelA; - } + return 0; } +#endif -static void e5EncoderInt() { - static int e5CurrentA=1; - int levelA=digitalRead(E5_ENCODER_A); - int levelB=digitalRead(E5_ENCODER_B); +int gpio_init() { + int ret=0; +#ifdef GPIO + initialiseEpoch(); + switch_debounce=millis(); - if(levelA!=e5CurrentA) { - if(levelA==levelB) ++e5EncoderPos; - if(levelA!=levelB) --e5EncoderPos; - e5CurrentA=levelA; - } -} + g_mutex_init(&encoder_mutex); + + gpio_set_defaults(controller); -static void e5TopEncoderInt() { - static int e5TopCurrentA=1; - int levelA=digitalRead(E5_TOP_ENCODER_A); - int levelB=digitalRead(E5_TOP_ENCODER_B); + chip=NULL; - if(levelA!=e5TopCurrentA) { - if(levelA==levelB) ++e5TopEncoderPos; - if(levelA!=levelB) --e5TopEncoderPos; - e5TopCurrentA=levelA; +//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 pI2CInterrupt() { - int level=digitalRead(I2C_INTERRUPT); - if(level==0) { - i2c_interrupt(); + // setup encoders + g_print("%s: setup encoders\n",__FUNCTION__); + for(int i=0;i1) { - if(pos<0 && pos>-vfo_encoder_divisor) { - pos=0; - } else if(pos>0 && posid].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=GPOINTER_TO_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=GPOINTER_TO_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=GPOINTER_TO_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=GPOINTER_TO_INT(data); - if(active_menu==E5_MENU) { - encoder_select(pos); - } else { - encoder_changed(e5_encoder_action,pos); - } - return 0; +#endif } - -static int e2_top_encoder_changed(void *data) { - int pos=GPOINTER_TO_INT(data); - if(active_menu==E2_MENU) { - encoder_select(pos); - } else { - encoder_changed(e2_top_encoder_action,pos); - } +int gpio_left_cw_key() { return 0; } -static int e3_top_encoder_changed(void *data) { - int pos=GPOINTER_TO_INT(data); - if(active_menu==E3_MENU) { - encoder_select(pos); - } else { - encoder_changed(e3_top_encoder_action,pos); - } +int gpio_right_cw_key() { return 0; } -static int e4_top_encoder_changed(void *data) { - int pos=GPOINTER_TO_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=GPOINTER_TO_INT(data); - if(active_menu==E5_MENU) { - encoder_select(pos); - } else { - encoder_changed(e5_top_encoder_action,pos); - } - return 0; +int gpio_cw_sidetone_enabled() { + return ENABLE_GPIO_SIDETONE; } -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,GINT_TO_POINTER(pos)); - } - - pos=e2_encoder_get_pos(); - if(pos!=0) { - g_idle_add(e2_encoder_changed,GINT_TO_POINTER(pos)); - } - - pos=e3_encoder_get_pos(); - if(pos!=0) { - g_idle_add(e3_encoder_changed,GINT_TO_POINTER(pos)); - } - - pos=e4_encoder_get_pos(); - if(pos!=0) { - g_idle_add(e4_encoder_changed,GINT_TO_POINTER(pos)); - } - - if(controller==CONTROLLER2_V1 || controller==CONTROLLER2_V2) { - pos=e5_encoder_get_pos(); - if(pos!=0) { - g_idle_add(e5_encoder_changed,GINT_TO_POINTER(pos)); - } - } - - - if(controller==CONTROLLER2_V2) { - pos=e2_top_encoder_get_pos(); - if(pos!=0) { - g_idle_add(e2_top_encoder_changed,GINT_TO_POINTER(pos)); - } - - pos=e3_top_encoder_get_pos(); - if(pos!=0) { - g_idle_add(e3_top_encoder_changed,GINT_TO_POINTER(pos)); - } - - pos=e4_top_encoder_get_pos(); - if(pos!=0) { - g_idle_add(e4_top_encoder_changed,GINT_TO_POINTER(pos)); - } - - pos=e5_top_encoder_get_pos(); - if(pos!=0) { - g_idle_add(e5_top_encoder_changed,GINT_TO_POINTER(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 b15d8a0..a9072f5 100644 --- a/gpio.h +++ b/gpio.h @@ -20,218 +20,66 @@ #ifndef _GPIO_H #define _GPIO_H -enum { - NO_CONTROLLER=0, - CONTROLLER1, - CONTROLLER2_V1, - CONTROLLER2_V2, -}; - -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 -}; +#define MAX_ENCODERS 5 +#define MAX_SWITCHES 16 +#define MAX_FUNCTIONS 6 + +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; + guchar bottom_encoder_state; + 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; + guchar top_encoder_state; + gboolean switch_enabled; + gboolean switch_pullup; + gint switch_address; + gint switch_function; + gulong switch_debounce; +} ENCODER; + +extern ENCODER *encoders; + +typedef struct _switch { + gboolean switch_enabled; + gboolean switch_pullup; + gint switch_address; + gint switch_function; + gulong switch_debounce; +} 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 long 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 process_function_switch(void *data); +extern void gpio_set_defaults(int ctrlr); +extern void gpio_restore_actions(); +extern void gpio_restore_state(); +extern void gpio_save_state(); +extern void gpio_save_actions(); +extern int gpio_init(); +extern void gpio_close(); -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; @@ -245,29 +93,4 @@ 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 void gpio_set_defaults(int ctrlr); -extern void gpio_restore_actions(); -extern void gpio_restore_state(); -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 7798b8e..78fc43b 100644 --- a/i2c.c +++ b/i2c.c @@ -1,16 +1,17 @@ +#ifdef GPIO #include #include #include #include #include #include -//#include +#include #include #include #include -//#include "i2c.h" -#include "wiringPiI2C.h" +#include "i2c.h" +#include "actions.h" #include "gpio.h" #include "band.h" #include "band_menu.h" @@ -44,31 +45,31 @@ static int fd; #define SW_17 0X0100 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 }; + { SW_2,SW_3,SW_4,SW_5,SW_6,SW_14,SW_15,SW_13, + SW_12,SW_11,SW_10,SW_9,SW_7,SW_8,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,157 +82,21 @@ 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); -//g_print("i2c_interrupt: flags=%04X ints=%04X\n",flags,ints); + ints=read_word_data(0x10); +g_print("%s: flags=%04X ints=%04X\n",__FUNCTION__,flags,ints); if(ints) { int i; for(i=0;i<16;i++) { if(i2c_sw[i]==ints) break; } if(i<16) { -//g_print("i1c_interrupt: sw=%d action=%d\n",i,sw_action[i]); - switch(sw_action[i]) { - case TUNE: - if(can_transmit) { - int tune=getTune(); - if(tune==0) tune=1; else tune=0; - g_idle_add(ext_tune_update,GINT_TO_POINTER(tune)); - } - break; - case MOX: - if(can_transmit) { - int mox=getMox(); - if(mox==0) mox=1; else mox=0; - g_idle_add(ext_mox_update,GINT_TO_POINTER(mox)); - } - 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); - break; - case MENU_MEMORY: - g_idle_add(ext_memory_update,NULL); - break; - case MENU_DIVERSITY: - g_idle_add(ext_diversity_update,GINT_TO_POINTER(1)); - break; - case MENU_PS: -#ifdef PURESIGNAL - g_idle_add(ext_start_ps,NULL); -#endif - break; - case FUNCTION: - g_idle_add(ext_function_update,NULL); - break; - case MUTE: - g_idle_add(ext_mute_update,NULL); - break; - case PAN_MINUS: - g_idle_add(ext_pan_update,GINT_TO_POINTER(-100)); - break; - case PAN_PLUS: - g_idle_add(ext_pan_update,GINT_TO_POINTER(100)); - break; - case ZOOM_MINUS: - g_idle_add(ext_zoom_update,GINT_TO_POINTER(-1)); - break; - case ZOOM_PLUS: - g_idle_add(ext_zoom_update,GINT_TO_POINTER(1)); - break; - } +g_print("%s: switches=%p sw=%d action=%d\n",__FUNCTION__,switches,i,switches[i].switch_function); + SWITCH_ACTION *a=g_new(SWITCH_ACTION,1); + a->action=switches[i].switch_function; + a->state=PRESSED; + g_idle_add(switch_action,a); } } } @@ -242,56 +107,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) { @@ -301,3 +171,4 @@ fprintf(stderr,"i2c_init: %s\n",i2c_device); } while(flags!=0); } +#endif diff --git a/iambic.c b/iambic.c index dadc20a..c81e7cf 100644 --- a/iambic.c +++ b/iambic.c @@ -177,6 +177,7 @@ ************************************************************************************************************** */ +#include #include #include #include @@ -191,7 +192,7 @@ #include #include -#ifdef GPIO +#ifdef LOCALCW #include "gpio.h" #endif #include "radio.h" @@ -240,14 +241,6 @@ extern int clock_nanosleep(clockid_t __clock_id, int __flags, struct timespec *__rem); #endif -#ifndef GPIO -// -// Dummy functions if compiled without GPIO -// -int gpio_cw_sidetone_enabled() { return 0; } -void gpio_cw_sidetone_set(int level) {} -#endif - static void keyer_straight_key(int state) { // // Interface for simple key-down action e.g. from a MIDI message diff --git a/mac_midi.c b/mac_midi.c index 60c7b01..5336e66 100644 --- a/mac_midi.c +++ b/mac_midi.c @@ -27,7 +27,17 @@ * */ +#include +#include "discovered.h" +#include "receiver.h" +#include "transmitter.h" +#include "receiver.h" +#include "adc.h" +#include "dac.h" +#include "radio.h" #include "midi.h" +#include "midi_menu.h" +#include "alsa_midi.h" #ifdef __APPLE__ @@ -43,6 +53,10 @@ #include #include +MIDI_DEVICE midi_devices[MAX_MIDI_DEVICES]; +int n_midi_devices; +int running; + // // MIDI callback function // called by MacOSX when data from the specified MIDI device arrives. @@ -69,6 +83,8 @@ static enum { CMD_PITCH, } command; +static gboolean configure=FALSE; + static void ReadMIDIdevice(const MIDIPacketList *pktlist, void *refCon, void *connRefCon) { int i,j,byte,chan,arg1,arg2; MIDIPacket *packet = (MIDIPacket *)pktlist->packet; @@ -119,19 +135,39 @@ static void ReadMIDIdevice(const MIDIPacketList *pktlist, void *refCon, void *co // messages with velocity == 0 when releasing // a push-button. if (arg2 == 0) { - NewMidiEvent(MIDI_EVENT_NOTE, chan, arg1, 0); + if(configure) { + NewMidiConfigureEvent(MIDI_EVENT_NOTE, chan, arg1, 0); + } else { + NewMidiEvent(MIDI_EVENT_NOTE, chan, arg1, 0); + } } else { - NewMidiEvent(MIDI_EVENT_NOTE, chan, arg1, 1); + if(configure) { + NewMidiConfigureEvent(MIDI_EVENT_NOTE, chan, arg1, 1); + } else { + NewMidiEvent(MIDI_EVENT_NOTE, chan, arg1, 1); + } } break; case CMD_NOTEOFF: - NewMidiEvent(MIDI_EVENT_NOTE, chan, arg1, 0); + if(configure) { + NewMidiConfigureEvent(MIDI_EVENT_NOTE, chan, arg1, 0); + } else { + NewMidiEvent(MIDI_EVENT_NOTE, chan, arg1, 0); + } break; case CMD_CTRL: - NewMidiEvent(MIDI_EVENT_CTRL, chan, arg1, arg2); + if(configure) { + NewMidiConfigureEvent(MIDI_EVENT_CTRL, chan, arg1, arg2); + } else { + NewMidiEvent(MIDI_EVENT_CTRL, chan, arg1, arg2); + } break; case CMD_PITCH: - NewMidiEvent(MIDI_EVENT_PITCH, chan, 0, arg1+128*arg2); + if(configure) { + NewMidiConfigureEvent(MIDI_EVENT_PITCH, chan, 0, arg1+128*arg2); + } else { + NewMidiEvent(MIDI_EVENT_PITCH, chan, 0, arg1+128*arg2); + } break; } state=STATE_SKIP; @@ -142,54 +178,159 @@ static void ReadMIDIdevice(const MIDIPacketList *pktlist, void *refCon, void *co } // j-loop through the list of packets } +// +// store the ports and clients locally such that we +// can properly close a MIDI connection. +// This can be local static data, no one outside this file +// needs it. +// +static MIDIPortRef myMIDIports[MAX_MIDI_DEVICES]; +static MIDIClientRef myClients[MAX_MIDI_DEVICES]; -void register_midi_device(char *myname) { - unsigned long nDevices; - int i; - CFStringRef pname; - char name[100]; - int FoundMIDIref=-1; - int mylen=strlen(myname); +void close_midi_device(index) { + fprintf(stderr,"%s index=%d\n",__FUNCTION__, index); + if (index < 0 || index > n_midi_devices) return; + // + // This should release the resources associated with the pending connection + // + MIDIPortDisconnectSource(myMIDIports[index], MIDIGetSource(index)); + midi_devices[index].active=0; +} +void register_midi_device(int index) { + OSStatus osret; + g_print("%s: index=%d\n",__FUNCTION__,index); // -// Go through the list of MIDI devices and -// look whether the one we are looking for is there +// Register a callback routine for the device // + if (index < 0 || index > MAX_MIDI_DEVICES) return; + + myClients[index]=0; + myMIDIports[index] = 0; + //Create client and port, and connect + osret=MIDIClientCreate(CFSTR("piHPSDR"),NULL,NULL, &myClients[index]); + if (osret !=0) { + g_print("%s: MIDIClientCreate failed with ret=%d\n", __FUNCTION__, (int) osret); + return; + } + osret=MIDIInputPortCreate(myClients[index], CFSTR("FromMIDI"), ReadMIDIdevice, NULL, &myMIDIports[index]); + if (osret !=0) { + g_print("%s: MIDIInputPortCreate failed with ret=%d\n", __FUNCTION__, (int) osret); + return; + } + osret=MIDIPortConnectSource(myMIDIports[index] ,MIDIGetSource(index), NULL); + if (osret != 0) { + g_print("%s: MIDIPortConnectSource failed with ret=%d\n", __FUNCTION__, (int) osret); + return; + } + // + // Now we have successfully opened the device. + // + midi_devices[index].active=1; + return; +} + +void get_midi_devices() { + int n; + int i; + CFStringRef pname; // MacOS name of the device + char name[100]; // C name of the device + OSStatus osret; + static int first=1; + + if (first) { + // + // perhaps not necessary in C, but good programming practise: + // initialize the table upon the first call + // + first=0; + for (i=0; i" // - if (strlen(name) == 0) strcpy(name,"NoPort"); - if (!strncmp(name, myname, mylen)) { - FoundMIDIref=i; - fprintf(stderr,"MIDI: registering device >%s<\n", name); - } else { - fprintf(stderr,"MIDI: looking for >%s< so >%s< does not match\n", myname,name); - } - } + if (strlen(name) == 0) sprintf(name,"NoPort%d",n_midi_devices); + g_print("%s: %s\n",__FUNCTION__,name); + if (midi_devices[n_midi_devices].name != NULL) { + if (strncmp(name, midi_devices[n_midi_devices].name,sizeof(name))) { + // + // This slot was occupied and the names do not match: + // Close device (if active), insert new name + // + if (midi_devices[n_midi_devices].active) { + close_midi_device(n_midi_devices); + } + g_free(midi_devices[n_midi_devices].name); + midi_devices[n_midi_devices].name=g_new(gchar,strlen(name)+1); + strcpy(midi_devices[n_midi_devices].name, name); + } else { + // + // This slot was occupied and the names match: do nothing! + // If there was no hot-plug or hot-unplug, we should always + // arrive here! + // + } + } else { + // + // This slot was unoccupied. Insert name and mark inactive + // + midi_devices[n_midi_devices].name=g_new(gchar,strlen(name)+1); + strcpy(midi_devices[n_midi_devices].name, name); + midi_devices[n_midi_devices].active=0; + } + n_midi_devices++; + } + // + // If there are more devices than we have slots in our Table + // just stop processing. + // + if (n_midi_devices >= MAX_MIDI_DEVICES) break; } - -// -// If we found "our" device, register a callback routine -// - - if (FoundMIDIref >= 0) { - MIDIClientRef client = 0; - MIDIPortRef myMIDIport = 0; - //Create client - MIDIClientCreate(CFSTR("piHPSDR"),NULL,NULL, &client); - MIDIInputPortCreate(client, CFSTR("FromMIDI"), ReadMIDIdevice, NULL, &myMIDIport); - MIDIPortConnectSource(myMIDIport,MIDIGetSource(FoundMIDIref), NULL); + g_print("%s: number of devices=%d\n",__FUNCTION__,n_midi_devices); + // + // Get rid of all devices lingering around above the high-water mark + // (this happens in the case of hot-unplugging) + // + for (i=n_midi_devices; i extern struct utsname unameData; +enum { + NO_CONTROLLER, + CONTROLLER1, + CONTROLLER2_V1, + CONTROLLER2_V2 +}; + +extern gint controller; + extern gint display_width; extern gint display_height; extern gint full_screen; diff --git a/midi.h b/midi.h index 54b14f4..2a29013 100644 --- a/midi.h +++ b/midi.h @@ -56,17 +56,39 @@ enum MIDIaction { MIDI_ACTION_ANF, // ANF: toggel ANF on/off MIDI_ACTION_ATT, // ATT: Step attenuator or Programmable attenuator MIDI_ACTION_VFO_B2A, // B2A: VFO B -> A + MIDI_ACTION_BAND_10, // BAND10 + MIDI_ACTION_BAND_12, // BAND12 + MIDI_ACTION_BAND_1240, // BAND1240 + MIDI_ACTION_BAND_144, // BAND144 + MIDI_ACTION_BAND_15, // BAND15 + MIDI_ACTION_BAND_160, // BAND160 + MIDI_ACTION_BAND_17, // BAND17 + MIDI_ACTION_BAND_20, // BAND20 + MIDI_ACTION_BAND_220, // BAND220 + MIDI_ACTION_BAND_2300, // BAND2300 + MIDI_ACTION_BAND_30, // BAND30 + MIDI_ACTION_BAND_3400, // BAND3400 + MIDI_ACTION_BAND_40, // BAND40 + MIDI_ACTION_BAND_430, // BAND430 + MIDI_ACTION_BAND_6, // BAND6 + MIDI_ACTION_BAND_60, // BAND60 + MIDI_ACTION_BAND_70, // BAND70 + MIDI_ACTION_BAND_80, // BAND80 + MIDI_ACTION_BAND_902, // BAND902 + MIDI_ACTION_BAND_AIR, // BANDAIR MIDI_ACTION_BAND_DOWN, // BANDDOWN: cycle through bands downwards + MIDI_ACTION_BAND_GEN, // BANDGEN MIDI_ACTION_BAND_UP, // BANDUP: cycle through bands upwards + MIDI_ACTION_BAND_WWV, // BANDWWVUP: cycle through bands upwards MIDI_ACTION_COMPRESS, // COMPRESS: TX compressor value MIDI_ACTION_CTUN, // CTUN: toggle CTUN on/off MIDI_ACTION_VFO, // CURRVFO: change VFO frequency - MIDI_ACTION_CWKEY, // CWKEY: Unconditional CW key-down/up (outside keyer) - MIDI_ACTION_CWL, // CWL: Left paddle pressed (use with ONOFF) - MIDI_ACTION_CWR, // CWR: Right paddle pressed (use with ONOFF) + MIDI_ACTION_CWKEYER, // CW(Keyer): Unconditional CW key-down/up (outside keyer) + MIDI_ACTION_CWLEFT, // CWLEFT: Left paddle pressed (use with ONOFF) + MIDI_ACTION_CWRIGHT, // CWRIGHT: Right paddle pressed (use with ONOFF) MIDI_ACTION_CWSPEED, // CWSPEED: Set speed of (iambic) CW keyer MIDI_ACTION_DIV_COARSEGAIN, // DIVCOARSEGAIN: change DIVERSITY gain in large increments - MIDI_ACTION_DIV_COARSEPHASE, // DIVPHASE: change DIVERSITY phase in large increments + MIDI_ACTION_DIV_COARSEPHASE, // DIVCOARSEPHASE: change DIVERSITY phase in large increments MIDI_ACTION_DIV_FINEGAIN, // DIVFINEGAIN: change DIVERSITY gain in small increments MIDI_ACTION_DIV_FINEPHASE, // DIVFINEPHASE: change DIVERSITY phase in small increments MIDI_ACTION_DIV_GAIN, // DIVGAIN: change DIVERSITY gain in medium increments @@ -76,6 +98,13 @@ enum MIDIaction { MIDI_ACTION_FILTER_DOWN, // FILTERDOWN: cycle through filters downwards MIDI_ACTION_FILTER_UP, // FILTERUP: cycle through filters upwards MIDI_ACTION_LOCK, // LOCK: lock VFOs, disable frequency changes + MIDI_ACTION_MEM_RECALL_M0, // RECALLM0: load current freq/mode/filter from memory slot #0 + MIDI_ACTION_MEM_RECALL_M1, // RECALLM1: load current freq/mode/filter from memory slot #1 + MIDI_ACTION_MEM_RECALL_M2, // RECALLM2: load current freq/mode/filter from memory slot #2 + MIDI_ACTION_MEM_RECALL_M3, // RECALLM3: load current freq/mode/filter from memory slot #3 + MIDI_ACTION_MEM_RECALL_M4, // RECALLM4: load current freq/mode/filter from memory slot #4 + MIDI_ACTION_MENU_FILTER, // MENU_FILTER + MIDI_ACTION_MENU_MODE, // MENU_MODE MIDI_ACTION_MIC_VOLUME, // MICGAIN: MIC gain MIDI_ACTION_MODE_DOWN, // MODEDOWN: cycle through modes downwards MIDI_ACTION_MODE_UP, // MODEUP: cycle through modes upwards @@ -83,17 +112,24 @@ enum MIDIaction { MIDI_ACTION_MUTE, // MUTE: toggle mute on/off MIDI_ACTION_NB, // NOISEBLANKER: cycle through NoiseBlanker states (none, NB, NB2) MIDI_ACTION_NR, // NOISEREDUCTION: cycle through NoiseReduction states (none, NR, NR2) + MIDI_ACTION_NUMPAD_0, // NUMPAD0 + MIDI_ACTION_NUMPAD_1, // NUMPAD1 + MIDI_ACTION_NUMPAD_2, // NUMPAD2 + MIDI_ACTION_NUMPAD_3, // NUMPAD3 + MIDI_ACTION_NUMPAD_4, // NUMPAD4 + MIDI_ACTION_NUMPAD_5, // NUMPAD5 + MIDI_ACTION_NUMPAD_6, // NUMPAD6 + MIDI_ACTION_NUMPAD_7, // NUMPAD7 + MIDI_ACTION_NUMPAD_8, // NUMPAD8 + MIDI_ACTION_NUMPAD_9, // NUMPAD9 + MIDI_ACTION_NUMPAD_CL, // NUMPADCL + MIDI_ACTION_NUMPAD_ENTER, // NUMPADENTER MIDI_ACTION_PAN, // PAN: change panning of panadater/waterfall when zoomed MIDI_ACTION_PAN_HIGH, // PANHIGH: "high" value of current panadapter MIDI_ACTION_PAN_LOW, // PANLOW: "low" value of current panadapter MIDI_ACTION_PRE, // PREAMP: preamp on/off - MIDI_ACTION_PTTONOFF, // PTT: set PTT state to "on" or "off" + MIDI_ACTION_PTTKEYER, // PTT(Keyer): set PTT state to "on" or "off" MIDI_ACTION_PS, // PURESIGNAL: toggle PURESIGNAL on/off - MIDI_ACTION_MEM_RECALL_M0, // RECALLM0: load current freq/mode/filter from memory slot #0 - MIDI_ACTION_MEM_RECALL_M1, // RECALLM1: load current freq/mode/filter from memory slot #1 - MIDI_ACTION_MEM_RECALL_M2, // RECALLM2: load current freq/mode/filter from memory slot #2 - MIDI_ACTION_MEM_RECALL_M3, // RECALLM3: load current freq/mode/filter from memory slot #3 - MIDI_ACTION_MEM_RECALL_M4, // RECALLM4: load current freq/mode/filter from memory slot #4 MIDI_ACTION_RF_GAIN, // RFGAIN: receiver RF gain MIDI_ACTION_TX_DRIVE, // RFPOWER: adjust TX RF output power MIDI_ACTION_RIT_CLEAR, // RITCLEAR: clear RIT and XIT value @@ -122,6 +158,7 @@ enum MIDIaction { MIDI_ACTION_ZOOM, // ZOOM: change zoom factor MIDI_ACTION_ZOOM_UP, // ZOOMUP: change zoom factor MIDI_ACTION_ZOOM_DOWN, // ZOOMDOWN: change zoom factor + MIDI_ACTION_LAST, // flag for end of list }; // @@ -148,12 +185,15 @@ enum MIDIaction { // enum MIDItype { - MIDI_TYPE_NONE=0, - MIDI_TYPE_KEY, // Button (press event) - MIDI_TYPE_KNOB, // Knob (value between 0 and 100) - MIDI_TYPE_WHEEL // Wheel (direction and speed) + MIDI_TYPE_NONE =0, + MIDI_TYPE_KEY =1, // Button (press event) + MIDI_TYPE_KNOB =2, // Knob (value between 0 and 100) + MIDI_TYPE_WHEEL=4 // Wheel (direction and speed) }; +extern gchar *midi_types[]; +extern gchar *midi_events[]; + // // MIDIevent encodes the actual MIDI event "seen" in Layer-1 and // passed to Layer-2. MIDI_NOTE events end up as MIDI_KEY and @@ -167,6 +207,15 @@ enum MIDIevent { MIDI_EVENT_PITCH }; +typedef struct _action_table { + enum MIDIaction action; + const char *str; + enum MIDItype type; + int onoff; +} ACTION_TABLE; + +extern ACTION_TABLE ActionTable[]; + // // Data structure for Layer-2 // @@ -212,17 +261,18 @@ struct desc { struct desc *next; // Next defined action for a controller/key with that note value (NULL for end of list) }; -struct cmdtable{ - struct desc *desc[128]; // description for Note On/Off and ControllerChange - struct desc *pitch; // description for PitchChanges -}; +extern struct desc *MidiCommandsTable[129]; + +extern int midi_debug; // // Layer-1 entry point, called once for all the MIDI devices // that have been defined. This is called upon startup by // Layer-2 through the function MIDIstartup. // -void register_midi_device(char *name); +void register_midi_device(int index); +void close_midi_device(int index); +void configure_midi_device(gboolean state); // // Layer-2 entry point (called by Layer1) @@ -235,7 +285,9 @@ void register_midi_device(char *name); // for each device description that was successfully read. void NewMidiEvent(enum MIDIevent event, int channel, int note, int val); -void MIDIstartup(); +int MIDIstartup(char *filename); +void MidiAddCommand(int note, struct desc *desc); +void MidiReleaseCommands(); // // Layer-3 entry point (called by Layer2). In Layer-3, all the pihpsdr diff --git a/midi2.c b/midi2.c index 50c6743..7010074 100644 --- a/midi2.c +++ b/midi2.c @@ -8,6 +8,7 @@ */ #include + #include #include #include @@ -16,12 +17,17 @@ #include "MacOS.h" // emulate clock_gettime on old MacOS systems #endif +#include "receiver.h" +#include "discovered.h" +#include "adc.h" +#include "dac.h" +#include "transmitter.h" +#include "radio.h" +#include "main.h" #include "midi.h" +#include "alsa_midi.h" -static double midi_startup_time; -static int midi_wait_startup=0; - -struct cmdtable MidiCommandsTable; +struct desc *MidiCommandsTable[129]; void NewMidiEvent(enum MIDIevent event, int channel, int note, int val) { @@ -38,28 +44,14 @@ void NewMidiEvent(enum MIDIevent event, int channel, int note, int val) { //now=ts.tv_sec + 1E-9*ts.tv_nsec; //g_print("%s:%12.3f:EVENT=%d CHAN=%d NOTE=%d VAL=%d\n",__FUNCTION__,now,event,channel,note,val); - // - // the midi_wait_startup/midi_startup_time mechanism takes care that in the first - // second after registering a MIDI device, all incoming MIDI messages are just discarded. - // This has been introduced since sometimes "old" MIDI messages are lingering around in the - // the system and get delivered immediately after registering the MIDI device. - // The midi_wait_startup variable takes care that we do not check the clock again and again - // after the first second. - // - if (midi_wait_startup) { - clock_gettime(CLOCK_MONOTONIC, &ts); - now=ts.tv_sec + 1E-9*ts.tv_nsec; - if (now < midi_startup_time + 1.0) return; - midi_wait_startup=0; - } if (event == MIDI_EVENT_PITCH) { - desc=MidiCommandsTable.pitch; + desc=MidiCommandsTable[128]; } else { - desc=MidiCommandsTable.desc[note]; + desc=MidiCommandsTable[note]; } -//fprintf(stderr,"MIDI:init DESC=%p\n",desc); +//g_print("MIDI:init DESC=%p\n",desc); while (desc) { -//fprintf(stderr,"DESC=%p next=%p CHAN=%d EVENT=%d\n", desc,desc->next,desc->channel,desc->event); +//g_print("DESC=%p next=%p CHAN=%d EVENT=%d\n", desc,desc->next,desc->channel,desc->event); if ((desc->channel == channel || desc->channel == -1) && (desc->event == event)) { // Found matching entry switch (desc->event) { @@ -81,17 +73,17 @@ void NewMidiEvent(enum MIDIevent event, int channel, int note, int val) { if (delta < desc->delay) break; last_wheel_tp = tp; } - // translate value to direction + // translate value to direction/speed new=0; - if ((val >= desc->vfl1) && (val <= desc->vfl2)) new=-100; - if ((val >= desc-> fl1) && (val <= desc-> fl2)) new=-10; + if ((val >= desc->vfl1) && (val <= desc->vfl2)) new=-16; + if ((val >= desc-> fl1) && (val <= desc-> fl2)) new=-4; if ((val >= desc->lft1) && (val <= desc->lft2)) new=-1; if ((val >= desc->rgt1) && (val <= desc->rgt2)) new= 1; - if ((val >= desc-> fr1) && (val <= desc-> fr2)) new= 10; - if ((val >= desc->vfr1) && (val <= desc->vfr2)) new= 100; -// fprintf(stderr,"WHEEL: val=%d new=%d thrs=%d/%d, %d/%d, %d/%d, %d/%d, %d/%d, %d/%d\n", -// val, new, desc->vfl1, desc->vfl2, desc->fl1, desc->fl2, desc->lft1, desc->lft2, -// desc->rgt1, desc->rgt2, desc->fr1, desc->fr2, desc->vfr1, desc->vfr2); + if ((val >= desc-> fr1) && (val <= desc-> fr2)) new= 4; + if ((val >= desc->vfr1) && (val <= desc->vfr2)) new= 16; +// g_print("WHEEL: val=%d new=%d thrs=%d/%d, %d/%d, %d/%d, %d/%d, %d/%d, %d/%d\n", +// val, new, desc->vfl1, desc->vfl2, desc->fl1, desc->fl2, desc->lft1, desc->lft2, +// desc->rgt1, desc->rgt2, desc->fr1, desc->fr2, desc->vfr1, desc->vfr2); if (new != 0) DoTheMidi(desc->action, desc->type, new); last_wheel_action=desc->action; } @@ -113,101 +105,139 @@ void NewMidiEvent(enum MIDIevent event, int channel, int note, int val) { } if (!desc) { // Nothing found. This is nothing to worry about, but log the key to stderr - if (event == MIDI_EVENT_PITCH) fprintf(stderr, "Unassigned PitchBend Value=%d\n", val); - if (event == MIDI_EVENT_NOTE ) fprintf(stderr, "Unassigned Key Note=%d Val=%d\n", note, val); - if (event == MIDI_EVENT_CTRL ) fprintf(stderr, "Unassigned Controller Ctl=%d Val=%d\n", note, val); + if (event == MIDI_EVENT_PITCH) g_print("Unassigned PitchBend Value=%d\n", val); + if (event == MIDI_EVENT_NOTE ) g_print("Unassigned Key Note=%d Val=%d\n", note, val); + if (event == MIDI_EVENT_CTRL ) g_print("Unassigned Controller Ctl=%d Val=%d\n", note, val); } } +gchar *midi_types[] = {"NONE","KEY","KNOB/SLIDER","*INVALID*","WHEEL"}; +gchar *midi_events[] = {"NONE","NOTE","CTRL","PITCH"}; + /* * This data structre connects names as used in the midi.props file with * our MIDIaction enum values. - * Take care that no key word is contained in another one! - * Example: use "CURRVFO" not "VFO" otherwise there is possibly - * a match for "VFO" when the key word is "VFOA". + * + * At some places in the code, it is assumes that ActionTable[i].action == i + * so keep the entries strictly in the order the enum is defined, and + * add one entry with ACTION_NONE at the end. */ -static struct { - enum MIDIaction action; // the MIDI action - const char *str; // the key word in the midi.props file - int onoff; // =1 if action both on press + release -} ActionTable[] = { - { MIDI_ACTION_VFO_A2B, "A2B", 0}, - { MIDI_ACTION_AF_GAIN, "AFGAIN", 0}, - { MIDI_ACTION_AGCATTACK, "AGCATTACK", 0}, - { MIDI_ACTION_AGC, "AGCVAL", 0}, - { MIDI_ACTION_ANF, "ANF", 0}, - { MIDI_ACTION_ATT, "ATT", 0}, - { MIDI_ACTION_VFO_B2A, "B2A", 0}, - { MIDI_ACTION_BAND_DOWN, "BANDDOWN", 0}, - { MIDI_ACTION_BAND_UP, "BANDUP", 0}, - { MIDI_ACTION_COMPRESS, "COMPRESS", 0}, - { MIDI_ACTION_CTUN, "CTUN", 0}, - { MIDI_ACTION_VFO, "CURRVFO", 0}, - { MIDI_ACTION_CWKEY, "CWKEY", 1}, - { MIDI_ACTION_CWL, "CWL", 1}, - { MIDI_ACTION_CWR, "CWR", 1}, - { MIDI_ACTION_CWSPEED, "CWSPEED", 0}, - { MIDI_ACTION_DIV_COARSEGAIN, "DIVCOARSEGAIN", 0}, - { MIDI_ACTION_DIV_COARSEPHASE, "DIVCOARSEPHASE", 0}, - { MIDI_ACTION_DIV_FINEGAIN, "DIVFINEGAIN", 0}, - { MIDI_ACTION_DIV_FINEPHASE, "DIVFINEPHASE", 0}, - { MIDI_ACTION_DIV_GAIN, "DIVGAIN", 0}, - { MIDI_ACTION_DIV_PHASE, "DIVPHASE", 0}, - { MIDI_ACTION_DIV_TOGGLE, "DIVTOGGLE", 0}, - { MIDI_ACTION_DUP, "DUP", 0}, - { MIDI_ACTION_FILTER_DOWN, "FILTERDOWN", 0}, - { MIDI_ACTION_FILTER_UP, "FILTERUP", 0}, - { MIDI_ACTION_LOCK, "LOCK", 0}, - { MIDI_ACTION_MIC_VOLUME, "MICGAIN", 0}, - { MIDI_ACTION_MODE_DOWN, "MODEDOWN", 0}, - { MIDI_ACTION_MODE_UP, "MODEUP", 0}, - { MIDI_ACTION_MOX, "MOX", 0}, - { MIDI_ACTION_MUTE, "MUTE", 0}, - { MIDI_ACTION_NB, "NOISEBLANKER", 0}, - { MIDI_ACTION_NR, "NOISEREDUCTION", 0}, - { MIDI_ACTION_PAN, "PAN", 0}, - { MIDI_ACTION_PAN_HIGH, "PANHIGH", 0}, - { MIDI_ACTION_PAN_LOW, "PANLOW", 0}, - { MIDI_ACTION_PRE, "PREAMP", 0}, - { MIDI_ACTION_PTTONOFF, "PTT", 1}, - { MIDI_ACTION_PS, "PURESIGNAL", 0}, - { MIDI_ACTION_MEM_RECALL_M0, "RECALLM0", 0}, - { MIDI_ACTION_MEM_RECALL_M1, "RECALLM1", 0}, - { MIDI_ACTION_MEM_RECALL_M2, "RECALLM2", 0}, - { MIDI_ACTION_MEM_RECALL_M3, "RECALLM3", 0}, - { MIDI_ACTION_MEM_RECALL_M4, "RECALLM4", 0}, - { MIDI_ACTION_RF_GAIN, "RFGAIN", 0}, - { MIDI_ACTION_TX_DRIVE, "RFPOWER", 0}, - { MIDI_ACTION_RIT_CLEAR, "RITCLEAR", 0}, - { MIDI_ACTION_RIT_STEP, "RITSTEP", 0}, - { MIDI_ACTION_RIT_TOGGLE, "RITTOGGLE", 0}, - { MIDI_ACTION_RIT_VAL, "RITVAL", 0}, - { MIDI_ACTION_SAT, "SAT", 0}, - { MIDI_ACTION_SNB, "SNB", 0}, - { MIDI_ACTION_SPLIT, "SPLIT", 0}, - { MIDI_ACTION_MEM_STORE_M0, "STOREM0", 0}, - { MIDI_ACTION_MEM_STORE_M1, "STOREM1", 0}, - { MIDI_ACTION_MEM_STORE_M2, "STOREM2", 0}, - { MIDI_ACTION_MEM_STORE_M3, "STOREM3", 0}, - { MIDI_ACTION_MEM_STORE_M4, "STOREM4", 0}, - { MIDI_ACTION_SWAP_RX, "SWAPRX", 0}, - { MIDI_ACTION_SWAP_VFO, "SWAPVFO", 0}, - { MIDI_ACTION_TUNE, "TUNE", 0}, - { MIDI_ACTION_VFOA, "VFOA", 0}, - { MIDI_ACTION_VFOB, "VFOB", 0}, - { MIDI_ACTION_VFO_STEP_UP, "VFOSTEPUP", 0}, - { MIDI_ACTION_VFO_STEP_DOWN, "VFOSTEPDOWN", 0}, - { MIDI_ACTION_VOX, "VOX", 0}, - { MIDI_ACTION_VOXLEVEL, "VOXLEVEL", 0}, - { MIDI_ACTION_XIT_CLEAR, "XITCLEAR", 0}, - { MIDI_ACTION_XIT_VAL, "XITVAL", 0}, - { MIDI_ACTION_ZOOM, "ZOOM", 0}, - { MIDI_ACTION_ZOOM_UP, "ZOOMUP", 0}, - { MIDI_ACTION_ZOOM_DOWN, "ZOOMDOWN", 0}, - { MIDI_ACTION_NONE, "NONE", 0} +ACTION_TABLE ActionTable[] = { + { MIDI_ACTION_NONE, "NONE", MIDI_TYPE_KEY|MIDI_TYPE_KNOB|MIDI_TYPE_WHEEL, 0}, + { MIDI_ACTION_VFO_A2B, "A2B", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_AF_GAIN, "AFGAIN", MIDI_TYPE_KNOB|MIDI_TYPE_WHEEL, 0}, + { MIDI_ACTION_AGCATTACK, "AGCATTACK", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_AGC, "AGCVAL", MIDI_TYPE_KNOB|MIDI_TYPE_WHEEL, 0}, + { MIDI_ACTION_ANF, "ANF", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_ATT, "ATT", MIDI_TYPE_KEY|MIDI_TYPE_KNOB|MIDI_TYPE_WHEEL, 0}, + { MIDI_ACTION_VFO_B2A, "B2A", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_BAND_10, "BAND10", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_BAND_12, "BAND12", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_BAND_1240, "BAND1240", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_BAND_144, "BAND144", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_BAND_15, "BAND15", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_BAND_160, "BAND160", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_BAND_17, "BAND17", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_BAND_20, "BAND20", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_BAND_220, "BAND220", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_BAND_2300, "BAND2300", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_BAND_30, "BAND30", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_BAND_3400, "BAND3400", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_BAND_40, "BAND40", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_BAND_430, "BAND430", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_BAND_6, "BAND6", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_BAND_60, "BAND60", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_BAND_70, "BAND70", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_BAND_80, "BAND80", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_BAND_902, "BAND902", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_BAND_AIR, "BANDAIR", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_BAND_DOWN, "BANDDOWN", MIDI_TYPE_KEY|MIDI_TYPE_KNOB|MIDI_TYPE_WHEEL, 0}, + { MIDI_ACTION_BAND_GEN, "BANDGEN", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_BAND_UP, "BANDUP", MIDI_TYPE_KEY|MIDI_TYPE_KNOB|MIDI_TYPE_WHEEL, 0}, + { MIDI_ACTION_BAND_WWV, "BANDWWV", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_COMPRESS, "COMPRESS", MIDI_TYPE_KNOB|MIDI_TYPE_WHEEL, 0}, + { MIDI_ACTION_CTUN, "CTUN", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_VFO, "CURRVFO", MIDI_TYPE_WHEEL, 0}, + { MIDI_ACTION_CWKEYER, "CW(Keyer)", MIDI_TYPE_KEY, 1}, + { MIDI_ACTION_CWLEFT, "CWLEFT", MIDI_TYPE_KEY, 1}, + { MIDI_ACTION_CWRIGHT, "CWRIGHT", MIDI_TYPE_KEY, 1}, + { MIDI_ACTION_CWSPEED, "CWSPEED", MIDI_TYPE_KNOB|MIDI_TYPE_WHEEL, 0}, + { MIDI_ACTION_DIV_COARSEGAIN, "DIVCOARSEGAIN", MIDI_TYPE_KNOB|MIDI_TYPE_WHEEL, 0}, + { MIDI_ACTION_DIV_COARSEPHASE, "DIVCOARSEPHASE", MIDI_TYPE_KNOB|MIDI_TYPE_WHEEL, 0}, + { MIDI_ACTION_DIV_FINEGAIN, "DIVFINEGAIN", MIDI_TYPE_KNOB|MIDI_TYPE_WHEEL, 0}, + { MIDI_ACTION_DIV_FINEPHASE, "DIVFINEPHASE", MIDI_TYPE_KNOB|MIDI_TYPE_WHEEL, 0}, + { MIDI_ACTION_DIV_GAIN, "DIVGAIN", MIDI_TYPE_KNOB|MIDI_TYPE_WHEEL, 0}, + { MIDI_ACTION_DIV_PHASE, "DIVPHASE", MIDI_TYPE_KNOB|MIDI_TYPE_WHEEL, 0}, + { MIDI_ACTION_DIV_TOGGLE, "DIVTOGGLE", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_DUP, "DUP", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_FILTER_DOWN, "FILTERDOWN", MIDI_TYPE_KEY|MIDI_TYPE_KNOB|MIDI_TYPE_WHEEL, 0}, + { MIDI_ACTION_FILTER_UP, "FILTERUP", MIDI_TYPE_KEY|MIDI_TYPE_KNOB|MIDI_TYPE_WHEEL, 0}, + { MIDI_ACTION_LOCK, "LOCK", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_MEM_RECALL_M0, "RECALLM0", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_MEM_RECALL_M1, "RECALLM1", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_MEM_RECALL_M2, "RECALLM2", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_MEM_RECALL_M3, "RECALLM3", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_MEM_RECALL_M4, "RECALLM4", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_MENU_FILTER, "MENU_FILTER", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_MENU_MODE, "MENU_MODE", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_MIC_VOLUME, "MICGAIN", MIDI_TYPE_KNOB|MIDI_TYPE_WHEEL, 0}, + { MIDI_ACTION_MODE_DOWN, "MODEDOWN", MIDI_TYPE_KEY|MIDI_TYPE_KNOB|MIDI_TYPE_WHEEL, 0}, + { MIDI_ACTION_MODE_UP, "MODEUP", MIDI_TYPE_KEY|MIDI_TYPE_KNOB|MIDI_TYPE_WHEEL, 0}, + { MIDI_ACTION_MOX, "MOX", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_MUTE, "MUTE", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_NB, "NOISEBLANKER", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_NR, "NOISEREDUCTION", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_NUMPAD_0, "NUMPAD0", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_NUMPAD_1, "NUMPAD1", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_NUMPAD_2, "NUMPAD2", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_NUMPAD_3, "NUMPAD3", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_NUMPAD_4, "NUMPAD4", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_NUMPAD_5, "NUMPAD5", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_NUMPAD_6, "NUMPAD6", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_NUMPAD_7, "NUMPAD7", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_NUMPAD_8, "NUMPAD8", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_NUMPAD_9, "NUMPAD9", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_NUMPAD_CL, "NUMPADCL", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_NUMPAD_ENTER, "NUMPADENTER", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_PAN, "PAN", MIDI_TYPE_KNOB|MIDI_TYPE_WHEEL, 0}, + { MIDI_ACTION_PAN_HIGH, "PANHIGH", MIDI_TYPE_KNOB|MIDI_TYPE_WHEEL, 0}, + { MIDI_ACTION_PAN_LOW, "PANLOW", MIDI_TYPE_KNOB|MIDI_TYPE_WHEEL, 0}, + { MIDI_ACTION_PRE, "PREAMP", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_PTTKEYER, "PTT(Keyer)", MIDI_TYPE_KEY, 1}, + { MIDI_ACTION_PS, "PURESIGNAL", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_RF_GAIN, "RFGAIN", MIDI_TYPE_KNOB|MIDI_TYPE_WHEEL, 0}, + { MIDI_ACTION_TX_DRIVE, "RFPOWER", MIDI_TYPE_KNOB|MIDI_TYPE_WHEEL, 0}, + { MIDI_ACTION_RIT_CLEAR, "RITCLEAR", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_RIT_STEP, "RITSTEP", MIDI_TYPE_KEY|MIDI_TYPE_WHEEL, 0}, + { MIDI_ACTION_RIT_TOGGLE, "RITTOGGLE", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_RIT_VAL, "RITVAL", MIDI_TYPE_KNOB|MIDI_TYPE_WHEEL, 0}, + { MIDI_ACTION_SAT, "SAT", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_SNB, "SNB", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_SPLIT, "SPLIT", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_MEM_STORE_M0, "STOREM0", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_MEM_STORE_M1, "STOREM1", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_MEM_STORE_M2, "STOREM2", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_MEM_STORE_M3, "STOREM3", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_MEM_STORE_M4, "STOREM4", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_SWAP_RX, "SWAPRX", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_SWAP_VFO, "SWAPVFO", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_TUNE, "TUNE", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_VFOA, "VFOA", MIDI_TYPE_WHEEL, 0}, + { MIDI_ACTION_VFOB, "VFOB", MIDI_TYPE_WHEEL, 0}, + { MIDI_ACTION_VFO_STEP_UP, "VFOSTEPUP", MIDI_TYPE_KEY|MIDI_TYPE_WHEEL, 0}, + { MIDI_ACTION_VFO_STEP_DOWN, "VFOSTEPDOWN", MIDI_TYPE_KEY|MIDI_TYPE_WHEEL, 0}, + { MIDI_ACTION_VOX, "VOX", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_VOXLEVEL, "VOXLEVEL", MIDI_TYPE_KNOB|MIDI_TYPE_WHEEL, 0}, + { MIDI_ACTION_XIT_CLEAR, "XITCLEAR", MIDI_TYPE_KEY, 0}, + { MIDI_ACTION_XIT_VAL, "XITVAL", MIDI_TYPE_KNOB|MIDI_TYPE_WHEEL, 0}, + { MIDI_ACTION_ZOOM, "ZOOM", MIDI_TYPE_KNOB|MIDI_TYPE_WHEEL, 0}, + { MIDI_ACTION_ZOOM_UP, "ZOOMUP", MIDI_TYPE_KEY|MIDI_TYPE_WHEEL, 0}, + { MIDI_ACTION_ZOOM_DOWN, "ZOOMDOWN", MIDI_TYPE_KEY|MIDI_TYPE_WHEEL, 0}, + { MIDI_ACTION_LAST, "NONE", MIDI_TYPE_NONE, 0}, }; + /* * Translation from keyword in midi.props file to MIDIaction */ @@ -227,12 +257,68 @@ static void keyword2action(char *s, enum MIDIaction *action, int *onoff) { *onoff = 0; } +int MIDIstop() { + for (int i=0; inext; + free(loop); + loop = new; + } + MidiCommandsTable[i]=NULL; + } +} + +/* + * Add a command to MidiCommandsTable + */ + +void MidiAddCommand(int note, struct desc *desc) { + struct desc *loop; + + if (note < 0 || note > 128) return; + + // + // Actions with channel == -1 (ANY) must go to the end of the list + // + if (MidiCommandsTable[note] == NULL) { + // initialize linked list + MidiCommandsTable[note]=desc; + } else if (desc->channel >= 0) { + // add to top of the list + desc->next = MidiCommandsTable[note]; + MidiCommandsTable[note]=desc; + } else { + // add to tail of the list + loop = MidiCommandsTable[note]; + while (loop->next != NULL) { + loop = loop->next; + } + loop->next=desc; + } +} + +/* + * Here we read in a MIDI description file and fill the MidiCommandsTable * data structure */ -void MIDIstartup() { +int MIDIstartup(char *filename) { FILE *fpin; char zeile[255]; char *cp,*cq; @@ -246,13 +332,17 @@ void MIDIstartup() { enum MIDIevent event; int i; char c; - struct timespec ts; - for (i=0; i<128; i++) MidiCommandsTable.desc[i]=NULL; - MidiCommandsTable.pitch=NULL; + MidiReleaseCommands(); - fpin=fopen("midi.props", "r"); - if (!fpin) return; + g_print("%s: %s\n",__FUNCTION__,filename); + fpin=fopen(filename, "r"); + + g_print("%s: fpin=%p\n",__FUNCTION__,fpin); + if (!fpin) { + g_print("%s: failed to open MIDI device\n",__FUNCTION__); + return -1; + } for (;;) { if (fgets(zeile, 255, fpin) == NULL) break; @@ -277,30 +367,16 @@ void MIDIstartup() { cp++; } -//fprintf(stderr,"\nMIDI:INP:%s\n",zeile); - - if ((cp = strstr(zeile, "DEVICE="))) { - // Delete comments and trailing blanks - cq=cp+7; - while (*cq != 0 && *cq != '#') cq++; - *cq--=0; - while (cq > cp+7 && (*cq == ' ' || *cq == '\t')) cq--; - *(cq+1)=0; -//fprintf(stderr,"MIDI:REG:>>>%s<<<\n",cp+7); - midi_wait_startup=1; - clock_gettime(CLOCK_MONOTONIC, &ts); - midi_startup_time=ts.tv_sec + 1E-9*ts.tv_nsec; - register_midi_device(cp+7); - continue; // nothing more in this line - } +g_print("\n%s:INP:%s\n",__FUNCTION__,zeile); + chan=-1; // default: any channel t1=t3=t5=t7= t9=t11=128; // range that never occurs t2=t4=t6=t8=t10=t12=-1; // range that never occurs + onoff=0; event=MIDI_EVENT_NONE; type=MIDI_TYPE_NONE; key=0; delay=0; - onoff=0; // // The KEY=, CTRL=, and PITCH= cases are mutually exclusive @@ -311,18 +387,18 @@ void MIDIstartup() { sscanf(cp+4, "%d", &key); event=MIDI_EVENT_NOTE; type=MIDI_TYPE_KEY; -//fprintf(stderr,"MIDI:KEY:%d\n", key); +g_print("%s: MIDI:KEY:%d\n",__FUNCTION__, key); } if ((cp = strstr(zeile, "CTRL="))) { sscanf(cp+5, "%d", &key); event=MIDI_EVENT_CTRL; type=MIDI_TYPE_KNOB; -//fprintf(stderr,"MIDI:CTL:%d\n", key); +g_print("%s: MIDI:CTL:%d\n",__FUNCTION__, key); } if ((cp = strstr(zeile, "PITCH "))) { event=MIDI_EVENT_PITCH; type=MIDI_TYPE_KNOB; -//fprintf(stderr,"MIDI:PITCH\n"); +g_print("%s: MIDI:PITCH\n",__FUNCTION__); } // // If event is still undefined, skip line @@ -342,16 +418,16 @@ void MIDIstartup() { sscanf(cp+5, "%d", &chan); chan--; if (chan<0 || chan>15) chan=-1; -//fprintf(stderr,"MIDI:CHA:%d\n",chan); +g_print("%s:CHAN:%d\n",__FUNCTION__,chan); } if ((cp = strstr(zeile, "WHEEL")) && (type == MIDI_TYPE_KNOB)) { // change type from MIDI_TYPE_KNOB to MIDI_TYPE_WHEEL type=MIDI_TYPE_WHEEL; -//fprintf(stderr,"MIDI:WHEEL\n"); +g_print("%s:WHEEL\n",__FUNCTION__); } if ((cp = strstr(zeile, "DELAY="))) { sscanf(cp+6, "%d", &delay); -//fprintf(stderr,"MIDI:DELAY:%d\n",delay); +g_print("%s:DELAY:%d\n",__FUNCTION__,delay); } if ((cp = strstr(zeile, "THR="))) { sscanf(cp+4, "%d %d %d %d %d %d %d %d %d %d %d %d", @@ -364,7 +440,7 @@ void MIDIstartup() { while (*cq != 0 && *cq != '\n' && *cq != ' ' && *cq != '\t') cq++; *cq=0; keyword2action(cp+7, &action, &onoff); -//fprintf(stderr,"MIDI:ACTION:%s (%d), onoff=%d\n",cp+7, action, onoff); +g_print("MIDI:ACTION:%s (%d), onoff=%d\n",cp+7, action, onoff); } // // All data for a descriptor has been read. Construct it! @@ -395,23 +471,12 @@ void MIDIstartup() { // if (event == MIDI_EVENT_PITCH) { //fprintf(stderr,"MIDI:TAB:Insert desc=%p in PITCH table\n",desc); - dp = MidiCommandsTable.pitch; - if (dp == NULL) { - MidiCommandsTable.pitch = desc; - } else { - while (dp->next != NULL) dp=dp->next; - dp->next=desc; - } + MidiAddCommand(129, desc); } if (event == MIDI_EVENT_NOTE || event == MIDI_EVENT_CTRL) { -//fprintf(stderr,"MIDI:TAB:Insert desc=%p in CMDS[%d] table\n",desc,key); - dp = MidiCommandsTable.desc[key]; - if (dp == NULL) { - MidiCommandsTable.desc[key]=desc; - } else { - while (dp->next != NULL) dp=dp->next; - dp->next=desc; - } +g_print("%s:TAB:Insert desc=%p in CMDS[%d] table\n",__FUNCTION__,desc,key); + MidiAddCommand(key, desc); } } + return 0; } diff --git a/midi3.c b/midi3.c index 38ea44a..3fc1b05 100644 --- a/midi3.c +++ b/midi3.c @@ -39,7 +39,7 @@ // code below, one can queue the "big switch statement" into the GTK // idle queue and exectue all GUI functions directly. // -// However, this is not wanted for CWKEY, CWL and CWR since +// However, this is not wanted for CWKEYER, CWLEFT and CWRIGHT since // these have to be processed with minimal delay (and do not call GUI functions). // // Therefore, these three cases are already handled in the MIDI callback @@ -61,7 +61,7 @@ typedef struct _MIDIcmd MIDIcmd; static int DoTheRestOfTheMIDI(void *data); void DoTheMidi(enum MIDIaction action, enum MIDItype type, int val) { - if (action == MIDI_ACTION_CWKEY) { + if (action == MIDI_ACTION_CWKEYER) { // // This is a CW key-up/down which uses functions from the keyer // that by-pass the interrupt-driven standard action. @@ -70,7 +70,8 @@ void DoTheMidi(enum MIDIaction action, enum MIDItype type, int val) { // MIDI using this command. // // NO BREAK-IN! The keyer has to take care of sending MIDI PTT - // on/off messages at appropriate times. + // on/off messages at appropriate times, or the operator has to + // manually engage/disengage PTT // // Since this if for immediate key-down, it does not rely on LOCALCW // @@ -85,11 +86,11 @@ void DoTheMidi(enum MIDIaction action, enum MIDItype type, int val) { return; } #ifdef LOCALCW - if (action == MIDI_ACTION_CWL) { + if (action == MIDI_ACTION_CWLEFT) { keyer_event(1, val); return; } - if (action == MIDI_ACTION_CWR) { + if (action == MIDI_ACTION_CWRIGHT) { keyer_event(0, val); return; } @@ -109,6 +110,7 @@ int DoTheRestOfTheMIDI(void *data) { MIDIcmd *cmd = (MIDIcmd *)data; int new; + int id, c25; double dnew; enum MIDIaction action = cmd->action; @@ -123,9 +125,7 @@ int DoTheRestOfTheMIDI(void *data) { switch (action) { /////////////////////////////////////////////////////////// "A2B" case MIDI_ACTION_VFO_A2B: // only key supported - if (type == MIDI_TYPE_KEY) { - vfo_a_to_b(); - } + vfo_a_to_b(); break; /////////////////////////////////////////////////////////// "AFGAIN" case MIDI_ACTION_AF_GAIN: // knob or wheel supported @@ -148,12 +148,10 @@ int DoTheRestOfTheMIDI(void *data) { /////////////////////////////////////////////////////////// "AGCATTACK" case MIDI_ACTION_AGCATTACK: // only key supported // cycle through fast/med/slow AGC attack - if (type == MIDI_TYPE_KEY) { - new=active_receiver->agc + 1; - if (new > AGC_FAST) new=0; - active_receiver->agc=new; - vfo_update(); - } + new=active_receiver->agc + 1; + if (new > AGC_FAST) new=0; + active_receiver->agc=new; + vfo_update(); break; /////////////////////////////////////////////////////////// "AGCVAL" case MIDI_ACTION_AGC: // knob or wheel supported @@ -176,17 +174,15 @@ int DoTheRestOfTheMIDI(void *data) { break; /////////////////////////////////////////////////////////// "ANF" case MIDI_ACTION_ANF: // only key supported - if (type == MIDI_TYPE_KEY) { - if (active_receiver->anf==0) { - active_receiver->anf=1; - mode_settings[vfo[active_receiver->id].mode].anf=1; - } else { - active_receiver->snb=0; - mode_settings[vfo[active_receiver->id].mode].anf=0; - } - SetRXAANFRun(active_receiver->id, active_receiver->anf); - vfo_update(); - } + if (active_receiver->anf==0) { + active_receiver->anf=1; + mode_settings[vfo[active_receiver->id].mode].anf=1; + } else { + active_receiver->snb=0; + mode_settings[vfo[active_receiver->id].mode].anf=0; + } + SetRXAANFRun(active_receiver->id, active_receiver->anf); + vfo_update(); break; /////////////////////////////////////////////////////////// "ATT" case MIDI_ACTION_ATT: // Key for ALEX attenuator, wheel or knob for slider @@ -232,10 +228,87 @@ int DoTheRestOfTheMIDI(void *data) { break; /////////////////////////////////////////////////////////// "B2A" case MIDI_ACTION_VFO_B2A: // only key supported - if (type == MIDI_TYPE_KEY) { - vfo_b_to_a(); - } + vfo_b_to_a(); break; + /////////////////////////////////////////////////////////// "BANDxxx" + case MIDI_ACTION_BAND_10: + vfo_band_changed(active_receiver->id, band10); + break; + case MIDI_ACTION_BAND_12: + vfo_band_changed(active_receiver->id, band12); + break; +#ifdef SOAPYSDR + case MIDI_ACTION_BAND_1240: + vfo_band_changed(active_receiver->id, band1240); + break; + case MIDI_ACTION_BAND_144: + vfo_band_changed(active_receiver->id, band144); + break; +#endif + case MIDI_ACTION_BAND_15: + vfo_band_changed(active_receiver->id, band15); + break; + case MIDI_ACTION_BAND_160: + vfo_band_changed(active_receiver->id, band160); + break; + case MIDI_ACTION_BAND_17: + vfo_band_changed(active_receiver->id, band17); + break; + case MIDI_ACTION_BAND_20: + vfo_band_changed(active_receiver->id, band20); + break; +#ifdef SOAPYSDR + case MIDI_ACTION_BAND_220: + vfo_band_changed(active_receiver->id, band220); + break; + case MIDI_ACTION_BAND_2300: + vfo_band_changed(active_receiver->id, band2300); + break; +#endif + case MIDI_ACTION_BAND_30: + vfo_band_changed(active_receiver->id, band30); + break; +#ifdef SOAPYSDR + case MIDI_ACTION_BAND_3400: + vfo_band_changed(active_receiver->id, band3400); + break; +#endif + case MIDI_ACTION_BAND_40: + vfo_band_changed(active_receiver->id, band40); + break; +#ifdef SOAPYSDR + case MIDI_ACTION_BAND_430: + vfo_band_changed(active_receiver->id, band430); + break; +#endif + case MIDI_ACTION_BAND_6: + vfo_band_changed(active_receiver->id, band6); + break; + case MIDI_ACTION_BAND_60: + vfo_band_changed(active_receiver->id, band60); + break; +#ifdef SOAPYSDR + case MIDI_ACTION_BAND_70: + vfo_band_changed(active_receiver->id, band70); + break; +#endif + case MIDI_ACTION_BAND_80: + vfo_band_changed(active_receiver->id, band80); + break; +#ifdef SOAPYSDR + case MIDI_ACTION_BAND_902: + vfo_band_changed(active_receiver->id, band902); + break; + case MIDI_ACTION_BAND_AIR: + vfo_band_changed(active_receiver->id, bandAIR); + break; +#endif + case MIDI_ACTION_BAND_GEN: + vfo_band_changed(active_receiver->id, bandGen); + break; + case MIDI_ACTION_BAND_WWV: + vfo_band_changed(active_receiver->id, bandWWV); + break; /////////////////////////////////////////////////////////// "BANDDOWN" /////////////////////////////////////////////////////////// "BANDUP" case MIDI_ACTION_BAND_DOWN: @@ -296,21 +369,17 @@ int DoTheRestOfTheMIDI(void *data) { /////////////////////////////////////////////////////////// "CTUN" case MIDI_ACTION_CTUN: // only key supported // toggle CTUN - if (type == MIDI_TYPE_KEY) { - int id=active_receiver->id; - vfo[id].ctun=vfo[id].ctun==1?0:1; - if(!vfo[id].ctun) { - vfo[id].offset=0; - } - vfo[id].ctun_frequency=vfo[id].frequency; - set_offset(receiver[id],vfo[id].offset); - } + id=active_receiver->id; + vfo[id].ctun=vfo[id].ctun==1?0:1; + if(!vfo[id].ctun) { + vfo[id].offset=0; + } + vfo[id].ctun_frequency=vfo[id].frequency; + set_offset(receiver[id],vfo[id].offset); break; /////////////////////////////////////////////////////////// "CURRVFO" case MIDI_ACTION_VFO: // only wheel supported - if (type == MIDI_TYPE_WHEEL && !locked) { - vfo_step(val); - } + vfo_step(val); break; /////////////////////////////////////////////////////////// "CWSPEED" case MIDI_ACTION_CWSPEED: // knob or wheel @@ -408,11 +477,9 @@ int DoTheRestOfTheMIDI(void *data) { break; /////////////////////////////////////////////////////////// "DIVTOGGLE" case MIDI_ACTION_DIV_TOGGLE: // only key supported - if (type == MIDI_TYPE_KEY) { - // enable/disable DIVERSITY - diversity_enabled = diversity_enabled ? 0 : 1; - vfo_update(); - } + // enable/disable DIVERSITY + diversity_enabled = diversity_enabled ? 0 : 1; + vfo_update(); break; /////////////////////////////////////////////////////////// "DUP" case MIDI_ACTION_DUP: @@ -453,12 +520,18 @@ int DoTheRestOfTheMIDI(void *data) { vfo_filter_changed(new); } break; + /////////////////////////////////////////////////////////// "MENU_FILTER" + case MIDI_ACTION_MENU_FILTER: + start_filter(); + break; + /////////////////////////////////////////////////////////// "MENU_MODE" + case MIDI_ACTION_MENU_MODE: + start_mode(); + break; /////////////////////////////////////////////////////////// "LOCK" case MIDI_ACTION_LOCK: // only key supported - if (type == MIDI_TYPE_KEY) { - locked=!locked; - vfo_update(); - } + locked=!locked; + vfo_update(); break; /////////////////////////////////////////////////////////// "MICGAIN" case MIDI_ACTION_MIC_VOLUME: // knob or wheel supported @@ -511,54 +584,86 @@ int DoTheRestOfTheMIDI(void *data) { /////////////////////////////////////////////////////////// "MOX" case MIDI_ACTION_MOX: // only key supported // Note this toggles the PTT state without knowing the - // actual state. See MIDI_ACTION_PTTONOFF for actually + // actual state. See MIDI_ACTION_PTTKEYER for actually // *setting* PTT - if (type == MIDI_TYPE_KEY && can_transmit) { + if (can_transmit) { new = !mox; mox_update(new); } break; /////////////////////////////////////////////////////////// "MUTE" case MIDI_ACTION_MUTE: - if (type == MIDI_TYPE_KEY) { - active_receiver->mute_radio=!active_receiver->mute_radio; - } + active_receiver->mute_radio=!active_receiver->mute_radio; break; /////////////////////////////////////////////////////////// "NOISEBLANKER" case MIDI_ACTION_NB: // only key supported // cycle through NoiseBlanker settings: OFF, NB, NB2 - if (type == MIDI_TYPE_KEY) { - if (active_receiver->nb) { - active_receiver->nb = 0; - active_receiver->nb2= 1; - } else if (active_receiver->nb2) { - active_receiver->nb = 0; - active_receiver->nb2= 0; - } else { - active_receiver->nb = 1; - active_receiver->nb2= 0; - } - vfo_update(); + if (active_receiver->nb) { + active_receiver->nb = 0; + active_receiver->nb2= 1; + } else if (active_receiver->nb2) { + active_receiver->nb = 0; + active_receiver->nb2= 0; + } else { + active_receiver->nb = 1; + active_receiver->nb2= 0; } + update_noise(); + vfo_update(); break; /////////////////////////////////////////////////////////// "NOISEREDUCTION" case MIDI_ACTION_NR: // only key supported // cycle through NoiseReduction settings: OFF, NR1, NR2 - if (type == MIDI_TYPE_KEY) { - if (active_receiver->nr) { - active_receiver->nr = 0; - active_receiver->nr2= 1; - } else if (active_receiver->nr2) { - active_receiver->nr = 0; - active_receiver->nr2= 0; - } else { - active_receiver->nr = 1; - active_receiver->nr2= 0; - } - update_noise(); - vfo_update(); + if (active_receiver->nr) { + active_receiver->nr = 0; + active_receiver->nr2= 1; + } else if (active_receiver->nr2) { + active_receiver->nr = 0; + active_receiver->nr2= 0; + } else { + active_receiver->nr = 1; + active_receiver->nr2= 0; } + update_noise(); + vfo_update(); break; + /////////////////////////////////////////////////////////// "NUMPADxx" + case MIDI_ACTION_NUMPAD_0: + num_pad(0); + break; + case MIDI_ACTION_NUMPAD_1: + num_pad(1); + break; + case MIDI_ACTION_NUMPAD_2: + num_pad(2); + break; + case MIDI_ACTION_NUMPAD_3: + num_pad(3); + break; + case MIDI_ACTION_NUMPAD_4: + num_pad(4); + break; + case MIDI_ACTION_NUMPAD_5: + num_pad(5); + break; + case MIDI_ACTION_NUMPAD_6: + num_pad(6); + break; + case MIDI_ACTION_NUMPAD_7: + num_pad(7); + break; + case MIDI_ACTION_NUMPAD_8: + num_pad(9); + break; + case MIDI_ACTION_NUMPAD_9: + num_pad(9); + break; + case MIDI_ACTION_NUMPAD_CL: + num_pad(-1); + break; + case MIDI_ACTION_NUMPAD_ENTER: + num_pad(-2); + break; /////////////////////////////////////////////////////////// "PAN" case MIDI_ACTION_PAN: // wheel and knob switch (type) { @@ -635,41 +740,39 @@ int DoTheRestOfTheMIDI(void *data) { break; /////////////////////////////////////////////////////////// "PREAMP" case MIDI_ACTION_PRE: // only key supported - if (type == MIDI_TYPE_KEY) { - // - // Normally on/off, but for CHARLY25, cycle through three - // possible states. Current HPSDR hardware does no have - // switch'able preamps. - // - int c25= (filter_board == CHARLY25); - new = active_receiver->preamp + active_receiver->dither; - new++; - if (c25) { - if (new >2) new=0; - } else { - if (new >1) new=0; - } - switch (new) { - case 0: - active_receiver->preamp=0; - if (c25) active_receiver->dither=0; - break; - case 1: - active_receiver->preamp=1; - if (c25) active_receiver->dither=0; - break; - case 2: - active_receiver->preamp=1; - if (c25) active_receiver->dither=1; - break; - } - update_att_preamp(); + // + // Normally on/off, but for CHARLY25, cycle through three + // possible states. Current HPSDR hardware does no have + // switch'able preamps. + // + c25= (filter_board == CHARLY25); + new = active_receiver->preamp + active_receiver->dither; + new++; + if (c25) { + if (new >2) new=0; + } else { + if (new >1) new=0; + } + switch (new) { + case 0: + active_receiver->preamp=0; + if (c25) active_receiver->dither=0; + break; + case 1: + active_receiver->preamp=1; + if (c25) active_receiver->dither=0; + break; + case 2: + active_receiver->preamp=1; + if (c25) active_receiver->dither=1; + break; } + update_att_preamp(); break; - /////////////////////////////////////////////////////////// "PTTONOFF" - case MIDI_ACTION_PTTONOFF: // key only + /////////////////////////////////////////////////////////// "PTT(Keyer)" + case MIDI_ACTION_PTTKEYER: // key only // always use with "ONOFF" - if (type == MIDI_TYPE_KEY && can_transmit) { + if (can_transmit) { mox_update(val); } break; @@ -677,27 +780,27 @@ int DoTheRestOfTheMIDI(void *data) { case MIDI_ACTION_PS: // only key supported #ifdef PURESIGNAL // toggle PURESIGNAL - if (type == MIDI_TYPE_KEY) { - if (can_transmit) { - new=!(transmitter->puresignal); - tx_set_ps(transmitter, new); - } - } + if (can_transmit) { + new=!(transmitter->puresignal); + tx_set_ps(transmitter, new); + } #endif break; - /////////////////////////////////////////////////////////// "RECALLM[0-4]" + /////////////////////////////////////////////////////////// "RECALLMx" case MIDI_ACTION_MEM_RECALL_M0: + recall_memory_slot(0); + break; case MIDI_ACTION_MEM_RECALL_M1: + recall_memory_slot(1); + break; case MIDI_ACTION_MEM_RECALL_M2: + recall_memory_slot(2); + break; case MIDI_ACTION_MEM_RECALL_M3: + recall_memory_slot(3); + break; case MIDI_ACTION_MEM_RECALL_M4: - // - // only key supported - // - if (type == MIDI_TYPE_KEY) { - new = action - MIDI_ACTION_MEM_RECALL_M0; - recall_memory_slot(new); - } + recall_memory_slot(4); break; /////////////////////////////////////////////////////////// "RFGAIN" case MIDI_ACTION_RF_GAIN: // knob or wheel supported @@ -730,11 +833,10 @@ int DoTheRestOfTheMIDI(void *data) { break; /////////////////////////////////////////////////////////// "RITCLEAR" case MIDI_ACTION_RIT_CLEAR: // only key supported - if (type == MIDI_TYPE_KEY) { - // clear RIT value - vfo[active_receiver->id].rit = new; - vfo_update(); - } + // clear RIT value + vfo[active_receiver->id].rit = new; + vfo_update(); + break; /////////////////////////////////////////////////////////// "RITSTEP" case MIDI_ACTION_RIT_STEP: // key or wheel supported // This cycles between RIT increments 1, 10, 100, 1, 10, 100, ... @@ -761,12 +863,10 @@ int DoTheRestOfTheMIDI(void *data) { break; /////////////////////////////////////////////////////////// "RITTOGGLE" case MIDI_ACTION_RIT_TOGGLE: // only key supported - if (type == MIDI_TYPE_KEY) { - // enable/disable RIT - new=vfo[active_receiver->id].rit_enabled; - vfo[active_receiver->id].rit_enabled = new ? 0 : 1; - vfo_update(); - } + // enable/disable RIT + new=vfo[active_receiver->id].rit_enabled; + vfo[active_receiver->id].rit_enabled = new ? 0 : 1; + vfo_update(); break; /////////////////////////////////////////////////////////// "RITVAL" case MIDI_ACTION_RIT_VAL: // wheel or knob @@ -811,42 +911,40 @@ int DoTheRestOfTheMIDI(void *data) { break; /////////////////////////////////////////////////////////// "SNB" case MIDI_ACTION_SNB: // only key supported - if (type == MIDI_TYPE_KEY) { - 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(); - } + 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; /////////////////////////////////////////////////////////// "SPLIT" case MIDI_ACTION_SPLIT: // only key supported // toggle split mode - if (type == MIDI_TYPE_KEY) { - new= split ? 0:1; - set_split(new); - } + new= split ? 0:1; + set_split(new); break; - /////////////////////////////////////////////////////////// "STOREM[0-4]" + /////////////////////////////////////////////////////////// "STOREMx" case MIDI_ACTION_MEM_STORE_M0: + store_memory_slot(0); + break; case MIDI_ACTION_MEM_STORE_M1: + store_memory_slot(1); + break; case MIDI_ACTION_MEM_STORE_M2: + store_memory_slot(2); + break; case MIDI_ACTION_MEM_STORE_M3: + store_memory_slot(3); + break; case MIDI_ACTION_MEM_STORE_M4: - // - // only key supported - // - if (type == MIDI_TYPE_KEY) { - new = action - MIDI_ACTION_MEM_STORE_M0; - store_memory_slot(new); - } - break; + store_memory_slot(4); + break; /////////////////////////////////////////////////////////// "SWAPRX" case MIDI_ACTION_SWAP_RX: // only key supported - if (type == MIDI_TYPE_KEY && receivers == 2) { + if (receivers == 2) { new=active_receiver->id; // 0 or 1 new= (new == 1) ? 0 : 1; // id of currently inactive receiver active_receiver=receiver[new]; @@ -857,13 +955,11 @@ int DoTheRestOfTheMIDI(void *data) { break; /////////////////////////////////////////////////////////// "SWAPVFO" case MIDI_ACTION_SWAP_VFO: // only key supported - if (type == MIDI_TYPE_KEY) { - vfo_a_swap_b(); - } + vfo_a_swap_b(); break; /////////////////////////////////////////////////////////// "TUNE" case MIDI_ACTION_TUNE: // only key supported - if (type == MIDI_TYPE_KEY && can_transmit) { + if (can_transmit) { new = !tune; tune_update(new); } @@ -872,7 +968,7 @@ int DoTheRestOfTheMIDI(void *data) { /////////////////////////////////////////////////////////// "VFOB" case MIDI_ACTION_VFOA: // only wheel supported case MIDI_ACTION_VFOB: // only wheel supported - if (type == MIDI_TYPE_WHEEL && !locked) { + if (!locked) { new = (action == MIDI_ACTION_VFOA) ? 0 : 1; vfo_id_step(new, val); } @@ -884,50 +980,25 @@ int DoTheRestOfTheMIDI(void *data) { switch (type) { case MIDI_TYPE_KEY: new = (action == MIDI_ACTION_VFO_STEP_UP) ? 1 : -1; + update_vfo_step(new); break; case MIDI_TYPE_WHEEL: new = (val > 0) ? 1 : -1; + update_vfo_step(new); break; default: // do nothing // we should not come here anyway - new = 0; - break; + break; } - if (new != 0) { - // - // locate where the current step size is located in our table - // - int i=0; - while(steps[i]!=step && steps[i]!=0) { - i++; - } - if(steps[i]!=0) { - // found. current step size is at position #i - if (new>0) { - // next higher step size, if not yet at end of list - i++; - if(steps[i]!=0) { - step=steps[i]; - } - } else { - // next lower step size, if not yet at end of list - i--; - if(i>=0) { - step=steps[i]; - } - } - } - vfo_update(); - } break; /////////////////////////////////////////////////////////// "VOX" case MIDI_ACTION_VOX: // only key supported // toggle VOX - if (type == MIDI_TYPE_KEY) { + if (can_transmit) { vox_enabled = !vox_enabled; vfo_update(); - } + } break; /////////////////////////////////////////////////////////// "VOXLEVEL" case MIDI_ACTION_VOXLEVEL: // knob or wheel supported @@ -951,13 +1022,11 @@ int DoTheRestOfTheMIDI(void *data) { break; /////////////////////////////////////////////////////////// "XITCLEAR" case MIDI_ACTION_XIT_CLEAR: // only key supported - if (type == MIDI_TYPE_KEY) { - // this clears the XIT value and disables XIT - if(can_transmit) { - transmitter->xit = 0; - transmitter->xit_enabled = 0; - vfo_update(); - } + // this clears the XIT value and disables XIT + if(can_transmit) { + transmitter->xit = 0; + transmitter->xit_enabled = 0; + vfo_update(); } break; /////////////////////////////////////////////////////////// "XITVAL" diff --git a/midi_menu.c b/midi_menu.c new file mode 100644 index 0000000..3c5c38e --- /dev/null +++ b/midi_menu.c @@ -0,0 +1,1782 @@ +/* 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 +#include +#include +#include +#include +#include + +#include "discovered.h" +#include "mode.h" +#include "filter.h" +#include "band.h" +#include "receiver.h" +#include "transmitter.h" +#include "receiver.h" +#include "adc.h" +#include "dac.h" +#include "radio.h" +#include "midi.h" +#include "alsa_midi.h" +#include "new_menu.h" +#include "midi_menu.h" +#include "property.h" + +enum { + EVENT_COLUMN, + CHANNEL_COLUMN, + NOTE_COLUMN, + TYPE_COLUMN, + ACTION_COLUMN, + N_COLUMNS +}; + +static GtkWidget *parent_window=NULL; +static GtkWidget *menu_b=NULL; +static GtkWidget *dialog=NULL; + +static GtkWidget *midi_enable_b; + +static GtkListStore *store; +static GtkWidget *view; +static GtkWidget *scrolled_window=NULL; +static gulong selection_signal_id; +GtkTreeSelection *selection; +static GtkTreeModel *model; +static GtkTreeIter iter; +struct desc *current_cmd; + +static GtkWidget *filename; + +static GtkWidget *newEvent; +static GtkWidget *newChannel; +static GtkWidget *newNote; +static GtkWidget *newVal; +static GtkWidget *newType; +static GtkWidget *newMin; +static GtkWidget *newMax; +static GtkWidget *newAction; +static GtkWidget *configure_b; +static GtkWidget *any_b; +static GtkWidget *add_b; +static GtkWidget *update_b; +static GtkWidget *delete_b; +static GtkWidget *device_b[MAX_MIDI_DEVICES]; + +static enum MIDIevent thisEvent=MIDI_EVENT_NONE; +static int thisChannel; +static int thisNote; +static int thisVal; +static int thisMin; +static int thisMax; +static int thisDelay; +static int thisVfl1, thisVfl2; +static int thisFl1, thisFl2; +static int thisLft1, thisLft2; +static int thisRgt1, thisRgt2; +static int thisFr1, thisFr2; +static int thisVfr1, thisVfr2; + +static GtkWidget *WheelContainer; +static GtkWidget *set_delay; +static GtkWidget *set_vfl1, *set_vfl2; +static GtkWidget *set_fl1, *set_fl2; +static GtkWidget *set_lft1, *set_lft2; +static GtkWidget *set_rgt1, *set_rgt2; +static GtkWidget *set_fr1, *set_fr2; +static GtkWidget *set_vfr1, *set_vfr2; + +static enum MIDItype thisType; +static enum MIDIaction thisAction; + +static gboolean accept_any=FALSE; + +enum { + UPDATE_NEW, + UPDATE_CURRENT, + UPDATE_EXISTING +}; + +static int update(void *data); +static void load_store(); +static void add_store(int key,struct desc *cmd); + +static void cleanup() { + configure_midi_device(FALSE); + if(dialog!=NULL) { + gtk_widget_destroy(dialog); + dialog=NULL; + sub_menu=NULL; + } +} + +static gboolean close_cb (GtkWidget *widget, GdkEventButton *event, gpointer data) { + cleanup(); + return TRUE; +} + +static gboolean delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_data) { + cleanup(); + return FALSE; +} + +static void device_cb(GtkWidget *widget, gpointer data) { + int index=GPOINTER_TO_INT(data); + int val=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); + if (val == 1) { + register_midi_device(index); + } else { + close_midi_device(index); + } + // take care button remains un-checked if opening failed + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), midi_devices[index].active); +} + +static void configure_cb(GtkWidget *widget, gpointer data) { + gboolean conf=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (widget)); + configure_midi_device(conf); + if (conf) { + gtk_widget_show(any_b); + } else { + gtk_widget_hide(any_b); + } +} + +static void any_cb(GtkWidget *widget, gpointer data) { + gboolean conf=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (widget)); + accept_any = conf; +} + +static void update_wheelparams(gpointer user_data) { + // + // Task: show or hide WheelContainer depending on whether + // thre current type is a wheel. If it is a wheel, + // set spin buttons to current values. + // + if (thisType==MIDI_TYPE_WHEEL) { + gtk_spin_button_set_value(GTK_SPIN_BUTTON(set_delay),(double) thisDelay); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(set_vfl1 ),(double) thisVfl1 ); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(set_vfl2 ),(double) thisVfl2 ); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(set_fl1 ),(double) thisFl1 ); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(set_fl2 ),(double) thisFl2 ); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(set_lft1 ),(double) thisLft1 ); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(set_lft2 ),(double) thisLft2 ); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(set_rgt1 ),(double) thisRgt1 ); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(set_rgt2 ),(double) thisRgt2 ); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(set_fr1 ),(double) thisFr1 ); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(set_fr2 ),(double) thisFr2 ); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(set_vfr1 ),(double) thisVfr1 ); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(set_vfr2 ),(double) thisVfr2 ); + gtk_widget_show(WheelContainer); + } else { + gtk_widget_hide(WheelContainer); + } +} + +static void type_changed_cb(GtkWidget *widget, gpointer data) { + int i=0; + int j=0; + + // update actions available for the type + gchar *type=gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(widget)); + + g_print("%s: type=%s action=%d\n",__FUNCTION__,type,thisAction); + gtk_combo_box_text_remove_all(GTK_COMBO_BOX_TEXT(newAction)); + if(type==NULL) { + // leave empty + gtk_combo_box_set_active (GTK_COMBO_BOX(newAction),0); + } else if (strcmp(type,"NONE")==0) { + thisType=MIDI_TYPE_NONE; + gtk_combo_box_set_active (GTK_COMBO_BOX(newAction),0); + } else if(strcmp(type,"KEY")==0) { + thisType=MIDI_TYPE_KEY; + // add all the Key actions + i=0; + j=0; + while(ActionTable[i].action!=MIDI_ACTION_LAST) { + if(ActionTable[i].type&MIDI_TYPE_KEY) { + gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(newAction),NULL,ActionTable[i].str); + if(ActionTable[i].action==thisAction) { + gtk_combo_box_set_active(GTK_COMBO_BOX(newAction),j); + } + j++; + } + i++; + } + } else if(strcmp(type,"KNOB/SLIDER")==0) { + thisType=MIDI_TYPE_KNOB; + // add all the Knob actions + while(ActionTable[i].action!=MIDI_ACTION_LAST) { + if(ActionTable[i].type&MIDI_TYPE_KNOB) { + gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(newAction),NULL,ActionTable[i].str); + if(ActionTable[i].action==thisAction) { + gtk_combo_box_set_active (GTK_COMBO_BOX(newAction),j); + } + j++; + } + i++; + } + } else if(strcmp(type,"WHEEL")==0) { + thisType=MIDI_TYPE_WHEEL; + // add all the Wheel actions + while(ActionTable[i].action!=MIDI_ACTION_LAST) { + if(ActionTable[i].type&MIDI_TYPE_WHEEL || ActionTable[i].type&MIDI_TYPE_KNOB) { + gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(newAction),NULL,ActionTable[i].str); + if(ActionTable[i].action==thisAction) { + gtk_combo_box_set_active (GTK_COMBO_BOX(newAction),j); + } + j++; + } + i++; + } + } + update_wheelparams(NULL); +} + +static void row_inserted_cb(GtkTreeModel *tree_model,GtkTreePath *path, GtkTreeIter *iter,gpointer user_data) { + //g_print("%s\n",__FUNCTION__); + gtk_tree_view_set_cursor(GTK_TREE_VIEW(view),path,NULL,FALSE); +} + + +static void tree_selection_changed_cb (GtkTreeSelection *selection, gpointer data) { + char *str_event; + char *str_channel; + char *str_note; + char *str_type; + char *str_action; + + //g_print("%s\n",__FUNCTION__); + //if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(configure_b))) { + if (gtk_tree_selection_get_selected (selection, &model, &iter)) { + gtk_tree_model_get(model, &iter, EVENT_COLUMN, &str_event, -1); + gtk_tree_model_get(model, &iter, CHANNEL_COLUMN, &str_channel, -1); + gtk_tree_model_get(model, &iter, NOTE_COLUMN, &str_note, -1); + gtk_tree_model_get(model, &iter, TYPE_COLUMN, &str_type, -1); + gtk_tree_model_get(model, &iter, ACTION_COLUMN, &str_action, -1); + + g_print("%s: %s %s %s %s %s\n",__FUNCTION__,str_event,str_channel,str_note,str_type,str_action); + + if(str_event!=NULL && str_channel!=NULL && str_note!=NULL && str_type!=NULL && str_action!=NULL) { + + if(strcmp(str_event,"CTRL")==0) { + thisEvent=MIDI_EVENT_CTRL; + } else if(strcmp(str_event,"PITCH")==0) { + thisEvent=MIDI_EVENT_PITCH; + } else if(strcmp(str_event,"NOTE")==0) { + thisEvent=MIDI_EVENT_NOTE; + } else { + thisEvent=MIDI_EVENT_NONE; + } + if (!strncmp(str_channel,"Any", 3)) { + thisChannel=-1; + } else { + thisChannel=atoi(str_channel); + } + thisNote=atoi(str_note); + thisVal=0; + thisMin=0; + thisMax=0; + if(strcmp(str_type,"KEY")==0) { + thisType=MIDI_TYPE_KEY; + } else if(strcmp(str_type,"KNOB/SLIDER")==0) { + thisType=MIDI_TYPE_KNOB; + } else if(strcmp(str_type,"WHEEL")==0) { + thisType=MIDI_TYPE_WHEEL; + } else { + thisType=MIDI_TYPE_NONE; + } + thisAction=MIDI_ACTION_NONE; + int i=0; + while(ActionTable[i].action!=MIDI_ACTION_LAST) { + if(strcmp(ActionTable[i].str,str_action)==0) { + thisAction=ActionTable[i].action; + break; + } + i++; + } + g_idle_add(update,GINT_TO_POINTER(UPDATE_EXISTING)); + } + } + //} +} + +static void find_current_cmd() { + struct desc *cmd; + g_print("%s: Note=%d Chan=%d Type=%d Action=%d\n",__FUNCTION__, thisNote, thisChannel, thisType, thisAction); + cmd=MidiCommandsTable[thisNote]; + while(cmd!=NULL) { + if((cmd->channel==thisChannel) && cmd->type==thisType && cmd->action==thisAction) { + g_print("%s: found cmd %p\n",__FUNCTION__,cmd); + break; + } + cmd=cmd->next; + } + current_cmd=cmd; // NULL if not found +} + +static void wheelparam_cb(GtkWidget *widget, gpointer user_data) { + int what = GPOINTER_TO_INT(user_data); + int val=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget)); + int newval=val; + + if (thisType != MIDI_TYPE_WHEEL) { + // we should never arrive here + return; + } + switch (what) { + case 1: // Delay + thisDelay=newval; + break; + case 2: // Very fast Left 1 + if (newval > thisVfl2) newval=thisVfl2; + thisVfl1=newval; + break; + case 3: // Very fast Left 2 + if (newval < thisVfl1) newval=thisVfl1; + thisVfl2=newval; + break; + case 4: // Fast Left 1 + if (newval > thisFl2) newval=thisFl2; + thisFl1=newval; + break; + case 5: // Fast Left 2 + if (newval < thisFl1) newval=thisFl1; + thisFl2=newval; + break; + case 6: // Left 1 + if (newval > thisLft2) newval=thisLft2; + thisLft1=newval; + break; + case 7: // Left 2 + if (newval < thisLft1) newval=thisLft1; + thisLft2=newval; + break; + case 8: // Right 1 + if (newval > thisRgt2) newval=thisRgt2; + thisRgt1=newval; + break; + case 9: // Right 2 + if (newval < thisRgt1) newval=thisRgt1; + thisRgt2=newval; + break; + case 10: // Fast Right 1 + if (newval > thisFr2) newval=thisFr2; + thisFr1=newval; + break; + case 11: // Fast Right2 + if (newval < thisFr1) newval=thisFr1; + thisFr2=newval; + break; + case 12: // Very fast Right 1 + if (newval > thisVfr2) newval=thisVfr2; + thisVfr1=newval; + break; + case 13: // Very fast Right 2 + if (newval < thisVfr1) newval=thisVfr1; + thisVfr2=newval; + break; + } + // + // If we have changed the value because we kept thisVfl2 >= thisVfl1 etc, + // update the spin button + // + gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget),(double) newval); +} + +static void clear_cb(GtkWidget *widget,gpointer user_data) { + + g_signal_handler_block(G_OBJECT(selection), selection_signal_id); + gtk_list_store_clear(store); + MidiReleaseCommands(); + g_signal_handler_unblock(G_OBJECT(selection), selection_signal_id); +} + +static void save_cb(GtkWidget *widget,gpointer user_data) { + GtkWidget *save_dialog; + GtkFileChooser *chooser; + GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SAVE; + gchar *filename; + gint res; + struct desc *cmd; + + save_dialog = gtk_file_chooser_dialog_new ("Save File", + GTK_WINDOW(dialog), + action, + "_Cancel", + GTK_RESPONSE_CANCEL, + "_Save", + GTK_RESPONSE_ACCEPT, + NULL); + chooser = GTK_FILE_CHOOSER (save_dialog); + gtk_file_chooser_set_do_overwrite_confirmation (chooser, TRUE); + gtk_file_chooser_set_current_name(chooser,"midi.midi"); + res = gtk_dialog_run (GTK_DIALOG (save_dialog)); + if(res==GTK_RESPONSE_ACCEPT) { + char *savefilename=gtk_file_chooser_get_filename(chooser); + clearProperties(); + midi_save_state(); + saveProperties(savefilename); + g_free(savefilename); + } + gtk_widget_destroy(save_dialog); +} + +static void load_cb(GtkWidget *widget,gpointer user_data) { + GtkWidget *load_dialog; + GtkFileChooser *chooser; + GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN; + gchar *filename; + gint res; + struct desc *cmd; + + load_dialog = gtk_file_chooser_dialog_new ("Open MIDI File", + GTK_WINDOW(dialog), + action, + "_Cancel", + GTK_RESPONSE_CANCEL, + "_Load", + GTK_RESPONSE_ACCEPT, + NULL); + chooser = GTK_FILE_CHOOSER (load_dialog); + res = gtk_dialog_run (GTK_DIALOG (load_dialog)); + if(res==GTK_RESPONSE_ACCEPT) { + char *loadfilename=gtk_file_chooser_get_filename(chooser); + clear_cb(NULL,NULL); + clearProperties(); + loadProperties(loadfilename); + midi_restore_state(); + g_signal_handler_block(G_OBJECT(selection), selection_signal_id); + load_store(); + g_signal_handler_unblock(G_OBJECT(selection), selection_signal_id); + g_free(loadfilename); + } + gtk_widget_destroy(load_dialog); +} + +static void load_original_cb(GtkWidget *widget,gpointer user_data) { + GtkWidget *load_dialog; + GtkFileChooser *chooser; + GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN; + gchar *filename; + gint res; + struct desc *cmd; + + load_dialog = gtk_file_chooser_dialog_new ("Open LEGACY MIDI File", + GTK_WINDOW(dialog), + action, + "_Cancel", + GTK_RESPONSE_CANCEL, + "_Load", + GTK_RESPONSE_ACCEPT, + NULL); + chooser = GTK_FILE_CHOOSER (load_dialog); + res = gtk_dialog_run (GTK_DIALOG (load_dialog)); + if(res==GTK_RESPONSE_ACCEPT) { + char *loadfilename=gtk_file_chooser_get_filename(chooser); + clear_cb(NULL,NULL); + MIDIstartup(loadfilename); + g_free(loadfilename); + g_signal_handler_block(G_OBJECT(selection), selection_signal_id); + load_store(); + g_signal_handler_unblock(G_OBJECT(selection), selection_signal_id); + } + gtk_widget_destroy(load_dialog); +} + +static void add_store(int key,struct desc *cmd) { + char str_event[16]; + char str_channel[16]; + char str_note[16]; + char str_type[32]; + char str_action[32]; + + //g_print("%s: key=%d desc=%p\n",__FUNCTION__,key,cmd); + switch(cmd->event) { + case MIDI_EVENT_NONE: + strcpy(str_event,"NONE"); + break; + case MIDI_EVENT_NOTE: + strcpy(str_event,"NOTE"); + break; + case MIDI_EVENT_CTRL: + strcpy(str_event,"CTRL"); + break; + case MIDI_EVENT_PITCH: + strcpy(str_event,"PITCH"); + break; + } + if (cmd->channel >= 0) { + sprintf(str_channel,"%d",cmd->channel); + } else { + sprintf(str_channel,"%s","Any"); + } + sprintf(str_note,"%d",key); + switch(cmd->type) { + case MIDI_TYPE_NONE: + strcpy(str_type,"NONE"); + break; + case MIDI_TYPE_KEY: + strcpy(str_type,"KEY"); + break; + case MIDI_TYPE_KNOB: + strcpy(str_type,"KNOB/SLIDER"); + break; + case MIDI_TYPE_WHEEL: + strcpy(str_type,"WHEEL"); + break; + } + // ATTENTION: this assumes ActionTable is sorted by action enum + strcpy(str_action,ActionTable[cmd->action].str); + + //g_print("%s: Event=%s Channel=%s Note=%s Type=%s Action=%s\n", __FUNCTION__, str_event, str_channel, str_note, str_type, str_action); + gtk_list_store_prepend(store,&iter); + gtk_list_store_set(store,&iter, + EVENT_COLUMN,str_event, + CHANNEL_COLUMN,str_channel, + NOTE_COLUMN,str_note, + TYPE_COLUMN,str_type, + ACTION_COLUMN,str_action, + -1); + + if(scrolled_window!=NULL) { + GtkAdjustment *adjustment=gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW(scrolled_window)); + //g_print("%s: adjustment=%f lower=%f upper=%f\n",__FUNCTION__,gtk_adjustment_get_value(adjustment),gtk_adjustment_get_lower(adjustment),gtk_adjustment_get_upper(adjustment)); + if(gtk_adjustment_get_value(adjustment)!=0.0) { + gtk_adjustment_set_value(adjustment,0.0); + } + } +} + +static void load_store() { + struct desc *cmd; + gtk_list_store_clear(store); + for(int i=127;i>=0;i--) { + cmd=MidiCommandsTable[i]; + while(cmd!=NULL) { + add_store(i,cmd); + cmd=cmd->next; + } + } +} + +static void add_cb(GtkButton *widget,gpointer user_data) { + + gchar *str_type=gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(newType)); + gchar *str_action=gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(newAction)); +; + + gint i; + gint type; + gint action; + gint onoff; + + if(str_type==NULL || str_action==NULL) { + return; + } + + if(strcmp(str_type,"KEY")==0) { + type=MIDI_TYPE_KEY; + } else if(strcmp(str_type,"KNOB/SLIDER")==0) { + type=MIDI_TYPE_KNOB; + } else if(strcmp(str_type,"WHEEL")==0) { + type=MIDI_TYPE_WHEEL; + } else { + type=MIDI_TYPE_NONE; + } + + action=MIDI_ACTION_NONE; + onoff=0; + i=0; + while(ActionTable[i].action!=MIDI_ACTION_LAST) { + if(strcmp(ActionTable[i].str,str_action)==0) { + action=ActionTable[i].action; + onoff=ActionTable[i].onoff; + break; + } + i++; + } + + g_print("%s: type=%s (%d) action=%s (%d)\n",__FUNCTION__,str_type,type,str_action,action); + + struct desc *desc; + desc = (struct desc *) malloc(sizeof(struct desc)); + desc->next = NULL; + desc->action = action; // MIDIaction + desc->type = type; // MIDItype + desc->event = thisEvent; // MIDevent + desc->onoff = onoff; + desc->delay = thisDelay; + desc->vfl1 = thisVfl1; + desc->vfl2 = thisVfl2; + desc->fl1 = thisFl1; + desc->fl2 = thisFl2; + desc->lft1 = thisLft1; + desc->lft2 = thisLft2; + desc->rgt1 = thisRgt1; + desc->rgt2 = thisRgt2; + desc->fr1 = thisFr1; + desc->fr2 = thisFr2; + desc->vfr1 = thisVfr1; + desc->vfr2 = thisVfr2; + desc->channel = thisChannel; + + gint key=thisNote; + if(key<0) key=0; + if(key>127) key=0; + + + MidiAddCommand(key, desc); + add_store(key,desc); + + gtk_widget_set_sensitive(add_b,FALSE); + gtk_widget_set_sensitive(update_b,TRUE); + gtk_widget_set_sensitive(delete_b,TRUE); + +} + +static void update_cb(GtkButton *widget,gpointer user_data) { + char str_event[16]; + char str_channel[16]; + char str_note[16]; + int i; + int onoff; + + if (current_cmd == NULL) { + g_print("%s: current_cmd is NULL!\n", __FUNCTION__); + return; + } + + gchar *str_type=gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(newType)); + gchar *str_action=gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(newAction)); +; + //g_print("%s: type=%s action=%s\n",__FUNCTION__,str_type,str_action); + + if(strcmp(str_type,"KEY")==0) { + thisType=MIDI_TYPE_KEY; + } else if(strcmp(str_type,"KNOB/SLIDER")==0) { + thisType=MIDI_TYPE_KNOB; + } else if(strcmp(str_type,"WHEEL")==0) { + thisType=MIDI_TYPE_WHEEL; + } else { + thisType=MIDI_TYPE_NONE; + } + + thisAction=MIDI_ACTION_NONE; + i=0; + while(ActionTable[i].action!=MIDI_ACTION_LAST) { + if(strcmp(ActionTable[i].str,str_action)==0) { + thisAction=ActionTable[i].action; + onoff=ActionTable[i].onoff; + break; + } + i++; + } + + current_cmd->channel=thisChannel; + current_cmd->type =thisType; + current_cmd->action =thisAction; + current_cmd->onoff =onoff; + current_cmd->delay =thisDelay; + + current_cmd->vfl1 =thisVfl1; + current_cmd->vfl2 =thisVfl2; + current_cmd->fl1 =thisFl1; + current_cmd->fl2 =thisFl2; + current_cmd->lft1 =thisLft1; + current_cmd->lft2 =thisLft2; + current_cmd->rgt1 =thisRgt1; + current_cmd->rgt2 =thisRgt2; + current_cmd->fr1 =thisFr1; + current_cmd->fr2 =thisFr2; + current_cmd->vfr1 =thisVfr1; + current_cmd->vfr2 =thisVfr2; + + switch(current_cmd->event) { + case MIDI_EVENT_NONE: + strcpy(str_event,"NONE"); + break; + case MIDI_EVENT_NOTE: + strcpy(str_event,"NOTE"); + break; + case MIDI_EVENT_CTRL: + strcpy(str_event,"CTRL"); + break; + case MIDI_EVENT_PITCH: + strcpy(str_event,"PITCH"); + break; + } + if (current_cmd->channel >= 0) { + sprintf(str_channel,"%d",current_cmd->channel); + } else { + sprintf(str_channel,"%s","Any"); + } + sprintf(str_note,"%d",thisNote); + + g_print("%s: event=%s channel=%s note=%s type=%s action=%s\n", + __FUNCTION__,str_event,str_channel,str_note,str_type,str_action); + gtk_list_store_set(store,&iter, + EVENT_COLUMN,str_event, + CHANNEL_COLUMN,str_channel, + NOTE_COLUMN,str_note, + TYPE_COLUMN,str_type, + ACTION_COLUMN,str_action, + -1); +} + +static void delete_cb(GtkButton *widget,gpointer user_data) { + struct desc *previous_cmd; + struct desc *next_cmd; + GtkTreeIter saved_iter; + g_print("%s: thisNote=%d current_cmd=%p\n",__FUNCTION__,thisNote,current_cmd); + + if (current_cmd == NULL) { + g_print("%s: current_cmd is NULL!\n", __FUNCTION__); + return; + } + + saved_iter=iter; + + + // remove from MidiCommandsTable + if(MidiCommandsTable[thisNote]==current_cmd) { + g_print("%s: remove first\n",__FUNCTION__); + MidiCommandsTable[thisNote]=current_cmd->next; + g_free(current_cmd); + current_cmd=NULL; + } else { + previous_cmd=MidiCommandsTable[thisNote]; + while(previous_cmd->next!=NULL) { + next_cmd=previous_cmd->next; + if(next_cmd==current_cmd) { + g_print("%s: remove next\n",__FUNCTION__); + previous_cmd->next=next_cmd->next; + g_free(next_cmd); + current_cmd=NULL; // note next_cmd == current_cmd + break; + } + previous_cmd=next_cmd; + } + } + + // remove from list store + gtk_list_store_remove(store,&saved_iter); + + gtk_widget_set_sensitive(add_b,TRUE); + gtk_widget_set_sensitive(update_b,FALSE); + gtk_widget_set_sensitive(delete_b,FALSE); + +} + +void midi_menu(GtkWidget *parent) { + int i; + int col=0; + int row=0; + GtkCellRenderer *renderer; + GtkWidget *lbl; + + parent_window=parent; + + dialog=gtk_dialog_new(); + gtk_window_set_transient_for(GTK_WINDOW(dialog),GTK_WINDOW(parent_window)); + gtk_window_set_title(GTK_WINDOW(dialog),"piHPSDR - MIDI"); + g_signal_connect (dialog, "delete_event", G_CALLBACK (delete_event), NULL); + + GdkRGBA color; + color.red = 1.0; + color.green = 1.0; + color.blue = 1.0; + color.alpha = 1.0; + gtk_widget_override_background_color(dialog,GTK_STATE_FLAG_NORMAL,&color); + + GtkWidget *content=gtk_dialog_get_content_area(GTK_DIALOG(dialog)); + + GtkWidget *grid=gtk_grid_new(); + gtk_grid_set_column_spacing (GTK_GRID(grid),2); + + row=0; + col=0; + + GtkWidget *close_b=gtk_button_new_with_label("Close"); + g_signal_connect(close_b, "pressed", G_CALLBACK(close_cb), NULL); + gtk_grid_attach(GTK_GRID(grid), close_b, col, row, 1, 1); + col++; + + get_midi_devices(); + if (n_midi_devices > 0) { + GtkWidget *devices_label=gtk_label_new(NULL); + gtk_label_set_markup(GTK_LABEL(devices_label), "Select MIDI device(s)"); + gtk_label_set_justify(GTK_LABEL(devices_label),GTK_JUSTIFY_LEFT); + gtk_grid_attach(GTK_GRID(grid),devices_label,col,row,2,1); + // + // Now put the device checkboxes in columns 3 (width: 1), 4 (width: 3), 7 (width: 1) + // and make as many rows as necessary + col=3; + int width = 1; + for (i=0; i 3) { + col=0; + row++; + } + } else { + GtkWidget *devices_label=gtk_label_new(NULL); + gtk_label_set_markup(GTK_LABEL(devices_label), "No MIDI devices found!"); + gtk_label_set_justify(GTK_LABEL(devices_label),GTK_JUSTIFY_LEFT); + gtk_grid_attach(GTK_GRID(grid),devices_label,col,row,3,1); + row++; + col=0; + } + + row++; + col=0; + + GtkWidget *clear_b=gtk_button_new_with_label("Clear"); + gtk_grid_attach(GTK_GRID(grid),clear_b,col,row,1,1); + g_signal_connect(clear_b,"clicked",G_CALLBACK(clear_cb),NULL); + col++; + + GtkWidget *save_b=gtk_button_new_with_label("Save"); + gtk_grid_attach(GTK_GRID(grid),save_b,col,row,1,1); + g_signal_connect(save_b,"clicked",G_CALLBACK(save_cb),NULL); + col++; + + GtkWidget *load_b=gtk_button_new_with_label("Load"); + gtk_grid_attach(GTK_GRID(grid),load_b,col,row,1,1); + g_signal_connect(load_b,"clicked",G_CALLBACK(load_cb),NULL); + col++; + + GtkWidget *load_original_b=gtk_button_new_with_label("Load Legacy"); + gtk_grid_attach(GTK_GRID(grid),load_original_b,col,row,1,1); + g_signal_connect(load_original_b,"clicked",G_CALLBACK(load_original_cb),NULL); + col++; + + configure_b=gtk_check_button_new_with_label("MIDI Configure"); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (configure_b), FALSE); + gtk_grid_attach(GTK_GRID(grid),configure_b,col,row,3,1); + g_signal_connect(configure_b,"toggled",G_CALLBACK(configure_cb),NULL); + + col+=3; + any_b=gtk_check_button_new_with_label("Configure for any channel"); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (any_b), FALSE); + gtk_grid_attach(GTK_GRID(grid),any_b,col,row,6,1); + g_signal_connect(any_b,"toggled",G_CALLBACK(any_cb),NULL); + + row++; + col=0; + GtkWidget *label=gtk_label_new("Evt"); + gtk_grid_attach(GTK_GRID(grid),label,col++,row,1,1); + label=gtk_label_new("Ch"); + gtk_grid_attach(GTK_GRID(grid),label,col++,row,1,1); + label=gtk_label_new("Note"); + gtk_grid_attach(GTK_GRID(grid),label,col++,row,1,1); + label=gtk_label_new("Type"); + gtk_grid_attach(GTK_GRID(grid),label,col++,row,1,1); + label=gtk_label_new("Value"); + gtk_grid_attach(GTK_GRID(grid),label,col++,row,1,1); + label=gtk_label_new("Min"); + gtk_grid_attach(GTK_GRID(grid),label,col++,row,1,1); + label=gtk_label_new("Max"); + gtk_grid_attach(GTK_GRID(grid),label,col++,row,1,1); + label=gtk_label_new("Action"); + gtk_grid_attach(GTK_GRID(grid),label,col++,row,1,1); + + + row++; + col=0; + newEvent=gtk_label_new(""); + gtk_grid_attach(GTK_GRID(grid),newEvent,col++,row,1,1); + newChannel=gtk_label_new(""); + gtk_grid_attach(GTK_GRID(grid),newChannel,col++,row,1,1); + newNote=gtk_label_new(""); + gtk_grid_attach(GTK_GRID(grid),newNote,col++,row,1,1); + newType=gtk_combo_box_text_new(); + gtk_grid_attach(GTK_GRID(grid),newType,col++,row,1,1); + g_signal_connect(newType,"changed",G_CALLBACK(type_changed_cb),NULL); + newVal=gtk_label_new(""); + gtk_grid_attach(GTK_GRID(grid),newVal,col++,row,1,1); + newMin=gtk_label_new(""); + gtk_grid_attach(GTK_GRID(grid),newMin,col++,row,1,1); + newMax=gtk_label_new(""); + gtk_grid_attach(GTK_GRID(grid),newMax,col++,row,1,1); + newAction=gtk_combo_box_text_new(); + gtk_combo_box_set_wrap_width(GTK_COMBO_BOX(newAction),4); + gtk_grid_attach(GTK_GRID(grid),newAction,col++,row,3,1); + +// +// Load Action button with all actions, such that it +// *now* assumes the maximum width +// + i=0; + while(ActionTable[i].action!=MIDI_ACTION_LAST) { + gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(newAction),NULL,ActionTable[i].str); + i++; + } + gtk_combo_box_set_active(GTK_COMBO_BOX(newAction),0); + + row++; + col=0; + + add_b=gtk_button_new_with_label("Add"); + g_signal_connect(add_b, "pressed", G_CALLBACK(add_cb),NULL); + gtk_grid_attach(GTK_GRID(grid),add_b,col++,row,1,1); + gtk_widget_set_sensitive(add_b,FALSE); + + update_b=gtk_button_new_with_label("Update"); + g_signal_connect(update_b, "pressed", G_CALLBACK(update_cb),NULL); + gtk_grid_attach(GTK_GRID(grid),update_b,col++,row,1,1); + gtk_widget_set_sensitive(update_b,FALSE); + + delete_b=gtk_button_new_with_label("Delete"); + g_signal_connect(delete_b, "pressed", G_CALLBACK(delete_cb),NULL); + gtk_grid_attach(GTK_GRID(grid),delete_b,col++,row,1,1); + gtk_widget_set_sensitive(delete_b,FALSE); + + row++; + col=0; + + scrolled_window=gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),GTK_POLICY_AUTOMATIC,GTK_POLICY_ALWAYS); + // + // At the top of the window, there are rows of checkboxes for MIDI devices, up to 3 in a row. + // In the unlikely case there are very many MIDI devices, vertical space becomes scarce + // + gtk_widget_set_size_request(scrolled_window,400,300-15*((n_midi_devices+1)/3)); + + view=gtk_tree_view_new(); + + renderer=gtk_cell_renderer_text_new(); + gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), -1, "Event", renderer, "text", EVENT_COLUMN, NULL); + + renderer=gtk_cell_renderer_text_new(); + gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), -1, "CHANNEL", renderer, "text", CHANNEL_COLUMN, NULL); + + renderer=gtk_cell_renderer_text_new(); + gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), -1, "NOTE", renderer, "text", NOTE_COLUMN, NULL); + + renderer=gtk_cell_renderer_text_new(); + gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), -1, "TYPE", renderer, "text", TYPE_COLUMN, NULL); + + renderer=gtk_cell_renderer_text_new(); + gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), -1, "ACTION", renderer, "text", ACTION_COLUMN, NULL); + + store=gtk_list_store_new(N_COLUMNS,G_TYPE_STRING,G_TYPE_STRING,G_TYPE_STRING,G_TYPE_STRING,G_TYPE_STRING,G_TYPE_STRING,G_TYPE_STRING); + + load_store(); + + gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store)); + + gtk_container_add(GTK_CONTAINER(scrolled_window),view); + + gtk_grid_attach(GTK_GRID(grid), scrolled_window, col, row, 5, 10); + + model=gtk_tree_view_get_model(GTK_TREE_VIEW(view)); + g_signal_connect(model,"row-inserted",G_CALLBACK(row_inserted_cb),NULL); + + selection=gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); + gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE); + + selection_signal_id=g_signal_connect(G_OBJECT(selection),"changed",G_CALLBACK(tree_selection_changed_cb),NULL); + + // + // Place a fixed container to hold the wheel parameters + // and create sub-grid + // + col=5; + WheelContainer=gtk_fixed_new(); + gtk_widget_set_size_request(WheelContainer,300,300-15*((n_midi_devices+1)/3)); + gtk_grid_attach(GTK_GRID(grid), WheelContainer, col, row, 6, 10); + // + // Showing/hiding the container may resize-the columns of the main grid, + // and causing other elements to move around. Therefore create a further + // "dummy" frame that is always shown. The dummy must have the same width + // and a small height. + // + GtkWidget *DummyContainer=gtk_fixed_new(); + gtk_widget_set_size_request(DummyContainer,300,1); + gtk_grid_attach(GTK_GRID(grid), DummyContainer, col, row, 6, 1); + + GtkWidget *WheelGrid=gtk_grid_new(); + gtk_grid_set_column_spacing (GTK_GRID(WheelGrid),2); + + col=0; + row=0; + + lbl=gtk_label_new(NULL); + // the new-line in the label get some space between the text and the spin buttons + gtk_label_set_markup(GTK_LABEL(lbl), "Configure special WHEEL parameters\n"); + gtk_widget_set_size_request(lbl,300,30); + gtk_widget_set_halign(lbl, GTK_ALIGN_CENTER); + + gtk_grid_attach(GTK_GRID(WheelGrid), lbl, col, row, 3, 1); + + // + // Finally, put wheel config elements into the wheel grid + // + col=0; + row++; + + lbl=gtk_label_new("Delay"); + gtk_widget_set_halign(lbl, GTK_ALIGN_START); + gtk_grid_attach(GTK_GRID(WheelGrid), lbl, col, row, 1, 1); + col++; + + set_delay = gtk_spin_button_new_with_range(0.0, 500.0, 10.0); + gtk_grid_attach(GTK_GRID(WheelGrid), set_delay, col, row, 1, 1); + g_signal_connect(set_delay, "value-changed", G_CALLBACK(wheelparam_cb), GINT_TO_POINTER(1)); + col++; + + row++; + col=0; + lbl=gtk_label_new("Left <<<"); + gtk_widget_set_halign(lbl, GTK_ALIGN_START); + gtk_grid_attach(GTK_GRID(WheelGrid), lbl, col, row, 1, 1); + col++; + + set_vfl1 = gtk_spin_button_new_with_range(-1.0, 127.0, 1.0); + gtk_grid_attach(GTK_GRID(WheelGrid), set_vfl1, col, row, 1, 1); + g_signal_connect(set_vfl1, "value-changed", G_CALLBACK(wheelparam_cb), GINT_TO_POINTER(2)); + col++; + + set_vfl2 = gtk_spin_button_new_with_range(-1.0, 127.0, 1.0); + gtk_grid_attach(GTK_GRID(WheelGrid), set_vfl2, col, row, 1, 1); + g_signal_connect(set_vfl2, "value-changed", G_CALLBACK(wheelparam_cb), GINT_TO_POINTER(3)); + col++; + + row++; + col=0; + + lbl=gtk_label_new("Left <<"); + gtk_widget_set_halign(lbl, GTK_ALIGN_START); + gtk_grid_attach(GTK_GRID(WheelGrid), lbl, col, row, 1, 1); + col++; + + set_fl1 = gtk_spin_button_new_with_range(-1.0, 127.0, 1.0); + gtk_grid_attach(GTK_GRID(WheelGrid), set_fl1, col, row, 1, 1); + g_signal_connect(set_fl1, "value-changed", G_CALLBACK(wheelparam_cb), GINT_TO_POINTER(4)); + col++; + + set_fl2 = gtk_spin_button_new_with_range(-1.0, 127.0, 1.0); + gtk_grid_attach(GTK_GRID(WheelGrid), set_fl2, col, row, 1, 1); + g_signal_connect(set_fl2, "value-changed", G_CALLBACK(wheelparam_cb), GINT_TO_POINTER(5)); + col++; + + row++; + col=0; + lbl=gtk_label_new("Left <"); + gtk_widget_set_halign(lbl, GTK_ALIGN_START); + gtk_grid_attach(GTK_GRID(WheelGrid), lbl, col, row, 1, 1); + col++; + + set_lft1 = gtk_spin_button_new_with_range(-1.0, 127.0, 1.0); + gtk_grid_attach(GTK_GRID(WheelGrid), set_lft1, col, row, 1, 1); + g_signal_connect(set_lft1, "value-changed", G_CALLBACK(wheelparam_cb), GINT_TO_POINTER(6)); + col++; + + set_lft2 = gtk_spin_button_new_with_range(-1.0, 127.0, 1.0); + gtk_grid_attach(GTK_GRID(WheelGrid), set_lft2, col, row, 1, 1); + g_signal_connect(set_lft2, "value-changed", G_CALLBACK(wheelparam_cb), GINT_TO_POINTER(7)); + col++; + + row++; + col=0; + lbl=gtk_label_new("Right >"); + gtk_widget_set_halign(lbl, GTK_ALIGN_START); + gtk_grid_attach(GTK_GRID(WheelGrid), lbl, col, row, 1, 1); + col++; + + set_rgt1 = gtk_spin_button_new_with_range(-1.0, 127.0, 1.0); + gtk_grid_attach(GTK_GRID(WheelGrid), set_rgt1, col, row, 1, 1); + g_signal_connect(set_rgt1, "value-changed", G_CALLBACK(wheelparam_cb), GINT_TO_POINTER(8)); + col++; + + set_rgt2 = gtk_spin_button_new_with_range(-1.0, 127.0, 1.0); + gtk_grid_attach(GTK_GRID(WheelGrid), set_rgt2, col, row, 1, 1); + g_signal_connect(set_rgt2, "value-changed", G_CALLBACK(wheelparam_cb), GINT_TO_POINTER(9)); + col++; + + row++; + col=0; + lbl=gtk_label_new("Right >>"); + gtk_widget_set_halign(lbl, GTK_ALIGN_START); + gtk_grid_attach(GTK_GRID(WheelGrid), lbl, col, row, 1, 1); + col++; + + set_fr1 = gtk_spin_button_new_with_range(-1.0, 127.0, 1.0); + gtk_grid_attach(GTK_GRID(WheelGrid), set_fr1, col, row, 1, 1); + g_signal_connect(set_fr1, "value-changed", G_CALLBACK(wheelparam_cb), GINT_TO_POINTER(10)); + col++; + + set_fr2 = gtk_spin_button_new_with_range(-1.0, 127.0, 1.0); + gtk_grid_attach(GTK_GRID(WheelGrid), set_fr2, col, row, 1, 1); + g_signal_connect(set_fr2, "value-changed", G_CALLBACK(wheelparam_cb), GINT_TO_POINTER(11)); + col++; + + row++; + col=0; + lbl=gtk_label_new("Right >>>"); + gtk_widget_set_halign(lbl, GTK_ALIGN_START); + gtk_grid_attach(GTK_GRID(WheelGrid), lbl, col, row, 1, 1); + col++; + + set_vfr1 = gtk_spin_button_new_with_range(-1.0, 127.0, 1.0); + gtk_grid_attach(GTK_GRID(WheelGrid), set_vfr1, col, row, 1, 1); + g_signal_connect(set_vfr1, "value-changed", G_CALLBACK(wheelparam_cb), GINT_TO_POINTER(12)); + col++; + + set_vfr2 = gtk_spin_button_new_with_range(-1.0, 127.0, 1.0); + gtk_grid_attach(GTK_GRID(WheelGrid), set_vfr2, col, row, 1, 1); + g_signal_connect(set_vfr2, "value-changed", G_CALLBACK(wheelparam_cb), GINT_TO_POINTER(13)); + col++; + + gtk_container_add(GTK_CONTAINER(content),grid); + gtk_container_add(GTK_CONTAINER(WheelContainer), WheelGrid); + sub_menu=dialog; + gtk_widget_show_all(dialog); + + // + // Clear Action box (we filled it just to set its width) + // + gtk_combo_box_text_remove_all(GTK_COMBO_BOX_TEXT(newAction)); + gtk_combo_box_set_active (GTK_COMBO_BOX(newAction),0); + // + // Hide "accept from any source" checkbox + // (made visible only if config is checked) + gtk_widget_hide(any_b); + gtk_widget_hide(WheelContainer); +} + +static int update(void *data) { + int state=GPOINTER_TO_INT(data); + gchar text[32]; + gint i=1; + gint j; + + switch(state) { + case UPDATE_NEW: + g_print("%s: UPDATE_NEW\n",__FUNCTION__); + switch(thisEvent) { + case MIDI_EVENT_NONE: + gtk_label_set_text(GTK_LABEL(newEvent),"NONE"); + break; + case MIDI_EVENT_NOTE: + gtk_label_set_text(GTK_LABEL(newEvent),"NOTE"); + break; + case MIDI_EVENT_CTRL: + gtk_label_set_text(GTK_LABEL(newEvent),"CTRL"); + break; + case MIDI_EVENT_PITCH: + gtk_label_set_text(GTK_LABEL(newEvent),"PITCH"); + break; + } + if (thisChannel >= 0) { + sprintf(text,"%d",thisChannel); + } else { + strcpy(text,"Any"); + } + gtk_label_set_text(GTK_LABEL(newChannel),text); + sprintf(text,"%d",thisNote); + gtk_label_set_text(GTK_LABEL(newNote),text); + gtk_combo_box_text_remove_all(GTK_COMBO_BOX_TEXT(newType)); + gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(newType),NULL,"NONE"); + switch(thisEvent) { + case MIDI_EVENT_NONE: + gtk_combo_box_set_active (GTK_COMBO_BOX(newType),0); + break; + case MIDI_EVENT_NOTE: + case MIDI_EVENT_PITCH: + gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(newType),NULL,"KEY"); + gtk_combo_box_set_active (GTK_COMBO_BOX(newType),1); + break; + case MIDI_EVENT_CTRL: + gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(newType),NULL,"KNOB/SLIDER"); + gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(newType),NULL,"WHEEL"); + gtk_combo_box_set_active (GTK_COMBO_BOX(newType),0); + break; + } + gtk_combo_box_text_remove_all(GTK_COMBO_BOX_TEXT(newAction)); + if(thisEvent==MIDI_EVENT_PITCH || thisEvent==MIDI_EVENT_NOTE) { + i=0; + j=0; + while(ActionTable[i].action!=MIDI_ACTION_LAST) { + if(ActionTable[i].type&MIDI_TYPE_KEY) { + gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(newAction),NULL,ActionTable[i].str); + if(ActionTable[i].action==thisAction) { + gtk_combo_box_set_active(GTK_COMBO_BOX(newAction),j); + } + j++; + } + i++; + } + + } + sprintf(text,"%d",thisVal); + gtk_label_set_text(GTK_LABEL(newVal),text); + sprintf(text,"%d",thisMin); + gtk_label_set_text(GTK_LABEL(newMin),text); + sprintf(text,"%d",thisMax); + gtk_label_set_text(GTK_LABEL(newMax),text); + + gtk_widget_set_sensitive(add_b,TRUE); + gtk_widget_set_sensitive(update_b,FALSE); + gtk_widget_set_sensitive(delete_b,FALSE); + break; + + case UPDATE_CURRENT: + g_print("%s: UPDATE_CURRENT\n",__FUNCTION__); + sprintf(text,"%d",thisVal); + gtk_label_set_text(GTK_LABEL(newVal),text); + sprintf(text,"%d",thisMin); + gtk_label_set_text(GTK_LABEL(newMin),text); + sprintf(text,"%d",thisMax); + gtk_label_set_text(GTK_LABEL(newMax),text); + break; + + case UPDATE_EXISTING: + g_print("%s: UPDATE_EXISTING Type=%d Action=%d\n",__FUNCTION__,thisType,thisAction); + switch(thisEvent) { + case MIDI_EVENT_NONE: + gtk_label_set_text(GTK_LABEL(newEvent),"NONE"); + break; + case MIDI_EVENT_NOTE: + gtk_label_set_text(GTK_LABEL(newEvent),"NOTE"); + break; + case MIDI_EVENT_CTRL: + gtk_label_set_text(GTK_LABEL(newEvent),"CTRL"); + break; + case MIDI_EVENT_PITCH: + gtk_label_set_text(GTK_LABEL(newEvent),"PITCH"); + break; + } + if (thisChannel >= 0) { + sprintf(text,"%d",thisChannel); + } else { + sprintf(text,"%s","Any"); + } + gtk_label_set_text(GTK_LABEL(newChannel),text); + sprintf(text,"%d",thisNote); + gtk_label_set_text(GTK_LABEL(newNote),text); + gtk_combo_box_text_remove_all(GTK_COMBO_BOX_TEXT(newType)); + gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(newType),NULL,"NONE"); + switch(thisEvent) { + case MIDI_EVENT_NONE: + gtk_combo_box_set_active (GTK_COMBO_BOX(newType),0); + break; + case MIDI_EVENT_NOTE: + case MIDI_EVENT_PITCH: + gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(newType),NULL,"KEY"); + if(thisType==MIDI_TYPE_NONE) { + gtk_combo_box_set_active (GTK_COMBO_BOX(newType),0); + } else if(thisType==MIDI_TYPE_KEY) { + gtk_combo_box_set_active (GTK_COMBO_BOX(newType),1); + } + break; + case MIDI_EVENT_CTRL: + gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(newType),NULL,"KNOB/SLIDER"); + gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(newType),NULL,"WHEEL"); + if(thisType==MIDI_TYPE_NONE) { + gtk_combo_box_set_active (GTK_COMBO_BOX(newType),0); + } else if(thisType==MIDI_TYPE_KNOB) { + gtk_combo_box_set_active (GTK_COMBO_BOX(newType),1); + } else if(thisType==MIDI_TYPE_WHEEL) { + gtk_combo_box_set_active (GTK_COMBO_BOX(newType),2); + } + break; + } + sprintf(text,"%d",thisVal); + gtk_label_set_text(GTK_LABEL(newVal),text); + sprintf(text,"%d",thisMin); + gtk_label_set_text(GTK_LABEL(newMin),text); + sprintf(text,"%d",thisMax); + gtk_label_set_text(GTK_LABEL(newMax),text); + + find_current_cmd(); + g_print("%s: current_cmd %p\n",__FUNCTION__,current_cmd); + + if (current_cmd != NULL) { + thisDelay = current_cmd->delay; + thisVfl1 = current_cmd->vfl1; + thisVfl2 = current_cmd->vfl2; + thisFl1 = current_cmd->fl1; + thisFl2 = current_cmd->fl2; + thisLft1 = current_cmd->lft1; + thisLft2 = current_cmd->lft2; + thisRgt1 = current_cmd->rgt1; + thisRgt2 = current_cmd->rgt2; + thisFr1 = current_cmd->fr1; + thisFr2 = current_cmd->fr2; + thisVfr1 = current_cmd->vfr1; + thisVfr2 = current_cmd->vfr2; + } + // no need for g_idle_add since this is called in the idle queue + update_wheelparams(NULL); + gtk_widget_set_sensitive(add_b,FALSE); + gtk_widget_set_sensitive(update_b,TRUE); + gtk_widget_set_sensitive(delete_b,TRUE); + break; + + } + + return 0; +} + +void NewMidiConfigureEvent(enum MIDIevent event, int channel, int note, int val) { + + gboolean valid; + char *str_event; + char *str_channel; + char *str_note; + char *str_type; + char *str_action; + + gint tree_event; + gint tree_channel; + gint tree_note; + + //g_print("%s: event=%d channel=%d note=%d val=%d\n", __FUNCTION__,event,channel,note,val); + + if(event==thisEvent && channel==thisChannel && note==thisNote) { + //g_print("%s: current event\n",__FUNCTION__); + thisVal=val; + if(valthisMax) thisMax=val; + g_idle_add(update,GINT_TO_POINTER(UPDATE_CURRENT)); + } else { + //g_print("%s: new or existing event\n",__FUNCTION__); + thisEvent=event; + thisChannel=channel; + if (accept_any) thisChannel=-1; + thisNote=note; + thisVal=val; + thisMin=val; + thisMax=val; + thisType=MIDI_TYPE_NONE; + thisAction=MIDI_ACTION_NONE; + // + // set default values for wheel parameters + // + thisDelay = 0; + thisVfl1 = -1; + thisVfl2 = -1; + thisFl1 = -1; + thisFl2 = -1; + thisLft1 = 0; + thisLft2 = 63; + thisRgt1 = 65; + thisRgt2 =127; + thisFr1 = -1; + thisFr2 = -1; + thisVfr1 = -1; + thisVfr2 = -1; + + // search tree to see if it is existing event + valid=gtk_tree_model_get_iter_first(model,&iter); + while(valid) { + gtk_tree_model_get(model, &iter, EVENT_COLUMN, &str_event, -1); + gtk_tree_model_get(model, &iter, CHANNEL_COLUMN, &str_channel, -1); + gtk_tree_model_get(model, &iter, NOTE_COLUMN, &str_note, -1); + gtk_tree_model_get(model, &iter, TYPE_COLUMN, &str_type, -1); + gtk_tree_model_get(model, &iter, ACTION_COLUMN, &str_action, -1); + + //g_print("%s: %s %s %s %s %s\n",__FUNCTION__,str_event,str_channel,str_note,str_type,str_action); + + if(str_event!=NULL && str_channel!=NULL && str_note!=NULL && str_type!=NULL && str_action!=NULL) { + if(strcmp(str_event,"CTRL")==0) { + tree_event=MIDI_EVENT_CTRL; + } else if(strcmp(str_event,"PITCH")==0) { + tree_event=MIDI_EVENT_PITCH; + } else if(strcmp(str_event,"NOTE")==0) { + tree_event=MIDI_EVENT_NOTE; + } else { + tree_event=MIDI_EVENT_NONE; + } + if (!strncmp(str_channel,"Any", 3)) { + tree_channel=-1; + } else { + tree_channel=atoi(str_channel); + } + tree_note=atoi(str_note); + + if(thisEvent==tree_event && thisChannel==tree_channel && thisNote==tree_note) { + thisVal=0; + thisMin=0; + thisMax=0; + if(strcmp(str_type,"KEY")==0) { + thisType=MIDI_TYPE_KEY; + } else if(strcmp(str_type,"KNOB/SLIDER")==0) { + thisType=MIDI_TYPE_KNOB; + } else if(strcmp(str_type,"WHEEL")==0) { + thisType=MIDI_TYPE_WHEEL; + } else { + thisType=MIDI_TYPE_NONE; + } + thisAction=MIDI_ACTION_NONE; + int i=1; + while(ActionTable[i].action!=MIDI_ACTION_LAST) { + if(strcmp(ActionTable[i].str,str_action)==0) { + thisAction=ActionTable[i].action; + break; + } + i++; + } + gtk_tree_view_set_cursor(GTK_TREE_VIEW(view),gtk_tree_model_get_path(model,&iter),NULL,FALSE); + g_idle_add(update,GINT_TO_POINTER(UPDATE_EXISTING)); + return; + } + } + + valid=gtk_tree_model_iter_next(model,&iter); + } + + // + // It is not guaranteed that update() will be executed before + // thisAction & friends are overwritten by the next incoming MIDI + // message. Therefore, we should allocate a data structure with + // all information therein that is needed by update() and pass + // a pointer. + // + g_idle_add(update,GINT_TO_POINTER(UPDATE_NEW)); + } +} + +void midi_save_state() { + char name[80]; + char value[80]; + struct desc *cmd; + gint index; + + index=0; + for (int i=0; ichannel,i,midi_events[cmd->event],midi_types[cmd->type],ActionTable[cmd->action].str); + + // + // There might be events that share the channel and the note value (one NOTE and one CTRL, for example) + // These must not share the same key in the property database so the "running index" must be part of the key + // + + sprintf(name,"midi[%d].index[%d].event",i,index); + setProperty(name,midi_events[cmd->event]); + + sprintf(name,"midi[%d].index[%d].type",i,index); + setProperty(name,midi_types[cmd->type]); + + //ATTENTION: assumes ActionTable is sorted by action enum + sprintf(name,"midi[%d].index[%d].action",i,index); + setProperty(name,(char *) ActionTable[cmd->action].str); + + sprintf(name,"midi[%d].index[%d].channel",i,index); + sprintf(value,"%d",cmd->channel); + setProperty(name, value); + + // + // For wheels, also store the additional parameters, + // but do so only if they deviate from the default values. + // + if (cmd->type == MIDI_TYPE_WHEEL) { + if (cmd->delay > 0) { + sprintf(name,"midi[%d].index[%d].delay",i,index); + sprintf(value,"%d",cmd->delay); + setProperty(name, value); + } + if (cmd->vfl1 != -1 || cmd->vfl2 != -1) { + sprintf(name,"midi[%d].index[%d].vfl1",i,index); + sprintf(value,"%d",cmd->vfl1); + setProperty(name, value); + sprintf(name,"midi[%d].index[%d].vfl2",i,index); + sprintf(value,"%d",cmd->vfl2); + setProperty(name, value); + } + if (cmd->fl1 != -1 || cmd->fl2 != -1) { + sprintf(name,"midi[%d].index[%d].fl1",i,index); + sprintf(value,"%d",cmd->fl1); + setProperty(name, value); + sprintf(name,"midi[%d].index[%d].fl2",i,index); + sprintf(value,"%d",cmd->fl2); + setProperty(name, value); + } + if (cmd->lft1 != 0 || cmd->lft2 != 63) { + sprintf(name,"midi[%d].index[%d].lft1",i,index); + sprintf(value,"%d",cmd->lft1); + setProperty(name, value); + sprintf(name,"midi[%d].index[%d].lft2",i,index); + sprintf(value,"%d",cmd->lft2); + setProperty(name, value); + } + if (cmd->rgt1 != 65 || cmd->rgt2 != 127) { + sprintf(name,"midi[%d].index[%d].rgt1",i,index); + sprintf(value,"%d",cmd->rgt1); + setProperty(name, value); + sprintf(name,"midi[%d].index[%d].rgt2",i,index); + sprintf(value,"%d",cmd->rgt2); + setProperty(name, value); + } + if (cmd->fr1 != -1 || cmd->fr2 != -1) { + sprintf(name,"midi[%d].index[%d].fr1",i,index); + sprintf(value,"%d",cmd->fr1); + setProperty(name, value); + sprintf(name,"midi[%d].index[%d].fr2",i,index); + sprintf(value,"%d",cmd->fr2); + setProperty(name, value); + } + if (cmd->vfr1 != -1 || cmd->vfr2 != -1) { + sprintf(name,"midi[%d].index[%d].vfr1",i,index); + sprintf(value,"%d",cmd->vfr1); + setProperty(name, value); + sprintf(name,"midi[%d].index[%d].vfr2",i,index); + sprintf(value,"%d",cmd->vfr2); + setProperty(name, value); + } + } + + cmd=cmd->next; + index++; + } + + if(index!=0) { + sprintf(name,"midi[%d].indices",i); + sprintf(value,"%d",index); + setProperty(name,value); + } + + } +} + +void midi_restore_state() { + char name[80]; + char *value; + gint indices; + gint channel; + gint event; + gint onoff; + gint type; + gint action; + gint delay; + gint vfl1, vfl2; + gint fl1, fl2; + gint lft1, lft2; + gint rgt1, rgt2; + gint fr1, fr2; + gint vfr1, vfr2; + + get_midi_devices(); + MidiReleaseCommands(); + + //g_print("%s\n",__FUNCTION__); + + // + // Note this is too early to open the MIDI devices, since the + // radio has not yet fully been configured. Therefore, only + // set the "active" flag, and the devices will be opened in + // radio.c when it is appropriate + // + + for(int i=0; i 15) channel=0; + } + + sprintf(name,"midi[%d].index[%d].delay",i,index); + value=getProperty(name); + delay=0; + if (value) delay=atoi(value); + + sprintf(name,"midi[%d].index[%d].vfl1",i,index); + value=getProperty(name); + vfl1=-1; + if (value) vfl1=atoi(value); + sprintf(name,"midi[%d].index[%d].vfl2",i,index); + value=getProperty(name); + vfl2=-1; + if (value) vfl2=atoi(value); + + sprintf(name,"midi[%d].index[%d].fl1",i,index); + value=getProperty(name); + fl1=-1; + if (value) fl1=atoi(value); + sprintf(name,"midi[%d].index[%d].fl2",i,index); + value=getProperty(name); + fl2=-1; + if (value) fl2=atoi(value); + + sprintf(name,"midi[%d].index[%d].lft1",i,index); + value=getProperty(name); + lft1=0; + if (value) lft1=atoi(value); + sprintf(name,"midi[%d].index[%d].lft2",i,index); + value=getProperty(name); + lft2=63; + if (value) lft2=atoi(value); + + sprintf(name,"midi[%d].index[%d].rgt1",i,index); + value=getProperty(name); + rgt1=65; + if (value) rgt1=atoi(value); + sprintf(name,"midi[%d].index[%d].rgt2",i,index); + value=getProperty(name); + rgt2=127; + if (value) rgt2=atoi(value); + + sprintf(name,"midi[%d].index[%d].fr1",i,index); + value=getProperty(name); + fr1=-1; + if (value) fr1=atoi(value); + sprintf(name,"midi[%d].index[%d].fr2",i,index); + value=getProperty(name); + fr2=-1; + if (value) fr2=atoi(value); + + sprintf(name,"midi[%d].index[%d].vfr1",i,index); + value=getProperty(name); + vfr1=-1; + if (value) vfr1=atoi(value); + sprintf(name,"midi[%d].index[%d].vfr2",i,index); + value=getProperty(name); + vfr2=-1; + if (value) vfr2=atoi(value); + + // ATTENTION: this assumes ActionTable is sorted by Action enums + onoff=ActionTable[action].onoff; + + struct desc *desc = (struct desc *) malloc(sizeof(struct desc)); + + desc->next = NULL; + desc->action = action; // MIDIaction + desc->type = type; // MIDItype + desc->event = event; // MIDevent + desc->onoff = onoff; + desc->delay = delay; + desc->vfl1 = vfl1; + desc->vfl2 = vfl2; + desc->fl1 = fl1; + desc->fl2 = fl2; + desc->lft1 = lft1; + desc->lft2 = lft2; + desc->rgt1 = rgt1; + desc->rgt2 = rgt2; + desc->fr1 = fr1; + desc->fr2 = fr2; + desc->vfr1 = vfr1; + desc->vfr2 = vfr2; + desc->channel = channel; + +//g_print("DESC INIT Note=%3d Action=%3d Type=%3d Event=%3d OnOff=%3d Chan=%3d Delay=%3d THR=%3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d\n", +// i, action, type, event, onoff, channel, delay, +// vfl1, vfl2, fl1, fl2, lft1, lft2, rgt1, rgt2, fr1, fr2, vfr1, vfr2); + MidiAddCommand(i, desc); + } + } + } +} + diff --git a/midi_menu.h b/midi_menu.h new file mode 100644 index 0000000..02220e1 --- /dev/null +++ b/midi_menu.h @@ -0,0 +1,24 @@ +/* Copyright (C) +* 2021 - 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. +* +*/ + +extern void midi_menu(GtkWidget *parent); +extern void NewMidiConfigureEvent(enum MIDIevent event, int channel, int note, int val); +extern void midi_save_state(); +extern void midi_restore_state(); + diff --git a/new_menu.c b/new_menu.c index 9c7bf7c..e1ed1e1 100644 --- a/new_menu.c +++ b/new_menu.c @@ -63,6 +63,10 @@ #ifdef CLIENT_SERVER #include "server_menu.h" #endif +#ifdef MIDI +#include "midi.h" +#include "midi_menu.h" +#endif static GtkWidget *menu_b=NULL; @@ -466,6 +470,18 @@ static gboolean server_cb (GtkWidget *widget, GdkEventButton *event, gpointer da } #endif +#ifdef MIDI +void start_midi() { + cleanup(); + midi_menu(top_window); +} + +static gboolean midi_cb (GtkWidget *widget, GdkEventButton *event, gpointer data) { + start_midi(); + return TRUE; +} +#endif + void new_menu() { int i; @@ -625,6 +641,13 @@ void new_menu() } #endif +#ifdef MIDI + GtkWidget *midi_b=gtk_button_new_with_label("MIDI"); + g_signal_connect (midi_b, "button-press-event", G_CALLBACK(midi_cb), NULL); + gtk_grid_attach(GTK_GRID(grid),midi_b,(i%5),i/5,1,1); + i++; +#endif + // // We need at least two receivers and two ADCs to do DIVERSITY // diff --git a/radio.c b/radio.c index 2e7c649..b7ce5d0 100644 --- a/radio.c +++ b/radio.c @@ -73,10 +73,9 @@ #endif #include "rigctl_menu.h" #ifdef MIDI -// rather than including MIDI.h with all its internal stuff -// (e.g. enum components) we just declare the single bit thereof -// we need here to make a strict compiler happy. -void MIDIstartup(); +#include "midi.h" +#include "alsa_midi.h" +#include "midi_menu.h" #endif #ifdef CLIENT_SERVER #include "client_server.h" @@ -97,6 +96,8 @@ void MIDIstartup(); #define TOOLBAR_HEIGHT (30) #define WATERFALL_HEIGHT (105) +gint controller=NO_CONTROLLER; + GtkWidget *fixed; static GtkWidget *vfo_panel; static GtkWidget *meter; @@ -108,28 +109,30 @@ 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; +*/ +gint sat_mode; - int region=REGION_OTHER; +int region=REGION_OTHER; - int echo=0; +int echo=0; - int radio_sample_rate; - gboolean iqswap; +int radio_sample_rate; +gboolean iqswap; - static gint save_timer_id; +static gint save_timer_id; - DISCOVERED *radio=NULL; +DISCOVERED *radio=NULL; #ifdef CLIENT_SERVER - gboolean radio_is_remote=FALSE; +gboolean radio_is_remote=FALSE; #endif - char property_path[128]; - GMutex property_mutex; +char property_path[128]; +GMutex property_mutex; RECEIVER *receiver[MAX_RECEIVERS]; RECEIVER *active_receiver; @@ -627,7 +630,7 @@ if(!radio_is_remote) { break; #ifdef SOAPYSDR case SOAPYSDR_PROTOCOL: - soapy_protocol_init(0,false); + soapy_protocol_init(FALSE); break; #endif } @@ -1120,16 +1123,17 @@ void start_radio() { #ifdef SOAPYSDR adc[0].antenna=0; if(device==SOAPYSDR_USB_DEVICE) { - adc[0].rx_gain=malloc(radio->info.soapy.rx_gains*sizeof(gint)); - for (size_t i = 0; i < radio->info.soapy.rx_gains; i++) { - adc[0].rx_gain[i]=0; + adc[0].gain=0; + if(radio->info.soapy.rx_gains>0) { + adc[0].min_gain=radio->info.soapy.rx_range[0].minimum; + adc[0].max_gain=radio->info.soapy.rx_range[0].maximum;; + } else { + adc[0].min_gain=0.0; + adc[0].max_gain=100.0; } adc[0].agc=FALSE; dac[0].antenna=1; - dac[0].tx_gain=malloc(radio->info.soapy.tx_gains*sizeof(gint)); - for (size_t i = 0; i < radio->info.soapy.tx_gains; i++) { - dac[0].tx_gain[i]=0; - } + dac[0].gain=0; } #endif @@ -1144,16 +1148,18 @@ void start_radio() { #ifdef SOAPYSDR adc[1].antenna=0; if(device==SOAPYSDR_USB_DEVICE) { - adc[1].rx_gain=malloc(radio->info.soapy.rx_gains*sizeof(gint)); - for (size_t i = 0; i < radio->info.soapy.rx_gains; i++) { - adc[1].rx_gain[i]=0; + adc[1].gain=0; + if(radio->info.soapy.rx_gains>0) { + adc[1].min_gain=radio->info.soapy.rx_range[0].minimum; + adc[1].max_gain=radio->info.soapy.rx_range[0].maximum;; + } else { + adc[1].min_gain=0.0; + adc[1].max_gain=100.0; } + adc[1].max_gain=0; adc[1].agc=FALSE; - - dac[1].tx_gain=malloc(radio->info.soapy.tx_gains*sizeof(gint)); - for (size_t i = 0; i < radio->info.soapy.tx_gains; i++) { - dac[1].tx_gain[i]=0; - } + dac[1].antenna=1; + dac[1].gain=0; } radio_sample_rate=radio->info.soapy.sample_rate; @@ -1258,28 +1264,15 @@ void start_radio() { if(can_transmit) { soapy_protocol_create_transmitter(transmitter); soapy_protocol_set_tx_antenna(transmitter,dac[0].antenna); -/* - for(int i=0;iinfo.soapy.tx_gains;i++) { - soapy_protocol_set_tx_gain_element(transmitter,radio->info.soapy.tx_gain[i],dac[0].tx_gain[i]); - } -*/ soapy_protocol_set_tx_gain(transmitter,transmitter->drive); soapy_protocol_set_tx_frequency(transmitter); soapy_protocol_start_transmitter(transmitter); } soapy_protocol_set_rx_antenna(rx,adc[0].antenna); -/* - for(int i=0;iinfo.soapy.rx_gains;i++) { - soapy_protocol_set_gain_element(rx,radio->info.soapy.rx_gain[i],adc[0].rx_gain[i]); - } -*/ - soapy_protocol_set_rx_frequency(rx,VFO_A); soapy_protocol_set_automatic_gain(rx,adc[0].agc); - for(int i=0;iinfo.soapy.rx_gains;i++) { - soapy_protocol_set_gain_element(rx,radio->info.soapy.rx_gain[i],adc[0].rx_gain[i]); - } + soapy_protocol_set_gain(rx); if(vfo[0].ctun) { setFrequency(vfo[0].ctun_frequency); @@ -1287,7 +1280,7 @@ void start_radio() { soapy_protocol_start_receiver(rx); //g_print("radio: set rf_gain=%f\n",rx->rf_gain); - soapy_protocol_set_gain(rx,rx->rf_gain); + soapy_protocol_set_gain(rx); } #endif @@ -1296,13 +1289,25 @@ void start_radio() { gdk_window_set_cursor(gtk_widget_get_window(top_window),gdk_cursor_new(GDK_ARROW)); +#ifdef MIDI // - // MIDIstartup must not be called before the radio is completely set up, since - // then MIDI can asynchronously trigger actions which require the radio already - // running. So this is the last thing we do when starting the radio. + // The MIDI devices could not be opened in midi_restore_state() since MIDI events + // must not fly in before the radio is fully configured. Therefore midi_restore_state() + // simply marks the devices to be opened here by hi-jacking the "active" flag. Note that + // apart from this (ab)use, this flag is updated ONLY in register_midi_device() and + // close_midi_device(). // -#ifdef MIDI - MIDIstartup(); + for (i=0; iinfo.soapy.rx_gain[0],(int)adc[0].gain); break; #endif } @@ -2080,9 +2085,7 @@ g_print("radioRestoreState: %s\n",property_path); memRestoreState(); vfo_restore_state(); modesettings_restore_state(); -#ifdef GPIO gpio_restore_actions(); -#endif value=getProperty("rigctl_enable"); if(value) rigctl_enable=atoi(value); value=getProperty("rigctl_port_base"); @@ -2094,10 +2097,12 @@ g_print("radioRestoreState: %s\n",property_path); value=getProperty("rigctl_serial_port"); if (value) strcpy(ser_port,value); + /* value=getProperty("adc_0_attenuation"); if(value) adc_attenuation[0]=atoi(value); value=getProperty("adc_1_attenuation"); if(value) adc_attenuation[1]=atoi(value); + */ value=getProperty("split"); if(value) split=atoi(value); @@ -2108,27 +2113,85 @@ g_print("radioRestoreState: %s\n",property_path); value=getProperty("mute_rx_while_transmitting"); if(value) mute_rx_while_transmitting=atoi(value); -#ifdef SOAPYSDR + value=getProperty("radio.adc[0].filters"); + if(value) adc[0].filters=atoi(value); + value=getProperty("radio.adc[0].hpf"); + if(value) adc[0].hpf=atoi(value); + value=getProperty("radio.adc[0].lpf"); + if(value) adc[0].lpf=atoi(value); + value=getProperty("radio.adc[0].antenna"); + if(value) adc[0].antenna=atoi(value); + value=getProperty("radio.adc[0].dither"); + if(value) adc[0].dither=atoi(value); + value=getProperty("radio.adc[0].random"); + if(value) adc[0].random=atoi(value); + value=getProperty("radio.adc[0].preamp"); + if(value) adc[0].preamp=atoi(value); + value=getProperty("radio.adc[0].attenuation"); + if(value) adc[0].attenuation=atoi(value); + value=getProperty("radio.adc[0].enable_step_attenuation"); + if(value) adc[0].enable_step_attenuation=atoi(value); + value=getProperty("radio.adc[0].gain"); + if(value) adc[0].gain=atof(value); + value=getProperty("radio.adc[0].min_gain"); + if(value) adc[0].min_gain=atof(value); + value=getProperty("radio.adc[0].max_gain"); + if(value) adc[0].max_gain=atof(value); + +#ifdef SOAPYSDR if(device==SOAPYSDR_USB_DEVICE) { - char name[128]; - for(int i=0;iinfo.soapy.rx_gains;i++) { - sprintf(name,"radio.adc[0].rx_gain.%s",radio->info.soapy.rx_gain[i]) ; - value=getProperty(name); - if(value!=NULL) adc[0].rx_gain[i]=atoi(value); - } value=getProperty("radio.adc[0].agc"); - if(value!=NULL) adc[0].agc=atoi(value); - value=getProperty("radio.adc[0].antenna"); - if(value!=NULL) adc[0].antenna=atoi(value); - - value=getProperty("radio.dac[0].antenna"); - if(value!=NULL) dac[0].antenna=atoi(value); - for(int i=0;iinfo.soapy.tx_gains;i++) { - sprintf(name,"radio.dac[0].tx_gain.%s",radio->info.soapy.tx_gain[i]); - value=getProperty(name); - if(value!=NULL) dac[0].tx_gain[i]=atoi(value); + if(value) adc[0].agc=atoi(value); + } +#endif + value=getProperty("radio.dac[0].antenna"); + if(value) dac[0].antenna=atoi(value); + value=getProperty("radio.dac[0].gain"); + if(value) dac[0].gain=atof(value); + + if(receivers>1) { + value=getProperty("radio.adc[1].filters"); + if(value) adc[1].filters=atoi(value); + value=getProperty("radio.adc[1].hpf"); + if(value) adc[1].hpf=atoi(value); + value=getProperty("radio.adc[1].lpf"); + if(value) adc[1].lpf=atoi(value); + value=getProperty("radio.adc[1].antenna"); + if(value) adc[1].antenna=atoi(value); + value=getProperty("radio.adc[1].dither"); + if(value) adc[1].dither=atoi(value); + value=getProperty("radio.adc[1].random"); + if(value) adc[1].random=atoi(value); + value=getProperty("radio.adc[1].preamp"); + if(value) adc[1].preamp=atoi(value); + value=getProperty("radio.adc[1].attenuation"); + if(value) adc[1].attenuation=atoi(value); + value=getProperty("radio.adc[1].enable_step_attenuation"); + if(value) adc[1].enable_step_attenuation=atoi(value); + value=getProperty("radio.adc[1].gain"); + if(value) adc[1].gain=atof(value); + value=getProperty("radio.adc[1].min_gain"); + if(value) adc[1].min_gain=atof(value); + value=getProperty("radio.adc[1].max_gain"); + if(value) adc[1].max_gain=atof(value); + + +#ifdef SOAPYSDR + if(device==SOAPYSDR_USB_DEVICE) { + value=getProperty("radio.adc[1].agc"); + if(value) adc[1].agc=atoi(value); } +#endif + + value=getProperty("radio.dac[1].antenna"); + if(value) dac[1].antenna=atoi(value); + value=getProperty("radio.dac[1].gain"); + if(value) dac[1].gain=atof(value); + } + +#ifdef MIDI + midi_restore_state(); #endif value=getProperty("radio.display_sequence_errors"); @@ -2354,63 +2417,87 @@ g_print("radioSaveState: %s\n",property_path); sprintf(value,"%f",tone_level); setProperty("tone_level",value); + /* sprintf(value,"%d",adc_attenuation[0]); setProperty("adc_0_attenuation",value); sprintf(value,"%d",adc_attenuation[1]); setProperty("adc_1_attenuation",value); + */ sprintf(value,"%d",rx_gain_calibration); setProperty("rx_gain_calibration",value); -#ifdef SOAPYSDR + sprintf(value,"%d", adc[0].filters); + setProperty("radio.adc[0].filters",value); + sprintf(value,"%d", adc[0].hpf); + setProperty("radio.adc[0].hpf",value); + sprintf(value,"%d", adc[0].lpf); + setProperty("radio.adc[0].lpf",value); + sprintf(value,"%d", adc[0].antenna); + setProperty("radio.adc[0].antenna",value); + sprintf(value,"%d", adc[0].dither); + setProperty("radio.adc[0].dither",value); + sprintf(value,"%d", adc[0].random); + setProperty("radio.adc[0].random",value); + sprintf(value,"%d", adc[0].preamp); + setProperty("radio.adc[0].preamp",value); + sprintf(value,"%d", adc[0].attenuation); + setProperty("radio.adc[0].attenuation",value); + sprintf(value,"%d", adc[0].enable_step_attenuation); + setProperty("radio.adc[0].enable_step_attenuation",value); + sprintf(value,"%f", adc[0].gain); + setProperty("radio.adc[0].gain",value); + sprintf(value,"%f", adc[0].min_gain); + setProperty("radio.adc[0].min_gain",value); + sprintf(value,"%f", adc[0].max_gain); + setProperty("radio.adc[0].max_gain",value); + + +#ifdef SOAPYSDR if(device==SOAPYSDR_USB_DEVICE) { - char name[128]; - for(int i=0;iinfo.soapy.rx_gains;i++) { - sprintf(name,"radio.adc[0].rx_gain.%s",radio->info.soapy.rx_gain[i]); - sprintf(value,"%d", adc[0].rx_gain[i]); - setProperty(name,value); - } - sprintf(name,"radio.adc[0].agc"); sprintf(value,"%d", soapy_protocol_get_automatic_gain(receiver[0])); - setProperty(name,value); - sprintf(name,"radio.adc[0].antenna"); - sprintf(value,"%d", adc[0].antenna); - setProperty(name,value); - - sprintf(name,"radio.dac[0].antenna"); - sprintf(value,"%d", dac[0].antenna); - setProperty(name,value); - - for(int i=0;iinfo.soapy.tx_gains;i++) { - sprintf(name,"radio.dac[0].tx_gain.%s",radio->info.soapy.tx_gain[i]); - sprintf(value,"%d", dac[0].tx_gain[i]); - setProperty(name,value); - } + setProperty("radio.adc[0].agc",value); + } +#endif - for(int i=0;iinfo.soapy.rx_gains;i++) { - sprintf(name,"radio.adc[1].rx_gain.%s",radio->info.soapy.rx_gain[i]); - sprintf(value,"%d", adc[1].rx_gain[i]); - setProperty(name,value); - } - sprintf(name,"radio.adc[1].agc"); - sprintf(value,"%d", soapy_protocol_get_automatic_gain(receiver[1])); - setProperty(name,value); - sprintf(name,"radio.adc[1].antenna"); + if(receivers>1) { + sprintf(value,"%d", adc[1].filters); + setProperty("radio.adc[1].filters",value); + sprintf(value,"%d", adc[1].hpf); + setProperty("radio.adc[1].hpf",value); + sprintf(value,"%d", adc[1].lpf); + setProperty("radio.adc[1].lpf",value); sprintf(value,"%d", adc[1].antenna); - setProperty(name,value); - - sprintf(name,"radio.dac[1].antenna"); - sprintf(value,"%d", dac[1].antenna); - setProperty(name,value); - - for(int i=0;iinfo.soapy.tx_gains;i++) { - sprintf(name,"radio.dac[1].tx_gain.%s",radio->info.soapy.tx_gain[i]); - sprintf(value,"%d", dac[1].tx_gain[i]); - setProperty(name,value); + setProperty("radio.adc[1].antenna",value); + sprintf(value,"%d", adc[1].dither); + setProperty("radio.adc[1].dither",value); + sprintf(value,"%d", adc[1].random); + setProperty("radio.adc[1].random",value); + sprintf(value,"%d", adc[1].preamp); + setProperty("radio.adc[1].preamp",value); + sprintf(value,"%d", adc[1].attenuation); + setProperty("radio.adc[1].attenuation",value); + sprintf(value,"%d", adc[1].enable_step_attenuation); + setProperty("radio.adc[1].enable_step_attenuation",value); + sprintf(value,"%f", adc[1].gain); + setProperty("radio.adc[1].gain",value); + sprintf(value,"%f", adc[1].min_gain); + setProperty("radio.adc[1].min_gain",value); + sprintf(value,"%f", adc[1].max_gain); + setProperty("radio.adc[1].max_gain",value); + +#ifdef SOAPYSDR + if(device==SOAPYSDR_USB_DEVICE) { + sprintf(value,"%d", soapy_protocol_get_automatic_gain(receiver[1])); + setProperty("radio.adc[1].agc",value); } - } #endif + sprintf(value,"%d", dac[1].antenna); + setProperty("radio.dac[1].antenna",value); + sprintf(value,"%f", dac[1].gain); + setProperty("radio.dac[1].gain",value); + } sprintf(value,"%d",receivers); setProperty("receivers",value); @@ -2457,6 +2544,10 @@ g_print("radioSaveState: %s\n",property_path); } #endif +#ifdef MIDI + midi_save_state(); +#endif + saveProperties(property_path); g_mutex_unlock(&property_mutex); } @@ -2564,9 +2655,6 @@ int remote_start(void *data) { reconfigure_radio(); g_idle_add(ext_vfo_update,(gpointer)NULL); gdk_window_set_cursor(gtk_widget_get_window(top_window),gdk_cursor_new(GDK_ARROW)); -#ifdef MIDI - MIDIstartup(); -#endif for(int i=0;irf_gain=gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget)); - - if(radio->device==SOAPYSDR_USB_DEVICE) { - soapy_protocol_set_gain(receiver[0],active_receiver->rf_gain); - } + adc->gain=gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget)); -/* - for(int i=0;iinfo.soapy.rx_gains;i++) { - int value=soapy_protocol_get_gain_element(active_receiver,radio->info.soapy.rx_gain[i]); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(rx_gains[i]),(double)value); + if(radio->device==SOAPYSDR_USB_DEVICE) { + soapy_protocol_set_gain(receiver[0]); } -*/ - } static void rx_gain_value_changed_cb(GtkWidget *widget, gpointer data) { ADC *adc=(ADC *)data; - int gain; if(radio->device==SOAPYSDR_USB_DEVICE) { - gain=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget)); - soapy_protocol_set_gain_element(receiver[0],(char *)gtk_widget_get_name(widget),gain); - + adc->gain=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget)); + soapy_protocol_set_gain_element(receiver[0],(char *)gtk_widget_get_name(widget),adc->gain); /* for(int i=0;iinfo.soapy.rx_gains;i++) { if(strcmp(radio->info.soapy.rx_gain[i],(char *)gtk_widget_get_name(widget))==0) { adc[0].rx_gain[i]=gain; + soapy_protocol_set_gain_element(receiver[0],(char *)gtk_widget_get_name(widget),gain); break; } } */ - } } @@ -150,7 +140,10 @@ static void tx_gain_value_changed_cb(GtkWidget *widget, gpointer data) { static void agc_changed_cb(GtkWidget *widget, gpointer data) { ADC *adc=(ADC *)data; gboolean agc=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); - soapy_protocol_set_automatic_gain(receiver[0],agc); + soapy_protocol_set_automatic_gain(active_receiver,agc); + if(!agc) { + soapy_protocol_set_gain(active_receiver); + } } /* @@ -546,21 +539,44 @@ void radio_menu(GtkWidget *parent) { #ifdef SOAPYSDR case SOAPYSDR_PROTOCOL: - { - GtkWidget *sample_rate_label=gtk_label_new(NULL); - gtk_label_set_markup(GTK_LABEL(sample_rate_label), "Sample Rate:"); - gtk_grid_attach(GTK_GRID(grid),sample_rate_label,col,row,1,1); - row++; + if(strcmp(radio->name,"sdrplay")==0) { + GtkWidget *sample_rate_combo_box=gtk_combo_box_text_new(); +// gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(sample_rate_combo_box),NULL,"96000"); +// gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(sample_rate_combo_box),NULL,"192000"); +// gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(sample_rate_combo_box),NULL,"384000"); + gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(sample_rate_combo_box),NULL,"768000"); + switch(radio_sample_rate) { + case 96000: + gtk_combo_box_set_active(GTK_COMBO_BOX(sample_rate_combo_box),0); + break; + case 192000: + gtk_combo_box_set_active(GTK_COMBO_BOX(sample_rate_combo_box),1); + break; + case 384000: + gtk_combo_box_set_active(GTK_COMBO_BOX(sample_rate_combo_box),2); + break; + case 768000: + gtk_combo_box_set_active(GTK_COMBO_BOX(sample_rate_combo_box),3); + break; + } + g_signal_connect(sample_rate_combo_box,"changed",G_CALLBACK(sample_rate_cb),radio); + gtk_grid_attach(GTK_GRID(grid),sample_rate_combo_box,col,row,1,1); + row++; + } else { + GtkWidget *sample_rate_label=gtk_label_new(NULL); + gtk_label_set_markup(GTK_LABEL(sample_rate_label), "Sample Rate:"); + gtk_grid_attach(GTK_GRID(grid),sample_rate_label,col,row,1,1); + row++; - char rate[16]; - sprintf(rate,"%d",radio->info.soapy.sample_rate); + char rate[16]; + sprintf(rate,"%d",radio->info.soapy.sample_rate); - GtkWidget *sample_rate=gtk_radio_button_new_with_label(NULL,rate); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (sample_rate), radio->info.soapy.sample_rate); - gtk_grid_attach(GTK_GRID(grid),sample_rate,col,row,1,1); - g_signal_connect(sample_rate,"toggled",G_CALLBACK(sample_rate_cb),GINT_TO_POINTER(radio->info.soapy.sample_rate)); + GtkWidget *sample_rate=gtk_radio_button_new_with_label(NULL,rate); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (sample_rate), radio->info.soapy.sample_rate); + gtk_grid_attach(GTK_GRID(grid),sample_rate,col,row,1,1); + g_signal_connect(sample_rate,"toggled",G_CALLBACK(sample_rate_cb),GINT_TO_POINTER(radio->info.soapy.sample_rate)); - col++; + col++; } break; #endif diff --git a/rx_panadapter.c b/rx_panadapter.c index c60cd7c..12bacc5 100644 --- a/rx_panadapter.c +++ b/rx_panadapter.c @@ -38,6 +38,7 @@ #include "rx_panadapter.h" #include "vfo.h" #include "mode.h" +#include "actions.h" #ifdef GPIO #include "gpio.h" #endif @@ -365,6 +366,7 @@ void rx_panadapter_update(RECEIVER *rx) { } f = ((min_display/divisor)*divisor)+divisor; + cairo_select_font_face(cr, DISPLAY_FONT, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); @@ -419,13 +421,13 @@ void rx_panadapter_update(RECEIVER *rx) { // agc if(rx->agc!=AGC_OFF) { - double knee_y=rx->agc_thresh+(double)adc_attenuation[rx->adc]; + double knee_y=rx->agc_thresh+(double)adc[rx->adc].attenuation; if (filter_board == ALEX && rx->adc == 0) knee_y += (double)(10*rx->alex_attenuation); knee_y = floor((rx->panadapter_high - knee_y) * (double) display_height / (rx->panadapter_high - rx->panadapter_low)); - double hang_y=rx->agc_hang+(double)adc_attenuation[rx->adc]; + double hang_y=rx->agc_hang+(double)adc[rx->adc].attenuation; if (filter_board == ALEX && rx->adc == 0) hang_y += (double)(10*rx->alex_attenuation); hang_y = floor((rx->panadapter_high - hang_y) * (double) display_height @@ -487,9 +489,9 @@ void rx_panadapter_update(RECEIVER *rx) { samples[pan]=-200.0; samples[display_width-1+pan]=-200.0; if(have_rx_gain) { - s1=(double)samples[pan]+rx_gain_calibration-adc_attenuation[rx->adc]; + s1=(double)samples[pan]+rx_gain_calibration-adc[rx->adc].attenuation; } else { - s1=(double)samples[pan]+(double)adc_attenuation[rx->adc]; + s1=(double)samples[pan]+(double)adc[rx->adc].attenuation; } cairo_move_to(cr, 0.0, s1); if (filter_board == ALEX && rx->adc == 0) s1 += (double)(10*rx->alex_attenuation); @@ -499,7 +501,8 @@ void rx_panadapter_update(RECEIVER *rx) { } #ifdef SOAPYSDR if(protocol==SOAPYSDR_PROTOCOL) { - s1-=rx->rf_gain; + //s1-=rx->rf_gain; + s1-=adc[rx->id].gain; } #endif @@ -509,9 +512,9 @@ void rx_panadapter_update(RECEIVER *rx) { cairo_move_to(cr, 0.0, s1); for(i=1;iadc]; + s2=(double)samples[i+pan]+rx_gain_calibration-adc[rx->adc].attenuation; } else { - s2=(double)samples[i+pan]+(double)adc_attenuation[rx->adc]; + s2=(double)samples[i+pan]+(double)adc[rx->adc].attenuation; } if (filter_board == ALEX && rx->adc == 0) s2 += (double)(10*rx->alex_attenuation); if (filter_board == CHARLY25) { @@ -520,7 +523,8 @@ void rx_panadapter_update(RECEIVER *rx) { } #ifdef SOAPYSDR if(protocol==SOAPYSDR_PROTOCOL) { - s2-=rx->rf_gain; + //s2-=rx->rf_gain; + s2-=adc[rx->id].gain; } #endif s2 = floor((rx->panadapter_high - s2) @@ -529,8 +533,7 @@ void rx_panadapter_update(RECEIVER *rx) { cairo_line_to(cr, (double)i, s2); } - cairo_pattern_t *gradient; - gradient=NULL; + cairo_pattern_t *gradient=NULL; if(display_gradient) { gradient = cairo_pattern_create_linear(0.0, display_height, 0.0, 0.0); // calculate where S9 is @@ -576,12 +579,14 @@ void rx_panadapter_update(RECEIVER *rx) { // cairo_set_line_width(cr, 1.0); } + cairo_set_line_width(cr, LINE_WIDTH); cairo_stroke(cr); if(gradient) { cairo_pattern_destroy(gradient); } +/* #ifdef GPIO if(rx->id==0 && controller==CONTROLLER1) { @@ -606,7 +611,7 @@ void rx_panadapter_update(RECEIVER *rx) { } } #endif - +*/ if(display_sequence_errors) { if(sequence_errors!=0) { cairo_move_to(cr,100.0,50.0); diff --git a/sliders.c b/sliders.c index 76163ed..7df32b5 100644 --- a/sliders.c +++ b/sliders.c @@ -389,26 +389,33 @@ void set_af_gain(int rx,double value) { static void rf_gain_value_changed_cb(GtkWidget *widget, gpointer data) { active_receiver->rf_gain=gtk_range_get_value(GTK_RANGE(af_gain_scale)); + switch(protocol) { #ifdef SOAPYSDR - if(protocol==SOAPYSDR_PROTOCOL) { - soapy_protocol_set_gain(active_receiver,active_receiver->rf_gain); - } + case SOAPYSDR_PROTOCOL: + soapy_protocol_set_gain(active_receiver); + break; #endif + default: + break; + } } void update_rf_gain() { - set_rf_gain(active_receiver->id,active_receiver->rf_gain); + //set_rf_gain(active_receiver->id,active_receiver->rf_gain); + set_rf_gain(active_receiver->id,adc[active_receiver->id].gain); } void set_rf_gain(int rx,double value) { - receiver[rx]->rf_gain=value; + g_print("%s\n",__FUNCTION__); + adc[receiver[rx]->id].gain=value; #ifdef SOAPYSDR if(protocol==SOAPYSDR_PROTOCOL) { - soapy_protocol_set_gain(active_receiver,active_receiver->rf_gain); + soapy_protocol_set_gain(receiver[rx]); } #endif if(display_sliders) { - gtk_range_set_value (GTK_RANGE(attenuation_scale),receiver[rx]->rf_gain); + //gtk_range_set_value (GTK_RANGE(attenuation_scale),receiver[rx]->rf_gain); + gtk_range_set_value (GTK_RANGE(rf_gain_scale),adc[receiver[rx]->id].gain); } else { if(scale_status!=RF_GAIN || scale_rx!=rx) { if(scale_status!=NO_FUNCTION) { @@ -426,7 +433,8 @@ void set_rf_gain(int rx,double value) { GtkWidget *content=gtk_dialog_get_content_area(GTK_DIALOG(scale_dialog)); rf_gain_scale=gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL,0.0, 100.0, 1.00); gtk_widget_set_size_request (rf_gain_scale, 400, 30); - gtk_range_set_value (GTK_RANGE(rf_gain_scale),receiver[rx]->rf_gain); + //gtk_range_set_value (GTK_RANGE(rf_gain_scale),receiver[rx]->rf_gain); + gtk_range_set_value (GTK_RANGE(rf_gain_scale),adc[receiver[rx]->id].gain); gtk_widget_show(rf_gain_scale); gtk_container_add(GTK_CONTAINER(content),rf_gain_scale); scale_timer=g_timeout_add(2000,scale_timeout_cb,NULL); @@ -434,7 +442,8 @@ void set_rf_gain(int rx,double value) { gtk_dialog_run(GTK_DIALOG(scale_dialog)); } else { g_source_remove(scale_timer); - gtk_range_set_value (GTK_RANGE(rf_gain_scale),receiver[rx]->rf_gain); + //gtk_range_set_value (GTK_RANGE(rf_gain_scale),receiver[rx]->rf_gain); + gtk_range_set_value (GTK_RANGE(rf_gain_scale),adc[receiver[rx]->id].gain); scale_timer=g_timeout_add(2000,scale_timeout_cb,NULL); } } diff --git a/soapy_protocol.c b/soapy_protocol.c index c10550a..1c111ef 100644 --- a/soapy_protocol.c +++ b/soapy_protocol.c @@ -26,6 +26,7 @@ #include "SoapySDR/Device.h" #include "SoapySDR/Formats.h" #include "SoapySDR/Version.h" +#include "SoapySDR/Logger.h" //#define TIMING #ifdef TIMING @@ -39,12 +40,8 @@ #include "filter.h" #include "receiver.h" #include "transmitter.h" -//#include "wideband.h" -//#include "adc.h" -//#include "dac.h" #include "radio.h" #include "main.h" -//#include "protocol1.h" #include "soapy_protocol.h" #include "audio.h" #include "signal.h" @@ -52,15 +49,17 @@ #include "ext.h" #include "error_handler.h" -static double bandwidth=2000000.0; -static SoapySDRDevice *soapy_device; -static SoapySDRStream *rx_stream; +#define MAX_CHANNELS 2 +static SoapySDRStream *rx_stream[MAX_CHANNELS]; static SoapySDRStream *tx_stream; +static SoapySDRDevice *soapy_device; static int max_samples; static int samples=0; +static double bandwidth=2000000.0; + static GThread *receive_thread_id; static gpointer receive_thread(gpointer data); @@ -88,8 +87,16 @@ void soapy_protocol_set_mic_sample_rate(int rate) { } void soapy_protocol_change_sample_rate(RECEIVER *rx) { + int rc; + // rx->mutex already locked - if(rx->sample_rate==radio_sample_rate) { + if(strcmp(radio->name,"sdrplay")==0) { + g_print("%s: setting samplerate=%f\n",__FUNCTION__,(double)rx->sample_rate); + rc=SoapySDRDevice_setSampleRate(soapy_device,SOAPY_SDR_RX,rx->adc,(double)rx->sample_rate); + if(rc!=0) { + g_print("%s: SoapySDRDevice_setSampleRate(%f) failed: %s\n",__FUNCTION__,(double)rx->sample_rate,SoapySDR_errToStr(rc)); + } + } else if(rx->sample_rate==radio_sample_rate) { if(rx->resample_buffer!=NULL) { g_free(rx->resample_buffer); rx->resample_buffer=NULL; @@ -121,41 +128,42 @@ void soapy_protocol_create_receiver(RECEIVER *rx) { mic_sample_divisor=rx->sample_rate/48000; -fprintf(stderr,"soapy_protocol_create_receiver: setting samplerate=%f adc=%d mic_sample_divisor=%d\n",(double)radio_sample_rate,rx->adc,mic_sample_divisor); + g_print("%s: device=%p adc=%d setting bandwidth=%f\n",__FUNCTION__,soapy_device,rx->adc,bandwidth); + rc=SoapySDRDevice_setBandwidth(soapy_device,SOAPY_SDR_RX,rx->adc,bandwidth); + if(rc!=0) { + g_print("%s: SoapySDRDevice_setBandwidth(%f) failed: %s\n",__FUNCTION__,(double)bandwidth,SoapySDR_errToStr(rc)); + } + + g_print("%s: setting samplerate=%f device=%p adc=%d mic_sample_divisor=%d\n",__FUNCTION__,(double)radio_sample_rate,soapy_device,rx->adc,mic_sample_divisor); rc=SoapySDRDevice_setSampleRate(soapy_device,SOAPY_SDR_RX,rx->adc,(double)radio_sample_rate); if(rc!=0) { - fprintf(stderr,"soapy_protocol_create_receiver: SoapySDRDevice_setSampleRate(%f) failed: %s\n",(double)radio_sample_rate,SoapySDR_errToStr(rc)); + g_print("%s: SoapySDRDevice_setSampleRate(%f) failed: %s\n",__FUNCTION__,(double)radio_sample_rate,SoapySDR_errToStr(rc)); } size_t channel=rx->adc; #if defined(SOAPY_SDR_API_VERSION) && (SOAPY_SDR_API_VERSION < 0x00080000) -fprintf(stderr,"soapy_protocol_create_receiver: SoapySDRDevice_setupStream(version<0x00080000): channel=%ld\n",channel); - rc=SoapySDRDevice_setupStream(soapy_device,&rx_stream,SOAPY_SDR_RX,SOAPY_SDR_CF32,&channel,1,NULL); + g_print("%s: SoapySDRDevice_setupStream(version<0x00080000): channel=%ld\n",__FUNCTION__,channel); + rc=SoapySDRDevice_setupStream(soapy_device,&rx_stream[channel],SOAPY_SDR_RX,SOAPY_SDR_CF32,&channel,1,NULL); if(rc!=0) { - fprintf(stderr,"soapy_protocol_create_receiver: SoapySDRDevice_setupStream (RX) failed: %s\n",SoapySDR_errToStr(rc)); + g_print("%s: SoapySDRDevice_setupStream (RX) failed: %s\n",__FUNCTION__,SoapySDR_errToStr(rc)); _exit(-1); } #else -fprintf(stderr,"soapy_protocol_create_receiver: SoapySDRDevice_setupStream(version>=0x00080000): channel=%ld\n",channel); - rx_stream=SoapySDRDevice_setupStream(soapy_device,SOAPY_SDR_RX,SOAPY_SDR_CF32,&channel,1,NULL); - if(rx_stream==NULL) { - fprintf(stderr,"soapy_protocol_create_receiver: SoapySDRDevice_setupStream (RX) failed (rx_stream is NULL)\n"); + g_print("%s: SoapySDRDevice_setupStream(version>=0x00080000): channel=%ld\n",__FUNCTION__,channel); + rx_stream[channel]=SoapySDRDevice_setupStream(soapy_device,SOAPY_SDR_RX,SOAPY_SDR_CF32,&channel,1,NULL); + if(rx_stream[channel]==NULL) { + g_print("%s: SoapySDRDevice_setupStream (RX) failed (rx_stream is NULL)\n",__FUNCTION__); _exit(-1); } #endif + g_print("%s: id=%d soapy_device=%p rx_stream=%p\n",__FUNCTION__,rx->id,soapy_device,rx_stream); - max_samples=SoapySDRDevice_getStreamMTU(soapy_device,rx_stream); + max_samples=SoapySDRDevice_getStreamMTU(soapy_device,rx_stream[channel]); + g_print("%s: max_samples=%d\n",__FUNCTION__,max_samples); if(max_samples>(2*rx->fft_size)) { max_samples=2*rx->fft_size; } - if(max_samples>=4096) { - max_samples=4096; - } else if(max_samples>=2048) { - max_samples=2048; - } else { - max_samples=1024; - } rx->buffer=g_new(double,max_samples*2); if(rx->sample_rate==radio_sample_rate) { @@ -169,54 +177,58 @@ fprintf(stderr,"soapy_protocol_create_receiver: SoapySDRDevice_setupStream(versi } -fprintf(stderr,"soapy_protocol_create_receiver: max_samples=%d buffer=%p\n",max_samples,rx->buffer); +g_print("%s: max_samples=%d buffer=%p\n",__FUNCTION__,max_samples,rx->buffer); } void soapy_protocol_start_receiver(RECEIVER *rx) { int rc; -double rate=SoapySDRDevice_getSampleRate(soapy_device,SOAPY_SDR_RX,rx->adc); -fprintf(stderr,"soapy_protocol_start_receiver: activate_stream rate=%f\n",rate); - rc=SoapySDRDevice_activateStream(soapy_device, rx_stream, 0, 0LL, 0); + g_print("%s: id=%d soapy_device=%p rx_stream=%p\n",__FUNCTION__,rx->id,soapy_device,rx_stream); + + size_t channel=rx->adc; + double rate=SoapySDRDevice_getSampleRate(soapy_device,SOAPY_SDR_RX,rx->adc); + g_print("%s: rate=%f\n",__FUNCTION__,rate); + + g_print("%s: activate Stream\n",__FUNCTION__); + rc=SoapySDRDevice_activateStream(soapy_device, rx_stream[channel], 0, 0LL, 0); if(rc!=0) { - fprintf(stderr,"soapy_protocol_start_receiver: SoapySDRDevice_activateStream failed: %s\n",SoapySDR_errToStr(rc)); + g_print("%s: SoapySDRDevice_activateStream failed: %s\n",__FUNCTION__,SoapySDR_errToStr(rc)); _exit(-1); } -fprintf(stderr,"soapy_protocol_start_receiver: create receive_thread\n"); + g_print("%s: create receiver_thread\n",__FUNCTION__); receive_thread_id = g_thread_new( "soapy_rx", receive_thread, rx); if( ! receive_thread_id ) { - fprintf(stderr,"g_thread_new failed for receive_thread\n"); + g_print("%s: g_thread_new failed for receive_thread\n",__FUNCTION__); exit( -1 ); } - fprintf(stderr, "receive_thread: id=%p\n",receive_thread_id); + g_print("%s: receiver_thread_id=%p\n",__FUNCTION__,receive_thread_id); } void soapy_protocol_create_transmitter(TRANSMITTER *tx) { int rc; - -fprintf(stderr,"soapy_protocol_create_transmitter: setting samplerate=%f\n",(double)tx->iq_output_rate); + g_print("%s: setting samplerate=%f\n",__FUNCTION__,(double)tx->iq_output_rate); rc=SoapySDRDevice_setSampleRate(soapy_device,SOAPY_SDR_TX,tx->dac,(double)tx->iq_output_rate); if(rc!=0) { - fprintf(stderr,"soapy_protocol_configure_transmitter: SoapySDRDevice_setSampleRate(%f) failed: %s\n",(double)tx->iq_output_rate,SoapySDR_errToStr(rc)); + g_print("%s: SoapySDRDevice_setSampleRate(%f) failed: %s\n",__FUNCTION__,(double)tx->iq_output_rate,SoapySDR_errToStr(rc)); } size_t channel=tx->dac; -fprintf(stderr,"soapy_protocol_create_transmitter: SoapySDRDevice_setupStream: channel=%ld\n",channel); + g_print("%s: SoapySDRDevice_setupStream: channel=%ld\n",__FUNCTION__,channel); #if defined(SOAPY_SDR_API_VERSION) && (SOAPY_SDR_API_VERSION < 0x00080000) rc=SoapySDRDevice_setupStream(soapy_device,&tx_stream,SOAPY_SDR_TX,SOAPY_SDR_CF32,&channel,1,NULL); if(rc!=0) { - fprintf(stderr,"soapy_protocol_create_transmitter: SoapySDRDevice_setupStream (RX) failed: %s\n",SoapySDR_errToStr(rc)); + g_print("%s: SoapySDRDevice_setupStream (RX) failed: %s\n",__FUNCTION__,SoapySDR_errToStr(rc)); _exit(-1); } #else tx_stream=SoapySDRDevice_setupStream(soapy_device,SOAPY_SDR_TX,SOAPY_SDR_CF32,&channel,1,NULL); if(tx_stream==NULL) { - fprintf(stderr,"soapy_protocol_create_transmitter: SoapySDRDevice_setupStream (TX) failed: %s\n",SoapySDR_errToStr(rc)); + g_print("%s: SoapySDRDevice_setupStream (TX) failed: %s\n",__FUNCTION__,SoapySDR_errToStr(rc)); _exit(-1); } #endif @@ -225,7 +237,7 @@ fprintf(stderr,"soapy_protocol_create_transmitter: SoapySDRDevice_setupStream: c if(max_tx_samples>(2*tx->fft_size)) { max_tx_samples=2*tx->fft_size; } -fprintf(stderr,"soapy_protocol_create_transmitter: max_tx_samples=%d\n",max_tx_samples); + g_print("%s: max_tx_samples=%d\n",__FUNCTION__,max_tx_samples); output_buffer=(float *)malloc(max_tx_samples*sizeof(float)*2); } @@ -253,38 +265,46 @@ fprintf(stderr,"soapy_protocol_stop_transmitter: deactivateStream\n"); } } -void soapy_protocol_init(int rx,gboolean hf) { +void soapy_protocol_init(gboolean hf) { SoapySDRKwargs args={}; + char temp[32]; int rc; int i; -fprintf(stderr,"soapy_protocol_init: rx=%d hf=%d\n",rx,hf); + + SoapySDR_setLogLevel(SOAPY_SDR_TRACE); + +g_print("%s: hf=%d driver=%s\n",__FUNCTION__,hf,radio->name); // initialize the radio -fprintf(stderr,"soapy_protocol_init: SoapySDRDevice_make\n"); SoapySDRKwargs_set(&args, "driver", radio->name); if(strcmp(radio->name,"rtlsdr")==0) { - char id[16]; - sprintf(id,"%d",radio->info.soapy.rtlsdr_count); - SoapySDRKwargs_set(&args, "rtl", id); + sprintf(temp,"%d",radio->info.soapy.rtlsdr_count); + SoapySDRKwargs_set(&args, "rtl", temp); if(hf) { SoapySDRKwargs_set(&args, "direct_samp", "2"); } else { SoapySDRKwargs_set(&args, "direct_samp", "0"); } + } else if(strcmp(radio->name,"sdrplay")==0) { + sprintf(temp,"SDRplay Dev%d",radio->info.soapy.sdrplay_count); + g_print("%s: label=%s\n",__FUNCTION__,temp); + SoapySDRKwargs_set(&args, "label", temp); } soapy_device=SoapySDRDevice_make(&args); if(soapy_device==NULL) { - fprintf(stderr,"soapy_protocol: SoapySDRDevice_make failed: %s\n",SoapySDRDevice_lastError()); + g_print("%s: SoapySDRDevice_make failed: %s\n",__FUNCTION__,SoapySDRDevice_lastError()); _exit(-1); } SoapySDRKwargs_clear(&args); + g_print("%s: soapy_device=%p\n",__FUNCTION__,soapy_device); + if(can_transmit) { if(transmitter->local_microphone) { if(audio_open_input()!=0) { - fprintf(stderr,"audio_open_input failed\n"); + g_print("%s: audio_open_input failed\n",__FUNCTION__); transmitter->local_microphone=0; } } @@ -306,8 +326,9 @@ static void *receive_thread(void *arg) { float fsample; running=TRUE; fprintf(stderr,"soapy_protocol: receive_thread\n"); + size_t channel=rx->adc; while(running) { - elements=SoapySDRDevice_readStream(soapy_device,rx_stream,buffs,max_samples,&flags,&timeNs,timeoutUs); + elements=SoapySDRDevice_readStream(soapy_device,rx_stream[channel],buffs,max_samples,&flags,&timeNs,timeoutUs); //fprintf(stderr,"soapy_protocol_receive_thread: SoapySDRDevice_readStream failed: max_samples=%d read=%d\n",max_samples,elements); if(elements<0) { continue; @@ -367,11 +388,13 @@ fprintf(stderr,"soapy_protocol: receive_thread\n"); } fprintf(stderr,"soapy_protocol: receive_thread: SoapySDRDevice_deactivateStream\n"); - SoapySDRDevice_deactivateStream(soapy_device,rx_stream,0,0LL); + SoapySDRDevice_deactivateStream(soapy_device,rx_stream[channel],0,0LL); + /* fprintf(stderr,"soapy_protocol: receive_thread: SoapySDRDevice_closeStream\n"); - SoapySDRDevice_closeStream(soapy_device,rx_stream); + SoapySDRDevice_closeStream(soapy_device,rx_stream[channel]); fprintf(stderr,"soapy_protocol: receive_thread: SoapySDRDevice_unmake\n"); SoapySDRDevice_unmake(soapy_device); + */ return NULL; } @@ -466,10 +489,10 @@ void soapy_protocol_set_tx_antenna(TRANSMITTER *tx,int ant) { } } -void soapy_protocol_set_gain(RECEIVER *rx,double gain) { +void soapy_protocol_set_gain(RECEIVER *rx) { int rc; //fprintf(stderr,"soapy_protocol_set_gain: adc=%d gain=%f\n",gain); - rc=SoapySDRDevice_setGain(soapy_device,SOAPY_SDR_RX,rx->adc,gain); + rc=SoapySDRDevice_setGain(soapy_device,SOAPY_SDR_RX,rx->adc,adc[rx->adc].gain); if(rc!=0) { fprintf(stderr,"soapy_protocol: SoapySDRDevice_setGain failed: %s\n",SoapySDR_errToStr(rc)); } @@ -477,10 +500,10 @@ void soapy_protocol_set_gain(RECEIVER *rx,double gain) { void soapy_protocol_set_gain_element(RECEIVER *rx,char *name,int gain) { int rc; -//fprintf(stderr,"soapy_protocol_set_gain: adc=%d %s=%d\n",rx->adc,name,gain); +g_print("%s: adc=%d %s=%d\n",__FUNCTION__,rx->adc,name,gain); rc=SoapySDRDevice_setGainElement(soapy_device,SOAPY_SDR_RX,rx->adc,name,(double)gain); if(rc!=0) { - fprintf(stderr,"soapy_protocol: SoapySDRDevice_setGainElement %s failed: %s\n",name,SoapySDR_errToStr(rc)); + g_print("%s: SoapySDRDevice_setGainElement %s failed: %s\n",__FUNCTION__,name,SoapySDR_errToStr(rc)); } } diff --git a/soapy_protocol.h b/soapy_protocol.h index 541dbf9..c5bb4d6 100644 --- a/soapy_protocol.h +++ b/soapy_protocol.h @@ -27,12 +27,12 @@ SoapySDRDevice *get_soapy_device(); void soapy_protocol_create_receiver(RECEIVER *rx); void soapy_protocol_start_receiver(RECEIVER *rx); -void soapy_protocol_init(int rx,gboolean hf); +void soapy_protocol_init(gboolean hf); void soapy_protocol_stop(); void soapy_protocol_set_rx_frequency(RECEIVER *rx,int v); void soapy_protocol_set_rx_antenna(RECEIVER *rx,int ant); void soapy_protocol_set_lna_gain(RECEIVER *rx,int gain); -void soapy_protocol_set_gain(RECEIVER *rx,double gain); +void soapy_protocol_set_gain(RECEIVER *rx); void soapy_protocol_set_gain_element(RECEIVER *rx,char *name,int gain); int soapy_protocol_get_gain_element(RECEIVER *rx,char *name); void soapy_protocol_change_sample_rate(RECEIVER *rx); diff --git a/switch_menu.c b/switch_menu.c index 14f722e..dadb6ce 100644 --- a/switch_menu.c +++ b/switch_menu.c @@ -18,6 +18,7 @@ */ #include +#include #include #include @@ -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,23 @@ 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; +g_print("%s: temp_switches=%p\n",__FUNCTION__,temp_switches); + temp_switches[choice->sw].switch_function=choice->action; GtkWidget *label=gtk_bin_get_child(GTK_BIN(choice->button)); sprintf(text,"%s",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 +96,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 +110,174 @@ 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; + GtkWidget *widget; + gint function=0; + +g_print("%s: switches_no_controller=%p switches_controller1=%p switches_controller2_v1=%p switches_controller2_v2=%p\n",__FUNCTION__,&switches_no_controller,&switches_controller1,&switches_controller2_v1,&switches_controller2_v2); - 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==NO_CONTROLLER || 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,"Close"); - 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%s",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,"%s",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,"%s",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,"%s",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,"%s",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,"%s",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,"%s",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,"%s",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,"%s",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,"%s",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,"%s",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,"%s",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,"%s",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,"%s",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,"%s",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,"%s",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); + g_print("%s: temp_switches=%p\n",__FUNCTION__,temp_switches); + + int original_row=row; + + if(controller==CONTROLLER2_V1 || controller==CONTROLLER2_V2) { + row=row+5; + col=0; + widget=gtk_button_new_with_label(sw_string[temp_switches[0].switch_function]); + g_signal_connect(widget,"button_press_event",G_CALLBACK(switch_cb),GINT_TO_POINTER(0)); + gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1); + col++; + widget=gtk_button_new_with_label(sw_string[temp_switches[1].switch_function]); + g_signal_connect(widget,"button_press_event",G_CALLBACK(switch_cb),GINT_TO_POINTER(1)); + gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1); + col++; + widget=gtk_button_new_with_label(sw_string[temp_switches[2].switch_function]); + g_signal_connect(widget,"button_press_event",G_CALLBACK(switch_cb),GINT_TO_POINTER(2)); + gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1); + col++; + widget=gtk_button_new_with_label(sw_string[temp_switches[3].switch_function]); + g_signal_connect(widget,"button_press_event",G_CALLBACK(switch_cb),GINT_TO_POINTER(3)); + gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1); + col++; + widget=gtk_button_new_with_label(sw_string[temp_switches[4].switch_function]); + g_signal_connect(widget,"button_press_event",G_CALLBACK(switch_cb),GINT_TO_POINTER(4)); + gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1); + col++; + widget=gtk_button_new_with_label(sw_string[temp_switches[5].switch_function]); + g_signal_connect(widget,"button_press_event",G_CALLBACK(switch_cb),GINT_TO_POINTER(5)); + gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1); + col++; + widget=gtk_button_new_with_label(sw_string[temp_switches[6].switch_function]); + g_signal_connect(widget,"button_press_event",G_CALLBACK(switch_cb),GINT_TO_POINTER(6)); + gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1); + col++; + + row=original_row; + col=8; + widget=gtk_button_new_with_label(sw_string[temp_switches[7].switch_function]); + g_signal_connect(widget,"button_press_event",G_CALLBACK(switch_cb),GINT_TO_POINTER(7)); + gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1); + row++; + col=7; + widget=gtk_button_new_with_label(sw_string[temp_switches[8].switch_function]); + g_signal_connect(widget,"button_press_event",G_CALLBACK(switch_cb),GINT_TO_POINTER(8)); + gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1); + col++; + widget=gtk_button_new_with_label(sw_string[temp_switches[9].switch_function]); + g_signal_connect(widget,"button_press_event",G_CALLBACK(switch_cb),GINT_TO_POINTER(9)); + gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1); + row++; + col=7; + widget=gtk_button_new_with_label(sw_string[temp_switches[10].switch_function]); + g_signal_connect(widget,"button_press_event",G_CALLBACK(switch_cb),GINT_TO_POINTER(10)); + gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1); + col++; + widget=gtk_button_new_with_label(sw_string[temp_switches[11].switch_function]); + g_signal_connect(widget,"button_press_event",G_CALLBACK(switch_cb),GINT_TO_POINTER(11)); + gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1); + row++; + col=7; + widget=gtk_button_new_with_label(sw_string[temp_switches[12].switch_function]); + g_signal_connect(widget,"button_press_event",G_CALLBACK(switch_cb),GINT_TO_POINTER(12)); + gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1); + col++; + widget=gtk_button_new_with_label(sw_string[temp_switches[13].switch_function]); + g_signal_connect(widget,"button_press_event",G_CALLBACK(switch_cb),GINT_TO_POINTER(13)); + gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1); + row++; + col=7; + widget=gtk_button_new_with_label(sw_string[temp_switches[14].switch_function]); + g_signal_connect(widget,"button_press_event",G_CALLBACK(switch_cb),GINT_TO_POINTER(14)); + gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1); + col++; + widget=gtk_button_new_with_label(sw_string[temp_switches[15].switch_function]); + g_signal_connect(widget,"button_press_event",G_CALLBACK(switch_cb),GINT_TO_POINTER(15)); + gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1); + + gtk_container_add(GTK_CONTAINER(content),grid); + } else { + int start_row=row; + for(int i=0;i%s",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); + col++; + } + + g_sprintf(label,"Function %d",function); + gtk_notebook_append_page(GTK_NOTEBOOK(notebook),grid,gtk_label_new(label)); + function++; + if(functionid,i); diff --git a/toolbar.h b/toolbar.h index 5a1b887..ea9063a 100644 --- a/toolbar.h +++ b/toolbar.h @@ -20,10 +20,12 @@ #ifndef _TOOLBAR_H #define _TOOLBAR_H +#include "gpio.h" #define MAX_FUNCTION 5 extern int function; +extern SWITCH *toolbar_switches; void update_toolbar_labels(); void ptt_update(int state); diff --git a/transmitter.c b/transmitter.c index 015f46e..ec74483 100644 --- a/transmitter.c +++ b/transmitter.c @@ -670,6 +670,11 @@ static gboolean update_display(gpointer data) { // reflected power, so correct for that // double gamma=(double) rev_average / (double) fwd_average; + // + // this prevents SWR going to infinity, from which the + // moving average cannot recover + // + if (gamma > 0.95) gamma=0.95; tx->swr=0.7*(1+gamma)/(1-gamma) + 0.3*tx->swr; } else { // diff --git a/tx_menu.c b/tx_menu.c index a7f30a8..868b020 100644 --- a/tx_menu.c +++ b/tx_menu.c @@ -384,9 +384,7 @@ void tx_menu(GtkWidget *parent) { GtkWidget *label=gtk_label_new(NULL); gtk_label_set_markup(GTK_LABEL(label), "TX Filter: "); -#ifdef GTK316 - gtk_label_set_xalign(GTK_LABEL(label),0); -#endif + gtk_widget_set_halign(label, GTK_ALIGN_START); gtk_grid_attach(GTK_GRID(grid),label,col,row,1,1); col++; @@ -414,9 +412,7 @@ void tx_menu(GtkWidget *parent) { GtkWidget *panadapter_high_label=gtk_label_new(NULL); gtk_label_set_markup(GTK_LABEL(panadapter_high_label), "Panadapter High: "); -#ifdef GTK316 - gtk_label_set_xalign(GTK_LABEL(panadapter_high_label),0); -#endif + gtk_widget_set_halign(panadapter_high_label, GTK_ALIGN_START); gtk_widget_show(panadapter_high_label); gtk_grid_attach(GTK_GRID(grid),panadapter_high_label,col,row,1,1); @@ -424,9 +420,7 @@ void tx_menu(GtkWidget *parent) { GtkWidget *panadapter_low_label=gtk_label_new(NULL); gtk_label_set_markup(GTK_LABEL(panadapter_low_label), "Panadapter Low: "); -#ifdef GTK316 - gtk_label_set_xalign(GTK_LABEL(panadapter_low_label),0); -#endif + gtk_widget_set_halign(panadapter_low_label, GTK_ALIGN_START); gtk_widget_show(panadapter_low_label); gtk_grid_attach(GTK_GRID(grid),panadapter_low_label,col,row,1,1); @@ -434,9 +428,7 @@ void tx_menu(GtkWidget *parent) { GtkWidget *panadapter_step_label=gtk_label_new(NULL); gtk_label_set_markup(GTK_LABEL(panadapter_step_label), "Panadapter Step: "); -#ifdef GTK316 - gtk_label_set_xalign(GTK_LABEL(panadapter_step_label),0); -#endif + gtk_widget_set_halign(panadapter_step_label, GTK_ALIGN_START); gtk_widget_show(panadapter_step_label); gtk_grid_attach(GTK_GRID(grid),panadapter_step_label,col,row,1,1); @@ -470,9 +462,7 @@ void tx_menu(GtkWidget *parent) { GtkWidget *am_carrier_level_label=gtk_label_new(NULL); gtk_label_set_markup(GTK_LABEL(am_carrier_level_label), "AM Carrier Level:"); -#ifdef GTK316 - gtk_label_set_xalign(GTK_LABEL(am_carrier_level_label),0); -#endif + gtk_widget_set_halign(am_carrier_level_label, GTK_ALIGN_START); gtk_widget_show(am_carrier_level_label); gtk_grid_attach(GTK_GRID(grid),am_carrier_level_label,col,row,1,1); @@ -535,9 +525,7 @@ void tx_menu(GtkWidget *parent) { GtkWidget *tune_percent_label=gtk_label_new(NULL); gtk_label_set_markup(GTK_LABEL(tune_percent_label), "Tune Percent:"); -#ifdef GTK316 - gtk_label_set_xalign(GTK_LABEL(tune_percent_label),0); -#endif + gtk_widget_set_halign(tune_percent_label, GTK_ALIGN_START); gtk_widget_show(tune_percent_label); gtk_grid_attach(GTK_GRID(grid),tune_percent_label,col,row,1,1); @@ -560,9 +548,7 @@ void tx_menu(GtkWidget *parent) { GtkWidget *swr_alarm_label=gtk_label_new(NULL); gtk_label_set_markup(GTK_LABEL(swr_alarm_label), "SWR alarm at:"); -#ifdef GTK316 - gtk_label_set_xalign(GTK_LABEL(swr_alarm_label),0); -#endif + gtk_widget_set_halign(swr_alarm_label, GTK_ALIGN_START); gtk_widget_show(swr_alarm_label); gtk_grid_attach(GTK_GRID(grid),swr_alarm_label,col,row,1,1); diff --git a/tx_panadapter.c b/tx_panadapter.c index 59d9eed..ac0e114 100644 --- a/tx_panadapter.c +++ b/tx_panadapter.c @@ -35,6 +35,7 @@ #include "tx_panadapter.h" #include "vfo.h" #include "mode.h" +#include "actions.h" #ifdef GPIO #include "gpio.h" #endif @@ -352,6 +353,7 @@ void tx_panadapter_update(TRANSMITTER *tx) { cairo_set_line_width(cr, 1.0); cairo_stroke(cr); +/* #ifdef GPIO if(controller==CONTROLLER1 && tx->dialog == NULL) { char text[64]; @@ -377,7 +379,7 @@ void tx_panadapter_update(TRANSMITTER *tx) { } } #endif - +*/ #ifdef PURESIGNAL if(tx->puresignal) { @@ -404,7 +406,7 @@ void tx_panadapter_update(TRANSMITTER *tx) { cairo_set_font_size(cr, DISPLAY_FONT_SIZE3); if(transmitter->fwd<0.0001) { - sprintf(text,"FWD %0.3f W",transmitter->exciter); + sprintf(text,"FWD %0.3f",transmitter->exciter); } else { static int max_count=0; static double max_level=0.0; @@ -417,7 +419,6 @@ void tx_panadapter_update(TRANSMITTER *tx) { } cairo_move_to(cr,10,15); cairo_show_text(cr, text); - // // Since colour is already red, no special // action for "high SWR" warning @@ -426,7 +427,7 @@ void tx_panadapter_update(TRANSMITTER *tx) { cairo_move_to(cr,10,30); cairo_show_text(cr, text); - sprintf(text,"ALC %2.1f dB",transmitter->alc); + sprintf(text,"ALC %2.1f",transmitter->alc); cairo_move_to(cr,10,45); cairo_show_text(cr, text); @@ -440,7 +441,6 @@ void tx_panadapter_update(TRANSMITTER *tx) { cairo_show_text(cr, text); */ } - // // If the SWR protection has been triggered, display message for three seconds // @@ -475,6 +475,7 @@ void tx_panadapter_update(TRANSMITTER *tx) { cairo_move_to(cr, 160.0, 30.0); cairo_show_text(cr, text); + if (tx_fifo_overrun || tx_fifo_underrun) { cairo_set_source_rgb(cr,1.0,0.0,0.0); if (tx_fifo_underrun) { diff --git a/vfo.c b/vfo.c index 174f449..c78418f 100644 --- a/vfo.c +++ b/vfo.c @@ -1078,6 +1078,13 @@ void vfo_update() { long long af = vfo[0].ctun ? vfo[0].ctun_frequency : vfo[0].frequency; long long bf = vfo[1].ctun ? vfo[1].ctun_frequency : vfo[1].frequency; + if(vfo[0].entering_frequency) { + af=vfo[0].entered_frequency; + } + if(vfo[1].entering_frequency) { + bf=vfo[1].entered_frequency; + } + #if 0 // // DL1YCF: code still here but deactivated: @@ -1115,7 +1122,9 @@ void vfo_update() { if (oob) sprintf(temp_text,"VFO A: Out of band"); cairo_set_source_rgb(cr, 1.0, 0.0, 0.0); } else { - if(id==0) { + if(vfo[0].entering_frequency) { + cairo_set_source_rgb(cr, 1.0, 1.0, 0.0); + } else if(id==0) { cairo_set_source_rgb(cr, 0.0, 1.0, 0.0); } else { cairo_set_source_rgb(cr, 0.0, 0.65, 0.0); @@ -1130,7 +1139,9 @@ void vfo_update() { if (oob) sprintf(temp_text,"VFO B: Out of band"); cairo_set_source_rgb(cr, 1.0, 0.0, 0.0); } else { - if(id==1) { + if(vfo[1].entering_frequency) { + cairo_set_source_rgb(cr, 1.0, 1.0, 0.0); + } else if(id==1) { cairo_set_source_rgb(cr, 0.0, 1.0, 0.0); } else { cairo_set_source_rgb(cr, 0.0, 0.65, 0.0); diff --git a/vfo.h b/vfo.h index 77be2f4..a479d17 100644 --- a/vfo.h +++ b/vfo.h @@ -44,6 +44,8 @@ struct _vfo { long long lo; long long offset; + gboolean entering_frequency; + long long entered_frequency; }; extern struct _vfo vfo[MAX_VFOS]; @@ -73,6 +75,7 @@ typedef struct _set_frequency { long long frequency; } SET_FREQUENCY; +#define STEPS 15 extern int steps[]; extern char *step_labels[]; -- 2.45.2