static GtkWidget *b_cw_active_low;
#endif
+#ifdef PTT
+static GtkWidget *ptt_label;
+static GtkWidget *ptt;
+static GtkWidget *b_enable_ptt;
+static GtkWidget *b_ptt_active_low;
+#endif
+
static gboolean save_cb (GtkWidget *widget, GdkEventButton *event, gpointer data) {
if(dialog!=NULL) {
ENABLE_VFO_ENCODER=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_vfo_encoder))?1:0;
ENABLE_E4_PULLUP=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_E4_pullup))?1:0;
E4_FUNCTION=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(E4_sw));
- if(controller==CONTROLLER2_V1 || controller==CONTROLLER2_V2 || controller==CUSTOM_CONTROLLER) {
+ if(controller==CONTROLLER2_V1 || controller==CONTROLLER2_V2) {
ENABLE_E5_ENCODER=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_E5_encoder))?1:0;
E5_ENCODER_A=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(E5_a));
E5_ENCODER_B=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(E5_b));
SIDETONE_GPIO=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(cws));
#endif
+#ifdef PTT
+ ENABLE_PTT_GPIO=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_enable_ptt))?1:0;
+ PTT_ACTIVE_LOW=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b_ptt_active_low))?1:0;
+ PTT_GPIO=gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(ptt));
+#endif
+
gpio_save_state();
gtk_widget_destroy(dialog);
}
// Encoders
GtkWidget *grid1=gtk_grid_new();
- gtk_grid_set_column_spacing (GTK_GRID(grid1),10);
+ gtk_grid_set_column_homogeneous(GTK_GRID(grid1),FALSE);
+ gtk_grid_set_row_homogeneous(GTK_GRID(grid1),TRUE);
+ gtk_grid_set_column_spacing (GTK_GRID(grid1),5);
row=0;
b_enable_vfo_encoder=gtk_check_button_new_with_label("Enable VFO");
row++;
- if(controller==CONTROLLER2_V1 || controller==CONTROLLER2_V2 || controller==CUSTOM_CONTROLLER) {
+ if(controller==CONTROLLER2_V1 || controller==CONTROLLER2_V2) {
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_notebook_append_page(GTK_NOTEBOOK(notebook),grid3,gtk_label_new("CW"));
#endif
+#ifdef PTT
+ GtkWidget *grid4=gtk_grid_new();
+ gtk_grid_set_column_spacing (GTK_GRID(grid4),10);
+ row=0;
+
+ b_enable_ptt=gtk_check_button_new_with_label("PTT Enable");
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_enable_ptt), ENABLE_PTT_GPIO);
+ gtk_widget_show(b_enable_ptt);
+ gtk_grid_attach(GTK_GRID(grid4),b_enable_ptt,0,row,1,1);
+
+ row++;
+
+ ptt_label=gtk_label_new("PTT GPIO:");
+ gtk_widget_show(ptt_label);
+ gtk_grid_attach(GTK_GRID(grid4),ptt_label,0,row,1,1);
+
+ ptt=gtk_spin_button_new_with_range (0.0,100.0,1.0);
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON(ptt),CWR_BUTTON);
+ gtk_widget_show(ptt);
+ gtk_grid_attach(GTK_GRID(grid4),ptt,1,row,1,1);
+
+ row++;
+
+ b_ptt_active_low=gtk_check_button_new_with_label("PTT active-low");
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_ptt_active_low), PTT_ACTIVE_LOW);
+ gtk_widget_show(b_ptt_active_low);
+ gtk_grid_attach(GTK_GRID(grid4),b_ptt_active_low,0,row,1,1);
+
+ gtk_notebook_append_page(GTK_NOTEBOOK(notebook),grid4,gtk_label_new("PTT"));
+#endif
+
gtk_grid_attach(GTK_GRID(grid0),notebook,0,1,6,1);
gtk_container_add(GTK_CONTAINER(content),grid0);
static char ipaddr_tcp_buf[IPADDR_LEN] = "10.10.10.10";
char *ipaddr_tcp = &ipaddr_tcp_buf[0];
+#ifdef SERVER
+GtkWidget *connect_addr_entry;
+static char connect_addr_buffer[30]="0.0.0.0:50000";
+char *connect_addr = &connect_addr_buffer[0];
+#endif
+
static gboolean delete_event_cb(GtkWidget *widget, GdkEvent *event, gpointer data) {
_exit(0);
}
return TRUE;
}
+#ifdef SERVER
+static gboolean connect_cb (GtkWidget *widget, GdkEventButton *event, gpointer data) {
+ // connect to remote host running piHPSDR
+ strncpy(connect_addr, gtk_entry_get_text(GTK_ENTRY(connect_addr_entry)), 30);
+g_print("connect_cb: %s\n",connect_addr);
+ return TRUE;
+}
+#endif
+
void discovery() {
//fprintf(stderr,"discovery\n");
//gtk_grid_set_column_homogeneous(GTK_GRID(grid),TRUE);
gtk_grid_set_row_spacing (GTK_GRID(grid),10);
- int i;
+ int row;
char version[16];
char text[256];
- for(i=0;i<devices;i++) {
- d=&discovered[i];
+ for(row=0;row<devices;row++) {
+ d=&discovered[row];
fprintf(stderr,"%p Protocol=%d name=%s\n",d,d->protocol,d->name);
sprintf(version,"v%d.%d",
d->software_version/10,
gtk_widget_override_font(label, pango_font_description_from_string("Sans 11"));
gtk_widget_set_halign (label, GTK_ALIGN_START);
gtk_widget_show(label);
- gtk_grid_attach(GTK_GRID(grid),label,0,i,3,1);
+ gtk_grid_attach(GTK_GRID(grid),label,0,row,3,1);
GtkWidget *start_button=gtk_button_new_with_label("Start");
gtk_widget_override_font(start_button, pango_font_description_from_string("Sans 16"));
gtk_widget_show(start_button);
- gtk_grid_attach(GTK_GRID(grid),start_button,3,i,1,1);
+ gtk_grid_attach(GTK_GRID(grid),start_button,3,row,1,1);
g_signal_connect(start_button,"button_press_event",G_CALLBACK(start_cb),(gpointer)d);
// if not available then cannot start it
gtk_button_set_label(GTK_BUTTON(start_button), "Not installed");
gtk_widget_set_sensitive(start_button, FALSE);
} else {
- apps_combobox[i] = gtk_combo_box_text_new();
- gtk_widget_override_font(apps_combobox[i], pango_font_description_from_string("Sans 11"));
+ apps_combobox[row] = gtk_combo_box_text_new();
+ gtk_widget_override_font(apps_combobox[row], pango_font_description_from_string("Sans 11"));
// We want the default selection priority for the STEMlab app to be
// RP-Trx > HAMlab-Trx > Pavel-Trx > Pavel-Rx, so we add in decreasing order and
// always set the newly added entry to be active.
if ((d->software_version & STEMLAB_PAVEL_RX) != 0) {
- gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(apps_combobox[i]),
+ gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(apps_combobox[row]),
"sdr_receiver_hpsdr", "Pavel-Rx");
- gtk_combo_box_set_active_id(GTK_COMBO_BOX(apps_combobox[i]),
+ gtk_combo_box_set_active_id(GTK_COMBO_BOX(apps_combobox[row]),
"sdr_receiver_hpsdr");
}
if ((d->software_version & STEMLAB_PAVEL_TRX) != 0) {
- gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(apps_combobox[i]),
+ gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(apps_combobox[row]),
"sdr_transceiver_hpsdr", "Pavel-Trx");
- gtk_combo_box_set_active_id(GTK_COMBO_BOX(apps_combobox[i]),
+ gtk_combo_box_set_active_id(GTK_COMBO_BOX(apps_combobox[row]),
"sdr_transceiver_hpsdr");
}
if ((d->software_version & HAMLAB_RP_TRX) != 0) {
- gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(apps_combobox[i]),
+ gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(apps_combobox[row]),
"hamlab_sdr_transceiver_hpsdr", "HAMlab-Trx");
- gtk_combo_box_set_active_id(GTK_COMBO_BOX(apps_combobox[i]),
+ gtk_combo_box_set_active_id(GTK_COMBO_BOX(apps_combobox[row]),
"hamlab_sdr_transceiver_hpsdr");
}
if ((d->software_version & STEMLAB_RP_TRX) != 0) {
- gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(apps_combobox[i]),
+ gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(apps_combobox[row]),
"stemlab_sdr_transceiver_hpsdr", "STEMlab-Trx");
- gtk_combo_box_set_active_id(GTK_COMBO_BOX(apps_combobox[i]),
+ gtk_combo_box_set_active_id(GTK_COMBO_BOX(apps_combobox[row]),
"stemlab_sdr_transceiver_hpsdr");
}
- gtk_widget_show(apps_combobox[i]);
- gtk_grid_attach(GTK_GRID(grid), apps_combobox[i], 4, i, 1, 1);
+ gtk_widget_show(apps_combobox[row]);
+ gtk_grid_attach(GTK_GRID(grid), apps_combobox[row], 4, i, 1, 1);
}
}
#endif
gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(gpio),NULL,"Controller1");
gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(gpio),NULL,"Controller2 V1");
gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(gpio),NULL,"Controller2 V2");
- gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(gpio),NULL,"Custom");
- gtk_grid_attach(GTK_GRID(grid),gpio,0,i,1,1);
+ gtk_grid_attach(GTK_GRID(grid),gpio,0,row,1,1);
gtk_combo_box_set_active(GTK_COMBO_BOX(gpio),controller);
g_signal_connect(gpio,"changed",G_CALLBACK(gpio_changed_cb),NULL);
GtkWidget *discover_b=gtk_button_new_with_label("Discover");
g_signal_connect (discover_b, "button-press-event", G_CALLBACK(discover_cb), NULL);
- gtk_grid_attach(GTK_GRID(grid),discover_b,1,i,1,1);
+ gtk_grid_attach(GTK_GRID(grid),discover_b,1,row,1,1);
GtkWidget *protocols_b=gtk_button_new_with_label("Protocols");
g_signal_connect (protocols_b, "button-press-event", G_CALLBACK(protocols_cb), NULL);
- gtk_grid_attach(GTK_GRID(grid),protocols_b,2,i,1,1);
+ gtk_grid_attach(GTK_GRID(grid),protocols_b,2,row,1,1);
#ifdef MIDI
GtkWidget *midi_b=gtk_button_new_with_label("ImportMIDI");
g_signal_connect (midi_b, "button-press-event", G_CALLBACK(midi_cb), NULL);
- gtk_grid_attach(GTK_GRID(grid),midi_b,3,i,1,1);
+ gtk_grid_attach(GTK_GRID(grid),midi_b,3,row,1,1);
#endif
- i++;
+ row++;
#ifdef GPIO
GtkWidget *gpio_b=gtk_button_new_with_label("Configure GPIO");
g_signal_connect (gpio_b, "button-press-event", G_CALLBACK(gpio_cb), NULL);
- gtk_grid_attach(GTK_GRID(grid),gpio_b,0,i,1,1);
+ gtk_grid_attach(GTK_GRID(grid),gpio_b,0,row,1,1);
#endif
GtkWidget *tcp_b=gtk_button_new_with_label("Use new TCP Addr:");
g_signal_connect (tcp_b, "button-press-event", G_CALLBACK(tcp_cb), NULL);
- gtk_grid_attach(GTK_GRID(grid),tcp_b,1,i,1,1);
+ gtk_grid_attach(GTK_GRID(grid),tcp_b,1,row,1,1);
tcpaddr=gtk_entry_new();
gtk_entry_set_max_length(GTK_ENTRY(tcpaddr), 20);
- gtk_grid_attach(GTK_GRID(grid),tcpaddr,2,i,1,1);
+ gtk_grid_attach(GTK_GRID(grid),tcpaddr,2,row,1,1);
gtk_entry_set_text(GTK_ENTRY(tcpaddr), ipaddr_tcp);
GtkWidget *exit_b=gtk_button_new_with_label("Exit");
g_signal_connect (exit_b, "button-press-event", G_CALLBACK(exit_cb), NULL);
- gtk_grid_attach(GTK_GRID(grid),exit_b,3,i,1,1);
+ gtk_grid_attach(GTK_GRID(grid),exit_b,3,row,1,1);
+
+#ifdef SERVER
+ row++;
+
+ GtkWidget *connect_b=gtk_button_new_with_label("Connect (Addr:Port)");
+ g_signal_connect (connect_b, "button-press-event", G_CALLBACK(connect_cb), NULL);
+ gtk_grid_attach(GTK_GRID(grid),connect_b,0,row,1,1);
+
+ connect_addr_entry=gtk_entry_new();
+ gtk_entry_set_max_length(GTK_ENTRY(connect_addr_entry), 30);
+ gtk_grid_attach(GTK_GRID(grid),connect_addr_entry,1,row,1,1);
+ gtk_entry_set_text(GTK_ENTRY(connect_addr_entry), connect_addr);
+
+#endif
+
gtk_container_add (GTK_CONTAINER (content), grid);
gtk_widget_show_all(discovery_dialog);
reconfigure_radio();
}
+static void display_zoompan_cb(GtkWidget *widget, gpointer data) {
+ display_zoompan=display_zoompan==1?0:1;
+ reconfigure_radio();
+}
+
static void display_sliders_cb(GtkWidget *widget, gpointer data) {
display_sliders=display_sliders==1?0:1;
reconfigure_radio();
row++;
row++;
row++;
- col=1;
+ col=0;
GtkWidget *b_display_waterfall=gtk_check_button_new_with_label("Display Waterfall");
col++;
+ GtkWidget *b_display_zoompan=gtk_check_button_new_with_label("Display Zoom/Pan");
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_display_zoompan), display_zoompan);
+ gtk_widget_show(b_display_zoompan);
+ gtk_grid_attach(GTK_GRID(grid),b_display_zoompan,col,row,1,1);
+ g_signal_connect(b_display_zoompan,"toggled",G_CALLBACK(display_zoompan_cb),(gpointer *)NULL);
+
+ col++;
+
GtkWidget *b_display_sliders=gtk_check_button_new_with_label("Display Sliders");
//gtk_widget_override_font(b_display_sliders, pango_font_description_from_string("Arial 18"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b_display_sliders), display_sliders);
GtkWidget *grid=gtk_grid_new();
- gtk_grid_set_column_homogeneous(GTK_GRID(grid),TRUE);
+ gtk_grid_set_column_homogeneous(GTK_GRID(grid),FALSE);
gtk_grid_set_row_homogeneous(GTK_GRID(grid),TRUE);
- gtk_grid_set_column_spacing (GTK_GRID(grid),5);
- gtk_grid_set_row_spacing (GTK_GRID(grid),5);
+ gtk_grid_set_column_spacing (GTK_GRID(grid),2);
+ gtk_grid_set_row_spacing (GTK_GRID(grid),2);
GtkWidget *close_b=gtk_button_new_with_label("Close");
g_signal_connect (close_b, "pressed", G_CALLBACK(close_cb), NULL);
#include "noise_menu.h"
#include "wdsp.h"
#include "ext.h"
+#include "zoompan.h"
// The following calls functions can be called usig g_idle_add
}
int ext_mox_update(void *data) {
-//g_print("ext_mox_update: %d\n",GPOINTER_TO_INT(data));
+g_print("ext_mox_update: %d\n",GPOINTER_TO_INT(data));
mox_update(GPOINTER_TO_INT(data));
return 0;
}
return 0;
}
-int ext_set_rx_frequency(void *data) {
- RX_FREQUENCY *p=(RX_FREQUENCY *)data;
- int b = get_band_from_frequency(p->frequency);
- if (b != vfo[p->rx].band) {
- vfo_band_changed(b);
+int ext_remote_command(void *data) {
+ REMOTE_COMMAND *p=(REMOTE_COMMAND *)data;
+ switch(p->cmd) {
+ case RX_FREQ_CMD:
+ {
+ int b = get_band_from_frequency(p->data.frequency);
+ if (b != vfo[p->id].band) {
+ vfo_band_changed(b);
+ }
+ setFrequency(p->data.frequency);
+ }
+ break;
+ case RX_MOVE_CMD:
+ vfo_move(p->data.frequency,TRUE);
+ break;
+ case RX_MOVETO_CMD:
+ vfo_move_to(p->data.frequency);
+ break;
+ case RX_MODE_CMD:
+ vfo_mode_changed(p->data.mode);
+ break;
+ case RX_FILTER_CMD:
+ vfo_filter_changed(p->data.filter);
+ break;
+ case RX_AGC_CMD:
+ active_receiver->agc=p->data.agc;
+ set_agc(active_receiver, active_receiver->agc);
+ vfo_update();
+ break;
+ case RX_NR_CMD:
+ break;
+ case RX_NB_CMD:
+ break;
+ case RX_SNB_CMD:
+ break;
+ case RX_SPLIT_CMD:
+ break;
+ case RX_SAT_CMD:
+ break;
+ case RX_DUP_CMD:
+ break;
}
- setFrequency(p->frequency);
g_free(data);
return 0;
+}
+int ext_mute_update(void *data) {
+ active_receiver->mute_radio=!active_receiver->mute_radio;
return 0;
}
-int ext_set_rx_mode(void *data) {
- RX_MODE *p=(RX_MODE *)data;
- vfo_mode_changed(p->mode);
+int ext_zoom_update(void *data) {
+ update_zoom((double)GPOINTER_TO_INT(data));
return 0;
}
-int ext_set_rx_filter(void *data) {
- RX_FILTER *p=(RX_FILTER *)data;
- vfo_filter_changed(p->filter);
+int ext_zoom_set(void *data) {
+ int pos=GPOINTER_TO_INT(data);
+ double zoom=((double)pos/(100.0/7.0))+1.0;
+ if((int)zoom!=active_receiver->zoom) {
+ set_zoom(active_receiver->id,(double)zoom);
+ }
return 0;
}
-int ext_mute_update(void *data) {
-g_print("ext_mute_update: currently %d\n",active_receiver->mute_radio);
- active_receiver->mute_radio=!active_receiver->mute_radio;
+int ext_pan_update(void *data) {
+ update_pan((double)GPOINTER_TO_INT(data));
return 0;
}
+int ext_pan_set(void *data) {
+ if(active_receiver->zoom>1) {
+ int pos=GPOINTER_TO_INT(data);
+ double pan=(double)((active_receiver->zoom-1)*active_receiver->width)*((double)pos/100.0);
+ set_pan(active_receiver->id,(double)pan);
+ }
+ return 0;
+}
// Use these calls from within the rigclt daemon, or the GPIO or MIDI stuff
//
-typedef struct _RX_FREQUENCY {
- int rx;
- long long frequency;
-} RX_FREQUENCY;
-
-typedef struct _RX_MODE {
- int rx;
- int mode;
-} RX_MODE;
-
-typedef struct _RX_FILTER {
- int rx;
- int filter;
-} RX_FILTER;
+enum {
+ RX_FREQ_CMD,
+ RX_MOVE_CMD,
+ RX_MOVETO_CMD,
+ RX_MODE_CMD,
+ RX_FILTER_CMD,
+ RX_AGC_CMD,
+ RX_NR_CMD,
+ RX_NB_CMD,
+ RX_SNB_CMD,
+ RX_SPLIT_CMD,
+ RX_SAT_CMD,
+ RX_DUP_CMD
+};
+
+typedef struct _REMOTE_COMMAND {
+ int id;
+ int cmd;
+ union {
+ long long frequency;
+ int mode;
+ int filter;
+ int agc;
+ int nr;
+ int nb;
+ int snb;
+ int split;
+ int sat;
+ int dup;
+ } data;
+} REMOTE_COMMAND;
extern int ext_discovery(void *data);
extern int ext_vfo_update(void *data);
int ext_start_ps(void *data);
#endif
-int ext_set_rx_frequency(void *data);
-int ext_set_rx_mode(void *data);
-int ext_set_rx_filter(void *data);
int ext_mute_update(void *data);
+
+int ext_zoom_update(void *data);
+int ext_zoom_set(void *data);
+int ext_pan_update(void *data);
+int ext_pan_set(void *data);
+
+int ext_remote_command(void *data);
#ifdef LOCALCW
#include "iambic.h"
#endif
+#include "zoompan.h"
// debounce settle time in ms
#define DEFAULT_SETTLE_TIME 50
int CW_ACTIVE_LOW=1;
#endif
+#ifdef PTT
+int ENABLE_PTT_GPIO=1;
+int PTT_GPIO=15;
+int PTT_ACTIVE_LOW=1;
+#endif
+
int vfoEncoderPos;
int vfoFunction;
char *encoder_string[ENCODER_ACTIONS] = {
"NO ACTION",
"AF GAIN",
- "RF GAIN",
- "AGC GAIN",
- "IF WIDTH",
- "IF SHIFT",
"AF GAIN RX1",
- "RF GAIN RX1",
"AF GAIN RX2",
- "RF GAIN RX2",
+ "AGC GAIN",
"AGC GAIN RX1",
"AGC GAIN RX2",
- "IF WIDTH RX1",
- "IF WIDTH RX2",
+ "ATTENUATION/RX GAIN",
+ "COMP",
+ "CW FREQUENCY",
+ "CW SPEED",
+ "DIVERSITY GAIN",
+ "DIVERSITY GAIN (coarse)",
+ "DIVERSITY GAIN (fine)",
+ "DIVERSITY PHASE",
+ "DIVERSITY PHASE (coarse)",
+ "DIVERSITY PHASE (fine)",
+ "DRIVE",
+ "IF SHIFT",
"IF SHIFT RX1",
"IF SHIFT RX2",
- "ATTENUATION/RX GAIN",
+ "IF WIDTH",
+ "IF WIDTH RX1",
+ "IF WIDTH RX2",
"MIC GAIN",
- "DRIVE",
- "TUNE DRIVE",
- "RIT",
- "RIT RX1",
- "RIT RX2",
- "XIT",
- "CW SPEED",
- "CW FREQUENCY",
+ "PAN",
"PANADAPTER HIGH",
"PANADAPTER LOW",
"PANADAPTER STEP",
- "WATERFALL HIGH",
- "WATERFALL LOW",
+ "RF GAIN",
+ "RF GAIN RX1",
+ "RF GAIN RX2",
+ "RIT",
+ "RIT RX1",
+ "RIT RX2",
"SQUELCH",
"SQUELCH RX1",
"SQUELCH RX2",
- "COMP",
- "DIVERSITY GAIN",
- "DIVERSITY GAIN (coarse)",
- "DIVERSITY GAIN (fine)",
- "DIVERSITY PHASE",
- "DIVERSITY PHASE (coarse)",
- "DIVERSITY PHASE (fine)"
+ "TUNE DRIVE",
+ "WATERFALL HIGH",
+ "WATERFALL LOW",
+ "XIT",
+ "ZOOM",
};
char *sw_string[SWITCH_ACTIONS] = {
"",
- "TUNE",
+ "A TO B",
+ "A SWAP B",
+ "AGC",
+ "B TO A",
+ "BAND -",
+ "BAND +",
+ "BSTACK -",
+ "BSTACK +",
+ "CTUN",
+ "DIV",
+ "FILTER -",
+ "FILTER +",
+ "FUNCTION",
+ "LOCK",
+ "MENU BAND",
+ "MENU BSTACK",
+ "MENU DIV",
+ "MENU FILTER",
+ "MENU FREQUENCY",
+ "MENU MEMORY",
+ "MENU MODE",
+ "MENU PS",
+ "MODE -",
+ "MODE +",
"MOX",
- "PS",
- "TWO TONE",
- "NR",
+ "MUTE",
"NB",
- "SNB",
+ "NR",
+ "PAN -",
+ "PAN +",
+ "PS",
"RIT",
"RIT CL",
+ "SAT",
+ "SNB",
+ "SPLIT",
+ "TUNE",
+ "TWO TONE",
"XIT",
"XIT CL",
- "BAND +",
- "BAND -",
- "BSTACK +",
- "BSTACK -",
- "MODE +",
- "MODE -",
- "FILTER +",
- "FILTER -",
- "A TO B",
- "B TO A",
- "A SWAP B",
- "LOCK",
- "CTUN",
- "AGC",
- "SPLIT",
- "DIV",
- "SAT",
- "BAND",
- "BSTACK",
- "MODE",
- "FILTER",
- "FREQUENCY",
- "MEMORY",
- "DIV MENU",
- "PS MENU",
- "FUNCTION",
- "MUTE"
+ "ZOOM -",
+ "ZOOM +",
};
int *sw_action=NULL;
return 0;
}
+#ifdef PTT
+static int ptt_pressed(void *data) {
+g_print("ptt_pressed\n");
+ if(can_transmit) g_idle_add(ext_mox_update,GINT_TO_POINTER(1));
+ return 0;
+}
+
+static int ptt_released(void *data) {
+g_print("ptt_released\n");
+ if(can_transmit) g_idle_add(ext_mox_update,GINT_TO_POINTER(0));
+ return 0;
+}
+#endif
+
static int e_function_pressed(void *data) {
int action=(int)data;
g_print("e_function_pressed: %d\n",action);
case MUTE:
g_idle_add(ext_mute_update,NULL);
break;
+ case PAN_MINUS:
+ g_idle_add(ext_pan_update,GINT_TO_POINTER(-100));
+ break;
+ case PAN_PLUS:
+ g_idle_add(ext_pan_update,GINT_TO_POINTER(100));
+ break;
+ case ZOOM_MINUS:
+ g_idle_add(ext_zoom_update,GINT_TO_POINTER(-1));
+ break;
+ case ZOOM_PLUS:
+ g_idle_add(ext_zoom_update,GINT_TO_POINTER(1));
+ break;
}
return 0;
}
}
}
+#ifdef PTT
+static int ptt_level=1;
+static unsigned long ptt_debounce=0;
+
+static void pttAlert() {
+ int t=millis();
+ if(millis()<ptt_debounce) {
+ return;
+ }
+ int level=digitalRead(PTT_GPIO);
+ if(level!=ptt_level) {
+ if(level==0) {
+ if(running) g_idle_add(ptt_pressed,NULL);
+ } else {
+ if(running) g_idle_add(ptt_released,NULL);
+ }
+ ptt_level=level;
+ ptt_debounce=t+settle_time;
+ }
+}
+#endif
+
void gpio_set_defaults(int ctrlr) {
g_print("gpio_set_defaults: %d\n",ctrlr);
if(sw_action!=NULL) {
if(value) ENABLE_GPIO_SIDETONE=atoi(value);
#endif
+#ifdef PTT
+ switch(controller) {
+ case NO_CONTROLLER:
+ PTT_GPIO=12;
+ break;
+ case CONTROLLER1:
+ PTT_GPIO=12;
+ break;
+ case CONTROLLER2_V1:
+ PTT_GPIO=15;
+ break;
+ case CONTROLLER2_V2:
+ PTT_GPIO=15;
+ break;
+ }
+ value=getProperty("ENABLE_PTT_GPIO");
+ if(value) ENABLE_PTT_GPIO=atoi(value);
+ value=getProperty("PTT_GPIO");
+ if(value) PTT_GPIO=atoi(value);
+ value=getProperty("PTT_ACTIVE_LOW");
+ if(value) PTT_ACTIVE_LOW=atoi(value);
+#endif
+
if(controller!=CONTROLLER1) {
value=getProperty("i2c_device");
if(value) {
setProperty("ENABLE_GPIO_SIDETONE",value);
#endif
+#ifdef PTT
+ sprintf(value,"%d",ENABLE_PTT_GPIO);
+ setProperty("ENABLE_PPT_GPIO",value);
+ sprintf(value,"%d",PTT_GPIO);
+ setProperty("PPT_GPIO",value);
+ sprintf(value,"%d",PTT_ACTIVE_LOW);
+ setProperty("PPT_ACTIVE_LOW",value);
+#endif
saveProperties("gpio.props");
}
static void setup_pin(int pin, int up_down, void(*pAlert)(void)) {
int rc;
+g_print("setup_pin: pin=%d up_down=%d\n",pin,up_down);
pinMode(pin,GPIO);
pinMode(pin,INPUT);
pullUpDnControl(pin,up_down);
}
#endif
+#ifdef PTT
+ if(ENABLE_PTT_GPIO) {
+g_print("PTT Enabled: setup pin %d active_low=%d\n",PTT_GPIO,PTT_ACTIVE_LOW);
+ setup_pin(PTT_GPIO,PTT_ACTIVE_LOW?PUD_UP:PUD_DOWN,pttAlert);
+ }
+#endif
+
return 0;
}
case ENCODER_DIVERSITY_PHASE_FINE:
update_diversity_phase((double)pos*0.1);
break;
+ case ENCODER_ZOOM:
+ update_zoom((double)pos);
+ break;
+ case ENCODER_PAN:
+ update_pan((double)pos*100);
+ break;
}
}
CONTROLLER1,
CONTROLLER2_V1,
CONTROLLER2_V2,
- CUSTOM_CONTROLLER
};
extern int controller;
enum {
ENCODER_NO_ACTION=0,
ENCODER_AF_GAIN,
- ENCODER_RF_GAIN,
- ENCODER_AGC_GAIN,
- ENCODER_IF_WIDTH,
- ENCODER_IF_SHIFT,
ENCODER_AF_GAIN_RX1,
- ENCODER_RF_GAIN_RX1,
ENCODER_AF_GAIN_RX2,
- ENCODER_RF_GAIN_RX2,
+ ENCODER_AGC_GAIN,
ENCODER_AGC_GAIN_RX1,
ENCODER_AGC_GAIN_RX2,
- ENCODER_IF_WIDTH_RX1,
- ENCODER_IF_WIDTH_RX2,
+ ENCODER_ATTENUATION,
+ ENCODER_COMP,
+ ENCODER_CW_FREQUENCY,
+ ENCODER_CW_SPEED,
+ ENCODER_DIVERSITY_GAIN,
+ ENCODER_DIVERSITY_GAIN_COARSE,
+ ENCODER_DIVERSITY_GAIN_FINE,
+ ENCODER_DIVERSITY_PHASE,
+ ENCODER_DIVERSITY_PHASE_COARSE,
+ ENCODER_DIVERSITY_PHASE_FINE,
+ ENCODER_DRIVE,
+ ENCODER_IF_SHIFT,
ENCODER_IF_SHIFT_RX1,
ENCODER_IF_SHIFT_RX2,
- ENCODER_ATTENUATION,
+ ENCODER_IF_WIDTH,
+ ENCODER_IF_WIDTH_RX1,
+ ENCODER_IF_WIDTH_RX2,
ENCODER_MIC_GAIN,
- ENCODER_DRIVE,
- ENCODER_TUNE_DRIVE,
- ENCODER_RIT,
- ENCODER_RIT_RX1,
- ENCODER_RIT_RX2,
- ENCODER_XIT,
- ENCODER_CW_SPEED,
- ENCODER_CW_FREQUENCY,
+ ENCODER_PAN,
ENCODER_PANADAPTER_HIGH,
ENCODER_PANADAPTER_LOW,
ENCODER_PANADAPTER_STEP,
- ENCODER_WATERFALL_HIGH,
- ENCODER_WATERFALL_LOW,
+ ENCODER_RF_GAIN,
+ ENCODER_RF_GAIN_RX1,
+ ENCODER_RF_GAIN_RX2,
+ ENCODER_RIT,
+ ENCODER_RIT_RX1,
+ ENCODER_RIT_RX2,
ENCODER_SQUELCH,
ENCODER_SQUELCH_RX1,
ENCODER_SQUELCH_RX2,
- ENCODER_COMP,
- ENCODER_DIVERSITY_GAIN,
- ENCODER_DIVERSITY_GAIN_COARSE,
- ENCODER_DIVERSITY_GAIN_FINE,
- ENCODER_DIVERSITY_PHASE,
- ENCODER_DIVERSITY_PHASE_COARSE,
- ENCODER_DIVERSITY_PHASE_FINE,
+ ENCODER_TUNE_DRIVE,
+ ENCODER_WATERFALL_HIGH,
+ ENCODER_WATERFALL_LOW,
+ ENCODER_XIT,
+ ENCODER_ZOOM,
ENCODER_ACTIONS
};
enum {
NO_ACTION=0,
- TUNE,
- MOX,
- PS,
- TWO_TONE,
- NR,
- NB,
- SNB,
- RIT,
- RIT_CLEAR,
- XIT,
- XIT_CLEAR,
- BAND_PLUS,
- BAND_MINUS,
- BANDSTACK_PLUS,
- BANDSTACK_MINUS,
- MODE_PLUS,
- MODE_MINUS,
- FILTER_PLUS,
- FILTER_MINUS,
A_TO_B,
- B_TO_A,
A_SWAP_B,
- LOCK,
- CTUN,
AGC,
- SPLIT,
+ B_TO_A,
+ BAND_MINUS,
+ BAND_PLUS,
+ BANDSTACK_MINUS,
+ BANDSTACK_PLUS,
+ CTUN,
DIVERSITY,
- SAT,
+ FILTER_MINUS,
+ FILTER_PLUS,
+ FUNCTION,
+ LOCK,
MENU_BAND,
MENU_BANDSTACK,
- MENU_MODE,
+ MENU_DIVERSITY,
MENU_FILTER,
MENU_FREQUENCY,
MENU_MEMORY,
- MENU_DIVERSITY,
+ MENU_MODE,
MENU_PS,
- FUNCTION,
+ MODE_MINUS,
+ MODE_PLUS,
+ MOX,
MUTE,
+ NB,
+ NR,
+ PAN_MINUS,
+ PAN_PLUS,
+ PS,
+ RIT,
+ RIT_CLEAR,
+ SAT,
+ SNB,
+ SPLIT,
+ TUNE,
+ TWO_TONE,
+ XIT,
+ XIT_CLEAR,
+ ZOOM_MINUS,
+ ZOOM_PLUS,
SWITCH_ACTIONS
};
extern int gpio_cw_sidetone_enabled();
#endif
+#ifdef PTT
+extern int ENABLE_PTT_GPIO;
+extern int PTT_GPIO;
+extern int PTT_ACTIVE_LOW;
+#endif
+
extern void gpio_set_defaults(int ctrlr);
extern void gpio_restore_actions();
extern void gpio_restore_state();
for(i=0;i<16;i++) {
if(i2c_sw[i]==ints) break;
}
-/*
- switch(ints) {
- case SW_2:
- i=CONTROLLER2_SW2;
- break;
- case SW_3:
- i=CONTROLLER2_SW3;
- break;
- case SW_4:
- i=CONTROLLER2_SW4;
- break;
- case SW_5:
- i=CONTROLLER2_SW5;
- break;
- case SW_6:
- i=CONTROLLER2_SW6;
- break;
- case SW_7:
- i=CONTROLLER2_SW7;
- break;
- case SW_8:
- i=CONTROLLER2_SW8;
- break;
- case SW_9:
- i=CONTROLLER2_SW9;
- break;
- case SW_10:
- i=CONTROLLER2_SW10;
- break;
- case SW_11:
- i=CONTROLLER2_SW11;
- break;
- case SW_12:
- i=CONTROLLER2_SW12;
- break;
- case SW_13:
- i=CONTROLLER2_SW13;
- break;
- case SW_14:
- i=CONTROLLER2_SW14;
- break;
- case SW_15:
- i=CONTROLLER2_SW15;
- break;
- case SW_16:
- i=CONTROLLER2_SW16;
- break;
- case SW_17:
- i=CONTROLLER2_SW17;
- break;
- }
-*/
if(i<16) {
//g_print("i1c_interrupt: sw=%d action=%d\n",i,sw_action[i]);
switch(sw_action[i]) {
case MUTE:
g_idle_add(ext_mute_update,NULL);
break;
+ case PAN_MINUS:
+ g_idle_add(ext_pan_update,GINT_TO_POINTER(-100));
+ break;
+ case PAN_PLUS:
+ g_idle_add(ext_pan_update,GINT_TO_POINTER(100));
+ break;
+ case ZOOM_MINUS:
+ g_idle_add(ext_zoom_update,GINT_TO_POINTER(-1));
+ break;
+ case ZOOM_PLUS:
+ g_idle_add(ext_zoom_update,GINT_TO_POINTER(1));
+ break;
}
}
}
enum MIDIaction {
ACTION_NONE=0, // NONE: No-Op (unassigned key)
VFO_A2B, // A2B: VFO A -> B
- AF_GAIN, // AFGAIN: AF gain
+ MIDI_AF_GAIN, // AFGAIN: AF gain
AGCATTACK, // AGCATTACK: AGC ATTACK (cycle fast/med/slow etc.)
MIDI_AGC, // AGCVAL: AGC level
ATT, // ATT: Step attenuator or Programmable attenuator
MIDI_MUTE, // MUTE: toggle mute on/off
MIDI_NB, // NOISEBLANKER: cycle through NoiseBlanker states (none, NB, NB2)
MIDI_NR, // NOISEREDUCTION: cycle through NoiseReduction states (none, NR, NR2)
+ MIDI_PAN, // PAN: change panning of panadater/waterfall when zoomed
PAN_HIGH, // PANHIGH: "high" value of current panadapter
PAN_LOW, // PANLOW: "low" value of current panadapter
PRE, // PREAMP: preamp on/off
VOXLEVEL, // VOXLEVEL: adjust VOX threshold
MIDI_XIT_CLEAR, // XITCLEAR: clear XIT value
XIT_VAL, // XITVAL: change XIT value
+ MIDI_ZOOM, // ZOOM: change zoom factor
+ ZOOM_UP, // ZOOMUP: change zoom factor
+ ZOOM_DOWN, // ZOOMDOWN: change zoom factor
};
//
const char *str;
} ActionTable[] = {
{ VFO_A2B, "A2B"},
- { AF_GAIN, "AFGAIN"},
+ { MIDI_AF_GAIN, "AFGAIN"},
{ AGCATTACK, "AGCATTACK"},
{ MIDI_AGC, "AGCVAL"},
{ ATT, "ATT"},
{ MIDI_MUTE, "MUTE"},
{ MIDI_NB, "NOISEBLANKER"},
{ MIDI_NR, "NOISEREDUCTION"},
+ { MIDI_PAN, "PAN"},
{ PAN_HIGH, "PANHIGH"},
{ PAN_LOW, "PANLOW"},
{ PRE, "PREAMP"},
{ VOXLEVEL, "VOXLEVEL"},
{ MIDI_XIT_CLEAR, "XITCLEAR"},
{ XIT_VAL, "XITVAL"},
+ { MIDI_ZOOM, "ZOOM"},
+ { ZOOM_UP, "ZOOMUP"},
+ { ZOOM_DOWN, "ZOOMDOWN"},
{ ACTION_NONE, "NONE"}
};
}
break;
/////////////////////////////////////////////////////////// "AFGAIN"
- case AF_GAIN: // knob or wheel supported
+ case MIDI_AF_GAIN: // knob or wheel supported
switch (type) {
case MIDI_KNOB:
active_receiver->volume = 0.01*val;
g_idle_add(ext_vfo_update, NULL);
}
break;
+ /////////////////////////////////////////////////////////// "PAN"
+ case MIDI_PAN: // wheel and knob
+ switch (type) {
+ case MIDI_WHEEL:
+ g_idle_add(ext_pan_update,GINT_TO_POINTER(val));
+ break;
+ case MIDI_KNOB:
+ g_idle_add(ext_pan_set,GINT_TO_POINTER(val));
+ break;
+ }
+ break;
/////////////////////////////////////////////////////////// "PANHIGH"
case PAN_HIGH: // wheel or knob
switch (type) {
g_idle_add(ext_vfo_update, NULL);
}
break;
+ /////////////////////////////////////////////////////////// "ZOOM"
+ case MIDI_ZOOM: // wheel and knob
+ switch (type) {
+ case MIDI_WHEEL:
+g_print("MIDI_ZOOM: MIDI_WHEEL: val=%d\n",val);
+ g_idle_add(ext_zoom_update,GINT_TO_POINTER(val));
+ break;
+ case MIDI_KNOB:
+g_print("MIDI_ZOOM: MIDI_KNOB: val=%d\n",val);
+ g_idle_add(ext_zoom_set,GINT_TO_POINTER(val));
+ break;
+ }
+ break;
+ /////////////////////////////////////////////////////////// "ZOOMDOWN"
+ /////////////////////////////////////////////////////////// "ZOOMUP"
+ case ZOOM_UP: // key
+ case ZOOM_DOWN: // key
+ switch (type) {
+ case MIDI_KEY:
+ new = (action == ZOOM_UP) ? 1 : -1;
+ g_idle_add(ext_zoom_update,GINT_TO_POINTER(new));
+ break;
+ case MIDI_WHEEL:
+ new = (val > 0) ? 1 : -1;
+ g_idle_add(ext_zoom_update,GINT_TO_POINTER(new));
+ break;
+ default:
+ // do nothing
+ // we should not come here anyway
+ break;
+ }
+ break;
case ACTION_NONE:
// No error message, this is the "official" action for un-used controller buttons.
if(ddc_sequence[ddc] !=sequence) {
g_print("DDC %d sequence error: expected %ld got %ld\n",ddc,ddc_sequence[ddc],sequence);
ddc_sequence[ddc]=sequence;
+ sequence_errors++;
}
ddc_sequence[ddc]++;
//
// and is no error condition
if (sequence != 0 && sequence != last_seq_num+1) {
g_print("SEQ ERROR: last %ld, recvd %ld\n", (long) last_seq_num, (long) sequence);
+ sequence_errors++;
}
last_seq_num=sequence;
switch(ep) {
#include "rx_panadapter.h"
#include "tx_panadapter.h"
#include "waterfall.h"
+#include "zoompan.h"
#include "sliders.h"
#include "toolbar.h"
#include "rigctl.h"
#ifdef MIDI
#include "midi.h"
#endif
+#ifdef SERVER
+#include "hpsdr_server.h"
+#endif
#define min(x,y) (x<y?x:y)
#define max(x,y) (x<y?y:x)
#define METER_HEIGHT (60)
#define METER_WIDTH (200)
#define PANADAPTER_HEIGHT (105)
+#define ZOOMPAN_HEIGHT (50)
#define SLIDERS_HEIGHT (100)
#define TOOLBAR_HEIGHT (30)
#define WATERFALL_HEIGHT (105)
static GtkWidget *vfo_panel;
static GtkWidget *meter;
static GtkWidget *menu;
+static GtkWidget *zoompan;
static GtkWidget *sliders;
static GtkWidget *toolbar;
static GtkWidget *panadapter;
int waterfall_high=-100;
int waterfall_low=-150;
+int display_zoompan=0;
int display_sliders=0;
int display_toolbar=0;
gboolean duplex=FALSE;
gboolean mute_rx_while_transmitting=FALSE;
+
+int sequence_errors=0;
+
gint rx_height;
void radio_stop() {
int y;
//g_print("reconfigure_radio: receivers=%d\n",receivers);
rx_height=display_height-VFO_HEIGHT;
+ if(display_zoompan) {
+ rx_height-=ZOOMPAN_HEIGHT;
+ }
if(display_sliders) {
rx_height-=SLIDERS_HEIGHT;
}
y+=rx_height/receivers;
}
+ if(display_zoompan) {
+ if(zoompan==NULL) {
+ zoompan = zoompan_init(display_width,ZOOMPAN_HEIGHT);
+ gtk_fixed_put(GTK_FIXED(fixed),zoompan,0,y);
+ } else {
+ gtk_fixed_put(GTK_FIXED(fixed),zoompan,0,y);
+ }
+ gtk_widget_show_all(zoompan);
+ y+=ZOOMPAN_HEIGHT;
+ } else {
+ if(zoompan!=NULL) {
+ gtk_container_remove(GTK_CONTAINER(fixed),zoompan);
+ zoompan=NULL;
+ }
+ }
+
if(display_sliders) {
if(sliders==NULL) {
sliders = sliders_init(display_width,SLIDERS_HEIGHT);
switch(controller) {
case CONTROLLER2_V1:
case CONTROLLER2_V2:
+ display_zoompan=1;
display_sliders=0;
display_toolbar=0;
break;
default:
+ display_zoompan=1;
display_sliders=1;
display_toolbar=1;
break;
}
#else
+ display_zoompan=1;
display_sliders=1;
display_toolbar=1;
#endif
rx_height=display_height-VFO_HEIGHT;
+ if(display_zoompan) {
+ rx_height-=ZOOMPAN_HEIGHT;
+ }
if(display_sliders) {
rx_height-=SLIDERS_HEIGHT;
}
transmitter=create_transmitter(CHANNEL_TX, buffer_size, fft_size, updates_per_second, display_width/4, display_height/2);
} else {
int tx_height=display_height-VFO_HEIGHT;
+ if(display_zoompan) tx_height-=ZOOMPAN_HEIGHT;
if(display_sliders) tx_height-=SLIDERS_HEIGHT;
if(display_toolbar) tx_height-=TOOLBAR_HEIGHT;
transmitter=create_transmitter(CHANNEL_TX, buffer_size, fft_size, updates_per_second, display_width, tx_height);
receiver[PS_RX_FEEDBACK]=create_pure_signal_receiver(PS_RX_FEEDBACK, buffer_size,protocol==ORIGINAL_PROTOCOL?active_receiver->sample_rate:192000,display_width);
switch (protocol) {
case NEW_PROTOCOL:
- pk = 0.2899;
- break;
+ pk = 0.2899;
+ break;
case ORIGINAL_PROTOCOL:
switch (device) {
- case DEVICE_HERMES_LITE2:
- pk = 0.2300;
+ case DEVICE_HERMES_LITE2:
+ pk = 0.2300;
break;
- default:
- pk = 0.4067;
+ default:
+ pk = 0.4067;
break;
}
}
audio_waterfall=audio_waterfall_init(200,100);
gtk_fixed_put(GTK_FIXED(fixed),audio_waterfall,0,VFO_HEIGHT+20);
#endif
-
+
+ gboolean init_gpio=FALSE;
+#ifdef LOCALCW
+ init_gpio=TRUE;
+#endif
+#ifdef PTT
+ init_gpio=TRUE;
+#endif
+#ifdef GPIO
+ init_gpio=TRUE;
+#endif
+
+ if(init_gpio) {
#ifdef GPIO
if(gpio_init()<0) {
g_print("GPIO failed to initialize\n");
}
#endif
+ }
+
#ifdef LOCALCW
// init local keyer if enabled
if (cw_keyer_internal == 0) {
#endif
}
+ if(display_zoompan) {
+ zoompan = zoompan_init(display_width,ZOOMPAN_HEIGHT);
+ gtk_fixed_put(GTK_FIXED(fixed),zoompan,0,y);
+ y+=ZOOMPAN_HEIGHT;
+ }
+
if(display_sliders) {
//g_print("create sliders\n");
sliders = sliders_init(display_width,SLIDERS_HEIGHT);
MIDIstartup();
#endif
+#ifdef SERVER
+ create_hpsdr_server();
+#endif
+
}
void disable_rigctl() {
break;
#ifdef SOAPYSDR
case SOAPYSDR_PROTOCOL:
- soapy_protocol_change_sample_rate(receiver[0],rate);
+ soapy_protocol_change_sample_rate(receiver[0]);
soapy_protocol_set_mic_sample_rate(rate);
break;
#endif
if(value) panadapter_high=atoi(value);
value=getProperty("panadapter_low");
if(value) panadapter_low=atoi(value);
+ value=getProperty("display_zoompan");
+ if(value) display_zoompan=atoi(value);
value=getProperty("display_sliders");
if(value) display_sliders=atoi(value);
value=getProperty("display_toolbar");
setProperty("panadapter_high",value);
sprintf(value,"%d",panadapter_low);
setProperty("panadapter_low",value);
+ sprintf(value,"%d",display_zoompan);
+ setProperty("display_zoompan",value);
sprintf(value,"%d",display_sliders);
setProperty("display_sliders",value);
sprintf(value,"%d",display_toolbar);
//extern int display_waterfall;
+extern int display_zoompan;
extern int display_sliders;
extern int display_toolbar;
extern int rx_gain_calibration; // position of the RX gain slider that
// corresponds to zero amplification/attenuation
+extern int sequence_errors;
+
extern void radio_stop();
extern void reconfigure_radio();
extern void start_radio();
#include "vfo.h"
#include "meter.h"
#include "rx_panadapter.h"
+#include "zoompan.h"
#include "sliders.h"
#include "waterfall.h"
#include "new_protocol.h"
making_active=FALSE;
g_idle_add(menu_active_receiver_changed,NULL);
g_idle_add(ext_vfo_update,NULL);
+ g_idle_add(zoompan_active_receiver_changed,NULL);
g_idle_add(sliders_active_receiver_changed,NULL);
if(event->button==3) {
g_idle_add(ext_start_rx,NULL);
}
- g_print("receiver: %d adc=%d attenuation=%d rx_gain_calibration=%d\n",rx->id,rx->adc,adc_attenuation[rx->adc],rx_gain_calibration);
+ ///g_print("receiver: %d adc=%d attenuation=%d rx_gain_calibration=%d\n",rx->id,rx->adc,adc_attenuation[rx->adc],rx_gain_calibration);
} else {
- //int display_width=gtk_widget_get_allocated_width (rx->panadapter);
- //int display_height=gtk_widget_get_allocated_height (rx->panadapter);
if(pressed) {
int x=(int)event->x;
if (event->button == 1) {
sprintf(value,"%f",rx->squelch);
setProperty(name,value);
+ sprintf(name,"receiver.%d.zoom",rx->id);
+ sprintf(value,"%d",rx->zoom);
+ setProperty(name,value);
+ sprintf(name,"receiver.%d.pan",rx->id);
+ sprintf(value,"%d",rx->pan);
+ setProperty(name,value);
}
void receiver_restore_state(RECEIVER *rx) {
value=getProperty(name);
if(value) rx->squelch=atof(value);
+ sprintf(name,"receiver.%d.zoom",rx->id);
+ value=getProperty(name);
+ if(value) rx->zoom=atoi(value);
+ sprintf(name,"receiver.%d.pan",rx->id);
+ value=getProperty(name);
+ if(value) rx->pan=atoi(value);
}
void reconfigure_receiver(RECEIVER *rx,int height) {
//fprintf(stderr,"update_display: %d displaying=%d\n",rx->id,rx->displaying);
if(rx->displaying) {
- GetPixels(rx->id,0,rx->pixel_samples,&rc);
- if(rc) {
- if(rx->display_panadapter) {
- rx_panadapter_update(rx);
- }
- if(rx->display_waterfall) {
- waterfall_update(rx);
- }
+ if(rx->pixels>0) {
+ GetPixels(rx->id,0,rx->pixel_samples,&rc);
+ if(rc) {
+ if(rx->display_panadapter) {
+ rx_panadapter_update(rx);
+ }
+ if(rx->display_waterfall) {
+ waterfall_update(rx);
+ }
}
-
- if(active_receiver==rx) {
- double m=GetRXAMeter(rx->id,smeter)+meter_calibration;
- meter_update(rx,SMETER,m,0.0,0.0,0.0);
+
+ if(active_receiver==rx) {
+ double m=GetRXAMeter(rx->id,smeter)+meter_calibration;
+ meter_update(rx,SMETER,m,0.0,0.0,0.0);
+ }
+ return TRUE;
}
- return TRUE;
}
return FALSE;
}
overlap = (int)max(0.0, ceil(fft_size - (double)rx->sample_rate / (double)rx->fps));
- fprintf(stderr,"SetAnalyzer id=%d buffer_size=%d overlap=%d\n",rx->id,rx->buffer_size,overlap);
+ //g_print("SetAnalyzer id=%d buffer_size=%d overlap=%d\n",rx->id,rx->buffer_size,overlap);
SetAnalyzer(rx->id,
fprintf(stderr,"create_receiver: id=%d default adc=%d\n",rx->id, rx->adc);
#ifdef SOAPYSDR
if(radio->device==SOAPYSDR_USB_DEVICE) {
-/*
- if(strcmp(radio->name,"lime")==0) {
- rx->sample_rate=384000;
- } else if(strcmp(radio->name,"rtlsdr")==0) {
- rx->sample_rate=384000;
- } else {
- rx->sample_rate=384000;
- }
-*/
rx->sample_rate=radio->info.soapy.sample_rate;
- rx->resample_step=1;
+ rx->resampler=NULL;
+ rx->resample_buffer=NULL;
} else {
#endif
rx->sample_rate=48000;
#endif
rx->buffer_size=buffer_size;
rx->fft_size=fft_size;
- rx->pixels=pixels;
rx->fps=fps;
rx->update_timer_id=-1;
-
-// rx->dds_offset=0;
-// rx->rit=0;
-
rx->width=width;
rx->height=height;
- // allocate buffers
- rx->iq_input_buffer=g_new(double,2*rx->buffer_size);
- rx->audio_buffer_size=480;
- rx->audio_sequence=0L;
- rx->pixel_samples=g_new(float,pixels);
-
rx->samples=0;
rx->displaying=0;
rx->display_panadapter=1;
rx->mute_radio=0;
+ rx->fexchange_errors=0;
+
+ rx->zoom=1;
+ rx->pan=0;
+
receiver_restore_state(rx);
-#ifdef SOAPYSDR
- rx->resample_step=radio->info.soapy.sample_rate/rx->sample_rate;
-#else
- rx->resample_step=1;
-#endif
+ // allocate buffers
+ rx->iq_input_buffer=g_new(double,2*rx->buffer_size);
+ rx->audio_buffer_size=480;
+ rx->audio_sequence=0L;
+ rx->pixels=pixels*rx->zoom;
+ rx->pixel_samples=g_new(float,rx->pixels);
+
fprintf(stderr,"create_receiver (after restore): rx=%p id=%d audio_buffer_size=%d local_audio=%d\n",rx,rx->id,rx->audio_buffer_size,rx->local_audio);
//rx->audio_buffer=g_new(guchar,rx->audio_buffer_size);
fprintf(stderr,"create_receiver: id=%d output_samples=%d\n",rx->id,rx->output_samples);
- rx->hz_per_pixel=(double)rx->sample_rate/(double)rx->width;
+ rx->hz_per_pixel=(double)rx->sample_rate/(double)rx->pixels;
// setup wdsp for this receiver
}
receiver_mode_changed(rx);
- //receiver_frequency_changed(rx);
int result;
XCreateAnalyzer(rx->id, &result, 262144, 1, 1, "");
SetInputSamplerate(rx->id, sample_rate);
SetEXTANBSamplerate (rx->id, sample_rate);
SetEXTNOBSamplerate (rx->id, sample_rate);
-#ifdef SOAPYSDR
if(protocol==SOAPYSDR_PROTOCOL) {
- rx->resample_step=radio_sample_rate/rx->sample_rate;
-g_print("receiver_change_sample_rate: resample_step=%d\n",rx->resample_step);
+ soapy_protocol_change_sample_rate(rx);
soapy_protocol_set_mic_sample_rate(rx->sample_rate);
}
-#endif
SetChannelState(rx->id,1,0);
int id=rx->id;
if(vfo[id].ctun) {
+
+ long long frequency=vfo[id].frequency;
+ long long half=(long long)rx->sample_rate/2LL;
+ long long rx_low=vfo[id].ctun_frequency+rx->filter_low;
+ long long rx_high=vfo[id].ctun_frequency+rx->filter_high;
+
+ if(rx->zoom>1) {
+ long long min_display=frequency-half+(long long)((double)rx->pan*rx->hz_per_pixel);
+ long long max_display=min_display+(long long)((double)rx->width*rx->hz_per_pixel);
+ if(rx_low<=min_display) {
+ rx->pan=rx->pan-(rx->width/2);
+ if(rx->pan<0) rx->pan=0;
+ set_pan(id,rx->pan);
+ } else if(rx_high>=max_display) {
+ rx->pan=rx->pan+(rx->width/2);
+ if(rx->pan>(rx->pixels-rx->width)) rx->pan=rx->pixels-rx->width;
+ set_pan(id,rx->pan);
+ }
+ }
+
vfo[id].offset=vfo[id].ctun_frequency-vfo[id].frequency;
if(vfo[id].rit_enabled) {
- vfo[id].offset+=vfo[id].rit;
+ vfo[id].offset+=vfo[id].rit;
}
set_offset(rx,vfo[id].offset);
} else {
fexchange0(rx->id, rx->iq_input_buffer, rx->audio_output_buffer, &error);
if(error!=0) {
- fprintf(stderr,"full_rx_buffer: id=%d fexchange0: error=%d\n",rx->id,error);
+ //fprintf(stderr,"full_rx_buffer: id=%d fexchange0: error=%d\n",rx->id,error);
+ rx->fexchange_errors++;
}
if(rx->displaying) {
rx->samples=0;
}
}
+
+void receiver_change_zoom(RECEIVER *rx,double zoom) {
+ g_mutex_lock(&rx->mutex);
+ if(rx->pixel_samples!=NULL) {
+ g_free(rx->pixel_samples);
+ }
+ rx->pixels=rx->width*(int)zoom;
+ rx->pixel_samples=g_new(float,rx->pixels);
+ rx->hz_per_pixel=(double)rx->sample_rate/(double)rx->pixels;
+ if(zoom==0) {
+ rx->pan=0;
+ } else {
+ if(vfo[rx->id].ctun) {
+ long long min_frequency=vfo[rx->id].frequency-(long long)(rx->sample_rate/2);
+ rx->pan=((vfo[rx->id].ctun_frequency-min_frequency)/rx->hz_per_pixel)-(rx->width/2);
+ if(rx->pan<0) rx->pan=0;
+ if(rx->pan>(rx->pixels-rx->width)) rx->pan=rx->pixels-rx->width;
+ } else {
+ rx->pan=(rx->pixels/2)-(rx->width/2);
+ }
+ }
+ rx->zoom=(int)zoom;
+ init_analyzer(rx);
+ g_mutex_unlock(&rx->mutex);
+}
+
+void receiver_change_pan(RECEIVER *rx,double pan) {
+ g_mutex_lock(&rx->mutex);
+ rx->pan=(int)pan;
+ g_mutex_unlock(&rx->mutex);
+}
+
gint mute_radio;
gdouble *buffer;
- gint resample_step;
+ void *resampler;
+ gdouble *resample_buffer;
+ gint resample_buffer_size;
+
+ gint fexchange_errors;
+
+ gint zoom;
+ gint pan;
gint x;
gint y;
extern void receiver_mode_changed(RECEIVER *rx);
extern void receiver_filter_changed(RECEIVER *rx);
extern void receiver_vfo_changed(RECEIVER *rx);
+extern void receiver_change_zoom(RECEIVER *rx,double zoom);
+extern void receiver_change_pan(RECEIVER *rx,double pan);
extern void set_mode(RECEIVER* rx,int m);
extern void set_filter(RECEIVER *rx,int low,int high);
static gfloat filter_right;
static gfloat cw_frequency;
+static gint sequence_error_count=0;
+static gint fexchange_error_count=0;
+
/* Create a new surface of the appropriate size to store our scribbles */
static gboolean
panadapter_configure_event_cb (GtkWidget *widget,
}
BAND *band=band_get_band(vfoband);
- long half=(long)rx->sample_rate/2L;
- double vfofreq=(double) display_width * 0.5;
+ long long half=(long long)rx->sample_rate/2LL;
+ double vfofreq=((double) rx->pixels * 0.5)-(double)rx->pan;
//
// There are two options here in CW mode, depending on cw_is_on_vfo_freq.
vfofreq -= (double) cw_keyer_sidetone_frequency / HzPerPixel;
}
}
- long long min_display=frequency-half;
- long long max_display=frequency+half;
+ long long min_display=frequency-half+(long long)((double)rx->pan*HzPerPixel);
+ long long max_display=min_display+(long long)((double)rx->width*HzPerPixel);
if(vfoband==band60) {
for(i=0;i<channel_entries;i++) {
cairo_set_source_rgb (cr, 0.6, 0.3, 0.3);
cairo_rectangle(cr, x1, 0.0, x2-x1, (double)display_height);
cairo_fill(cr);
-/*
- cairo_set_source_rgba (cr, 0.5, 1.0, 0.0, 1.0);
- cairo_move_to(cr,(double)x1,0.0);
- cairo_line_to(cr,(double)x1,(double)display_height);
- cairo_stroke(cr);
- cairo_move_to(cr,(double)x2,0.0);
- cairo_line_to(cr,(double)x2,(double)display_height);
- cairo_stroke(cr);
-*/
}
}
// filter
cairo_set_source_rgba (cr, 0.25, 0.25, 0.25, 0.75);
- filter_left =(double)display_width*0.5 +(((double)rx->filter_low+offset)/HzPerPixel);
- filter_right=(double)display_width*0.5 +(((double)rx->filter_high+offset)/HzPerPixel);
+ //filter_left =(double)display_width*0.5 +(((double)rx->filter_low+offset)/HzPerPixel);
+ //filter_right=(double)display_width*0.5 +(((double)rx->filter_high+offset)/HzPerPixel);
+ filter_left =((double)rx->pixels*0.5)-(double)rx->pan +(((double)rx->filter_low+offset)/HzPerPixel);
+ filter_right=((double)rx->pixels*0.5)-(double)rx->pan +(((double)rx->filter_high+offset)/HzPerPixel);
cairo_rectangle(cr, filter_left, 0.0, filter_right-filter_left, (double)display_height);
cairo_fill(cr);
switch(rx->sample_rate) {
case 48000:
divisor=5000L;
+ switch(rx->zoom) {
+ case 2:
+ case 3:
+ case 4:
+ divisor=2000L;
+ break;
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ divisor=1000L;
+ break;
+ }
break;
case 96000:
case 100000:
divisor=10000L;
+ switch(rx->zoom) {
+ case 2:
+ case 3:
+ case 4:
+ divisor=5000L;
+ break;
+ case 5:
+ case 6:
+ divisor=2000L;
+ break;
+ case 7:
+ case 8:
+ divisor=1000L;
+ break;
+ }
break;
case 192000:
divisor=20000L;
+ switch(rx->zoom) {
+ case 2:
+ case 3:
+ divisor=10000L;
+ break;
+ case 4:
+ case 5:
+ case 6:
+ divisor=5000L;
+ break;
+ case 7:
+ case 8:
+ divisor=2000L;
+ break;
+ }
break;
case 384000:
divisor=50000L;
+ switch(rx->zoom) {
+ case 2:
+ case 3:
+ divisor=25000L;
+ break;
+ case 4:
+ case 5:
+ case 6:
+ divisor=10000L;
+ break;
+ case 7:
+ case 8:
+ divisor=5000L;
+ break;
+ }
break;
case 768000:
divisor=100000L;
+ switch(rx->zoom) {
+ case 2:
+ case 3:
+ divisor=50000L;
+ break;
+ case 4:
+ case 5:
+ case 6:
+ divisor=25000L;
+ break;
+ case 7:
+ case 8:
+ divisor=20000L;
+ break;
+ }
break;
case 1048576:
case 1536000:
case 2097152:
divisor=200000L;
+ switch(rx->zoom) {
+ case 2:
+ case 3:
+ divisor=100000L;
+ break;
+ case 4:
+ case 5:
+ case 6:
+ divisor=50000L;
+ break;
+ case 7:
+ case 8:
+ divisor=20000L;
+ break;
+ }
break;
}
for(i=0;i<display_width;i++) {
- f = frequency - half + (long) (HzPerPixel * i);
+ f = frequency - half + (long) (HzPerPixel * (i+rx->pan));
if (f > 0) {
if ((f % divisor) < (long) HzPerPixel) {
cairo_set_line_width(cr, 1.0);
- //cairo_move_to(cr,(double)i,0.0);
+ //cairo_move_to(cr,(double)x,0.0);
cairo_move_to(cr,(double)i,10.0);
cairo_line_to(cr,(double)i,(double)display_height);
// signal
double s1,s2;
- samples[0]=-200.0;
- samples[display_width-1]=-200.0;
+ samples[rx->pan]=-200.0;
+ samples[display_width-1+rx->pan]=-200.0;
if(have_rx_gain) {
- s1=(double)samples[0]+rx_gain_calibration-adc_attenuation[rx->adc];
+ s1=(double)samples[rx->pan]+rx_gain_calibration-adc_attenuation[rx->adc];
} else {
- s1=(double)samples[0]+(double)adc_attenuation[rx->adc];
+ s1=(double)samples[rx->pan]+(double)adc_attenuation[rx->adc];
}
if (filter_board == ALEX && rx->adc == 0) s1 += (double)(10*rx->alex_attenuation);
if (filter_board == CHARLY25) {
cairo_move_to(cr, 0.0, s1);
for(i=1;i<display_width;i++) {
if(have_rx_gain) {
- s2=(double)samples[i]+rx_gain_calibration-adc_attenuation[rx->adc];
+ s2=(double)samples[i+rx->pan]+rx_gain_calibration-adc_attenuation[rx->adc];
} else {
- s2=(double)samples[i]+(double)adc_attenuation[rx->adc];
+ s2=(double)samples[i+rx->pan]+(double)adc_attenuation[rx->adc];
}
if (filter_board == ALEX && rx->adc == 0) s2 += (double)(10*rx->alex_attenuation);
if (filter_board == CHARLY25) {
}
#endif
+ if(sequence_errors!=0) {
+ cairo_move_to(cr,100,20);
+ cairo_set_source_rgb(cr,1.0,0.0,0.0);
+ cairo_set_font_size(cr,12);
+ cairo_show_text(cr, "Sequence Error");
+ sequence_error_count++;
+ // show for 1 second
+ if(sequence_error_count==2*rx->fps) {
+ sequence_errors=0;
+ sequence_error_count=0;
+ }
+ }
+
+ if(rx->fexchange_errors!=0) {
+ cairo_move_to(cr,100,30);
+ cairo_set_source_rgb(cr,1.0,0.0,0.0);
+ cairo_set_font_size(cr,12);
+ cairo_show_text(cr, "fexchange Error");
+ fexchange_error_count++;
+ // show for 1 second
+ if(fexchange_error_count==2*rx->fps) {
+ rx->fexchange_errors=0;
+ fexchange_error_count=0;
+ }
+ }
+
cairo_destroy (cr);
gtk_widget_queue_draw (rx->panadapter);
static GtkWidget *sliders;
-enum {
- NO_FUNCTION=0,
- AF_GAIN,
- RF_GAIN,
- MIC_GAIN,
- LINEIN_GAIN,
- AGC_GAIN,
- DRIVE,
- ATTENUATION,
- SQUELCH,
- COMP,
- FILTER_WIDTH,
- FILTER_SHIFT,
- DIVERSITY_GAIN,
- DIVERSITY_PHASE,
-};
-
-static gint scale_timer;
-static int scale_status=NO_FUNCTION;
-static int scale_rx=0;
-static GtkWidget *scale_dialog;
+gint scale_timer;
+int scale_status=NO_FUNCTION;
+int scale_rx=0;
+GtkWidget *scale_dialog;
+
static GtkWidget *af_gain_label;
static GtkWidget *af_gain_scale;
static GtkWidget *rf_gain_label;
#include "receiver.h"
#include "transmitter.h"
+enum {
+ NO_FUNCTION=0,
+ AF_GAIN,
+ RF_GAIN,
+ MIC_GAIN,
+ LINEIN_GAIN,
+ AGC_GAIN,
+ DRIVE,
+ ATTENUATION,
+ SQUELCH,
+ COMP,
+ FILTER_WIDTH,
+ FILTER_SHIFT,
+ DIVERSITY_GAIN,
+ DIVERSITY_PHASE,
+ ZOOM,
+ PAN
+};
+
+extern gint scale_timer;
+extern gint scale_status;
+extern gint scale_rx;
+extern GtkWidget *scale_dialog;
+int scale_timeout_cb(gpointer data);
+
extern void att_type_changed(void);
extern void update_att_preamp(void);
}
fprintf(stderr,"\n");
free(rx_rates);
+
+ if(strcmp(driver,"lime")==0) {
+ sample_rate=768000;
+ } else if(strcmp(driver,"rtlsdr")==0) {
+ sample_rate=1024000;
+ } else if(strcmp(driver,"plutosdr")==0) {
+ sample_rate=2048000;
+ } else {
+ sample_rate=1024000;
+ }
+
fprintf(stderr,"sample_rate selected %d\n",sample_rate);
SoapySDRRange *tx_rates=SoapySDRDevice_getSampleRateRange(sdr, SOAPY_SDR_TX, 1, &tx_rates_length);
static SoapySDRDevice *soapy_device;
static SoapySDRStream *rx_stream;
static SoapySDRStream *tx_stream;
-static int soapy_rx_sample_rate;
static int max_samples;
static int samples=0;
void soapy_protocol_set_mic_sample_rate(int rate) {
mic_sample_divisor=rate/48000;
+g_print("soapy_protocol_set_mic_sample_rate: rate=%d mic_sample_divisor=%d\n",rate,mic_sample_divisor);
}
-void soapy_protocol_change_sample_rate(RECEIVER *rx,int rate) {
+void soapy_protocol_change_sample_rate(RECEIVER *rx) {
+g_print("soapy_protocol_change_sample_rate: %d\n",rx->sample_rate);
+ if(rx->sample_rate==radio_sample_rate) {
+ if(rx->resample_buffer!=NULL) {
+ g_free(rx->resample_buffer);
+ rx->resample_buffer=NULL;
+ rx->resample_buffer_size=0;
+ }
+ if(rx->resampler!=NULL) {
+ destroy_resample(rx->resampler);
+ rx->resampler=NULL;
+ }
+ } else {
+ if(rx->resample_buffer!=NULL) {
+ g_free(rx->resample_buffer);
+ rx->resample_buffer=NULL;
+ }
+ if(rx->resampler!=NULL) {
+ destroy_resample(rx->resampler);
+ rx->resampler=NULL;
+ }
+ rx->resample_buffer_size=2*max_samples/(radio_sample_rate/rx->sample_rate);
+ rx->resample_buffer=g_new(double,rx->resample_buffer_size);
+ rx->resampler=create_resample (1,max_samples,rx->buffer,rx->resample_buffer,radio_sample_rate,rx->sample_rate,0.0,0,1.0);
+
+g_print("soapy_protocol_change_sample_rate: buffer=%p buffer_size=%d resampler=%p\n",rx->resample_buffer,rx->resample_buffer_size,rx->resampler);
+ }
+
}
void soapy_protocol_create_receiver(RECEIVER *rx) {
int rc;
- soapy_rx_sample_rate=rx->sample_rate;
- if(rx->sample_rate!=radio_sample_rate) {
- soapy_rx_sample_rate=radio_sample_rate;
- }
- mic_sample_divisor=soapy_rx_sample_rate/48000;
+ mic_sample_divisor=rx->sample_rate/48000;
-fprintf(stderr,"soapy_protocol_create_receiver: setting samplerate=%f adc=%d mic_sample_divisor=%d\n",(double)soapy_rx_sample_rate,rx->adc,mic_sample_divisor);
- rc=SoapySDRDevice_setSampleRate(soapy_device,SOAPY_SDR_RX,rx->adc,(double)soapy_rx_sample_rate);
+fprintf(stderr,"soapy_protocol_create_receiver: setting samplerate=%f adc=%d mic_sample_divisor=%d\n",(double)radio_sample_rate,rx->adc,mic_sample_divisor);
+ rc=SoapySDRDevice_setSampleRate(soapy_device,SOAPY_SDR_RX,rx->adc,(double)radio_sample_rate);
if(rc!=0) {
- fprintf(stderr,"soapy_protocol_create_receiver: SoapySDRDevice_setSampleRate(%f) failed: %s\n",(double)soapy_rx_sample_rate,SoapySDR_errToStr(rc));
+ fprintf(stderr,"soapy_protocol_create_receiver: SoapySDRDevice_setSampleRate(%f) failed: %s\n",(double)radio_sample_rate,SoapySDR_errToStr(rc));
}
-
-
size_t channel=rx->adc;
#if defined(SOAPY_SDR_API_VERSION) && (SOAPY_SDR_API_VERSION < 0x00080000)
fprintf(stderr,"soapy_protocol_create_receiver: SoapySDRDevice_setupStream(version<0x00080000): channel=%ld\n",channel);
if(max_samples>(2*rx->fft_size)) {
max_samples=2*rx->fft_size;
}
+ if(max_samples>=4096) {
+ max_samples=4096;
+ } else if(max_samples>=2048) {
+ max_samples=2048;
+ } else {
+ max_samples=1024;
+ }
rx->buffer=g_new(double,max_samples*2);
+ if(rx->sample_rate==radio_sample_rate) {
+ rx->resample_buffer=NULL;
+ rx->resampler=NULL;
+ rx->resample_buffer_size=0;
+ } else {
+ rx->resample_buffer_size=2*max_samples/(radio_sample_rate/rx->sample_rate);
+ rx->resample_buffer=g_new(double,rx->resample_buffer_size);
+ rx->resampler=create_resample (1,max_samples,rx->buffer,rx->resample_buffer,radio_sample_rate,rx->sample_rate,0.0,0,1.0);
+ }
+
+
fprintf(stderr,"soapy_protocol_create_receiver: max_samples=%d buffer=%p\n",max_samples,rx->buffer);
}
rx->buffer[i*2]=(double)buffer[i*2];
rx->buffer[(i*2)+1]=(double)buffer[(i*2)+1];
}
- if(rx->sample_rate!=radio_sample_rate) {
- for(int i=0;i<elements;i+=rx->resample_step) {
- isample=rx->buffer[i*2];
- qsample=rx->buffer[(i*2)+1];
+
+
+ if(rx->resampler!=NULL) {
+ int samples=xresample(rx->resampler);
+ for(i=0;i<samples;i++) {
+ isample=rx->resample_buffer[i*2];
+ qsample=rx->resample_buffer[(i*2)+1];
if(iqswap) {
add_iq_samples(rx,qsample,isample);
} else {
if(can_transmit) {
mic_samples++;
if(mic_samples>=mic_sample_divisor) { // reduce to 48000
- fsample = transmitter->local_microphone ? audio_get_next_mic_sample() : (float)0.0;
+ if(transmitter!=NULL) {
+ fsample = transmitter->local_microphone ? audio_get_next_mic_sample() : 0.0F;
+ } else {
+ fsample=0.0F;
+ }
add_mic_sample(transmitter,fsample);
mic_samples=0;
}
if(can_transmit) {
mic_samples++;
if(mic_samples>=mic_sample_divisor) { // reduce to 48000
- fsample = transmitter->local_microphone ? audio_get_next_mic_sample() : (float)0.0;
+ if(transmitter!=NULL) {
+ fsample = transmitter->local_microphone ? audio_get_next_mic_sample() : 0.0F;
+ } else {
+ fsample=0.0F;
+ }
add_mic_sample(transmitter,fsample);
mic_samples=0;
}
void soapy_protocol_set_gain(RECEIVER *rx,double gain);
void soapy_protocol_set_gain_element(RECEIVER *rx,char *name,int gain);
int soapy_protocol_get_gain_element(RECEIVER *rx,char *name);
-void soapy_protocol_change_sample_rate(RECEIVER *rx,int rate);
+void soapy_protocol_change_sample_rate(RECEIVER *rx);
gboolean soapy_protocol_get_automatic_gain(RECEIVER *rx);
void soapy_protocol_set_automatic_gain(RECEIVER *rx,gboolean mode);
void soapy_protocol_create_transmitter(TRANSMITTER *tx);
if(!locked) {
if(vfo[id].ctun) {
+ // don't let ctun go beyond end of passband
+ long long frequency=vfo[id].frequency;
+ long long rx_low=((vfo[id].ctun_frequency/step + steps)*step)+active_receiver->filter_low;
+ long long rx_high=((vfo[id].ctun_frequency/step + steps)*step)+active_receiver->filter_high;
+ long long half=(long long)active_receiver->sample_rate/2LL;
+ long long min_freq=frequency-half;
+ long long max_freq=frequency+half;
+
+ if(rx_low<=min_freq) {
+ return;
+ } else if(rx_high>=max_freq) {
+ return;
+ }
+
delta=vfo[id].ctun_frequency;
vfo[id].ctun_frequency=(vfo[id].ctun_frequency/step + steps)*step;
delta=vfo[id].ctun_frequency - delta;
if(!locked) {
if(vfo[id].ctun) {
+ // don't let ctun go beyond end of passband
+ long long frequency=vfo[id].frequency;
+ long long rx_low=vfo[id].ctun_frequency+hz+active_receiver->filter_low;
+ long long rx_high=vfo[id].ctun_frequency+hz+active_receiver->filter_high;
+ long long half=(long long)active_receiver->sample_rate/2LL;
+ long long min_freq=frequency-half;
+ long long max_freq=frequency+half;
+
+ if(rx_low<=min_freq) {
+ return;
+ } else if(rx_high>=max_freq) {
+ return;
+ }
+
delta=vfo[id].ctun_frequency;
vfo[id].ctun_frequency=vfo[id].ctun_frequency+hz;
if(round && (vfo[id].mode!=modeCWL && vfo[id].mode!=modeCWU)) {
}
void vfo_move_to(long long hz) {
- // hz is the offset from the min frequency
+ // hz is the offset from the min displayed frequency
int id=active_receiver->id;
long long offset=hz;
long long half=(long long)(active_receiver->sample_rate/2);
if(vfo[id].mode!=modeCWL && vfo[id].mode!=modeCWU) {
offset=(hz/step)*step;
}
- f=(vfo[id].frequency-half)+offset;
+ f=(vfo[id].frequency-half)+offset+((double)active_receiver->pan*active_receiver->hz_per_pixel);
if(!locked) {
if(vfo[id].ctun) {
#ifdef PURESIGNAL
if(can_transmit) {
- //cairo_move_to(cr, 180, 15);
- cairo_move_to(cr, 55, 50);
+ cairo_move_to(cr, 130, 50);
if(transmitter->puresignal) {
cairo_set_source_rgb(cr, 1.0, 1.0, 0.0);
} else {
cairo_show_text(cr, "PS");
}
#endif
-
+
+ cairo_move_to(cr, 55, 50);
+ if(active_receiver->zoom>1) {
+ cairo_set_source_rgb(cr, 1.0, 1.0, 0.0);
+ } else {
+ cairo_set_source_rgb(cr, 0.7, 0.7, 0.7);
+ }
+ cairo_set_font_size(cr, 12);
+ sprintf(temp_text,"Zoom x%d",active_receiver->zoom);
+ cairo_show_text(cr, temp_text);
if(vfo[id].rit_enabled==0) {
cairo_set_source_rgb(cr, 0.7, 0.7, 0.7);
cairo_set_source_rgb(cr, 0.0, 1.0, 0.0);
}
sprintf(temp_text,"RIT: %lldHz",vfo[id].rit);
- //cairo_move_to(cr, 210, 15);
cairo_move_to(cr, 170, 15);
cairo_set_font_size(cr, 12);
cairo_show_text(cr, temp_text);
}
cairo_show_text(cr, "SNB");
- //cairo_move_to(cr, 300, 50);
cairo_move_to(cr, 270, 50);
switch(active_receiver->agc) {
case AGC_OFF:
// we should display the compressor (level)
//
if(can_transmit) {
- //cairo_move_to(cr, 400, 50);
cairo_move_to(cr, 330, 50);
if (transmitter->compressor) {
sprintf(temp_text,"CMPR %d dB",(int) transmitter->compressor_level);
s++;
}
sprintf(temp_text,"Step %s",step_labels[s]);
- //cairo_move_to(cr, 300, 15);
cairo_move_to(cr, 400, 15);
cairo_set_source_rgb(cr, 1.0, 1.0, 0.0);
cairo_show_text(cr, temp_text);
-/*
- cairo_move_to(cr, (my_width/4)*3, 50);
- cairo_show_text(cr, getFrequencyInfo(af));
-*/
-
- //cairo_move_to(cr, 400, 15);
cairo_move_to(cr, 430, 50);
if(vfo[id].ctun) {
cairo_set_source_rgb(cr, 1.0, 1.0, 0.0);
}
cairo_show_text(cr, "CTUN");
- //cairo_move_to(cr, 450, 15);
cairo_move_to(cr, 470, 50);
if(cat_control>0) {
cairo_set_source_rgb(cr, 1.0, 1.0, 0.0);
}
cairo_show_text(cr, "Locked");
- //cairo_move_to(cr, 55, 50);
cairo_move_to(cr, 260, 18);
if(split) {
cairo_set_source_rgb(cr, 1.0, 0.0, 0.0);
}
cairo_show_text(cr, "Split");
- //cairo_move_to(cr, 95, 50);
cairo_move_to(cr, 260, 28);
if(sat_mode!=SAT_NONE) {
cairo_set_source_rgb(cr, 1.0, 0.0, 0.0);
cairo_set_source_rgb(cr, 0.7, 0.7, 0.7);
}
sprintf(temp_text,"DUP");
- //cairo_move_to(cr, 130, 50);
cairo_move_to(cr, 260, 38);
cairo_set_font_size(cr, 12);
cairo_show_text(cr, temp_text);
samples=rx->pixel_samples;
for(i=0;i<width;i++) {
if(have_rx_gain) {
- sample=samples[i]+(float)(rx_gain_calibration-adc_attenuation[rx->adc]);
+ sample=samples[i+rx->pan]+(float)(rx_gain_calibration-adc_attenuation[rx->adc]);
} else {
- sample=samples[i]+(float)adc_attenuation[rx->adc];
+ sample=samples[i+rx->pan]+(float)adc_attenuation[rx->adc];
}
average+=(int)sample;
if(sample<(float)rx->waterfall_low) {
--- /dev/null
+/* Copyright (C)
+* 2015 - John Melton, G0ORX/N6LYT
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+*/
+
+//
+// DL1YCF:
+// uncomment the #define line following, then you will get
+// a "TX compression" slider with an enabling checkbox
+// in the bottom right of the sliders area, instead of the
+// sequelch slider and checkbox.
+// This option can also be passed to the compiler with "-D"
+// and thus be activated through the Makefile.
+//
+//#define COMPRESSION_SLIDER_INSTEAD_OF_SQUELCH 1
+//
+
+#include <gtk/gtk.h>
+#include <semaphore.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "main.h"
+#include "receiver.h"
+#include "radio.h"
+#include "vfo.h"
+#include "sliders.h"
+#include "zoompan.h"
+
+static int width;
+static int height;
+
+static GtkWidget *zoompan;
+static GtkWidget *zoom_label;
+static GtkWidget *zoom_scale;
+static GtkWidget *pan_label;
+static GtkWidget *pan_scale;
+
+static GdkRGBA white;
+static GdkRGBA gray;
+
+int zoompan_active_receiver_changed(void *data) {
+ if(display_zoompan) {
+ gtk_range_set_value(GTK_RANGE(zoom_scale),active_receiver->zoom);
+ gtk_range_set_range(GTK_RANGE(pan_scale),0.0,(double)(active_receiver->pixels-active_receiver->width));
+ gtk_range_set_value (GTK_RANGE(pan_scale),active_receiver->pan);
+ if(active_receiver->zoom == 1) {
+ gtk_widget_set_sensitive(pan_scale, FALSE);
+ }
+ }
+ return FALSE;
+}
+
+static void zoom_value_changed_cb(GtkWidget *widget, gpointer data) {
+ receiver_change_zoom(active_receiver,gtk_range_get_value(GTK_RANGE(zoom_scale)));
+ gtk_range_set_range(GTK_RANGE(pan_scale),0.0,(double)(active_receiver->pixels-active_receiver->width));
+ gtk_range_set_value (GTK_RANGE(pan_scale),active_receiver->pan);
+ if(active_receiver->zoom == 1) {
+ gtk_widget_set_sensitive(pan_scale, FALSE);
+ } else {
+ gtk_widget_set_sensitive(pan_scale, TRUE);
+ }
+ vfo_update();
+}
+
+void set_zoom(int rx,double value) {
+ receiver[rx]->zoom=value;
+ if(display_zoompan) {
+ gtk_range_set_value (GTK_RANGE(zoom_scale),receiver[rx]->zoom);
+ } else {
+ if(scale_status!=ZOOM || scale_rx!=rx) {
+ if(scale_status!=NO_FUNCTION) {
+ g_source_remove(scale_timer);
+ gtk_widget_destroy(scale_dialog);
+ scale_status=NO_FUNCTION;
+ }
+ }
+ if(scale_status==NO_FUNCTION) {
+ scale_status=ZOOM;
+ scale_rx=rx;
+ char title[64];
+ sprintf(title,"Zoom RX %d",rx);
+ scale_dialog=gtk_dialog_new_with_buttons(title,GTK_WINDOW(top_window),GTK_DIALOG_DESTROY_WITH_PARENT,NULL,NULL);
+ GtkWidget *content=gtk_dialog_get_content_area(GTK_DIALOG(scale_dialog));
+ zoom_scale=gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL,1.0, MAX_ZOOM, 1.00);
+ gtk_widget_set_size_request (zoom_scale, 400, 30);
+ gtk_range_set_value (GTK_RANGE(zoom_scale),receiver[rx]->zoom);
+ gtk_widget_show(zoom_scale);
+ gtk_container_add(GTK_CONTAINER(content),zoom_scale);
+ scale_timer=g_timeout_add(2000,scale_timeout_cb,NULL);
+ gtk_dialog_run(GTK_DIALOG(scale_dialog));
+ } else {
+ g_source_remove(scale_timer);
+ gtk_range_set_value (GTK_RANGE(zoom_scale),receiver[rx]->zoom);
+ scale_timer=g_timeout_add(2000,scale_timeout_cb,NULL);
+ }
+ }
+ vfo_update();
+}
+
+void update_zoom(double zoom) {
+ int z=active_receiver->zoom+(int)zoom;
+ if(z>MAX_ZOOM) z=MAX_ZOOM;
+ if(z<1) z=1;
+ set_zoom(active_receiver->id,z);
+}
+
+static void pan_value_changed_cb(GtkWidget *widget, gpointer data) {
+ receiver_change_pan(active_receiver,gtk_range_get_value(GTK_RANGE(pan_scale)));
+}
+
+void set_pan(int rx,double value) {
+ receiver[rx]->pan=(int)value;
+ if(display_zoompan) {
+ gtk_range_set_value (GTK_RANGE(pan_scale),receiver[rx]->pan);
+ } else {
+ if(scale_status!=PAN || scale_rx!=rx) {
+ if(scale_status!=NO_FUNCTION) {
+ g_source_remove(scale_timer);
+ gtk_widget_destroy(scale_dialog);
+ scale_status=NO_FUNCTION;
+ }
+ }
+ if(scale_status==NO_FUNCTION) {
+ scale_status=PAN;
+ scale_rx=rx;
+ char title[64];
+ sprintf(title,"Pan RX %d",rx);
+ scale_dialog=gtk_dialog_new_with_buttons(title,GTK_WINDOW(top_window),GTK_DIALOG_DESTROY_WITH_PARENT,NULL,NULL);
+ GtkWidget *content=gtk_dialog_get_content_area(GTK_DIALOG(scale_dialog));
+ pan_scale=gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL,0.0, active_receiver->zoom==1?active_receiver->pixels:active_receiver->pixels-active_receiver->width, 1.00);
+ gtk_widget_set_size_request (pan_scale, 400, 30);
+ gtk_range_set_value (GTK_RANGE(pan_scale),receiver[rx]->pan);
+ gtk_widget_show(pan_scale);
+ gtk_container_add(GTK_CONTAINER(content),pan_scale);
+ scale_timer=g_timeout_add(2000,scale_timeout_cb,NULL);
+ gtk_dialog_run(GTK_DIALOG(scale_dialog));
+ } else {
+ g_source_remove(scale_timer);
+ gtk_range_set_value (GTK_RANGE(pan_scale),receiver[rx]->pan);
+ scale_timer=g_timeout_add(2000,scale_timeout_cb,NULL);
+ }
+ }
+}
+
+void update_pan(double pan) {
+ int p=active_receiver->pan+(int)pan;
+ if(p<0) p=0;
+ if(p>(active_receiver->pixels-active_receiver->width)) p=active_receiver->pixels-active_receiver->width;
+ set_pan(active_receiver->id,p);
+}
+
+GtkWidget *zoompan_init(int my_width, int my_height) {
+ width=my_width;
+ height=my_height;
+
+fprintf(stderr,"zoompan_init: width=%d height=%d\n", width,height);
+
+ zoompan=gtk_grid_new();
+ gtk_widget_set_size_request (zoompan, width, height);
+ gtk_grid_set_row_homogeneous(GTK_GRID(zoompan), FALSE);
+ gtk_grid_set_column_homogeneous(GTK_GRID(zoompan),TRUE);
+
+ zoom_label=gtk_label_new("Zoom");
+ gtk_widget_override_font(zoom_label, pango_font_description_from_string("Sans 10"));
+ gtk_widget_show(zoom_label);
+ gtk_grid_attach(GTK_GRID(zoompan),zoom_label,0,0,1,1);
+
+ zoom_scale=gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL,1.0,MAX_ZOOM,1.00);
+ gtk_widget_override_font(zoom_scale, pango_font_description_from_string("Sans 10"));
+ gtk_range_set_increments (GTK_RANGE(zoom_scale),1.0,1.0);
+ gtk_range_set_value (GTK_RANGE(zoom_scale),active_receiver->zoom);
+ gtk_widget_show(zoom_scale);
+ gtk_grid_attach(GTK_GRID(zoompan),zoom_scale,1,0,2,1);
+ g_signal_connect(G_OBJECT(zoom_scale),"value_changed",G_CALLBACK(zoom_value_changed_cb),NULL);
+
+ pan_label=gtk_label_new("Pan:");
+ gtk_widget_override_font(pan_label, pango_font_description_from_string("Sans 10"));
+ gtk_widget_show(pan_label);
+ gtk_grid_attach(GTK_GRID(zoompan),pan_label,3,0,1,1);
+
+ pan_scale=gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL,0.0,active_receiver->zoom==1?active_receiver->pixels:active_receiver->pixels-active_receiver->width,1.0);
+ gtk_widget_override_font(pan_scale, pango_font_description_from_string("Sans 10"));
+ gtk_scale_set_draw_value (GTK_SCALE(pan_scale), FALSE);
+ gtk_range_set_increments (GTK_RANGE(pan_scale),10.0,10.0);
+ gtk_range_set_value (GTK_RANGE(pan_scale),active_receiver->pan);
+ gtk_widget_show(pan_scale);
+ gtk_grid_attach(GTK_GRID(zoompan),pan_scale,4,0,5,1);
+ g_signal_connect(G_OBJECT(pan_scale),"value_changed",G_CALLBACK(pan_value_changed_cb),NULL);
+
+ if(active_receiver->zoom == 1) {
+ gtk_widget_set_sensitive(pan_scale, FALSE);
+ }
+
+ return zoompan;
+}
--- /dev/null
+/* Copyright (C)
+* 2015 - John Melton, G0ORX/N6LYT
+*
+* 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 _ZOOMPAN_H
+#define _ZOOMPAN_H
+
+#define MAX_ZOOM 8
+
+extern GtkWidget *zoompan_init(int my_width, int my_height);
+extern int zoompan_active_receiver_changed(void *data);
+
+extern void update_pan(double pan);
+extern void update_zoom(double zoom);
+
+extern void set_pan(int rx,double value);
+extern void set_zoom(int rx,double value);
+#endif