From: g0orx Date: Wed, 3 Feb 2016 09:51:29 +0000 (+1030) Subject: Ininital commit of source files X-Git-Url: https://git.rkrishnan.org/listings/frontends//%22%3C?a=commitdiff_plain;h=d89e02e670c673589337ce248263c55b29278bca;p=pihpsdr.git Ininital commit of source files --- diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c5bae3b --- /dev/null +++ b/Makefile @@ -0,0 +1,86 @@ +UNAME_N := $(shell uname -n) + +CC=gcc +LINK=gcc +OPTIONS=-g -D $(UNAME_N) +GTKINCLUDES=`pkg-config --cflags gtk+-3.0` +GTKLIBS=`pkg-config --libs gtk+-3.0` +LIBS=-lwiringPi -lpigpio -lrt -lm -lwdsp -lpthread $(GTKLIBS) +INCLUDES=$(GTKINCLUDES) + +COMPILE=$(CC) $(OPTIONS) $(INCLUDES) + +PROGRAM=pihpsdr + + +SOURCES= \ +band.c \ +filter.c \ +main.c \ +meter.c \ +mode.c \ +new_discovery.c \ +new_protocol.c \ +new_protocol_programmer.c \ +panadapter.c \ +property.c \ +radio.c \ +rotary_encoder.c \ +splash.c \ +toolbar.c \ +vfo.c \ +waterfall.c + +HEADERS= \ +agc.h \ +alex.h \ +band.h \ +bandstack.h \ +channel.h \ +discovered.h \ +filter.h \ +meter.h \ +mode.h \ +new_discovery.h \ +new_protocol.h \ +panadapter.h \ +property.h \ +radio.h \ +rotary_encoder.h \ +splash.h \ +toolbar.h \ +vfo.h \ +waterfall.h \ +xvtr.h + +OBJS= \ +band.o \ +filter.o \ +main.o \ +meter.o \ +mode.o \ +new_discovery.o \ +new_protocol.o \ +new_protocol_programmer.o \ +panadapter.o \ +property.o \ +radio.o \ +rotary_encoder.o \ +splash.o \ +toolbar.o \ +vfo.o \ +waterfall.o + +all: $(PROGRAM) $(HEADERS) $(SOURCES) + +$(PROGRAM): $(OBJS) + $(LINK) -o $(PROGRAM) $(OBJS) $(LIBS) + +.c.o: + $(COMPILE) $(OPTIONS) -c -o $@ $< + + +clean: + -rm -f *.o + -rm -f $(PROGRAM) + diff --git a/agc.h b/agc.h new file mode 100644 index 0000000..c6e3aff --- /dev/null +++ b/agc.h @@ -0,0 +1,6 @@ +#define AGC_OFF 0 +#define AGC_LONG 1 +#define AGC_SLOW 2 +#define AGC_MEDIUM 3 +#define AGC_FAST 4 + diff --git a/alex.h b/alex.h new file mode 100644 index 0000000..7ead806 --- /dev/null +++ b/alex.h @@ -0,0 +1,31 @@ +#define ALEX_RX_ANTENNA_NONE 0x00000000 +#define ALEX_RX_ANTENNA_XVTR 0x00000900 +#define ALEX_RX_ANTENNA_EXT1 0x00000A00 +#define ALEX_RX_ANTENNA_EXT2 0x00000C00 +#define ALEX_RX_ANTENNA_BYPASS 0x00000800 + +#define ALEX_TX_ANTENNA_1 0x01000000 +#define ALEX_TX_ANTENNA_2 0x02000000 +#define ALEX_TX_ANTENNA_3 0x04000000 + +#define ALEX_ATTENUATION_0dB 0x00000000 +#define ALEX_ATTENUATION_10dB 0x00004000 +#define ALEX_ATTENUATION_20dB 0x00002000 +#define ALEX_ATTENUATION_30dB 0x00006000 + +#define ALEX_30_20_LPF 0x00100000 +#define ALEX_60_40_LPF 0x00200000 +#define ALEX_80_LPF 0x00400000 +#define ALEX_160_LPF 0x00800000 +#define ALEX_6_BYPASS_LPF 0x20000000 +#define ALEX_12_10_LPF 0x40000000 +#define ALEX_17_15_LPF 0x80000000 + +#define ALEX_13MHZ_HPF 0x00000002 +#define ALEX_20MHZ_HPF 0x00000004 +#define ALEX_9_5MHZ_HPF 0x00000010 +#define ALEX_6_5MHZ_HPF 0x00000020 +#define ALEX_1_5MHZ_HPF 0x00000040 +#define ALEX_BYPASS_HPF 0x00000800 + +#define ALEX_6M_PREAMP 0x00000008 diff --git a/band.c b/band.c new file mode 100644 index 0000000..53ec328 --- /dev/null +++ b/band.c @@ -0,0 +1,344 @@ +#include + +#include "bandstack.h" +#include "band.h" +#include "filter.h" +#include "mode.h" +#include "xvtr.h" +#include "alex.h" +#include "property.h" + +int band=band20; +int xvtr_band=band160; + +/* --------------------------------------------------------------------------*/ +/** +* @brief bandstack +*/ +/* ----------------------------------------------------------------------------*/ +BANDSTACK_ENTRY bandstack_entries160[] = + {{1810000LL,modeCWL,filterF4,-2800,-200,-2800,-200}, + {1835000LL,modeCWU,filterF0,-2800,-200,-2800,-200}, + {1845000LL,modeUSB,filterF5,-2800,-200,-2800,-200}}; + +BANDSTACK_ENTRY bandstack_entries80[] = + {{3501000LL,modeCWL,filterF0,-2800,-200,-2800,-200}, + {3751000LL,modeLSB,filterF5,-2800,-200,-2800,-200}, + {3850000LL,modeLSB,filterF5,-2800,-200,-2800,-200}}; + +BANDSTACK_ENTRY bandstack_entries60[] = + {{5330500LL,modeUSB,filterF5,-2800,-200,-2800,-200}, + {5346500LL,modeUSB,filterF5,-2800,-200,-2800,-200}, + {5366500LL,modeUSB,filterF5,-2800,-200,-2800,-200}, + {5371500LL,modeUSB,filterF5,-2800,-200,-2800,-200}, + {5403500LL,modeUSB,filterF5,-2800,-200,-2800,-200}}; + +BANDSTACK_ENTRY bandstack_entries40[] = + {{7001000LL,modeCWL,filterF0,-2800,-200,-2800,-200}, + {7152000LL,modeLSB,filterF5,-2800,-200,-2800,-200}, + {7255000LL,modeLSB,filterF5,-2800,-200,-2800,-200}}; + +BANDSTACK_ENTRY bandstack_entries30[] = + {{10120000LL,modeCWU,filterF0,200,2800,200,2800}, + {10130000LL,modeCWU,filterF0,200,2800,200,2800}, + {10140000LL,modeCWU,filterF4,200,2800,200,2800}}; + +BANDSTACK_ENTRY bandstack_entries20[] = + {{14010000LL,modeCWU,filterF0,200,2800,200,2800}, + {14230000LL,modeUSB,filterF5,200,2800,200,2800}, + {14336000LL,modeUSB,filterF5,200,2800,200,2800}}; + +BANDSTACK_ENTRY bandstack_entries18[] = + {{18068600LL,modeCWU,filterF0,200,2800,200,2800}, + {18125000LL,modeUSB,filterF5,200,2800,200,2800}, + {18140000LL,modeUSB,filterF5,200,2800,200,2800}}; + +BANDSTACK_ENTRY bandstack_entries15[] = + {{21001000LL,modeCWU,filterF0,200,2800,200,2800}, + {21255000LL,modeUSB,filterF5,200,2800,200,2800}, + {21300000LL,modeUSB,filterF5,200,2800,200,2800}}; + +BANDSTACK_ENTRY bandstack_entries12[] = + {{24895000LL,modeCWU,filterF0,200,2800,200,2800}, + {24900000LL,modeUSB,filterF5,200,2800,200,2800}, + {24910000LL,modeUSB,filterF5,200,2800,200,2800}}; + +BANDSTACK_ENTRY bandstack_entries10[] = + {{28010000LL,modeCWU,filterF0,200,2800,200,2800}, + {28300000LL,modeUSB,filterF5,200,2800,200,2800}, + {28400000LL,modeUSB,filterF5,200,2800,200,2800}}; + +BANDSTACK_ENTRY bandstack_entries50[] = + {{50010000LL,modeCWU,filterF0,200,2800,200,2800}, + {50125000LL,modeUSB,filterF5,200,2800,200,2800}, + {50200000LL,modeUSB,filterF5,200,2800,200,2800}}; + +BANDSTACK_ENTRY bandstack_entriesGEN[] = + {{909000LL,modeAM,filterF6,-6000,6000,-6000,60000}, + {5975000LL,modeAM,filterF6,-6000,6000,-6000,60000}, + {13845000LL,modeAM,filterF6,-6000,6000,-6000,60000}}; + +BANDSTACK_ENTRY bandstack_entriesWWV[] = + {{2500000LL,modeSAM,filterF6,200,2800,200,2800}, + {5000000LL,modeSAM,filterF6,200,2800,200,2800}, + {10000000LL,modeSAM,filterF6,200,2800,200,2800}, + {15000000LL,modeSAM,filterF6,200,2800,200,2800}, + {20000000LL,modeSAM,filterF6,200,2800,200,2800}}; + +BANDSTACK bandstack160={3,1,bandstack_entries160}; +BANDSTACK bandstack80={3,1,bandstack_entries80}; +BANDSTACK bandstack60={5,1,bandstack_entries60}; +BANDSTACK bandstack40={3,1,bandstack_entries40}; +BANDSTACK bandstack30={3,1,bandstack_entries30}; +BANDSTACK bandstack20={3,1,bandstack_entries20}; +BANDSTACK bandstack18={3,1,bandstack_entries18}; +BANDSTACK bandstack15={3,1,bandstack_entries15}; +BANDSTACK bandstack12={3,1,bandstack_entries12}; +BANDSTACK bandstack10={3,1,bandstack_entries10}; +BANDSTACK bandstack50={3,1,bandstack_entries50}; +BANDSTACK bandstackGEN={3,1,bandstack_entriesGEN}; +BANDSTACK bandstackWWV={5,1,bandstack_entriesWWV}; + +BAND bands[BANDS] = + {{"160",&bandstack160,0,0,0,ALEX_RX_ANTENNA_NONE,ALEX_TX_ANTENNA_1,ALEX_ATTENUATION_0dB}, + {"80",&bandstack80,0,0,0,ALEX_RX_ANTENNA_NONE,ALEX_TX_ANTENNA_1,ALEX_ATTENUATION_0dB}, + {"60",&bandstack60,0,0,0,ALEX_RX_ANTENNA_NONE,ALEX_TX_ANTENNA_1,ALEX_ATTENUATION_0dB}, + {"40",&bandstack40,0,0,0,ALEX_RX_ANTENNA_NONE,ALEX_TX_ANTENNA_1,ALEX_ATTENUATION_0dB}, + {"30",&bandstack30,0,0,0,ALEX_RX_ANTENNA_NONE,ALEX_TX_ANTENNA_1,ALEX_ATTENUATION_0dB}, + {"20",&bandstack20,0,0,0,ALEX_RX_ANTENNA_NONE,ALEX_TX_ANTENNA_1,ALEX_ATTENUATION_0dB}, + {"18",&bandstack18,0,0,0,ALEX_RX_ANTENNA_NONE,ALEX_TX_ANTENNA_1,ALEX_ATTENUATION_0dB}, + {"15",&bandstack15,0,0,0,ALEX_RX_ANTENNA_NONE,ALEX_TX_ANTENNA_1,ALEX_ATTENUATION_0dB}, + {"12",&bandstack12,0,0,0,ALEX_RX_ANTENNA_NONE,ALEX_TX_ANTENNA_1,ALEX_ATTENUATION_0dB}, + {"10",&bandstack10,0,0,0,ALEX_RX_ANTENNA_NONE,ALEX_TX_ANTENNA_1,ALEX_ATTENUATION_0dB}, + {"50",&bandstack50,0,0,0,ALEX_RX_ANTENNA_NONE,ALEX_TX_ANTENNA_1,ALEX_ATTENUATION_0dB}, + {"GEN",&bandstackGEN,0,0,0,ALEX_RX_ANTENNA_NONE,ALEX_TX_ANTENNA_1,ALEX_ATTENUATION_0dB}, + {"WWV",&bandstackWWV,0,0,0,ALEX_RX_ANTENNA_NONE,ALEX_TX_ANTENNA_1,ALEX_ATTENUATION_0dB}}; + +#define NUM_BAND_LIMITS 22 + +BAND_LIMITS bandLimits[NUM_BAND_LIMITS] = { + {1800000LL,2000000LL}, + {3500000LL,4000000LL}, + {5330500LL,5403500LL}, + {7000000LL,7300000LL}, + {10100000LL,10150000LL}, + {14000000LL,14350000LL}, + {18068000LL,18168000LL}, + {21000000LL,21450000LL}, + {24890000LL,24990000LL}, + {28000000LL,29700000LL}, + {50000000LL,54000000LL}, + {144000000LL,148000000LL}, + {222000000LL,224980000LL}, + {420000000LL,450000000LL}, + {902000000LL,928000000LL}, + {1240000000LL,1300000000LL}, + {2300000000LL,2450000000LL}, + {3456000000LL,3456400000LL}, + {5760000000LL,5760400000LL}, + {10368000000LL,10368400000LL}, + {24192000000LL,24192400000LL}, + {47088000000LL,47088400000LL} +}; + +/* --------------------------------------------------------------------------*/ +/** +* @brief xvtr +*/ +/* ----------------------------------------------------------------------------*/ +static XVTR_ENTRY xvtr[12]= + {{"",0LL,0LL,0LL,0LL,0LL,0LL,0LL,0LL,0,modeUSB,filterF5,-2800,-200,-2800,-200,0,0,0,0}, + {"",0LL,0LL,0LL,0LL,0LL,0LL,0LL,0LL,0,modeUSB,filterF5,-2800,-200,-2800,-200,0,0,0,0}, + {"",0LL,0LL,0LL,0LL,0LL,0LL,0LL,0LL,0,modeUSB,filterF5,-2800,-200,-2800,-200,0,0,0,0}, + {"",0LL,0LL,0LL,0LL,0LL,0LL,0LL,0LL,0,modeUSB,filterF5,-2800,-200,-2800,-200,0,0,0,0}, + {"",0LL,0LL,0LL,0LL,0LL,0LL,0LL,0LL,0,modeUSB,filterF5,-2800,-200,-2800,-200,0,0,0,0}, + {"",0LL,0LL,0LL,0LL,0LL,0LL,0LL,0LL,0,modeUSB,filterF5,-2800,-200,-2800,-200,0,0,0,0}, + {"",0LL,0LL,0LL,0LL,0LL,0LL,0LL,0LL,0,modeUSB,filterF5,-2800,-200,-2800,-200,0,0,0,0}, + {"",0LL,0LL,0LL,0LL,0LL,0LL,0LL,0LL,0,modeUSB,filterF5,-2800,-200,-2800,-200,0,0,0,0}, + {"",0LL,0LL,0LL,0LL,0LL,0LL,0LL,0LL,0,modeUSB,filterF5,-2800,-200,-2800,-200,0,0,0,0}, + {"",0LL,0LL,0LL,0LL,0LL,0LL,0LL,0LL,0,modeUSB,filterF5,-2800,-200,-2800,-200,0,0,0,0}, + {"",0LL,0LL,0LL,0LL,0LL,0LL,0LL,0LL,0,modeUSB,filterF5,-2800,-200,-2800,-200,0,0,0,0}, + {"",0LL,0LL,0LL,0LL,0LL,0LL,0LL,0LL,0,modeUSB,filterF5,-2800,-200,-2800,-200,0,0,0,0}}; + + +BANDSTACK_ENTRY *bandstack_entry_get_current() { + BANDSTACK *bandstack=bands[band].bandstack; + BANDSTACK_ENTRY *entry=&bandstack->entry[bandstack->current_entry]; + return entry; +} + +BANDSTACK_ENTRY *bandstack_entry_next() { + BANDSTACK *bandstack=bands[band].bandstack; + bandstack->current_entry++; + if(bandstack->current_entry==bandstack->entries) { + bandstack->current_entry=0; + } + BANDSTACK_ENTRY *entry=&bandstack->entry[bandstack->current_entry]; + return entry; +} + +int band_get_current() { + return band; +} + +BAND *band_get_current_band() { + BAND *b=&bands[band]; + return b; +} + +BAND *band_get_band(int b) { + BAND *band=&bands[b]; + return band; +} + +BAND *band_set_current(int b) { + band=b; + return &bands[b]; +} + + +void bandSaveState() { + char name[128]; + char value[128]; + int current; + BANDSTACK_ENTRY* entry; + + int b; + int stack; + for(b=0;bentries); + sprintf(name,"band.%d.entries",b); + setProperty(name,value); + + sprintf(value,"%d",bands[b].bandstack->current_entry); + sprintf(name,"band.%d.current",b); + setProperty(name,value); + + sprintf(value,"%d",bands[b].preamp); + sprintf(name,"band.%d.preamp",b); + setProperty(name,value); + + sprintf(value,"%ld",bands[b].alexRxAntenna); + sprintf(name,"band.%d.alexRxAntenna",b); + setProperty(name,value); + + sprintf(value,"%ld",bands[b].alexTxAntenna); + sprintf(name,"band.%d.alexTxAntenna",b); + setProperty(name,value); + + sprintf(value,"%ld",bands[b].alexAttenuation); + sprintf(name,"band.%d.alexAttenuation",b); + setProperty(name,value); + + for(stack=0;stackentries;stack++) { + entry=bands[b].bandstack->entry; + entry+=stack; + + sprintf(value,"%lld",entry->frequencyA); + sprintf(name,"band.%d.stack.%d.a",b,stack); + setProperty(name,value); + + sprintf(value,"%d",entry->mode); + sprintf(name,"band.%d.stack.%d.mode",b,stack); + setProperty(name,value); + + sprintf(value,"%d",entry->filter); + sprintf(name,"band.%d.stack.%d.filter",b,stack); + setProperty(name,value); + + sprintf(value,"%d",entry->var1Low); + sprintf(name,"band.%d.stack.%d.var1Low",b,stack); + setProperty(name,value); + + sprintf(value,"%d",entry->var1High); + sprintf(name,"band.%d.stack.%d.var1High",b,stack); + setProperty(name,value); + + sprintf(value,"%d",entry->var2Low); + sprintf(name,"band.%d.stack.%d.var2Low",b,stack); + setProperty(name,value); + + sprintf(value,"%d",entry->var2High); + sprintf(name,"band.%d.stack.%d.var2High",b,stack); + setProperty(name,value); + + } + } + + sprintf(value,"%d",band); + setProperty("band",value); +} + +void bandRestoreState() { + char* value; + + int b; + int stack; + char name[128]; + BANDSTACK_ENTRY* entry; + int current; + + + for(b=0;bentries=atoi(value); + + sprintf(name,"band.%d.current",b); + value=getProperty(name); + if(value) bands[b].bandstack->current_entry=atoi(value); + + sprintf(name,"band.%d.preamp",b); + value=getProperty(name); + if(value) bands[b].preamp=atoi(value); + + sprintf(name,"band.%d.alexRxAntenna",b); + value=getProperty(name); + if(value) bands[b].alexRxAntenna=atoi(value); + + sprintf(name,"band.%d.alexTxAntenna",b); + value=getProperty(name); + if(value) bands[b].alexTxAntenna=atoi(value); + + sprintf(name,"band.%d.alexAttenuation",b); + value=getProperty(name); + if(value) bands[b].alexAttenuation=atoi(value); + for(stack=0;stackentries;stack++) { + entry=bands[b].bandstack->entry; + entry+=stack; + + sprintf(name,"band.%d.stack.%d.a",b,stack); + value=getProperty(name); + if(value) entry->frequencyA=atoll(value); + + sprintf(name,"band.%d.stack.%d.mode",b,stack); + value=getProperty(name); + if(value) entry->mode=atoi(value); + + sprintf(name,"band.%d.stack.%d.filter",b,stack); + value=getProperty(name); + if(value) entry->filter=atoi(value); + + sprintf(name,"band.%d.stack.%d.var1Low",b,stack); + value=getProperty(name); + if(value) entry->var1Low=atoi(value); + + sprintf(name,"band.%d.stack.%d.var1High",b,stack); + value=getProperty(name); + if(value) entry->var1High=atoi(value); + + sprintf(name,"band.%d.stack.%d.var2Low",b,stack); + value=getProperty(name); + if(value) entry->var2Low=atoi(value); + + sprintf(name,"band.%d.stack.%d.var2High",b,stack); + value=getProperty(name); + if(value) entry->var2High=atoi(value); + + } + } + value=getProperty("band"); + if(value) band=atoi(value); +} + + diff --git a/band.h b/band.h new file mode 100644 index 0000000..24d15c1 --- /dev/null +++ b/band.h @@ -0,0 +1,100 @@ +/** +* @file band.h +* @brief Header files for the Amateur Radio band stack. +* @author John Melton, G0ORX/N6LYT, Doxygen Comments Dave Larsen, KV0S +* @version 0.1 +* @date 2009-04-11 +*/ +// band.h + +/* Copyright (C) +* 2009 - John Melton, G0ORX/N6LYT, Doxygen Comments Dave Larsen, KV0S +* 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 "bandstack.h" + +#define band160 0 +#define band80 1 +#define band60 2 +#define band40 3 +#define band30 4 +#define band20 5 +#define band17 6 +#define band15 7 +#define band12 8 +#define band10 9 +#define band6 10 +#define bandGen 11 +#define bandWWV 12 + +#define BANDS 13 + +/* --------------------------------------------------------------------------*/ +/** +* @brief Bandlimit definition +*/ +struct _BAND_LIMITS { + long long minFrequency; + long long maxFrequency; +}; + +typedef struct _BAND_LIMITS BAND_LIMITS; + +/* --------------------------------------------------------------------------*/ +/** +* @brief Band definition +*/ +struct _BAND { + char title[16]; + BANDSTACK *bandstack; + unsigned char OCrx; + unsigned char OCtx; + int preamp; + unsigned long alexRxAntenna; + unsigned long alexTxAntenna; + unsigned long alexAttenuation; +}; + +typedef struct _BAND BAND; + +int band; +int xvtr_band; +gboolean displayHF; + +int band_get_current(); +BAND *band_get_current_band(); +BAND *band_get_band(int b); +BAND *band_set_current(int b); + +BANDSTACK_ENTRY *bandstack_entry_next(); +BANDSTACK_ENTRY *bandstack_entry_get_current(); + +/* +void bandSaveState(); +void bandRestoreState(); +void forceBand(int band,int setup); +void configureXVTRButton(int setup); +GtkWidget* buildBandUI(); + +int remoteSetBand(gpointer *data); + +BAND_LIMITS* getBandLimits(long long minDisplay,long long maxDisplay); +XVTR_ENTRY* getXvtrEntry(int i); + +*/ + diff --git a/bandstack.h b/bandstack.h new file mode 100644 index 0000000..2fb8e9a --- /dev/null +++ b/bandstack.h @@ -0,0 +1,54 @@ +/** +* @file bandstack.h +* @brief Bandstack definition files +* @author John Melton, G0ORX/N6LYT, Doxygen Comments Dave Larsen, KV0S +* @version 0.1 +* @date 2009-04-11 +*/ +// bandstack.h + +/* Copyright (C) +* This program is free software; you can redistribute it and/or2009 - John Melton, G0ORX/N6LYT, Doxygen Comments Dave Larsen, KV0S +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* +*/ + +#ifndef BANDSTACK_H +#define BANDSTACK_H +/* --------------------------------------------------------------------------*/ +/** +* @brief Bandstack definition +*/ +struct _BANDSTACK_ENTRY { + long long frequencyA; + int mode; + int filter; + int var1Low; + int var1High; + int var2Low; + int var2High; +}; + +typedef struct _BANDSTACK_ENTRY BANDSTACK_ENTRY; + +struct _BANDSTACK { + int entries; + int current_entry; + BANDSTACK_ENTRY *entry; +}; + +typedef struct _BANDSTACK BANDSTACK; + +#endif + diff --git a/calculus b/calculus new file mode 100644 index 0000000..7b51e4f Binary files /dev/null and b/calculus differ diff --git a/channel.h b/channel.h new file mode 100644 index 0000000..ae1e178 --- /dev/null +++ b/channel.h @@ -0,0 +1,12 @@ +#define CHANNEL_RX0 0 +#define CHANNEL_RX1 1 +#define CHANNEL_RX2 2 +#define CHANNEL_RX3 3 +#define CHANNEL_RX4 4 +#define CHANNEL_RX5 5 +#define CHANNEL_RX6 6 +#define CHANNEL_RX7 7 +#define CHANNEL_TX 8 +#define CHANNEL_BS 9 +#define CHANNEL_SUBRX 10 + diff --git a/discovered.h b/discovered.h new file mode 100644 index 0000000..e644e69 --- /dev/null +++ b/discovered.h @@ -0,0 +1,45 @@ +#include + +#define MAX_DEVICES 16 + +#define DEVICE_METIS 0 +#define DEVICE_HERMES 1 +#define DEVICE_GRIFFIN 2 +#define DEVICE_ANGELIA 4 +#define DEVICE_ORION 5 +#define DEVICE_HERMES_LITE 6 + +#define NEW_DEVICE_ATLAS 0 +#define NEW_DEVICE_HERMES 1 +#define NEW_DEVICE_HERMES2 2 +#define NEW_DEVICE_ANGELIA 3 +#define NEW_DEVICE_ORION 4 +#define NEW_DEVICE_ANAN_10E 5 +#define NEW_DEVICE_HERMES_LITE 6 + +#define STATE_AVAILABLE 2 +#define STATE_SENDING 3 + +#define ORIGINAL_PROTOCOL 0 +#define NEW_PROTOCOL 1 + +struct _DISCOVERED { + int protocol; + int device; + char name[16]; + int software_version; + unsigned char mac_address[6]; + int status; + int address_length; + struct sockaddr_in address; + int interface_length; + struct sockaddr_in interface_address; + char interface_name[64]; +}; + +typedef struct _DISCOVERED DISCOVERED; + +extern int selected_device; +extern int devices; +extern DISCOVERED discovered[MAX_DEVICES]; + diff --git a/filter.c b/filter.c new file mode 100644 index 0000000..e6b0fe5 --- /dev/null +++ b/filter.c @@ -0,0 +1,184 @@ +#include "filter.h" + +FILTER filterLSB[FILTERS]={ + {-5150,-150,"5.0k"}, + {-4550,-150,"4.4k"}, + {-3950,-150,"3.8k"}, + {-3450,-150,"3.3k"}, + {-3050,-150,"2.9k"}, + {-2850,-150,"2.7k"}, + {-2550,-150,"2.4k"}, + {-2250,-150,"2.1k"}, + {-1950,-150,"1.8k"}, + {-1150,-150,"1.0k"}/*, + {-2850,-150,"Var1"}, + {-2850,-150,"Var2"}*/ + }; + +FILTER filterDIGL[FILTERS]={ + {-5150,-150,"5.0k"}, + {-4550,-150,"4.4k"}, + {-3950,-150,"3.8k"}, + {-3450,-150,"3.3k"}, + {-3050,-150,"2.9k"}, + {-2850,-150,"2.7k"}, + {-2550,-150,"2.4k"}, + {-2250,-150,"2.1k"}, + {-1950,-150,"1.8k"}, + {-1150,-150,"1.0k"}/*, + {-2850,-150,"Var1"}, + {-2850,-150,"Var2"}*/ + }; + +FILTER filterUSB[FILTERS]={ + {150,5150,"5.0k"}, + {150,4550,"4.4k"}, + {150,3950,"3.8k"}, + {150,3450,"3.3k"}, + {150,3050,"2.9k"}, + {150,2850,"2.7k"}, + {150,2550,"2.4k"}, + {150,2250,"2.1k"}, + {150,1950,"1.8k"}, + {150,1150,"1.0k"}/*, + {150,2850,"Var1"}, + {150,2850,"Var2"}*/ + }; + +FILTER filterDIGU[FILTERS]={ + {150,5150,"5.0k"}, + {150,4550,"4.4k"}, + {150,3950,"3.8k"}, + {150,3450,"3.3k"}, + {150,3050,"2.9k"}, + {150,2850,"2.7k"}, + {150,2550,"2.4k"}, + {150,2250,"2.1k"}, + {150,1950,"1.8k"}, + {150,1150,"1.0k"}/*, + {150,2850,"Var1"}, + {150,2850,"Var2"}*/ + }; + +FILTER filterCWL[FILTERS]={ + {500,500,"1.0k"}, + {400,400,"800"}, + {375,375,"750"}, + {300,300,"600"}, + {250,250,"500"}, + {200,200,"400"}, + {125,125,"250"}, + {50,50,"100"}, + {25,25,"50"}, + {13,13,"25"}/*, + {250,250,"Var1"}, + {250,250,"Var2"}*/ + }; + +FILTER filterCWU[FILTERS]={ + {500,500,"1.0k"}, + {400,400,"800"}, + {375,375,"750"}, + {300,300,"600"}, + {250,250,"500"}, + {200,200,"400"}, + {125,125,"250"}, + {50,50,"100"}, + {25,25,"50"}, + {13,13,"25"}/*, + {250,250,"Var1"}, + {250,250,"Var2"}*/ + }; + +FILTER filterAM[FILTERS]={ + {-8000,8000,"16k"}, + {-6000,6000,"12k"}, + {-5000,5000,"10k"}, + {-4000,4000,"8k"}, + {-3300,3300,"6.6k"}, + {-2600,2600,"5.2k"}, + {-2000,2000,"4.0k"}, + {-1550,1550,"3.1k"}, + {-1450,1450,"2.9k"}, + {-1200,1200,"2.4k"}/*, + {-3300,3300,"Var1"}, + {-3300,3300,"Var2"}*/ + }; + +FILTER filterSAM[FILTERS]={ + {-8000,8000,"16k"}, + {-6000,6000,"12k"}, + {-5000,5000,"10k"}, + {-4000,4000,"8k"}, + {-3300,3300,"6.6k"}, + {-2600,2600,"5.2k"}, + {-2000,2000,"4.0k"}, + {-1550,1550,"3.1k"}, + {-1450,1450,"2.9k"}, + {-1200,1200,"2.4k"}/*, + {-3300,3300,"Var1"}, + {-3300,3300,"Var2"}*/ + }; + +FILTER filterFMN[FILTERS]={ + {-8000,8000,"16k"}, + {-6000,6000,"12k"}, + {-5000,5000,"10k"}, + {-4000,4000,"8k"}, + {-3300,3300,"6.6k"}, + {-2600,2600,"5.2k"}, + {-2000,2000,"4.0k"}, + {-1550,1550,"3.1k"}, + {-1450,1450,"2.9k"}, + {-1200,1200,"2.4k"}/*, + {-3300,3300,"Var1"}, + {-3300,3300,"Var2"}*/ + }; + +FILTER filterDSB[FILTERS]={ + {-8000,8000,"16k"}, + {-6000,6000,"12k"}, + {-5000,5000,"10k"}, + {-4000,4000,"8k"}, + {-3300,3300,"6.6k"}, + {-2600,2600,"5.2k"}, + {-2000,2000,"4.0k"}, + {-1550,1550,"3.1k"}, + {-1450,1450,"2.9k"}, + {-1200,1200,"2.4k"}/*, + {-3300,3300,"Var1"}, + {-3300,3300,"Var2"}*/ + }; + +FILTER filterSPEC[FILTERS]={ + {-8000,8000,"16k"}, + {-6000,6000,"12k"}, + {-5000,5000,"10k"}, + {-4000,4000,"8k"}, + {-3300,3300,"6.6k"}, + {-2600,2600,"5.2k"}, + {-2000,2000,"4.0k"}, + {-1550,1550,"3.1k"}, + {-1450,1450,"2.9k"}, + {-1200,1200,"2.4k"}/*, + {-3300,3300,"Var1"}, + {-3300,3300,"Var2"}*/ + }; + +FILTER filterDRM[FILTERS]={ + {-8000,8000,"16k"}, + {-6000,6000,"12k"}, + {-5000,5000,"10k"}, + {-4000,4000,"8k"}, + {-3300,3300,"6.6k"}, + {-2600,2600,"5.2k"}, + {-2000,2000,"4.0k"}, + {-1550,1550,"3.1k"}, + {-1450,1450,"2.9k"}, + {-1200,1200,"2.4k"}/*, + {-3300,3300,"Var1"}, + {-3300,3300,"Var2"}*/ + }; + +FILTER *filters[]={filterLSB,filterUSB,filterDSB,filterCWL,filterCWU,filterFMN,filterAM,filterDIGU,filterSPEC,filterDIGL,filterSAM,filterDRM}; + diff --git a/filter.h b/filter.h new file mode 100644 index 0000000..ad72c9f --- /dev/null +++ b/filter.h @@ -0,0 +1,79 @@ +/** +* @file filter.h +* @brief Header files to define the filters. +* @author John Melton, G0ORX/N6LYT, Doxygen Comments Dave Larsen, KV0S +* @version 0.1 +* @date 2009-04-11 +*/ +// filter.h +/* Copyright (C) +* 2009 - John Melton, G0ORX/N6LYT, Doxygen Comments Dave Larsen, KV0S +* 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 "mode.h" + +// disable Var1 and Var2 (change to 12 to enable) +#define FILTERS 10 + +#define CW_PITCH 600 + +struct _FILTER { + int low; + int high; + char* title; +}; + +typedef struct _FILTER FILTER; + +#define filterF0 0 +#define filterF1 1 +#define filterF2 2 +#define filterF3 3 +#define filterF4 4 +#define filterF5 5 +#define filterF6 6 +#define filterF7 7 +#define filterF8 8 +#define filterF9 9 +#define filterVar1 10 +#define filterVar2 11 + +int filter; + +int filterLow; +int filterHigh; + +int txFilterLowCut; +int txFilterHighCut; + +int filterVar1Low; +int filterVar1High; +int filterVar2Low; +int filterVar2High; + + +FILTER *filters[MODES]; + +/* +int updateFilter(void * data); +GtkWidget* buildFilterUI(); +void filterSaveState(); +void filterRestoreState(); +void setFilterValues(int mode); +void setFilter(int filter); +void setTxFilters(); +*/ diff --git a/main.c b/main.c new file mode 100644 index 0000000..814e9f5 --- /dev/null +++ b/main.c @@ -0,0 +1,345 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "main.h" +#include "channel.h" +#include "discovered.h" +#include "new_discovery.h" +#include "new_protocol.h" +#include "wdsp.h" +#include "vfo.h" +#include "meter.h" +#include "panadapter.h" +#include "splash.h" +#include "waterfall.h" +#include "toolbar.h" +#include "radio.h" + +#define VFO_HEIGHT (display_height/8) +#define VFO_WIDTH ((display_width/4)*3) +#define METER_HEIGHT (display_height/8) +#define METER_WIDTH (display_width/4) +#define PANADAPTER_HEIGHT (display_height/4) +#define TOOLBAR_HEIGHT (display_height/4) +#define WATERFALL_HEIGHT (display_height-(VFO_HEIGHT+PANADAPTER_HEIGHT+TOOLBAR_HEIGHT)) + +struct utsname unameData; + +gint display_width; +gint display_height; + +static gint update_timer_id; +static gint updates_per_second=10; + +static gint save_timer_id; + +static float *samples; + +static int start=0; + +static GtkWidget *discovery_dialog; + +gint update(gpointer data) { + int result; + GetPixels(isTransmitting()==0?CHANNEL_RX0:CHANNEL_TX,samples,&result); + if(result==1) { + panadapter_update(samples,isTransmitting()); + if(!isTransmitting()) { + waterfall_update(samples); + } + } + + if(!isTransmitting()) { + float m=GetRXAMeter(CHANNEL_RX0, 1/*WDSP.S_AV*/); + meter_update(SMETER,(double)m,0.0); + } else { + + DISCOVERED *d=&discovered[selected_device]; + + double constant1=5.0; + double constant2=0.108; + + switch(d->device) { + case NEW_DEVICE_ATLAS: + constant1=3.3; + constant2=0.09; + break; + case NEW_DEVICE_HERMES: + constant1=3.3; + constant2=0.09; + break; + case NEW_DEVICE_HERMES2: + constant1=3.3; + constant2=0.095; + break; + case NEW_DEVICE_ANGELIA: + constant1=3.3; + constant2=0.095; + break; + case NEW_DEVICE_ORION: + constant1=5.0; + constant2=0.108; + break; + case NEW_DEVICE_ANAN_10E: + constant1=3.3; + constant2=0.09; + break; + case NEW_DEVICE_HERMES_LITE: + constant1=3.3; + constant2=0.09; + break; + } + + int power=alex_forward_power; + if(power==0) { + power=exciter_power; + } + double v1; + double fwd; + double rev; + v1=((double)power/4095.0)*constant1; + fwd=(v1*v1)/constant2; + + rev=0.0; + if(alex_forward_power!=0) { + power=alex_reverse_power; + v1=((double)power/4095.0)*constant1; + rev=(v1*v1)/constant2; + } + meter_update(POWER,fwd,rev); + } + + return TRUE; +} + +static gint save_cb(gpointer data) { + radioSaveState(); + saveProperties(property_path); + return TRUE; +} + +static void start_cb(GtkWidget *widget, gpointer data) { +fprintf(stderr,"start_cb\n"); + selected_device=(int)data; + start=1; + gtk_widget_destroy(discovery_dialog); +} + +static void configure_cb(GtkWidget *widget, gpointer data) { +} + + +gint init(void* arg) { + + GtkWidget *window; + GtkWidget *grid; + GtkWidget *vfo; + GtkWidget *meter; + GtkWidget *panadapter; + GtkWidget *waterfall; + GtkWidget *toolbar; + + DISCOVERED* d; + + char wisdom_directory[1024]; + char wisdom_file[1024]; + + fprintf(stderr,"init\n"); + + // check if wisdom file exists + getcwd(wisdom_directory, sizeof(wisdom_directory)); + strcpy(&wisdom_directory[strlen(wisdom_directory)],"/"); + strcpy(wisdom_file,wisdom_directory); + strcpy(&wisdom_file[strlen(wisdom_file)],"wdspWisdom"); + if(access(wisdom_file,F_OK)<0) { + WDSPwisdom (wisdom_directory); + } + + while(!start) { + new_discovery(); + if(devices==0) { + fprintf(stderr,"No devices found!\n"); + GtkDialogFlags flags = GTK_DIALOG_DESTROY_WITH_PARENT; + discovery_dialog = gtk_message_dialog_new (GTK_WINDOW(splash_window), + flags, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK_CANCEL, + "No devices found! Retry Discovery?"); + gint result=gtk_dialog_run (GTK_DIALOG (discovery_dialog)); + if(result==GTK_RESPONSE_CANCEL) { + _exit(0); + } + } else if(devices==1) { + selected_device=0; + start=1; + } else { + fprintf(stderr,"%s: found %d devices.\n", (char *)arg, devices); + GtkDialogFlags flags=GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT; + discovery_dialog = gtk_dialog_new_with_buttons ("Discovered", + GTK_WINDOW(splash_window), + flags, + "Discover", + GTK_RESPONSE_REJECT, + NULL); + + GtkWidget *content; + +// g_signal_connect_swapped(discovery_dialog,"response",G_CALLBACK(gtk_widget_destroy),discovery_dialog); + + content=gtk_dialog_get_content_area(GTK_DIALOG(discovery_dialog)); + + GtkWidget *grid=gtk_grid_new(); + gtk_grid_set_row_homogeneous(GTK_GRID(grid),TRUE); + gtk_grid_set_column_homogeneous(GTK_GRID(grid),TRUE); + + int i; + char text[128]; + for(i=0;iname, + inet_ntoa(d->address.sin_addr), + d->mac_address[0], + d->mac_address[1], + d->mac_address[2], + d->mac_address[3], + d->mac_address[4], + d->mac_address[5], + d->interface_name); + + GtkWidget *label=gtk_label_new(text); + gtk_widget_show(label); + gtk_grid_attach(GTK_GRID(grid),label,0,i,3,1); + + GtkWidget *start_button=gtk_button_new_with_label("Start"); + gtk_widget_show(start_button); + gtk_grid_attach(GTK_GRID(grid),start_button,3,i,1,1); + g_signal_connect(start_button,"pressed",G_CALLBACK(start_cb),(gpointer *)i); + + GtkWidget *configure_button=gtk_button_new_with_label("Configure"); + gtk_widget_show(configure_button); + gtk_grid_attach(GTK_GRID(grid),configure_button,4,i,1,1); + g_signal_connect(configure_button,"pressed",G_CALLBACK(configure_cb),(gpointer *)i); + } + + gtk_container_add (GTK_CONTAINER (content), grid); + gtk_widget_show_all(discovery_dialog); + gint result=gtk_dialog_run(GTK_DIALOG(discovery_dialog)); + } + } + + d=&discovered[selected_device]; + sprintf(property_path,"%02X-%02X-%02X-%02X-%02X-%02X.props", + d->mac_address[0], + d->mac_address[1], + d->mac_address[2], + d->mac_address[3], + d->mac_address[4], + d->mac_address[5]); + + loadProperties(property_path); + radioRestoreState(); + + samples=malloc(display_width*sizeof(float)); + + //selected_device=0; + setSampleRate(48000); + new_protocol_init(0,display_width); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (window), "pihpsdr"); + + //g_signal_connect (window, "destroy", G_CALLBACK (close_window), NULL); + + gtk_container_set_border_width (GTK_CONTAINER (window), 0); + + grid = gtk_grid_new(); + gtk_container_add(GTK_CONTAINER(window), grid); + + vfo = vfo_init(VFO_WIDTH,VFO_HEIGHT,window); + gtk_grid_attach(GTK_GRID(grid), vfo, 0, 0, 3, 1); + + meter = meter_init(METER_WIDTH,METER_HEIGHT); + gtk_grid_attach(GTK_GRID(grid), meter, 3, 0, 1, 1); + + panadapter = panadapter_init(display_width,PANADAPTER_HEIGHT); + gtk_grid_attach(GTK_GRID(grid), panadapter, 0, 1, 4, 1); + + waterfall = waterfall_init(display_width,WATERFALL_HEIGHT); + gtk_grid_attach(GTK_GRID(grid), waterfall, 0, 2, 4, 1); + + toolbar = toolbar_init(display_width,TOOLBAR_HEIGHT,window); + gtk_grid_attach(GTK_GRID(grid), toolbar, 0, 3, 4, 1); + + splash_close(); + + + gtk_widget_show_all (window); + + gtk_window_fullscreen(GTK_WINDOW(window)); + + GdkCursor *cursor=gdk_cursor_new(GDK_ARROW); + GdkWindow *gdk_window = gtk_widget_get_window(window); + gdk_window_set_cursor(gdk_window,cursor); + +/* + GdkDisplay *display=gdk_display_get_default(); + if(display==NULL) { + fprintf(stderr,"no default display!\n"); + _exit(0); + } + + GdkCursor *cursor=gdk_cursor_new_for_display(display,GDK_ARROW); +*/ + + update_timer_id=gdk_threads_add_timeout(1000/updates_per_second, update, NULL); + + // save every 30 seconds + save_timer_id=gdk_threads_add_timeout(30000, save_cb, NULL); + + vfo_update(NULL); + + return 0; +} + + +int +main (int argc, + char *argv[]) +{ + gtk_init (&argc, &argv); + + uname(&unameData); + fprintf(stderr,"sysname: %s\n",unameData.sysname); + fprintf(stderr,"nodename: %s\n",unameData.nodename); + fprintf(stderr,"release: %s\n",unameData.release); + fprintf(stderr,"version: %s\n",unameData.version); + fprintf(stderr,"machine: %s\n",unameData.machine); + + GdkScreen *screen=gdk_screen_get_default(); + if(screen==NULL) { + fprintf(stderr,"no default screen!\n"); + _exit(0); + } + + + //display_width=gdk_screen_get_width(screen); + //display_height=gdk_screen_get_height(screen); + display_width=800; + display_height=480; + + splash_show("splash.png", 0, display_width, display_height); + + g_idle_add(init,(void *)argv[0]); + + gtk_main(); + + return 0; +} diff --git a/main.h b/main.h new file mode 100644 index 0000000..1e1d955 --- /dev/null +++ b/main.h @@ -0,0 +1,2 @@ +#include +extern struct utsname unameData; diff --git a/meter.c b/meter.c new file mode 100644 index 0000000..2d77107 --- /dev/null +++ b/meter.c @@ -0,0 +1,182 @@ +#include +#include +#include +#include +#include + +#include "meter.h" + +static GtkWidget *meter; +static cairo_surface_t *meter_surface = NULL; + +static int meter_width; +static int meter_height; + +static void +meter_clear_surface (void) +{ + cairo_t *cr; + cr = cairo_create (meter_surface); + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + cairo_destroy (cr); +} + +meter_configure_event_cb (GtkWidget *widget, + GdkEventConfigure *event, + gpointer data) +{ + if (meter_surface) + cairo_surface_destroy (meter_surface); + + meter_surface = gdk_window_create_similar_surface (gtk_widget_get_window (widget), + CAIRO_CONTENT_COLOR, + gtk_widget_get_allocated_width (widget), + gtk_widget_get_allocated_height (widget)); + + /* Initialize the surface to black */ + meter_clear_surface (); + + return TRUE; +} + +/* Redraw the screen from the surface. Note that the ::draw + * signal receives a ready-to-be-used cairo_t that is already + * clipped to only draw the exposed areas of the widget + */ +static gboolean +meter_draw_cb (GtkWidget *widget, cairo_t *cr, gpointer data) { + cairo_set_source_surface (cr, meter_surface, 0, 0); + cairo_paint (cr); + + return FALSE; +} + +GtkWidget* meter_init(int width,int height) { + + meter_width=width; + meter_height=height; + + meter = gtk_drawing_area_new (); + gtk_widget_set_size_request (meter, width, height); + + /* Signals used to handle the backing surface */ + g_signal_connect (meter, "draw", + G_CALLBACK (meter_draw_cb), NULL); + g_signal_connect (meter,"configure-event", + G_CALLBACK (meter_configure_event_cb), NULL); + + + return meter; +} + + +void meter_update(int meter_type,double value,double reverse) { + + char sf[32]; + int text_location; + cairo_t *cr; + cr = cairo_create (meter_surface); + + // clear the meter + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + cairo_set_source_rgb(cr, 1, 1, 1); + switch(meter_type) { + case SMETER: + // value is dBm + text_location=10; + cairo_select_font_face(cr, "Arial", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_BOLD); + double level=value+(double)get_attenuation(); + if(meter_width>=114) { + int db=meter_width/114; // S9+60 (9*6)+60 + int i; + cairo_set_line_width(cr, 1.0); + cairo_set_source_rgb(cr, 1, 1, 1); + for(i=0;i<54;i++) { + cairo_move_to(cr,(double)(i*db),(double)meter_height-20); + if(i%18==0) { + cairo_line_to(cr,(double)(i*db),(double)(meter_height-30)); + } else if(i%6==0) { + cairo_line_to(cr,(double)(i*db),(double)(meter_height-25)); + } + } + cairo_stroke(cr); + + cairo_set_font_size(cr, 12); + cairo_move_to(cr, (double)(18*db)-3.0, (double)meter_height); + cairo_show_text(cr, "3"); + cairo_move_to(cr, (double)(36*db)-3.0, (double)meter_height); + cairo_show_text(cr, "6"); + + cairo_set_source_rgb(cr, 1, 0, 0); + cairo_move_to(cr,(double)(54*db),(double)meter_height-20); + cairo_line_to(cr,(double)(54*db),(double)(meter_height-30)); + cairo_move_to(cr,(double)(74*db),(double)meter_height-20); + cairo_line_to(cr,(double)(74*db),(double)(meter_height-30)); + cairo_move_to(cr,(double)(94*db),(double)meter_height-20); + cairo_line_to(cr,(double)(94*db),(double)(meter_height-30)); + cairo_move_to(cr,(double)(114*db),(double)meter_height-20); + cairo_line_to(cr,(double)(114*db),(double)(meter_height-30)); + cairo_stroke(cr); + + cairo_move_to(cr, (double)(54*db)-3.0, (double)meter_height); + cairo_show_text(cr, "9"); + cairo_move_to(cr, (double)(74*db)-12.0, (double)meter_height); + cairo_show_text(cr, "+20"); + cairo_move_to(cr, (double)(94*db)-9.0, (double)meter_height); + cairo_show_text(cr, "+40"); + cairo_move_to(cr, (double)(114*db)-6.0, (double)meter_height); + cairo_show_text(cr, "+60"); + + cairo_set_source_rgb(cr, 0, 1, 0); + cairo_move_to(cr,(double)((level+127.0)*db),(double)meter_height-30); + cairo_line_to(cr,(double)((level+127.0)*db),(double)(meter_height-50)); + cairo_stroke(cr); + + text_location=(db*114)+5; + } + + cairo_set_font_size(cr, 16); + sprintf(sf,"%d dBm",(int)level); + cairo_move_to(cr, text_location, 45); + cairo_show_text(cr, sf); + break; + case POWER: + // value is Watts + cairo_select_font_face(cr, "Arial", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_BOLD); + cairo_set_font_size(cr, 18); + + sprintf(sf,"FWD: %3.2f W",value); + cairo_move_to(cr, 10, 25); + cairo_show_text(cr, sf); + + // value is Watts + double swr=(value+reverse)/(value-reverse); + cairo_select_font_face(cr, "Arial", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_BOLD); + cairo_set_font_size(cr, 18); + + sprintf(sf,"SWR: %1.2f:1",swr); + cairo_move_to(cr, 10, 45); + cairo_show_text(cr, sf); + +/* + sprintf(sf,"REV: %3.2f W",reverse); + cairo_move_to(cr, 10, 45); + cairo_show_text(cr, sf); +*/ + break; + } + + cairo_destroy(cr); + gtk_widget_queue_draw (meter); +} diff --git a/meter.h b/meter.h new file mode 100644 index 0000000..ad197d3 --- /dev/null +++ b/meter.h @@ -0,0 +1,6 @@ +#define SMETER 0 +#define POWER 1 + + +GtkWidget* meter_init(int width,int height); +void meter_update(int meter_type,double value,double reverse); diff --git a/mode.c b/mode.c new file mode 100644 index 0000000..98fdfa5 --- /dev/null +++ b/mode.c @@ -0,0 +1,2 @@ +char *mode_string[]={"LSB","USB","DSB","CWL","CWU","FMN","AM","DIGU","SPEC","DIGL","SAM","DRM"}; + diff --git a/mode.h b/mode.h new file mode 100644 index 0000000..a4766a0 --- /dev/null +++ b/mode.h @@ -0,0 +1,55 @@ +/** +* @file mode.h +* @brief Header files for the mode functions +* @author John Melton, G0ORX/N6LYT, Doxygen Comments Dave Larsen, KV0S +* @version 0.1 +* @date 2009-04-12 +*/ +// mode.h + +/* Copyright (C) +* 2009 - John Melton, G0ORX/N6LYT, Doxygen Comments Dave Larsen, KV0S +* 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. +* +*/ + +#define modeLSB 0 +#define modeUSB 1 +#define modeDSB 2 +#define modeCWL 3 +#define modeCWU 4 +#define modeFMN 5 +#define modeAM 6 +#define modeDIGU 7 +#define modeSPEC 8 +#define modeDIGL 9 +#define modeSAM 10 +#define modeDRM 11 + +#define MODES 12 + +int mode; + +char *mode_string[MODES]; + +/* +int updateMode(void * data); + +void setMode(int mode); +void modeSaveState(); +void modeRestoreState(); +GtkWidget* buildModeUI(); +char* modeToString(); +*/ diff --git a/new_discovery.c b/new_discovery.c new file mode 100644 index 0000000..fe4a05a --- /dev/null +++ b/new_discovery.c @@ -0,0 +1,250 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "discovered.h" +//#include "discovery.h" + +int selected_device=0; +int devices=0; +DISCOVERED discovered[MAX_DEVICES]; + +static char interface_name[64]; +static struct sockaddr_in interface_addr={0}; +static int interface_length; + +#define DISCOVERY_PORT 1024 +static int discovery_socket; +static struct sockaddr_in discovery_addr; + +void new_discover(struct ifaddrs* iface); + +static pthread_t discover_thread_id; +void* new_discover_receive_thread(void* arg); + +void print_device(int i) { + fprintf(stderr,"discovery: found protocol=%d device=%d software_version=%d status=%d address=%s (%02X:%02X:%02X:%02X:%02X:%02X) on %s\n", + discovered[i].protocol, + discovered[i].device, + discovered[i].software_version, + discovered[i].status, + inet_ntoa(discovered[i].address.sin_addr), + discovered[i].mac_address[0], + discovered[i].mac_address[1], + discovered[i].mac_address[2], + discovered[i].mac_address[3], + discovered[i].mac_address[4], + discovered[i].mac_address[5], + discovered[i].interface_name); +} + +void new_discovery() { + devices=0; + selected_device=0; + struct ifaddrs *addrs,*ifa; + getifaddrs(&addrs); + ifa = addrs; + while (ifa) { + if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET) { + if((ifa->ifa_flags&IFF_UP)==IFF_UP + && (ifa->ifa_flags&IFF_RUNNING)==IFF_RUNNING + && (ifa->ifa_flags&IFF_LOOPBACK)!=IFF_LOOPBACK) { + new_discover(ifa); + } + } + ifa = ifa->ifa_next; + } + freeifaddrs(addrs); + + + fprintf(stderr, "new_discovery found %d devices\n",devices); + + int i; + for(i=0;iifa_name); + fprintf(stderr,"new_discover: looking for HPSDR devices on %s\n",interface_name); + + // send a broadcast to locate metis boards on the network + discovery_socket=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP); + if(discovery_socket<0) { + perror("new_discover: create socket failed for discovery_socket\n"); + exit(-1); + } + + int optval = 1; + setsockopt(discovery_socket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); + + sa = (struct sockaddr_in *) iface->ifa_addr; + //addr = inet_ntoa(sa->sin_addr); + + // bind to this interface and the discovery port + interface_addr.sin_family = AF_INET; + interface_addr.sin_addr.s_addr = sa->sin_addr.s_addr; + interface_addr.sin_port = htons(DISCOVERY_PORT); + if(bind(discovery_socket,(struct sockaddr*)&interface_addr,sizeof(interface_addr))<0) { + perror("new_discover: bind socket failed for discovery_socket\n"); + exit(-1); + } + + fprintf(stderr,"new_discover: bound to %s\n",interface_name); + + // allow broadcast on the socket + int on=1; + rc=setsockopt(discovery_socket, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)); + if(rc != 0) { + fprintf(stderr,"new_discover: cannot set SO_BROADCAST: rc=%d\n", rc); + exit(-1); + } + + // setup to address + struct sockaddr_in to_addr={0}; + to_addr.sin_family=AF_INET; + to_addr.sin_port=htons(DISCOVERY_PORT); + to_addr.sin_addr.s_addr=htonl(INADDR_BROADCAST); + + // start a receive thread to collect discovery response packets + rc=pthread_create(&discover_thread_id,NULL,new_discover_receive_thread,NULL); + if(rc != 0) { + fprintf(stderr,"pthread_create failed on new_discover_receive_thread: rc=%d\n", rc); + exit(-1); + } + + + // send discovery packet + unsigned char buffer[60]; + buffer[0]=0x00; + buffer[1]=0x00; + buffer[2]=0x00; + buffer[3]=0x00; + buffer[4]=0x02; + int i; + for(i=5;i<60;i++) { + buffer[i]=0x00; + } + + if(sendto(discovery_socket,buffer,60,0,(struct sockaddr*)&to_addr,sizeof(to_addr))<0) { + perror("new_discover: sendto socket failed for discovery_socket\n"); + exit(-1); + } + + // wait for receive thread to complete + void* status; + pthread_join(discover_thread_id,&status); + + close(discovery_socket); + + fprintf(stderr,"new_discover: exiting discover for %s\n",iface->ifa_name); +} + +void* new_discover_receive_thread(void* arg) { + struct sockaddr_in addr; + int len; + unsigned char buffer[2048]; + int bytes_read; + struct timeval tv; + int i; + + tv.tv_sec = 1; + tv.tv_usec = 0; + + setsockopt(discovery_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,sizeof(struct timeval)); + + len=sizeof(addr); + while(1) { + bytes_read=recvfrom(discovery_socket,buffer,sizeof(buffer),0,(struct sockaddr*)&addr,&len); + if(bytes_read<0) { + fprintf(stderr,"new_discover: bytes read %d\n", bytes_read); + perror("new_discover: recvfrom socket failed for discover_receive_thread"); + break; + } + fprintf(stderr,"new_discover: received %d bytes\n",bytes_read); + if(bytes_read==1444) { + if(devices>0) { + break; + } + } else { + if(buffer[0]==0 && buffer[1]==0 && buffer[2]==0 && buffer[3]==0) { + int status = buffer[4] & 0xFF; + if (status == 2 || status == 3) { + if(devices + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "alex.h" +#include "new_protocol.h" +#include "channel.h" +#include "discovered.h" +#include "wdsp.h" +#include "radio.h" +#include "vfo.h" +#include "toolbar.h" + +#define PI 3.1415926535897932F + +static int receiver; +static int running=0; + +int data_socket; + +static struct sockaddr_in base_addr; +static int base_addr_length; + +static struct sockaddr_in receiver_addr; +static int receiver_addr_length; + +static struct sockaddr_in transmitter_addr; +static int transmitter_addr_length; + +static struct sockaddr_in high_priority_addr; +static int high_priority_addr_length; + +static struct sockaddr_in audio_addr; +static int audio_addr_length; + +static struct sockaddr_in iq_addr; +static int iq_addr_length; + +static struct sockaddr_in data_addr; +static int data_addr_length; + +static pthread_t new_protocol_thread_id; +static pthread_t new_protocol_timer_thread_id; + +sem_t response_sem; + +static long rx_sequence = 0; + +static long high_priority_sequence = 0; +static long general_sequence = 0; +static long rx_specific_sequence = 0; +static long tx_specific_sequence = 0; + +static int lt2208Dither = 0; +static int lt2208Random = 0; +static int attenuation = 20; // 20dB + +static long long ddsAFrequency = 14250000; +static int filterLow=150; +static int filterHigh=2550; +static int mode=modeUSB; +static unsigned long alex_rx_antenna=0; +static unsigned long alex_tx_antenna=0; +static unsigned long alex_attenuation=0; + +static int buffer_size=BUFFER_SIZE; +static int fft_size=4096; +static int sampleRate=48000; +static int dspRate=48000; +static int outputRate=48000; + +static int micSampleRate=48000; +static int micDspRate=48000; +static int micOutputRate=192000; + +static int spectrumWIDTH=800; +static int SPECTRUM_UPDATES_PER_SECOND=10; + +static int mox=0; +static int tune=0; +static float phase = 0.0F; + +static int ptt; +static int dot; +static int dash; +static int pll_locked; +static int adc_overload; +unsigned int exciter_power; +unsigned int alex_forward_power; +unsigned int alex_reverse_power; +static int supply_volts; + +long response_sequence; +int response; + +int send_high_priority=0; +int send_general=0; + +static void initAnalyzer(int channel,int buffer_size); +static void* new_protocol_thread(void* arg); +static void* new_protocol_timer_thread(void* arg); + +void filter_board_changed() { + send_general=1; +} + +void pa_changed() { + send_general=1; +} + +void tuner_changed() { + send_general=1; +} + +void cw_changed() { +} + +void set_attenuation(int value) { + attenuation=value; +} + +int get_attenuation() { + return attenuation; +} + +void set_alex_rx_antenna(unsigned long v) { + alex_rx_antenna=v; + send_high_priority=1; +} + +void set_alex_tx_antenna(unsigned long v) { + alex_tx_antenna=v; + send_high_priority=1; +} + +void set_alex_attenuation(unsigned long v) { + alex_attenuation=v; + send_high_priority=1; +} + +void setSampleRate(int rate) { + sampleRate=rate; +} + +int getSampleRate() { + return sampleRate; +} + +void setFrequency(long long f) { + ddsAFrequency=f; + send_high_priority=1; +} + +long long getFrequency() { + return ddsAFrequency; +} + +void setMode(int m) { + mode=m; + SetRXAMode(receiver, mode); + SetTXAMode(CHANNEL_TX, mode); +} + +int getMode() { + return mode; +} + +void setFilter(int low,int high) { + if(mode==modeCWL) { + filterLow=-cwPitch-low; + filterHigh=-cwPitch+high; + } else if(mode==modeCWU) { + filterLow=cwPitch-low; + filterHigh=cwPitch+high; + } else { + filterLow=low; + filterHigh=high; + } + + RXANBPSetFreqs(receiver,(double)filterLow,(double)filterHigh); + SetRXABandpassFreqs(receiver, (double)filterLow, (double)filterHigh); + SetRXASNBAOutputBandwidth(receiver, (double)filterLow, (double)filterHigh); + + SetTXABandpassFreqs(CHANNEL_TX, (double)filterLow, (double)filterHigh); +} + +int getFilterLow() { + return filterLow; +} + +int getFilterHigh() { + return filterHigh; +} + +void setMox(int state) { + if(mox!=state) { + mox=state; + send_high_priority=1; + } +} + +int getMox() { + return mox; +} + +void setTune(int state) { + if(tune!=state) { + tune=state; + send_high_priority=1; + send_general=1; + } +} + +int getTune() { + return tune; +} + +int isTransmitting() { + return ptt!=0 || mox!=0 || tune!=0; +} + +double getDrive() { + return (double)drive/255.0; +} + +void setDrive(double value) { + drive=(int)(value*255.0); + send_high_priority=1; +} + +double getTuneDrive() { + return (double)tune_drive/255.0; +} + +void setTuneDrive(double value) { + tune_drive=(int)(value*255.0); + send_high_priority=1; +} + +void new_protocol_init(int rx,int pixels) { + int rc; + receiver=rx; + spectrumWIDTH=pixels; + + fprintf(stderr,"new_protocol_init: %d\n",rx); + + rc=sem_init(&response_sem, 0, 0); + + fprintf(stderr,"OpenChannel %d buffer_size=%d fft_size=%d sampleRate=%d dspRate=%d outputRate=%d\n", + rx, + buffer_size, + fft_size, + sampleRate, + dspRate, + outputRate); + + OpenChannel(rx, + buffer_size, + fft_size, + sampleRate, + dspRate, + outputRate, + 0, // receive + 1, // run + 0.010, 0.025, 0.0, 0.010, 0); + + fprintf(stderr,"OpenChannel %d buffer_size=%d fft_size=%d sampleRate=%d dspRate=%d outputRate=%d\n", + CHANNEL_TX, + buffer_size, + fft_size, + micSampleRate, + micDspRate, + micOutputRate); + + OpenChannel(CHANNEL_TX, + buffer_size, + fft_size, + micSampleRate, + micDspRate, + micOutputRate, + 1, // transmit + 1, // run + 0.010, 0.025, 0.0, 0.010, 0); + + fprintf(stderr,"XCreateAnalyzer %d\n",rx); + int success; + XCreateAnalyzer(rx, &success, 262144, 1, 1, ""); + if (success != 0) { + fprintf(stderr, "XCreateAnalyzer %d failed: %d\n" ,rx,success); + } + initAnalyzer(rx,buffer_size); + + XCreateAnalyzer(CHANNEL_TX, &success, 262144, 1, 1, ""); + if (success != 0) { + fprintf(stderr, "XCreateAnalyzer CHANNEL_TX failed: %d\n" ,success); + } + initAnalyzer(CHANNEL_TX,BUFFER_SIZE); + + rc=pthread_create(&new_protocol_thread_id,NULL,new_protocol_thread,NULL); + if(rc != 0) { + fprintf(stderr,"pthread_create failed on new_protocol_thread for receiver %d: rc=%d\n", receiver, rc); + exit(-1); + } + + SetRXAMode(rx, mode); + SetRXABandpassFreqs(rx, (double)filterLow, (double)filterHigh); + SetRXAAGCMode(rx, agc); + SetRXAAGCTop(rx,agc_gain); + + SetRXAAMDSBMode(CHANNEL_RX0, 0); + SetRXAShiftRun(CHANNEL_RX0, 0); + SetRXAEMNRgainMethod(CHANNEL_RX0, 1); + SetRXAEMNRnpeMethod(CHANNEL_RX0, 0); + SetRXAEMNRaeRun(CHANNEL_RX0, 1); + SetRXAEMNRPosition(CHANNEL_RX0, 0); + SetRXAEMNRRun(CHANNEL_RX0, 0); + SetRXAANRRun(CHANNEL_RX0, 0); + SetRXAANFRun(CHANNEL_RX0, 0); + + SetTXAMode(CHANNEL_TX, mode); + SetTXABandpassFreqs(CHANNEL_TX, (double)filterLow, (double)filterHigh); + SetTXABandpassWindow(CHANNEL_TX, 1); + SetTXABandpassRun(CHANNEL_TX, 1); + + SetTXACFIRRun(CHANNEL_TX, 1); + SetTXAEQRun(CHANNEL_TX, 0); + SetTXACTCSSRun(CHANNEL_TX, 0); + SetTXAAMSQRun(CHANNEL_TX, 0); + SetTXACompressorRun(CHANNEL_TX, 0); + SetTXAosctrlRun(CHANNEL_TX, 0); + SetTXAPreGenRun(CHANNEL_TX, 0); + SetTXAPostGenRun(CHANNEL_TX, 0); + +} + +static void initAnalyzer(int channel,int buffer_size) { + int flp[] = {0}; + double KEEP_TIME = 0.1; + int spur_elimination_ffts = 1; + int data_type = 1; + int fft_size = 8192; + int window_type = 4; + double kaiser_pi = 14.0; + int overlap = 2048; + int clip = 0; + int span_clip_l = 0; + int span_clip_h = 0; + int pixels=spectrumWIDTH; + int stitches = 1; + int avm = 0; + double tau = 0.001 * 120.0; + int MAX_AV_FRAMES = 60; + int display_average = MAX(2, (int) MIN((double) MAX_AV_FRAMES, (double) SPECTRUM_UPDATES_PER_SECOND * tau)); + double avb = exp(-1.0 / (SPECTRUM_UPDATES_PER_SECOND * tau)); + int calibration_data_set = 0; + double span_min_freq = 0.0; + double span_max_freq = 0.0; + + int max_w = fft_size + (int) MIN(KEEP_TIME * (double) SPECTRUM_UPDATES_PER_SECOND, KEEP_TIME * (double) fft_size * (double) SPECTRUM_UPDATES_PER_SECOND); + + fprintf(stderr,"SetAnalyzer channel=%d\n",channel); + SetAnalyzer(channel, + spur_elimination_ffts, //number of LO frequencies = number of ffts used in elimination + data_type, //0 for real input data (I only); 1 for complex input data (I & Q) + flp, //vector with one elt for each LO frequency, 1 if high-side LO, 0 otherwise + fft_size, //size of the fft, i.e., number of input samples + buffer_size, //number of samples transferred for each OpenBuffer()/CloseBuffer() + window_type, //integer specifying which window function to use + kaiser_pi, //PiAlpha parameter for Kaiser window + overlap, //number of samples each fft (other than the first) is to re-use from the previous + clip, //number of fft output bins to be clipped from EACH side of each sub-span + span_clip_l, //number of bins to clip from low end of entire span + span_clip_h, //number of bins to clip from high end of entire span + pixels, //number of pixel values to return. may be either <= or > number of bins + stitches, //number of sub-spans to concatenate to form a complete span + avm, //averaging mode + display_average, //number of spans to (moving) average for pixel result + avb, //back multiplier for weighted averaging + calibration_data_set, //identifier of which set of calibration data to use + span_min_freq, //frequency at first pixel value8192 + span_max_freq, //frequency at last pixel value + max_w //max samples to hold in input ring buffers + ); +} + + +static void new_protocol_general() { + unsigned char buffer[60]; + +fprintf(stderr,"new_protocol_general: receiver=%d\n", receiver); + + memset(buffer, 0, sizeof(buffer)); + + buffer[0]=general_sequence>>24; + buffer[1]=general_sequence>>16; + buffer[2]=general_sequence>>8; + buffer[3]=general_sequence; + + // use defaults apart from + buffer[37]=0x08; // phase word (not frequency) + buffer[58]=pa; // enable PA 0x01 + if((filter_board==APOLLO) && tune && apollo_tuner) { + buffer[58]|=0x02; + } + + if(filter_board==ALEX) { + buffer[59]=0x01; // enable Alex 0 + } + + if(sendto(data_socket,buffer,sizeof(buffer),0,(struct sockaddr*)&base_addr,base_addr_length)<0) { + fprintf(stderr,"sendto socket failed for general\n"); + exit(1); + } + + general_sequence++; +} + +static void new_protocol_high_priority(int run,int tx,int drive) { + unsigned char buffer[1444]; + +//fprintf(stderr,"new_protocol_high_priority: run=%d tx=%d drive=%d tx_ant=0x%08x rx_ant=0x%08x\n", run, tx, drive, alex_tx_antenna, alex_rx_antenna); + memset(buffer, 0, sizeof(buffer)); + + buffer[0]=high_priority_sequence>>24; + buffer[1]=high_priority_sequence>>16; + buffer[2]=high_priority_sequence>>8; + buffer[3]=high_priority_sequence; + + buffer[4]=run|(tx<<1); + + extern long long ddsAFrequency; + + long phase=(long)((4294967296.0*(double)ddsAFrequency)/122880000.0); + +// rx + buffer[9]=phase>>24; + buffer[10]=phase>>16; + buffer[11]=phase>>8; + buffer[12]=phase; + +// tx + buffer[329]=phase>>24; + buffer[330]=phase>>16; + buffer[331]=phase>>8; + buffer[332]=phase; + + + buffer[345]=drive; + +// alex HPF filters +/* +if (frequency < 1800000) HPF <= 6'b100000; // bypass +else if (frequency < 6500000) HPF <= 6'b010000; // 1.5MHz HPF +else if (frequency < 9500000) HPF <= 6'b001000; // 6.5MHz HPF +else if (frequency < 13000000) HPF <= 6'b000100; // 9.5MHz HPF +else if (frequency < 20000000) HPF <= 6'b000001; // 13MHz HPF +else HPF <= 6'b000010; // 20MHz HPF +*/ + + long filters=0x00000000; +// set HPF + if(ddsAFrequency<1800000L) { + filters|=ALEX_BYPASS_HPF; + } else if(ddsAFrequency<6500000L) { + filters|=ALEX_1_5MHZ_HPF; + } else if(ddsAFrequency<9500000L) { + filters|=ALEX_6_5MHZ_HPF; + } else if(ddsAFrequency<13000000L) { + filters|=ALEX_9_5MHZ_HPF; + } else if(ddsAFrequency<20000000L) { + filters|=ALEX_13MHZ_HPF; + } else { + filters|=ALEX_20MHZ_HPF; + } +// alex LPF filters +/* +if (frequency > 32000000) LPF <= 7'b0010000; // > 10m so use 6m LPF^M +else if (frequency > 22000000) LPF <= 7'b0100000; // > 15m so use 12/10m LPF^M +else if (frequency > 15000000) LPF <= 7'b1000000; // > 20m so use 17/15m LPF^M +else if (frequency > 8000000) LPF <= 7'b0000001; // > 40m so use 30/20m LPF ^M +else if (frequency > 4500000) LPF <= 7'b0000010; // > 80m so use 60/40m LPF^M +else if (frequency > 2400000) LPF <= 7'b0000100; // > 160m so use 80m LPF ^M +else LPF <= 7'b0001000; // < 2.4MHz so use 160m LPF^M +*/ + + if(ddsAFrequency>32000000) { + filters|=ALEX_6_BYPASS_LPF; + } else if(ddsAFrequency>22000000) { + filters|=ALEX_12_10_LPF; + } else if(ddsAFrequency>15000000) { + filters|=ALEX_17_15_LPF; + } else if(ddsAFrequency>8000000) { + filters|=ALEX_30_20_LPF; + } else if(ddsAFrequency>4500000) { + filters|=ALEX_60_40_LPF; + } else if(ddsAFrequency>2400000) { + filters|=ALEX_80_LPF; + } else { + filters|=ALEX_160_LPF; + } + + filters|=alex_rx_antenna; + filters|=alex_tx_antenna; + filters|=alex_attenuation; + + if(tx) { + filters|=0x08000000; + } + +/* + buffer[1420]=filters>>24; + buffer[1421]=filters>>16; + buffer[1422]=filters>>8; + buffer[1423]=filters; +*/ + + buffer[1432]=filters>>24; + buffer[1433]=filters>>16; + buffer[1434]=filters>>8; + buffer[1435]=filters; + + //buffer[1442]=attenuation; + buffer[1443]=attenuation; + +//fprintf(stderr,"[4]=%02X\n", buffer[4]); +//fprintf(stderr,"filters=%04X\n", filters); + + if(sendto(data_socket,buffer,sizeof(buffer),0,(struct sockaddr*)&high_priority_addr,high_priority_addr_length)<0) { + fprintf(stderr,"sendto socket failed for high priority\n"); + exit(1); + } + + high_priority_sequence++; +} + +static void new_protocol_transmit_specific() { + unsigned char buffer[60]; + + memset(buffer, 0, sizeof(buffer)); + + buffer[0]=tx_specific_sequence>>24; + buffer[1]=tx_specific_sequence>>16; + buffer[2]=tx_specific_sequence>>8; + buffer[3]=tx_specific_sequence; + + buffer[4]=1; // 1 DAC + buffer[5]=0; // no CW + if(cw_keyer_internal) { + buffer[5]|=0x02; + } + if(cw_keys_reversed) { + buffer[5]|=0x04; + } + if(cw_keyer_mode==KEYER_MODE_A) { + buffer[5]|=0x08; + } + if(cw_keyer_mode==KEYER_MODE_B) { + buffer[5]|=0x28; + } + if(cw_keyer_spacing) { + buffer[5]|=0x40; + } + if(cw_breakin) { + buffer[5]|=0x80; + } + + buffer[6]=cw_keyer_sidetone_volume; // sidetone off + buffer[7]=cw_keyer_sidetone_frequency>>8; buffer[8]=cw_keyer_sidetone_frequency; // sidetone frequency + buffer[9]=cw_keyer_speed; // cw keyer speed + buffer[10]=cw_keyer_weight; // cw weight + buffer[11]=cw_keyer_hang_time>>8; buffer[12]=cw_keyer_hang_time; // cw hang delay + buffer[13]=0; // rf delay + buffer[50]=orion_mic; + buffer[51]=0x7F; // Line in gain + + if(sendto(data_socket,buffer,sizeof(buffer),0,(struct sockaddr*)&transmitter_addr,transmitter_addr_length)<0) { + fprintf(stderr,"sendto socket failed for tx specific\n"); + exit(1); + } + + tx_specific_sequence++; + +} + +static void new_protocol_receive_specific() { + unsigned char buffer[1444]; + int i; + + memset(buffer, 0, sizeof(buffer)); + + buffer[0]=rx_specific_sequence>>24; + buffer[1]=rx_specific_sequence>>16; + buffer[2]=rx_specific_sequence>>8; + buffer[3]=rx_specific_sequence; + + buffer[4]=2; // 2 ADCs + buffer[5]=0; // dither off + if(lt2208Dither) { + buffer[5]=0x01<>8)&0xFF; + buffer[19]=(sampleRate/1000)&0xFF; + buffer[22]=24; + + buffer[24]=((sampleRate/1000)>>8)&0xFF; + buffer[25]=(sampleRate/1000)&0xFF; + buffer[28]=24; + + if(sendto(data_socket,buffer,sizeof(buffer),0,(struct sockaddr*)&receiver_addr,receiver_addr_length)<0) { + fprintf(stderr,"sendto socket failed for start: receiver=%d\n",receiver); + exit(1); + } + + rx_specific_sequence++; +} + +static void new_protocol_start() { + running=1; + new_protocol_transmit_specific(); + new_protocol_receive_specific(); + int rc=pthread_create(&new_protocol_timer_thread_id,NULL,new_protocol_timer_thread,NULL); + if(rc != 0) { + fprintf(stderr,"pthread_create failed on new_protocol_timer_thread: %d\n", rc); + exit(-1); + } +} + +void new_protocol_stop() { + new_protocol_high_priority(0,0,0); + running=0; + sleep(1); +} + +/* +float sineWave(float* buf, int samples, float phase, float freq) { + float phase_step = 2 * PI * freq / 192000.0F; + int i; + for (i = 0; i < samples; i++) { + buf[i] = (float) sin(phase); + phase += phase_step; + } + return phase; +} +*/ +float sineWave(double* buf, int samples, float phase, float freq) { + float phase_step = 2 * PI * freq / 192000.0F; + int i; + for (i = 0; i < samples; i++) { + buf[i*2] = (double) sin(phase); + phase += phase_step; + } + return phase; +} + +double calibrate(int v) { + // Angelia + double v1; + v1=(double)v/4095.0*3.3; + + return (v1*v1)/0.095; +} + +void* new_protocol_thread(void* arg) { + + DISCOVERED* d=&discovered[selected_device]; + + struct sockaddr_in addr; + int length; + unsigned char buffer[2048]; + int bytesread; + short sourceport; + + long sequence; + long long timestamp; + int bitspersample; + int samplesperframe; + + int b; + int leftsample; + int rightsample; + float leftsamplefloat; + float rightsamplefloat; + + int previous_ptt; + int previous_dot; + int previous_dash; + + int samples; + //float leftinputbuffer[BUFFER_SIZE]; + //float rightinputbuffer[BUFFER_SIZE]; + double iqinputbuffer[BUFFER_SIZE*2]; + + int outputsamples; + //float leftoutputbuffer[BUFFER_SIZE]; + //float rightoutputbuffer[BUFFER_SIZE]; + double audiooutputbuffer[BUFFER_SIZE*2]; + + short leftaudiosample; + short rightaudiosample; + long audiosequence; + unsigned char audiobuffer[1444]; + int audioindex; + + int micsample; + float micsamplefloat; + + int micsamples; +/* + float micleftinputbuffer[BUFFER_SIZE]; // 48000 + float micrightinputbuffer[BUFFER_SIZE]; +*/ + double micinputbuffer[BUFFER_SIZE*2]; + + int micoutputsamples; +/* + float micleftoutputbuffer[BUFFER_SIZE*4]; // 192000 + float micrightoutputbuffer[BUFFER_SIZE*4]; +*/ + double micoutputbuffer[BUFFER_SIZE*4*2]; + + int isample; + int qsample; + long tx_iq_sequence; + unsigned char iqbuffer[1444]; + int iqindex; + + int i, j; +fprintf(stderr,"new_protocol_thread: receiver=%d\n", receiver); + + micsamples=0; + iqindex=4; + + switch(sampleRate) { + case 48000: + outputsamples=BUFFER_SIZE; + break; + case 96000: + outputsamples=BUFFER_SIZE/2; + break; + case 192000: + outputsamples=BUFFER_SIZE/4; + break; + case 384000: + outputsamples=BUFFER_SIZE/8; + break; + } + + micoutputsamples=BUFFER_SIZE*4; // 48000 in, 192000 out + +fprintf(stderr,"outputsamples=%d\n", outputsamples); + data_socket=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP); + if(data_socket<0) { + fprintf(stderr,"metis: create socket failed for data_socket: receiver=%d\n",receiver); + exit(-1); + } + + int optval = 1; + setsockopt(data_socket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); + + // bind to the interface + if(bind(data_socket,(struct sockaddr*)&d->interface_address,d->interface_length)<0) { + fprintf(stderr,"metis: bind socket failed for data_socket: receiver=%d\n",receiver); + exit(-1); + } + + memcpy(&base_addr,&d->address,d->address_length); + base_addr_length=d->address_length; + base_addr.sin_port=htons(GENERAL_REGISTERS_FROM_HOST_PORT); + + memcpy(&receiver_addr,&d->address,d->address_length); + receiver_addr_length=d->address_length; + receiver_addr.sin_port=htons(RECEIVER_SPECIFIC_REGISTERS_FROM_HOST_PORT); + + memcpy(&transmitter_addr,&d->address,d->address_length); + transmitter_addr_length=d->address_length; + transmitter_addr.sin_port=htons(TRANSMITTER_SPECIFIC_REGISTERS_FROM_HOST_PORT); + + memcpy(&high_priority_addr,&d->address,d->address_length); + high_priority_addr_length=d->address_length; + high_priority_addr.sin_port=htons(HIGH_PRIORITY_FROM_HOST_PORT); + + memcpy(&audio_addr,&d->address,d->address_length); + audio_addr_length=d->address_length; + audio_addr.sin_port=htons(AUDIO_FROM_HOST_PORT); + + memcpy(&iq_addr,&d->address,d->address_length); + iq_addr_length=d->address_length; + iq_addr.sin_port=htons(TX_IQ_FROM_HOST_PORT); + + memcpy(&data_addr,&d->address,d->address_length); + data_addr_length=d->address_length; + data_addr.sin_port=htons(RX_IQ_TO_HOST_PORT+receiver); + + samples=0; + audioindex=4; // leave space for sequence + audiosequence=0L; + + new_protocol_general(); + new_protocol_start(); + new_protocol_high_priority(1,0,drive); + + while(running) { + bytesread=recvfrom(data_socket,buffer,sizeof(buffer),0,(struct sockaddr*)&addr,&length); + if(bytesread<0) { + fprintf(stderr,"recvfrom socket failed for new_protocol_thread: receiver=%d", receiver); + exit(1); + } + + short sourceport=ntohs(addr.sin_port); + +//fprintf(stderr,"received packet length %d from port %d\n",bytesread,sourceport); + + if(sourceport==RX_IQ_TO_HOST_PORT) { + + sequence=((buffer[0]&0xFF)<<24)+((buffer[1]&0xFF)<<16)+((buffer[2]&0xFF)<<8)+(buffer[3]&0xFF); + 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); + +//fprintf(stderr,"samples per frame %d\n",samplesperframe); + + //if(!isTransmitting()) { + b=16; + for(i=0;i>8; + audiobuffer[audioindex++]=leftaudiosample; + audiobuffer[audioindex++]=rightaudiosample>>8; + audiobuffer[audioindex++]=rightaudiosample; + + if(audioindex>=sizeof(audiobuffer)) { + // insert the sequence + audiobuffer[0]=audiosequence>>24; + audiobuffer[1]=audiosequence>>16; + audiobuffer[2]=audiosequence>>8; + audiobuffer[3]=audiosequence; + // send the buffer + if(sendto(data_socket,audiobuffer,sizeof(audiobuffer),0,(struct sockaddr*)&audio_addr,audio_addr_length)<0) { + fprintf(stderr,"sendto socket failed for audio\n"); + exit(1); + } + audioindex=4; + audiosequence++; + } + } + samples=0; + } + } + //} + + } else if(sourceport==COMMAND_RESPONCE_TO_HOST_PORT) { + // command/response + response_sequence=((buffer[0]&0xFF)<<24)+((buffer[1]&0xFF)<<16)+((buffer[2]&0xFF)<<8)+(buffer[3]&0xFF); + response=buffer[4]&0xFF; + fprintf(stderr,"response_sequence=%ld response=%d\n",response_sequence,response); + sem_post(&response_sem); + + } else if(sourceport==HIGH_PRIORITY_TO_HOST_PORT) { + // high priority + sequence=((buffer[0]&0xFF)<<24)+((buffer[1]&0xFF)<<16)+((buffer[2]&0xFF)<<8)+(buffer[3]&0xFF); + + previous_ptt=ptt; + previous_dot=dot; + previous_dash=dash; + + ptt=buffer[4]&0x01; + dot=(buffer[4]>>1)&0x01; + dash=(buffer[4]>>2)&0x01; + pll_locked=(buffer[4]>>3)&0x01; + adc_overload=buffer[5]&0x01; + exciter_power=((buffer[6]&0xFF)<<8)|(buffer[7]&0xFF); + alex_forward_power=((buffer[14]&0xFF)<<8)|(buffer[15]&0xFF); + alex_reverse_power=((buffer[22]&0xFF)<<8)|(buffer[23]&0xFF); + supply_volts=((buffer[49]&0xFF)<<8)|(buffer[50]&0xFF); + + if(previous_ptt!=ptt) { + //send_high_priority=1; + previous_ptt=ptt; + g_idle_add(ptt_update,(gpointer)ptt); + } + + } else if(sourceport==MIC_LINE_TO_HOST_PORT) { + // Mic/Line data + sequence=((buffer[0]&0xFF)<<24)+((buffer[1]&0xFF)<<16)+((buffer[2]&0xFF)<<8)+(buffer[3]&0xFF); + if(isTransmitting()) { + b=4; + + for(i=0;i<720;i++) { + if(byte_swap) { + micsample = (int)((unsigned char)buffer[b++] & 0xFF); + micsample |= (int)((signed char) buffer[b++]) << 8; + } else { + micsample = (int)((signed char) buffer[b++]) << 8; + micsample |= (int)((unsigned char)buffer[b++] & 0xFF); + } + micsamplefloat = (float)micsample/32767.0F; // 16 bit sample + + micinputbuffer[micsamples*2]=(double)(micsamplefloat*mic_gain); + micinputbuffer[(micsamples*2)+1]=0.0; + + micsamples++; + + if(micsamples==BUFFER_SIZE) { + int error; + + if(tune==1) { + //float tunefrequency = (float)((filterLow + filterHigh - filterLow) / 2); + float tunefrequency = (float)((filterHigh - filterLow) / 2); + phase=sineWave(micinputbuffer, BUFFER_SIZE, phase, tunefrequency); + } + + fexchange0(CHANNEL_TX, micinputbuffer, micoutputbuffer, &error); + if(error!=0) { + fprintf(stderr,"fexchange0 returned error: %d for transmitter\n", error); + } + + for(j=0;j>16; + iqbuffer[iqindex++]=isample>>8; + iqbuffer[iqindex++]=isample; + iqbuffer[iqindex++]=qsample>>16; + iqbuffer[iqindex++]=qsample>>8; + iqbuffer[iqindex++]=qsample; + + if(iqindex>=sizeof(iqbuffer)) { + // insert the sequence + iqbuffer[0]=tx_iq_sequence>>24; + iqbuffer[1]=tx_iq_sequence>>16; + iqbuffer[2]=tx_iq_sequence>>8; + iqbuffer[3]=tx_iq_sequence; + + // send the buffer + if(sendto(data_socket,iqbuffer,sizeof(iqbuffer),0,(struct sockaddr*)&iq_addr,iq_addr_length)<0) { + fprintf(stderr,"sendto socket failed for iq\n"); + exit(1); + } + iqindex=4; + tx_iq_sequence++; + } + + } + //Spectrum(CHANNEL_TX, 0, 0, micrightoutputbuffer, micleftoutputbuffer); + Spectrum0(1, CHANNEL_TX, 0, 0, micoutputbuffer); + micsamples=0; + } +#ifdef ECHO_MIC + audiobuffer[audioindex++]=micsample>>8; + audiobuffer[audioindex++]=micsample; + audiobuffer[audioindex++]=micsample>>8; + audiobuffer[audioindex++]=micsample; + + if(audioindex>=sizeof(audiobuffer)) { + // insert the sequence + audiobuffer[0]=audiosequence>>24; + audiobuffer[1]=audiosequence>>16; + audiobuffer[2]=audiosequence>>8; + audiobuffer[3]=audiosequence; + // send the buffer + if(sendto(data_socket,audiobuffer,sizeof(audiobuffer),0,(struct sockaddr*)&audio_addr,audio_addr_length)<0) { + fprintf(stderr,"sendto socket failed for audio\n"); + exit(1); + } + audioindex=4; + audiosequence++; + } +#endif + } + } + } else { + } + + if(running) { + if(send_general==1) { + new_protocol_general(); + send_general=0; + } + if(send_high_priority==1) { + new_protocol_high_priority(1,isTransmitting(),tune==0?drive:tune_drive); + send_high_priority=0; + } + } + + } + + close(data_socket); +} + +void* new_protocol_timer_thread(void* arg) { + int count=0; +fprintf(stderr,"new_protocol_timer_thread\n"); + while(running) { + usleep(100000); // 100ms + if(running) { + if(count==0) { + new_protocol_transmit_specific(); + count=1; + } else { + new_protocol_receive_specific(); + count=0; + } + } + } +} diff --git a/new_protocol.h b/new_protocol.h new file mode 100644 index 0000000..1252f65 --- /dev/null +++ b/new_protocol.h @@ -0,0 +1,78 @@ + +// port definitions from host +#define GENERAL_REGISTERS_FROM_HOST_PORT 1024 +#define PROGRAMMING_FROM_HOST_PORT 1024 +#define RECEIVER_SPECIFIC_REGISTERS_FROM_HOST_PORT 1025 +#define TRANSMITTER_SPECIFIC_REGISTERS_FROM_HOST_PORT 1026 +#define HIGH_PRIORITY_FROM_HOST_PORT 1027 +#define AUDIO_FROM_HOST_PORT 1028 +#define TX_IQ_FROM_HOST_PORT 1029 + +// port definitions to host +#define COMMAND_RESPONCE_TO_HOST_PORT 1024 +#define HIGH_PRIORITY_TO_HOST_PORT 1025 +#define MIC_LINE_TO_HOST_PORT 1026 +#define WIDE_BAND_TO_HOST_PORT 1027 +#define RX_IQ_TO_HOST_PORT 1035 + +#define BUFFER_SIZE 1024 + +#define modeLSB 0 +#define modeUSB 1 +#define modeDSB 2 +#define modeCWL 3 +#define modeCWU 4 +#define modeFMN 5 +#define modeAM 6 +#define modeDIGU 7 +#define modeSPEC 8 +#define modeDIGL 9 +#define modeSAM 10 +#define modeDRM 11 + +extern int data_socket; +extern sem_t response_sem; + +extern long response_sequence; +extern int response; + +extern unsigned int exciter_power; +extern unsigned int alex_forward_power; +extern unsigned int alex_reverse_power; + +void new_protocol_init(int rx,int pixels); +void new_protocol_stop(); + +void filter_board_changed(); +void pa_changed(); +void tuner_changed(); +void cw_changed(); + +void set_attenuation(int value); +int get_attenuation(); + +void set_alex_rx_antenna(unsigned long v); +void set_alex_tx_antenna(unsigned long v); +void set_alex_attenuation(unsigned long v); + +void setMox(int state); +int getMox(); +void setTune(int state); +int getTune(); +int isTransmitting(); + +double getDrive(); +void setDrive(double d); +double getTuneDrive(); +void setTuneDrive(double d); + +void setSampleRate(int rate); +int getSampleRate(); +void setFrequency(long long f); +long long getFrequency(); +void setMode(int m); +int getMode(); +void setFilter(int low,int high); +int getFilterLow(); +int getFilterHigh(); + diff --git a/new_protocol_programmer.c b/new_protocol_programmer.c new file mode 100644 index 0000000..8d0dea0 --- /dev/null +++ b/new_protocol_programmer.c @@ -0,0 +1,213 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "discovered.h" +#include "new_protocol.h" +#include "new_protocol.h" + +static long sequence; +static long block_sequence; + +static struct sockaddr_in program_addr; +static int program_addr_length; + +static char* source; +static long blocks; + +static pthread_t programmer_thread_id; +static pthread_t programmer_response_thread_id; + +static int running; + +void *programmer_thread(void *arg); +void *programmer_response_thread(void *arg); + +void new_protocol_programmer(char *filename ) { + int rc; + + fprintf(stderr,"new_protocol_programmer: %s\n",filename); + + sequence=0L; + block_sequence=0L; + + DISCOVERED* d=&discovered[selected_device]; + + memcpy(&program_addr,&d->address,d->address_length); + program_addr_length=d->address_length; + program_addr.sin_port=htons(PROGRAMMING_FROM_HOST_PORT); + + FILE *fp; + long length; + + fp=fopen(filename,"rb"); + + if(fp==NULL) { + fprintf(stderr, "file %s not found!\n", filename); + exit(-1); + } + + fseek(fp,0L,SEEK_END); + length=ftell(fp); + fseek(fp,0L,SEEK_SET); + fprintf(stderr,"the file's length is %ld bytes\n",length); + + long source_size=((length+511)/512)*512; + fprintf(stderr,"allocating %ld bytes\n",source_size); + source=(char *)malloc(source_size); + + blocks=source_size/256; + + // read the file in + int r; + int b=0; + while((r==fread(&source[b],sizeof(char),512, fp))>0) { + b+=r; + } + + fclose(fp); + + // start the thread to program + rc=pthread_create(&programmer_thread_id,NULL,programmer_thread,NULL); + if(rc != 0) { + fprintf(stderr,"pthread_create failed on programmer_thread: rc=%d\n", rc); + exit(-1); + } + +} + +void programmer_erase() { + char buffer[60]; + + fprintf(stderr,"programmer_erase\n"); + memset(buffer, 0, sizeof(buffer)); + + buffer[0]=sequence>>24; + buffer[1]=sequence>>16; + buffer[2]=sequence>>8; + buffer[3]=sequence; + + buffer[4]=0x04; // Erase command + + if(sendto(data_socket,buffer,sizeof(buffer),0,(struct sockaddr*)&program_addr,program_addr_length)<0) { + fprintf(stderr,"sendto socket failed for erase\n"); + exit(1); + } + +} + +void programmer_send_block(long block) { + char buffer[265]; + + fprintf(stderr,"programmer_send_block: %ld\n",block); + + memset(buffer, 0, sizeof(buffer)); + + buffer[0]=block_sequence>>24; + buffer[1]=block_sequence>>16; + buffer[2]=block_sequence>>8; + buffer[3]=block_sequence; + + buffer[4]=0x05; // Program command + + + buffer[5]=blocks>>24; + buffer[6]=blocks>>16; + buffer[7]=blocks>>8; + buffer[8]=blocks; + + + // copy a block (256 bytes) + memcpy(&buffer[9],&source[block*256],256); + + if(sendto(data_socket,buffer,sizeof(buffer),0,(struct sockaddr*)&program_addr,program_addr_length)<0) { + fprintf(stderr,"sendto socket failed for erase\n"); + exit(1); + } +} + +void *programmer_thread(void *arg) { + + int result; + struct timespec ts; + + fprintf(stderr,"programmer_thread\n"); + programmer_erase(); + + // wait for the response to the erase command + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec+=120; // wait for 30 seconds + result=sem_timedwait(&response_sem,&ts); + if(result==-1) { + if(errno == ETIMEDOUT) { + fprintf(stderr,"timedout waiting for response for erase (start)\n"); + exit(1); + } else { + fprintf(stderr,"sem_timedwait failed for response for erase (start): %d\n",errno); + exit(1); + } + } + if(response!=0x03) { + fprintf(stderr,"response error %d for erase (start)\n", response); + exit(1); + } + + // wait for the erase to complete + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec+=120; // wait for 30 seconds + result=sem_timedwait(&response_sem,&ts); + if(result==-1) { + if(errno == ETIMEDOUT) { + fprintf(stderr,"timedout waiting for response for erase (complete)\n"); + exit(1); + } else { + fprintf(stderr,"sem_timedwait failed for response for erase (complete): %d\n",errno); + exit(1); + } + } + if(response!=0x03) { + fprintf(stderr,"response error %d for erase (complete)\n", response); + exit(1); + } + + long b=0; + + while(b +#include +#include +#include +#include +#include +#include +#include "new_protocol.h" +#include "panadapter.h" +#include "vfo.h" + +static GtkWidget *panadapter; +static cairo_surface_t *panadapter_surface = NULL; + +static float* samples; + +static gint last_x; +static gboolean has_moved=FALSE; +static gboolean pressed=FALSE; + +static float panadapter_max=-60.0; +static float panadapter_min=-160.0; + +static gfloat hz_per_pixel; +static gfloat filter_left; +static gfloat filter_right; + +static int display_width; +static int panadapter_height; + +static void +panadapter_clear_surface (void) +{ + cairo_t *cr; + + cr = cairo_create (panadapter_surface); + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + cairo_destroy (cr); +} + +/* Create a new surface of the appropriate size to store our scribbles */ +static gboolean +panadapter_configure_event_cb (GtkWidget *widget, + GdkEventConfigure *event, + gpointer data) +{ + if (panadapter_surface) + cairo_surface_destroy (panadapter_surface); + + panadapter_surface = gdk_window_create_similar_surface (gtk_widget_get_window (widget), + CAIRO_CONTENT_COLOR, + gtk_widget_get_allocated_width (widget), + gtk_widget_get_allocated_height (widget)); + + /* Initialize the surface to white */ + panadapter_clear_surface (); + + /* We've handled the configure event, no need for further processing. */ + return TRUE; +} + +/* Redraw the screen from the surface. Note that the ::draw + * signal receives a ready-to-be-used cairo_t that is already + * clipped to only draw the exposed areas of the widget + */ +static gboolean +panadapter_draw_cb (GtkWidget *widget, + cairo_t *cr, + gpointer data) +{ + cairo_set_source_surface (cr, panadapter_surface, 0, 0); + cairo_paint (cr); + + return FALSE; +} + +static gboolean +panadapter_button_press_event_cb (GtkWidget *widget, + GdkEventButton *event, + gpointer data) +{ + int x=(int)event->x; + if (event->button == 1) { + last_x=(int)event->x; + has_moved=FALSE; + pressed=TRUE; + } + return TRUE; +} + +static gboolean +panadapter_button_release_event_cb (GtkWidget *widget, + GdkEventButton *event, + gpointer data) +{ + int x=(int)event->x; + if (event->button == 1) { + if(has_moved) { + // drag + vfo_move((int)((float)(x-last_x)*hz_per_pixel)); + } else { + // move to this frequency + vfo_move((int)((float)(x-(display_width/2))*hz_per_pixel)); + } + last_x=x; + pressed=FALSE; + } + return TRUE; +} + +static gboolean +panadapter_motion_notify_event_cb (GtkWidget *widget, + GdkEventMotion *event, + gpointer data) +{ + int x, y; + GdkModifierType state; + gdk_window_get_device_position (event->window, + event->device, + &x, + &y, + &state); + if((state & GDK_BUTTON1_MASK == GDK_BUTTON1_MASK) || pressed) { + int moved=last_x-x; + vfo_move((int)((float)moved*hz_per_pixel)); + last_x=x; + has_moved=TRUE; + } + + return TRUE; +} + +static void +close_window (void) +{ + if (panadapter_surface) + cairo_surface_destroy (panadapter_surface); + + gtk_main_quit (); +} + +void panadapter_update(float *data,int tx) { + int i; + int result; + + float saved_max; + float saved_min; + gfloat saved_hz_per_pixel; + + samples=data; + //if(result==1) { + if(panadapter_surface) { + + if(tx) { + saved_max=panadapter_max; + saved_min=panadapter_min; + saved_hz_per_pixel=hz_per_pixel; + + panadapter_max=30; + panadapter_min=-100; + hz_per_pixel=192000.0/(double)display_width; + } + + //clear_panadater_surface(); + cairo_t *cr; + cr = cairo_create (panadapter_surface); + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + // filter + cairo_set_source_rgb (cr, 0.25, 0.25, 0.25); + filter_left=(double)display_width/2.0+((double)getFilterLow()/hz_per_pixel); + filter_right=(double)display_width/2.0+((double)getFilterHigh()/hz_per_pixel); + cairo_rectangle(cr, filter_left, 0.0, filter_right-filter_left, (double)panadapter_height); + cairo_fill(cr); + + // plot the levels + int V = (int)(panadapter_max - panadapter_min); + int numSteps = V / 20; + for (i = 1; i < numSteps; i++) { + int num = panadapter_max - i * 20; + int y = (int)floor((panadapter_max - num) * panadapter_height / V); + + cairo_set_source_rgb (cr, 0, 1, 1); + cairo_set_line_width(cr, 1.0); + cairo_move_to(cr,0.0,(double)y); + cairo_line_to(cr,(double)display_width,(double)y); + + cairo_set_source_rgb (cr, 0, 1, 1); + cairo_select_font_face(cr, "Arial", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_BOLD); + cairo_set_font_size(cr, 12); + char v[32]; + sprintf(v,"%d dBm",num); + cairo_move_to(cr, 1, (double)y); + cairo_show_text(cr, v); + } + cairo_stroke(cr); + + // plot frequency markers + long f; + for(i=0;i 0) { + if ((f % 20000) < (long) hz_per_pixel) { + cairo_set_source_rgb (cr, 0, 1, 1); + cairo_set_line_width(cr, 1.0); + cairo_move_to(cr,(double)i,0.0); + cairo_line_to(cr,(double)i,(double)panadapter_height); + + cairo_set_source_rgb (cr, 0, 1, 1); + cairo_select_font_face(cr, "Arial", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_BOLD); + cairo_set_font_size(cr, 12); + char v[32]; + sprintf(v,"%0ld.%03ld",f/1000000,(f%1000000)/1000); + cairo_move_to(cr, (double)i, (double)(panadapter_height-10)); + cairo_show_text(cr, v); + } + } + } + cairo_stroke(cr); + + // cursor + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_set_line_width(cr, 1.0); + cairo_move_to(cr,(double)display_width/2.0,0.0); + cairo_line_to(cr,(double)display_width/2.0,(double)panadapter_height); + cairo_stroke(cr); + + // signal + cairo_set_source_rgb(cr, 1, 1, 1); + cairo_set_line_width(cr, 1.0); + + double s1,s2; + samples[0]=panadapter_min-20; + samples[display_width-1]=panadapter_min-20; + for(i=1;i +#include +#include +#include "property.h" + +PROPERTY* properties; + +/* --------------------------------------------------------------------------*/ +/** +* @brief Load Properties +* +* @param filename +*/ +void loadProperties(char* filename) { + char string[80]; + char* name; + char* value; + FILE* f=fopen(filename,"r"); + properties=NULL; + PROPERTY* property; + + fprintf(stderr,"loadProperties: %s\n",filename); + + if(f) { + while(fgets(string,sizeof(string),f)) { + if(string[0]!='#') { + name=strtok(string,"="); + value=strtok(NULL,"\n"); + property=malloc(sizeof(PROPERTY)); + property->name=malloc(strlen(name)+1); + strcpy(property->name,name); + property->value=malloc(strlen(value)+1); + strcpy(property->value,value); + property->next_property=properties; + properties=property; + } + } + fclose(f); + } +} + +/* --------------------------------------------------------------------------*/ +/** +* @brief Save Properties +* +* @param filename +*/ +void saveProperties(char* filename) { + PROPERTY* property=properties; + FILE* f=fopen(filename,"w+"); + char line[512]; + if(!f) { + fprintf(stderr,"can't open %s\n",filename); + exit(1); + } + while(property) { + sprintf(line,"%s=%s\n",property->name,property->value); + fwrite(line,1,strlen(line),f); + property=property->next_property; + } + fclose(f); +} + +/* --------------------------------------------------------------------------*/ +/** +* @brief Get Properties +* +* @param name +* +* @return +*/ +char* getProperty(char* name) { + char* value=NULL; + PROPERTY* property=properties; + while(property) { + if(strcmp(name,property->name)==0) { + value=property->value; + break; + } + property=property->next_property; + } + return value; +} + +/* --------------------------------------------------------------------------*/ +/** +* @brief Set Properties +* +* @param name +* @param value +*/ +void setProperty(char* name,char* value) { + PROPERTY* property=properties; + while(property) { + if(strcmp(name,property->name)==0) { + break; + } + property=property->next_property; + } + if(property) { + // just update + free(property->value); + property->value=malloc(strlen(value)+1); + strcpy(property->value,value); + } else { + // new property + property=malloc(sizeof(PROPERTY)); + property->name=malloc(strlen(name)+1); + strcpy(property->name,name); + property->value=malloc(strlen(value)+1); + strcpy(property->value,value); + property->next_property=properties; + properties=property; + } +} + diff --git a/property.h b/property.h new file mode 100644 index 0000000..55cd608 --- /dev/null +++ b/property.h @@ -0,0 +1,16 @@ +typedef struct _PROPERTY PROPERTY; + +/* --------------------------------------------------------------------------*/ +/** +* @brief Property structure +*/ +struct _PROPERTY { + char* name; + char* value; + PROPERTY* next_property; +}; + +void loadProperties(char* filename); +char* getProperty(char* name); +void setProperty(char* name,char* value); + diff --git a/radio.c b/radio.c new file mode 100644 index 0000000..1188605 --- /dev/null +++ b/radio.c @@ -0,0 +1,199 @@ +#include +#include +#include + +#include "radio.h" +#include "agc.h" +#include "band.h" +#include "discovered.h" +#include "property.h" + +char property_path[128]; + +int sample_rate=48000; +int filter_board=ALEX; +int pa=PA_ENABLED; +int apollo_tuner=0; + +int panadapter_high=-80; +int panadapter_low=-160; + +int waterfall_high=-100; +int waterfall_low=-150; +int waterfall_automatic=1; + +double volume=0.2; +double mic_gain=1.5; + +int orion_mic=MIC_BOOST|ORION_MIC_PTT_ENABLED|ORION_MIC_PTT_TIP_BIAS_RING|ORION_MIC_BIAS_ENABLED; + +int agc=AGC_MEDIUM; +double agc_gain=60.0; + +int nr=0; +int nb=0; +int anf=0; +int snb=0; + +int cwPitch=600; + +int tune_drive=6; +int drive=60; + +int receivers=2; +int adc[2]={0,1}; + +int locked=0; + +int step=100; + +int byte_swap=0; + +int cw_keys_reversed=0; // 0=disabled 1=enabled +int cw_keyer_speed=12; // 1-60 WPM +int cw_keyer_mode=KEYER_STRAIGHT; +int cw_keyer_weight=30; // 0-100 +int cw_keyer_spacing=0; // 0=on 1=off +int cw_keyer_internal=1; // 0=external 1=internal +int cw_keyer_sidetone_volume=127; // 0-127 +int cw_keyer_ptt_delay=20; // 0-255ms +int cw_keyer_hang_time=300; // ms +int cw_keyer_sidetone_frequency=400; // Hz +int cw_breakin=1; // 0=disabled 1=enabled + +void radioRestoreState() { + char *value; + value=getProperty("sample_rate"); + if(value) sample_rate=atoi(value); + value=getProperty("filter_board"); + if(value) filter_board=atoi(value); + value=getProperty("apollo_tuner"); + if(value) apollo_tuner=atoi(value); + value=getProperty("pa"); + if(value) pa=atoi(value); + value=getProperty("panadapter_high"); + if(value) panadapter_high=atoi(value); + value=getProperty("panadapter_low"); + if(value) panadapter_low=atoi(value); + value=getProperty("waterfall_high"); + if(value) waterfall_high=atoi(value); + value=getProperty("waterfall_low"); + if(value) waterfall_low=atoi(value); + value=getProperty("waterfall_automatic"); + if(value) waterfall_automatic=atoi(value); + value=getProperty("volume"); + if(value) volume=atof(value); + value=getProperty("mic_gain"); + if(value) mic_gain=atof(value); + value=getProperty("orion_mic"); + if(value) orion_mic=atof(value); + value=getProperty("nr"); + if(value) nr=atoi(value); + value=getProperty("nb"); + if(value) nb=atoi(value); + value=getProperty("anf"); + if(value) anf=atoi(value); + value=getProperty("snb"); + if(value) snb=atoi(value); + value=getProperty("agc"); + if(value) agc=atoi(value); + value=getProperty("agc_gain"); + if(value) agc_gain=atof(value); + value=getProperty("step"); + if(value) step=atoi(value); + value=getProperty("byte_swap"); + if(value) byte_swap=atoi(value); + value=getProperty("cw_keys_reversed"); + if(value) cw_keys_reversed=atoi(value); + value=getProperty("cw_keyer_speed"); + if(value) cw_keyer_speed=atoi(value); + value=getProperty("cw_keyer_mode"); + if(value) cw_keyer_mode=atoi(value); + value=getProperty("cw_keyer_weight"); + if(value) cw_keyer_weight=atoi(value); + value=getProperty("cw_keyer_spacing"); + if(value) cw_keyer_spacing=atoi(value); + value=getProperty("cw_keyer_internal"); + if(value) cw_keyer_internal=atoi(value); + value=getProperty("cw_keyer_sidetone_volume"); + if(value) cw_keyer_sidetone_volume=atoi(value); + value=getProperty("cw_keyer_ptt_delay"); + if(value) cw_keyer_ptt_delay=atoi(value); + value=getProperty("cw_keyer_hang_time"); + if(value) cw_keyer_hang_time=atoi(value); + value=getProperty("cw_keyer_sidetone_frequency"); + if(value) cw_keyer_sidetone_frequency=atoi(value); + value=getProperty("cw_breakin"); + if(value) cw_breakin=atoi(value); + + + bandRestoreState(); +} + +void radioSaveState() { + char value[80]; + sprintf(value,"%d",sample_rate); + setProperty("sample_rate",value); + sprintf(value,"%d",filter_board); + setProperty("filter_board",value); + sprintf(value,"%d",apollo_tuner); + setProperty("apollo_tuner",value); + sprintf(value,"%d",pa); + setProperty("pa",value); + sprintf(value,"%d",panadapter_high); + setProperty("panadapter_high",value); + sprintf(value,"%d",panadapter_low); + setProperty("panadapter_low",value); + sprintf(value,"%d",waterfall_high); + setProperty("waterfall_high",value); + sprintf(value,"%d",waterfall_low); + setProperty("waterfall_low",value); + sprintf(value,"%d",waterfall_automatic); + setProperty("waterfall_automatic",value); + sprintf(value,"%f",volume); + setProperty("volume",value); + sprintf(value,"%f",mic_gain); + setProperty("mic_gain",value); + sprintf(value,"%d",orion_mic); + setProperty("orion_mic",value); + sprintf(value,"%d",nr); + setProperty("nr",value); + sprintf(value,"%d",nb); + setProperty("nb",value); + sprintf(value,"%d",anf); + setProperty("anf",value); + sprintf(value,"%d",snb); + setProperty("snb",value); + sprintf(value,"%d",agc); + setProperty("agc",value); + sprintf(value,"%f",agc_gain); + setProperty("agc_gain",value); + sprintf(value,"%d",step); + setProperty("step",value); + sprintf(value,"%d",byte_swap); + setProperty("byte_swap",value); + sprintf(value,"%d",cw_keys_reversed); + setProperty("cw_keys_reversed",value); + sprintf(value,"%d",cw_keyer_speed); + setProperty("cw_keyer_speed",value); + sprintf(value,"%d",cw_keyer_mode); + setProperty("cw_keyer_mode",value); + sprintf(value,"%d",cw_keyer_weight); + setProperty("cw_keyer_weight",value); + sprintf(value,"%d",cw_keyer_spacing); + setProperty("cw_keyer_spacing",value); + sprintf(value,"%d",cw_keyer_internal); + setProperty("cw_keyer_internal",value); + sprintf(value,"%d",cw_keyer_sidetone_volume); + setProperty("cw_keyer_sidetone_volume",value); + sprintf(value,"%d",cw_keyer_ptt_delay); + setProperty("cw_keyer_ptt_delay",value); + sprintf(value,"%d",cw_keyer_hang_time); + setProperty("cw_keyer_hang_time",value); + sprintf(value,"%d",cw_keyer_sidetone_frequency); + setProperty("cw_keyer_sidetone_frequency",value); + sprintf(value,"%d",cw_breakin); + setProperty("cw_breakin",value); + + bandSaveState(); +} diff --git a/radio.h b/radio.h new file mode 100644 index 0000000..28ef822 --- /dev/null +++ b/radio.h @@ -0,0 +1,80 @@ + +#define MIC_IN 0x00 +#define LINE_IN 0x01 +#define MIC_BOOST 0x02 +#define ORION_MIC_PTT_ENABLED 0x00 +#define ORION_MIC_PTT_DISABLED 0x04 +#define ORION_MIC_PTT_RING_BIAS_TIP 0x00 +#define ORION_MIC_PTT_TIP_BIAS_RING 0x08 +#define ORION_MIC_BIAS_DISABLED 0x00 +#define ORION_MIC_BIAS_ENABLED 0x10 + +extern char property_path[]; + +#define NONE 0 + +#define ALEX 1 +#define APOLLO 2 + +#define PA_DISABLED 0 +#define PA_ENABLED 1 + +#define APOLLO_TUNER 1 + +#define KEYER_STRAIGHT 0 +#define KEYER_MODE_A 1 +#define KEYER_MODE_B 2 + +extern int sample_rate; +extern int filter_board; +extern int pa; +extern int apollo_tuner; + +extern int panadapter_high; +extern int panadapter_low; + +extern int waterfall_high; +extern int waterfall_low; +extern int waterfall_automatic; + +extern double volume; +extern double mic_gain; +extern int agc; +extern double agc_gain; + +extern int nr; +extern int nb; +extern int anf; +extern int snb; + +extern int cwPitch; + +extern int orion_mic; + +extern int tune_drive; +extern int drive; + +int receivers; +int adc[2]; + +int locked; + +extern int step; + +extern int byte_swap; + +extern int cw_keys_reversed; +extern int cw_keyer_speed; +extern int cw_keyer_mode; +extern int cw_keyer_weight; +extern int cw_keyer_spacing; +extern int cw_keyer_internal; +extern int cw_keyer_sidetone_volume; +extern int cw_keyer_ptt_delay; +extern int cw_keyer_hang_time; +extern int cw_keyer_sidetone_frequency; +extern int cw_breakin; + +extern void radioRestoreState(); +extern void radioSaveState(); + diff --git a/rotary_encoder.c b/rotary_encoder.c new file mode 100644 index 0000000..9e70db4 --- /dev/null +++ b/rotary_encoder.c @@ -0,0 +1,298 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rotary_encoder.h" +#include "main.h" + +#define SYSFS_GPIO_DIR "/sys/class/gpio" + +#define RASPBERRYPI_VFO_ENCODER_A 14 +#define RASPBERRYPI_VFO_ENCODER_B 15 + +#define ODROID_VFO_ENCODER_A 108 +#define ODROID_VFO_ENCODER_B 97 +#define ODROID_VFO_ENCODER_A_PIN 23 +#define ODROID_VFO_ENCODER_B_PIN 24 + +#define AF_ENCODER_A 20 +#define AF_ENCODER_B 26 +#define AF_FUNCTION 21 + +#define RF_ENCODER_A 16 +#define RF_ENCODER_B 19 +#define RF_FUNCTION 13 + +#define FUNCTION 12 +#define BAND 6 + +static int VFO_ENCODER_A=14; +static int VFO_ENCODER_B=15; + +static int VFO_ENCODER_A_PIN=0; +static int VFO_ENCODER_B_PIN=0; + +static volatile int vfoEncoderPos; +static volatile int afEncoderPos; +static volatile int afFunction; +static volatile int rfEncoderPos; +static volatile int rfFunction; +static volatile int function; +static volatile int band; + +static void afFunctionAlert(int gpio, int level, uint32_t tick) { + afFunction=(level==0); +} + +static void rfFunctionAlert(int gpio, int level, uint32_t tick) { + rfFunction=(level==0); +} + +static void functionAlert(int gpio, int level, uint32_t tick) { + function=(level==0); +} + +static void bandAlert(int gpio, int level, uint32_t tick) { + band=(level==0); +} + +static void vfoEncoderPulse(int gpio, int level, unsigned int tick) { + static int levA=0, levB=0, lastGpio = -1; + +//fprintf(stderr,"vfoEncoderPulse:%d=%d\n",gpio,level); + if (gpio == VFO_ENCODER_A) levA = level; else levB = level; + + if (gpio != lastGpio) /* debounce */ + { + lastGpio = gpio; + + if ((gpio == VFO_ENCODER_A) && (level == 0)) + { + if (!levB) ++vfoEncoderPos; + } + else if ((gpio == VFO_ENCODER_B) && (level == 1)) + { + if (levA) --vfoEncoderPos; + } + } +} + +static void afEncoderPulse(int gpio, int level, uint32_t tick) +{ + static int levA=0, levB=0, lastGpio = -1; + + if (gpio == AF_ENCODER_A) levA = level; else levB = level; + + if (gpio != lastGpio) /* debounce */ + { + lastGpio = gpio; + + if ((gpio == AF_ENCODER_A) && (level == 0)) + { + if (!levB) ++afEncoderPos; + } + else if ((gpio == AF_ENCODER_B) && (level == 1)) + { + if (levA) --afEncoderPos; + } + } +} + +static void rfEncoderPulse(int gpio, int level, uint32_t tick) +{ + static int levA=0, levB=0, lastGpio = -1; + + if (gpio == RF_ENCODER_A) levA = level; else levB = level; + + if (gpio != lastGpio) /* debounce */ + { + lastGpio = gpio; + + if ((gpio == RF_ENCODER_A) && (level == 0)) + { + if (!levB) ++rfEncoderPos; + } + else if ((gpio == RF_ENCODER_B) && (level == 1)) + { + if (levA) --rfEncoderPos; + } + } +} + +void interruptB(void) { + vfoEncoderPulse(VFO_ENCODER_B,digitalRead(VFO_ENCODER_B_PIN),0); +} + +void interruptA(void) { + vfoEncoderPulse(VFO_ENCODER_A,digitalRead(VFO_ENCODER_A_PIN),0); +} + +int encoder_init() { + + if(strcmp(unameData.nodename,"raspberrypi")==0) { + + VFO_ENCODER_A=RASPBERRYPI_VFO_ENCODER_A; + VFO_ENCODER_B=RASPBERRYPI_VFO_ENCODER_B; + VFO_ENCODER_A_PIN=0; + VFO_ENCODER_B_PIN=0; + + fprintf(stderr,"encoder_init: VFO_ENCODER_A=%d VFO_ENCODER_B=%d\n",VFO_ENCODER_A,VFO_ENCODER_B); + + if(gpioInitialise()<0) { + fprintf(stderr,"Cannot initialize GPIO\n"); + return -1; + } + + gpioSetMode(VFO_ENCODER_A, PI_INPUT); + gpioSetMode(VFO_ENCODER_B, PI_INPUT); + gpioSetPullUpDown(VFO_ENCODER_A, PI_PUD_UP); + gpioSetPullUpDown(VFO_ENCODER_B, PI_PUD_UP); + gpioSetAlertFunc(VFO_ENCODER_A, vfoEncoderPulse); + gpioSetAlertFunc(VFO_ENCODER_B, vfoEncoderPulse); + vfoEncoderPos=0; + + + gpioSetMode(AF_FUNCTION, PI_INPUT); + gpioSetPullUpDown(AF_FUNCTION,PI_PUD_UP); + gpioSetAlertFunc(AF_FUNCTION, afFunctionAlert); + afFunction=0; + + gpioSetMode(AF_ENCODER_A, PI_INPUT); + gpioSetMode(AF_ENCODER_B, PI_INPUT); + gpioSetPullUpDown(AF_ENCODER_A, PI_PUD_OFF); + gpioSetPullUpDown(AF_ENCODER_B, PI_PUD_OFF); + gpioSetAlertFunc(AF_ENCODER_A, afEncoderPulse); + gpioSetAlertFunc(AF_ENCODER_B, afEncoderPulse); + afEncoderPos=0; + + gpioSetMode(RF_FUNCTION, PI_INPUT); + gpioSetPullUpDown(RF_FUNCTION,PI_PUD_UP); + gpioSetAlertFunc(RF_FUNCTION, rfFunctionAlert); + rfFunction=0; + + gpioSetMode(RF_ENCODER_A, PI_INPUT); + gpioSetMode(RF_ENCODER_B, PI_INPUT); + gpioSetPullUpDown(RF_ENCODER_A, PI_PUD_OFF); + gpioSetPullUpDown(RF_ENCODER_B, PI_PUD_OFF); + gpioSetAlertFunc(RF_ENCODER_A, rfEncoderPulse); + gpioSetAlertFunc(RF_ENCODER_B, rfEncoderPulse); + rfEncoderPos=0; + + gpioSetMode(FUNCTION, PI_INPUT); + gpioSetPullUpDown(FUNCTION,PI_PUD_UP); + gpioSetAlertFunc(FUNCTION, functionAlert); + + gpioSetMode(BAND, PI_INPUT); + gpioSetPullUpDown(BAND,PI_PUD_UP); + gpioSetAlertFunc(BAND, bandAlert); + + } else if(strcmp(unameData.nodename,"odroid")==0) { + + VFO_ENCODER_A=ODROID_VFO_ENCODER_A; + VFO_ENCODER_B=ODROID_VFO_ENCODER_B; + VFO_ENCODER_A_PIN=ODROID_VFO_ENCODER_A_PIN; + VFO_ENCODER_B_PIN=ODROID_VFO_ENCODER_B_PIN; + + fprintf(stderr,"encoder_init: VFO_ENCODER_A=%d VFO_ENCODER_B=%d\n",VFO_ENCODER_A,VFO_ENCODER_B); + + if (wiringPiSetup () < 0) { + printf ("Unable to setup wiringPi: %s\n", strerror (errno)); + return 1; + } + + FILE *fp; + + fp = popen("echo 97 > /sys/class/gpio/export\n", "r"); + pclose(fp); + fp = popen("echo \"in\" > /sys/class/gpio/gpio97/direction\n", "r"); + pclose(fp); + fp = popen("chmod 0666 /sys/class/gpio/gpio97/value\n", "r"); + pclose(fp); + + fp = popen("echo 108 > /sys/class/gpio/export\n", "r"); + pclose(fp); + fp = popen("echo \"in\" > /sys/class/gpio/gpio108/direction\n", "r"); + pclose(fp); + fp = popen("chmod 0666 /sys/class/gpio/gpio108/value\n", "r"); + pclose(fp); + + if ( wiringPiISR (24, INT_EDGE_BOTH, &interruptB) < 0 ) { + printf ("Unable to setup ISR: %s\n", strerror (errno)); + return 1; + } + + if ( wiringPiISR (23, INT_EDGE_BOTH, &interruptA) < 0 ) { + printf ("Unable to setup ISR: %s\n", strerror (errno)); + return 1; + } + } else { + fprintf(stderr,"Unknown nodename: %s. Rotary Encoder not enabled.\n",unameData.nodename); + return 1; + } + + + return 0; +} + +void encoder_close() { + if(strcmp(unameData.nodename,"odroid")==0) { + FILE *fp; + fp = popen("echo 97 > /sys/class/gpio/unexport\n", "r"); + pclose(fp); + fp = popen("echo 108 > /sys/class/gpio/unexport\n", "r"); + pclose(fp); + } +} + +int vfo_encoder_get_pos() { + int pos=vfoEncoderPos; + + if(strcmp(unameData.nodename,"raspberrypi")==0) { + if(pos<0 && pos>-12) { + pos=0; + } else if(pos>0 && pos<12) { + pos=0; + } + pos=pos/12; + vfoEncoderPos=vfoEncoderPos-(pos*12); + } else if(strcmp(unameData.nodename,"odroid")==0) { + vfoEncoderPos=0; + } + return pos; +} + +int af_encoder_get_pos() { + int pos=afEncoderPos; + afEncoderPos=0; + return pos; +} + +int af_function_get_state() { + return afFunction; +} + +int rf_encoder_get_pos() { + int pos=rfEncoderPos; + rfEncoderPos=0; + return pos; +} + +int rf_function_get_state() { + return rfFunction; +} + +int function_get_state() { + return function; +} + +int band_get_state() { + return band; +} diff --git a/rotary_encoder.h b/rotary_encoder.h new file mode 100644 index 0000000..604feb1 --- /dev/null +++ b/rotary_encoder.h @@ -0,0 +1,6 @@ +int encoder_init(); +void encoder_close(); +int vfo_encoder_get_pos(); +int af_encoder_get_pos(); +int af_function_get_state(); + diff --git a/splash.c b/splash.c new file mode 100644 index 0000000..53c7909 --- /dev/null +++ b/splash.c @@ -0,0 +1,23 @@ +#include + +GtkWidget *splash_window; + +/* Close the splash screen */ +void splash_close() +{ + gtk_widget_destroy(splash_window); +} + + +void splash_show(char* image_name,int time,int width,int height) +{ + GtkWidget *image; + splash_window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_widget_set_size_request(splash_window, width, height); + gtk_window_set_decorated(GTK_WINDOW(splash_window), FALSE); + gtk_window_set_position(GTK_WINDOW(splash_window),GTK_WIN_POS_CENTER_ALWAYS); + gtk_window_set_resizable(GTK_WINDOW(splash_window), FALSE); + image=gtk_image_new_from_file(image_name); + gtk_container_add(GTK_CONTAINER(splash_window), image); + gtk_widget_show_all (splash_window); +} diff --git a/splash.h b/splash.h new file mode 100644 index 0000000..5adb9ef --- /dev/null +++ b/splash.h @@ -0,0 +1,5 @@ + +extern GtkWidget* splash_window; + +void splash_close(void); +void splash_show(char* image_name,int time,int width,int height); diff --git a/splash.png b/splash.png new file mode 100644 index 0000000..4b249eb Binary files /dev/null and b/splash.png differ diff --git a/start_pihpsdr.sh b/start_pihpsdr.sh new file mode 100755 index 0000000..98af331 --- /dev/null +++ b/start_pihpsdr.sh @@ -0,0 +1,2 @@ +cd ~/pihpsdr +sudo ~/pihpsdr/pihpsdr diff --git a/toolbar.c b/toolbar.c new file mode 100644 index 0000000..048ad04 --- /dev/null +++ b/toolbar.c @@ -0,0 +1,1007 @@ +#include +#include +#include + +#include "toolbar.h" +#include "mode.h" +#include "filter.h" +#include "bandstack.h" +#include "band.h" +#include "discovered.h" +#include "new_protocol.h" +#include "rotary_encoder.h" +#include "vfo.h" +#include "alex.h" +#include "agc.h" +#include "channel.h" +#include "wdsp.h" +#include "radio.h" +#include "property.h" + +static int width; +static int height; + +static int column=0; + +static GtkWidget *parent_window; +static GtkWidget *toolbar; +static GtkWidget *toolbar_bottom; +static GtkWidget *toolbar_top; + +static GtkWidget *last_band; +static GtkWidget *last_mode; +static GtkWidget *last_filter; + +static GtkWidget *af_gain_label; +static GtkWidget *audio_scale; +static GtkWidget *agc_gain_label; +static GtkWidget *agc_scale; +static GtkWidget *mic_gain_label; +static GtkWidget *mic_scale; +static GtkWidget *drive_scale; +static GtkWidget *tune_scale; + +static GdkRGBA white; +static GdkRGBA gray; + +static void band_select_cb(GtkWidget *widget, gpointer data) { + GtkWidget *label; + int b=(int)data; + BANDSTACK_ENTRY *entry; + if(b==band_get_current()) { + entry=bandstack_entry_next(); + } else { + BAND* band=band_set_current(b); + entry=bandstack_entry_get_current(); + gtk_widget_override_background_color(last_band, GTK_STATE_NORMAL, &white); + last_band=widget; + gtk_widget_override_background_color(last_band, GTK_STATE_NORMAL, &gray); + } + setFrequency(entry->frequencyA); + setMode(entry->mode); + FILTER* band_filters=filters[entry->mode]; + FILTER* band_filter=&band_filters[entry->filter]; + setFilter(band_filter->low,band_filter->high); + + BAND *band=band_get_current_band(); + set_alex_rx_antenna(band->alexRxAntenna); + set_alex_tx_antenna(band->alexTxAntenna); + set_alex_attenuation(band->alexAttenuation); + vfo_update(NULL); +} + +static void band_cb(GtkWidget *widget, gpointer data) { + GtkWidget *dialog=gtk_dialog_new_with_buttons("Band",GTK_WINDOW(parent_window),GTK_DIALOG_DESTROY_WITH_PARENT,NULL,NULL); + GtkWidget *content=gtk_dialog_get_content_area(GTK_DIALOG(dialog)); + GtkWidget *grid=gtk_grid_new(); + gtk_grid_set_column_homogeneous(GTK_GRID(grid),TRUE); + gtk_grid_set_row_homogeneous(GTK_GRID(grid),TRUE); + GtkWidget *b; + int i; + for(i=0;ititle); + gtk_widget_override_background_color(b, GTK_STATE_NORMAL, &white); + gtk_widget_override_font(b, pango_font_description_from_string("Arial 20")); + if(i==band_get_current()) { + gtk_widget_override_background_color(b, GTK_STATE_NORMAL, &gray); + last_band=b; + } + gtk_widget_show(b); + gtk_grid_attach(GTK_GRID(grid),b,i%5,i/5,1,1); + g_signal_connect(b,"clicked",G_CALLBACK(band_select_cb),(gpointer *)i); + } + + gtk_container_add(GTK_CONTAINER(content),grid); + + GtkWidget *close_button=gtk_dialog_add_button(GTK_DIALOG(dialog),"Close",GTK_RESPONSE_OK); + gtk_widget_override_font(close_button, pango_font_description_from_string("Arial 20")); + gtk_widget_show_all(dialog); + + g_signal_connect_swapped (dialog, + "response", + G_CALLBACK (gtk_widget_destroy), + dialog); + + int result=gtk_dialog_run(GTK_DIALOG(dialog)); + +} + +static void mode_select_cb(GtkWidget *widget, gpointer data) { + int m=(int)data; + BANDSTACK_ENTRY *entry; + entry=bandstack_entry_get_current(); + entry->mode=m; + setMode(entry->mode); + FILTER* band_filters=filters[entry->mode]; + FILTER* band_filter=&band_filters[entry->filter]; + setFilter(band_filter->low,band_filter->high); + gtk_widget_override_background_color(last_mode, GTK_STATE_NORMAL, &white); + last_mode=widget; + gtk_widget_override_background_color(last_mode, GTK_STATE_NORMAL, &gray); + vfo_update(NULL); +} + +static void mode_cb(GtkWidget *widget, gpointer data) { + BANDSTACK_ENTRY *entry=bandstack_entry_get_current(); + GtkWidget *dialog=gtk_dialog_new_with_buttons("Mode",GTK_WINDOW(parent_window),GTK_DIALOG_DESTROY_WITH_PARENT,NULL,NULL); + GtkWidget *content=gtk_dialog_get_content_area(GTK_DIALOG(dialog)); + GtkWidget *grid=gtk_grid_new(); + gtk_grid_set_column_homogeneous(GTK_GRID(grid),TRUE); + gtk_grid_set_row_homogeneous(GTK_GRID(grid),TRUE); + + GtkWidget *b; + int i; + for(i=0;imode) { + gtk_widget_override_background_color(b, GTK_STATE_NORMAL, &gray); + last_mode=b; + } else { + gtk_widget_override_background_color(b, GTK_STATE_NORMAL, &white); + } + gtk_widget_override_font(b, pango_font_description_from_string("Arial 20")); + gtk_widget_show(b); + gtk_grid_attach(GTK_GRID(grid),b,i%5,i/5,1,1); + g_signal_connect(b,"pressed",G_CALLBACK(mode_select_cb),(gpointer *)i); + } + gtk_container_add(GTK_CONTAINER(content),grid); + GtkWidget *close_button=gtk_dialog_add_button(GTK_DIALOG(dialog),"Close",GTK_RESPONSE_OK); + gtk_widget_override_font(close_button, pango_font_description_from_string("Arial 20")); + gtk_widget_show_all(dialog); + + g_signal_connect_swapped (dialog, + "response", + G_CALLBACK (gtk_widget_destroy), + dialog); + + int result=gtk_dialog_run(GTK_DIALOG(dialog)); + +} + +static void filter_select_cb(GtkWidget *widget, gpointer data) { + int f=(int)data; + BANDSTACK_ENTRY *entry; + entry=bandstack_entry_get_current(); + entry->filter=f; + FILTER* band_filters=filters[entry->mode]; + FILTER* band_filter=&band_filters[entry->filter]; + setFilter(band_filter->low,band_filter->high); + gtk_widget_override_background_color(last_filter, GTK_STATE_NORMAL, &white); + last_filter=widget; + gtk_widget_override_background_color(last_filter, GTK_STATE_NORMAL, &gray); + vfo_update(NULL); +} + +static void filter_cb(GtkWidget *widget, gpointer data) { + BANDSTACK_ENTRY *entry=bandstack_entry_get_current(); + FILTER* band_filters=filters[entry->mode]; + GtkWidget *dialog=gtk_dialog_new_with_buttons("Mode",GTK_WINDOW(parent_window),GTK_DIALOG_DESTROY_WITH_PARENT,NULL,NULL); + GtkWidget *content=gtk_dialog_get_content_area(GTK_DIALOG(dialog)); + GtkWidget *grid=gtk_grid_new(); + gtk_grid_set_column_homogeneous(GTK_GRID(grid),TRUE); + gtk_grid_set_row_homogeneous(GTK_GRID(grid),TRUE); + + GtkWidget *b; + int i; + for(i=0;ifilter) { + gtk_widget_override_background_color(b, GTK_STATE_NORMAL, &gray); + last_filter=b; + } else { + gtk_widget_override_background_color(b, GTK_STATE_NORMAL, &white); + } + gtk_widget_show(b); + gtk_grid_attach(GTK_GRID(grid),b,i%5,i/5,1,1); + g_signal_connect(b,"pressed",G_CALLBACK(filter_select_cb),(gpointer *)i); + } + gtk_container_add(GTK_CONTAINER(content),grid); + GtkWidget *close_button=gtk_dialog_add_button(GTK_DIALOG(dialog),"Close",GTK_RESPONSE_OK); + gtk_widget_override_font(close_button, pango_font_description_from_string("Arial 20")); + gtk_widget_show_all(dialog); + + g_signal_connect_swapped (dialog, + "response", + G_CALLBACK (gtk_widget_destroy), + dialog); + + int result=gtk_dialog_run(GTK_DIALOG(dialog)); + +} + +static void agc_select_cb(GtkWidget *widget, gpointer data) { + agc=(int)data; + SetRXAAGCMode(CHANNEL_RX0, agc); +} + +static void agcgain_value_changed_cb(GtkWidget *widget, gpointer data) { + agc_gain=gtk_range_get_value(GTK_RANGE(widget)); + SetRXAAGCTop(CHANNEL_RX0, agc_gain); +} + +void set_agc_gain(double value) { + agc_gain=value; + gtk_range_set_value (GTK_RANGE(agc_scale),agc_gain); + SetRXAAGCTop(CHANNEL_RX0, agc_gain); +} + +static void afgain_value_changed_cb(GtkWidget *widget, gpointer data) { + volume=gtk_range_get_value(GTK_RANGE(widget)); +} + +void set_af_gain(double value) { + volume=value; + gtk_range_set_value (GTK_RANGE(audio_scale),volume); +} + +static void micgain_value_changed_cb(GtkWidget *widget, gpointer data) { + mic_gain=gtk_range_get_value(GTK_RANGE(widget)); +} + +static void nr_cb(GtkWidget *widget, gpointer data) { + nr=nr==0?1:0; + SetRXAANRRun(CHANNEL_RX0, nr); +} + +static void nb_cb(GtkWidget *widget, gpointer data) { + nb=nb==0?1:0; + SetRXAEMNRRun(CHANNEL_RX0, nb); +} + +static void anf_cb(GtkWidget *widget, gpointer data) { + anf=anf==0?1:0; + SetRXAANFRun(CHANNEL_RX0, anf); +} + +static void snb_cb(GtkWidget *widget, gpointer data) { + snb=snb==0?1:0; + SetRXASNBARun(CHANNEL_RX0, snb); +} + +static void linein_cb(GtkWidget *widget, gpointer data) { + if((orion_mic&0x01)==LINE_IN) { + orion_mic=orion_mic&0xFE; + } else { + orion_mic=orion_mic|LINE_IN; + } +} + +static void micboost_cb(GtkWidget *widget, gpointer data) { + if((orion_mic&0x02)==MIC_BOOST) { + orion_mic=orion_mic&0xFD; + } else { + orion_mic=orion_mic|MIC_BOOST; + } +} + +static void byteswap_cb(GtkWidget *widget, gpointer data) { + byte_swap=byte_swap?0:1; +} + +static void ptt_cb(GtkWidget *widget, gpointer data) { + if((orion_mic&0x04)==ORION_MIC_PTT_ENABLED) { + orion_mic=orion_mic|ORION_MIC_PTT_DISABLED; + } else { + orion_mic=orion_mic&0xFB; + } +} + +static void ptt_ring_cb(GtkWidget *widget, gpointer data) { + if((orion_mic&0x08)==ORION_MIC_PTT_RING_BIAS_TIP) { + orion_mic=orion_mic|ORION_MIC_PTT_TIP_BIAS_RING; + } else { + orion_mic=orion_mic&0xF7; + } +} + +static void bias_cb(GtkWidget *widget, gpointer data) { + if((orion_mic&0x10)==ORION_MIC_BIAS_DISABLED) { + orion_mic=orion_mic|ORION_MIC_BIAS_ENABLED; + } else { + orion_mic=orion_mic&0xEF; + } +} + +static void audio_cb(GtkWidget *widget, gpointer data) { + GtkWidget *dialog=gtk_dialog_new_with_buttons("Audio",GTK_WINDOW(parent_window),GTK_DIALOG_DESTROY_WITH_PARENT,NULL,NULL); + + GtkWidget *content=gtk_dialog_get_content_area(GTK_DIALOG(dialog)); + GtkWidget *grid=gtk_grid_new(); + + gtk_grid_set_column_homogeneous(GTK_GRID(grid),TRUE); + gtk_grid_set_row_homogeneous(GTK_GRID(grid),TRUE); + + GtkWidget *b_off=gtk_radio_button_new_with_label(NULL,"Off"); + gtk_widget_override_font(b_off, pango_font_description_from_string("Arial 18")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_off), agc==AGC_OFF); + gtk_widget_show(b_off); + gtk_grid_attach(GTK_GRID(grid),b_off,0,0,2,1); + g_signal_connect(b_off,"pressed",G_CALLBACK(agc_select_cb),(gpointer *)AGC_OFF); + + GtkWidget *b_long=gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(b_off),"Long"); + gtk_widget_override_font(b_long, pango_font_description_from_string("Arial 18")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_long), agc==AGC_LONG); + gtk_widget_show(b_long); + gtk_grid_attach(GTK_GRID(grid),b_long,0,1,2,1); + g_signal_connect(b_long,"pressed",G_CALLBACK(agc_select_cb),(gpointer *)AGC_LONG); + + GtkWidget *b_slow=gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(b_long),"Slow"); + gtk_widget_override_font(b_slow, pango_font_description_from_string("Arial 18")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_slow), agc==AGC_SLOW); + gtk_widget_show(b_slow); + gtk_grid_attach(GTK_GRID(grid),b_slow,0,2,2,1); + g_signal_connect(b_slow,"pressed",G_CALLBACK(agc_select_cb),(gpointer *)AGC_SLOW); + + GtkWidget *b_medium=gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(b_slow),"Medium"); + gtk_widget_override_font(b_medium, pango_font_description_from_string("Arial 18")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_medium), agc==AGC_MEDIUM); + gtk_widget_show(b_medium); + gtk_grid_attach(GTK_GRID(grid),b_medium,0,3,2,1); + g_signal_connect(b_medium,"pressed",G_CALLBACK(agc_select_cb),(gpointer *)AGC_MEDIUM); + + GtkWidget *b_fast=gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(b_medium),"Fast"); + gtk_widget_override_font(b_fast, pango_font_description_from_string("Arial 18")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_fast), agc==AGC_FAST); + gtk_widget_show(b_fast); + gtk_grid_attach(GTK_GRID(grid),b_fast,0,4,2,1); + g_signal_connect(b_fast,"pressed",G_CALLBACK(agc_select_cb),(gpointer *)AGC_FAST); + + + GtkWidget *b_nr=gtk_check_button_new_with_label("NR"); + gtk_widget_override_font(b_nr, pango_font_description_from_string("Arial 18")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_nr), nr==1); + gtk_widget_show(b_nr); + gtk_grid_attach(GTK_GRID(grid),b_nr,2,0,2,1); + g_signal_connect(b_nr,"toggled",G_CALLBACK(nr_cb),NULL); + + GtkWidget *b_nb=gtk_check_button_new_with_label("NB"); + gtk_widget_override_font(b_nb, pango_font_description_from_string("Arial 18")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_nb), nb==1); + gtk_widget_show(b_nb); + gtk_grid_attach(GTK_GRID(grid),b_nb,2,1,2,1); + g_signal_connect(b_nb,"toggled",G_CALLBACK(nb_cb),NULL); + + GtkWidget *b_anf=gtk_check_button_new_with_label("ANF"); + gtk_widget_override_font(b_anf, pango_font_description_from_string("Arial 18")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_anf), anf==1); + gtk_widget_show(b_anf); + gtk_grid_attach(GTK_GRID(grid),b_anf,2,2,2,1); + g_signal_connect(b_anf,"toggled",G_CALLBACK(anf_cb),NULL); + + GtkWidget *b_snb=gtk_check_button_new_with_label("SNB"); + gtk_widget_override_font(b_snb, pango_font_description_from_string("Arial 18")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_snb), snb==1); + gtk_widget_show(b_snb); + gtk_grid_attach(GTK_GRID(grid),b_snb,2,3,2,1); + g_signal_connect(b_snb,"toggled",G_CALLBACK(snb_cb),NULL); + + gtk_container_add(GTK_CONTAINER(content),grid); + GtkWidget *close_button=gtk_dialog_add_button(GTK_DIALOG(dialog),"Close",GTK_RESPONSE_OK); + gtk_widget_override_font(close_button, pango_font_description_from_string("Arial 18")); + gtk_widget_show_all(dialog); + + g_signal_connect_swapped (dialog, + "response", + G_CALLBACK (gtk_widget_destroy), + dialog); + + int result=gtk_dialog_run(GTK_DIALOG(dialog)); + +} + +void set_drive(double value) { + setDrive(value); + gtk_range_set_value (GTK_RANGE(drive_scale),value); +} + +static void drive_value_changed_cb(GtkWidget *widget, gpointer data) { + setDrive(gtk_range_get_value(GTK_RANGE(widget))); +} + +void set_tune(double value) { + setTuneDrive(value); + gtk_range_set_value (GTK_RANGE(tune_scale),value); +} + +static void tune_value_changed_cb(GtkWidget *widget, gpointer data) { + setTuneDrive(gtk_range_get_value(GTK_RANGE(widget))); +} + +static void yes_cb(GtkWidget *widget, gpointer data) { + encoder_close(); + _exit(0); +} + +static void halt_cb(GtkWidget *widget, gpointer data) { + encoder_close(); + system("shutdown -h -P now"); + _exit(0); +} + +static void exit_cb(GtkWidget *widget, gpointer data) { + + radioSaveState(); + saveProperties(property_path); + + GtkWidget *dialog=gtk_dialog_new_with_buttons("Audio",GTK_WINDOW(parent_window),GTK_DIALOG_DESTROY_WITH_PARENT,NULL,NULL); + + GtkWidget *content=gtk_dialog_get_content_area(GTK_DIALOG(dialog)); + GtkWidget *grid=gtk_grid_new(); + + gtk_grid_set_column_homogeneous(GTK_GRID(grid),TRUE); + gtk_grid_set_row_homogeneous(GTK_GRID(grid),TRUE); + + GtkWidget *label=gtk_label_new("Exit?"); + gtk_widget_override_font(label, pango_font_description_from_string("Arial 18")); + gtk_widget_show(label); + gtk_grid_attach(GTK_GRID(grid),label,1,0,1,1); + + GtkWidget *b_yes=gtk_button_new_with_label("Yes (to CLI)"); + gtk_widget_override_font(b_yes, pango_font_description_from_string("Arial 18")); + gtk_widget_show(b_yes); + gtk_grid_attach(GTK_GRID(grid),b_yes,0,1,1,1); + g_signal_connect(b_yes,"pressed",G_CALLBACK(yes_cb),NULL); + + GtkWidget *b_halt=gtk_button_new_with_label("Halt System"); + gtk_widget_override_font(b_halt, pango_font_description_from_string("Arial 18")); + gtk_widget_show(b_halt); + gtk_grid_attach(GTK_GRID(grid),b_halt,2,1,1,1); + g_signal_connect(b_halt,"pressed",G_CALLBACK(halt_cb),NULL); + + gtk_container_add(GTK_CONTAINER(content),grid); + GtkWidget *close_button=gtk_dialog_add_button(GTK_DIALOG(dialog),"Cancel",GTK_RESPONSE_OK); + gtk_widget_override_font(close_button, pango_font_description_from_string("Arial 18")); + gtk_widget_show_all(dialog); + + g_signal_connect_swapped (dialog, + "response", + G_CALLBACK (gtk_widget_destroy), + dialog); + + int result=gtk_dialog_run(GTK_DIALOG(dialog)); + +} + +static void apollo_cb(GtkWidget *widget, gpointer data); + +static void alex_cb(GtkWidget *widget, gpointer data) { +fprintf(stderr,"alex_cb\n"); + if(filter_board==ALEX) { +fprintf(stderr,"alex_cb: was ALEX setting NONE\n"); + filter_board=NONE; + } else if(filter_board==NONE) { +fprintf(stderr,"alex_cb: was NONE setting ALEX\n"); + filter_board=ALEX; + } else if(filter_board==APOLLO) { +fprintf(stderr,"alex_cb: was APOLLO setting ALEX\n"); + GtkWidget *w=(GtkWidget *)data; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), FALSE); + filter_board=ALEX; + } + filter_board_changed(); +} + +static void apollo_cb(GtkWidget *widget, gpointer data) { +fprintf(stderr,"apollo_cb\n"); + if(filter_board==APOLLO) { +fprintf(stderr,"apollo_cb: was APOLLO setting NONE\n"); + filter_board=NONE; + } else if(filter_board==NONE) { +fprintf(stderr,"apollo_cb: was NONE setting APOLLO\n"); + filter_board=APOLLO; + } else if(filter_board==ALEX) { +fprintf(stderr,"apollo_cb: was ALEX setting APOLLO\n"); + GtkWidget *w=(GtkWidget *)data; + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), FALSE); + filter_board=APOLLO; + } + filter_board_changed(); +} + +static void apollo_tuner_cb(GtkWidget *widget, gpointer data) { + apollo_tuner=apollo_tuner==1?0:1; + tuner_changed(); +} + +static void pa_cb(GtkWidget *widget, gpointer data) { + pa=pa==1?0:1; + pa_changed(); +} + +static void cw_keyer_internal_cb(GtkWidget *widget, gpointer data) { + cw_keyer_internal=cw_keyer_internal==1?0:1; + cw_changed(); +} + +static void cw_keyer_speed_value_changed_cb(GtkWidget *widget, gpointer data) { + cw_keyer_speed=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget)); + cw_changed(); +} + +static void cw_breakin_cb(GtkWidget *widget, gpointer data) { + cw_breakin=cw_breakin==1?0:1; + cw_changed(); +} + +static void cw_keyer_hang_time_value_changed_cb(GtkWidget *widget, gpointer data) { + cw_keyer_hang_time=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget)); + cw_changed(); +} + +static void cw_keys_reversed_cb(GtkWidget *widget, gpointer data) { + cw_keys_reversed=cw_keys_reversed==1?0:1; + cw_changed(); +} + +static void cw_keyer_mode_cb(GtkWidget *widget, gpointer data) { + cw_keyer_mode=(int)data; + cw_changed(); +} + +static void config_cb(GtkWidget *widget, gpointer data) { + GtkWidget *dialog=gtk_dialog_new_with_buttons("Audio",GTK_WINDOW(parent_window),GTK_DIALOG_DESTROY_WITH_PARENT,NULL,NULL); + GtkWidget *content=gtk_dialog_get_content_area(GTK_DIALOG(dialog)); + GtkWidget *grid=gtk_grid_new(); + gtk_grid_set_column_homogeneous(GTK_GRID(grid),TRUE); + gtk_grid_set_row_homogeneous(GTK_GRID(grid),TRUE); + + GtkWidget *linein_b=gtk_check_button_new_with_label("Line In"); + gtk_widget_override_font(linein_b, pango_font_description_from_string("Arial 18")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (linein_b), (orion_mic&0x01)==LINE_IN); + gtk_widget_show(linein_b); + gtk_grid_attach(GTK_GRID(grid),linein_b,0,0,1,1); + g_signal_connect(linein_b,"toggled",G_CALLBACK(linein_cb),NULL); + + GtkWidget *micboost_b=gtk_check_button_new_with_label("Boost"); + gtk_widget_override_font(micboost_b, pango_font_description_from_string("Arial 18")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (micboost_b), (orion_mic&0x02)==MIC_BOOST); + gtk_widget_show(micboost_b); + gtk_grid_attach(GTK_GRID(grid),micboost_b,0,1,1,1); + g_signal_connect(micboost_b,"toggled",G_CALLBACK(micboost_cb),NULL); + + GtkWidget *byteswap_b=gtk_check_button_new_with_label("Byte swap"); + gtk_widget_override_font(byteswap_b, pango_font_description_from_string("Arial 18")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (byteswap_b), byte_swap); + gtk_widget_show(byteswap_b); + gtk_grid_attach(GTK_GRID(grid),byteswap_b,0,2,1,1); + g_signal_connect(byteswap_b,"toggled",G_CALLBACK(byteswap_cb),NULL); + + DISCOVERED* d=&discovered[selected_device]; + if(d->device==NEW_DEVICE_ORION) { + GtkWidget *ptt_b=gtk_check_button_new_with_label("PTT Enabled"); + gtk_widget_override_font(ptt_b, pango_font_description_from_string("Arial 18")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ptt_b), (orion_mic&0x04)==ORION_MIC_PTT_ENABLED); + gtk_widget_show(ptt_b); + gtk_grid_attach(GTK_GRID(grid),ptt_b,0,3,1,1); + g_signal_connect(ptt_b,"toggled",G_CALLBACK(ptt_cb),NULL); + + GtkWidget *ptt_ring_b=gtk_check_button_new_with_label("PTT On Ring"); + gtk_widget_override_font(ptt_ring_b, pango_font_description_from_string("Arial 18")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ptt_ring_b), (orion_mic&0x08)==ORION_MIC_PTT_RING_BIAS_TIP); + gtk_widget_show(ptt_ring_b); + gtk_grid_attach(GTK_GRID(grid),ptt_ring_b,0,4,1,1); + g_signal_connect(ptt_ring_b,"toggled",G_CALLBACK(ptt_ring_cb),NULL); + + GtkWidget *bias_b=gtk_check_button_new_with_label("BIAS Enabled"); + gtk_widget_override_font(bias_b, pango_font_description_from_string("Arial 18")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (bias_b), (orion_mic&0x10)==ORION_MIC_BIAS_ENABLED); + gtk_widget_show(bias_b); + gtk_grid_attach(GTK_GRID(grid),bias_b,0,5,1,1); + g_signal_connect(bias_b,"toggled",G_CALLBACK(bias_cb),NULL); + } + + GtkWidget *alex_b=gtk_check_button_new_with_label("ALEX"); + gtk_widget_override_font(alex_b, pango_font_description_from_string("Arial 18")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (alex_b), filter_board==ALEX); + gtk_widget_show(alex_b); + gtk_grid_attach(GTK_GRID(grid),alex_b,1,0,1,1); + + GtkWidget *apollo_b=gtk_check_button_new_with_label("APOLLO"); + gtk_widget_override_font(apollo_b, pango_font_description_from_string("Arial 18")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (apollo_b), filter_board==APOLLO); + gtk_widget_show(apollo_b); + gtk_grid_attach(GTK_GRID(grid),apollo_b,1,1,1,1); + + g_signal_connect(alex_b,"toggled",G_CALLBACK(alex_cb),apollo_b); + g_signal_connect(apollo_b,"toggled",G_CALLBACK(apollo_cb),alex_b); + + GtkWidget *apollo_tuner_b=gtk_check_button_new_with_label("Auto Tuner"); + gtk_widget_override_font(apollo_tuner_b, pango_font_description_from_string("Arial 18")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (apollo_tuner_b), apollo_tuner); + gtk_widget_show(apollo_tuner_b); + gtk_grid_attach(GTK_GRID(grid),apollo_tuner_b,1,2,1,1); + g_signal_connect(apollo_tuner_b,"toggled",G_CALLBACK(apollo_tuner_cb),NULL); + + GtkWidget *pa_b=gtk_check_button_new_with_label("PA"); + gtk_widget_override_font(pa_b, pango_font_description_from_string("Arial 18")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pa_b), pa); + gtk_widget_show(pa_b); + gtk_grid_attach(GTK_GRID(grid),pa_b,1,3,1,1); + g_signal_connect(pa_b,"toggled",G_CALLBACK(pa_cb),NULL); + + gtk_container_add(GTK_CONTAINER(content),grid); + GtkWidget *close_button=gtk_dialog_add_button(GTK_DIALOG(dialog),"Close",GTK_RESPONSE_OK); + gtk_widget_override_font(close_button, pango_font_description_from_string("Arial 18")); + gtk_widget_show_all(dialog); + + g_signal_connect_swapped (dialog, + "response", + G_CALLBACK (gtk_widget_destroy), + dialog); + + int result=gtk_dialog_run(GTK_DIALOG(dialog)); +} + +static void cw_cb(GtkWidget *widget, gpointer data) { + GtkWidget *dialog=gtk_dialog_new_with_buttons("CW",GTK_WINDOW(parent_window),GTK_DIALOG_DESTROY_WITH_PARENT,NULL,NULL); + GtkWidget *content=gtk_dialog_get_content_area(GTK_DIALOG(dialog)); + GtkWidget *grid=gtk_grid_new(); + //gtk_grid_set_column_homogeneous(GTK_GRID(grid),TRUE); + gtk_grid_set_row_homogeneous(GTK_GRID(grid),TRUE); + + + GtkWidget *cw_keyer_internal_b=gtk_check_button_new_with_label("CW Internal - Speed (WPM)"); + gtk_widget_override_font(cw_keyer_internal_b, pango_font_description_from_string("Arial 18")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cw_keyer_internal_b), cw_keyer_internal); + gtk_widget_show(cw_keyer_internal_b); + gtk_grid_attach(GTK_GRID(grid),cw_keyer_internal_b,0,0,1,1); + g_signal_connect(cw_keyer_internal_b,"toggled",G_CALLBACK(cw_keyer_internal_cb),NULL); + + GtkWidget *cw_keyer_speed_b=gtk_spin_button_new_with_range(1.0,60.0,1.0); + gtk_widget_override_font(cw_keyer_speed_b, pango_font_description_from_string("Arial 18")); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(cw_keyer_speed_b),(double)cw_keyer_speed); + gtk_widget_show(cw_keyer_speed_b); + gtk_grid_attach(GTK_GRID(grid),cw_keyer_speed_b,1,0,1,1); + g_signal_connect(cw_keyer_speed_b,"value_changed",G_CALLBACK(cw_keyer_speed_value_changed_cb),NULL); + + GtkWidget *cw_breakin_b=gtk_check_button_new_with_label("CW Break In - Delay (ms)"); + gtk_widget_override_font(cw_breakin_b, pango_font_description_from_string("Arial 18")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cw_breakin_b), cw_breakin); + gtk_widget_show(cw_breakin_b); + gtk_grid_attach(GTK_GRID(grid),cw_breakin_b,0,1,1,1); + g_signal_connect(cw_breakin_b,"toggled",G_CALLBACK(cw_breakin_cb),NULL); + + GtkWidget *cw_keyer_hang_time_b=gtk_spin_button_new_with_range(0.0,1000.0,1.0); + gtk_widget_override_font(cw_keyer_hang_time_b, pango_font_description_from_string("Arial 18")); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(cw_keyer_hang_time_b),(double)cw_keyer_hang_time); + gtk_widget_show(cw_keyer_hang_time_b); + gtk_grid_attach(GTK_GRID(grid),cw_keyer_hang_time_b,1,1,1,1); + g_signal_connect(cw_keyer_hang_time_b,"value_changed",G_CALLBACK(cw_keyer_hang_time_value_changed_cb),NULL); + + GtkWidget *cw_keyer_straight=gtk_radio_button_new_with_label(NULL,"CW KEYER STRAIGHT"); + gtk_widget_override_font(cw_keyer_straight, pango_font_description_from_string("Arial 18")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cw_keyer_straight), cw_keyer_mode==KEYER_STRAIGHT); + gtk_widget_show(cw_keyer_straight); + gtk_grid_attach(GTK_GRID(grid),cw_keyer_straight,0,2,1,1); + g_signal_connect(cw_keyer_straight,"pressed",G_CALLBACK(cw_keyer_mode_cb),(gpointer *)KEYER_STRAIGHT); + + GtkWidget *cw_keyer_mode_a=gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(cw_keyer_straight),"CW KEYER MODE A"); + gtk_widget_override_font(cw_keyer_mode_a, pango_font_description_from_string("Arial 18")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cw_keyer_mode_a), cw_keyer_mode==KEYER_MODE_A); + gtk_widget_show(cw_keyer_mode_a); + gtk_grid_attach(GTK_GRID(grid),cw_keyer_mode_a,0,3,1,1); + g_signal_connect(cw_keyer_mode_a,"pressed",G_CALLBACK(cw_keyer_mode_cb),(gpointer *)KEYER_MODE_A); + + GtkWidget *cw_keyer_mode_b=gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(cw_keyer_mode_a),"CW KEYER MODE B"); + gtk_widget_override_font(cw_keyer_mode_b, pango_font_description_from_string("Arial 18")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cw_keyer_mode_b), cw_keyer_mode==KEYER_MODE_B); + gtk_widget_show(cw_keyer_mode_b); + gtk_grid_attach(GTK_GRID(grid),cw_keyer_mode_b,0,4,1,1); + g_signal_connect(cw_keyer_mode_b,"pressed",G_CALLBACK(cw_keyer_mode_cb),(gpointer *)KEYER_MODE_B); + +/* +int cw_keyer_speed=12; // 1-60 WPM +int cw_keyer_weight=30; // 0-100 +int cw_keyer_spacing=0; // 0=on 1=off +int cw_keyer_sidetone_volume=127; // 0-127 +int cw_keyer_ptt_delay=20; // 0-255ms +int cw_keyer_hang_time=10; // ms +int cw_keyer_sidetone_frequency=400; // Hz +*/ + + gtk_container_add(GTK_CONTAINER(content),grid); + GtkWidget *close_button=gtk_dialog_add_button(GTK_DIALOG(dialog),"Close",GTK_RESPONSE_OK); + gtk_widget_override_font(close_button, pango_font_description_from_string("Arial 18")); + gtk_widget_show_all(dialog); + + g_signal_connect_swapped (dialog, + "response", + G_CALLBACK (gtk_widget_destroy), + dialog); + + int result=gtk_dialog_run(GTK_DIALOG(dialog)); +} + +static void adc_cb(GtkWidget *widget, gpointer data) { + int adc0=adc[0]; + adc[0]=adc[1]; + adc[1]=adc0; + + char label[16]; + gtk_grid_remove_row(GTK_GRID(toolbar_top),0); + + sprintf(label,"RX0=%d",adc[0]); + GtkWidget *rx0=gtk_label_new(label); + gtk_widget_override_font(rx0, pango_font_description_from_string("Arial 16")); + gtk_widget_show(rx0); + gtk_grid_attach(GTK_GRID(toolbar_top),rx0,0,0,1,1); + + sprintf(label,"RX1=%d",adc[1]); + GtkWidget *rx1=gtk_label_new(label); + gtk_widget_override_font(rx1, pango_font_description_from_string("Arial 16")); + gtk_widget_show(rx1); + gtk_grid_attach(GTK_GRID(toolbar_top),rx1,1,0,1,1); +} + +static void lock_cb(GtkWidget *widget, gpointer data) { + locked=locked==1?0:1; + vfo_update(NULL); +} + +static void mox_cb(GtkWidget *widget, gpointer data) { + gtk_grid_remove_row (GTK_GRID(toolbar_top),0); + if(getTune()==1) { + setTune(0); + } + setMox(getMox()==0?1:0); + vfo_update(NULL); + if(getMox()) { + mic_gain_label=gtk_label_new("Mic Gain:"); + gtk_widget_override_font(mic_gain_label, pango_font_description_from_string("Arial 18")); + gtk_widget_show(mic_gain_label); + gtk_grid_attach(GTK_GRID(toolbar_top),mic_gain_label,0,0,1,1); + + mic_scale=gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL,0.0, 1.0, 0.01); + gtk_range_set_value (GTK_RANGE(mic_scale),mic_gain); + gtk_widget_show(mic_scale); + gtk_grid_attach(GTK_GRID(toolbar_top),mic_scale,1,0,2,1); + g_signal_connect(G_OBJECT(mic_scale),"value_changed",G_CALLBACK(micgain_value_changed_cb),NULL); + + GtkWidget *drive_label=gtk_label_new("Drive:"); + gtk_widget_override_font(drive_label, pango_font_description_from_string("Arial 18")); + gtk_widget_show(drive_label); + gtk_grid_attach(GTK_GRID(toolbar_top),drive_label,3,0,1,1); + + drive_scale=gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL,0.0, 1.0, 0.01); + gtk_range_set_value (GTK_RANGE(drive_scale),getDrive()); + gtk_widget_show(drive_scale); + gtk_grid_attach(GTK_GRID(toolbar_top),drive_scale,4,0,2,1); + g_signal_connect(G_OBJECT(drive_scale),"value_changed",G_CALLBACK(drive_value_changed_cb),NULL); + } else { + af_gain_label=gtk_label_new("AF:"); + gtk_widget_override_font(af_gain_label, pango_font_description_from_string("Arial 18")); + gtk_widget_show(af_gain_label); + gtk_grid_attach(GTK_GRID(toolbar_top),af_gain_label,0,0,1,1); + + audio_scale=gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL,0.0, 1.0, 0.01); + gtk_range_set_value (GTK_RANGE(audio_scale),volume); + gtk_widget_show(audio_scale); + gtk_grid_attach(GTK_GRID(toolbar_top),audio_scale,1,0,2,1); + g_signal_connect(G_OBJECT(audio_scale),"value_changed",G_CALLBACK(afgain_value_changed_cb),NULL); + + agc_gain_label=gtk_label_new("AGC:"); + gtk_widget_override_font(agc_gain_label, pango_font_description_from_string("Arial 18")); + gtk_widget_show(agc_gain_label); + gtk_grid_attach(GTK_GRID(toolbar_top),agc_gain_label,3,0,1,1); + + agc_scale=gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL,0.0, 120.0, 1.0); + gtk_range_set_value (GTK_RANGE(agc_scale),agc_gain); + gtk_widget_show(agc_scale); + gtk_grid_attach(GTK_GRID(toolbar_top),agc_scale,4,0,2,1); + g_signal_connect(G_OBJECT(agc_scale),"value_changed",G_CALLBACK(agcgain_value_changed_cb),NULL); + + } + //gtk_widget_queue_draw(toolbar_top); +} + +int ptt_update(void *data) { + BANDSTACK_ENTRY *entry; + entry=bandstack_entry_get_current(); + int ptt=(int)data; + if((entry->mode==modeCWL || entry->mode==modeCWU) && cw_keyer_internal==1) { + if(ptt!= getMox()) { + mox_cb(NULL,NULL); + } + } else { + mox_cb(NULL,NULL); + } + return 0; +} + +static void tune_cb(GtkWidget *widget, gpointer data) { + gtk_grid_remove_row (GTK_GRID(toolbar_top),0); + if(getMox()==1) { + setMox(0); + } + setTune(getTune()==0?1:0); + vfo_update(NULL); + if(getTune()) { + GtkWidget *tune_label=gtk_label_new("Tune Drive:"); + gtk_widget_override_font(tune_label, pango_font_description_from_string("Arial 18")); + gtk_widget_show(tune_label); + gtk_grid_attach(GTK_GRID(toolbar_top),tune_label,0,0,1,1); + + tune_scale=gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL,0.0, 1.0, 0.01); + gtk_range_set_value (GTK_RANGE(tune_scale),getTuneDrive()); + gtk_widget_show(tune_scale); + gtk_grid_attach(GTK_GRID(toolbar_top),tune_scale,1,0,2,1); + g_signal_connect(G_OBJECT(tune_scale),"value_changed",G_CALLBACK(tune_value_changed_cb),NULL); + } else { + af_gain_label=gtk_label_new("AF:"); + gtk_widget_override_font(af_gain_label, pango_font_description_from_string("Arial 18")); + gtk_widget_show(af_gain_label); + gtk_grid_attach(GTK_GRID(toolbar_top),af_gain_label,0,0,1,1); + + audio_scale=gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL,0.0, 1.0, 0.01); + gtk_range_set_value (GTK_RANGE(audio_scale),volume); + gtk_widget_show(audio_scale); + gtk_grid_attach(GTK_GRID(toolbar_top),audio_scale,1,0,2,1); + g_signal_connect(G_OBJECT(audio_scale),"value_changed",G_CALLBACK(afgain_value_changed_cb),NULL); + + agc_gain_label=gtk_label_new("AGC:"); + gtk_widget_override_font(agc_gain_label, pango_font_description_from_string("Arial 18")); + gtk_widget_show(agc_gain_label); + gtk_grid_attach(GTK_GRID(toolbar_top),agc_gain_label,3,0,1,1); + + agc_scale=gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL,0.0, 120.0, 1.0); + gtk_range_set_value (GTK_RANGE(agc_scale),agc_gain); + gtk_widget_show(agc_scale); + gtk_grid_attach(GTK_GRID(toolbar_top),agc_scale,4,0,2,1); + g_signal_connect(G_OBJECT(agc_scale),"value_changed",G_CALLBACK(agcgain_value_changed_cb),NULL); + } +} + +GtkWidget *toolbar_init(int my_width, int my_height, GtkWidget* parent) { + width=my_width; + height=my_height; + parent_window=parent; + + white.red=1.0; + white.green=1.0; + white.blue=1.0; + white.alpha=0.0; + + gray.red=0.25; + gray.green=0.25; + gray.blue=0.25; + gray.alpha=0.0; + + toolbar=gtk_grid_new(); + gtk_widget_set_size_request (toolbar, width, height); + gtk_grid_set_row_homogeneous(GTK_GRID(toolbar), TRUE); + + toolbar_top=gtk_grid_new(); + gtk_grid_set_column_homogeneous(GTK_GRID(toolbar_top),TRUE); + + toolbar_bottom=gtk_grid_new(); + gtk_grid_set_column_homogeneous(GTK_GRID(toolbar_bottom),FALSE); + + GtkWidget *band=gtk_button_new_with_label("Band"); + gtk_widget_override_font(band, pango_font_description_from_string("Arial 20")); + g_signal_connect(G_OBJECT(band),"clicked",G_CALLBACK(band_cb),NULL); + gtk_widget_show(band); + gtk_grid_attach(GTK_GRID(toolbar_bottom),band,column,0,1,1); + column++; + + GtkWidget *mode=gtk_button_new_with_label("Mode"); + gtk_widget_override_font(mode, pango_font_description_from_string("Arial 20")); + g_signal_connect(G_OBJECT(mode),"clicked",G_CALLBACK(mode_cb),NULL); + gtk_widget_show(mode); + gtk_grid_attach(GTK_GRID(toolbar_bottom),mode,column,0,1,1); + column++; + + GtkWidget *filter=gtk_button_new_with_label("Filter"); + gtk_widget_override_font(filter, pango_font_description_from_string("Arial 20")); + g_signal_connect(G_OBJECT(filter),"clicked",G_CALLBACK(filter_cb),NULL); + gtk_widget_show(filter); + gtk_grid_attach(GTK_GRID(toolbar_bottom),filter,column,0,1,1); + column++; + + GtkWidget *audio=gtk_button_new_with_label("Audio"); + gtk_widget_override_font(audio, pango_font_description_from_string("Arial 20")); + g_signal_connect(G_OBJECT(audio),"clicked",G_CALLBACK(audio_cb),NULL); + gtk_widget_show(audio); + gtk_grid_attach(GTK_GRID(toolbar_bottom),audio,column,0,1,1); + column++; + + GtkWidget *config=gtk_button_new_with_label("Config"); + gtk_widget_override_font(config, pango_font_description_from_string("Arial 20")); + g_signal_connect(G_OBJECT(config),"clicked",G_CALLBACK(config_cb),NULL); + gtk_widget_show(config); + gtk_grid_attach(GTK_GRID(toolbar_bottom),config,column,0,1,1); + column++; + + GtkWidget *cw=gtk_button_new_with_label("CW"); + gtk_widget_override_font(cw, pango_font_description_from_string("Arial 20")); + g_signal_connect(G_OBJECT(cw),"clicked",G_CALLBACK(cw_cb),NULL); + gtk_widget_show(cw); + gtk_grid_attach(GTK_GRID(toolbar_bottom),cw,column,0,1,1); + column++; + + GtkWidget *exit=gtk_button_new_with_label("Exit"); + gtk_widget_override_font(exit, pango_font_description_from_string("Arial 20")); + g_signal_connect(G_OBJECT(exit),"clicked",G_CALLBACK(exit_cb),NULL); + gtk_widget_show(exit); + gtk_grid_attach(GTK_GRID(toolbar_bottom),exit,column,0,1,1); + column++; + + GtkWidget *lock=gtk_button_new_with_label("Lock"); + gtk_widget_override_font(lock, pango_font_description_from_string("Arial 20")); + g_signal_connect(G_OBJECT(lock),"clicked",G_CALLBACK(lock_cb),NULL); + gtk_widget_show(lock); + gtk_grid_attach(GTK_GRID(toolbar_bottom),lock,column,0,1,1); + column++; + + GtkWidget *tune=gtk_button_new_with_label("Tune"); + gtk_widget_override_font(tune, pango_font_description_from_string("Arial 20")); + g_signal_connect(G_OBJECT(tune),"clicked",G_CALLBACK(tune_cb),NULL); + gtk_widget_show(tune); + gtk_grid_attach(GTK_GRID(toolbar_bottom),tune,column,0,1,1); + column++; + + GtkWidget *tx=gtk_button_new_with_label("Mox"); + gtk_widget_override_font(tx, pango_font_description_from_string("Arial 20")); + g_signal_connect(G_OBJECT(tx),"clicked",G_CALLBACK(mox_cb),NULL); + gtk_widget_show(tx); + gtk_grid_attach(GTK_GRID(toolbar_bottom),tx,column,0,1,1); + column++; + + + // default to receive controls on top bar + af_gain_label=gtk_label_new("AF:"); + gtk_widget_override_font(af_gain_label, pango_font_description_from_string("Arial 18")); + gtk_widget_show(af_gain_label); + gtk_grid_attach(GTK_GRID(toolbar_top),af_gain_label,0,0,1,1); + + audio_scale=gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL,0.0, 1.0, 0.01); + gtk_range_set_value (GTK_RANGE(audio_scale),volume); + gtk_widget_show(audio_scale); + gtk_grid_attach(GTK_GRID(toolbar_top),audio_scale,1,0,2,1); + g_signal_connect(G_OBJECT(audio_scale),"value_changed",G_CALLBACK(afgain_value_changed_cb),NULL); + + agc_gain_label=gtk_label_new("AGC:"); + gtk_widget_override_font(agc_gain_label, pango_font_description_from_string("Arial 18")); + gtk_widget_show(agc_gain_label); + gtk_grid_attach(GTK_GRID(toolbar_top),agc_gain_label,3,0,1,1); + + agc_scale=gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL,0.0, 120.0, 1.0); + gtk_range_set_value (GTK_RANGE(agc_scale),agc_gain); + gtk_widget_show(agc_scale); + gtk_grid_attach(GTK_GRID(toolbar_top),agc_scale,4,0,2,1); + g_signal_connect(G_OBJECT(agc_scale),"value_changed",G_CALLBACK(agcgain_value_changed_cb),NULL); + +/* + + GtkWidget *drive_label=gtk_label_new("Drive:"); + gtk_widget_override_font(drive_label, pango_font_description_from_string("Arial 18")); + gtk_widget_show(drive_label); + gtk_grid_attach(toolbar_top,drive_label,6,0,1,1); + + drive_scale=gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL,0.0, 1.0, 0.01); + gtk_range_set_value (drive_scale,getTuneDrive()); + gtk_widget_show(drive_scale); + gtk_grid_attach(toolbar_top,drive_scale,7,0,2,1); + g_signal_connect(G_OBJECT(drive_scale),"value_changed",G_CALLBACK(drive_value_changed_cb),NULL); + + GtkWidget *tune_label=gtk_label_new("Tune:"); + gtk_widget_override_font(tune_label, pango_font_description_from_string("Arial 18")); + gtk_widget_show(tune_label); + gtk_grid_attach(toolbar_top,tune_label,9,0,1,1); + + tune_scale=gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL,0.0, 1.0, 0.01); + gtk_range_set_value (tune_scale,getTuneDrive()); + gtk_widget_show(tune_scale); + gtk_grid_attach(toolbar_top,tune_scale,10,0,2,1); + g_signal_connect(G_OBJECT(tune_scale),"value_changed",G_CALLBACK(tune_value_changed_cb),NULL); +*/ + + gtk_grid_attach(GTK_GRID(toolbar),toolbar_top,0,0,1,1); + gtk_widget_show(toolbar_top); + gtk_grid_attach(GTK_GRID(toolbar),toolbar_bottom,0,1,1,1); + gtk_widget_show(toolbar_bottom); + + return toolbar; +} diff --git a/toolbar.h b/toolbar.h new file mode 100644 index 0000000..53c25f3 --- /dev/null +++ b/toolbar.h @@ -0,0 +1,6 @@ +void set_agc_gain(double value); +void set_af_gain(double value); +void set_drive(double drive); +void set_tune(double tune); +int ptt_update(void *data); +GtkWidget *toolbar_init(int my_width, int my_height, GtkWidget* parent); diff --git a/vfo.c b/vfo.c new file mode 100644 index 0000000..648f31d --- /dev/null +++ b/vfo.c @@ -0,0 +1,384 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mode.h" +#include "filter.h" +#include "bandstack.h" +#include "band.h" +#include "new_protocol.h" +#include "rotary_encoder.h" +#include "radio.h" +#include "vfo.h" +#include "channel.h" +#include "wdsp.h" + +static GtkWidget *parent_window; + +static GtkWidget *vfo; +static cairo_surface_t *vfo_surface = NULL; + +static pthread_t rotary_encoder_thread_id; + +static int steps[]={1,10,25,50,100,250,500,1000,2500,5000,6250,9000,10000,12500,15000,20000,25000,30000,50000,100000,0}; +static char *step_labels[]={"1Hz","10Hz","25Hz","50Hz","100Hz","250Hz","500Hz","1kHz","2.5kHz","5kHz","6.25kHz","9kHz","10kHz","12.5kHz","15kHz","20kHz","25kHz","30kHz","50kHz","100kHz",0}; +static int af_function=0; +static int previous_af_function=0; +static int rf_function=0; +static int previous_rf_function=0; +static int band_button=0; +static int previous_band_button=0; + +static GtkWidget* menu=NULL; +static GtkWidget* band_menu=NULL; + +void vfo_step(int steps) { + if(!locked) { + BANDSTACK_ENTRY* entry=bandstack_entry_get_current(); + entry->frequencyA=entry->frequencyA+(steps*step); + setFrequency(entry->frequencyA); + vfo_update(NULL); + } +} + +void vfo_move(int hz) { + if(!locked) { + BANDSTACK_ENTRY* entry=bandstack_entry_get_current(); + entry->frequencyA=(entry->frequencyA+hz)/step*step; + setFrequency(entry->frequencyA); + vfo_update(NULL); + } +} + +static int rotary_encoder_changed(void *data) { + if(!locked) { + int pos=*(int*)data; + BANDSTACK_ENTRY* entry=bandstack_entry_get_current(); + entry->frequencyA=entry->frequencyA+(pos*step); + setFrequency(entry->frequencyA); + vfo_update(NULL); + } + free(data); + return 0; +} + +static int af_encoder_changed(void *data) { + int pos=*(int*)data; + if(pos!=0) { + if(af_function) { + // agc gain + double gain=agc_gain; + gain+=(double)pos; + if(gain<0.0) { + gain=0.0; + } else if(gain>120.0) { + gain=120.0; + } + set_agc_gain(gain); + } else { + // af gain + double gain=volume; + gain+=(double)pos/20.0; + if(gain<0.0) { + gain=0.0; + } else if(gain>1.0) { + gain=1.0; + } + set_af_gain(gain); + } + } + free(data); + return 0; +} + +static int rf_encoder_changed(void *data) { + int pos=*(int*)data; + if(pos!=0) { + if(rf_function) { + // tune drive + double d=getTuneDrive(); + d+=(double)pos/10.0; + if(d<0.0) { + d=0.0; + } else if(d>1.0) { + d=1.0; + } + set_tune(d); + } else { + // drive + double d=getDrive(); + d+=(double)pos/10.0; + if(d<0.0) { + d=0.0; + } else if(d>1.0) { + d=1.0; + } + set_drive(d); + } + } + free(data); + return 0; +} + +static int band_pressed(void *data) { + int function=*(int*)data; + + BANDSTACK_ENTRY *entry; + if(function) { + entry=bandstack_entry_next(); + } else { + int b=band_get_current(); + b++; + if(b>=BANDS) { + b=0; + } + BAND* band=band_set_current(b); + entry=bandstack_entry_get_current(); + } + + setFrequency(entry->frequencyA); + setMode(entry->mode); + FILTER* band_filters=filters[entry->mode]; + FILTER* band_filter=&band_filters[entry->filter]; + setFilter(band_filter->low,band_filter->high); + + BAND *band=band_get_current_band(); + set_alex_rx_antenna(band->alexRxAntenna); + set_alex_tx_antenna(band->alexTxAntenna); + set_alex_attenuation(band->alexAttenuation); + vfo_update(NULL); + + + free(data); + return 0; +} + +static void* rotary_encoder_thread(void *arg) { + int pos; + while(1) { + + pos=vfo_encoder_get_pos(); + if(pos!=0) { + int *p=malloc(sizeof(int)); + *p=pos; + g_idle_add(rotary_encoder_changed,(gpointer)p); + } + + af_function=af_function_get_state(); + if(af_function!=previous_af_function) { + fprintf(stderr,"af_function: %d\n",af_function); + previous_af_function=af_function; + } + pos=af_encoder_get_pos(); + if(pos!=0) { + int *p=malloc(sizeof(int)); + *p=pos; + g_idle_add(af_encoder_changed,(gpointer)p); + } + + rf_function=rf_function_get_state(); + if(rf_function!=previous_rf_function) { + fprintf(stderr,"rf_function: %d\n",rf_function); + previous_rf_function=rf_function; + } + pos=rf_encoder_get_pos(); + if(pos!=0) { + int *p=malloc(sizeof(int)); + *p=pos; + g_idle_add(rf_encoder_changed,(gpointer)p); + } + + int band_button=band_get_state(); + if(band_button!=previous_band_button) { + fprintf(stderr,"band_button: %d\n",band_button); + previous_band_button=band_button; + if(band_button) { + int function=function_get_state(); + g_idle_add(band_pressed,(gpointer)function); + } + } + +#ifdef raspberrypi + gpioDelay(100000); // 10 per second +#endif +#ifdef odroid + usleep(100000); +#endif + } +} + +static gboolean vfo_configure_event_cb (GtkWidget *widget, + GdkEventConfigure *event, + gpointer data) +{ + if (vfo_surface) + cairo_surface_destroy (vfo_surface); + + vfo_surface = gdk_window_create_similar_surface (gtk_widget_get_window (widget), + CAIRO_CONTENT_COLOR, + gtk_widget_get_allocated_width (widget), + gtk_widget_get_allocated_height (widget)); + + /* Initialize the surface to black */ + cairo_t *cr; + cr = cairo_create (vfo_surface); + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + /* We've handled the configure event, no need for further processing. */ + return TRUE; +} + +static gboolean vfo_draw_cb (GtkWidget *widget, + cairo_t *cr, + gpointer data) +{ + cairo_set_source_surface (cr, vfo_surface, 0, 0); + cairo_paint (cr); + + return FALSE; +} + +int vfo_update(void *data) { + BANDSTACK_ENTRY* entry=bandstack_entry_get_current(); + FILTER* band_filters=filters[entry->mode]; + FILTER* band_filter=&band_filters[entry->filter]; + if(vfo_surface) { + cairo_t *cr; + cr = cairo_create (vfo_surface); + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + cairo_select_font_face(cr, "Arial", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_BOLD); + cairo_set_font_size(cr, 36); + + if(isTransmitting()) { + cairo_set_source_rgb(cr, 1, 0, 0); + } else { + cairo_set_source_rgb(cr, 0, 1, 0); + } + + char sf[32]; + sprintf(sf,"%0lld.%06lld MHz %s %s",entry->frequencyA/(long long)1000000,entry->frequencyA%(long long)1000000,mode_string[entry->mode],band_filter->title); + cairo_move_to(cr, 130, 45); + cairo_show_text(cr, sf); + + cairo_set_font_size(cr, 18); + sprintf(sf,"Step %dHz",step); + cairo_move_to(cr, 10, 25); + cairo_show_text(cr, sf); + + if(locked) { + cairo_set_source_rgb(cr, 1, 0, 0); + cairo_move_to(cr, 10, 50); + cairo_show_text(cr, "Locked"); + } + + cairo_destroy (cr); + gtk_widget_queue_draw (vfo); + } + return 0; +} + +static gboolean +vfo_step_select_cb (GtkWidget *widget, + gpointer data) +{ + step=steps[(int)data]; + vfo_update(NULL); +} + +static gboolean +vfo_press_event_cb (GtkWidget *widget, + GdkEventButton *event, + gpointer data) +{ + GtkWidget *dialog=gtk_dialog_new_with_buttons("VFO",GTK_WINDOW(parent_window),GTK_DIALOG_DESTROY_WITH_PARENT,NULL,NULL); + + GtkWidget *content=gtk_dialog_get_content_area(GTK_DIALOG(dialog)); + GtkWidget *grid=gtk_grid_new(); + + gtk_grid_set_column_homogeneous(GTK_GRID(grid),TRUE); + gtk_grid_set_row_homogeneous(GTK_GRID(grid),TRUE); + + GtkWidget *step_rb=NULL; + int i=0; + while(steps[i]!=0) { + if(i==0) { + step_rb=gtk_radio_button_new_with_label(NULL,step_labels[i]); + } else { + step_rb=gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(step_rb),step_labels[i]); + } + gtk_widget_override_font(step_rb, pango_font_description_from_string("Arial 18")); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (step_rb), steps[i]==step); + gtk_widget_show(step_rb); + gtk_grid_attach(GTK_GRID(grid),step_rb,i/5,i%5,1,1); + g_signal_connect(step_rb,"pressed",G_CALLBACK(vfo_step_select_cb),(gpointer *)i); + i++; + } + + gtk_container_add(GTK_CONTAINER(content),grid); + GtkWidget *close_button=gtk_dialog_add_button(GTK_DIALOG(dialog),"Close",GTK_RESPONSE_OK); + gtk_widget_override_font(close_button, pango_font_description_from_string("Arial 18")); + gtk_widget_show_all(dialog); + + g_signal_connect_swapped (dialog, + "response", + G_CALLBACK (gtk_widget_destroy), + dialog); + + int result=gtk_dialog_run(GTK_DIALOG(dialog)); + + return TRUE; +} + +GtkWidget* vfo_init(int width,int height,GtkWidget *parent) { + + parent_window=parent; + + vfo = gtk_drawing_area_new (); + /* set a minimum size */ + gtk_widget_set_size_request (vfo, width, height); + + /* Signals used to handle the backing surface */ + g_signal_connect (vfo, "draw", + G_CALLBACK (vfo_draw_cb), NULL); + g_signal_connect (vfo,"configure-event", + G_CALLBACK (vfo_configure_event_cb), NULL); + + if(encoder_init() == 0) { + int rc=pthread_create(&rotary_encoder_thread_id, NULL, rotary_encoder_thread, NULL); + if(rc<0) { + fprintf(stderr,"pthread_create for rotary_encoder_thread failed %d\n",rc); + } + } else { + fprintf(stderr,"encoder_init failed\n"); + } + + /* Event signals */ + g_signal_connect (vfo, "button-press-event", + G_CALLBACK (vfo_press_event_cb), NULL); + gtk_widget_set_events (vfo, gtk_widget_get_events (vfo) + | GDK_BUTTON_PRESS_MASK); + + BAND *band=band_get_current_band(); + BANDSTACK_ENTRY* entry=bandstack_entry_get_current(); + setFrequency(entry->frequencyA); + setMode(entry->mode); + FILTER* band_filters=filters[entry->mode]; + FILTER* band_filter=&band_filters[entry->filter]; + setFilter(band_filter->low,band_filter->high); + + set_alex_rx_antenna(band->alexRxAntenna); + set_alex_tx_antenna(band->alexTxAntenna); + set_alex_attenuation(band->alexAttenuation); + + return vfo; +} diff --git a/vfo.h b/vfo.h new file mode 100644 index 0000000..22d2da1 --- /dev/null +++ b/vfo.h @@ -0,0 +1,5 @@ + +GtkWidget* vfo_init(int width,int height,GtkWidget *parent); +void vfo_step(int steps); +void vfo_move(int hz); +int vfo_update(void*); diff --git a/waterfall.c b/waterfall.c new file mode 100644 index 0000000..176e868 --- /dev/null +++ b/waterfall.c @@ -0,0 +1,245 @@ + +#include +#include +#include +#include +#include +#include +#include "vfo.h" +#include "new_protocol.h" +#include "waterfall.h" + +static GtkWidget *waterfall; +static GdkPixbuf *pixbuf = NULL; + +static float highThreshold = -100.0f; +static float lowThreshold = -150.0f; + +static int colorLowR=0; // black +static int colorLowG=0; +static int colorLowB=0; + +static int colorMidR=255; // red +static int colorMidG=0; +static int colorMidB=0; + +static int colorHighR=255; // yellow +static int colorHighG=255; +static int colorHighB=0; + + +static gint first_x; +static gint last_x; +static gboolean has_moved=FALSE; +static gboolean pressed=FALSE; + +static gfloat hz_per_pixel; + +#define BANDS 7 + +static long long frequency[BANDS]; +static gint mode[BANDS]; +static gint band=4; + +static int display_width; +static int waterfall_height; + +/* Create a new surface of the appropriate size to store our scribbles */ +static gboolean +waterfall_configure_event_cb (GtkWidget *widget, + GdkEventConfigure *event, + gpointer data) +{ + return TRUE; +} + +/* Redraw the screen from the surface. Note that the ::draw + * signal receives a ready-to-be-used cairo_t that is already + * clipped to only draw the exposed areas of the widget + */ +static gboolean +waterfall_draw_cb (GtkWidget *widget, + cairo_t *cr, + gpointer data) +{ + gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0); + cairo_paint (cr); + return TRUE; +} + +static gboolean +waterfall_button_press_event_cb (GtkWidget *widget, + GdkEventButton *event, + gpointer data) +{ + int x=(int)event->x; + if (event->button == 1) { + last_x=(int)event->x; + has_moved=FALSE; + pressed=TRUE; + } + return TRUE; +} + +static gboolean +waterfall_button_release_event_cb (GtkWidget *widget, + GdkEventButton *event, + gpointer data) +{ + int x=(int)event->x; + if (event->button == 1) { + if(has_moved) { + // drag + vfo_move((int)((float)(x-last_x)*hz_per_pixel)); + } else { + // move to this frequency + vfo_move((int)((float)(x-(display_width/2))*hz_per_pixel)); + } + last_x=x; + pressed=FALSE; + } + return TRUE; +} + +static gboolean +waterfall_motion_notify_event_cb (GtkWidget *widget, + GdkEventMotion *event, + gpointer data) +{ + int x, y; + GdkModifierType state; + gdk_window_get_device_position (event->window, + event->device, + &x, + &y, + &state); + if((state & GDK_BUTTON1_MASK == GDK_BUTTON1_MASK) || pressed) { + int moved=last_x-x; + vfo_move((int)((float)moved*hz_per_pixel)); + last_x=x; + has_moved=TRUE; + } + + return TRUE; +} + +void waterfall_update(float *data) { + + + int i; + + char *pixels = gdk_pixbuf_get_pixels (pixbuf); + + int width=gdk_pixbuf_get_width(pixbuf); + int height=gdk_pixbuf_get_height(pixbuf); + int rowstride=gdk_pixbuf_get_rowstride(pixbuf); + int channels=gdk_pixbuf_get_n_channels(pixbuf); + + memmove(&pixels[rowstride],pixels,(height-1)*rowstride); + + float sample; + int average=0; + char *p; + p=pixels; + for(i=0;ihighThreshold) { + *p++=colorHighR; + *p++=colorHighG; + *p++=colorHighB; + } else { + float range=highThreshold-lowThreshold; + float offset=sample-lowThreshold; + float percent=offset/range; + if(percent<(2.0f/9.0f)) { + float local_percent = percent / (2.0f/9.0f); + *p++ = (int)((1.0f-local_percent)*colorLowR); + *p++ = (int)((1.0f-local_percent)*colorLowG); + *p++ = (int)(colorLowB + local_percent*(255-colorLowB)); + } else if(percent<(3.0f/9.0f)) { + float local_percent = (percent - 2.0f/9.0f) / (1.0f/9.0f); + *p++ = 0; + *p++ = (int)(local_percent*255); + *p++ = 255; + } else if(percent<(4.0f/9.0f)) { + float local_percent = (percent - 3.0f/9.0f) / (1.0f/9.0f); + *p++ = 0; + *p++ = 255; + *p++ = (int)((1.0f-local_percent)*255); + } else if(percent<(5.0f/9.0f)) { + float local_percent = (percent - 4.0f/9.0f) / (1.0f/9.0f); + *p++ = (int)(local_percent*255); + *p++ = 255; + *p++ = 0; + } else if(percent<(7.0f/9.0f)) { + float local_percent = (percent - 5.0f/9.0f) / (2.0f/9.0f); + *p++ = 255; + *p++ = (int)((1.0f-local_percent)*255); + *p++ = 0; + } else if(percent<(8.0f/9.0f)) { + float local_percent = (percent - 7.0f/9.0f) / (1.0f/9.0f); + *p++ = 255; + *p++ = 0; + *p++ = (int)(local_percent*255); + } else { + float local_percent = (percent - 8.0f/9.0f) / (1.0f/9.0f); + *p++ = (int)((0.75f + 0.25f*(1.0f-local_percent))*255.0f); + *p++ = (int)(local_percent*255.0f*0.5f); + *p++ = 255; + } + } + + } + + + lowThreshold=(float)((average/display_width)); + highThreshold=lowThreshold+50.0; + + gtk_widget_queue_draw (waterfall); + +} + +GtkWidget* waterfall_init(int width,int height) { + display_width=width; + waterfall_height=height; + + hz_per_pixel=(double)getSampleRate()/(double)display_width; + + //waterfall_frame = gtk_frame_new (NULL); + waterfall = gtk_drawing_area_new (); + gtk_widget_set_size_request (waterfall, width, height); + + /* Signals used to handle the backing surface */ + g_signal_connect (waterfall, "draw", + G_CALLBACK (waterfall_draw_cb), NULL); + g_signal_connect (waterfall,"configure-event", + G_CALLBACK (waterfall_configure_event_cb), NULL); + + pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, width, height); + + /* Event signals */ + g_signal_connect (waterfall, "motion-notify-event", + G_CALLBACK (waterfall_motion_notify_event_cb), NULL); + g_signal_connect (waterfall, "button-press-event", + G_CALLBACK (waterfall_button_press_event_cb), NULL); + g_signal_connect (waterfall, "button-release-event", + G_CALLBACK (waterfall_button_release_event_cb), NULL); + + /* Ask to receive events the drawing area doesn't normally + * subscribe to. In particular, we need to ask for the + * button press and motion notify events that want to handle. + */ + gtk_widget_set_events (waterfall, gtk_widget_get_events (waterfall) + | GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK + | GDK_BUTTON1_MOTION_MASK + | GDK_POINTER_MOTION_MASK + | GDK_POINTER_MOTION_HINT_MASK); + + return waterfall; +} diff --git a/waterfall.h b/waterfall.h new file mode 100644 index 0000000..7b5e379 --- /dev/null +++ b/waterfall.h @@ -0,0 +1,3 @@ + +void waterfall_update(float *data); +GtkWidget* waterfall_init(int width,int height); diff --git a/xvtr.h b/xvtr.h new file mode 100644 index 0000000..bc948d6 --- /dev/null +++ b/xvtr.h @@ -0,0 +1,56 @@ +/** +* @file xvtr.h +* @brief XVTR definition files +* @author John Melton, G0ORX/N6LYT, Doxygen Comments Dave Larsen, KV0S +* @version 0.1 +* @date 2009-04-11 +*/ +// xvtr.h + +/* Copyright (C) +* This program is free software; you can redistribute it and/or2009 - John Melton, G0ORX/N6LYT, Doxygen Comments Dave Larsen, KV0S +* 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. +* +*/ + +/* --------------------------------------------------------------------------*/ +/** +* @brief XVTR definition +*/ +struct _XVTR_ENTRY { + char name[32]; + long long rxFrequency; + long long rxFrequencyMin; + long long rxFrequencyMax; + long long rxFrequencyLO; + long long txFrequency; + long long txFrequencyMin; + long long txFrequencyMax; + long long txFrequencyLO; + int fullDuplex; + int mode; + int filter; + int var1Low; + int var1High; + int var2Low; + int var2High; + int step; + int preamp; + int alexRxAntenna; + int alexTxAntenna; + int alexAttenuation; +}; + +typedef struct _XVTR_ENTRY XVTR_ENTRY; +