// 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;
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(trim<audio_buffer_size) {
if ((rc = snd_pcm_writei (rx->playback_handle, rx->playback_buffer, audio_buffer_size-trim)) != audio_buffer_size-trim) {
if(rc<0) {
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);
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);
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);
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);
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
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);
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
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);
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);
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) {
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);
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);
int can_transmit=0;
gboolean duplex=FALSE;
+gint rx_height;
void radio_stop() {
if(can_transmit) {
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;
}
}
if(can_transmit) {
- reconfigure_transmitter(transmitter,rx_height);
+ if(!duplex) {
+ reconfigure_transmitter(transmitter,display_width,rx_height);
+ }
}
-
}
static gboolean save_cb(gpointer data) {
y+=MENU_HEIGHT;
- int rx_height=display_height-VFO_HEIGHT;
+ rx_height=display_height-VFO_HEIGHT;
if(display_sliders) {
rx_height-=SLIDERS_HEIGHT;
}
//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;
static void rxtx(int state) {
int i;
- g_print("rxtx: state=%d duplex=%d\n",state,duplex);
if(state) {
// switch to tx
#ifdef FREEDV
// 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);
}
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);
}
void setMox(int state) {
-g_print("setMox: %d\n",state);
if(!can_transmit) return;
vox_cancel(); // remove time-out
if(mox!=state) {
extern int rit_increment;
extern gboolean duplex;
+extern gint rx_height;
extern int lt2208Dither;
extern int lt2208Random;
#include <stdlib.h>
#include <string.h>
+#include "main.h"
#include "new_menu.h"
#include "radio_menu.h"
#include "adc.h"
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();
}
}
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);
+ }
+ }
}
}
#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++;
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);
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));
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)
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));
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");
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));
#include "main.h"
#include "receiver.h"
#include "meter.h"
+#include "filter.h"
#include "mode.h"
#include "property.h"
#include "radio.h"
#define min(x,y) (x<y?x:y)
#define max(x,y) (x<y?y:x)
-static int filterLow;
-static int filterHigh;
-
static int waterfall_samples=0;
static int waterfall_resample=8;
extern void cw_audio_write(double sample);
+static void init_analyzer(TRANSMITTER *tx);
+
+static gboolean delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_data) {
+ // ignore delete event
+ return TRUE;
+}
+
static gint update_out_of_band(gpointer data) {
TRANSMITTER *tx=(TRANSMITTER *)data;
tx->out_of_band=0;
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) {
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);
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);
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,
}
+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);
}
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;
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;
tx->filter_low=tx_filter_low;
tx->filter_high=tx_filter_high;
+ tx->use_rx_filter=FALSE;
tx->out_of_band=0;
// 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);
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);
}
}
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) {
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];
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;
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)
#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;
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;
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) {
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;i<n_input_devices;i++) {
- input=gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(input),input_devices[i].description);
- if(transmitter->microphone_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);
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;i<n_input_devices;i++) {
+ input=gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(input),input_devices[i].description);
+ if(transmitter->microphone_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: ");
#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 */
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);
last_x=(int)event->x;
has_moved=FALSE;
pressed=TRUE;
+ } else {
+ g_idle_add(ext_start_tx,NULL);
}
return TRUE;
}
float *samples;
float saved_max;
float saved_min;
- gfloat saved_hz_per_pixel;
cairo_text_extents_t extents;
if(tx->panadapter_surface) {
}
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;
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);
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)
// 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 {
}
}
- divisor=5000LL;
+#ifdef TX_FREQ_MARKERS
+ //divisor=5000LL;
+ divisor=50000LL;
for(i=0;i<display_width;i++) {
f = frequency - half + (long) (hz_per_pixel * i);
if (f > 0) {
}
}
cairo_stroke(cr);
+#endif
// band edges
long long min_display=frequency-half;
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)
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);
}
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);
-
+*/
}
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;b<bandstack->entries;b++) {
BANDSTACK_ENTRY *entry=&bandstack->entry[b];
entry->frequency=xvtr->frequencyMin+((xvtr->frequencyMax-xvtr->frequencyMin)/2);
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);
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);
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);