From: John Melton G0ORX Date: Thu, 25 Feb 2021 16:32:34 +0000 (+0000) Subject: One Makefile. Added MIDI configuration menu. X-Git-Url: https://git.rkrishnan.org/pf/vdrive/simplejson//%22?a=commitdiff_plain;h=8e34ef51308ed5628e275f8ef29894eb926b6f1b;p=pihpsdr.git One Makefile. Added MIDI configuration menu. --- diff --git a/Makefile b/Makefile index 7c41f2c..742ecf5 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,10 @@ +# 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) -ISSUE := $(shell cat /etc/issue.net) -ifneq ($(filter %Raspbian,$(ISSUE)),) - OSFLAG=-D RASPBIAN -endif - # uncomment the following line to force 480x320 screen #SMALL_SCREEN_OPTIONS=-D SMALL_SCREEN @@ -28,7 +26,7 @@ PURESIGNAL_INCLUDE=PURESIGNAL #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 @@ -40,7 +38,7 @@ PURESIGNAL_INCLUDE=PURESIGNAL #STEMLAB_DISCOVERY=STEMLAB_DISCOVERY_NOAVAHI # uncomment the line below to include MIDI support -#MIDI_INCLUDE=MIDI +MIDI_INCLUDE=MIDI # uncomment the line below for various debug facilities #DEBUG_OPTION=-D DEBUG @@ -55,11 +53,18 @@ LINK=gcc 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 +ifeq ($(UNAME_S), Darwin) +MIDI_SOURCES= mac_midi.c midi2.c midi3.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 @@ -123,6 +128,10 @@ PTT_OPTIONS=-D PTT endif ifeq ($(GPIO_INCLUDE),GPIO) +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= \ @@ -182,18 +191,33 @@ endif GTKINCLUDES=`pkg-config --cflags gtk+-3.0` GTKLIBS=`pkg-config --libs gtk+-3.0` +ifeq ($(UNAME_S), Linux) AUDIO_LIBS=-lpulse-simple -lpulse -lpulse-mainloop-glib -//AUDIO_LIBS=-lasound +AUDIO_SOURCES=pulseaudio.c +AUDIO_OBJS=pulseaudio.o +endif +ifeq ($(UNAME_S), Darwin) +AUDIO_OPTIONS=-DPORTAUDIO +AUDIO_LIBS=-lportaudio +AUDIO_SOURCES=portaudio.c +AUDIO_OBJS=portaudio.o +endif CFLAGS= -g -Wno-deprecated-declarations -O3 OPTIONS=$(SMALL_SCREEN_OPTIONS) $(MIDI_OPTIONS) $(PURESIGNAL_OPTIONS) $(REMOTE_OPTIONS) $(USBOZY_OPTIONS) \ - $(GPIO_OPTIONS) $(SOAPYSDR_OPTIONS) $(LOCALCW_OPTIONS) \ + $(GPIO_OPTIONS) $(GPIOD_OPTIONS) $(SOAPYSDR_OPTIONS) $(LOCALCW_OPTIONS) \ $(STEMLAB_OPTIONS) \ $(PTT_OPTIONS) \ $(SERVER_OPTIONS) \ - -D GIT_DATE='"$(GIT_DATE)"' -D GIT_VERSION='"$(GIT_VERSION)"' $(DEBUG_OPTION) $(OSFLAG) + $(AUDIO_OPTIONS) \ + -D GIT_DATE='"$(GIT_DATE)"' -D GIT_VERSION='"$(GIT_VERSION)"' $(DEBUG_OPTION) + + +ifeq ($(UNAME_S), Linux) +RT_OPTION=-lrt +endif -LIBS=-lrt -lm -lwdsp -lpthread $(AUDIO_LIBS) $(USBOZY_LIBS) $(GTKLIBS) $(GPIO_LIBS) $(SOAPYSDRLIBS) $(STEMLAB_LIBS) $(MIDI_LIBS) +LIBS=$(RT_OPTION) -lm -lwdsp -lpthread $(AUDIO_LIBS) $(USBOZY_LIBS) $(GTKLIBS) $(GPIO_LIBS) $(SOAPYSDRLIBS) $(STEMLAB_LIBS) $(MIDI_LIBS) INCLUDES=$(GTKINCLUDES) COMPILE=$(CC) $(CFLAGS) $(OPTIONS) $(INCLUDES) @@ -204,7 +228,6 @@ COMPILE=$(CC) $(CFLAGS) $(OPTIONS) $(INCLUDES) PROGRAM=pihpsdr SOURCES= \ -pulseaudio.c \ band.c \ discovered.c \ discovery.c \ @@ -270,11 +293,16 @@ error_handler.c \ cwramp.c \ protocols.c \ css.c \ -actions.c +actions.c \ +configure.c \ +i2c.c \ +gpio.c \ +encoder_menu.c \ +switch_menu.c + HEADERS= \ -pulseaudio.h \ agc.h \ alex.h \ band.h \ @@ -341,11 +369,16 @@ ext.h \ error_handler.h \ protocols.h \ css.h \ -actions.h +actions.h \ +configure.h \ +i2c.h \ +gpio.h \ +encoder_menu.h \ +switch_menu.h + OBJS= \ -pulseaudio.o \ band.o \ discovered.o \ discovery.o \ @@ -411,21 +444,26 @@ error_handler.o \ cwramp.o \ protocols.o \ css.o \ -actions.o - -$(PROGRAM): $(OBJS) $(REMOTE_OBJS) $(USBOZY_OBJS) $(SOAPYSDR_OBJS) \ - $(LOCALCW_OBJS) $(GPIO_OBJS) $(PURESIGNAL_OBJS) \ +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) \ + $(LINK) -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) \ +all: prebuild $(PROGRAM) $(HEADERS) $(AUDIO_HEADERS) $(USBOZY_HEADERS) $(SOAPYSDR_HEADERS) \ + $(LOCALCW_HEADERS) \ $(PURESIGNAL_HEADERS) $(MIDI_HEADERS) $(STEMLAB_HEADERS) $(SERVER_HEADERS)\ - $(SOURCES) \ - $(USBOZY_SOURCES) $(SOAPYSDR_SOURCES) $(LOCALCW_SOURCE) $(GPIO_SOURCES) \ + $(AUDIO_SOURCES) $(SOURCES) \ + $(USBOZY_SOURCES) $(SOAPYSDR_SOURCES) $(LOCALCW_SOURCE) $(PURESIGNAL_SOURCES) $(MIDI_SOURCES) $(STEMLAB_SOURCES) $(SERVER_SOURCES) .PHONY: prebuild @@ -443,8 +481,8 @@ CPPINCLUDES:=$(shell echo $(INCLUDES) | sed -e "s/-pthread / /" ) .PHONY: cppcheck cppcheck: - cppcheck $(CPPOPTIONS) $(OPTIONS) $(CPPINCLUDES) $(SOURCES) $(REMOTE_SOURCES) \ - $(USBOZY_SOURCES) $(SOAPYSDR_SOURCES) $(GPIO_SOURCES) \ + cppcheck $(CPPOPTIONS) $(OPTIONS) $(CPPINCLUDES) $(AUDIO_SOURCES) $(SOURCES) $(REMOTE_SOURCES) \ + $(USBOZY_SOURCES) $(SOAPYSDR_SOURCES) \ $(PURESIGNAL_SOURCES) $(MIDI_SOURCES) $(STEMLAB_SOURCES) $(LOCALCW_SOURCES) \ $(SERVER_SOURCES) diff --git a/Makefile.mac b/Makefile.mac deleted file mode 100644 index 6d6fdec..0000000 --- a/Makefile.mac +++ /dev/null @@ -1,514 +0,0 @@ -# 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 USB Ozy support -# USBOZY_INCLUDE=USBOZY - -# uncomment the line below to include Pure Signal support -PURESIGNAL_INCLUDE=PURESIGNAL - -# uncomment the line to below include support local CW keyer -LOCALCW_INCLUDE=LOCALCW - -# uncomment the line below for SoapySDR -#SOAPYSDR_INCLUDE=SOAPYSDR - -# uncomment the line to below include support for sx1509 i2c expander -#SX1509_INCLUDE=sx1509 - -# uncomment the line below to include support for STEMlab discovery (WITH AVAHI) -#STEMLAB_DISCOVERY=STEMLAB_DISCOVERY - -# uncomment the line below to include support for STEMlab discovery (WITHOUT AVAHI) -STEMLAB_DISCOVERY=STEMLAB_DISCOVERY_NOAVAHI - -# uncomment the line below to include MIDI support -MIDI_INCLUDE=MIDI - -# very early code not included yet -#SERVER_INCLUDE=SERVER - -# uncomment the line below for various debug facilities -#DEBUG_OPTION=-D DEBUG - -CC=gcc -LINK=gcc - -ifeq ($(CONTROLLER2_V2_INCLUDE),CONTROLLER2_V2) -CONTROLLER2_OPTIONS=-D CONTROLLER2_V2 -endif -ifeq ($(CONTROLLER2_V1_INCLUDE),CONTROLLER2_V1) -CONTROLLER2_OPTIONS=-D CONTROLLER2_V1 -endif - -ifeq ($(MIDI_INCLUDE),MIDI) -MIDI_OPTIONS=-D MIDI -MIDI_SOURCES= mac_midi.c midi2.c midi3.c -MIDI_HEADERS= midi.h -MIDI_OBJS= mac_midi.o midi2.o midi3.o -MIDI_LIBS= -framework CoreMIDI -framework Foundation -endif - -ifeq ($(PURESIGNAL_INCLUDE),PURESIGNAL) -PURESIGNAL_OPTIONS=-D PURESIGNAL -PURESIGNAL_SOURCES= \ -ps_menu.c -PURESIGNAL_HEADERS= \ -ps_menu.h -PURESIGNAL_OBJS= \ -ps_menu.o -endif - -ifeq ($(REMOTE_INCLUDE),REMOTE) -REMOTE_OPTIONS=-D REMOTE -REMOTE_SOURCES= \ -remote_radio.c \ -remote_receiver.c -REMOTE_HEADERS= \ -remote_radio.h \ -remote_receiver.h -REMOTE_OBJS= \ -remote_radio.o \ -remote_receiver.o -endif - -ifeq ($(USBOZY_INCLUDE),USBOZY) -USBOZY_OPTIONS=-D USBOZY -USBOZY_LIBS=-lusb-1.0 -USBOZY_SOURCES= \ -ozyio.c -USBOZY_HEADERS= \ -ozyio.h -USBOZY_OBJS= \ -ozyio.o -endif - -ifeq ($(SOAPYSDR_INCLUDE),SOAPYSDR) -SOAPYSDR_OPTIONS=-D SOAPYSDR -SOAPYSDRLIBS=-lSoapySDR -SOAPYSDR_SOURCES= \ -soapy_discovery.c \ -soapy_protocol.c -SOAPYSDR_HEADERS= \ -soapy_discovery.h \ -soapy_protocol.h -SOAPYSDR_OBJS= \ -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 - -# -# We have two versions of STEMLAB_DISCOVERY here, -# the second one has to be used -# if you do not have the avahi (devel-) libraries -# on your system. -# -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` -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_SOURCES=stemlab_discovery.c -STEMLAB_HEADERS=stemlab_discovery.h -STEMLAB_OBJS=stemlab_discovery.o -endif - -ifeq ($(SERVER_INCLUDE), SERVER) -SERVER_OPTIONS=-D SERVER -SERVER_SOURCES= \ -hpsdr_server.c -SERVER_HEADERS= \ -hpsdr_server.h -SERVER_OBJS= \ -hpsdr_server.o -endif - -GTKINCLUDES=`pkg-config --cflags gtk+-3.0` -GTKLIBS=`pkg-config --libs gtk+-3.0` - -AUDIO_OPTIONS=-DPORTAUDIO -AUDIO_LIBS=-lportaudio -O3 - -CFLAGS= -g -Wno-deprecated-declarations -OPTIONS=$(MIDI_OPTIONS) $(PURESIGNAL_OPTIONS) $(REMOTE_OPTIONS) $(USBOZY_OPTIONS) \ - $(SOAPYSDR_OPTIONS) $(LOCALCW_OPTIONS) \ - $(STEMLAB_OPTIONS) \ - $(CONTROLLER2_OPTIONS) $(AUDIO_OPTIONS) \ - -D GIT_DATE='"$(GIT_DATE)"' -D GIT_VERSION='"$(GIT_VERSION)"' $(DEBUG_OPTION) - -LIBS= -lm -lwdsp -lpthread $(AUDIO_LIBS) $(USBOZY_LIBS) $(GTKLIBS) $(SOAPYSDRLIBS) $(STEMLAB_LIBS) $(MIDI_LIBS) -INCLUDES=$(GTKINCLUDES) - -COMPILE=$(CC) $(CFLAGS) $(OPTIONS) $(INCLUDES) - -.c.o: - $(COMPILE) -c -o $@ $< - -PROGRAM=pihpsdr - -SOURCES= \ -audio.c \ -band.c \ -configure.c \ -discovered.c \ -discovery.c \ -filter.c \ -main.c \ -new_menu.c \ -about_menu.c \ -exit_menu.c \ -radio_menu.c \ -rx_menu.c \ -ant_menu.c \ -display_menu.c \ -dsp_menu.c \ -pa_menu.c \ -cw_menu.c \ -oc_menu.c \ -portaudio.c \ -xvtr_menu.c \ -equalizer_menu.c \ -step_menu.c \ -meter_menu.c \ -band_menu.c \ -bandstack_menu.c \ -mode_menu.c \ -filter_menu.c \ -noise_menu.c \ -agc_menu.c \ -vox_menu.c \ -fft_menu.c \ -diversity_menu.c \ -tx_menu.c \ -vfo_menu.c \ -test_menu.c \ -meter.c \ -mode.c \ -old_discovery.c \ -new_discovery.c \ -old_protocol.c \ -new_protocol.c \ -new_protocol_programmer.c \ -rx_panadapter.c \ -tx_panadapter.c \ -property.c \ -radio.c \ -receiver.c \ -rigctl.c \ -rigctl_menu.c \ -toolbar.c \ -transmitter.c \ -zoompan.c \ -sliders.c \ -version.c \ -vfo.c \ -waterfall.c \ -button_text.c \ -vox.c \ -update.c \ -store.c \ -store_menu.c \ -memory.c \ -led.c \ -ext.c \ -error_handler.c \ -cwramp.c \ -protocols.c - - -HEADERS= \ -audio.h \ -agc.h \ -alex.h \ -band.h \ -configure.h \ -bandstack.h \ -channel.h \ -discovered.h \ -discovery.h \ -filter.h \ -new_menu.h \ -about_menu.h \ -rx_menu.h \ -exit_menu.h \ -radio_menu.h \ -ant_menu.h \ -display_menu.h \ -dsp_menu.h \ -pa_menu.h \ -cw_menu.h \ -oc_menu.h \ -xvtr_menu.h \ -equalizer_menu.h \ -step_menu.h \ -meter_menu.h \ -band_menu.h \ -bandstack_menu.h \ -mode_menu.h \ -filter_menu.h \ -noise_menu.h \ -agc_menu.h \ -vox_menu.h \ -fft_menu.h \ -diversity_menu.h \ -tx_menu.h \ -vfo_menu.h \ -test_menu.h \ -meter.h \ -mode.h \ -old_discovery.h \ -new_discovery.h \ -old_protocol.h \ -new_protocol.h \ -rx_panadapter.h \ -tx_panadapter.h \ -property.h \ -radio.h \ -receiver.h \ -rigctl.h \ -rigctl_menu.h \ -toolbar.h \ -transmitter.h \ -zoompan.h \ -sliders.h \ -version.h \ -vfo.h \ -waterfall.h \ -button_text.h \ -vox.h \ -update.h \ -store.h \ -store_menu.h \ -memory.h \ -led.h \ -ext.h \ -error_handler.h \ -protocols.h - - -OBJS= \ -audio.o \ -portaudio.o \ -band.o \ -configure.o \ -discovered.o \ -discovery.o \ -filter.o \ -version.o \ -main.o \ -new_menu.o \ -about_menu.o \ -rx_menu.o \ -exit_menu.o \ -radio_menu.o \ -ant_menu.o \ -display_menu.o \ -dsp_menu.o \ -pa_menu.o \ -cw_menu.o \ -oc_menu.o \ -xvtr_menu.o \ -equalizer_menu.o \ -step_menu.o \ -meter_menu.o \ -band_menu.o \ -bandstack_menu.o \ -mode_menu.o \ -filter_menu.o \ -noise_menu.o \ -agc_menu.o \ -vox_menu.o \ -fft_menu.o \ -diversity_menu.o \ -tx_menu.o \ -vfo_menu.o \ -test_menu.o \ -meter.o \ -mode.o \ -old_discovery.o \ -new_discovery.o \ -old_protocol.o \ -new_protocol.o \ -new_protocol_programmer.o \ -rx_panadapter.o \ -tx_panadapter.o \ -property.o \ -radio.o \ -receiver.o \ -rigctl.o \ -rigctl_menu.o \ -toolbar.o \ -transmitter.o \ -zoompan.o \ -sliders.o \ -vfo.o \ -waterfall.o \ -button_text.o \ -vox.o \ -update.o \ -store.o \ -store_menu.o \ -memory.o \ -led.o \ -ext.o \ -error_handler.o \ -cwramp.o \ -protocols.o - -$(PROGRAM): $(OBJS) $(REMOTE_OBJS) $(USBOZY_OBJS) $(SOAPYSDR_OBJS) \ - $(LOCALCW_OBJS) $(PURESIGNAL_OBJS) \ - $(MIDI_OBJS) $(STEMLAB_OBJS) - $(LINK) -o $(PROGRAM) $(OBJS) $(REMOTE_OBJS) $(USBOZY_OBJS) \ - $(SOAPYSDR_OBJS) $(LOCALCW_OBJS) $(PURESIGNAL_OBJS) \ - $(MIDI_OBJS) $(STEMLAB_OBJS) $(LIBS) - -all: prebuild $(PROGRAM) $(HEADERS) $(REMOTE_HEADERS) $(USBOZY_HEADERS) $(SOAPYSDR_HEADERS) \ - $(LOCALCW_HEADERS) \ - $(PURESIGNAL_HEADERS) $(MIDI_HEADERS) $(STEMLAB_HEADERS) $(SOURCES) $(REMOTE_SOURCES) \ - $(USBOZY_SOURCES) $(SOAPYSDR_SOURCES) \ - $(PURESIGNAL_SOURCES) $(MIDI_SOURCES) $(STEMLAB_SOURCES) $(LOCALCW_SOURCES) - -prebuild: - rm -f version.o - -# -# On some platforms, INCLUDES contains "-pthread" (from a pkg-config output) -# which is not a valid cppcheck option -# Therefore, correct this here. Furthermore, we can add additional options to CPP -# in the variable CPPOPTIONS -# -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) \ - $(PURESIGNAL_SOURCES) $(MIDI_SOURCES) $(STEMLAB_SOURCES) $(LOCALCW_SOURCES) - -clean: - -rm -f *.o - -rm -f $(PROGRAM) hpsdrsim - -rm -rf $(PROGRAM).app - -install: $(PROGRAM) - cp $(PROGRAM) /usr/local/bin - -release: $(PROGRAM) - cp $(PROGRAM) release/pihpsdr - cd release; tar cvf pihpsdr.tar pihpsdr - cd release; tar cvf pihpsdr-$(GIT_VERSION).tar pihpsdr - -nocontroller: clean controller1 $(PROGRAM) - cp $(PROGRAM) release/pihpsdr - cd release; tar cvf pihpsdr-nocontroller.$(GIT_VERSION).tar pihpsdr - -controller1: clean $(PROGRAM) - cp $(PROGRAM) release/pihpsdr - cd release; tar cvf pihpsdr-controller1.$(GIT_VERSION).tar pihpsdr - -controller2v1: clean $(PROGRAM) - cp $(PROGRAM) release/pihpsdr - cd release; tar cvf pihpsdr-controller2-v1.$(GIT_VERSION).tar pihpsdr - -controller2v2: clean $(PROGRAM) - cp $(PROGRAM) release/pihpsdr - cd release; tar cvf pihpsdr-controller2-v2.$(GIT_VERSION).tar pihpsdr - - -############################################################################# -# -# hpsdrsim is a cool program that emulates an SDR board with UDP and TCP -# facilities. It even feeds back the TX signal and distorts it, so that -# you can test PURESIGNAL. -# This feature only works if the sample rate is 48000 -# -############################################################################# - -hpsdrsim.o: hpsdrsim.c hpsdrsim.h - $(CC) -c -O -DPORTAUDIO 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 -lportaudio -lm -lpthread - -############################################################################# -# -# This is for MacOS "app" creation ONLY -# -# Note: Note that we need a wrapper script to start the program, and -# that it requires a working GTK installation on the Mac. -# The program will not work if the -# libgtk, libgdk, libglib, libgobj, libgio libraries -# are copied to the Frameworks dir and "activated", because -# this stuff depends on tons of other files in /usr/local. -# -# We bundle the "app" with the other libraries such as WDSP, -# portaudio, fftw etc. such that the "app" runs on Macs which -# do not have them. But it is *very* hard to do this with GTK. -# -# piHPSDR working dir -# =================== -# -# 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. -# -############################################################################# -app: $(OBJS) $(REMOTE_OBJS) $(USBOZY_OBJS) \ - $(LOCALCW_OBJS) \ - $(PURESIGNAL_OBJS) $(MIDI_OBJS) $(STEMLAB_OBJS) - $(LINK) -headerpad_max_install_names -o $(PROGRAM) $(OBJS) $(REMOTE_OBJS) \ - $(USBOZY_OBJS) \ - $(LOCALCW_OBJS) $(PURESIGNAL_OBJS) \ - $(MIDI_OBJS) $(STEMLAB_OBJS) $(LIBS) - @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-bin - @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/pihpsdr.sh pihpsdr.app/Contents/MacOS/pihpsdr - @cp MacOS/hpsdr.png pihpsdr.app/Contents/Resources - @for lib in `otool -L pihpsdr.app/Contents/MacOS/pihpsdr-bin | grep dylib | sed -e "s/ (.*//" | grep -Ev "/(usr/lib|System)" | grep -Ev /libg | grep -Ev pango | grep -Ev cairo`; do \ - 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-bin; \ - done - @# once more to install libraries on which libs just copied depend (such as wdsp -> fftw) - @for file in pihpsdr.app/Contents/Frameworks/*.dylib; do \ - for lib in `otool -L pihpsdr.app/Contents/Frameworks/*.dylib | grep -v pihpsdr.app | grep -v "executable_path" | grep dylib | sed -e "s/ (.*//" | grep -Ev "/(usr/lib|System)" | grep -Ev /libg | grep -Ev pango | grep -Ev cairo`; do \ - 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" $$file; \ - done; \ - done -############################################################################# - diff --git a/adc.h b/adc.h index c1ab51d..8c0be6c 100644 --- a/adc.h +++ b/adc.h @@ -66,7 +66,7 @@ typedef struct _adc { gint attenuation; gboolean enable_step_attenuation; #ifdef SOAPYSDR - gint *rx_gain; + gdouble gain; gboolean agc; #endif } ADC; diff --git a/alsa_midi.c b/alsa_midi.c index 89dc8e5..eb4d0af 100644 --- a/alsa_midi.c +++ b/alsa_midi.c @@ -18,7 +18,11 @@ * program amidi.c in alsautils. */ +#include + #include "midi.h" +#include "midi_menu.h" +#include "alsa_midi.h" #ifndef __APPLE__ @@ -28,6 +32,10 @@ static pthread_t midi_thread_id; static void* midi_thread(void *); +MIDI_DEVICE midi_devices[MAX_MIDI_DEVICES]; +int n_midi_devices; +int running; + static char portname[64]; static enum { @@ -43,9 +51,17 @@ static enum { CMD_PITCH, } command; +static gboolean configure=FALSE; + +static snd_rawmidi_t *input; + +void configure_midi_device(gboolean state) { + configure=state; +} + static void *midi_thread(void *arg) { int ret; - snd_rawmidi_t *input; + MIDI_DEVICE *midi_device=(MIDI_DEVICE *)arg; int npfds; struct pollfd *pfds; unsigned char buf[32]; @@ -54,22 +70,28 @@ static void *midi_thread(void *arg) { int i; int chan,arg1,arg2; - if ((ret = snd_rawmidi_open(&input, NULL, portname, SND_RAWMIDI_NONBLOCK)) < 0) { - fprintf(stderr,"cannot open port \"%s\": %s\n", portname, snd_strerror(ret)); + /* + if ((ret = snd_rawmidi_open(&input, NULL, midi_device->port, SND_RAWMIDI_NONBLOCK)) < 0) { + fprintf(stderr,"cannot open port \"%s\": %s\n", midi_device->port, snd_strerror(ret)); return NULL; } + */ + + running=1; + 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 (;;) { + while (running) { ret = poll(pfds, npfds, 250); if (ret < 0) { fprintf(stderr,"poll failed: %s\n", strerror(errno)); // Do not give up, but also do not fire too rapidly usleep(250000); } + if(!running) continue; if (ret <= 0) continue; // nothing arrived, do next poll() if ((ret = snd_rawmidi_poll_descriptors_revents(input, pfds, npfds, &revents)) < 0) { fprintf(stderr,"cannot get poll events: %s\n", snd_strerror(errno)); @@ -129,19 +151,39 @@ static void *midi_thread(void *arg) { // messages with velocity == 0 when releasing // a push-button if (arg2 == 0) { - NewMidiEvent(MIDI_NOTE, chan, arg1, 0); + if(configure) { + NewMidiConfigureEvent(MIDI_NOTE, chan, arg1, 0); + } else { + NewMidiEvent(MIDI_NOTE, chan, arg1, 0); + } } else { - NewMidiEvent(MIDI_NOTE, chan, arg1, 1); + if(configure) { + NewMidiConfigureEvent(MIDI_NOTE, chan, arg1, 1); + } else { + NewMidiEvent(MIDI_NOTE, chan, arg1, 1); + } } break; case CMD_NOTEOFF: - NewMidiEvent(MIDI_NOTE, chan, arg1, 0); + if(configure) { + NewMidiConfigureEvent(MIDI_NOTE, chan, arg1, 0); + } else { + NewMidiEvent(MIDI_NOTE, chan, arg1, 0); + } break; case CMD_CTRL: - NewMidiEvent(MIDI_CTRL, chan, arg1, arg2); + if(configure) { + NewMidiConfigureEvent(MIDI_CTRL, chan, arg1, arg2); + } else { + NewMidiEvent(MIDI_CTRL, chan, arg1, arg2); + } break; case CMD_PITCH: - NewMidiEvent(MIDI_PITCH, chan, 0, arg1+128*arg2); + if(configure) { + NewMidiConfigureEvent(MIDI_PITCH, chan, 0, arg1+128*arg2); + } else { + NewMidiEvent(MIDI_PITCH, chan, 0, arg1+128*arg2); + } break; } state=STATE_SKIP; @@ -151,9 +193,52 @@ static void *midi_thread(void *arg) { } } -void register_midi_device(char *myname) { +int register_midi_device(char *myname) { + int i; + int ret=0; + + configure=FALSE; + + for(i=0;i=n_midi_devices) { + g_print("%s: Cannot find MIDI device: %s\n",__FUNCTION__,myname); + ret=-1; + } +} + +void close_midi_device() { + int ret; + + g_print("%s\n",__FUNCTION__); + if(input!=NULL) { + g_print("%s: snd_rawmidi_close\n",__FUNCTION__); + running=0; + if((ret = snd_rawmidi_close(input)) < 0) { + g_print("%s: cannot close port: %s\n",__FUNCTION__, snd_strerror(ret)); + } + input=NULL; + usleep(250000L); + } +} + +void get_midi_devices() { - int mylen=strlen(myname); snd_ctl_t *ctl; snd_rawmidi_info_t *info; int card, device, subs, sub, ret; @@ -161,13 +246,14 @@ void register_midi_device(char *myname) { int found=0; char name[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); + //fprintf(stderr,"Found Sound Card=%d\n",card); sprintf(name,"hw:%d", card); if ((ret = snd_ctl_open(&ctl, name, 0)) < 0) { fprintf(stderr,"cannot open control for card %d: %s\n", card, snd_strerror(ret)); @@ -181,7 +267,7 @@ void register_midi_device(char *myname) { break; } if (device < 0) break; - fprintf(stderr,"Found Device=%d on Card=%d\n", device, card); + //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); @@ -192,7 +278,7 @@ void register_midi_device(char *myname) { } else { subs = 0; } - fprintf(stderr,"Number of MIDI input devices: %d\n", subs); + //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) { @@ -216,12 +302,13 @@ void register_midi_device(char *myname) { sprintf(portname,"hw:%d,%d,%d", card, device, sub); devnam=subnam; } - if (!strncmp(myname, devnam, mylen)) { - found=1; - fprintf(stderr,"MIDI device %s selected (PortName=%s)\n", devnam, portname); - } else { - fprintf(stderr,"MIDI device found BUT NOT SELECTED: %s\n", devnam); - } + + midi_devices[n_midi_devices].name=g_new(gchar,strlen(devnam)+1); + strcpy(midi_devices[n_midi_devices].name,devnam); + + midi_devices[n_midi_devices].port=g_new(gchar,strlen(portname)+1); + strcpy(midi_devices[n_midi_devices].port,portname); + n_midi_devices++; } } snd_ctl_close(ctl); @@ -231,14 +318,9 @@ void register_midi_device(char *myname) { break; } } - if (!found) { - fprintf(stderr,"MIDI device %s NOT FOUND!\n", myname); - return; - } - // Found our MIDI input device. Spawn off a thread reading data - ret = pthread_create(&midi_thread_id, NULL, midi_thread, NULL); - if (ret < 0) { - fprintf(stderr,"Failed to create MIDI read thread\n"); + + for(int i=0;iprotocol,d->name); break; #ifdef SOAPYSDR case SOAPYSDR_PROTOCOL: - sprintf(text,"%s (Protocol SOAPY_SDR %s) on USB",d->name,d->info.soapy.version); + sprintf(text,"%s (Protocol SOAPY_SDR %s) on %s",d->name,d->info.soapy.version,d->info.soapy.address); break; + #endif #ifdef STEMLAB_DISCOVERY case STEMLAB_PROTOCOL: @@ -571,7 +572,7 @@ fprintf(stderr,"%p Protocol=%d name=%s\n",d,d->protocol,d->name); gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(gpio),NULL,"Controller1"); gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(gpio),NULL,"Controller2 V1"); gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(gpio),NULL,"Controller2 V2"); - gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(gpio),NULL,"Controller I2C"); + //gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(gpio),NULL,"Controller I2C"); gtk_grid_attach(GTK_GRID(grid),gpio,0,row,1,1); gtk_combo_box_set_active(GTK_COMBO_BOX(gpio),controller); @@ -586,12 +587,13 @@ 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/display_menu.c b/display_menu.c index 0dba23b..38aab90 100644 --- a/display_menu.c +++ b/display_menu.c @@ -440,25 +440,23 @@ void display_menu(GtkWidget *parent) { col++; - if(controller!=CONTROLLER_I2C) { - GtkWidget *b_display_sliders=gtk_check_button_new_with_label("Display Sliders"); - //gtk_widget_override_font(b_display_sliders, pango_font_description_from_string("Arial 18")); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_display_sliders), display_sliders); - gtk_widget_show(b_display_sliders); - gtk_grid_attach(GTK_GRID(grid),b_display_sliders,col,row,1,1); - g_signal_connect(b_display_sliders,"toggled",G_CALLBACK(display_sliders_cb),(gpointer *)NULL); - - col++; - - GtkWidget *b_display_toolbar=gtk_check_button_new_with_label("Display Toolbar"); - //gtk_widget_override_font(b_display_toolbar, pango_font_description_from_string("Arial 18")); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_display_toolbar), display_toolbar); - gtk_widget_show(b_display_toolbar); - gtk_grid_attach(GTK_GRID(grid),b_display_toolbar,col,row,1,1); - g_signal_connect(b_display_toolbar,"toggled",G_CALLBACK(display_toolbar_cb),(gpointer *)NULL); - - col++; - } + GtkWidget *b_display_sliders=gtk_check_button_new_with_label("Display Sliders"); + //gtk_widget_override_font(b_display_sliders, pango_font_description_from_string("Arial 18")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_display_sliders), display_sliders); + gtk_widget_show(b_display_sliders); + gtk_grid_attach(GTK_GRID(grid),b_display_sliders,col,row,1,1); + g_signal_connect(b_display_sliders,"toggled",G_CALLBACK(display_sliders_cb),(gpointer *)NULL); + + col++; + + GtkWidget *b_display_toolbar=gtk_check_button_new_with_label("Display Toolbar"); + //gtk_widget_override_font(b_display_toolbar, pango_font_description_from_string("Arial 18")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_display_toolbar), display_toolbar); + gtk_widget_show(b_display_toolbar); + gtk_grid_attach(GTK_GRID(grid),b_display_toolbar,col,row,1,1); + g_signal_connect(b_display_toolbar,"toggled",G_CALLBACK(display_toolbar_cb),(gpointer *)NULL); + + col++; GtkWidget *b_display_sequence_errors=gtk_check_button_new_with_label("Display Seq Errs"); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_display_sequence_errors), display_sequence_errors); diff --git a/ext.c b/ext.c index fc57b0b..6ee09b2 100644 --- a/ext.c +++ b/ext.c @@ -53,6 +53,47 @@ // The following calls functions can be called usig g_idle_add +int ext_menu_filter(void *data) { + start_filter(); + return 0; +} + +int ext_menu_mode(void *data) { + start_mode(); + return 0; +} + +int ext_num_pad(void *data) { + gint val=GPOINTER_TO_INT(data); + 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(rx); + return 0; +} + int ext_vfo_mode_changed(void * data) { int mode=GPOINTER_TO_INT(data); @@ -428,6 +469,13 @@ void band_plus(int id) { } } +int ext_band_select(void *data) { + int b=GPOINTER_TO_INT(data); + g_print("%s: %d\n",__FUNCTION__,b); + vfo_band_changed(active_receiver->id,b); + return 0; +} + int ext_band_plus(void *data) { band_plus(active_receiver->id); return 0; diff --git a/ext.h b/ext.h index 51f1bcc..647f1fc 100644 --- a/ext.h +++ b/ext.h @@ -31,6 +31,9 @@ extern int ext_remote_command(void *data); extern int ext_receiver_remote_update_display(void *data); #endif +extern int ext_menu_filter(void *data); +extern int ext_menu_mode(void *data); +extern int ext_num_pad(void *data); extern void local_set_frequency(int v,long long f); extern int ext_discovery(void *data); extern int ext_vfo_update(void *data); @@ -55,6 +58,7 @@ extern int ext_nr_update(void *data); extern int ext_nb_update(void *data); extern int ext_snb_update(void *data); extern int ext_anf_update(void *data); +extern int ext_band_select(void *data); extern void band_plus(int id); extern int ext_band_plus(void *data); extern void band_minus(int id); diff --git a/gpio.c b/gpio.c index ca48856..5674cca 100644 --- a/gpio.c +++ b/gpio.c @@ -1,6 +1,6 @@ /* 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 @@ -33,10 +33,12 @@ #include #include +#ifdef GPIO #include #include #include #include +#endif #include "band.h" #include "channel.h" @@ -60,10 +62,28 @@ #include "ext.h" #include "sliders.h" #include "new_protocol.h" +#include "zoompan.h" #ifdef LOCALCW #include "iambic.h" + +// +// Broadcom pins #9, 10, 11 are not used +// by Controller1 and Controller2_V1 +// (and keep #2,3 reserved for I2C extensions) +// +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; +#endif + +#ifdef PTT +int ENABLE_PTT_GPIO=1; +int PTT_GPIO=14; +int PTT_ACTIVE_LOW=1; #endif -#include "zoompan.h" enum { TOP_ENCODER, @@ -75,12 +95,13 @@ enum { B }; +#ifdef GPIO char *consumer="pihpsdr"; char *gpio_device="/dev/gpiochip0"; static struct gpiod_chip *chip=NULL; -//static struct gpiod_line *line=NULL; +#endif static GMutex encoder_mutex; static GThread *monitor_thread_id; @@ -514,6 +535,7 @@ int process_function_switch(void *data) { return 0; } +#ifdef GPIO static unsigned long switch_debounce; static void process_encoder(int e,int l,int addr,int val) { @@ -560,8 +582,21 @@ static void process_edge(int offset,int value) { gint i; gint t; gboolean found; - // check encoders + 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;i #include #include @@ -306,3 +307,4 @@ void i2c_init() { } while(flags!=0); } +#endif diff --git a/iambic.c b/iambic.c index 58a20cb..6f32453 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" diff --git a/mac_midi.c b/mac_midi.c index d52603d..898527f 100644 --- a/mac_midi.c +++ b/mac_midi.c @@ -27,10 +27,30 @@ * */ +#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" #ifdef __APPLE__ +typedef struct _midi_device { + char *name; + char *port; +} MIDI_DEVICE; + +#define MAX_MIDI_DEVICES 10 + +MIDI_DEVICE midi_devices[MAX_MIDI_DEVICES]; +int n_midi_devices; + + /* * For MacOS, things are easy: * The OS takes care of everything, we only have to register a callback @@ -43,6 +63,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 +93,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 +145,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_NOTE, chan, arg1, 0); + if(configure) { + NewMidiConfigureEvent(MIDI_NOTE, chan, arg1, 0); + } else { + NewMidiEvent(MIDI_NOTE, chan, arg1, 0); + } } else { - NewMidiEvent(MIDI_NOTE, chan, arg1, 1); + if(configure) { + NewMidiConfigureEvent(MIDI_NOTE, chan, arg1, 1); + } else { + NewMidiEvent(MIDI_NOTE, chan, arg1, 1); + } } break; case CMD_NOTEOFF: - NewMidiEvent(MIDI_NOTE, chan, arg1, 0); + if(configure) { + NewMidiConfigureEvent(MIDI_NOTE, chan, arg1, 0); + } else { + NewMidiEvent(MIDI_NOTE, chan, arg1, 0); + } break; case CMD_CTRL: - NewMidiEvent(MIDI_CTRL, chan, arg1, arg2); + if(configure) { + NewMidiConfigureEvent(MIDI_CTRL, chan, arg1, arg2); + } else { + NewMidiEvent(MIDI_CTRL, chan, arg1, arg2); + } break; case CMD_PITCH: - NewMidiEvent(MIDI_PITCH, chan, 0, arg1+128*arg2); + if(configure) { + NewMidiConfigureEvent(MIDI_PITCH, chan, 0, arg1+128*arg2); + } else { + NewMidiEvent(MIDI_PITCH, chan, 0, arg1+128*arg2); + } break; } state=STATE_SKIP; @@ -142,35 +188,31 @@ static void ReadMIDIdevice(const MIDIPacketList *pktlist, void *refCon, void *co } // j-loop through the list of packets } +void close_midi_device() { + fprintf(stderr,"%s\n",__FUNCTION__); +} -void register_midi_device(char *myname) { - unsigned long nDevices; +int register_midi_device(char *myname) { int i; CFStringRef pname; char name[100]; int FoundMIDIref=-1; int mylen=strlen(myname); + int ret; + configure=false; + g_print("%s: %s\n",__FUNCTION__,myname); // // Go through the list of MIDI devices and // look whether the one we are looking for is there // - - nDevices=MIDIGetNumberOfSources(); - for (i=0; i>>%s<<<\n", name); - if (!strncmp(name, myname, mylen)) { - FoundMIDIref=i; - fprintf(stderr,"MIDI device found and selected: >>>%s<<<\n", name); - } else { - fprintf(stderr,"MIDI device found BUT NOT SELECTED: >>>%s<<<\n", name); - } + for (i=0; i>>%s<<<\n", name); + } else { + fprintf(stderr,"MIDI device found BUT NOT SELECTED: >>>%s<<<\n", name); } } @@ -185,6 +227,40 @@ void register_midi_device(char *myname) { MIDIClientCreate(CFSTR("piHPSDR"),NULL,NULL, &client); MIDIInputPortCreate(client, CFSTR("FromMIDI"), ReadMIDIdevice, NULL, &myMIDIport); MIDIPortConnectSource(myMIDIport,MIDIGetSource(FoundMIDIref), NULL); + ret=0; + } else { + ret=-1; + } + + return ret; +} + +void get_midi_devices() { + int n; + int i; + CFStringRef pname; + char name[100]; + int FoundMIDIref=-1; + + n=MIDIGetNumberOfSources(); + n_midi_devices=0; + for (i=0; i A - BAND_DOWN, // BANDDOWN: cycle through bands downwards - BAND_UP, // BANDUP: cycle through bands upwards + MIDI_BAND_10, // BAND10 + MIDI_BAND_12, // BAND12 + MIDI_BAND_1240, // BAND1240 + MIDI_BAND_144, // BAND144 + MIDI_BAND_15, // BAND15 + MIDI_BAND_160, // BAND160 + MIDI_BAND_17, // BAND17 + MIDI_BAND_20, // BAND20 + MIDI_BAND_220, // BAND220 + MIDI_BAND_2300, // BAND2300 + MIDI_BAND_30, // BAND30 + MIDI_BAND_3400, // BAND3400 + MIDI_BAND_40, // BAND40 + MIDI_BAND_430, // BAND430 + MIDI_BAND_6, // BAND6 + MIDI_BAND_60, // BAND60 + MIDI_BAND_70, // BAND70 + MIDI_BAND_80, // BAND80 + MIDI_BAND_902, // BAND902 + MIDI_BAND_AIR, // BANDAIR + BAND_DOWN, // BANDDOWN + MIDI_BAND_GEN, // BANDGEN + BAND_UP, // BANDUP + MIDI_BAND_WWV, // BANDWWV COMPRESS, // COMPRESS: TX compressor value MIDI_CTUN, // CTUN: toggle CTUN on/off VFO, // CURRVFO: change VFO frequency - CWL, // CWL: Left paddle pressed (use with ONOFF) - CWR, // CWR: Right paddle pressed (use with ONOFF) + CWLEFT, // CWL: Left paddle pressed (use with ONOFF) + CWRIGHT, // CWR: Right paddle pressed (use with ONOFF) CWSPEED, // CWSPEED: Set speed of (iambic) CW keyer DIV_COARSEGAIN, // DIVCOARSEGAIN: change DIVERSITY gain in large increments DIV_COARSEPHASE, // DIVPHASE: change DIVERSITY phase in large increments @@ -73,6 +97,8 @@ enum MIDIaction { MIDI_DUP, // DUP: toggle duplex on/off FILTER_DOWN, // FILTERDOWN: cycle through filters downwards FILTER_UP, // FILTERUP: cycle through filters upwards + MENU_FILTER, + MENU_MODE, MIDI_LOCK, // LOCK: lock VFOs, disable frequency changes MIC_VOLUME, // MICGAIN: MIC gain MODE_DOWN, // MODEDOWN: cycle through modes downwards @@ -81,6 +107,18 @@ enum MIDIaction { MIDI_MUTE, // MUTE: toggle mute on/off MIDI_NB, // NOISEBLANKER: cycle through NoiseBlanker states (none, NB, NB2) MIDI_NR, // NOISEREDUCTION: cycle through NoiseReduction states (none, NR, NR2) + NUMPAD_0, // NUMPAD0 + NUMPAD_1, // NUMPAD1 + NUMPAD_2, // NUMPAD2 + NUMPAD_3, // NUMPAD3 + NUMPAD_4, // NUMPAD4 + NUMPAD_5, // NUMPAD5 + NUMPAD_6, // NUMPAD6 + NUMPAD_7, // NUMPAD7 + NUMPAD_8, // NUMPAD8 + NUMPAD_9, // NUMPAD9 + NUMPAD_CL, // NUMPADCL + NUMPAD_ENTER, // NUMPADENTER MIDI_PAN, // PAN: change panning of panadater/waterfall when zoomed PAN_HIGH, // PANHIGH: "high" value of current panadapter PAN_LOW, // PANLOW: "low" value of current panadapter @@ -136,11 +174,14 @@ enum MIDIaction { enum MIDItype { TYPE_NONE=0, - MIDI_KEY, // Button (press event) - MIDI_KNOB, // Knob (value between 0 and 100) - MIDI_WHEEL // Wheel (direction and speed) + MIDI_KEY=1, // Button (press event) + MIDI_KNOB=2, // Knob (value between 0 and 100) + MIDI_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 @@ -158,6 +199,14 @@ enum MIDIevent { // Data structure for Layer-2 // +typedef struct _action_table { + enum MIDIaction action; + const char *str; + enum MIDItype type; +} ACTION_TABLE; + +extern ACTION_TABLE ActionTable[]; + // // There is linked list of all specified MIDI events for a given "Note" value, // which contains the defined actions for all MIDI_NOTE and MIDI_CTRL events @@ -199,17 +248,23 @@ struct desc { struct desc *next; // Next defined action for a controller/key with that note value (NULL for end of list) }; -struct cmdtable{ +struct cmdtable { struct desc *desc[128]; // description for Note On/Off and ControllerChange struct desc *pitch; // description for PitchChanges }; +extern struct cmdtable MidiCommandsTable; + +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); +int register_midi_device(char *name); +void close_midi_device(); +void configure_midi_device(gboolean state); // // Layer-2 entry point (called by Layer1) @@ -222,7 +277,8 @@ 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); +int MIDIstop(); // // Layer-3 entry point (called by Layer2). In Layer-3, all the pihpsdr @@ -232,3 +288,4 @@ void MIDIstartup(); // void DoTheMidi(enum MIDIaction code, enum MIDItype type, int val); +#endif diff --git a/midi2.c b/midi2.c index 7683721..f0c5175 100644 --- a/midi2.c +++ b/midi2.c @@ -8,12 +8,21 @@ */ #include + #include #include #include #include +#include "receiver.h" +#include "discovered.h" +#include "adc.h" +#include "dac.h" +#include "transmitter.h" +#include "radio.h" +#include "main.h" #include "midi.h" + struct cmdtable MidiCommandsTable; void NewMidiEvent(enum MIDIevent event, int channel, int note, int val) { @@ -24,15 +33,15 @@ void NewMidiEvent(enum MIDIevent event, int channel, int note, int val) { static struct timespec tp, last_wheel_tp={0,0}; long delta; -//g_print("%s:EVENT=%d CHAN=%d NOTE=%d VAL=%d\n",__FUNCTION__,event,channel,note,val); +//g_print("%s: EVENT=%d CHAN=%d NOTE=%d VAL=%d\n",__FUNCTION__,event,channel,note,val); if (event == MIDI_PITCH) { desc=MidiCommandsTable.pitch; } else { desc=MidiCommandsTable.desc[note]; } -//fprintf(stderr,"MIDI:init DESC=%p\n",desc); +//g_print("%s: init DESC=%p\n",__FUNCTION__,desc); while (desc) { -//fprintf(stderr,"DESC=%p next=%p CHAN=%d EVENT=%d\n", desc,desc->next,desc->channel,desc->event); +//g_print("%s: DESC=%p next=%p CHAN=%d EVENT=%d\n",__FUNCTION__,desc,desc->next,desc->channel,desc->event); if ((desc->channel == channel || desc->channel == -1) && (desc->event == event)) { // Found matching entry switch (desc->event) { @@ -56,12 +65,15 @@ void NewMidiEvent(enum MIDIevent event, int channel, int note, int val) { } // translate value to direction new=0; + new=val-64; + /* if ((val >= desc->vfl1) && (val <= desc->vfl2)) new=-100; if ((val >= desc-> fl1) && (val <= desc-> fl2)) new=-10; 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); @@ -86,12 +98,15 @@ 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_PITCH) fprintf(stderr, "Unassigned PitchBend Value=%d\n", val); - if (event == MIDI_NOTE ) fprintf(stderr, "Unassigned Key Note=%d Val=%d\n", note, val); - if (event == MIDI_CTRL ) fprintf(stderr, "Unassigned Controller Ctl=%d Val=%d\n", note, val); + if (event == MIDI_PITCH) g_print("%s: Unassigned PitchBend Value=%d\n",__FUNCTION__, val); + if (event == MIDI_NOTE ) g_print("%s: Unassigned Key Note=%d Val=%d\n",__FUNCTION__, note, val); + if (event == MIDI_CTRL ) g_print("%s: Unassigned Controller Ctl=%d Val=%d\n",__FUNCTION__, 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. @@ -100,72 +115,113 @@ void NewMidiEvent(enum MIDIevent event, int channel, int note, int val) { * a match for "VFO" when the key word is "VFOA". */ +/* static struct { enum MIDIaction action; const char *str; + enum MIDItype type; } ActionTable[] = { - { VFO_A2B, "A2B"}, - { MIDI_AF_GAIN, "AFGAIN"}, - { AGCATTACK, "AGCATTACK"}, - { MIDI_AGC, "AGCVAL"}, - { ANF, "ANF"}, - { ATT, "ATT"}, - { VFO_B2A, "B2A"}, - { BAND_DOWN, "BANDDOWN"}, - { BAND_UP, "BANDUP"}, - { COMPRESS, "COMPRESS"}, - { MIDI_CTUN, "CTUN"}, - { VFO, "CURRVFO"}, - { CWL, "CWL"}, - { CWR, "CWR"}, - { CWSPEED, "CWSPEED"}, - { DIV_COARSEGAIN, "DIVCOARSEGAIN"}, - { DIV_COARSEPHASE, "DIVCOARSEPHASE"}, - { DIV_FINEGAIN, "DIVFINEGAIN"}, - { DIV_FINEPHASE, "DIVFINEPHASE"}, - { DIV_GAIN, "DIVGAIN"}, - { DIV_PHASE, "DIVPHASE"}, - { DIV_TOGGLE, "DIVTOGGLE"}, - { MIDI_DUP, "DUP"}, - { FILTER_DOWN, "FILTERDOWN"}, - { FILTER_UP, "FILTERUP"}, - { MIDI_LOCK, "LOCK"}, - { MIC_VOLUME, "MICGAIN"}, - { MODE_DOWN, "MODEDOWN"}, - { MODE_UP, "MODEUP"}, - { MIDI_MOX, "MOX"}, - { MIDI_MUTE, "MUTE"}, - { MIDI_NB, "NOISEBLANKER"}, - { MIDI_NR, "NOISEREDUCTION"}, - { MIDI_PAN, "PAN"}, - { PAN_HIGH, "PANHIGH"}, - { PAN_LOW, "PANLOW"}, - { PRE, "PREAMP"}, - { MIDI_PS, "PURESIGNAL"}, - { MIDI_RF_GAIN, "RFGAIN"}, - { TX_DRIVE, "RFPOWER"}, - { MIDI_RIT_CLEAR, "RITCLEAR"}, - { RIT_STEP, "RITSTEP"}, - { RIT_TOGGLE, "RITTOGGLE"}, - { RIT_VAL, "RITVAL"}, - { MIDI_SAT, "SAT"}, - { SNB, "SNB"}, - { MIDI_SPLIT, "SPLIT"}, - { SWAP_RX, "SWAPRX"}, - { SWAP_VFO, "SWAPVFO"}, - { MIDI_TUNE, "TUNE"}, - { VFOA, "VFOA"}, - { VFOB, "VFOB"}, - { VFO_STEP_UP, "VFOSTEPUP"}, - { VFO_STEP_DOWN, "VFOSTEPDOWN"}, - { VOX, "VOX"}, - { VOXLEVEL, "VOXLEVEL"}, - { MIDI_XIT_CLEAR, "XITCLEAR"}, - { XIT_VAL, "XITVAL"}, - { MIDI_ZOOM, "ZOOM"}, - { ZOOM_UP, "ZOOMUP"}, - { ZOOM_DOWN, "ZOOMDOWN"}, - { ACTION_NONE, "NONE"} +*/ +ACTION_TABLE ActionTable[] = { + { ACTION_NONE, "NONE", TYPE_NONE}, + { VFO_A2B, "A2B", MIDI_KEY}, + { MIDI_AF_GAIN, "AFGAIN", MIDI_KNOB|MIDI_WHEEL}, + { AGCATTACK, "AGCATTACK", MIDI_KEY}, + { MIDI_AGC, "AGCVAL", MIDI_KNOB|MIDI_WHEEL}, + { ANF, "ANF", MIDI_KEY}, + { ATT, "ATT", MIDI_KNOB|MIDI_WHEEL}, + { VFO_B2A, "B2A", MIDI_KEY}, + { MIDI_BAND_10, "BAND10", MIDI_KEY}, + { MIDI_BAND_12, "BAND12", MIDI_KEY}, + { MIDI_BAND_1240, "BAND1240", MIDI_KEY}, + { MIDI_BAND_144, "BAND144", MIDI_KEY}, + { MIDI_BAND_15, "BAND15", MIDI_KEY}, + { MIDI_BAND_160, "BAND160", MIDI_KEY}, + { MIDI_BAND_17, "BAND17", MIDI_KEY}, + { MIDI_BAND_20, "BAND20", MIDI_KEY}, + { MIDI_BAND_220, "BAND220", MIDI_KEY}, + { MIDI_BAND_2300, "BAND2300", MIDI_KEY}, + { MIDI_BAND_30, "BAND30", MIDI_KEY}, + { MIDI_BAND_3400, "BAND3400", MIDI_KEY}, + { MIDI_BAND_40, "BAND40", MIDI_KEY}, + { MIDI_BAND_430, "BAND430", MIDI_KEY}, + { MIDI_BAND_6, "BAND6", MIDI_KEY}, + { MIDI_BAND_60, "BAND60", MIDI_KEY}, + { MIDI_BAND_70, "BAND70", MIDI_KEY}, + { MIDI_BAND_80, "BAND80", MIDI_KEY}, + { MIDI_BAND_902, "BAND902", MIDI_KEY}, + { MIDI_BAND_AIR, "BANDAIR", MIDI_KEY}, + { BAND_DOWN, "BANDDOWN", MIDI_KEY}, + { MIDI_BAND_GEN, "BANDGEN", MIDI_KEY}, + { BAND_UP, "BANDUP", MIDI_KEY}, + { MIDI_BAND_WWV, "BANDWWV", MIDI_KEY}, + { COMPRESS, "COMPRESS", MIDI_KEY}, + { MIDI_CTUN, "CTUN", MIDI_KEY}, + { VFO, "CURRVFO", MIDI_WHEEL}, + { CWLEFT, "CWL", MIDI_KEY}, + { CWRIGHT, "CWR", MIDI_KEY}, + { CWSPEED, "CWSPEED", MIDI_KNOB|MIDI_WHEEL}, + { DIV_COARSEGAIN, "DIVCOARSEGAIN", MIDI_KNOB|MIDI_WHEEL}, + { DIV_COARSEPHASE, "DIVCOARSEPHASE", MIDI_KNOB|MIDI_WHEEL}, + { DIV_FINEGAIN, "DIVFINEGAIN", MIDI_KNOB|MIDI_WHEEL}, + { DIV_FINEPHASE, "DIVFINEPHASE", MIDI_KNOB|MIDI_WHEEL}, + { DIV_GAIN, "DIVGAIN", MIDI_KNOB|MIDI_WHEEL}, + { DIV_PHASE, "DIVPHASE", MIDI_KNOB|MIDI_WHEEL}, + { DIV_TOGGLE, "DIVTOGGLE", MIDI_KEY}, + { MIDI_DUP, "DUP", MIDI_KEY}, + { FILTER_DOWN, "FILTERDOWN", MIDI_KEY}, + { FILTER_UP, "FILTERUP", MIDI_KEY}, + { MENU_FILTER, "MENU_FILTER", MIDI_KEY}, + { MENU_MODE, "MENU_MODE", MIDI_KEY}, + { MIDI_LOCK, "LOCK", MIDI_KEY}, + { MIC_VOLUME, "MICGAIN", MIDI_KNOB|MIDI_WHEEL}, + { MODE_DOWN, "MODEDOWN", MIDI_KEY|MIDI_KNOB|MIDI_WHEEL}, + { MODE_UP, "MODEUP", MIDI_KEY|MIDI_KNOB|MIDI_WHEEL}, + { MIDI_MOX, "MOX", MIDI_KEY}, + { MIDI_MUTE, "MUTE", MIDI_KEY}, + { MIDI_NB, "NOISEBLANKER", MIDI_KEY}, + { MIDI_NR, "NOISEREDUCTION", MIDI_KEY}, + { NUMPAD_0, "NUMPAD0", MIDI_KEY}, + { NUMPAD_1, "NUMPAD1", MIDI_KEY}, + { NUMPAD_2, "NUMPAD2", MIDI_KEY}, + { NUMPAD_3, "NUMPAD3", MIDI_KEY}, + { NUMPAD_4, "NUMPAD4", MIDI_KEY}, + { NUMPAD_5, "NUMPAD5", MIDI_KEY}, + { NUMPAD_6, "NUMPAD6", MIDI_KEY}, + { NUMPAD_7, "NUMPAD7", MIDI_KEY}, + { NUMPAD_8, "NUMPAD8", MIDI_KEY}, + { NUMPAD_9, "NUMPAD9", MIDI_KEY}, + { NUMPAD_CL, "NUMPADCL", MIDI_KEY}, + { NUMPAD_ENTER, "NUMPADENTER", MIDI_KEY}, + { MIDI_PAN, "PAN", MIDI_KNOB|MIDI_WHEEL}, + { PAN_HIGH, "PANHIGH", MIDI_KNOB|MIDI_WHEEL}, + { PAN_LOW, "PANLOW", MIDI_KNOB|MIDI_WHEEL}, + { PRE, "PREAMP", MIDI_KEY}, + { MIDI_PS, "PURESIGNAL", MIDI_KEY}, + { MIDI_RF_GAIN, "RFGAIN", MIDI_KNOB|MIDI_WHEEL}, + { TX_DRIVE, "RFPOWER", MIDI_KNOB|MIDI_WHEEL}, + { MIDI_RIT_CLEAR, "RITCLEAR", MIDI_KEY}, + { RIT_STEP, "RITSTEP", MIDI_KNOB|MIDI_WHEEL}, + { RIT_TOGGLE, "RITTOGGLE", MIDI_KEY}, + { RIT_VAL, "RITVAL", MIDI_KNOB|MIDI_WHEEL}, + { MIDI_SAT, "SAT", MIDI_KEY}, + { SNB, "SNB", MIDI_KEY}, + { MIDI_SPLIT, "SPLIT", MIDI_KEY}, + { SWAP_RX, "SWAPRX", MIDI_KEY}, + { SWAP_VFO, "SWAPVFO", MIDI_KEY}, + { MIDI_TUNE, "TUNE", MIDI_KEY}, + { VFOA, "VFOA", MIDI_WHEEL}, + { VFOB, "VFOB", MIDI_WHEEL}, + { VFO_STEP_UP, "VFOSTEPUP", MIDI_KEY}, + { VFO_STEP_DOWN, "VFOSTEPDOWN", MIDI_KEY}, + { VOX, "VOX", MIDI_KEY}, + { VOXLEVEL, "VOXLEVEL", MIDI_KNOB|MIDI_WHEEL}, + { MIDI_XIT_CLEAR, "XITCLEAR", MIDI_KEY}, + { XIT_VAL, "XITVAL", MIDI_KNOB|MIDI_WHEEL}, + { MIDI_ZOOM, "ZOOM", MIDI_KNOB|MIDI_WHEEL}, + { ZOOM_UP, "ZOOMUP", MIDI_KEY}, + { ZOOM_DOWN, "ZOOMDOWN", MIDI_KEY}, + { ACTION_NONE, "NONE", TYPE_NONE} }; /* @@ -182,12 +238,19 @@ static enum MIDIaction keyword2action(char *s) { return ACTION_NONE; } + +int MIDIstop() { + midi_enabled=FALSE; + close_midi_device(); + return 0; +} + /* - * Here we read in a MIDI description file "midi.def" and fill the MidiCommandsTable + * 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; @@ -205,8 +268,14 @@ void MIDIstartup() { for (i=0; i<128; i++) MidiCommandsTable.desc[i]=NULL; MidiCommandsTable.pitch=NULL; - 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; @@ -231,7 +300,7 @@ void MIDIstartup() { cp++; } -//fprintf(stderr,"\nMIDI:INP:%s\n",zeile); +g_print("\n%s:INP:%s\n",__FUNCTION__,zeile); if ((cp = strstr(zeile, "DEVICE="))) { // Delete comments and trailing blanks @@ -241,7 +310,7 @@ void MIDIstartup() { while (cq > cp+7 && (*cq == ' ' || *cq == '\t')) cq--; *(cq+1)=0; //fprintf(stderr,"MIDI:REG:>>>%s<<<\n",cp+7); - register_midi_device(cp+7); + int result=register_midi_device(cp+7); continue; // nothing more in this line } chan=-1; // default: any channel @@ -262,18 +331,18 @@ void MIDIstartup() { sscanf(cp+4, "%d", &key); event=MIDI_NOTE; type=MIDI_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_CTRL; type=MIDI_KNOB; -//fprintf(stderr,"MIDI:CTL:%d\n", key); +g_print("%s: MIDI:CTL:%d\n",__FUNCTION__, key); } if ((cp = strstr(zeile, "PITCH "))) { event=MIDI_PITCH; type=MIDI_KNOB; -//fprintf(stderr,"MIDI:PITCH\n"); +g_print("%s: MIDI:PITCH\n",__FUNCTION__); } // // If event is still undefined, skip line @@ -293,20 +362,20 @@ 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_KNOB)) { // change type from MIDI_KNOB to MIDI_WHEEL type=MIDI_WHEEL; -//fprintf(stderr,"MIDI:WHEEL\n"); +g_print("%s:WHEEL\n",__FUNCTION__); } if ((cp = strstr(zeile, "ONOFF"))) { onoff=1; -//fprintf(stderr,"MIDI:ONOFF\n"); +g_print("%s:ONOFF\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", @@ -319,7 +388,7 @@ void MIDIstartup() { while (*cq != 0 && *cq != '\n' && *cq != ' ' && *cq != '\t') cq++; *cq=0; action=keyword2action(cp+7); -//fprintf(stderr,"MIDI:ACTION:%s (%d)\n",cp+7, action); +g_print("%s: MIDI:ACTION:%s (%d)\n",__FUNCTION__,cp+7, action); } // // All data for a descriptor has been read. Construct it! @@ -359,7 +428,7 @@ void MIDIstartup() { } } if (event == MIDI_KEY || event == MIDI_CTRL) { -//fprintf(stderr,"MIDI:TAB:Insert desc=%p in CMDS[%d] table\n",desc,key); +g_print("%s:TAB:Insert desc=%p in CMDS[%d] table\n",__FUNCTION__,desc,key); dp = MidiCommandsTable.desc[key]; if (dp == NULL) { MidiCommandsTable.desc[key]=desc; @@ -369,4 +438,6 @@ void MIDIstartup() { } } } + + return 0; } diff --git a/midi3.c b/midi3.c index 3a096aa..212f3c6 100644 --- a/midi3.c +++ b/midi3.c @@ -148,6 +148,166 @@ void DoTheMidi(enum MIDIaction action, enum MIDItype type, int val) { g_idle_add(ext_vfo_b_to_a, NULL); } break; + /////////////////////////////////////////////////////////// "NUMPADxx" + case NUMPAD_0: + g_idle_add(ext_num_pad,GINT_TO_POINTER(0)); + break; + case NUMPAD_1: + g_idle_add(ext_num_pad,GINT_TO_POINTER(1)); + break; + case NUMPAD_2: + g_idle_add(ext_num_pad,GINT_TO_POINTER(2)); + break; + case NUMPAD_3: + g_idle_add(ext_num_pad,GINT_TO_POINTER(3)); + break; + case NUMPAD_4: + g_idle_add(ext_num_pad,GINT_TO_POINTER(4)); + break; + case NUMPAD_5: + g_idle_add(ext_num_pad,GINT_TO_POINTER(5)); + break; + case NUMPAD_6: + g_idle_add(ext_num_pad,GINT_TO_POINTER(6)); + break; + case NUMPAD_7: + g_idle_add(ext_num_pad,GINT_TO_POINTER(7)); + break; + case NUMPAD_8: + g_idle_add(ext_num_pad,GINT_TO_POINTER(8)); + break; + case NUMPAD_9: + g_idle_add(ext_num_pad,GINT_TO_POINTER(9)); + break; + case NUMPAD_CL: + g_idle_add(ext_num_pad,GINT_TO_POINTER(-1)); + break; + case NUMPAD_ENTER: + g_idle_add(ext_num_pad,GINT_TO_POINTER(-2)); + break; + break; + + /////////////////////////////////////////////////////////// "BANDxxx" + case MIDI_BAND_10: + if (type == MIDI_KEY) { + g_idle_add(ext_band_select, GINT_TO_POINTER(band10)); + } + break; + case MIDI_BAND_12: + if (type == MIDI_KEY) { + g_idle_add(ext_band_select, GINT_TO_POINTER(band12)); + } + break; +#ifdef SOAPYSDR + case MIDI_BAND_1240: + if (type == MIDI_KEY) { + g_idle_add(ext_band_select, GINT_TO_POINTER(band1240)); + } + break; + case MIDI_BAND_144: + if (type == MIDI_KEY) { + g_idle_add(ext_band_select, GINT_TO_POINTER(band144)); + } + break; +#endif + case MIDI_BAND_15: + if (type == MIDI_KEY) { + g_idle_add(ext_band_select, GINT_TO_POINTER(band15)); + } + break; + case MIDI_BAND_160: + if (type == MIDI_KEY) { + g_idle_add(ext_band_select, GINT_TO_POINTER(band160)); + } + break; + case MIDI_BAND_17: + if (type == MIDI_KEY) { + g_idle_add(ext_band_select, GINT_TO_POINTER(band17)); + } + break; + case MIDI_BAND_20: + if (type == MIDI_KEY) { + g_idle_add(ext_band_select, GINT_TO_POINTER(band20)); + } + break; +#ifdef SOAPYSDR + case MIDI_BAND_220: + if (type == MIDI_KEY) { + g_idle_add(ext_band_select, GINT_TO_POINTER(band220)); + } + break; + case MIDI_BAND_2300: + if (type == MIDI_KEY) { + g_idle_add(ext_band_select, GINT_TO_POINTER(band2300)); + } + break; +#endif + case MIDI_BAND_30: + if (type == MIDI_KEY) { + g_idle_add(ext_band_select, GINT_TO_POINTER(band30)); + } + break; +#ifdef SOAPYSDR + case MIDI_BAND_3400: + if (type == MIDI_KEY) { + g_idle_add(ext_band_select, GINT_TO_POINTER(band3400)); + } + break; + case MIDI_BAND_70: + if (type == MIDI_KEY) { + g_idle_add(ext_band_select, GINT_TO_POINTER(band70)); + } + break; +#endif + case MIDI_BAND_40: + if (type == MIDI_KEY) { + g_idle_add(ext_band_select, GINT_TO_POINTER(band40)); + } + break; +#ifdef SOAPYSDR + case MIDI_BAND_430: + if (type == MIDI_KEY) { + g_idle_add(ext_band_select, GINT_TO_POINTER(band430)); + } + break; +#endif + case MIDI_BAND_6: + if (type == MIDI_KEY) { + g_idle_add(ext_band_select, GINT_TO_POINTER(band6)); + } + break; + case MIDI_BAND_60: + if (type == MIDI_KEY) { + g_idle_add(ext_band_select, GINT_TO_POINTER(band60)); + } + break; + case MIDI_BAND_80: + if (type == MIDI_KEY) { + g_idle_add(ext_band_select, GINT_TO_POINTER(band80)); + } + break; +#ifdef SOAPYSDR + case MIDI_BAND_902: + if (type == MIDI_KEY) { + g_idle_add(ext_band_select, GINT_TO_POINTER(band902)); + } + break; + case MIDI_BAND_AIR: + if (type == MIDI_KEY) { + g_idle_add(ext_band_select, GINT_TO_POINTER(bandAIR)); + } + break; +#endif + case MIDI_BAND_GEN: + if (type == MIDI_KEY) { + g_idle_add(ext_band_select, GINT_TO_POINTER(bandGen)); + } + break; + case MIDI_BAND_WWV: + if (type == MIDI_KEY) { + g_idle_add(ext_band_select, GINT_TO_POINTER(bandWWV)); + } + break; /////////////////////////////////////////////////////////// "BANDDOWN" /////////////////////////////////////////////////////////// "BANDUP" case BAND_DOWN: @@ -218,15 +378,15 @@ void DoTheMidi(enum MIDIaction action, enum MIDItype type, int val) { break; /////////////////////////////////////////////////////////// "CWL" /////////////////////////////////////////////////////////// "CWR" - case CWL: // only key - case CWR: // only key + case CWLEFT: // only key + case CWRIGHT: // only key #ifdef LOCALCW if (type == MIDI_KEY) { - new=(action == CWL); + new=(action == CWLEFT); keyer_event(new,val); } #else - g_print("%s: %s:%d\n",__FUNCTION__,action==CWL?"CWL":"CWR",val); + g_print("%s: %s:%d\n",__FUNCTION__,action==CWLEFT?"CWL":"CWR",val); #endif break; @@ -375,6 +535,14 @@ void DoTheMidi(enum MIDIaction action, enum MIDItype type, int val) { g_idle_add(ext_vfo_filter_changed, GINT_TO_POINTER(new)); } break; + /////////////////////////////////////////////////////////// "MENU_FILTFILTERER" + case MENU_FILTER: + g_idle_add(ext_menu_filter, NULL); + break; + /////////////////////////////////////////////////////////// "MENU_MODE" + case MENU_MODE: + g_idle_add(ext_menu_mode, NULL); + break; /////////////////////////////////////////////////////////// "LOCK" case MIDI_LOCK: // only key supported if (type == MIDI_KEY) { diff --git a/midi_menu.c b/midi_menu.c new file mode 100644 index 0000000..2a85480 --- /dev/null +++ b/midi_menu.c @@ -0,0 +1,1222 @@ +/* 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; +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 *add_b; +static GtkWidget *update_b; +static GtkWidget *delete_b; + +static enum MIDIevent thisEvent=EVENT_NONE; +static int thisChannel; +static int thisNote; +static int thisVal; +static int thisMin; +static int thisMax; +static enum MIDItype thisType; +static enum MIDIaction thisAction; + +gchar *midi_device_name=NULL; +static gint device_index=-1; + +enum { + UPDATE_NEW, + UPDATE_CURRENT, + UPDATE_EXISTING +}; + +static int update(void *data); +static void load_store(); + +static void cleanup() { + 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 gboolean midi_enable_cb(GtkWidget *widget,gpointer data) { + if(midi_enabled) { + close_midi_device(); + } + midi_enabled=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (widget)); + if(midi_enabled) { + if(register_midi_device(midi_device_name)<0) { + midi_enabled=FALSE; + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (widget), midi_enabled); + } + } + return TRUE; +} + +static void configure_cb(GtkWidget *widget, gpointer data) { + gboolean conf=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (widget)); + configure_midi_device(conf); +} + +static void device_changed_cb(GtkWidget *widget, gpointer data) { + device_index = gtk_combo_box_get_active(GTK_COMBO_BOX(widget)); + if(midi_device_name!=NULL) { + g_free(midi_device_name); + } + midi_device_name=g_new(gchar,strlen(midi_devices[device_index].name)+1); + strcpy(midi_device_name,midi_devices[device_index].name); + if(midi_enabled) { + close_midi_device(); + if(register_midi_device(midi_device_name)) { + midi_enabled=FALSE; + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(midi_enable_b), midi_enabled); + } + } +} + +static void type_changed_cb(GtkWidget *widget, gpointer data) { + int i=1; + int j=1; + + // 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)); + gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(newAction),NULL,ActionTable[0].str); + if(type==NULL || strcmp(type,"NONE")==0) { + // leave empty + gtk_combo_box_set_active (GTK_COMBO_BOX(newAction),0); + } else if(strcmp(type,"KEY")==0) { + // add all the Key actions + while(ActionTable[i].action!=ACTION_NONE) { + if(ActionTable[i].type&MIDI_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) { + // add all the Knob actions + while(ActionTable[i].action!=ACTION_NONE) { + if(ActionTable[i].type&MIDI_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) { + // add all the Wheel actions + while(ActionTable[i].action!=ACTION_NONE) { + if(ActionTable[i].type&MIDI_WHEEL || ActionTable[i].type&MIDI_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++; + } + } +} + +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_CTRL; + } else if(strcmp(str_event,"PITCH")==0) { + thisEvent=MIDI_PITCH; + } else if(strcmp(str_event,"NOTE")==0) { + thisEvent=MIDI_NOTE; + } else { + thisEvent=EVENT_NONE; + } + thisChannel=atoi(str_channel); + thisNote=atoi(str_note); + thisVal=0; + thisMin=0; + thisMax=0; + if(strcmp(str_type,"KEY")==0) { + thisType=MIDI_KEY; + } else if(strcmp(str_type,"KNOB/SLIDER")==0) { + thisType=MIDI_KNOB; + } else if(strcmp(str_type,"WHEEL")==0) { + thisType=MIDI_WHEEL; + } else { + thisType=TYPE_NONE; + } + thisAction=ACTION_NONE; + int i=1; + while(ActionTable[i].action!=ACTION_NONE) { + 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:\n",__FUNCTION__); + cmd=MidiCommandsTable.desc[thisNote]; + while(cmd!=NULL) { + if((cmd->channel==thisChannel || cmd->channel==-1) && cmd->type==thisType && cmd->action==thisAction) { + g_print("%s: found cmd %p\n",__FUNCTION__,cmd); + break; + } + cmd=cmd->next; + } + current_cmd=cmd; +} + +static void clear_cb(GtkWidget *widget,gpointer user_data) { + struct desc *cmd; + struct desc *next; + for(int i=0;i<128;i++) { + cmd=MidiCommandsTable.desc[i]; + while(cmd!=NULL) { + next=cmd->next; + g_free(cmd); + cmd=next; + } + MidiCommandsTable.desc[i]=NULL; + } + gtk_list_store_clear(store); +} + +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); + if(midi_device_name==NULL) { + filename=g_new(gchar,10); + sprintf(filename,"midi.midi"); + } else { + filename=g_new(gchar,strlen(midi_device_name)+6); + sprintf(filename,"%s.midi",midi_device_name); + } + gtk_file_chooser_set_current_name(chooser,filename); + 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); + g_free(filename); +} + +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, + "_Save", + GTK_RESPONSE_ACCEPT, + NULL); + chooser = GTK_FILE_CHOOSER (load_dialog); + if(midi_device_name==NULL) { + filename=g_new(gchar,10); + sprintf(filename,"midi.midi"); + } else { + filename=g_new(gchar,strlen(midi_device_name)+6); + sprintf(filename,"%s.midi",midi_device_name); + } + gtk_file_chooser_set_current_name(chooser,filename); + 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(); + load_store(); + g_free(loadfilename); + } + gtk_widget_destroy(load_dialog); + g_free(filename); +} + +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 ORIGINAL MIDI File", + GTK_WINDOW(dialog), + action, + "_Cancel", + GTK_RESPONSE_CANCEL, + "_Save", + GTK_RESPONSE_ACCEPT, + NULL); + chooser = GTK_FILE_CHOOSER (load_dialog); + filename=g_new(gchar,strlen(midi_device_name)+6); + sprintf(filename,"%s.midi",midi_device_name); + gtk_file_chooser_set_current_name(chooser,filename); + 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); + load_store(); + g_free(loadfilename); + } + gtk_widget_destroy(load_dialog); + g_free(filename); +} + +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 EVENT_NONE: + strcpy(str_event,"NONE"); + break; + case MIDI_NOTE: + strcpy(str_event,"NOTE"); + break; + case MIDI_CTRL: + strcpy(str_event,"CTRL"); + break; + case MIDI_PITCH: + strcpy(str_event,"PITCH"); + break; + } + sprintf(str_channel,"%d",cmd->channel); + sprintf(str_note,"%d",key); + switch(cmd->type) { + case TYPE_NONE: + strcpy(str_type,"NONE"); + break; + case MIDI_KEY: + strcpy(str_type,"KEY"); + break; + case MIDI_KNOB: + strcpy(str_type,"KNOB/SLIDER"); + break; + case MIDI_WHEEL: + strcpy(str_type,"WHEEL"); + break; + } + strcpy(str_action,ActionTable[cmd->action].str); + 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=0;i<128;i++) { + cmd=MidiCommandsTable.desc[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; + + if(strcmp(str_type,"KEY")==0) { + type=MIDI_KEY; + } else if(strcmp(str_type,"KNOB/SLIDER")==0) { + type=MIDI_KNOB; + } else if(strcmp(str_type,"WHEEL")==0) { + type=MIDI_WHEEL; + } else { + type=TYPE_NONE; + } + + action=ACTION_NONE; + i=1; + while(ActionTable[i].action!=ACTION_NONE) { + if(strcmp(ActionTable[i].str,str_action)==0) { + action=ActionTable[i].action; + 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 = action==CWLEFT || action==CWRIGHT; + desc->delay = 0; + desc->vfl1 = -1; + desc->vfl2 = -1; + desc->fl1 = -1; + desc->fl2 = -1; + desc->lft1 = -1; + desc->lft2 = 63; + desc->rgt1 = 64; + desc->rgt2 = 128; + desc->fr1 = 128; + desc->fr2 = 128; + desc->vfr1 = 128; + desc->vfr2 = 128; + desc->channel = thisChannel; + + gint key=thisNote; + if(key<0) key=0; + if(key>127) key=0; + + + if(MidiCommandsTable.desc[key]!=NULL) { + desc->next=MidiCommandsTable.desc[key]; + } + MidiCommandsTable.desc[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; + + + 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_KEY; + } else if(strcmp(str_type,"KNOB/SLIDER")==0) { + thisType=MIDI_KNOB; + } else if(strcmp(str_type,"WHEEL")==0) { + thisType=MIDI_WHEEL; + } else { + thisType=TYPE_NONE; + } + + thisAction=ACTION_NONE; + i=1; + while(ActionTable[i].action!=ACTION_NONE) { + if(strcmp(ActionTable[i].str,str_action)==0) { + thisAction=ActionTable[i].action; + break; + } + i++; + } + + current_cmd->channel=thisChannel; + current_cmd->type=thisType; + current_cmd->action=thisAction; + + switch(current_cmd->event) { + case EVENT_NONE: + strcpy(str_event,"NONE"); + break; + case MIDI_NOTE: + strcpy(str_event,"NOTE"); + break; + case MIDI_CTRL: + strcpy(str_event,"CTRL"); + break; + case MIDI_PITCH: + strcpy(str_event,"PITCH"); + break; + } + sprintf(str_channel,"%d",current_cmd->channel); + 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); + + saved_iter=iter; + + + // remove from MidiCommandsTable + if(MidiCommandsTable.desc[thisNote]==current_cmd) { + g_print("%s: remove first\n",__FUNCTION__); + MidiCommandsTable.desc[thisNote]=current_cmd->next; + g_free(current_cmd); + } else { + previous_cmd=MidiCommandsTable.desc[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); + 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; + + dialog=gtk_dialog_new(); + gtk_window_set_transient_for(GTK_WINDOW(dialog),GTK_WINDOW(parent_window)); + char title[64]; + sprintf(title,"piHPSDR - MIDI"); + gtk_window_set_title(GTK_WINDOW(dialog),title); + 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; + + get_midi_devices(); + if(n_midi_devices>0) { + GtkWidget *devices_label=gtk_label_new("Select MIDI device: "); + gtk_grid_attach(GTK_GRID(grid),devices_label,col,row,3,1); + col+=3; + + GtkWidget *devices=gtk_combo_box_text_new(); + for(int i=0;ithisMax) 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; + thisNote=note; + thisVal=val; + thisMin=val; + thisMax=val; + thisType=TYPE_NONE; + thisAction=ACTION_NONE; + + // 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_CTRL; + } else if(strcmp(str_event,"PITCH")==0) { + tree_event=MIDI_PITCH; + } else if(strcmp(str_event,"NOTE")==0) { + tree_event=MIDI_NOTE; + } else { + tree_event=EVENT_NONE; + } + tree_channel=atoi(str_channel); + tree_note=atoi(str_note); + + if(thisEvent==tree_event && (thisChannel==tree_channel || tree_channel==-1) && thisNote==tree_note) { + thisVal=0; + thisMin=0; + thisMax=0; + if(strcmp(str_type,"KEY")==0) { + thisType=MIDI_KEY; + } else if(strcmp(str_type,"KNOB/SLIDER")==0) { + thisType=MIDI_KNOB; + } else if(strcmp(str_type,"WHEEL")==0) { + thisType=MIDI_WHEEL; + } else { + thisType=TYPE_NONE; + } + thisAction=ACTION_NONE; + int i=1; + while(ActionTable[i].action!=ACTION_NONE) { + 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); + } + + g_idle_add(update,GINT_TO_POINTER(UPDATE_NEW)); + } +} + +void midi_save_state() { + char name[80]; + char value[80]; + struct desc *cmd; + gint channels; + + if(device_index!=-1) { + setProperty("midi_device",midi_devices[device_index].name); + for(int i=0;i<128;i++) { + channels=0; + cmd=MidiCommandsTable.desc[i]; + while(cmd!=NULL) { + //g_print("%s: channel=%d key=%d event=%s onoff=%d type=%s action=%s\n",__FUNCTION__,cmd->channel,i,midi_events[cmd->event],cmd->onoff,midi_types[cmd->type],ActionTable[cmd->action].str); + + sprintf(name,"midi[%d].channel[%d]",i,channels); + sprintf(value,"%d",cmd->channel); + setProperty(name,value); + sprintf(name,"midi[%d].channel[%d].event",i,cmd->channel); + setProperty(name,midi_events[cmd->event]); + sprintf(name,"midi[%d].channel[%d].onoff",i,cmd->channel); + sprintf(value,"%d",cmd->onoff); + setProperty(name,value); + sprintf(name,"midi[%d].channel[%d].type",i,cmd->channel); + setProperty(name,midi_types[cmd->type]); + sprintf(name,"midi[%d].channel[%d].action",i,cmd->channel); + sprintf(value,"%s",ActionTable[cmd->action].str); + setProperty(name,value); + cmd=cmd->next; + channels++; + } + + if(channels!=0) { + sprintf(name,"midi[%d].channels",i); + sprintf(value,"%d",channels); + setProperty(name,value); + } + + } + } +} + +void midi_restore_state() { + char name[80]; + char *value; + gint channels; + gint channel; + gint event; + gint onoff; + gint type; + gint action; + + struct desc *cmd; + + get_midi_devices(); + + //g_print("%s\n",__FUNCTION__); + value=getProperty("midi_device"); + if(value) { + //g_print("%s: device=%s\n",__FUNCTION__,value); + midi_device_name=g_new(gchar,strlen(value)+1); + strcpy(midi_device_name,value); + + + for(int i=0;inext = NULL; + desc->action = action; // MIDIaction + desc->type = type; // MIDItype + desc->event = event; // MIDevent + desc->onoff = onoff; + desc->delay = 0; + desc->vfl1 = -1; + desc->vfl2 = -1; + desc->fl1 = -1; + desc->fl2 = -1; + desc->lft1 = -1; + desc->lft2 = 63; + desc->rgt1 = 64; + desc->rgt2 = 128; + desc->fr1 = 128; + desc->fr2 = 128; + desc->vfr1 = 128; + desc->vfr2 = 128; + desc->channel = channel; + + if(MidiCommandsTable.desc[i]!=NULL) { + desc->next=MidiCommandsTable.desc[i]; + } + MidiCommandsTable.desc[i]=desc; + } + } + } + } + +} + diff --git a/midi_menu.h b/midi_menu.h new file mode 100644 index 0000000..bed7e0a --- /dev/null +++ b/midi_menu.h @@ -0,0 +1,25 @@ +/* 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 gchar *midi_device_name; +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 24a819c..7c5c1b3 100644 --- a/new_menu.c +++ b/new_menu.c @@ -58,14 +58,15 @@ #include "fft_menu.h" #include "main.h" #include "actions.h" -#ifdef GPIO #include "gpio.h" -#endif #include "old_protocol.h" #include "new_protocol.h" #ifdef CLIENT_SERVER #include "server_menu.h" #endif +#ifdef MIDI +#include "midi_menu.h" +#endif static GtkWidget *menu_b=NULL; @@ -193,6 +194,7 @@ static gboolean encoder_cb (GtkWidget *widget, GdkEventButton *event, gpointer d encoder_menu(top_window); return TRUE; } +#endif static gboolean switch_cb (GtkWidget *widget, GdkEventButton *event, gpointer data) { cleanup(); @@ -200,8 +202,6 @@ static gboolean switch_cb (GtkWidget *widget, GdkEventButton *event, gpointer da return TRUE; } -#endif - static gboolean cw_cb (GtkWidget *widget, GdkEventButton *event, gpointer data) { cleanup(); cw_menu(top_window); @@ -433,6 +433,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; @@ -580,7 +592,6 @@ void new_menu() gtk_grid_attach(GTK_GRID(grid),rigctl_b,(i%5),i/5,1,1); i++; -#ifdef GPIO switch(controller) { case NO_CONTROLLER: { @@ -594,11 +605,12 @@ void new_menu() case CONTROLLER2_V1: case CONTROLLER2_V2: { +#ifdef GPIO GtkWidget *encoders_b=gtk_button_new_with_label("Encoders"); g_signal_connect (encoders_b, "button-press-event", G_CALLBACK(encoder_cb), NULL); gtk_grid_attach(GTK_GRID(grid),encoders_b,(i%5),i/5,1,1); i++; - +#endif GtkWidget *switches_b=gtk_button_new_with_label("Switches"); g_signal_connect (switches_b, "button-press-event", G_CALLBACK(switch_cb), NULL); gtk_grid_attach(GTK_GRID(grid),switches_b,(i%5),i/5,1,1); @@ -606,6 +618,12 @@ void new_menu() } break; } + +#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 // diff --git a/new_protocol.c b/new_protocol.c index 40a33e1..dfcb00e 100644 --- a/new_protocol.c +++ b/new_protocol.c @@ -75,8 +75,8 @@ #define RXACTION_PS 2 // deliver 2*119 samples to PS engine #define RXACTION_DIV 3 // take 2*119 samples, mix them, deliver to a receiver -static int rxcase[MAX_DDC]; -static int rxid [MAX_DDC]; +static int rxcase[7/*MAX_DDC*/]; +static int rxid [7/*MAX_DDC*/]; int data_socket=-1; @@ -109,8 +109,8 @@ static int audio_addr_length; static struct sockaddr_in iq_addr; static int iq_addr_length; -static struct sockaddr_in data_addr[MAX_DDC]; -static int data_addr_length[MAX_DDC]; +static struct sockaddr_in data_addr[7/*MAX_DDC*/]; +static int data_addr_length[7/*MAX_DDC*/]; static GThread *new_protocol_thread_id; static GThread *new_protocol_timer_thread_id; @@ -119,7 +119,7 @@ static long high_priority_sequence = 0; static long general_sequence = 0; static long rx_specific_sequence = 0; static long tx_specific_sequence = 0; -static long ddc_sequence[MAX_DDC]; +static long ddc_sequence[7/*MAX_DDC*/]; //static int buffer_size=BUFFER_SIZE; //static int fft_size=4096; @@ -175,13 +175,13 @@ static sem_t mic_line_sem_buffer; #endif static GThread *mic_line_thread_id; #ifdef __APPLE__ -static sem_t *iq_sem_ready[MAX_DDC]; -static sem_t *iq_sem_buffer[MAX_DDC]; +static sem_t *iq_sem_ready[7/*MAX_DDC*/]; +static sem_t *iq_sem_buffer[7/*MAX_DDC*/]; #else -static sem_t iq_sem_ready[MAX_DDC]; -static sem_t iq_sem_buffer[MAX_DDC]; +static sem_t iq_sem_ready[7/*MAX_DDC*/]; +static sem_t iq_sem_buffer[7/*MAX_DDC*/]; #endif -static GThread *iq_thread_id[MAX_DDC]; +static GThread *iq_thread_id[7/*MAX_DDC*/]; #ifdef INCLUDED static int outputsamples; @@ -199,7 +199,7 @@ static socklen_t length=sizeof(addr); // Network buffers #define NET_BUFFER_SIZE 2048 -static unsigned char *iq_buffer[MAX_DDC]; +static unsigned char *iq_buffer[7/*MAX_DDC*/]; static unsigned char *command_response_buffer; static unsigned char *high_priority_buffer; static unsigned char *mic_line_buffer; diff --git a/portaudio.c b/portaudio.c index 2ed083c..ac33586 100644 --- a/portaudio.c +++ b/portaudio.c @@ -454,8 +454,7 @@ int audio_write (RECEIVER *rx, float left, float right) return 0; } -int cw_audio_write(float sample) { - RECEIVER *rx = active_receiver; +int cw_audio_write(RECEIVER *rx,float sample) { float *buffer = rx->local_audio_buffer; if (rx->playback_handle != NULL && rx->local_audio_buffer != NULL) { diff --git a/radio.c b/radio.c index 5bbc536..05c1056 100644 --- a/radio.c +++ b/radio.c @@ -71,10 +71,12 @@ #include "iambic.h" #endif #ifdef MIDI +#include "alsa_midi.h" +#include "midi_menu.h" // 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(); +//extern void MIDIstartup(); #endif #ifdef CLIENT_SERVER #include "client_server.h" @@ -95,6 +97,10 @@ void MIDIstartup(); #define TOOLBAR_HEIGHT (30) #define WATERFALL_HEIGHT (105) +#ifdef MIDI +gboolean midi_enabled; +#endif + gint controller=NO_CONTROLLER; GtkWidget *fixed; @@ -114,29 +120,39 @@ 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 *receiver[7]; RECEIVER *active_receiver; TRANSMITTER *transmitter; +int RECEIVERS; +int MAX_RECEIVERS; +int MAX_DDC; +#ifdef PURESIGNAL +int PS_TX_FEEDBACK; +int PS_RX_FEEDBACK; +#endif + + + int buffer_size=1024; // 64, 128, 256, 512, 1024, 2048 int fft_size=2048; // 1024, 2048, 4096, 8192, 16384 @@ -198,7 +214,7 @@ int mic_ptt_tip_bias_ring=0; //int drive_level=0; //int tune_drive_level=0; -int receivers=RECEIVERS; +int receivers; ADC adc[2]; DAC dac[2]; @@ -620,7 +636,7 @@ if(!radio_is_remote) { break; #ifdef SOAPYSDR case SOAPYSDR_PROTOCOL: - soapy_protocol_init(0,false); + soapy_protocol_init(FALSE); break; #endif } @@ -648,12 +664,6 @@ if(!radio_is_remote) { y+=TOOLBAR_HEIGHT; } -// -// Now, if there should only one receiver be displayed -// at startup, do the change. We must momentarily fake -// the number of receivers otherwise radio_change_receivers -// will do nothing. -// g_print("create_visual: receivers=%d RECEIVERS=%d\n",receivers,RECEIVERS); if (receivers != RECEIVERS) { int r=receivers; @@ -1100,16 +1110,10 @@ 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; 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 @@ -1124,16 +1128,10 @@ 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; 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; @@ -1154,11 +1152,6 @@ void start_radio() { display_sliders=0; display_toolbar=0; break; - case CONTROLLER_I2C: - display_zoompan=0; - display_sliders=0; - display_toolbar=0; - break; } #else display_zoompan=1; @@ -1175,6 +1168,36 @@ void start_radio() { display_sequence_errors=TRUE; + g_print("%s: setup RECEIVERS protocol=%d\n",__FUNCTION__,protocol); + switch(protocol) { +#ifdef SOAPYSDR + case SOAPYSDR_PROTOCOL: + g_print("%s: setup RECEIVERS SOAPYSDR\n",__FUNCTION__); + RECEIVERS=1; + MAX_RECEIVERS=RECEIVERS; +#ifdef PURESIGNAL + PS_TX_FEEDBACK=0; + PS_RX_FEEDBACK=0; +#endif + MAX_DDC=1; + break; +#endif + default: + g_print("%s: setup RECEIVERS default\n",__FUNCTION__); + RECEIVERS=2; +#ifdef PURESIGNAL + MAX_RECEIVERS=(RECEIVERS+2); + PS_TX_FEEDBACK=(RECEIVERS); + PS_RX_FEEDBACK=(RECEIVERS+1); +#else + MAX_RECEIVERS=RECEIVERS; +#endif + MAX_DDC=(RECEIVERS+2); + break; + } + + receivers=RECEIVERS; + radioRestoreState(); // @@ -1234,28 +1257,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); @@ -1263,7 +1273,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 @@ -1278,7 +1288,14 @@ void start_radio() { // running. So this is the last thing we do when starting the radio. // #ifdef MIDI - MIDIstartup(); + g_print("%s: midi_enabled=%d midi_device_name=%s\n",__FUNCTION__,midi_enabled,midi_device_name); + if(midi_enabled && (midi_device_name!=NULL)) { + if(register_midi_device(midi_device_name)<0) { + midi_enabled=FALSE; + } + } else { + midi_enabled=FALSE; + } #endif #ifdef CLIENT_SERVER @@ -2066,12 +2083,8 @@ g_print("radioRestoreState: %s\n",property_path); #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].gain"); + if(value!=NULL) adc[0].gain=atoi(value); value=getProperty("radio.adc[0].agc"); if(value!=NULL) adc[0].agc=atoi(value); value=getProperty("radio.adc[0].antenna"); @@ -2079,14 +2092,17 @@ g_print("radioRestoreState: %s\n",property_path); 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); - } + value=getProperty("radio.dac[0].gain"); + if(value!=NULL) dac[0].gain=atoi(value); } #endif +#ifdef MIDI + midi_restore_state(); + value=getProperty("radio.midi_enabled"); + if(value) midi_enabled=atoi(value); +#endif + value=getProperty("radio.display_sequence_errors"); if(value!=NULL) display_sequence_errors=atoi(value); @@ -2322,49 +2338,32 @@ g_print("radioSaveState: %s\n",property_path); #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,"%f", adc[0].gain); + setProperty("radio.adc[0].gain",value); sprintf(value,"%d", soapy_protocol_get_automatic_gain(receiver[0])); - setProperty(name,value); - sprintf(name,"radio.adc[0].antenna"); + setProperty("radio.adc[0].agc",value); sprintf(value,"%d", adc[0].antenna); - setProperty(name,value); + setProperty("radio.adc[0].antenna",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); - } - - 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"); - 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.dac[0].antenna",value); + + sprintf(value,"%f", dac[0].gain); + setProperty("radio.dac[0].gain",value); + + if(receivers>1) { + sprintf(value,"%f", adc[1].gain); + setProperty("radio.adc[1].gain",value); + sprintf(value,"%d", soapy_protocol_get_automatic_gain(receiver[1])); + setProperty("radio.adc[1].agc",value); + sprintf(value,"%d", adc[1].antenna); + setProperty("radio.adc[1].antenna",value); + + sprintf(value,"%d", dac[1].antenna); + setProperty("radio.dac[1].antenna",value); + + sprintf(value,"%f", dac[1].gain); + setProperty("radio.dac[1].gain",value); } } #endif @@ -2410,6 +2409,12 @@ g_print("radioSaveState: %s\n",property_path); } #endif +#ifdef MIDI + sprintf(value,"%d",midi_enabled); + setProperty("radio.midi_enabled",value); + midi_save_state(); +#endif + saveProperties(property_path); g_mutex_unlock(&property_mutex); } @@ -2479,7 +2484,7 @@ void radio_change_region(int r) { #ifdef CLIENT_SERVER int remote_start(void *data) { char *server=(char *)data; - sprintf(property_path,"%s@%s.props",radio->name,server); + sprintf(property_path,"%s@%s.props",name,server); radio_is_remote=TRUE; #ifdef GPIO switch(controller) { diff --git a/radio.h b/radio.h index 7e3d4c0..4fbd580 100644 --- a/radio.h +++ b/radio.h @@ -78,22 +78,33 @@ extern char property_path[]; extern int region; -// specify how many receivers: for PURESIGNAL need two extra -#define RECEIVERS 2 +extern int RECEIVERS; +extern int MAX_RECEIVERS; +extern int MAX_DDC; #ifdef PURESIGNAL -#define MAX_RECEIVERS (RECEIVERS+2) -#define PS_TX_FEEDBACK (RECEIVERS) -#define PS_RX_FEEDBACK (RECEIVERS+1) -#else -#define MAX_RECEIVERS RECEIVERS +extern int PS_TX_FEEDBACK; +extern int PS_RX_FEEDBACK; #endif -#define MAX_DDC (RECEIVERS+2) + +// specify how many receivers: for PURESIGNAL need two extra +//#define RECEIVERS 2 +//#ifdef PURESIGNAL +//#define MAX_RECEIVERS (RECEIVERS+2) +//#define PS_TX_FEEDBACK (RECEIVERS) +//#define PS_RX_FEEDBACK (RECEIVERS+1) +//#else +//#define MAX_RECEIVERS RECEIVERS +//#endif +//#define MAX_DDC (RECEIVERS+2) extern RECEIVER *receiver[]; extern RECEIVER *active_receiver; extern TRANSMITTER *transmitter; +#ifdef MIDI +extern gboolean midi_enabled; +#endif #define PA_DISABLED 0 #define PA_ENABLED 1 diff --git a/radio_menu.c b/radio_menu.c index 2602bcb..f77a6cc 100644 --- a/radio_menu.c +++ b/radio_menu.c @@ -84,19 +84,11 @@ static gboolean delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_d #ifdef SOAPYSDR static void rf_gain_value_changed_cb(GtkWidget *widget, gpointer data) { ADC *adc=(ADC *)data; - active_receiver->rf_gain=gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget)); + adc->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); + soapy_protocol_set_gain(receiver[0]); } - -/* - 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); - } -*/ - } static void rx_gain_value_changed_cb(GtkWidget *widget, gpointer data) { @@ -548,21 +540,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 @@ -816,7 +831,6 @@ void radio_menu(GtkWidget *parent) { col=0; if(radio->device==SOAPYSDR_USB_DEVICE) { int i; -/* if(radio->info.soapy.rx_gains>0) { GtkWidget *rx_gain=gtk_label_new(NULL); gtk_label_set_markup(GTK_LABEL(rx_gain), "RX Gains:"); @@ -835,50 +849,46 @@ void radio_menu(GtkWidget *parent) { row++; temp_row=row; -*/ col=0; -/* - //rx_gains=g_new(GtkWidget*,radio->info.soapy.rx_gains); - for(i=0;iinfo.soapy.rx_gains;i++) { + if(strcmp(radio->name,"sdrplay")==0) { + for(i=0;iinfo.soapy.rx_gains;i++) { + col=0; + GtkWidget *rx_gain_label=gtk_label_new(radio->info.soapy.rx_gain[i]); + gtk_grid_attach(GTK_GRID(grid),rx_gain_label,col,row,1,1); + col++; + SoapySDRRange range=radio->info.soapy.rx_range[i]; + if(range.step==0.0) { + range.step=1.0; + } + rx_gains[i]=gtk_spin_button_new_with_range(range.minimum,range.maximum,range.step); + gtk_widget_set_name (rx_gains[i], radio->info.soapy.rx_gain[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); + gtk_grid_attach(GTK_GRID(grid),rx_gains[i],col,row,1,1); + g_signal_connect(rx_gains[i],"value_changed",G_CALLBACK(rx_gain_value_changed_cb),&adc[0]); + + row++; + } + } else { + // used single gain control - LimeSDR works out best setting for the 3 rx gains col=0; - GtkWidget *rx_gain_label=gtk_label_new(radio->info.soapy.rx_gain[i]); - gtk_grid_attach(GTK_GRID(grid),rx_gain_label,col,row,1,1); + GtkWidget *rf_gain_label=gtk_label_new(NULL); + gtk_label_set_markup(GTK_LABEL(rf_gain_label), "RF Gain"); + gtk_grid_attach(GTK_GRID(grid),rf_gain_label,col,row,1,1); col++; - SoapySDRRange range=radio->info.soapy.rx_range[i]; - if(range.step==0.0) { - range.step=1.0; + double max=100; + if(strcmp(radio->name,"lime")==0) { + max=60.0; + } else if(strcmp(radio->name,"plutosdr")==0) { + max=73.0; } - rx_gains[i]=gtk_spin_button_new_with_range(range.minimum,range.maximum,range.step); - gtk_widget_set_name (rx_gains[i], radio->info.soapy.rx_gain[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); - //gtk_spin_button_set_value(GTK_SPIN_BUTTON(rx_gains[i]),(double)adc[0].rx_gain[i]); - gtk_grid_attach(GTK_GRID(grid),rx_gains[i],col,row,1,1); - g_signal_connect(rx_gains[i],"value_changed",G_CALLBACK(rx_gain_value_changed_cb),&adc[0]); - - gtk_widget_set_sensitive(rx_gains[i], FALSE); + GtkWidget *rf_gain_b=gtk_spin_button_new_with_range(0.0,max,1.0); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(rf_gain_b),active_receiver->rf_gain); + gtk_grid_attach(GTK_GRID(grid),rf_gain_b,col,row,1,1); + g_signal_connect(rf_gain_b,"value_changed",G_CALLBACK(rf_gain_value_changed_cb),&adc[0]); row++; } -*/ - // used single gain control - LimeSDR works out best setting for the 3 rx gains - col=0; - GtkWidget *rf_gain_label=gtk_label_new(NULL); - gtk_label_set_markup(GTK_LABEL(rf_gain_label), "RF Gain"); - gtk_grid_attach(GTK_GRID(grid),rf_gain_label,col,row,1,1); - col++; - double max=100; - if(strcmp(radio->name,"lime")==0) { - max=60.0; - } else if(strcmp(radio->name,"plutosdr")==0) { - max=73.0; - } - GtkWidget *rf_gain_b=gtk_spin_button_new_with_range(0.0,max,1.0); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(rf_gain_b),active_receiver->rf_gain); - gtk_grid_attach(GTK_GRID(grid),rf_gain_b,col,row,1,1); - g_signal_connect(rf_gain_b,"value_changed",G_CALLBACK(rf_gain_value_changed_cb),&adc[0]); - - row++; if(radio->info.soapy.rx_has_automatic_gain) { GtkWidget *agc=gtk_check_button_new_with_label("Hardware AGC: "); diff --git a/receiver.c b/receiver.c index 7d93db8..eb9ba05 100644 --- a/receiver.c +++ b/receiver.c @@ -1183,6 +1183,7 @@ void receiver_change_sample_rate(RECEIVER *rx,int sample_rate) { g_print("receiver_change_sample_rate: id=%d rate=%d scale=%d buffer_size=%d output_samples=%d\n",rx->id,sample_rate,scale,rx->buffer_size,rx->output_samples); #ifdef PURESIGNAL + if(can_transmit && transmitter->puresignal) { if (rx->id == PS_RX_FEEDBACK) { if (protocol == ORIGINAL_PROTOCOL) { rx->pixels = 2* scale * rx->width; @@ -1199,6 +1200,7 @@ g_print("receiver_change_sample_rate: id=%d rate=%d scale=%d buffer_size=%d outp g_mutex_unlock(&rx->mutex); return; } + } #endif if (rx->audio_output_buffer != NULL) { g_free(rx->audio_output_buffer); diff --git a/receiver.h b/receiver.h index 1132c0f..236d31d 100644 --- a/receiver.h +++ b/receiver.h @@ -25,7 +25,6 @@ #else #include #include -//#include #endif enum _audio_t { diff --git a/sliders.c b/sliders.c index a13eb3b..d4f2461 100644 --- a/sliders.c +++ b/sliders.c @@ -391,7 +391,7 @@ static void rf_gain_value_changed_cb(GtkWidget *widget, gpointer data) { active_receiver->rf_gain=gtk_range_get_value(GTK_RANGE(af_gain_scale)); #ifdef SOAPYSDR if(protocol==SOAPYSDR_PROTOCOL) { - soapy_protocol_set_gain(active_receiver,active_receiver->rf_gain); + soapy_protocol_set_gain(active_receiver); } #endif } @@ -404,7 +404,7 @@ void set_rf_gain(int rx,double value) { receiver[rx]->rf_gain=value; #ifdef SOAPYSDR if(protocol==SOAPYSDR_PROTOCOL) { - soapy_protocol_set_gain(active_receiver,active_receiver->rf_gain); + soapy_protocol_set_gain(active_receiver); } #endif if(display_sliders) { diff --git a/soapy_discovery.c b/soapy_discovery.c index e1eaa4f..a8a026e 100644 --- a/soapy_discovery.c +++ b/soapy_discovery.c @@ -27,17 +27,23 @@ #include "soapy_discovery.h" static int rtlsdr_count=0; +static int sdrplay_count=0; static void get_info(char *driver) { size_t rx_rates_length, tx_rates_length, rx_gains_length, tx_gains_length, ranges_length, rx_antennas_length, tx_antennas_length, rx_bandwidth_length, tx_bandwidth_length; int i; SoapySDRKwargs args={}; int software_version=0; + char *version; + char *address=NULL; int rtlsdr_val=0; + int sdrplay_val=0; char fw_version[16]; char gw_version[16]; char hw_version[16]; char p_version[16]; + char** tx_antennas; + char** tx_gains; fprintf(stderr,"soapy_discovery: get_info: %s\n", driver); @@ -53,6 +59,12 @@ static void get_info(char *driver) { SoapySDRKwargs_set(&args, "rtl", count); rtlsdr_val=rtlsdr_count; rtlsdr_count++; + } else if(strcmp(driver,"sdrplay")==0) { + char label[16]; + sprintf(label,"SDRplay Dev%d",sdrplay_count); + SoapySDRKwargs_set(&args, "label", label); + sdrplay_val=sdrplay_count; + sdrplay_count++; } SoapySDRDevice *sdr = SoapySDRDevice_make(&args); SoapySDRKwargs_clear(&args); @@ -63,6 +75,9 @@ static void get_info(char *driver) { char *hardwarekey=SoapySDRDevice_getHardwareKey(sdr); fprintf(stderr,"HardwareKey=%s\n",hardwarekey); + if(strcmp(driver,"sdrplay")==0) { + address=hardwarekey; + } SoapySDRKwargs info=SoapySDRDevice_getHardwareInfo(sdr); for(i=0;i %f (%f),", tx_rates[i].minimum, tx_rates[i].maximum, tx_rates[i].minimum/48000.0); + if(tx_channels>0) { + SoapySDRRange *tx_rates=SoapySDRDevice_getSampleRateRange(sdr, SOAPY_SDR_TX, 1, &tx_rates_length); + fprintf(stderr,"Tx sample rates: "); + for (size_t i = 0; i < tx_rates_length; i++) { + fprintf(stderr,"%f -> %f (%f),", tx_rates[i].minimum, tx_rates[i].maximum, tx_rates[i].minimum/48000.0); + } + fprintf(stderr,"\n"); + free(tx_rates); } - fprintf(stderr,"\n"); - free(tx_rates); double *bandwidths=SoapySDRDevice_listBandwidths(sdr, SOAPY_SDR_RX, 0, &rx_bandwidth_length); fprintf(stderr,"Rx bandwidths: "); @@ -146,19 +174,23 @@ static void get_info(char *driver) { fprintf(stderr,"\n"); free(bandwidths); - bandwidths=SoapySDRDevice_listBandwidths(sdr, SOAPY_SDR_TX, 0, &tx_bandwidth_length); - fprintf(stderr,"Tx bandwidths: "); - for (size_t i = 0; i < tx_bandwidth_length; i++) { - fprintf(stderr,"%f, ", bandwidths[i]); + if(tx_channels>0) { + bandwidths=SoapySDRDevice_listBandwidths(sdr, SOAPY_SDR_TX, 0, &tx_bandwidth_length); + fprintf(stderr,"Tx bandwidths: "); + for (size_t i = 0; i < tx_bandwidth_length; i++) { + fprintf(stderr,"%f, ", bandwidths[i]); + } + fprintf(stderr,"\n"); + free(bandwidths); } - fprintf(stderr,"\n"); - free(bandwidths); double bandwidth=SoapySDRDevice_getBandwidth(sdr, SOAPY_SDR_RX, 0); fprintf(stderr,"RX0: bandwidth=%f\n",bandwidth); - bandwidth=SoapySDRDevice_getBandwidth(sdr, SOAPY_SDR_TX, 0); - fprintf(stderr,"TX0: bandwidth=%f\n",bandwidth); + if(tx_channels>0) { + bandwidth=SoapySDRDevice_getBandwidth(sdr, SOAPY_SDR_TX, 0); + fprintf(stderr,"TX0: bandwidth=%f\n",bandwidth); + } SoapySDRRange *ranges = SoapySDRDevice_getFrequencyRange(sdr, SOAPY_SDR_RX, 0, &ranges_length); fprintf(stderr,"Rx freq ranges: "); @@ -170,10 +202,13 @@ static void get_info(char *driver) { for (size_t i = 0; i < rx_antennas_length; i++) fprintf(stderr, "%s, ", rx_antennas[i]); fprintf(stderr,"\n"); - char** tx_antennas = SoapySDRDevice_listAntennas(sdr, SOAPY_SDR_TX, 0, &tx_antennas_length); - fprintf(stderr, "Tx antennas: "); - for (size_t i = 0; i < tx_antennas_length; i++) fprintf(stderr, "%s, ", tx_antennas[i]); - fprintf(stderr,"\n"); + + if(tx_channels>0) { + tx_antennas = SoapySDRDevice_listAntennas(sdr, SOAPY_SDR_TX, 0, &tx_antennas_length); + fprintf(stderr, "Tx antennas: "); + for (size_t i = 0; i < tx_antennas_length; i++) fprintf(stderr, "%s, ", tx_antennas[i]); + fprintf(stderr,"\n"); + } char **rx_gains = SoapySDRDevice_listGains(sdr, SOAPY_SDR_RX, 0, &rx_gains_length); @@ -183,7 +218,9 @@ static void get_info(char *driver) { gboolean has_automatic_dc_offset_correction=SoapySDRDevice_hasDCOffsetMode(sdr, SOAPY_SDR_RX, 0); fprintf(stderr,"has_automaic_dc_offset_correction=%d\n",has_automatic_dc_offset_correction); - char **tx_gains = SoapySDRDevice_listGains(sdr, SOAPY_SDR_TX, 1, &tx_gains_length); + if(tx_channels>0) { + tx_gains = SoapySDRDevice_listGains(sdr, SOAPY_SDR_TX, 1, &tx_gains_length); + } size_t formats_length; char **formats = SoapySDRDevice_getStreamFormats(sdr,SOAPY_SDR_RX,0,&formats_length); @@ -191,7 +228,18 @@ static void get_info(char *driver) { for (size_t i = 0; i < formats_length; i++) fprintf(stderr, "%s, ", formats[i]); fprintf(stderr,"\n"); - fprintf(stderr,"float=%lu double=%lu\n",sizeof(float),sizeof(double)); + size_t sensors; + char **sensor = SoapySDRDevice_listSensors(sdr, &sensors); + gboolean has_temp=FALSE; + char *ptr; + fprintf(stderr, "Sensors:\n"); + for (size_t i = 0; i < sensors; i++) { + char *value=SoapySDRDevice_readSensor(sdr, sensor[i]); + fprintf(stderr, " %s=%s\n", sensor[i],value); + if((ptr=strstr(sensor[i],"temp"))!=NULL) { + has_temp=TRUE; + } + } if(devices %f step=%f\n",tx_range.minimum,tx_range.maximum,tx_range.step); - discovered[devices].info.soapy.tx_range[i]=tx_range; + if(tx_channels>0) { + discovered[devices].info.soapy.tx_gains=tx_gains_length; + discovered[devices].info.soapy.tx_gain=tx_gains; + discovered[devices].info.soapy.tx_range=malloc(tx_gains_length*sizeof(SoapySDRRange)); + fprintf(stderr,"Tx gains: \n"); + for (size_t i = 0; i < tx_gains_length; i++) { + fprintf(stderr,"%s ", tx_gains[i]); + SoapySDRRange tx_range=SoapySDRDevice_getGainElementRange(sdr, SOAPY_SDR_TX, 1, tx_gains[i]); + fprintf(stderr,"%f -> %f step=%f\n",tx_range.minimum,tx_range.maximum,tx_range.step); + discovered[devices].info.soapy.tx_range[i]=tx_range; + } + discovered[devices].info.soapy.tx_antennas=tx_antennas_length; + discovered[devices].info.soapy.tx_antenna=tx_antennas; } - discovered[devices].info.soapy.tx_antennas=tx_antennas_length; - discovered[devices].info.soapy.tx_antenna=tx_antennas; + discovered[devices].info.soapy.sensors=sensors; + discovered[devices].info.soapy.sensor=sensor; + discovered[devices].info.soapy.has_temp=has_temp; + + + if(address!=NULL) { + strcpy(discovered[devices].info.soapy.address,address); + } else { + strcpy(discovered[devices].info.soapy.address,"USB"); + } + devices++; } + SoapySDRDevice_unmake(sdr); free(ranges); - } void soapy_discovery() { diff --git a/soapy_protocol.c b/soapy_protocol.c index c10550a..ba308dc 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,34 +128,43 @@ 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) { @@ -156,6 +172,7 @@ fprintf(stderr,"soapy_protocol_create_receiver: SoapySDRDevice_setupStream(versi } else { max_samples=1024; } + */ rx->buffer=g_new(double,max_samples*2); if(rx->sample_rate==radio_sample_rate) { @@ -169,54 +186,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 +246,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 +274,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 +335,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,9 +397,9 @@ 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 +496,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)); } 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 4148779..c72100b 100644 --- a/switch_menu.c +++ b/switch_menu.c @@ -191,7 +191,7 @@ next_function_set: gtk_grid_attach(GTK_GRID(grid),widget,col,row,1,1); col++; - if((controller==NO_CONTROLLER || controller==CONTROLLER1) && (i==0 || i==(max_switches-1))) { + if((controller==NO_CONTROLLER || controller==CONTROLLER1) && (temp_switches[i].switch_function==FUNCTION)) { widget=gtk_label_new(NULL); g_sprintf(label,"%s",sw_string[temp_switches[i].switch_function]); gtk_label_set_markup (GTK_LABEL(widget), label); diff --git a/tx_menu.c b/tx_menu.c index a6edc0a..570e417 100644 --- a/tx_menu.c +++ b/tx_menu.c @@ -233,9 +233,11 @@ static gboolean emp_cb (GtkWidget *widget, gpointer data) { return FALSE; } +/* static void tune_value_changed_cb(GtkWidget *widget, gpointer data) { setTuneDrive(gtk_range_get_value(GTK_RANGE(tune_scale))); } +*/ void tx_menu(GtkWidget *parent) { int i; diff --git a/vfo.c b/vfo.c index b056147..6da5c02 100644 --- a/vfo.c +++ b/vfo.c @@ -953,14 +953,23 @@ 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; + } int oob=0; if (can_transmit) oob=transmitter->out_of_band; + sprintf(temp_text,"VFO A: %0lld.%06lld",af/(long long)1000000,af%(long long)1000000); if(txvfo == 0 && (isTransmitting() || oob)) { 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); @@ -975,7 +984,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 55e0562..f46d32f 100644 --- a/vfo.h +++ b/vfo.h @@ -44,6 +44,9 @@ struct _vfo { long long lo; long long offset; + gboolean entering_frequency; + gint64 entered_frequency; + }; extern struct _vfo vfo[MAX_VFOS];