From a876dcad17b88519b21e5942a3075fe2140860cc Mon Sep 17 00:00:00 2001 From: John Melton G0ORX Date: Fri, 15 Nov 2019 11:16:49 +0000 Subject: [PATCH] Fixed TX panadapter for duplex/non-duplex. Added 'use_rx_filter' to TX menu. Some cleanup --- audio.c | 12 +++-- configure.c | 21 +++++--- ext.c | 5 ++ ext.h | 1 + new_menu.h | 1 + radio.c | 33 ++++++++----- radio.h | 1 + radio_menu.c | 11 +++++ receiver.c | 20 ++++++-- rx_menu.c | 30 +++++++----- soapy_protocol.c | 17 ++++--- transmitter.c | 125 ++++++++++++++++++++++++++++++++--------------- transmitter.h | 5 +- tx_menu.c | 108 ++++++++++++++++++++++++++++++---------- tx_panadapter.c | 67 ++++++++++++------------- xvtr_menu.c | 9 ++++ 16 files changed, 320 insertions(+), 146 deletions(-) diff --git a/audio.c b/audio.c index 5ca7e39..326124f 100644 --- a/audio.c +++ b/audio.c @@ -368,6 +368,8 @@ fprintf(stderr,"audio delay=%ld trim=%ld\n",delay,trim); // if rx == active_receiver and while transmitting, DO NOTHING // since cw_audio_write may be active // +static int buffers=0; + int audio_write(RECEIVER *rx,short left_sample,short right_sample) { snd_pcm_sframes_t delay; long rc; @@ -397,15 +399,19 @@ int audio_write(RECEIVER *rx,short left_sample,short right_sample) { if(rx->playback_offset==OUTPUT_BUFFER_SIZE) { + buffers++; + trim=0; + int max_delay=audio_buffer_size*4; if(snd_pcm_delay(rx->playback_handle,&delay)==0) { - if(delay>2048) { - trim=delay-2048; -fprintf(stderr,"audio delay=%ld trim=%ld audio_buffer_size=%d\n",delay,trim,audio_buffer_size); + if(delay>max_delay) { + trim=delay-max_delay; +//fprintf(stderr,"audio buffers=%d delay=%ld trim=%ld audio_buffer_size=%d\n",buffers,delay,trim,audio_buffer_size); } } + if(trimplayback_handle, rx->playback_buffer, audio_buffer_size-trim)) != audio_buffer_size-trim) { if(rc<0) { diff --git a/configure.c b/configure.c index e0d0462..05caa2d 100644 --- a/configure.c +++ b/configure.c @@ -187,7 +187,7 @@ static gboolean cancel_cb (GtkWidget *widget, GdkEventButton *event, gpointer da void configure_gpio(GtkWidget *parent) { gpio_restore_state(); - dialog=gtk_dialog_new_with_buttons("Configure GPIO",GTK_WINDOW(parent),GTK_DIALOG_DESTROY_WITH_PARENT,NULL,NULL); + dialog=gtk_dialog_new_with_buttons("Configure GPIO (WiringPi pin numbers)",GTK_WINDOW(parent),GTK_DIALOG_DESTROY_WITH_PARENT,NULL,NULL); GtkWidget *content=gtk_dialog_get_content_area(GTK_DIALOG(dialog)); GtkWidget *grid=gtk_grid_new(); //gtk_grid_set_column_homogeneous(GTK_GRID(grid),TRUE); @@ -285,9 +285,8 @@ void configure_gpio(GtkWidget *parent) { gtk_widget_show(b_enable_E3_pullup); gtk_grid_attach(GTK_GRID(grid),b_enable_E3_pullup,5,y,1,1); - - y++; + b_enable_E4_encoder=gtk_check_button_new_with_label("Enable E4"); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_enable_E4_encoder), ENABLE_E4_ENCODER); gtk_widget_show(b_enable_E4_encoder); @@ -316,8 +315,9 @@ void configure_gpio(GtkWidget *parent) { gtk_widget_show(b_enable_E4_pullup); gtk_grid_attach(GTK_GRID(grid),b_enable_E4_pullup,5,y,1,1); -#if defined (CONTROLLER2_V2) || defined (CONTROLLER2_V1) y++; + +#if defined (CONTROLLER2_V2) || defined (CONTROLLER2_V1) b_enable_E5_encoder=gtk_check_button_new_with_label("Enable E5"); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_enable_E5_encoder), ENABLE_E5_ENCODER); gtk_widget_show(b_enable_E5_encoder); @@ -346,10 +346,11 @@ void configure_gpio(GtkWidget *parent) { gtk_widget_show(b_enable_E5_pullup); gtk_grid_attach(GTK_GRID(grid),b_enable_E5_pullup,5,y,1,1); + y++; + #endif #if !defined (CONTROLLER2_V2) && !defined(CONTROLLER2_V1) - y++; b_enable_mox=gtk_check_button_new_with_label("Enable MOX/TUN"); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_enable_mox), ENABLE_MOX_BUTTON); gtk_widget_show(b_enable_mox); @@ -379,6 +380,7 @@ void configure_gpio(GtkWidget *parent) { gtk_spin_button_set_value (GTK_SPIN_BUTTON(S1),S1_BUTTON); gtk_widget_show(S1); gtk_grid_attach(GTK_GRID(grid),S1,2,y,1,1); + #endif #ifdef LOCALCW @@ -399,10 +401,12 @@ void configure_gpio(GtkWidget *parent) { gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_enable_cwlr), ENABLE_CW_BUTTONS); gtk_widget_show(b_enable_cwlr); gtk_grid_attach(GTK_GRID(grid),b_enable_cwlr,5,y,1,1); + #endif y++; + #if !defined (CONTROLLER2_V2) && !defined (CONTROLLER2_V1) b_enable_S2=gtk_check_button_new_with_label("Enable S2"); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_enable_S2), ENABLE_S2_BUTTON); @@ -417,6 +421,7 @@ void configure_gpio(GtkWidget *parent) { gtk_spin_button_set_value (GTK_SPIN_BUTTON(S2),S2_BUTTON); gtk_widget_show(S2); gtk_grid_attach(GTK_GRID(grid),S2,2,y,1,1); + #endif #ifdef LOCALCW @@ -468,9 +473,9 @@ void configure_gpio(GtkWidget *parent) { gtk_widget_show(b_enable_cws); gtk_grid_attach(GTK_GRID(grid),b_enable_cws,5,y,1,1); #endif - y++; #if !defined (CONTROLLER2_V2) && !defined (CONTROLLER2_V1) + y++; b_enable_S4=gtk_check_button_new_with_label("Enable S4"); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_enable_S4), ENABLE_S4_BUTTON); gtk_widget_show(b_enable_S4); @@ -538,11 +543,11 @@ void configure_gpio(GtkWidget *parent) { GtkWidget *save_b=gtk_button_new_with_label("Save"); g_signal_connect (save_b, "button_press_event", G_CALLBACK(save_cb), NULL); - gtk_grid_attach(GTK_GRID(grid),save_b,4,y-1,1,1); + gtk_grid_attach(GTK_GRID(grid),save_b,4,y,1,1); GtkWidget *cancel_b=gtk_button_new_with_label("Cancel"); g_signal_connect (cancel_b, "button_press_event", G_CALLBACK(cancel_cb), NULL); - gtk_grid_attach(GTK_GRID(grid),cancel_b,5,y-1,1,1); + gtk_grid_attach(GTK_GRID(grid),cancel_b,5,y,1,1); gtk_container_add(GTK_CONTAINER(content),grid); diff --git a/ext.c b/ext.c index b1d115e..58dfff5 100644 --- a/ext.c +++ b/ext.c @@ -554,6 +554,11 @@ int ext_start_rx(void *data) { return 0; } +int ext_start_tx(void *data) { + start_tx(); + return 0; +} + int ext_diversity_update(void *data) { int menu=GPOINTER_TO_INT(data); if(menu) { diff --git a/ext.h b/ext.h index 7be8e67..6c44e2b 100644 --- a/ext.h +++ b/ext.h @@ -102,6 +102,7 @@ int ext_set_attenuation_value(void *data); int ext_set_compression(void *data); int ext_start_rx(void *data); +int ext_start_tx(void *data); int ext_diversity_update(void *data); int ext_sat_update(void *data); int ext_set_rf_gain(void *data); diff --git a/new_menu.h b/new_menu.h index f251aae..3983531 100644 --- a/new_menu.h +++ b/new_menu.h @@ -17,6 +17,7 @@ extern void start_vfo(); extern void start_agc(); extern void start_store(); extern void start_rx(); +extern void start_tx(); extern void start_diversity(); extern void encoder_step(int encoder,int step); diff --git a/radio.c b/radio.c index 925baa3..8175e82 100644 --- a/radio.c +++ b/radio.c @@ -320,6 +320,7 @@ double display_calibration=0.0; int can_transmit=0; gboolean duplex=FALSE; +gint rx_height; void radio_stop() { if(can_transmit) { @@ -338,7 +339,7 @@ void reconfigure_radio() { int i; int y; //fprintf(stderr,"reconfigure_radio: receivers=%d\n",receivers); - int rx_height=display_height-VFO_HEIGHT; + rx_height=display_height-VFO_HEIGHT; if(display_sliders) { rx_height-=SLIDERS_HEIGHT; } @@ -388,9 +389,10 @@ void reconfigure_radio() { } if(can_transmit) { - reconfigure_transmitter(transmitter,rx_height); + if(!duplex) { + reconfigure_transmitter(transmitter,display_width,rx_height); + } } - } static gboolean save_cb(gpointer data) { @@ -799,7 +801,7 @@ void start_radio() { y+=MENU_HEIGHT; - int rx_height=display_height-VFO_HEIGHT; + rx_height=display_height-VFO_HEIGHT; if(display_sliders) { rx_height-=SLIDERS_HEIGHT; } @@ -832,7 +834,11 @@ void start_radio() { //fprintf(stderr,"Create transmitter\n"); if(can_transmit) { - transmitter=create_transmitter(CHANNEL_TX, buffer_size, fft_size, updates_per_second, display_width/3, PANADAPTER_HEIGHT); + if(duplex) { + transmitter=create_transmitter(CHANNEL_TX, buffer_size, fft_size, updates_per_second, display_width/4, display_height/2); + } else { + transmitter=create_transmitter(CHANNEL_TX, buffer_size, fft_size, updates_per_second, display_width, PANADAPTER_HEIGHT); + } transmitter->x=0; transmitter->y=VFO_HEIGHT; @@ -1054,7 +1060,6 @@ void radio_change_sample_rate(int rate) { static void rxtx(int state) { int i; - g_print("rxtx: state=%d duplex=%d\n",state,duplex); if(state) { // switch to tx #ifdef FREEDV @@ -1092,7 +1097,12 @@ static void rxtx(int state) { // gtk_widget_show(audio_waterfall); // } //#endif - gtk_fixed_put(GTK_FIXED(fixed),transmitter->panel,transmitter->x,transmitter->y); + + if(duplex) { + gtk_widget_show_all(transmitter->dialog); + } else { + gtk_fixed_put(GTK_FIXED(fixed),transmitter->panel,transmitter->x,transmitter->y); + } SetChannelState(transmitter->id,1,0); tx_set_displaying(transmitter,1); @@ -1115,9 +1125,11 @@ static void rxtx(int state) { } SetChannelState(transmitter->id,0,1); tx_set_displaying(transmitter,0); - g_object_ref((gpointer)transmitter->panel); - g_object_ref((gpointer)transmitter->panadapter); - gtk_container_remove(GTK_CONTAINER(fixed),transmitter->panel); + if(duplex) { + gtk_widget_hide(transmitter->dialog); + } else { + gtk_container_remove(GTK_CONTAINER(fixed), transmitter->panel); + } //#ifdef FREEDV // if(active_receiver->freedv) { // gtk_widget_hide(audio_waterfall); @@ -1145,7 +1157,6 @@ static void rxtx(int state) { } void setMox(int state) { -g_print("setMox: %d\n",state); if(!can_transmit) return; vox_cancel(); // remove time-out if(mox!=state) { diff --git a/radio.h b/radio.h index de3c11e..04381f8 100644 --- a/radio.h +++ b/radio.h @@ -172,6 +172,7 @@ extern long long step; extern int rit_increment; extern gboolean duplex; +extern gint rx_height; extern int lt2208Dither; extern int lt2208Random; diff --git a/radio_menu.c b/radio_menu.c index 163aa4b..0559c3a 100644 --- a/radio_menu.c +++ b/radio_menu.c @@ -24,6 +24,7 @@ #include #include +#include "main.h" #include "new_menu.h" #include "radio_menu.h" #include "adc.h" @@ -197,6 +198,16 @@ static void split_cb(GtkWidget *widget, gpointer data) { static void duplex_cb(GtkWidget *widget, gpointer data) { duplex=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); + if(duplex) { + gtk_container_remove(GTK_CONTAINER(fixed),transmitter->panel); + reconfigure_transmitter(transmitter,display_width/4,display_height/2); + create_dialog(transmitter); + } else { + GtkWidget *content=gtk_dialog_get_content_area(GTK_DIALOG(transmitter->dialog)); + gtk_container_remove(GTK_CONTAINER(content),transmitter->panel); + gtk_widget_destroy(transmitter->dialog); + reconfigure_transmitter(transmitter,display_width,rx_height); + } vfo_update(); } diff --git a/receiver.c b/receiver.c index d428dfa..de2f4d3 100644 --- a/receiver.c +++ b/receiver.c @@ -1232,18 +1232,32 @@ void receiver_frequency_changed(RECEIVER *rx) { } void receiver_filter_changed(RECEIVER *rx) { + int filter_low, filter_high; int m=vfo[rx->id].mode; if(m==modeFMN) { if(rx->deviation==2500) { - set_filter(rx,-4000,4000); + filter_low=-4000; + filter_high=4000; } else { - set_filter(rx,-8000,8000); + filter_low=-8000; + filter_high=8000; } + set_filter(rx,filter_low,filter_high); set_deviation(rx); } else { FILTER *mode_filters=filters[m]; FILTER *filter=&mode_filters[vfo[rx->id].filter]; - set_filter(rx,filter->low,filter->high); + filter_low=filter->low; + filter_high=filter->high; + set_filter(rx,filter_low,filter_high); + } + + if(can_transmit && transmitter!=NULL) { + if(transmitter->use_rx_filter) { + if(rx==active_receiver) { + tx_set_filter(transmitter,filter_low,filter_high); + } + } } } diff --git a/rx_menu.c b/rx_menu.c index 871e8ae..84c2d91 100644 --- a/rx_menu.c +++ b/rx_menu.c @@ -243,21 +243,29 @@ void rx_menu(GtkWidget *parent) { #ifdef SOAPYSDR case SOAPYSDR_PROTOCOL: { + int row=1; GtkWidget *sample_rate_label=gtk_label_new("Sample Rate"); - gtk_grid_attach(GTK_GRID(grid),sample_rate_label,x,1,1,1); + gtk_grid_attach(GTK_GRID(grid),sample_rate_label,x,row,1,1); + row++; + - char rate[16]; - sprintf(rate,"%d",radio->info.soapy.sample_rate); - GtkWidget *sample_rate=gtk_radio_button_new_with_label(NULL,rate); + char rate_string[16]; + sprintf(rate_string,"%d",radio->info.soapy.sample_rate); + GtkWidget *sample_rate=gtk_radio_button_new_with_label(NULL,rate_string); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (sample_rate), radio->info.soapy.sample_rate); - gtk_grid_attach(GTK_GRID(grid),sample_rate,x,2,1,1); + gtk_grid_attach(GTK_GRID(grid),sample_rate,x,row,1,1); g_signal_connect(sample_rate,"pressed",G_CALLBACK(sample_rate_cb),(gpointer *)radio->info.soapy.sample_rate); - - if(radio->info.soapy.sample_rate>384000) { - GtkWidget *sample_rate_384K=gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(sample_rate),"384000"); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (sample_rate_384K), active_receiver->sample_rate==384000); - gtk_grid_attach(GTK_GRID(grid),sample_rate_384K,x,3,1,1); - g_signal_connect(sample_rate_384K,"pressed",G_CALLBACK(sample_rate_cb),(gpointer *)384000); + row++; + + int rate=radio->info.soapy.sample_rate/2; + while(rate>=48000) { + sprintf(rate_string,"%d",rate); + GtkWidget *next_sample_rate=gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(sample_rate),rate_string); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (next_sample_rate), active_receiver->sample_rate==rate); + gtk_grid_attach(GTK_GRID(grid),next_sample_rate,x,row,1,1); + g_signal_connect(next_sample_rate,"pressed",G_CALLBACK(sample_rate_cb),(gpointer *)rate); + rate=rate/2; + row++; } } x++; diff --git a/soapy_protocol.c b/soapy_protocol.c index fdbaa41..7530d62 100644 --- a/soapy_protocol.c +++ b/soapy_protocol.c @@ -111,6 +111,8 @@ fprintf(stderr,"soapy_protocol_create_receiver: setting samplerate=%f adc=%d\n", fprintf(stderr,"soapy_protocol_create_receiver: SoapySDRDevice_setSampleRate(%f) failed: %s\n",(double)soapy_rx_sample_rate,SoapySDR_errToStr(rc)); } + + size_t channel=rx->adc; #if defined(SOAPY_SDR_API_VERSION) && (SOAPY_SDR_API_VERSION < 0x00080000) fprintf(stderr,"soapy_protocol_create_receiver: SoapySDRDevice_setupStream(version<0x00080000): channel=%ld\n",channel); @@ -142,7 +144,8 @@ fprintf(stderr,"soapy_protocol_create_receiver: max_samples=%d buffer=%p\n",max_ void soapy_protocol_start_receiver(RECEIVER *rx) { int rc; -fprintf(stderr,"soapy_protocol_start_receiver: activate_stream\n"); +double rate=SoapySDRDevice_getSampleRate(soapy_device,SOAPY_SDR_RX,rx->adc); +fprintf(stderr,"soapy_protocol_start_receiver: activate_stream rate=%f\n",rate); rc=SoapySDRDevice_activateStream(soapy_device, rx_stream, 0, 0LL, 0); if(rc!=0) { fprintf(stderr,"soapy_protocol_start_receiver: SoapySDRDevice_activateStream failed: %s\n",SoapySDR_errToStr(rc)); @@ -169,6 +172,7 @@ fprintf(stderr,"soapy_protocol_create_transmitter: setting samplerate=%f\n",(dou fprintf(stderr,"soapy_protocol_configure_transmitter: SoapySDRDevice_setSampleRate(%f) failed: %s\n",(double)tx->iq_output_rate,SoapySDR_errToStr(rc)); } + size_t channel=tx->dac; fprintf(stderr,"soapy_protocol_create_transmitter: SoapySDRDevice_setupStream: channel=%ld\n",channel); #if defined(SOAPY_SDR_API_VERSION) && (SOAPY_SDR_API_VERSION < 0x00080000) @@ -197,7 +201,8 @@ fprintf(stderr,"soapy_protocol_create_transmitter: max_tx_samples=%d\n",max_tx_s void soapy_protocol_start_transmitter(TRANSMITTER *tx) { int rc; -fprintf(stderr,"soapy_protocol_start_transmitter: activateStream\n"); +double rate=SoapySDRDevice_getSampleRate(soapy_device,SOAPY_SDR_TX,tx->dac); +fprintf(stderr,"soapy_protocol_start_transmitter: activateStream rate=%f\n",rate); rc=SoapySDRDevice_activateStream(soapy_device, tx_stream, 0, 0LL, 0); if(rc!=0) { fprintf(stderr,"soapy_protocol_start_transmitter: SoapySDRDevice_activateStream failed: %s\n",SoapySDR_errToStr(rc)); @@ -377,8 +382,9 @@ void soapy_protocol_iq_samples(float isample,float qsample) { long long timeNs=0; long timeoutUs=100000L; if(isTransmitting()) { - output_buffer[output_buffer_index++]=isample; - output_buffer[output_buffer_index++]=qsample; + output_buffer[(output_buffer_index*2)]=isample; + output_buffer[(output_buffer_index*2)+1]=qsample; + output_buffer_index++; if(output_buffer_index>=max_tx_samples) { // write the buffer //g_print("soapy_protocol_iq_samples: writeStream\n"); @@ -432,8 +438,7 @@ void soapy_protocol_set_tx_frequency(TRANSMITTER *tx) { f+=(double)(transmitter->xit); } - -g_print("soapy_protocol_set_tx_frequency: %f\n",f); +//fprintf(stderr,"soapy_protocol_set_tx_frequency: %f\n",f); rc=SoapySDRDevice_setFrequency(soapy_device,SOAPY_SDR_TX,tx->dac,f,NULL); if(rc!=0) { fprintf(stderr,"soapy_protocol: SoapySDRDevice_setFrequency(TX) failed: %s\n",SoapySDR_errToStr(rc)); diff --git a/transmitter.c b/transmitter.c index ec4be79..cc85395 100644 --- a/transmitter.c +++ b/transmitter.c @@ -31,6 +31,7 @@ #include "main.h" #include "receiver.h" #include "meter.h" +#include "filter.h" #include "mode.h" #include "property.h" #include "radio.h" @@ -59,9 +60,6 @@ double getNextInternalSideToneSample(); #define min(x,y) (xout_of_band=0; @@ -138,9 +143,20 @@ void transmitter_set_compressor(TRANSMITTER *tx,int state) { SetTXACompressorRun(tx->id, tx->compressor); } -void reconfigure_transmitter(TRANSMITTER *tx,int height) { -g_print("reconfigure_transmitter: width=%d height=%d\n",tx->width,height); - gtk_widget_set_size_request(tx->panadapter, tx->width, height); +void reconfigure_transmitter(TRANSMITTER *tx,int width,int height) { +g_print("reconfigure_transmitter: width=%d height=%d\n",width,height); + if(width!=tx->width) { + tx->width=width; + tx->height=height; + int ratio=tx->iq_output_rate/tx->mic_sample_rate; +/* + tx->pixels=width*ratio*4; + g_free(tx->pixel_samples); + tx->pixel_samples=g_new(float,tx->pixels); + init_analyzer(tx); +*/ + } + gtk_widget_set_size_request(tx->panadapter, width, height); } void transmitter_save_state(TRANSMITTER *tx) { @@ -156,6 +172,9 @@ void transmitter_save_state(TRANSMITTER *tx) { sprintf(name,"transmitter.%d.filter_high",tx->id); sprintf(value,"%d",tx->filter_high); setProperty(name,value); + sprintf(name,"transmitter.%d.use_rx_filter",tx->id); + sprintf(value,"%d",tx->use_rx_filter); + setProperty(name,value); sprintf(name,"transmitter.%d.alex_antenna",tx->id); sprintf(value,"%d",tx->alex_antenna); setProperty(name,value); @@ -253,6 +272,9 @@ void transmitter_restore_state(TRANSMITTER *tx) { sprintf(name,"transmitter.%d.filter_high",tx->id); value=getProperty(name); if(value) tx->filter_high=atoi(value); + sprintf(name,"transmitter.%d.use_rx_filter",tx->id); + value=getProperty(name); + if(value) tx->use_rx_filter=atoi(value); sprintf(name,"transmitter.%d.alex_antenna",tx->id); value=getProperty(name); if(value) tx->alex_antenna=atoi(value); @@ -521,7 +543,7 @@ static void init_analyzer(TRANSMITTER *tx) { overlap = (int)max(0.0, ceil(fft_size - (double)tx->mic_sample_rate / (double)tx->fps)); - fprintf(stderr,"SetAnalyzer id=%d buffer_size=%d overlap=%d\n",tx->id,tx->output_samples,overlap); + fprintf(stderr,"SetAnalyzer id=%d buffer_size=%d overlap=%d pixels=%d\n",tx->id,tx->output_samples,overlap,tx->pixels); SetAnalyzer(tx->id, @@ -547,9 +569,23 @@ static void init_analyzer(TRANSMITTER *tx) { } +void create_dialog(TRANSMITTER *tx) { +g_print("create_dialog\n"); + tx->dialog=gtk_dialog_new(); + gtk_window_set_transient_for(GTK_WINDOW(tx->dialog),GTK_WINDOW(top_window)); + gtk_window_set_title(GTK_WINDOW(tx->dialog),"TX"); + g_signal_connect (tx->dialog, "delete_event", G_CALLBACK (delete_event), NULL); + GtkWidget *content=gtk_dialog_get_content_area(GTK_DIALOG(tx->dialog)); +g_print("create_dialog: add tx->panel\n"); + gtk_widget_set_size_request (tx->panel, display_width/4, display_height/2); + gtk_container_add(GTK_CONTAINER(content),tx->panel); +} + static void create_visual(TRANSMITTER *tx) { fprintf(stderr,"transmitter: create_visual: id=%d width=%d height=%d\n",tx->id, tx->width,tx->height); + + tx->dialog=NULL; tx->panel=gtk_fixed_new(); gtk_widget_set_size_request (tx->panel, tx->width, tx->height); @@ -560,13 +596,18 @@ static void create_visual(TRANSMITTER *tx) { } gtk_widget_show_all(tx->panel); + g_object_ref((gpointer)tx->panel); + + if(duplex) { + create_dialog(tx); + } } TRANSMITTER *create_transmitter(int id, int buffer_size, int fft_size, int fps, int width, int height) { int rc; - TRANSMITTER *tx=malloc(sizeof(TRANSMITTER)); + TRANSMITTER *tx=g_new(TRANSMITTER,1); tx->id=id; tx->dac=0; tx->buffer_size=buffer_size; @@ -578,34 +619,25 @@ TRANSMITTER *create_transmitter(int id, int buffer_size, int fft_size, int fps, tx->mic_sample_rate=48000; tx->mic_dsp_rate=48000; tx->iq_output_rate=48000; - tx->output_samples=tx->buffer_size; - tx->pixels=width; // to allow 48k to 24k conversion break; case NEW_PROTOCOL: tx->mic_sample_rate=48000; tx->mic_dsp_rate=96000; tx->iq_output_rate=192000; - tx->output_samples=tx->buffer_size*4; - tx->pixels=width*4; // to allow 192k to 24k conversion break; #ifdef SOAPYSDR case SOAPYSDR_PROTOCOL: tx->mic_sample_rate=48000; tx->mic_dsp_rate=96000; tx->iq_output_rate=radio_sample_rate; - tx->output_samples=tx->buffer_size*(tx->iq_output_rate/tx->mic_sample_rate); - tx->pixels=width*(tx->iq_output_rate/tx->mic_sample_rate); -/* - tx->mic_sample_rate=48000; - tx->mic_dsp_rate=48000; - tx->iq_output_rate=48000; - tx->output_samples=tx->buffer_size; - tx->pixels=width; // to allow 48k to 24k conversion -*/ break; #endif } + int ratio=tx->iq_output_rate/tx->mic_sample_rate; + tx->output_samples=tx->buffer_size*ratio; + //tx->pixels=width*ratio*4; + tx->pixels=display_width*ratio*2; tx->width=width; tx->height=height; @@ -623,6 +655,7 @@ fprintf(stderr,"create_transmitter: id=%d buffer_size=%d mic_sample_rate=%d mic_ tx->filter_low=tx_filter_low; tx->filter_high=tx_filter_high; + tx->use_rx_filter=FALSE; tx->out_of_band=0; @@ -664,20 +697,20 @@ fprintf(stderr,"create_transmitter: id=%d buffer_size=%d mic_sample_rate=%d mic_ // allocate buffers fprintf(stderr,"transmitter: allocate buffers: mic_input_buffer=%d iq_output_buffer=%d pixels=%d\n",tx->buffer_size,tx->output_samples,tx->pixels); - tx->mic_input_buffer=malloc(sizeof(double)*2*tx->buffer_size); - tx->iq_output_buffer=malloc(sizeof(double)*2*tx->output_samples); + tx->mic_input_buffer=g_new(double,2*tx->buffer_size); + tx->iq_output_buffer=g_new(double,2*tx->output_samples); tx->samples=0; - tx->pixel_samples=malloc(sizeof(float)*tx->pixels); - if (cw_shape_buffer48) free(cw_shape_buffer48); - if (cw_shape_buffer192) free(cw_shape_buffer192); + tx->pixel_samples=g_new(float,tx->pixels); + if (cw_shape_buffer48) g_free(cw_shape_buffer48); + if (cw_shape_buffer192) g_free(cw_shape_buffer192); // // We need this one both for old and new protocol, since // is is also used to shape the audio samples - cw_shape_buffer48=malloc(sizeof(double)*tx->buffer_size); + cw_shape_buffer48=g_new(double,tx->buffer_size); if (protocol == NEW_PROTOCOL) { // We need this buffer for the new protocol only, where it is only // used to shape the TX envelope - cw_shape_buffer192=malloc(sizeof(double)*tx->output_samples); + cw_shape_buffer192=g_new(double,tx->output_samples); } fprintf(stderr,"transmitter: allocate buffers: mic_input_buffer=%p iq_output_buffer=%p pixels=%p\n",tx->mic_input_buffer,tx->iq_output_buffer,tx->pixel_samples); @@ -770,10 +803,31 @@ fprintf(stderr,"transmitter: allocate buffers: mic_input_buffer=%p iq_output_buf void tx_set_mode(TRANSMITTER* tx,int mode) { if(tx!=NULL) { + int filter_low, filter_high; tx->mode=mode; g_print("tx_set_mode: %s\n",mode_string[tx->mode]); SetTXAMode(tx->id, tx->mode); - tx_set_filter(tx,tx_filter_low,tx_filter_high); + if(tx->use_rx_filter) { + int m=vfo[active_receiver->id].mode; + if(m==modeFMN) { + if(active_receiver->deviation==2500) { + filter_low=-4000; + filter_high=4000; + } else { + filter_low=-8000; + filter_high=8000; + } + } else { + FILTER *mode_filters=filters[m]; + FILTER *filter=&mode_filters[vfo[active_receiver->id].filter]; + filter_low=filter->low; + filter_high=filter->high; + } + } else { + filter_low=tx_filter_low; + filter_high=tx_filter_high; + } + tx_set_filter(tx,filter_low,filter_high); } } @@ -824,16 +878,7 @@ fprintf(stderr,"tx_set_filter: tx=%p mode=%s low=%d high=%d\n",tx,mode_string[mo double fl=tx->filter_low; double fh=tx->filter_high; -/* - if(split) { - fl+=vfo[VFO_B].offset; - fh+=vfo[VFO_B].offset; - } else { - fl+=vfo[VFO_A].offset; - fh+=vfo[VFO_A].offset; - } -*/ - SetTXABandpassFreqs(tx->id, fl,fh); + SetTXABandpassFreqs(tx->id,fl,fh); } void tx_set_pre_emphasize(TRANSMITTER *tx,int state) { @@ -994,7 +1039,7 @@ static void full_tx_buffer(TRANSMITTER *tx) { double is,qs; if(iqswap) { qs=tx->iq_output_buffer[j*2]; - qs=tx->iq_output_buffer[(j*2)+1]; + is=tx->iq_output_buffer[(j*2)+1]; } else { is=tx->iq_output_buffer[j*2]; qs=tx->iq_output_buffer[(j*2)+1]; diff --git a/transmitter.h b/transmitter.h index 83c15a3..08505cd 100644 --- a/transmitter.h +++ b/transmitter.h @@ -48,12 +48,14 @@ typedef struct _transmitter { int mode; int filter_low; int filter_high; + gboolean use_rx_filter; int alex_antenna; int width; int height; + GtkWidget *dialog; GtkWidget *panel; GtkWidget *panadapter; @@ -115,7 +117,8 @@ typedef struct _transmitter { extern TRANSMITTER *create_transmitter(int id, int buffer_size, int fft_size, int fps, int width, int height); -void reconfigure_transmitter(TRANSMITTER *tx,int height); +void create_dialog(TRANSMITTER *tx); +void reconfigure_transmitter(TRANSMITTER *tx,int width,int height); // // CW pulse shaper variables, needed by rigctl (CAT CW) and iambic.c (LOCALCW) diff --git a/tx_menu.c b/tx_menu.c index 2528754..33b2660 100644 --- a/tx_menu.c +++ b/tx_menu.c @@ -25,6 +25,9 @@ #include "sliders.h" #include "transmitter.h" #include "ext.h" +#include "filter.h" +#include "mode.h" +#include "vfo.h" static GtkWidget *parent_window=NULL; static GtkWidget *dialog=NULL; @@ -33,6 +36,8 @@ static GtkWidget *input; static GtkWidget *micin_b=NULL; static GtkWidget *linein_b=NULL; static GtkWidget *micboost_b=NULL; +static GtkWidget *tx_spin_low; +static GtkWidget *tx_spin_high; static GtkWidget *tune_label; static GtkWidget *tune_scale; @@ -110,6 +115,42 @@ static void tune_percent_cb (GtkWidget *widget, gpointer data) { transmitter->tune_percent=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget)); } +static void use_rx_filter_cb(GtkWidget *widget, gpointer data) { + transmitter->use_rx_filter=gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); + int filter_low,filter_high; + + if(transmitter->use_rx_filter) { + int m=vfo[active_receiver->id].mode; + if(m==modeFMN) { + if(active_receiver->deviation==2500) { + filter_low=-4000; + filter_high=4000; + } else { + filter_low=-8000; + filter_high=8000; + } + } else { + FILTER *mode_filters=filters[m]; + FILTER *filter=&mode_filters[vfo[active_receiver->id].filter]; + filter_low=filter->low; + filter_high=filter->high; + } + } else { + filter_low=tx_filter_low; + filter_high=tx_filter_high; + } + + tx_set_filter(transmitter,filter_low,filter_high); + + if(transmitter->use_rx_filter) { + gtk_widget_set_sensitive (tx_spin_low, FALSE); + gtk_widget_set_sensitive (tx_spin_high, FALSE); + } else { + gtk_widget_set_sensitive (tx_spin_low, TRUE); + gtk_widget_set_sensitive (tx_spin_high, TRUE); + } +} + static void local_microphone_cb(GtkWidget *widget, gpointer data) { if(gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) { if(transmitter->microphone_name==NULL) { @@ -262,31 +303,6 @@ void tx_menu(GtkWidget *parent) { row++; col=0; - - if(n_input_devices>0) { - GtkWidget *local_microphone_b=gtk_check_button_new_with_label("Local Microphone Input"); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (local_microphone_b), transmitter->local_microphone); - gtk_widget_show(local_microphone_b); - gtk_grid_attach(GTK_GRID(grid),local_microphone_b,col,row++,2,1); - g_signal_connect(local_microphone_b,"toggled",G_CALLBACK(local_microphone_cb),NULL); - - input=NULL; - for(i=0;imicrophone_name!=NULL) { - if(strcmp(transmitter->microphone_name,input_devices[i].description)==0) { - gtk_combo_box_set_active(GTK_COMBO_BOX(input),i); - } - } - gtk_widget_show(input); - gtk_grid_attach(GTK_GRID(grid),input,col,row++,2,1); - g_signal_connect(input,"pressed",G_CALLBACK(local_input_changed_cb),(gpointer)(long)i); - } - } - - row=1; - col=3; - GtkWidget *label=gtk_label_new("TX Filter: "); #ifdef GTK316 gtk_label_set_xalign(GTK_LABEL(label),0); @@ -295,20 +311,58 @@ void tx_menu(GtkWidget *parent) { col++; - GtkWidget *tx_spin_low=gtk_spin_button_new_with_range(0.0,8000.0,1.0); + GtkWidget *use_rx_filter_b=gtk_check_button_new_with_label("Use RX filter"); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (use_rx_filter_b), transmitter->use_rx_filter); + gtk_widget_show(use_rx_filter_b); + gtk_grid_attach(GTK_GRID(grid),use_rx_filter_b,col,row,1,1); + g_signal_connect(use_rx_filter_b,"toggled",G_CALLBACK(use_rx_filter_cb),NULL); + + col++; + + tx_spin_low=gtk_spin_button_new_with_range(0.0,8000.0,1.0); gtk_spin_button_set_value(GTK_SPIN_BUTTON(tx_spin_low),(double)tx_filter_low); gtk_grid_attach(GTK_GRID(grid),tx_spin_low,col,row,1,1); g_signal_connect(tx_spin_low,"value-changed",G_CALLBACK(tx_spin_low_cb),NULL); + if(transmitter->use_rx_filter) { + gtk_widget_set_sensitive (tx_spin_low, FALSE); + } col++; - GtkWidget *tx_spin_high=gtk_spin_button_new_with_range(0.0,8000.0,1.0); + tx_spin_high=gtk_spin_button_new_with_range(0.0,8000.0,1.0); gtk_spin_button_set_value(GTK_SPIN_BUTTON(tx_spin_high),(double)tx_filter_high); gtk_grid_attach(GTK_GRID(grid),tx_spin_high,col,row,1,1); g_signal_connect(tx_spin_high,"value-changed",G_CALLBACK(tx_spin_high_cb),NULL); + if(transmitter->use_rx_filter) { + gtk_widget_set_sensitive (tx_spin_high, FALSE); + } row++; + col=0; + + int saved_row=row; + + if(n_input_devices>0) { + GtkWidget *local_microphone_b=gtk_check_button_new_with_label("Local Microphone Input"); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (local_microphone_b), transmitter->local_microphone); + gtk_widget_show(local_microphone_b); + gtk_grid_attach(GTK_GRID(grid),local_microphone_b,col,row++,2,1); + g_signal_connect(local_microphone_b,"toggled",G_CALLBACK(local_microphone_cb),NULL); + + input=NULL; + for(i=0;imicrophone_name!=NULL) { + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(input),strcmp(transmitter->microphone_name,input_devices[i].description)==0); + } + gtk_widget_show(input); + gtk_grid_attach(GTK_GRID(grid),input,col,row++,2,1); + g_signal_connect(input,"pressed",G_CALLBACK(local_input_changed_cb),(gpointer)(long)i); + } + } + + row=saved_row; col=3; GtkWidget *panadapter_high_label=gtk_label_new("Panadapter High: "); diff --git a/tx_panadapter.c b/tx_panadapter.c index 04b86bd..d764e51 100644 --- a/tx_panadapter.c +++ b/tx_panadapter.c @@ -41,15 +41,16 @@ #ifdef GPIO #include "gpio.h" #endif - +#include "ext.h" +#include "new_menu.h" static gint last_x; static gboolean has_moved=FALSE; static gboolean pressed=FALSE; -static gfloat hz_per_pixel; -static gfloat filter_left; -static gfloat filter_right; +static gdouble hz_per_pixel; +static gdouble filter_left=0.0; +static gdouble filter_right=0.0; /* Create a new surface of the appropriate size to store our scribbles */ @@ -62,7 +63,6 @@ tx_panadapter_configure_event_cb (GtkWidget *widget, int display_width=gtk_widget_get_allocated_width (tx->panadapter); int display_height=gtk_widget_get_allocated_height (tx->panadapter); -g_print("tx_panadapter_configure_event_cb: width=%d height=%d\n",display_width,display_height); if (tx->panadapter_surface) cairo_surface_destroy (tx->panadapter_surface); @@ -105,6 +105,8 @@ tx_panadapter_button_press_event_cb (GtkWidget *widget, last_x=(int)event->x; has_moved=FALSE; pressed=TRUE; + } else { + g_idle_add(ext_start_tx,NULL); } return TRUE; } @@ -182,7 +184,6 @@ void tx_panadapter_update(TRANSMITTER *tx) { float *samples; float saved_max; float saved_min; - gfloat saved_hz_per_pixel; cairo_text_extents_t extents; if(tx->panadapter_surface) { @@ -197,9 +198,7 @@ void tx_panadapter_update(TRANSMITTER *tx) { } samples=tx->pixel_samples; - //hz_per_pixel=(double)tx->output_rate/(double)display_width; - //hz_per_pixel=24000.0/(double)display_width; - hz_per_pixel=48000.0/(double)display_width; + hz_per_pixel=(double)tx->iq_output_rate/(double)tx->pixels; //clear_panadater_surface(); cairo_t *cr; @@ -207,6 +206,7 @@ void tx_panadapter_update(TRANSMITTER *tx) { cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); cairo_paint (cr); + // filter if (vfo[id].mode != modeCWU && vfo[id].mode != modeCWL) { cairo_set_source_rgb (cr, 0.25, 0.25, 0.25); @@ -214,6 +214,7 @@ void tx_panadapter_update(TRANSMITTER *tx) { filter_right=(double)display_width/2.0+((double)tx->filter_high/hz_per_pixel); cairo_rectangle(cr, filter_left, 0.0, filter_right-filter_left, (double)display_height); cairo_fill(cr); + } // plot the levels 0, -20, 40, ... dBm (green line with label) @@ -249,10 +250,9 @@ void tx_panadapter_update(TRANSMITTER *tx) { // plot frequency markers long long f; long long divisor=20000; - //long long half=12000LL; //(long long)(tx->output_rate/2); - long long half=24000LL; //(long long)(tx->output_rate/2); + //long long half=24000LL; //(long long)(tx->output_rate/2); + long long half=6000LL; //(long long)(tx->output_rate/2); long long frequency; - //frequency=vfo[id].frequency+vfo[id].offset; if(vfo[id].ctun) { frequency=vfo[id].ctun_frequency-vfo[id].lo_tx; } else { @@ -269,7 +269,9 @@ void tx_panadapter_update(TRANSMITTER *tx) { } } - divisor=5000LL; +#ifdef TX_FREQ_MARKERS + //divisor=5000LL; + divisor=50000LL; for(i=0;i 0) { @@ -294,6 +296,7 @@ void tx_panadapter_update(TRANSMITTER *tx) { } } cairo_stroke(cr); +#endif // band edges long long min_display=frequency-half; @@ -332,21 +335,7 @@ void tx_panadapter_update(TRANSMITTER *tx) { samples[0]=-200.0; samples[display_width-1]=-200.0; - int offset=0; - - switch(protocol) { - case ORIGINAL_PROTOCOL: - offset=0; - break; - case NEW_PROTOCOL: - offset=(tx->pixels/8)*3; - break; -#ifdef SOAPYSDR - case SOAPYSDR_PROTOCOL: - offset=(tx->pixels/16)*7; - break; -#endif - } + int offset=(tx->pixels/2)-(display_width/2); s1=(double)samples[0+offset]; s1 = floor((tx->panadapter_high - s1) @@ -420,17 +409,18 @@ void tx_panadapter_update(TRANSMITTER *tx) { if(duplex) { char text[64]; cairo_set_source_rgb(cr,1.0,0.0,0.0); + cairo_set_font_size(cr, 16); - sprintf(text,"FWD: %f",transmitter->fwd); - cairo_move_to(cr,10,display_height-40); + sprintf(text,"FWD: %0.3f",transmitter->fwd); + cairo_move_to(cr,10,15); cairo_show_text(cr, text); - sprintf(text,"REV: %f",transmitter->rev); - cairo_move_to(cr,10,display_height-30); + sprintf(text,"REV: %0.3f",transmitter->rev); + cairo_move_to(cr,10,30); cairo_show_text(cr, text); - sprintf(text,"ALC: %f",transmitter->alc); - cairo_move_to(cr,10,display_height-20); + sprintf(text,"ALC: %0.3f",transmitter->alc); + cairo_move_to(cr,10,45); cairo_show_text(cr, text); } @@ -455,25 +445,30 @@ fprintf(stderr,"tx_panadapter_init: %d x %d\n",width,height); G_CALLBACK (tx_panadapter_configure_event_cb), tx); /* Event signals */ +/* g_signal_connect (tx->panadapter, "motion-notify-event", G_CALLBACK (tx_panadapter_motion_notify_event_cb), tx); +*/ g_signal_connect (tx->panadapter, "button-press-event", G_CALLBACK (tx_panadapter_button_press_event_cb), tx); +/* g_signal_connect (tx->panadapter, "button-release-event", G_CALLBACK (tx_panadapter_button_release_event_cb), tx); g_signal_connect(tx->panadapter,"scroll_event", G_CALLBACK(tx_panadapter_scroll_event_cb),tx); +*/ /* 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 (tx->panadapter, gtk_widget_get_events (tx->panadapter) - | GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_PRESS_MASK); +/* | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON1_MOTION_MASK | GDK_SCROLL_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK); - +*/ } diff --git a/xvtr_menu.c b/xvtr_menu.c index 5d5534a..f584e8d 100644 --- a/xvtr_menu.c +++ b/xvtr_menu.c @@ -68,11 +68,16 @@ static void save_xvtr () { xvtr->frequencyLO=(long long)(atof(lof)*1000000.0); loerr=gtk_entry_get_text(GTK_ENTRY(lo_error[i])); xvtr->errorLO=atoll(loerr); +/* txlof=gtk_entry_get_text(GTK_ENTRY(tx_lo_frequency[i])); xvtr->txFrequencyLO=(long long)(atof(txlof)*1000000.0); txloerr=gtk_entry_get_text(GTK_ENTRY(tx_lo_error[i])); xvtr->txErrorLO=atoll(txloerr); +*/ + xvtr->txFrequencyLO=0LL; + xvtr->txErrorLO=0LL; xvtr->disablePA=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(disable_pa[i])); + for(b=0;bentries;b++) { BANDSTACK_ENTRY *entry=&bandstack->entry[b]; entry->frequency=xvtr->frequencyMin+((xvtr->frequencyMax-xvtr->frequencyMin)/2); @@ -243,10 +248,12 @@ fprintf(stderr,"xvtr_menu\n"); gtk_grid_attach(GTK_GRID(grid),label,3,1,1,1); label=gtk_label_new("LO Err(Hz)"); gtk_grid_attach(GTK_GRID(grid),label,4,1,1,1); +/* label=gtk_label_new("TX LO Freq(MHz)"); gtk_grid_attach(GTK_GRID(grid),label,5,1,1,1); label=gtk_label_new("TX LO Err(Hz)"); gtk_grid_attach(GTK_GRID(grid),label,6,1,1,1); +*/ label=gtk_label_new("Disable PA"); gtk_grid_attach(GTK_GRID(grid),label,7,1,1,1); @@ -287,6 +294,7 @@ fprintf(stderr,"xvtr_menu\n"); gtk_grid_attach(GTK_GRID(grid),lo_error[i],4,i+2,1,1); g_signal_connect(lo_error[i],"changed",G_CALLBACK(lo_error_cb),GINT_TO_POINTER(i)); +/* tx_lo_frequency[i]=gtk_entry_new(); gtk_entry_set_width_chars(GTK_ENTRY(tx_lo_frequency[i]),7); sprintf(f,"%5.3f",(double)xvtr->txFrequencyLO/1000000.0); @@ -300,6 +308,7 @@ fprintf(stderr,"xvtr_menu\n"); gtk_entry_set_text(GTK_ENTRY(tx_lo_error[i]),f); gtk_grid_attach(GTK_GRID(grid),tx_lo_error[i],6,i+2,1,1); g_signal_connect(tx_lo_error[i],"changed",G_CALLBACK(tx_lo_error_cb),GINT_TO_POINTER(i)); +*/ disable_pa[i]=gtk_check_button_new(); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(disable_pa[i]),xvtr->disablePA); -- 2.45.2