Includes two fixes for STEMlab/HAMlab.
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleIdentifier</key>
+ <string>piHPSDR</string>
+ <key>CFBundleExecutable</key>
+ <string>pihpsdr</string>
+ <key>CFBundleIconFile</key>
+ <string>hpsdr.icns</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleSignature</key>
+ <string>BNDL</string>
+</dict>
+</plist>
--- /dev/null
+#!/bin/sh
+
+#
+# Launch the exe file from a shell.
+# This is the only way to make a GTK app bundle
+# It still relies on a working GTK installation
+#
+# A full-fledged wrapper here would set dozens of
+# environment variables.
+#
+this=`dirname $0`
+cd $this/../Resources
+
+exec $this/pihpsdr-bin
GIT_DATE := $(firstword $(shell git --no-pager show --date=short --format="%ai" --name-only))
GIT_VERSION := $(shell git describe --abbrev=0 --tags)
+#DL1YCF: this uses PortAudio rather than ALSA
+PORTAUDIO_INCLUDE=PORTAUDIO
+
+#DL1YCF: un-commment this line for activate work-around some RedPitaty HPSDR bugs
+STEMLAB_FIX_OPTION=-DSTEMLAB_FIX
+
+#DL1YCF: un-commment if you need librt (probably always, except on MacOS)
+#LIBRT= -lrt
+
# uncomment the line below to include GPIO
#GPIO_INCLUDE=GPIO
# uncomment the line to below include support local CW keyer
#LOCALCW_INCLUDE=LOCALCW
-# uncomment the line below to include support for STEMlab discovery
+# uncomment the line below to include support for STEMlab discovery (does not work on MacOS)
#STEMLAB_DISCOVERY=STEMLAB_DISCOVERY
+# uncomment the line below to include support for stripped-down STEMlab discovery that works on MacOS
+STEMLAB_DISCOVERY=STEMLAB_DISCOVERY_MAC
+
#uncomment the line below for the platform being compiled on
-UNAME_N=raspberrypi
+UNAME_N=MacOS
+#UNAME_N=raspberrypi
#UNAME_N=odroid
#UNAME_N=up
#UNAME_N=pine64
#UNAME_N=jetsen
CC=gcc
+
+ifeq ($(UNAME_N),MacOS)
+#
+# This is only necessary for "make app", since the "patched"
+# library names are longer
+#
+LINK=gcc -headerpad_max_install_names
+else
LINK=gcc
+endif
# uncomment the line below for various debug facilities
#DEBUG_OPTION=-D DEBUG
I2C_OBJS=i2c.o
endif
+#
+# STEMLAB_DISCOVERY_MAC depends on curl but not on avahi
+#
+ifeq ($(STEMLAB_DISCOVERY), STEMLAB_DISCOVERY_MAC)
+STEMLAB_OPTIONS=-D STEMLAB_DISCOVERY `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 ($(STEMLAB_DISCOVERY), STEMLAB_DISCOVERY)
STEMLAB_OPTIONS=-D STEMLAB_DISCOVERY \
`pkg-config --cflags avahi-gobject` \
GTKINCLUDES=`pkg-config --cflags gtk+-3.0`
GTKLIBS=`pkg-config --libs gtk+-3.0`
+ifeq ($(PORTAUDIO_INCLUDE), PORTAUDIO)
+PORTAUDIO_OPTIONS=-DPORTAUDIO
+AUDIO_LIBS=-lportaudio
+else
AUDIO_LIBS=-lasound
#AUDIO_LIBS=-lsoundio
+endif
+
+OPTIONS=-g -Wno-deprecated-declarations $(PURESIGNAL_OPTIONS) $(REMOTE_OPTIONS) $(RADIOBERRY_OPTIONS) \
+ $(USBOZY_OPTIONS) $(I2C_OPTIONS) $(GPIO_OPTIONS) $(LIMESDR_OPTIONS) $(FREEDV_OPTIONS) \
+ $(LOCALCW_OPTIONS) $(PSK_OPTIONS) $(STEMLAB_OPTIONS) $(STEMLAB_FIX_OPTION) \
+ $(PORTAUDIO_OPTIONS) \
+ -D GIT_DATE='"$(GIT_DATE)"' -D GIT_VERSION='"$(GIT_VERSION)"' $(DEBUG_OPTION) -O3
-OPTIONS=-g -Wno-deprecated-declarations $(PURESIGNAL_OPTIONS) $(REMOTE_OPTIONS) $(USBOZY_OPTIONS) $(I2C_OPTIONS) $(GPIO_OPTIONS) $(LIMESDR_OPTIONS) $(FREEDV_OPTIONS) $(LOCALCW_OPTIONS) $(RADIOBERRY_OPTIONS) $(PSK_OPTIONS) $(STEMLAB_OPTIONS) -D GIT_DATE='"$(GIT_DATE)"' -D GIT_VERSION='"$(GIT_VERSION)"' $(DEBUG_OPTION) -O3
+LIBS= $(LIBRT) -lm -lwdsp -lpthread $(AUDIO_LIBS) $(USBOZY_LIBS) $(PSKLIBS) $(GTKLIBS) $(GPIO_LIBS) \
+ $(SOAPYSDRLIBS) $(FREEDVLIBS) $(STEMLAB_LIBS)
-LIBS=-lrt -lm -lwdsp -lpthread $(AUDIO_LIBS) $(USBOZY_LIBS) $(PSKLIBS) $(GTKLIBS) $(GPIO_LIBS) $(SOAPYSDRLIBS) $(FREEDVLIBS) $(STEMLAB_LIBS)
INCLUDES=$(GTKINCLUDES)
COMPILE=$(CC) $(OPTIONS) $(INCLUDES)
pa_menu.c \
cw_menu.c \
oc_menu.c \
+portaudio.c \
xvtr_menu.c \
equalizer_menu.c \
step_menu.c \
memory.o \
led.o \
ext.o \
-error_handler.o
+error_handler.o \
+portaudio.o
$(PROGRAM): $(OBJS) $(REMOTE_OBJS) $(USBOZY_OBJS) $(LIMESDR_OBJS) $(FREEDV_OBJS) $(LOCALCW_OBJS) $(I2C_OBJS) $(GPIO_OBJS) $(PSK_OBJS) $(PURESIGNAL_OBJS) $(STEMLAB_OBJS)
- $(LINK) -o $(PROGRAM) $(OBJS) $(REMOTE_OBJS) $(USBOZY_OBJS) $(I2C_OBJS) $(GPIO_OBJS) $(LIMESDR_OBJS) $(FREEDV_OBJS) $(LOCALCW_OBJS) $(PSK_OBJS) $(LIBS) $(PURESIGNAL_OBJS) $(STEMLAB_OBJS)
+ $(LINK) -o $(PROGRAM) $(OBJS) $(REMOTE_OBJS) $(USBOZY_OBJS) $(I2C_OBJS) $(GPIO_OBJS) $(LIMESDR_OBJS) $(FREEDV_OBJS) $(LOCALCW_OBJS) $(PSK_OBJS) $(PURESIGNAL_OBJS) $(STEMLAB_OBJS) $(LIBS)
all: prebuild $(PROGRAM) $(HEADERS) $(REMOTE_HEADERS) $(USBOZY_HEADERS) $(LIMESDR_HEADERS) $(FREEDV_HEADERS) $(LOCALCW_HEADERS) $(I2C_HEADERS) $(GPIO_HEADERS) $(PSK_HEADERS) $(PURESIGNAL_HEADERS) $(STEMLAB_HEADERS) $(SOURCES) $(REMOTE_SOURCES) $(USBOZY_SOURCES) $(LIMESDR_SOURCES) $(FREEDV_SOURCES) $(I2C_SOURCES) $(GPIO_SOURCES) $(PSK_SOURCES) $(PURESIGNAL_SOURCES) $(STEMLAB_SOURCES)
clean:
-rm -f *.o
-rm -f $(PROGRAM)
+ -rm -rf $(PROGRAM).app
install: $(PROGRAM)
cp $(PROGRAM) /usr/local/bin
cd release; tar cvf pihpsdr.tar pihpsdr
cd release; tar cvf pihpsdr-$(GIT_VERSION).tar pihpsdr
+#############################################################################
+#
+# 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.
+#
+# ATTENTION
+# =========
+# Upon starting a freshly built application in an "app" bundle,
+# it will do the FFT calculations required for wdspWisdom, since
+# this is then stored *within* the app bundle.
+#
+#############################################################################
+app: pihpsdr
+ @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 `; 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
+#############################################################################
+
--- /dev/null
+===============================================================
+= =
+= piHPSDR on the Macintosh. =
+= =
+= Port done by DL1YCF Christoph van Wullen. =
+= =
+===============================================================
+
+
+
+============================
+NOTES ON CHANGES IN THE CODE
+============================
+
+To make piHPSDR work on MacOS, I had to do two major things:
+
+a) Semaphores: MacOS does not have sem_t variables, only
+ sem_t pointers that must not be dereferences. Therefore
+ it has no working sem_init.
+ On MacOS one must use sem_open instead and use sem_t
+ pointers instead of sem_t variable throughout. This is
+ not recommended for LINUX, since named semaphores stay
+ alive even when the program terminates (on MacOS, all
+ semaphores are automatically destroyed). Therefore
+ *every* declaration of sem_t variable and *every*
+ call to semaphore functions had to be modified. Everything
+ is coded as
+
+#ifdef __APPLE__
+ use sem_t pointers
+#else
+ usem_t variables
+#endif
+
+ NOTE this change also applies to WDSP.
+
+b) Audio: MacOS does not have ALSA, therefore an additional
+ file portaudio.c is provided that is a functional duplicate
+ of audio.c. The whole file audio.c is not "protected with
+
+#ifndef PORTAUDIO
+everything in audio.c
+#endif
+
+ and the new file portaudio.c consequently reads
+
+#ifdef PORTAUDIO
+everything in portaudio.c
+#endif
+
+ such that one can link and compile both files. As an additional benefit,
+ the PortAudio module also offeres a two-tone generator as TX "mic" input.
+
+c) Only relevant for STEMLAB/HAMLAB: the "special" code that starts the
+ HPSDR application on the RedPitaya board via a browser interface relies
+ on AVAHI to detect the RedPitaya board. This does not work on MacOS
+ since we do not have AVAHI. However, libcurl is available on MacOS.
+ Therefore I provide a stripped-down version in the file stemlab_discovery.c
+ which assumes that the RedPitaya board is accessible by a fixed
+ IP address. This address is read from $HOME/.rp.inet and set to 192.168.1.3
+ if this file could not be read.
+ If your STEMlab/HAMlab is then there, the list of applications is obtained
+ and the HPSDR application with highest priority is started, the priority
+ defined through the following list (first line = highest priority)
+
+ hamlab_sdr_transceiver_hpsdr
+ stemlab_sdr_transceiver_hpsdr
+ sdr_transceiver_hpsdr
+ sdr_receiver_hpsdr
+
+=============
+PREREQUISITES
+=============
+
+Since Audio and GUI are OpenSource and not Apple-specific, one needs some
+third-party libraries to link the program. Most recommended is to use
+"homebrew". You will need portaudio and gtk+3 for piHPSDR, and
+fftw3 for wdsp (which you have to compile separately). Note that packages
+such as gtk+3 depend on other packages, but these are automatically installed
+by homebrew. The Makefile itself relies on pkg-config to determine the
+compile and link flags for certain external software.
+
+Of course, you need the Xcode command line tools (make, gcc, and friends).
+
+Before you compile piHPSDR, you need to compile wdsp. Using the Mac-Makefile
+there, "make install" will put libwdsp.dylib in /usr/local/lib. This is needed
+by piHPSDR.
+
+===================
+COMPILE and INSTALL
+===================
+
+
+That's easy. Just adjust the Makefile according to the instructions found there
+and type "make". In my case (I have a HAMLAB RedPitaya-based SDR box), I need
+the following options in the Makefile (and have all others commented out):
+
+PORTAUDIO_INCLUDE=PORTAUDIO
+STEMLAB_FIX_OPTION=-DSTEMLAB_FIX
+STEMLAB_DISCOVERY=STEMLAB_DISCOVERY_MAC
+UNAME_N=MacOS
+
+The first one activates the PortAudio code and disables the Linux ALSA
+code, the second option activates some work-arounds around some RedPitaya
+HPSDR application bugs (this is also required if you are NOT using MacOS),
+and the third option activates code to start the HPSDR program on a RedPitaya
+before the actual discovery stuff takes place.
+
+Note: never un-comment the lines containing LIBRT, GPI_INCLUDE, I2C_INCLUDE,
+SX1509_INCLUDE, or LOCALCW_INCLUDE. This software/hardware is not present on a Mac.
+
+As a result of "make", you get an executable file "pihpsdr" which you
+can start from the terminal. With "make app" you can make a click-able
+MacOS application bundle. However note that this bundle is not self-contained:
+it needs a working gtk+3 environment. To put all this into an app bundle
+would create an app file hundreds of MByte long: you need all those pixbuf
+loaders etc. etc. etc. installed.
+
+What we do is to include portaudio, WDSP, fftw3 and some other libs into the bundle.
+
+
+===========================
+piHPSDR and wsjtx or fldigi
+===========================
+
+a) CAT control: use hamlib, and choose "OpenHPSDR piHPSDR" radio model and
+ e.g. port number 19090. Then, activate rigctl in the piHPSDR menu, choosing
+ the same port number there.
+
+b) Audio: here you need the "SoundFlower" free-software program for MacOS, that
+ provides virtual audio cables. I have stripped down this somewhat, it now provides
+ two stero devices (named VAC A and VAC B) and has less overhead, since audio data
+ is no longer processed (no volume control) but simply moved: after all, this is what
+ a "cable" is supposed to do.
+
+ For example, you can Choose "VAC A" as the RX output device and "VAC B" as the
+ TX input (mic) device in piHPSDR, and choose "VAC B" as the output device and "VAC A"
+ as the input device in fldigi or wsjt-x.
+ The modified version of SoundFlower is available on my github account, github.com/dl1ycf,
+ with the name MacOSVirtualAudioCable.
+
//wdsp_set_agc(CHANNEL_RX0, agc);
set_agc(active_receiver, active_receiver->agc);
vfo_update();
+ // DL1YCF added return statement to make the compiler happy.
+ // however I am unsure about the correct return value.
+ // I would have coded this as a void function.
+ return FALSE;
}
void agc_menu(GtkWidget *parent) {
*
*/
+//
+// DL1YCF: If PortAudio is used instead of ALSO (e.g. on MacOS),
+// this file is not used (and replaced by portaudio.c).
+
+#ifndef PORTAUDIO
#include <gtk/gtk.h>
n++;
}
snd_device_name_free_hint(hints);
-}
\ No newline at end of file
+}
+#endif
int height=gtk_widget_get_allocated_height (widget);
fprintf(stderr,"audio: waterfall_configure_event: width=%d height=%d\n",width,height);
pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, width, height);
- char *pixels = gdk_pixbuf_get_pixels (pixbuf);
+ // DL1YCF changed to uchar *
+ unsigned char *pixels = gdk_pixbuf_get_pixels (pixbuf);
memset(pixels, 0, width*height*3);
int i;
if(pixbuf) {
- char *pixels = gdk_pixbuf_get_pixels (pixbuf);
+ // DL1YCF changed to uchar *
+ unsigned char *pixels = gdk_pixbuf_get_pixels (pixbuf);
int width=gdk_pixbuf_get_width(pixbuf);
int height=gdk_pixbuf_get_height(pixbuf);
memmove(&pixels[rowstride*(header+1)],&pixels[rowstride*header],(height-(header+1))*rowstride);
float sample;
- char *p;
+ // DL1YCF changed to uchar *
+ unsigned char *p;
int average=0;
p=&pixels[rowstride*header];
for(i=0;i<width;i++) {
last_band=widget;
set_button_text_color(last_band,"orange");
vfo_band_changed(b);
+ // DL1YCF added return statement to make the compiler happy.
+ // however I am unsure about the correct return value.
+ // I would have coded this as a void function.
+ return FALSE;
}
void band_menu(GtkWidget *parent) {
last_bandstack=widget;
set_button_text_color(last_bandstack,"orange");
vfo_bandstack_changed(b);
+ // DL1YCF added return statement to make the compiler happy.
+ // however I am unsure about the correct return value.
+ // I would have coded this as a void function.
+ return FALSE;
}
void bandstack_menu(GtkWidget *parent) {
}
static void nr2_gain_cb(GtkWidget *widget, gpointer data) {
- active_receiver->nr2_gain_method==(uintptr_t)data;
+// DL1YCF changed == to =
+ active_receiver->nr2_gain_method=(uintptr_t)data;
SetRXAEMNRgainMethod(active_receiver->id, active_receiver->nr2_gain_method);
}
gtk_range_set_value(GTK_RANGE(mid_scale),(double)tx_equalizer[2]);
gtk_range_set_value(GTK_RANGE(high_scale),(double)tx_equalizer[3]);
}
+ // DL1YCF added return statement to make the compiler happy.
+ // however I am unsure about the correct return value.
+ // I would have coded this as a void function.
+ return FALSE;
}
static gboolean rx_rb_cb (GtkWidget *widget, GdkEventButton *event, gpointer data) {
gtk_range_set_value(GTK_RANGE(mid_scale),(double)rx_equalizer[2]);
gtk_range_set_value(GTK_RANGE(high_scale),(double)rx_equalizer[3]);
}
+ // DL1YCF added return statement to make the compiler happy.
+ // however I am unsure about the correct return value.
+ // I would have coded this as a void function.
+ return FALSE;
}
static gboolean enable_cb (GtkWidget *widget, GdkEventButton *event, gpointer data) {
enable_rx_equalizer=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
SetRXAEQRun(active_receiver->id, enable_rx_equalizer);
}
+ // DL1YCF added return statement to make the compiler happy.
+ // however I am unsure about the correct return value.
+ // I would have coded this as a void function.
+ return FALSE;
}
static void value_changed_cb (GtkWidget *widget, gpointer data) {
gtk_widget_show(label);
timer=g_timeout_add(5000,timeout_cb,NULL);
int result=gtk_dialog_run(GTK_DIALOG(dialog));
+ // DL1YCF added return statement to make the compiler happy.
+ // however I am unsure about the correct return value.
+ // I would have coded this as a void function.
+ return FALSE;
}
void error_handler(char *text,char *err) {
int ext_set_frequency(void *data) {
setFrequency(*(long long *)data);
free(data);
+ // DL1YCF added return statement
+ // this one is CRITICAL to avoid free() being called
+ // repeatedly on the same pointer
+ return 0;
}
int ext_vfo_update(void *data) {
int ext_mode_update(void *data) {
start_mode();
+ // DL1YCF added return statement
+ return 0;
}
int ext_filter_update(void *data) {
start_filter();
+ // DL1YCF added return statement
+ return 0;
}
int ext_noise_update(void *data) {
start_noise();
+ // DL1YCF added return statement
+ return 0;
}
int ext_ptt_update(void *data) {
set_button_text_color(last_filter,"black");
last_filter=widget;
set_button_text_color(last_filter,"orange");
+ // DL1YCF added return statement to make the compiler happy.
+ // however I am unsure about the correct return value.
+ // I would have coded this as a void function.
+ return FALSE;
}
static gboolean deviation_select_cb (GtkWidget *widget, gpointer data) {
last_filter=widget;
set_button_text_color(last_filter,"orange");
vfo_update();
+ // DL1YCF added return statement to make the compiler happy.
+ // however I am unsure about the correct return value.
+ // I would have coded this as a void function.
+ return FALSE;
}
static void var_spin_low_cb (GtkWidget *widget, gpointer data) {
}
}
vfo_update();
+ // DL1YCF added return statement
+ return FALSE;
}
static GtkWidget *last_mode;
int *kdot;
int *kdash;
static int running = 0;
+#ifdef __APPLE__
+static sem_t *cw_event;
+#else
static sem_t cw_event;
+#endif
int keyer_out = 0;
kcwr = state;
if (state || cw_keyer_mode == KEYER_STRAIGHT) {
+#ifdef __APPLE__
+ sem_post(cw_event);
+#else
sem_post(&cw_event);
+#endif
}
}
#endif
fprintf(stderr,"keyer_thread state running= %d\n", running);
while(running) {
+#ifdef __APPLE__
+ sem_wait(cw_event);
+#else
sem_wait(&cw_event);
+#endif
key_state = CHECK;
softToneCreate(SIDETONE_GPIO);
}
+#ifdef __APPLE__
+ cw_event=sem_open("CW", O_CREAT, 0700, 0);
+ rc = (cw_event == SEM_FAILED);
+#else
rc = sem_init(&cw_event, 0, 0);
+#endif
rc |= pthread_create(&keyer_thread_id, NULL, keyer_thread, NULL);
running = 1;
if(rc < 0) {
*
*/
+// DL1YCF
+// Define maximum window size.
+// Original values 800 and 480, but if the screen is large, why not using it?
+
+#define MAX_DISPLAY_WIDTH 1020
+#define MAX_DISPLAY_HEIGHT 700
+
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <math.h>
static GtkWidget *discovery_dialog;
+#ifdef __APPLE__
+static sem_t *wisdom_sem;
+#else
static sem_t wisdom_sem;
+#endif
static GdkCursor *cursor_arrow;
static GdkCursor *cursor_watch;
fprintf(stderr,"Creating wisdom file: %s\n", (char *)arg);
status_text("Creating FFTW Wisdom file ...");
WDSPwisdom ((char *)arg);
+#ifdef __APPLE__
+ sem_post(wisdom_sem);
+#else
sem_post(&wisdom_sem);
+#endif
+ return NULL;
}
gboolean main_delete (GtkWidget *widget) {
strcpy(&wisdom_file[strlen(wisdom_file)],"wdspWisdom");
status_text("Checking FFTW Wisdom file ...");
if(access(wisdom_file,F_OK)<0) {
+#ifdef __APPLE__
+ int rc;
+ wisdom_sem=sem_open("WISDOM", O_CREAT, 0700, 0);
+#else
int rc=sem_init(&wisdom_sem, 0, 0);
+#endif
rc=pthread_create(&wisdom_thread_id, NULL, wisdom_thread, (void *)wisdom_directory);
+#ifdef __APPLE__
+ while(sem_trywait(wisdom_sem)<0) {
+#else
while(sem_trywait(&wisdom_sem)<0) {
+#endif
status_text(wisdom_get_status());
while (gtk_events_pending ())
gtk_main_iteration ();
display_height=gdk_screen_get_height(screen);
fprintf(stderr,"width=%d height=%d\n", display_width, display_height);
- if(display_width>800 || display_height>480) {
-/*
- if(display_width>1600) {
- display_width=1600;
- } else {
- display_width=800;
- }
- if(display_height>960) {
- display_height=960;
- } else {
- display_height=480;
- }
-*/
- display_width=800;
- display_height=480;
+
+ // DL1YCF: use define'd constants here
+ if(display_width>MAX_DISPLAY_WIDTH || display_height>MAX_DISPLAY_HEIGHT) {
+ display_width=MAX_DISPLAY_WIDTH;
+ display_height=MAX_DISPLAY_HEIGHT;
full_screen=0;
}
last_mode=widget;
set_button_text_color(last_mode,"orange");
vfo_mode_changed(m);
+ // DL1YCF added return statement to make the compiler happy.
+ // however I am unsure about the correct return value.
+ // I would have coded this as a void function.
+ return FALSE;
}
void mode_menu(GtkWidget *parent) {
//void* new_discover_receive_thread(void* arg) {
gpointer new_discover_receive_thread(gpointer data) {
struct sockaddr_in addr;
- int len;
+ // DL1YCF change from int to socklen_t
+ socklen_t len;
unsigned char buffer[2048];
int bytes_read;
struct timeval tv;
}
fprintf(stderr,"new_discover: exiting new_discover_receive_thread\n");
g_thread_exit(NULL);
+ // DL1YCF added return statement to make compiler happy.
+ return NULL;
}
static int running;
+#ifdef __APPLE__
+//
+//DL1YCF:
+//Mac OS does not have sem_init for un-named semaphores,
+//we have to use named semaphores created with sem_open.
+//As a side effect, we consistently have to use sem_t
+//pointers instead of sem_t variables
+//
+sem_t *response_sem;
+#else
sem_t response_sem;
+#endif
static struct sockaddr_in base_addr;
static int base_addr_length;
//static sem_t send_general_sem;
//static int send_general=0;
+#ifdef __APPLE__
+static sem_t *command_response_sem_ready;
+static sem_t *command_response_sem_buffer;
+#else
static sem_t command_response_sem_ready;
static sem_t command_response_sem_buffer;
+#endif
static GThread *command_response_thread_id;
+#ifdef __APPLE__
+static sem_t *high_priority_sem_ready;
+static sem_t *high_priority_sem_buffer;
+#else
static sem_t high_priority_sem_ready;
static sem_t high_priority_sem_buffer;
+#endif
static GThread *high_priority_thread_id;
+#ifdef __APPLE__
+static sem_t *mic_line_sem_ready;
+static sem_t *mic_line_sem_buffer;
+#else
static sem_t mic_line_sem_ready;
static sem_t mic_line_sem_buffer;
+#endif
static GThread *mic_line_thread_id;
+#ifdef __APPLE__
+static sem_t *iq_sem_ready[MAX_RECEIVERS];
+static sem_t *iq_sem_buffer[MAX_RECEIVERS];
+#else
static sem_t iq_sem_ready[MAX_RECEIVERS];
static sem_t iq_sem_buffer[MAX_RECEIVERS];
+#endif
static GThread *iq_thread_id[MAX_RECEIVERS];
static int samples[MAX_RECEIVERS];
#define NET_BUFFER_SIZE 2048
// Network buffers
static struct sockaddr_in addr;
-static int length;
+// DL1YCF next line: changed int to socklen_t
+static socklen_t length;
//static unsigned char buffer[NET_BUFFER_SIZE];
static unsigned char *iq_buffer[MAX_RECEIVERS];
static unsigned char *command_response_buffer;
new_protocol_calc_buffers();
#endif
+#ifdef __APPLE__
+ response_sem=sem_open("RESPONSE", O_CREAT, 0700, 0);
+#else
rc=sem_init(&response_sem, 0, 0);
+#endif
//rc=sem_init(&send_high_priority_sem, 0, 1);
//rc=sem_init(&send_general_sem, 0, 1);
+#ifdef __APPLE__
+ command_response_sem_ready=sem_open("COMMRESREADY", O_CREAT, 0700, 0);
+ command_response_sem_buffer=sem_open("COMMRESBUF", O_CREAT, 0700, 0);
+#else
rc=sem_init(&command_response_sem_ready, 0, 0);
rc=sem_init(&command_response_sem_buffer, 0, 0);
+#endif
command_response_thread_id = g_thread_new( "command_response thread",command_response_thread, NULL);
if( ! command_response_thread_id ) {
fprintf(stderr,"g_thread_new failed on command_response_thread\n");
exit( -1 );
}
fprintf(stderr, "command_response_thread: id=%p\n",command_response_thread_id);
+#ifdef __APPLE__
+ high_priority_sem_ready=sem_open("HIGHREADY", O_CREAT, 0700, 0);
+ high_priority_sem_buffer=sem_open("HIGHBUF", O_CREAT, 0700, 0);
+#else
rc=sem_init(&high_priority_sem_ready, 0, 0);
rc=sem_init(&high_priority_sem_buffer, 0, 0);
+#endif
high_priority_thread_id = g_thread_new( "high_priority thread", high_priority_thread, NULL);
if( ! high_priority_thread_id ) {
fprintf(stderr,"g_thread_new failed on high_priority_thread\n");
exit( -1 );
}
fprintf(stderr, "high_priority_thread: id=%p\n",high_priority_thread_id);
+#ifdef __APPLE__
+ mic_line_sem_ready=sem_open("MICREADY", O_CREAT, 0700, 0);
+ mic_line_sem_buffer=sem_open("MICBUF", O_CREAT, 0700, 0);
+#else
rc=sem_init(&mic_line_sem_ready, 0, 0);
rc=sem_init(&mic_line_sem_buffer, 0, 0);
+#endif
mic_line_thread_id = g_thread_new( "mic_line thread", mic_line_thread, NULL);
if( ! mic_line_thread_id ) {
fprintf(stderr,"g_thread_new failed on mic_line_thread\n");
fprintf(stderr, "mic_line_thread: id=%p\n",mic_line_thread_id);
for(i=0;i<RECEIVERS;i++) {
+#ifdef __APPLE__
+ char sname[12];
+#endif
ddc=receiver[i]->ddc;
+#ifdef __APPLE__
+ sprintf(sname,"IQREADY%03d", ddc);
+ iq_sem_ready[ddc]=sem_open(sname, O_CREAT, 0700, 0);
+ sprintf(sname,"IQBUF%03d", ddc);
+ iq_sem_buffer[ddc]=sem_open(sname, O_CREAT, 0700, 0);
+#else
rc=sem_init(&iq_sem_ready[ddc], 0, 0);
rc=sem_init(&iq_sem_buffer[ddc], 0, 0);
+#endif
iq_thread_id[ddc] = g_thread_new( "iq thread", iq_thread, (gpointer)(long)i);
- if( ! iq_thread_id ) {
- fprintf(stderr,"g_thread_new failed for iq_thread: rx=%d\n",i);
- exit( -1 );
- }
+ //DL1YCF: g_thread new always returns a value, upon failure the program aborts
+ // so the next four lines have been deactivated.
+ //if( ! iq_thread_id ) {
+ // fprintf(stderr,"g_thread_new failed for iq_thread: rx=%d\n",i);
+ // exit( -1 );
+ //}
fprintf(stderr, "iq_thread: rx=%d ddc=%d thread=%p\n",i, ddc, iq_thread_id);
}
#ifdef PURESIGNAL
// for PS the two feedback streams are synced on the one DDC
if(device!=NEW_DEVICE_HERMES) {
+#ifdef __APPLE__
+ char sname[12];
+#endif
ddc=receiver[PS_TX_FEEDBACK]->ddc;
+#ifdef __APPLE__
+ sprintf(sname,"IQREADY%03d", ddc);
+ iq_sem_ready[ddc]=sem_open(sname, O_CREAT, 0700, 0);
+ sprintf(sname,"IQBUF%03d", ddc);
+ iq_sem_buffer[ddc]=sem_open(sname, O_CREAT, 0700, 0);
+#else
rc=sem_init(&iq_sem_ready[ddc], 0, 0);
rc=sem_init(&iq_sem_buffer[ddc], 0, 0);
+#endif
iq_thread_id[ddc] = g_thread_new( "ps iq thread", ps_iq_thread, (gpointer)(long)PS_TX_FEEDBACK);
if( ! iq_thread_id ) {
fprintf(stderr,"g_thread_new failed for ps_iq_thread: rx=%d\n",PS_TX_FEEDBACK);
if(ddc>=MAX_RECEIVERS) {
fprintf(stderr,"unexpected iq data from ddc %d\n",ddc);
} else {
+#ifdef __APPLE__
+ sem_wait(iq_sem_ready[ddc]);
+#else
sem_wait(&iq_sem_ready[ddc]);
+#endif
iq_buffer[ddc]=buffer;
+#ifdef __APPLE__
+ sem_post(iq_sem_buffer[ddc]);
+#else
sem_post(&iq_sem_buffer[ddc]);
+#endif
}
break;
case COMMAND_RESPONCE_TO_HOST_PORT:
+#ifdef __APPLE__
+ sem_wait(command_response_sem_ready);
+#else
sem_wait(&command_response_sem_ready);
+#endif
command_response_buffer=buffer;
+#ifdef __APPLE__
+ sem_post(command_response_sem_buffer);
+#else
sem_post(&command_response_sem_buffer);
+#endif
//process_command_response();
break;
case HIGH_PRIORITY_TO_HOST_PORT:
+#ifdef __APPLE__
+ sem_wait(high_priority_sem_ready);
+#else
sem_wait(&high_priority_sem_ready);
+#endif
high_priority_buffer=buffer;
+#ifdef __APPLE__
+ sem_post(high_priority_sem_buffer);
+#else
sem_post(&high_priority_sem_buffer);
+#endif
//process_high_priority();
break;
case MIC_LINE_TO_HOST_PORT:
+#ifdef __APPLE__
+ sem_wait(mic_line_sem_ready);
+#else
sem_wait(&mic_line_sem_ready);
+#endif
mic_line_buffer=buffer;
mic_bytes_read=bytesread;
+#ifdef __APPLE__
+ sem_post(mic_line_sem_buffer);
+#else
sem_post(&mic_line_sem_buffer);
+#endif
break;
default:
fprintf(stderr,"new_protocol_thread: Unknown port %d\n",sourceport);
}
close(data_socket);
+ return NULL;
}
static gpointer command_response_thread(gpointer data) {
while(1) {
fprintf(stderr,"command_response_thread\n");
+#ifdef __APPLE__
+ sem_post(command_response_sem_ready);
+ sem_wait(command_response_sem_buffer);
+#else
sem_post(&command_response_sem_ready);
sem_wait(&command_response_sem_buffer);
+#endif
process_command_response();
free(command_response_buffer);
}
static gpointer high_priority_thread(gpointer data) {
fprintf(stderr,"high_priority_thread\n");
while(1) {
+#ifdef __APPLE__
+ sem_post(high_priority_sem_ready);
+ sem_wait(high_priority_sem_buffer);
+#else
sem_post(&high_priority_sem_ready);
sem_wait(&high_priority_sem_buffer);
+#endif
process_high_priority();
free(high_priority_buffer);
}
static gpointer mic_line_thread(gpointer data) {
fprintf(stderr,"mic_line_thread\n");
while(1) {
+#ifdef __APPLE__
+ sem_post(mic_line_sem_ready);
+ sem_wait(mic_line_sem_buffer);
+#else
sem_post(&mic_line_sem_ready);
sem_wait(&mic_line_sem_buffer);
+#endif
if(!transmitter->local_microphone) {
process_mic_data(mic_bytes_read);
}
int ddc=receiver[rx]->ddc;
fprintf(stderr,"iq_thread: rx=%d ddc=%d\n",rx,ddc);
while(1) {
+#ifdef __APPLE__
+ sem_post(iq_sem_ready[ddc]);
+ sem_wait(iq_sem_buffer[ddc]);
+#else
sem_post(&iq_sem_ready[ddc]);
sem_wait(&iq_sem_buffer[ddc]);
+#endif
process_iq_data(receiver[rx]);
free(iq_buffer[ddc]);
}
int ddc=receiver[rx]->ddc;
fprintf(stderr,"ps_iq_thread: rx=%d ddc=%d\n",rx,ddc);
while(1) {
+#ifdef __APPLE__
+ sem_post(iq_sem_ready[ddc]);
+ sem_wait(iq_sem_buffer[ddc]);
+#else
sem_post(&iq_sem_ready[ddc]);
sem_wait(&iq_sem_buffer[ddc]);
+#endif
process_ps_iq_data(receiver[rx]);
free(iq_buffer[ddc]);
}
}
rx->iq_sequence++;
- timestamp=((long long)(buffer[4]&0xFF)<<56)+((long long)(buffer[5]&0xFF)<<48)+((long long)(buffer[6]&0xFF)<<40)+((long long)(buffer[7]&0xFF)<<32);
+// DL1YCF: changed semicolon at end of next line to a plus sign
+ timestamp=((long long)(buffer[4]&0xFF)<<56)+((long long)(buffer[5]&0xFF)<<48)+((long long)(buffer[6]&0xFF)<<40)+((long long)(buffer[7]&0xFF)<<32)+
((long long)(buffer[8]&0xFF)<<24)+((long long)(buffer[9]&0xFF)<<16)+((long long)(buffer[10]&0xFF)<<8)+(long long)(buffer[11]&0xFF);
bitspersample=((buffer[12]&0xFF)<<8)+(buffer[13]&0xFF);
samplesperframe=((buffer[14]&0xFF)<<8)+(buffer[15]&0xFF);
response_sequence=((command_response_buffer[0]&0xFF)<<24)+((command_response_buffer[1]&0xFF)<<16)+((command_response_buffer[2]&0xFF)<<8)+(command_response_buffer[3]&0xFF);
response=command_response_buffer[4]&0xFF;
fprintf(stderr,"response_sequence=%ld response=%d\n",response_sequence,response);
+#ifdef __APPLE__
+ sem_post(response_sem);
+#else
sem_post(&response_sem);
+#endif
}
static void process_high_priority(unsigned char *buffer) {
sequence=((mic_line_buffer[0]&0xFF)<<24)+((mic_line_buffer[1]&0xFF)<<16)+((mic_line_buffer[2]&0xFF)<<8)+(mic_line_buffer[3]&0xFF);
b=4;
for(i=0;i<MIC_SAMPLES;i++) {
- sample=(short)((mic_line_buffer[b++]<<8) | (mic_line_buffer[b++]&0xFF));
+ // DL1YCF: changed this to two statements such that the order of pointer increments
+ // becomes clearly defined.
+ sample=(short)(mic_line_buffer[b++]<<8);
+ sample |= (short) (mic_line_buffer[b++]&0xFF);
#ifdef FREEDV
if(active_receiver->freedv) {
add_freedv_mic_sample(transmitter,sample);
b=0;
for(i=0;i<MIC_SAMPLES;i++) {
if(le) {
- sample = (short)((buffer[b++]&0xFF) | (buffer[b++]<<8));
+ // DL1YCF: changed this to two statements such that the order of pointer increments
+ // becomes clearly defined.
+ sample = (short)(buffer[b++]&0xFF);
+ sample |= (short) (buffer[b++]<<8);
} else {
- sample = (short)((buffer[b++]<<8) | (buffer[b++]&0xFF));
+ // DL1YCF: changed this to two statements such that the order of pointer increments
+ // becomes clearly defined.
+ sample = (short)(buffer[b++]<<8);
+ sample |= (short) (buffer[b++]&0xFF);
}
#ifdef FREEDV
if(active_receiver->freedv) {
// }
// }
}
+ // DL1YCF: added return statement to make compiler happy.
+ return NULL;
}
#define MIC_SAMPLES 64
extern int data_socket;
+#ifdef __APPLE__
+extern sem_t *response_sem;
+#else
extern sem_t response_sem;
+#endif
/*
extern long response_sequence;
// wait for the response to the erase command
clock_gettime(CLOCK_REALTIME, &ts);
ts.tv_sec+=120; // wait for 30 seconds
+#ifdef __APPLE__
+ result=sem_trywait(response_sem);
+#else
result=sem_timedwait(&response_sem,&ts);
+#endif
if(result==-1) {
if(errno == ETIMEDOUT) {
fprintf(stderr,"timedout waiting for response for erase (start)\n");
// wait for the erase to complete
clock_gettime(CLOCK_REALTIME, &ts);
ts.tv_sec+=120; // wait for 30 seconds
+#ifdef __APPLE__
+ result=sem_trywait(response_sem);
+#else
result=sem_timedwait(&response_sem,&ts);
+#endif
if(result==-1) {
if(errno == ETIMEDOUT) {
fprintf(stderr,"timedout waiting for response for erase (complete)\n");
programmer_send_block(b);
clock_gettime(CLOCK_REALTIME, &ts);
ts.tv_sec+=5; // wait for 5 seconds
+#ifdef __APPLE__
+ result=sem_trywait(response_sem);
+#else
result=sem_timedwait(&response_sem,&ts);
+#endif
if(result==-1) {
if(errno == ETIMEDOUT) {
fprintf(stderr,"timedout waiting for response for sent block\n");
}
block_sequence++;
}
-
+
+ // DL1YCF added return statement to make compiler happy.
+ return NULL;
}
//static void *discover_receive_thread(void* arg) {
static gpointer discover_receive_thread(gpointer data) {
struct sockaddr_in addr;
- int len;
+ // DL1YCF changed int to socklen_t
+ socklen_t len;
unsigned char buffer[2048];
int bytes_read;
struct timeval tv;
#else
strcpy(discovered[devices].name,"Hermes Lite");
#endif
+
break;
case DEVICE_ORION2:
strcpy(discovered[devices].name,"Orion 2");
}
fprintf(stderr,"discovery: exiting discover_receive_thread\n");
g_thread_exit(NULL);
+ // DL1YCF added return statement to make compiler happy.
+ return NULL;
}
void old_discovery() {
static int running;
static long ep4_sequence;
+// DL1YCF added this variable for lost-package-check
+static long last_seq_num=0;
+
static int current_rx=0;
static int samples=0;
static GThread *receive_thread_id;
static void start_receive_thread();
static gpointer receive_thread(gpointer arg);
-static void process_ozy_input_buffer(char *buffer);
+// DL1YCF changed buffer to uchar*
+static void process_ozy_input_buffer(unsigned char *buffer);
static void process_bandscope_buffer(char *buffer);
void ozy_send_buffer();
static long send_sequence=-1;
static int metis_offset=8;
-static int metis_write(unsigned char ep,char* buffer,int length);
+// DL1YCF changed buffer to uchar*
+static int metis_write(unsigned char ep,unsigned char* buffer,int length);
static void metis_start_stop(int command);
-static void metis_send_buffer(char* buffer,int length);
+// DL1YCF changed buffer to uchar*
+static void metis_send_buffer(unsigned char* buffer,int length);
static void metis_restart();
#define COMMON_MERCURY_FREQUENCY 0x80
static gpointer receive_thread(gpointer arg) {
struct sockaddr_in addr;
- int length;
+ // DL1YCF changed from int to socklen_t
+ socklen_t length;
unsigned char buffer[2048];
int bytes_read;
int ep;
// get the sequence number
sequence=((buffer[4]&0xFF)<<24)+((buffer[5]&0xFF)<<16)+((buffer[6]&0xFF)<<8)+(buffer[7]&0xFF);
+ // DL1YCF: added check on lost packets
+ if (sequence != last_seq_num+1) {
+ fprintf(stderr,"SEQ ERROR: last %ld, recvd %ld\n", last_seq_num, sequence);
+ }
+ last_seq_num=sequence;
switch(ep) {
case 6: // EP6
// process the data
break;
}
}
+ // DL1YCF added return statement to make compiler happy.
+ return NULL;
}
-static void process_ozy_input_buffer(char *buffer) {
+// Dl1YCF changed buffer to uchar*
+static void process_ozy_input_buffer(unsigned char *buffer) {
int i,j;
int r;
int b=0;
// always 48000 samples per second
b=0;
for(i=0;i<720;i++) {
+ // avoid pointer increments in logical-or constructs, as the sequence
+ // is undefined
if(le) {
- sample = (short)((buffer[b++]&0xFF) | (buffer[b++]<<8));
+ // DL1YCF: changed this to two statements such that the order of pointer increments
+ // becomes clearly defined.
+ sample = (short) (buffer[b++]&0xFF);
+ sample |= (short) (buffer[b++]<<8);
} else {
- sample = (short)((buffer[b++]<<8) | (buffer[b++]&0xFF));
+ // DL1YCF: changed this to two statements such that the order of pointer increments
+ // becomes clearly defined.
+ sample = (short)(buffer[b++]<<8);
+ sample |= (short) (buffer[b++]&0xFF);
}
#ifdef FREEDV
if(active_receiver->freedv) {
}
*/
-
+#ifdef PROTOCOL_DEBUG
+// DL1YCF Debug: save last values and log changes
+static unsigned char last_c1[20], last_c2[20], last_c3[20], last_c4[20], last_mox;
+#endif
void ozy_send_buffer() {
{
BAND *band=band_get_current_band();
int power=0;
+#ifdef STEMLAB_FIX
+ //
+ // DL1YCF:
+ // On my HAMlab RedPitaya-based SDR transceiver, CW is generated on-board the RP.
+ // However, while in CW mode, DriveLevel changes do not become effective.
+ // If the CW paddle is hit, the new PTT state is sent to piHPSDR, then the TX drive
+ // is sent the next time "command 3" is performed, but this often is too late and
+ // CW is generated with zero DriveLevel.
+ // Therefore, when in CW mode, send the TX drive level also when receiving.
+ //
+ if(split) {
+ mode=vfo[1].mode;
+ } else {
+ mode=vfo[0].mode;
+ }
+ if(isTransmitting() || (mode == modeCWU) || (mode == modeCWL)) {
+#else
if(isTransmitting()) {
+#endif
if(tune && !transmitter->tune_use_drive) {
power=(int)((double)transmitter->drive_level/100.0*(double)transmitter->tune_percent);
} else {
}
}
+#ifdef PROTOCOL_DEBUG
+//
+// DL1YCF debug:
+// look for changed parameters and log them
+// This is great for debugging protocol problems,
+// such as the HAMlab CW error fixed above, so I
+// leave it here deactivated
+//
+ int ind = output_buffer[C0] >> 1;
+ if (last_c1[ind] != output_buffer[C1]) {
+ fprintf(stderr, "C0=%x Old C1=%x New C1=%x\n", 2*ind,last_c1[ind], output_buffer[C1]);
+ last_c1[ind]=output_buffer[C1];
+ }
+ if (last_c2[ind] != output_buffer[C2]) {
+ fprintf(stderr, "C0=%x Old C2=%x New C2=%x\n", 2*ind,last_c2[ind], output_buffer[C2]);
+ last_c2[ind]=output_buffer[C2];
+ }
+ if (last_c3[ind] != output_buffer[C3]) {
+ fprintf(stderr, "C0=%x Old C3=%x New C3=%x\n", 2*ind,last_c3[ind], output_buffer[C3]);
+ last_c3[ind]=output_buffer[C3];
+ }
+ if (last_c4[ind] != output_buffer[C4]) {
+ fprintf(stderr, "C0=%x Old C4=%x New C4=%x\n", 2*ind,last_c4[ind], output_buffer[C4]);
+ last_c4[ind]=output_buffer[C4];
+ }
+ if ((output_buffer[C0] & 1) != last_mox) {
+ fprintf(stderr, "Last Mox=%d New Mox=%d\n", last_mox, output_buffer[C0] & 1);
+ last_mox=output_buffer[C0] & 1;
+ }
+#endif
+
#ifdef USBOZY
//
// if we have a USB interfaced Ozy device:
}
#endif
-static int metis_write(unsigned char ep,char* buffer,int length) {
+// DL1YCF change buffer to uchar*
+static int metis_write(unsigned char ep,unsigned char* buffer,int length) {
int i;
// copy the buffer over
static void metis_restart() {
// reset metis frame
- metis_offset==8;
+ // DL1YCF change == to = in the next line
+ metis_offset=8;
// reset current rx
current_rx=0;
+#ifdef STEMLAB_FIX
+ // DL1YCF:
+ // My RedPitaya HPSDR "clone" won't start up
+ // if too many commands are sent here. Note these
+ // packets are only there for sync-ing in the clock
+ // source etc.
+ // Note that always two 512-byte OZY buffers are
+ // combined into one METIS packet.
+ //
+ command=1; // ship out a "C0=0" and a "set tx" command
+ ozy_send_buffer();
+ ozy_send_buffer();
+ command=2; // ship out a "C0=0" and a "set rx" command for RX1
+ ozy_send_buffer();
+ ozy_send_buffer();
+
+ // DL1YCF: reset for the next commands
+ current_rx=0;
+ command=1;
+#else
+ // DL1YCF this is the original code, which does not do what it pretends ....
// send commands twice
command=1;
do {
do {
ozy_send_buffer();
} while (command!=1);
+#endif
sleep(1);
#endif
}
-static void metis_send_buffer(char* buffer,int length) {
+// DL1YCF changedbuffer to uchar *
+static void metis_send_buffer(unsigned char* buffer,int length) {
if(sendto(data_socket,buffer,length,0,(struct sockaddr*)&data_addr,data_addr_length)!=length) {
perror("sendto socket failed for metis_send_data\n");
}
--- /dev/null
+#ifdef PORTAUDIO
+//
+// DL1YCF: if PortAudio is NOT used, this file is empty, and audio.c
+// is used instead.
+// Here we also implement two (hopefully useful) functions:
+// - a dummy two-tone 'Microphone' device
+//
+
+#include <gtk/gtk.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <sched.h>
+#include <semaphore.h>
+
+#include "new_protocol.h"
+#include "old_protocol.h"
+#ifdef RADIOBERRY
+#include "radioberry.h"
+#endif
+#include "radio.h"
+#include "receiver.h"
+#include "portaudio.h"
+#include "math.h" // for sintab, two-tone generator
+
+static PaStream *record_handle=NULL;
+
+#define MAXDEVICES 12
+
+const char *input_devices[MAXDEVICES];
+const char *output_devices[MAXDEVICES];
+
+int n_input_devices=0;
+int n_output_devices=0;
+
+static int in_device_no[MAXDEVICES];
+static int out_device_no[MAXDEVICES];
+
+static unsigned char *mic_buffer=NULL;
+static int mic_buffer_size;
+static int audio_buffer_size=256;
+
+//
+// Dummy Two-tone input device
+//
+static int TwoTone=0;
+#define lentab 480
+static float sintab[lentab];
+static int tonept;
+#define twopi 6.2831853071795864769252867665590
+#define factab (twopi/480)
+
+
+//
+// AUDIO_GET_CARDS
+//
+// This inits PortAudio and looks for suitable input and output channels
+//
+void audio_get_cards()
+{
+ int i, numDevices;
+ const PaDeviceInfo *deviceInfo;
+ PaStreamParameters inputParameters, outputParameters;
+
+ PaError err;
+
+ // generate sine tab
+ for (i=0; i< lentab; i++) sintab[i] = 0.35*(sin(7*i*factab)+sin(19*i*factab));
+
+ err = Pa_Initialize();
+ if( err != paNoError )
+ {
+ fprintf(stderr, "PORTAUDIO ERROR: Pa_Initialize: %s\n", Pa_GetErrorText(err));
+ return;
+ }
+ numDevices = Pa_GetDeviceCount();
+ if( numDevices < 0 ) return;
+
+ n_input_devices=0;
+ n_output_devices=0;
+
+ for( i=0; i<numDevices; i++ )
+ {
+ deviceInfo = Pa_GetDeviceInfo( i );
+
+ inputParameters.device = i;
+ inputParameters.channelCount = 1;
+ inputParameters.sampleFormat = paFloat32;
+ inputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
+ inputParameters.hostApiSpecificStreamInfo = NULL;
+ if (Pa_IsFormatSupported(&inputParameters, NULL, 48000.0) == paFormatIsSupported) {
+ // duplicate the first suitable device, this will become
+ // a dummy two-tone generator
+ if (n_input_devices == 0) {
+ input_devices[n_input_devices]="TwoTone";
+ in_device_no[n_input_devices++] =i;
+ }
+ if (n_input_devices < MAXDEVICES) {
+ input_devices[n_input_devices]=deviceInfo->name;
+ in_device_no[n_input_devices++] =i;
+ }
+ fprintf(stderr,"PORTAUDIO INPUT DEVICE, No=%d, Name=%s\n", i, deviceInfo->name);
+ }
+
+ outputParameters.device = i;
+ outputParameters.channelCount = 1;
+ outputParameters.sampleFormat = paFloat32;
+ outputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
+ outputParameters.hostApiSpecificStreamInfo = NULL;
+ if (Pa_IsFormatSupported(NULL, &outputParameters, 48000.0) == paFormatIsSupported) {
+ if (n_output_devices < MAXDEVICES) {
+ output_devices[n_output_devices]=deviceInfo->name;
+ out_device_no[n_output_devices++] =i;
+ }
+ fprintf(stderr,"PORTAUDIO OUTPUT DEVICE, No=%d, Name=%s\n", i, deviceInfo->name);
+ }
+ }
+}
+
+//
+// AUDIO_OPEN_INPUT
+//
+// open a PA stream that connects to the TX microphone
+// The PA callback function then sends the data to the transmitter
+//
+
+int pa_mic_cb(const void*, void*, unsigned long, const PaStreamCallbackTimeInfo*, PaStreamCallbackFlags, void*);
+unsigned char *micbuffer = NULL;
+
+int audio_open_input()
+{
+ PaError err;
+ PaStreamParameters inputParameters, outputParameters;
+ long framesPerBuffer;
+ int i;
+
+ fprintf(stderr,"audio_open_input: %d\n",transmitter->input_device);
+ if(transmitter->input_device<0 || transmitter->input_device>=n_input_devices) {
+ transmitter->input_device=0;
+ return -1;
+ }
+
+ switch(protocol) {
+ case ORIGINAL_PROTOCOL:
+ framesPerBuffer = 720;
+ break;
+ case NEW_PROTOCOL:
+ framesPerBuffer = 64;
+ break;
+#ifdef RADIOBERRY
+ case RADIOBERRY_PROTOCOL:
+ framesPerBuffer = 1024;
+ break;
+#endif
+ default:
+ break;
+ }
+
+ bzero( &inputParameters, sizeof( inputParameters ) ); //not necessary if you are filling in all the fields
+ inputParameters.channelCount = 1;
+ inputParameters.device = in_device_no[transmitter->input_device];
+ inputParameters.hostApiSpecificStreamInfo = NULL;
+ inputParameters.sampleFormat = paFloat32;
+ inputParameters.suggestedLatency = Pa_GetDeviceInfo(in_device_no[transmitter->input_device])->defaultLowInputLatency ;
+ inputParameters.hostApiSpecificStreamInfo = NULL; //See you specific host's API docs for info on using this field
+
+ err = Pa_OpenStream(&record_handle, &inputParameters, NULL, 48000.0, framesPerBuffer, paNoFlag, pa_mic_cb, NULL);
+ if (err != paNoError) {
+ fprintf(stderr, "PORTAUDIO ERROR: AOI open stream: %s\n",Pa_GetErrorText(err));
+ return -1;
+ }
+
+ err = Pa_StartStream(record_handle);
+ if (err != paNoError) {
+ fprintf(stderr, "PORTAUDIO ERROR: AOI start stream:%s\n",Pa_GetErrorText(err));
+ return -1;
+ }
+ mic_buffer=(unsigned char *)malloc(2*framesPerBuffer);
+ mic_buffer_size=framesPerBuffer;
+ TwoTone=0;
+ if (transmitter->input_device == 0) {
+ tonept=0;
+ TwoTone=1;
+ }
+ return 0;
+}
+
+//
+// PortAudio call-back function for Audio input
+//
+int pa_mic_cb(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer,
+ const PaStreamCallbackTimeInfo* timeInfo,
+ PaStreamCallbackFlags statusFlags,
+ void *userdata)
+{
+ const float *in = (float *)inputBuffer;
+ int i;
+ short isample;
+ unsigned char *p;
+
+//
+// Convert input buffer in paFloat32 into a sequence of 16-bit
+// values in the mic buffer
+//
+ if (mic_buffer == NULL) return paAbort;
+
+ p=mic_buffer;
+ if (in == NULL || framesPerBuffer != mic_buffer_size) {
+ for (i=0; i<mic_buffer_size; i++) {
+ *p++ = 0;
+ *p++ = 0;
+ }
+ } else if (TwoTone == 0) {
+ for (i=0; i<framesPerBuffer; i++) {
+ isample=(short) (in[i]*32768.0);
+ *p++ = (isample & 0xFF); // LittleEndian
+ *p++ = (isample >> 8)& 0xFF;
+ }
+ } else {
+ for (i=0; i<framesPerBuffer; i++) {
+ isample=(short) (sintab[tonept++]*32768.0);
+ if (tonept == lentab) tonept=0;
+ *p++ = (isample & 0xFF); // LittleEndian
+ *p++ = (isample >> 8)& 0xFF;
+ }
+ }
+//
+// Call routine to send mic buffer
+//
+ switch(protocol) {
+ case ORIGINAL_PROTOCOL:
+ old_protocol_process_local_mic(mic_buffer,1);
+ break;
+ case NEW_PROTOCOL:
+ new_protocol_process_local_mic(mic_buffer,1);
+ break;
+#ifdef RADIOBERRY
+ case RADIOBERRY_PROTOCOL:
+ radioberry_protocol_process_local_mic(mic_buffer,1);
+ break;
+#endif
+ default:
+ break;
+ }
+ return paContinue;
+}
+
+//
+// AUDIO_OPEN_OUTPUT
+//
+// open a PA stream for data from one of the RX
+//
+int audio_open_output(RECEIVER *rx)
+{
+ PaError err;
+ PaStreamParameters outputParameters;
+ long framesPerBuffer=(long) audio_buffer_size;
+
+ int padev = out_device_no[rx->audio_device];
+ fprintf(stderr,"audio_open_output: %d PADEV=%d\n",rx->audio_device,padev);
+ if(rx->audio_device<0 || rx->audio_device>=n_output_devices) {
+ rx->audio_device=-1;
+ return -1;
+ }
+ bzero( &outputParameters, sizeof( outputParameters ) ); //not necessary if you are filling in all the fields
+ outputParameters.channelCount = 1; // Always MONO
+ outputParameters.device = padev;
+ outputParameters.hostApiSpecificStreamInfo = NULL;
+ outputParameters.sampleFormat = paFloat32;
+ outputParameters.suggestedLatency = Pa_GetDeviceInfo(padev)->defaultLowOutputLatency ;
+ outputParameters.hostApiSpecificStreamInfo = NULL; //See you specific host's API docs for info on using this field
+
+ // Try using AudioWrite without a call-back function
+
+ rx->playback_buffer=malloc(audio_buffer_size*sizeof(float));
+ rx->playback_offset=0;
+ err = Pa_OpenStream(&(rx->playback_handle), NULL, &outputParameters, 48000.0, framesPerBuffer, paNoFlag, NULL, NULL);
+ if (err != paNoError) {
+ fprintf(stderr,"PORTAUDIO ERROR: AOO open stream: %s\n",Pa_GetErrorText(err));
+ rx->playback_handle = NULL;
+ if (rx->playback_buffer) free(rx->playback_buffer);
+ rx->playback_buffer = NULL;
+ return -1;
+ }
+
+ err = Pa_StartStream(rx->playback_handle);
+ if (err != paNoError) {
+ fprintf(stderr,"PORTAUDIO ERROR: AOO start stream:%s\n",Pa_GetErrorText(err));
+ rx->playback_handle=NULL;
+ if (rx->playback_buffer) free(rx->playback_buffer);
+ rx->playback_buffer = NULL;
+ return -1;
+ }
+ // Write one buffer to avoid under-flow errors
+ // (this gives us 5 msec to pass before we have to call audio_write the first time)
+ bzero(rx->playback_buffer, (size_t) audio_buffer_size*sizeof(float));
+ err=Pa_WriteStream(rx->playback_handle, (void *) rx->playback_buffer, (unsigned long) audio_buffer_size);
+ return 0;
+}
+
+//
+// AUDIO_CLOSE_INPUT
+//
+// close a TX microphone stream
+//
+void audio_close_input()
+{
+ PaError err;
+
+ fprintf(stderr,"AudioCloseInput: %d\n", transmitter->input_device);
+
+ if(record_handle!=NULL) {
+ err = Pa_StopStream(record_handle);
+ if (err != paNoError) {
+ fprintf(stderr,"PORTAUDIO ERROR: ACI stop stream: %s\n",Pa_GetErrorText(err));
+ }
+ err = Pa_CloseStream(record_handle);
+ if (err != paNoError) {
+ fprintf(stderr,"PORTAUDIO ERROR: ACI close stream: %s\n",Pa_GetErrorText(err));
+ }
+ record_handle=NULL;
+ }
+ if(mic_buffer!=NULL) {
+ free(mic_buffer);
+ mic_buffer=NULL;
+ }
+}
+
+//
+// AUDIO_CLOSE_OUTPUT
+//
+// shut down the stream connected with audio from one of the RX
+//
+void audio_close_output(RECEIVER *rx) {
+ PaError err;
+
+ fprintf(stderr,"AudioCloseOutput: %d\n", rx->audio_device);
+
+// free the buffer first, this then indicates to audio_write to do nothing
+ if(rx->playback_buffer!=NULL) {
+ free(rx->playback_buffer);
+ rx->playback_buffer=NULL;
+ }
+
+ if(rx->playback_handle!=NULL) {
+ err = Pa_StopStream(rx->playback_handle);
+ if (err != paNoError) {
+ fprintf(stderr,"PORTAUDIO ERROR: ACO stop stream: %s\n",Pa_GetErrorText(err));
+ }
+ err = Pa_CloseStream(rx->playback_handle);
+ if (err != paNoError) {
+ fprintf(stderr,"PORTAUDIO ERROR: ACO close stream: %s\n",Pa_GetErrorText(err));
+ }
+ rx->playback_handle=NULL;
+ }
+}
+
+//
+// AUDIO_WRITE
+//
+// send RX audio data to a PA output stream
+// we have to store the data such that the PA callback function
+// can access it.
+//
+static int apt=0;
+int audio_write (RECEIVER *rx, short r, short l)
+{
+ PaError err;
+
+ if (rx->playback_handle != NULL && rx->playback_buffer != NULL) {
+ rx->playback_buffer[rx->playback_offset++] = (r + l) *0.000015259; // 65536 --> 1.0
+ if (rx->playback_offset == audio_buffer_size) {
+ rx->playback_offset=0;
+ err=Pa_WriteStream(rx->playback_handle, (void *) rx->playback_buffer, (unsigned long) audio_buffer_size);
+ //if (err != paNoError) {
+ // fprintf(stderr,"PORTAUDIO ERROR: write stream dev=%d: %s\n",out_device_no[rx->audio_device],Pa_GetErrorText(err));
+ // return -1;
+ // }
+ }
+ }
+ return 0;
+}
+
+//
+// CW audio write
+// This is a dummy here because I think it is not correctly implemented in audio.c
+//
+void cw_audio_write(double sample) {
+}
+
+#endif
DISCOVERED *radio=NULL;
char property_path[128];
+#ifdef __APPLE__
+sem_t *property_sem;
+#else
sem_t property_sem;
+#endif
RECEIVER *receiver[MAX_RECEIVERS];
RECEIVER *active_receiver;
} else {
gtk_fixed_move(GTK_FIXED(fixed),sliders,0,y);
}
- gtk_widget_show_all(sliders);
+ gtk_widget_show_all(sliders); // DL1YCF this shows both C25 and Alex ATT/Preamp sliders
+ att_type_changed(); // DL1YCF added here to hide the „wrong“ ones.
} else {
if(sliders!=NULL) {
gtk_container_remove(GTK_CONTAINER(fixed),sliders);
gdk_window_set_cursor(gtk_widget_get_window(top_window),gdk_cursor_new(GDK_WATCH));
int rc;
+#ifdef __APPLE__
+ property_sem=sem_open("PROPERTY", O_CREAT, 0700, 0);
+ rc=(property_sem == SEM_FAILED);
+#else
rc=sem_init(&property_sem, 0, 0);
+#endif
if(rc!=0) {
fprintf(stderr,"start_radio: sem_init failed for property_sem: %d\n", rc);
exit(-1);
}
+#ifdef __APPLE__
+ sem_post(property_sem);
+#else
sem_post(&property_sem);
+#endif
char text[256];
//for(i=0;i<devices;i++) {
char *value;
fprintf(stderr,"radioRestoreState: %s\n",property_path);
+#ifdef __APPLE__
+ sem_wait(property_sem);
+#else
sem_wait(&property_sem);
+#endif
loadProperties(property_path);
value=getProperty("region");
value=getProperty("rx2_gain_slider");
if(value) rx_gain_slider[1]=atoi(value);
+#ifdef __APPLE__
+ sem_post(property_sem);
+#else
sem_post(&property_sem);
+#endif
}
void radioSaveState() {
int i;
char value[80];
+#ifdef __APPLE__
+ sem_wait(property_sem);
+#else
sem_wait(&property_sem);
+#endif
sprintf(value,"%d",region);
setProperty("region",value);
sprintf(value,"%d",buffer_size);
setProperty("rigctl_port_base",value);
saveProperties(property_path);
+#ifdef __APPLE__
+ sem_post(property_sem);
+#else
sem_post(&property_sem);
+#endif
}
void calculate_display_average(RECEIVER *rx) {
&x,
&y,
&state);
- if((state & GDK_BUTTON1_MASK == GDK_BUTTON1_MASK) || pressed) {
+ // DL1YCF added a pair of () to fix an error
+ if(((state & GDK_BUTTON1_MASK) == GDK_BUTTON1_MASK) || pressed) {
int moved=last_x-x;
vfo_move((long long)((float)moved*rx->hz_per_pixel));
last_x=x;
#define _RECEIVER_H
#include <gtk/gtk.h>
+#ifdef PORTAUDIO
+#include "portaudio.h"
+#else
#include <alsa/asoundlib.h>
+#endif
#define AUDIO_BUFFER_SIZE 260
int local_audio;
int mute_when_not_active;
int audio_device;
+#ifdef PORTAUDIO
+ PaStream *playback_handle;
+ float *playback_buffer;
+#else
snd_pcm_t *playback_handle;
- int playback_offset;
unsigned char *playback_buffer;
+#endif
+ int playback_offset;
int low_latency;
int squelch_enable;
int rigctlGetFilterLow();
int rigctlGetFilterHigh();
-int rigctlSetFilterLow(int val);
-int rigctlSetFilterHigh(int val);
+// DL1YCF changed next to function to void
+void rigctlSetFilterLow(int val);
+void rigctlSetFilterHigh(int val);
int new_level;
int active_transmitter = 0;
int rigctl_busy = 0; // Used to tell rigctl_menu that launch has already occured
typedef struct _client {
int socket;
- int address_length;
+ // Dl1YCF change from int to socklen_t
+ socklen_t address_length;
struct sockaddr_in address;
GThread *thread_id;
} CLIENT;
// Wait throttle time
usleep(RIGCTL_TIMER_DELAY);
rigctl_timer = 0;
+ // DL1YCF added return statement to make compiler happy.
+ return NULL;
}
//
if(agc_resp == 0) {
active_receiver->agc = AGC_OFF;
- } else if(agc_resp >0 && agc_resp <= 5 || (agc_resp == 84)) {
+ } else if((agc_resp >0 && agc_resp <= 5) || (agc_resp == 84)) { // DL1YCF: added () to improve readability
active_receiver->agc = AGC_FAST;
// fprintf(stderr,"GT command FAST\n");
- } else if(agc_resp >6 && agc_resp <= 10 || (agc_resp == 2*84)) {
+ } else if((agc_resp >6 && agc_resp <= 10) || (agc_resp == 2*84)) { // DL1YCF: added () to improve readability
active_receiver->agc = AGC_MEDIUM;
// fprintf(stderr,"GT command MED\n");
- } else if(agc_resp >11 && agc_resp <= 15 || (agc_resp == 3*84)) {
+ } else if((agc_resp >11 && agc_resp <= 15) || (agc_resp == 3*84)) { // DL1YCF: added () to improve readability
active_receiver->agc = AGC_SLOW;
//fprintf(stderr,"GT command SLOW\n");
- } else if(agc_resp >16 && agc_resp <= 20 || (agc_resp == 4*84)) {
+ } else if((agc_resp >16 && agc_resp <= 20) || (agc_resp == 4*84)) { // DL1YCF: added () to improve readability
active_receiver->agc = AGC_LONG;
// fprintf(stderr,"GT command LONG\n");
}
send_resp(client_sock,"IS00000;");
}
}
- else if((strcmp(cmd_str,"KS")==0) && (zzid_flag == 0) ||
- (strcmp(cmd_str,"CS")==0) && (zzid_flag==1)) {
+ else if(((strcmp(cmd_str,"KS")==0) && (zzid_flag == 0)) || // Dl1YCF added () to improve readablity
+ ((strcmp(cmd_str,"CS")==0) && (zzid_flag==1))) { // Dl1YCF added () to improve readablity
// TS-2000 - KS - Set/Reads keying speed 0-060 max
// PiHPSDR - ZZCS - Sets/Reads Keying speed
if(len <=2) {
send_resp(client_sock,"?;");
}
}
- else if((strcmp(cmd_str,"SD")==0) && (zzid_flag == 0) ||
- (strcmp(cmd_str,"CD")==0) && (zzid_flag ==1)) {
+ else if(((strcmp(cmd_str,"SD")==0) && (zzid_flag == 0)) || // Dl1YCF added () to improve readablity
+ ((strcmp(cmd_str,"CD")==0) && (zzid_flag ==1))) { // Dl1YCF added () to improve readablity
// PiHPSDR - ZZCD - Set/Read CW Keyer Hang Time
// TS-2000 - SD - Set/Read Break In Delay
//
// Determine how high above 127 we are..making a range of 114 from S0 to S9+60db
// 5 is a fugdge factor that shouldn't be there - but seems to get us to S9=SM015
- level = abs(127+(level + (double) adc_attenuation[receiver[r]->adc]))+5;
+ // DL1YCF replaced abs by fabs, and changed 127 to floating point constant
+ level = fabs(127.0+(level + (double) adc_attenuation[receiver[r]->adc]))+5;
// Clip the value just in case
if(cmd_input[2] == '0') {
}
}
-
-int rigctlSetFilterLow(int val){
+// Changed these two functions to void
+void rigctlSetFilterLow(int val){
};
-int rigctlSetFilterHigh(int val){
+void rigctlSetFilterHigh(int val){
};
void set_freqB(long long new_freqB) {
active_receiver->mute_radio=gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
}
+//
+// DL1YCF:
+// possible the device has been changed:
+// call audo_close_output with old device, audio_open_output with new one
+//
static void local_output_changed_cb(GtkWidget *widget, gpointer data) {
- active_receiver->audio_device=(int)(long)data;
-fprintf(stderr,"local_output_changed rx=%d to %d\n",active_receiver->id,active_receiver->audio_device);
+//active_receiver->audio_device=(int)(long)data;
+ int newdev = (int)(long)data;
+fprintf(stderr,"local_output_changed rx=%d from %d to %d\n",active_receiver->id,active_receiver->audio_device,newdev);
if(active_receiver->local_audio) {
- audio_close_output(active_receiver);
- if(audio_open_output(active_receiver)==0) {
+ audio_close_output(active_receiver); // audio_close with OLD device
+ active_receiver->audio_device=newdev; // update rx to NEW device
+ if(audio_open_output(active_receiver)==0) { // audio_open with NEW device
active_receiver->local_audio=1;
} else {
active_receiver->local_audio=0;
*
*/
+#ifdef __APPLE__
+
+
+//
+// MacOS has no vahi, but it does have libcurl.
+// Therefore we try to start the SDR app on the RedPitaya
+// assuming is has the (fixed) ip address which can be
+// read from $HOME/.rp.inet, if this does not succeed it
+// defaults to 192.168.1.3.
+//
+// So, on MacOS, just configure your STEMLAB/HAMLAB to this
+// fixed IP address and you need not open a browser to start
+// SDR *before* you can use piHPSDR.
+//
+// Sure it's not perfect, but it makes life much easier for me.
+//
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <curl/curl.h>
+#include <glib.h>
+
+extern void status_text(const char *);
+
+static const char *appid = NULL;
+
+//
+// Extract the list of apps from the JSON answer
+//
+static size_t app_list_callback(void *buffer, size_t size, size_t nmemb, void *data) {
+ const gchar *needle;
+
+ needle="\"sdr_receiver_hpsdr\"";
+ if (g_strstr_len(buffer, size*nmemb, needle) != NULL) {
+ appid="sdr_receiver_hpsdr";
+ }
+
+ needle="\"sdr_transceiver_hpsdr\"";
+ if (g_strstr_len(buffer, size*nmemb, needle) != NULL) {
+ appid="sdr_transceiver_hpsdr";
+ }
+
+ needle="\"stemlab_sdr_transceiver_hpsdr\"";
+ if (g_strstr_len(buffer, size*nmemb, needle) != NULL) {
+ appid="stemlab_sdr_transceiver_hpsdr";
+ }
+
+ needle="\"hamlab_sdr_transceiver_hpsdr\"";
+ if (g_strstr_len(buffer, size*nmemb, needle) != NULL) {
+ appid="hamlab_sdr_transceiver_hpsdr";
+ }
+
+ if (appid) fprintf(stderr,"RedPitay WEB application to start: %s\n", appid);
+ return size * nmemb;
+}
+
+void stemlab_discovery() {
+ // this one is used "as the last resort", if nothing else is found.
+ size_t len;
+ char inet[20];
+ char txt[150];
+ CURL *curl_handle;
+ CURLcode curl_error;
+ FILE *fpin;
+ char *p;
+
+ fprintf(stderr,"Stripped-down STEMLAB/HAMLAB discovery...\n");
+//
+// Try to read inet addr from $HOME/.rp.inet, otherwise take 192.168.1.3
+//
+ strcpy(inet,"192,168.1.3");
+ p=getenv("HOME");
+ if (p) {
+ strncpy(txt,p, (size_t) 100); // way less than size of txt
+ } else {
+ strcpy(txt,".");
+ }
+ strcat(txt,"/.rp.inet");
+ fprintf(stderr,"Trying to read inet addr from file=%s\n", txt);
+ fpin=fopen(txt, "r");
+ if (fpin) {
+ len=100;
+ p=txt;
+ len=getline(&p, &len, fpin);
+ // not txt now contains the trailing newline character
+ while (*p != 0) {
+ if (*p == '\n') *p = 0;
+ p++;
+ }
+ if (len < 20) strcpy(inet,txt);
+ }
+ fclose(fpin);
+ fprintf(stderr,"STEMLAB: using inet addr %s\n", inet);
+//
+// Do a HEAD request (poor curl's ping) to see whether the device is on-line
+// allow a 15 sec time-out
+ status_text("Looking for a STEMLAB web server ...");
+ curl_handle = curl_easy_init();
+ if (curl_handle == NULL) {
+ fprintf(stderr, "stemlab_start: Failed to create cURL handle\n");
+ return;
+ }
+ sprintf(txt,"http://%s",inet);
+ curl_error = curl_easy_setopt(curl_handle, CURLOPT_URL, txt);
+ curl_error = curl_easy_setopt(curl_handle, CURLOPT_NOBODY, (long) 1);
+ curl_error = curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, (long) 15);
+ curl_error = curl_easy_perform(curl_handle);
+ curl_easy_cleanup(curl_handle);
+ if (curl_error == CURLE_OPERATION_TIMEDOUT) {
+ sprintf(txt,"No response from web server at %s", inet);
+ status_text(txt);
+ fprintf(stderr,"%s\n",txt);
+ }
+ if (curl_error != CURLE_OK) {
+ fprintf(stderr, "STEMLAB ping error: %s\n", curl_easy_strerror(curl_error));
+ return;
+ }
+
+//
+//obtain a list of apps, and choose the right one by looking for the following
+//target strings (in that order). Whatever is found first, is started. Then, we rely
+//on the original discovery() to discover the device.
+//
+//hamlab_sdr_transceiver_hpsdr
+//stemlab_sdr_transceiver_hpsdr
+//sdr_transceiver_hpsdr
+//sdr_receiver_hpsdr
+//
+ curl_handle = curl_easy_init();
+ if (curl_handle == NULL) {
+ fprintf(stderr, "stemlab_start: Failed to create cURL handle\n");
+ return;
+ }
+ sprintf(txt,"http://%s/bazaar?apps=", inet);
+ curl_error = curl_easy_setopt(curl_handle, CURLOPT_URL, txt);
+ curl_error = curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, (long) 60);
+ curl_error = curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, app_list_callback);
+ curl_error = curl_easy_perform(curl_handle);
+ curl_easy_cleanup(curl_handle);
+ if (curl_error == CURLE_OPERATION_TIMEDOUT) {
+ status_text("No Response from RedPitaya in 60 secs");
+ fprintf(stderr,"60-sec TimeOut met when trying to get list of HPSDR apps from RedPitaya\n");
+ }
+ if (curl_error != CURLE_OK) {
+ fprintf(stderr, "STEMLAB app-list error: %s\n", curl_easy_strerror(curl_error));
+ return;
+ }
+
+//
+// Now we actually start the hpsdr application
+// Actually, try to stop it first, then re-start it.
+//
+ if (appid) {
+ curl_handle = curl_easy_init();
+ if (curl_handle == NULL) {
+ fprintf(stderr, "stemlab_start: Failed to create cURL handle\n");
+ return;
+ }
+ sprintf(txt,"http://%s/bazaar?stop=%s",inet,appid);
+ curl_error = curl_easy_setopt(curl_handle, CURLOPT_URL, txt);
+ curl_error = curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, (long) 60);
+ curl_error = curl_easy_perform(curl_handle);
+ if (curl_error == CURLE_OPERATION_TIMEDOUT) {
+ fprintf(stderr,"60-sec TimeOut met when trying to stop HPSDR app on RedPitaya\n");
+ }
+ if (curl_error != CURLE_OK) {
+ fprintf(stderr, "STEMLAB app-start error: %s\n", curl_easy_strerror(curl_error));
+ }
+ curl_handle = curl_easy_init();
+ if (curl_handle == NULL) {
+ fprintf(stderr, "stemlab_start: Failed to create cURL handle\n");
+ return;
+ }
+ sprintf(txt,"http://%s/bazaar?start=%s",inet,appid);
+ curl_error = curl_easy_setopt(curl_handle, CURLOPT_URL, txt);
+ curl_error = curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, (long) 60);
+ curl_error = curl_easy_perform(curl_handle);
+ if (curl_error == CURLE_OPERATION_TIMEDOUT) {
+ fprintf(stderr,"60-sec TimeOut met when trying to start HPSDR app on RedPitaya\n");
+ }
+ if (curl_error != CURLE_OK) {
+ fprintf(stderr, "STEMLAB app-start error: %s\n", curl_easy_strerror(curl_error));
+ }
+
+ }
+ // Whether or net we have successfully started the HPSDR application on the RedPitaya,
+ // we now return to the regular HPSDR protocol handling code that will eventually detect
+ // the "board". If this code does not work, you have to open a browser and start the HPSDR
+ // application manually.
+}
+
+// dummy function
+void stemlab_cleanup() {
+}
+
+// dummy function, never called
+void stemlab_start_app() {
+}
+
+#else
+
#include <errno.h>
#include <ifaddrs.h>
#include <net/if.h>
curl_global_cleanup();
}
}
+#endif
static gboolean step_select_cb (GtkWidget *widget, gpointer data) {
step=steps[(uintptr_t)data];
vfo_update();
+ // DL1YCF added return statement to make the compiler happy.
+ // however I am unsure about the correct return value.
+ // I would have coded this as a void function.
+ return FALSE;
}
void step_menu(GtkWidget *parent) {
// Save in the file now..
memSaveState();
+ // DL1YCF added return statement to make the compiler happy.
+ // however I am unsure about the correct return value.
+ // I would have coded this as a void function.
+ return FALSE;
}
static gboolean recall_select_cb (GtkWidget *widget, gpointer data) {
vfo_mode_changed(mem[index].mode);
g_idle_add(ext_vfo_update,NULL);
+ // DL1YCF added return statement to make the compiler happy.
+ // however I am unsure about the correct return value.
+ // I would have coded this as a void function.
+ return FALSE;
}
void store_menu(GtkWidget *parent) {
int key = 0;
+// DL1YCF added next line.
+extern void cw_audio_write(double sample);
static gint update_out_of_band(gpointer data) {
TRANSMITTER *tx=(TRANSMITTER *)data;
tx->out_of_band=0;
static gboolean emp_cb (GtkWidget *widget, gpointer data) {
pre_emphasize=gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
tx_set_pre_emphasize(transmitter,pre_emphasize);
+ // DL1YCF added return statement to make the compiler happy.
+ // however I am unsure about the correct return value.
+ // I would have coded this as a void function.
+ return FALSE;
}
static void tune_value_changed_cb(GtkWidget *widget, gpointer data) {
&x,
&y,
&state);
- if((state & GDK_BUTTON1_MASK == GDK_BUTTON1_MASK) || pressed) {
+ // DL1YCF: added a pair of () to fix an error
+ if(((state & GDK_BUTTON1_MASK) == GDK_BUTTON1_MASK) || pressed) {
int moved=last_x-x;
vfo_move((long long)((float)moved*hz_per_pixel));
last_x=x;
} else {
vfo_move(-step);
}
+ // DL1YCF added return statement to make the compiler happy.
+ // however I am unsure about the correct return value.
+ // I would have coded this as a void function.
+ return FALSE;
}
void tx_panadapter_update(TRANSMITTER *tx) {
} else {
vfo_move(-step);
}
+ // DL1YCF added return statement to make the compiler happy.
+ // however I am unsure about the correct return value.
+ // I would have coded this as a void function.
+ return FALSE;
}
}
}
vfo_update();
+ // DL1YCF added return statement to make the compiler happy.
+ // however I am unsure about the correct return value.
+ // I would have coded this as a void function.
+ return FALSE;
}
static void rit_cb(GtkComboBox *widget,gpointer data) {
g_idle_add(level_update,NULL);
usleep(100000); // 100ms
}
+ // DL1YCF added return statement to make compilers happy.
+ return NULL;
}
static void cleanup() {
display_height=gtk_widget_get_allocated_height (widget);
rx->pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, display_width, display_height);
- char *pixels = gdk_pixbuf_get_pixels (rx->pixbuf);
+ // DL1YCF changed to uchar
+ unsigned char *pixels = gdk_pixbuf_get_pixels (rx->pixbuf);
memset(pixels, 0, display_width*display_height*3);
float *samples;
if(rx->pixbuf) {
- char *pixels = gdk_pixbuf_get_pixels (rx->pixbuf);
+ // DL1YCF changed to uchar
+ unsigned char *pixels = gdk_pixbuf_get_pixels (rx->pixbuf);
int width=gdk_pixbuf_get_width(rx->pixbuf);
int height=gdk_pixbuf_get_height(rx->pixbuf);
float sample;
int average=0;
- char *p;
+ // DL1YCF changed to uchar
+ unsigned char *p;
p=pixels;
samples=rx->pixel_samples;
for(i=0;i<width;i++) {