1 /**
2  * Copyright (C) 2012-2014 Analog Devices, Inc.
3  *
4  * Licensed under the GPL-2.
5  *
6  **/
7 #include <stdio.h>
8 
9 #include <gtk/gtk.h>
10 #include <gtkdatabox.h>
11 #include <glib.h>
12 #include <gtkdatabox_grid.h>
13 #include <gtkdatabox_points.h>
14 #include <gtkdatabox_lines.h>
15 #include <math.h>
16 #include <stdint.h>
17 #include <errno.h>
18 #include <fcntl.h>
19 #include <stdbool.h>
20 #include <stdlib.h>
21 #include <sys/stat.h>
22 #include <string.h>
23 #include <unistd.h>
24 
25 #include <ad9361.h>
26 #include <iio.h>
27 
28 #include "../datatypes.h"
29 #include "../osc.h"
30 #include "../iio_widget.h"
31 #include "../libini2.h"
32 #include "../osc_plugin.h"
33 #include "../config.h"
34 #include "../eeprom.h"
35 #include "../fru.h"
36 #include "../iio_utils.h"
37 #include "block_diagram.h"
38 #include "dac_data_manager.h"
39 #include "fir_filter.h"
40 #include "scpi.h"
41 
42 #define HANNING_ENBW 1.50
43 
44 #define THIS_DRIVER "AD936X"
45 #define PHY_DEVICE "ad9361-phy"
46 #define DDS_DEVICE "cf-ad9361-dds-core-lpc"
47 #define CAP_DEVICE "cf-ad9361-lpc"
48 #define UDC_RX_DEVICE "adf4351-udc-rx-pmod"
49 #define UDC_TX_DEVICE "adf4351-udc-tx-pmod"
50 
51 #define ARRAY_SIZE(x) (!sizeof(x) ?: sizeof(x) / sizeof((x)[0]))
52 
53 #define MHZ_TO_HZ(x) ((x) * 1000000ul)
54 
55 #define REFCLK_RATE 40000000
56 
57 extern bool dma_valid_selection(const char *device, unsigned mask, unsigned channel_count);
58 
59 static struct dac_data_manager *dac_tx_manager;
60 
61 static bool is_2rx_2tx;
62 static bool has_udc_driver;
63 static bool can_update_widgets;
64 static bool tx_rssi_available;
65 
66 static const gdouble mhz_scale = 1000000.0;
67 static const gdouble inv_scale = -1.0;
68 
69 static const char *freq_name;
70 
71 static volatile int auto_calibrate = 0;
72 static unsigned int dcxo_coarse_num, dcxo_fine_num;
73 struct tuning_param
74 {
75 	double frequency;
76 	int coarse;
77 	int fine;
78 };
79 
80 static struct iio_widget widgets[100];
81 static struct iio_widget *glb_widgets, *tx_widgets, *rx_widgets, *fpga_widgets;
82 static unsigned int rx1_gain, rx2_gain;
83 static unsigned int num_glb, num_tx, num_rx, num_fpga;
84 static unsigned int rx_lo, tx_lo;
85 static unsigned int rx_sample_freq, tx_sample_freq;
86 static double updn_freq_span;
87 static double updn_freq_mix_sign;
88 static char last_fir_filter[PATH_MAX];
89 static char *rx_fastlock_store_name, *rx_fastlock_recall_name;
90 static char *tx_fastlock_store_name, *tx_fastlock_recall_name;
91 
92 static struct iio_context *ctx;
93 static struct iio_device *dev, *dds, *cap, *udc_rx, *udc_tx;
94 
95 #define SECTION_GLOBAL 0
96 #define SECTION_TX 1
97 #define SECTION_RX 2
98 #define SECTION_FPGA 3
99 static GtkToggleToolButton *section_toggle[4];
100 static GtkWidget *section_setting[4];
101 
102 /* Widgets for Global Settings */
103 static GtkWidget *ensm_mode;
104 static GtkWidget *ensm_mode_available;
105 static GtkWidget *calib_mode;
106 static GtkWidget *calib_mode_available;
107 static GtkWidget *trx_rate_governor;
108 static GtkWidget *trx_rate_governor_available;
109 static GtkWidget *filter_fir_config;
110 static GtkWidget *up_down_converter;
111 static GtkWidget *dcxo_cal_progressbar;
112 static GtkWidget *dcxo_cal_type;
113 static GtkWidget *dcxo_cal;
114 static GtkWidget *enable_auto_filter;
115 static GtkWidget *dcxo_cal_tab;
116 
117 /* Widgets for Receive Settings */
118 static GtkWidget *rx_gain_control_rx1;
119 static GtkWidget *rx_gain_control_modes_rx1;
120 static GtkWidget *rf_port_select_rx;
121 static GtkWidget *rx_gain_control_rx2;
122 static GtkWidget *rx_gain_control_modes_rx2;
123 static GtkWidget *rx1_rssi;
124 static GtkWidget *rx2_rssi;
125 static GtkWidget *tx1_rssi;
126 static GtkWidget *tx2_rssi;
127 static GtkWidget *rx_path_rates;
128 static GtkWidget *tx_path_rates;
129 static GtkWidget *fir_filter_en_tx;
130 static GtkWidget *enable_fir_filter_rx;
131 static GtkWidget *enable_fir_filter_rx_tx;
132 static GtkWidget *disable_all_fir_filters;
133 static GtkWidget *rf_port_select_tx;
134 static GtkWidget *rx_fastlock_profile;
135 static GtkWidget *tx_fastlock_profile;
136 static GtkWidget *rx_phase_rotation[2];
137 
138 static GtkWidget *fpga_tx_frequency_available;
139 static GtkWidget *fpga_rx_frequency_available;
140 
141 static GtkWidget *sampling_freq_rx_decim;
142 static GtkWidget *sampling_freq_tx_inter;
143 
144 static gint this_page;
145 static GtkNotebook *nbook;
146 static GtkWidget *fmcomms2_panel;
147 static gboolean plugin_detached;
148 
149 static const char *fmcomms2_sr_attribs[] = {
150 	PHY_DEVICE".trx_rate_governor",
151 	PHY_DEVICE".dcxo_tune_coarse",
152 	PHY_DEVICE".dcxo_tune_fine",
153 	PHY_DEVICE".xo_correction",
154 	PHY_DEVICE".ensm_mode",
155 	PHY_DEVICE".in_voltage0_rf_port_select",
156 	PHY_DEVICE".in_voltage0_gain_control_mode",
157 	PHY_DEVICE".in_voltage0_hardwaregain",
158 	PHY_DEVICE".in_voltage1_gain_control_mode",
159 	PHY_DEVICE".in_voltage1_hardwaregain",
160 	PHY_DEVICE".in_voltage_bb_dc_offset_tracking_en",
161 	PHY_DEVICE".in_voltage_quadrature_tracking_en",
162 	PHY_DEVICE".in_voltage_rf_dc_offset_tracking_en",
163 	PHY_DEVICE".out_voltage0_rf_port_select",
164 	PHY_DEVICE".out_altvoltage0_RX_LO_external",
165 	PHY_DEVICE".out_altvoltage1_TX_LO_external",
166 	PHY_DEVICE".out_altvoltage0_RX_LO_frequency",
167 	PHY_DEVICE".out_altvoltage1_TX_LO_frequency",
168 	PHY_DEVICE".out_voltage0_hardwaregain",
169 	PHY_DEVICE".out_voltage1_hardwaregain",
170 	PHY_DEVICE".out_voltage_sampling_frequency",
171 	PHY_DEVICE".in_voltage_rf_bandwidth",
172 	PHY_DEVICE".out_voltage_rf_bandwidth",
173 	PHY_DEVICE".in_voltage_filter_fir_en",
174 	PHY_DEVICE".out_voltage_filter_fir_en",
175 	PHY_DEVICE".in_out_voltage_filter_fir_en",
176 
177 	DDS_DEVICE".out_altvoltage0_TX1_I_F1_frequency",
178 	DDS_DEVICE".out_altvoltage0_TX1_I_F1_phase",
179 	DDS_DEVICE".out_altvoltage0_TX1_I_F1_scale",
180 	DDS_DEVICE".out_altvoltage1_TX1_I_F2_frequency",
181 	DDS_DEVICE".out_altvoltage1_TX1_I_F2_phase",
182 	DDS_DEVICE".out_altvoltage1_TX1_I_F2_scale",
183 	DDS_DEVICE".out_altvoltage2_TX1_Q_F1_frequency",
184 	DDS_DEVICE".out_altvoltage2_TX1_Q_F1_phase",
185 	DDS_DEVICE".out_altvoltage2_TX1_Q_F1_scale",
186 	DDS_DEVICE".out_altvoltage3_TX1_Q_F2_frequency",
187 	DDS_DEVICE".out_altvoltage3_TX1_Q_F2_phase",
188 	DDS_DEVICE".out_altvoltage3_TX1_Q_F2_scale",
189 	DDS_DEVICE".out_altvoltage4_TX2_I_F1_frequency",
190 	DDS_DEVICE".out_altvoltage4_TX2_I_F1_phase",
191 	DDS_DEVICE".out_altvoltage4_TX2_I_F1_scale",
192 	DDS_DEVICE".out_altvoltage5_TX2_I_F2_frequency",
193 	DDS_DEVICE".out_altvoltage5_TX2_I_F2_phase",
194 	DDS_DEVICE".out_altvoltage5_TX2_I_F2_scale",
195 	DDS_DEVICE".out_altvoltage6_TX2_Q_F1_frequency",
196 	DDS_DEVICE".out_altvoltage6_TX2_Q_F1_phase",
197 	DDS_DEVICE".out_altvoltage6_TX2_Q_F1_scale",
198 	DDS_DEVICE".out_altvoltage7_TX2_Q_F2_frequency",
199 	DDS_DEVICE".out_altvoltage7_TX2_Q_F2_phase",
200 	DDS_DEVICE".out_altvoltage7_TX2_Q_F2_scale",
201 
202 	UDC_RX_DEVICE".out_altvoltage0_frequency",
203 	UDC_TX_DEVICE".out_altvoltage0_frequency",
204 };
205 
206 static const char * fmcomms2_driver_attribs[] = {
207 	"load_fir_filter_file",
208 	"dds_mode_tx1",
209 	"dds_mode_tx2",
210 	"global_settings_show",
211 	"tx_show",
212 	"rx_show",
213 	"fpga_show",
214 	"up_down_converter",
215 	"tx_channel_0",
216 	"tx_channel_1",
217 	"tx_channel_2",
218 	"tx_channel_3",
219 	"dac_buf_filename",
220 };
221 
glb_settings_update_labels(void)222 static void glb_settings_update_labels(void)
223 {
224 	float rates[6];
225 	char tmp[160], buf[1024];
226 	ssize_t ret;
227 
228 	ret = iio_device_attr_read(dev, "ensm_mode", buf, sizeof(buf));
229 	if (ret > 0)
230 		gtk_label_set_text(GTK_LABEL(ensm_mode), buf);
231 	else
232 		gtk_label_set_text(GTK_LABEL(ensm_mode), "<error>");
233 
234 	ret = iio_device_attr_read(dev, "calib_mode", buf, sizeof(buf));
235 	if (ret > 0)
236 		gtk_label_set_text(GTK_LABEL(calib_mode), buf);
237 	else
238 		gtk_label_set_text(GTK_LABEL(calib_mode), "<error>");
239 
240 	ret = iio_device_attr_read(dev, "trx_rate_governor", buf, sizeof(buf));
241 	if (ret > 0)
242 		gtk_label_set_text(GTK_LABEL(trx_rate_governor), buf);
243 	else
244 		gtk_label_set_text(GTK_LABEL(trx_rate_governor), "<error>");
245 
246 	ret = iio_channel_attr_read(
247 			iio_device_find_channel(dev, "voltage0", false),
248 			"gain_control_mode", buf, sizeof(buf));
249 	if (ret > 0)
250 		gtk_label_set_text(GTK_LABEL(rx_gain_control_rx1), buf);
251 	else
252 		gtk_label_set_text(GTK_LABEL(rx_gain_control_rx1), "<error>");
253 
254 	if (is_2rx_2tx) {
255 		ret = iio_channel_attr_read(
256 				iio_device_find_channel(dev, "voltage1", false),
257 				"gain_control_mode", buf, sizeof(buf));
258 		if (ret > 0)
259 			gtk_label_set_text(GTK_LABEL(rx_gain_control_rx2), buf);
260 		else
261 			gtk_label_set_text(GTK_LABEL(rx_gain_control_rx2), "<error>");
262 	}
263 
264 	ret = iio_device_attr_read(dev, "rx_path_rates", buf, sizeof(buf));
265 	if (ret > 0) {
266 		sscanf(buf, "BBPLL:%f ADC:%f R2:%f R1:%f RF:%f RXSAMP:%f",
267 		        &rates[0], &rates[1], &rates[2], &rates[3], &rates[4],
268 			&rates[5]);
269 		sprintf(tmp, "BBPLL: %4.3f   ADC: %4.3f   R2: %4.3f   R1: %4.3f   RF: %4.3f   RXSAMP: %4.3f",
270 		        rates[0] / 1e6, rates[1] / 1e6, rates[2] / 1e6,
271 			rates[3] / 1e6, rates[4] / 1e6, rates[5] / 1e6);
272 
273 		gtk_label_set_text(GTK_LABEL(rx_path_rates), tmp);
274 	} else {
275 		gtk_label_set_text(GTK_LABEL(rx_path_rates), "<error>");
276 	}
277 
278 	ret = iio_device_attr_read(dev, "tx_path_rates", buf, sizeof(buf));
279 	if (ret > 0) {
280 		sscanf(buf, "BBPLL:%f DAC:%f T2:%f T1:%f TF:%f TXSAMP:%f",
281 		        &rates[0], &rates[1], &rates[2], &rates[3], &rates[4],
282 			&rates[5]);
283 		sprintf(tmp, "BBPLL: %4.3f   DAC: %4.3f   T2: %4.3f   T1: %4.3f   TF: %4.3f   TXSAMP: %4.3f",
284 		        rates[0] / 1e6, rates[1] / 1e6, rates[2] / 1e6,
285 			rates[3] / 1e6, rates[4] / 1e6, rates[5] / 1e6);
286 
287 		gtk_label_set_text(GTK_LABEL(tx_path_rates), tmp);
288 	} else {
289 		gtk_label_set_text(GTK_LABEL(tx_path_rates), "<error>");
290 	}
291 
292 	iio_widget_update(&rx_widgets[rx1_gain]);
293 	if (is_2rx_2tx)
294 		iio_widget_update(&rx_widgets[rx2_gain]);
295 }
296 
rf_port_select_rx_changed_cb(GtkComboBoxText * cmb,gpointer data)297 static void rf_port_select_rx_changed_cb(GtkComboBoxText *cmb, gpointer data)
298 {
299 	gchar *port_name;
300 	bool tx1 = false, tx2 = false;
301 
302 	port_name = gtk_combo_box_text_get_active_text(cmb);
303 	if (!port_name)
304 		return;
305 
306 	if (!strcmp(port_name, "TX_MONITOR1")) {
307 		tx1 = true;
308 	} else if (!strcmp(port_name, "TX_MONITOR2")) {
309 		tx2 = true;
310 	} else if (!strcmp(port_name, "TX_MONITOR1_2")) {
311 		tx1 = tx2 = true;
312 	}
313 	gtk_widget_set_visible(tx1_rssi, tx1);
314 	gtk_widget_set_visible(tx2_rssi, tx2);
315 
316 	g_free(port_name);
317 }
318 
rx_freq_info_update(void)319 static void rx_freq_info_update(void)
320 {
321 	double lo_freq;
322 
323 	if (cap)
324 		rx_update_device_sampling_freq(CAP_DEVICE,
325 						USE_INTERN_SAMPLING_FREQ);
326 	lo_freq = mhz_scale * gtk_spin_button_get_value(
327 			GTK_SPIN_BUTTON(rx_widgets[rx_lo].widget));
328 	if (cap)
329 		rx_update_channel_lo_freq(CAP_DEVICE, "all", lo_freq);
330 }
331 
int_dec_freq_update(void)332 static void int_dec_freq_update(void)
333 {
334 	struct iio_channel *ch;
335 	double freq;
336 
337 	if (cap) {
338 		ch = iio_device_find_channel(cap, "voltage0", false);
339 		iio_channel_attr_read_double(ch, "sampling_frequency", &freq);
340 		gtk_spin_button_set_value(GTK_SPIN_BUTTON(sampling_freq_rx_decim), freq / mhz_scale);
341 	}
342 
343 	if (dds) {
344 		ch = iio_device_find_channel(dds, "voltage0", true);
345 		iio_channel_attr_read_double(ch, "sampling_frequency", &freq);
346 		gtk_spin_button_set_value(GTK_SPIN_BUTTON(sampling_freq_tx_inter), freq / mhz_scale);
347 	}
348 }
349 
sample_frequency_changed_cb(void * data)350 static void sample_frequency_changed_cb(void *data)
351 {
352 	glb_settings_update_labels();
353 	rx_freq_info_update();
354 	iio_update_widgets(fpga_widgets, num_fpga);
355 	int_dec_freq_update();
356 }
357 
get_gui_tx_sampling_freq(void)358 static double get_gui_tx_sampling_freq(void)
359 {
360 	return gtk_spin_button_get_value(GTK_SPIN_BUTTON(tx_widgets[tx_sample_freq].widget));
361 }
362 
363 static void filter_fir_update(void); /* forwrad declaration */
364 
tx_sample_frequency_changed_cb(void * data)365 static void tx_sample_frequency_changed_cb(void *data)
366 {
367 	double rate;
368 	bool auto_fir;
369 
370 	/* Skip rx_sample_freq changed, since RX and TX rates are always the same */
371 	if (!data)
372 		return;
373 
374 	auto_fir = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (enable_auto_filter));
375 	rate = get_gui_tx_sampling_freq();
376 
377 	if (auto_fir) {
378 		ad9361_set_bb_rate (dev, (unsigned long) (rate * 1000000));
379 		gtk_widget_show(enable_fir_filter_rx_tx);
380 		gtk_widget_show(disable_all_fir_filters);
381 		filter_fir_update();
382 		gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(filter_fir_config), "(None)");
383 	} else {
384 		iio_spin_button_save(&tx_widgets[tx_sample_freq]);
385 	}
386 	/* We've set the sampling freq. Now read back the value and update the widget. */
387 	iio_widget_update(&tx_widgets[tx_sample_freq]);
388 
389 	dac_data_manager_freq_widgets_range_update(dac_tx_manager, rate / 2.0);
390 	sample_frequency_changed_cb(NULL);
391 }
392 
rssi_update_label(GtkWidget * label,const char * chn,bool is_tx)393 static void rssi_update_label(GtkWidget *label, const char *chn,  bool is_tx)
394 {
395 	char buf[1024];
396 	int ret;
397 
398 	/* don't update if it is hidden (to quiet down SPI) */
399 	if (!gtk_widget_is_drawable(GTK_WIDGET(label)))
400 		return;
401 
402 	ret = iio_channel_attr_read(
403 			iio_device_find_channel(dev, chn, is_tx),
404 			"rssi", buf, sizeof(buf));
405 	if (ret > 0)
406 		gtk_label_set_text(GTK_LABEL(label), buf);
407 	else
408 		gtk_label_set_text(GTK_LABEL(label), "<error>");
409 }
410 
rssi_update_labels(void)411 static void rssi_update_labels(void)
412 {
413 	rssi_update_label(rx1_rssi, "voltage0", false);
414 	if (tx_rssi_available)
415 		rssi_update_label(tx1_rssi, "voltage0", true);
416 	if (is_2rx_2tx) {
417 		rssi_update_label(rx2_rssi, "voltage1", false);
418 		if (tx_rssi_available)
419 			rssi_update_label(tx2_rssi, "voltage1", true);
420 	}
421 }
422 
update_display(gpointer foo)423 static gboolean update_display(gpointer foo)
424 {
425 	if (this_page == gtk_notebook_get_current_page(nbook) || plugin_detached) {
426 		gchar *gain_mode;
427 
428 		rssi_update_labels();
429 		gain_mode = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(rx_gain_control_modes_rx1));
430 		if (gain_mode && strcmp(gain_mode, "manual"))
431 			iio_widget_update(&rx_widgets[rx1_gain]);
432 		g_free(gain_mode);
433 
434 		gain_mode = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(rx_gain_control_modes_rx2));
435 		if (is_2rx_2tx && gain_mode && strcmp(gain_mode, "manual"))
436 			iio_widget_update(&rx_widgets[rx2_gain]);
437 		g_free(gain_mode);
438 	}
439 
440 	return TRUE;
441 }
442 
443 const double RX_CENTER_FREQ = 340; /* MHz */
444 const double TX_CENTER_FREQ = 370; /* MHz */
445 
get_span_multiple_from(double frequency,double span)446 static double get_span_multiple_from(double frequency, double span)
447 {
448 	double num = 0;
449 
450 	if (span <= 0)
451 		return 0;
452 
453 	while (num <= frequency)
454 		num += span;
455 
456 	return (num - span);
457 }
458 
split_target_lo_freq(double target_freq,double * ext_pll,double * ad9361_lo,double span,const double center_freq)459 static int split_target_lo_freq(double target_freq, double *ext_pll, double *ad9361_lo,
460 		double span, const double center_freq)
461 {
462 	double small_freq, large_freq;
463 
464 	large_freq = get_span_multiple_from(target_freq, span);
465 	small_freq = target_freq - large_freq;
466 
467 	*ad9361_lo = center_freq - small_freq * updn_freq_mix_sign;
468 	*ext_pll = center_freq + large_freq * updn_freq_mix_sign;
469 
470 	return 0;
471 }
472 
473 #define UPDN_RX 1
474 #define UPDN_TX 2
475 
updn_converter_lo_freq_changed_cb(GtkSpinButton * button,int data)476 static void updn_converter_lo_freq_changed_cb(GtkSpinButton *button, int data)
477 {
478 	struct iio_channel *ad9361_ch, *updn_ch;
479 	double target_freq, ad9361_lo, updn_pll, center_freq;
480 	int ret;
481 
482 	if (data == UPDN_RX) {
483 		ad9361_ch = iio_device_find_channel(dev, "altvoltage0", true);
484 		updn_ch = iio_device_find_channel(udc_rx, "altvoltage0", true);
485 		center_freq = RX_CENTER_FREQ;
486 	} else if (data == UPDN_TX) {
487 		ad9361_ch = iio_device_find_channel(dev, "altvoltage1", true);
488 		updn_ch = iio_device_find_channel(udc_tx, "altvoltage0", true);
489 		center_freq = TX_CENTER_FREQ;
490 	} else {
491 		return;
492 	}
493 
494 	target_freq = gtk_spin_button_get_value(button);
495 	split_target_lo_freq(target_freq, &updn_pll, &ad9361_lo, updn_freq_span, center_freq);
496 	ret = iio_channel_attr_write_longlong(ad9361_ch, freq_name, (long long)MHZ_TO_HZ(ad9361_lo));
497 	if (ret < 0)
498 		fprintf(stderr,"Write to %s attribute of %s device: %s\n",
499 			freq_name, PHY_DEVICE, strerror(-ret));
500 	ret = iio_channel_attr_write_longlong(updn_ch, "frequency", (long long)MHZ_TO_HZ(updn_pll));
501 	if (ret < 0)
502 		fprintf(stderr,"Write to %s attribute of %s device: %s\n",
503 			"frequency", (UPDN_TX) ? UDC_TX_DEVICE : UDC_RX_DEVICE, strerror(-ret));
504 	rx_freq_info_update();
505 }
506 
507 #define UPDN_LO_FREQ_MIN 1   /* MHz */
508 #define UPDN_LO_FREQ_MAX 120 /* MHz */
509 
up_down_converter_toggled_cb(GtkToggleButton * button,gpointer data)510 static void up_down_converter_toggled_cb(GtkToggleButton *button, gpointer data)
511 {
512 	static gint rx_updn_hid, tx_updn_hid;
513 	static gdouble lo_min, lo_max;
514 	static void (*rx_lo_update_value)(struct iio_widget *, const char *, size_t);
515 	static void (*tx_lo_update_value)(struct iio_widget *, const char *, size_t);
516 
517 	if (gtk_toggle_button_get_active(button)) {
518 		iio_spin_button_progress_deactivate(&rx_widgets[rx_lo]);
519 		iio_spin_button_progress_deactivate(&tx_widgets[tx_lo]);
520 		rx_updn_hid = g_signal_connect(rx_widgets[rx_lo].widget, "value-changed",
521 			G_CALLBACK(updn_converter_lo_freq_changed_cb), (gpointer)UPDN_RX);
522 		tx_updn_hid = g_signal_connect(tx_widgets[tx_lo].widget, "value-changed",
523 			G_CALLBACK(updn_converter_lo_freq_changed_cb), (gpointer)UPDN_TX);
524 		gtk_spin_button_get_range(GTK_SPIN_BUTTON(rx_widgets[rx_lo].widget), &lo_min, &lo_max);
525 		gtk_spin_button_set_range(GTK_SPIN_BUTTON(rx_widgets[rx_lo].widget), UPDN_LO_FREQ_MIN, UPDN_LO_FREQ_MAX);
526 		gtk_spin_button_set_range(GTK_SPIN_BUTTON(tx_widgets[tx_lo].widget), UPDN_LO_FREQ_MIN, UPDN_LO_FREQ_MAX);
527 		rx_lo_update_value = rx_widgets[rx_lo].update_value;
528 		tx_lo_update_value = tx_widgets[tx_lo].update_value;
529 		rx_widgets[rx_lo].update_value = NULL;
530 		tx_widgets[tx_lo].update_value = NULL;
531 	} else {
532 		g_signal_handler_disconnect(rx_widgets[rx_lo].widget, rx_updn_hid);
533 		g_signal_handler_disconnect(tx_widgets[tx_lo].widget, tx_updn_hid);
534 		rx_widgets[rx_lo].update_value = rx_lo_update_value;
535 		tx_widgets[tx_lo].update_value = tx_lo_update_value;
536 		iio_spin_button_progress_activate(&rx_widgets[rx_lo]);
537 		iio_spin_button_progress_activate(&tx_widgets[tx_lo]);
538 		g_signal_emit_by_name(rx_widgets[rx_lo].widget,
539 			"value-changed", NULL);
540 		g_signal_emit_by_name(tx_widgets[tx_lo].widget,
541 			"value-changed", NULL);
542 		gtk_spin_button_set_range(GTK_SPIN_BUTTON(rx_widgets[rx_lo].widget), lo_min, lo_max);
543 		gtk_spin_button_set_range(GTK_SPIN_BUTTON(tx_widgets[tx_lo].widget), lo_min, lo_max);
544 	}
545 }
546 
rx_phase_rotation_update()547 static void rx_phase_rotation_update()
548 {
549 	struct iio_channel *out[4];
550 	gdouble val[4];
551 	int i, d = 0;
552 
553 	if (!cap)
554 		return;
555 
556 	out[0] = iio_device_find_channel(cap, "voltage0", false);
557 	out[1] = iio_device_find_channel(cap, "voltage1", false);
558 
559 	if (is_2rx_2tx) {
560 		out[2] = iio_device_find_channel(cap, "voltage2", false);
561 		out[3] = iio_device_find_channel(cap, "voltage3", false);
562 		d = 2;
563 	}
564 
565 	for (i = 0; i <= d; i += 2) {
566 		iio_channel_attr_read_double(out[i], "calibscale", &val[0]);
567 		iio_channel_attr_read_double(out[i], "calibphase", &val[1]);
568 		iio_channel_attr_read_double(out[i + 1], "calibscale", &val[2]);
569 		iio_channel_attr_read_double(out[i + 1], "calibphase", &val[3]);
570 
571 		val[0] = acos(val[0]) * 360.0 / (2.0 * M_PI);
572 		val[1] = asin(-1.0 * val[1]) * 360.0 / (2.0 * M_PI);
573 		val[2] = acos(val[2]) * 360.0 / (2.0 * M_PI);
574 		val[3] = asin(val[3]) * 360.0 / (2.0 * M_PI);
575 
576 		if (val[1] < 0.0)
577 			val[0] *= -1.0;
578 		if (val[3] < 0.0)
579 			val[2] *= -1.0;
580 		if (val[1] < -90.0)
581 			val[0] = (val[0] * -1.0) - 180.0;
582 		if (val[3] < -90.0)
583 			val[0] = (val[0] * -1.0) - 180.0;
584 
585 		if (fabs(val[0]) > 90.0) {
586 			if (val[1] < 0.0)
587 				val[1] = (val[1] * -1.0) - 180.0;
588 			else
589 				val[1] = 180 - val[1];
590 		}
591 		if (fabs(val[2]) > 90.0) {
592 			if (val[3] < 0.0)
593 				val[3] = (val[3] * -1.0) - 180.0;
594 			else
595 				val[3] = 180 - val[3];
596 		}
597 
598 		if (round(val[0]) != round(val[1]) &&
599 					round(val[0]) != round(val[2]) &&
600 					round(val[0]) != round(val[3])) {
601 			printf("error calculating phase rotations\n");
602 			val[0] = 0.0;
603 		} else
604 			val[0] = (val[0] + val[1] + val[2] + val[3]) / 4.0;
605 
606 		gtk_spin_button_set_value(GTK_SPIN_BUTTON(rx_phase_rotation[i/2]), val[0]);
607 	}
608 }
609 
dcxo_widgets_update(void)610 static void dcxo_widgets_update(void)
611 {
612 	char val[64];
613 	int ret;
614 
615 	ret = iio_device_attr_read(dev, "dcxo_tune_coarse", val, sizeof(val));
616 
617 	if (ret < 0)
618 		gtk_widget_hide(dcxo_cal_tab);
619 	else
620 		gtk_widget_show(dcxo_cal_tab);
621 }
622 
int_dec_update_cb(GtkComboBox * cmb,gpointer data)623 static void int_dec_update_cb(GtkComboBox *cmb, gpointer data)
624 {
625 	if (gtk_combo_box_get_active(cmb) > 0)
626 		gtk_widget_show(GTK_WIDGET(data));
627 	else
628 		gtk_widget_hide(GTK_WIDGET(data));
629 
630 	int_dec_freq_update();
631 	rx_freq_info_update();
632 }
633 
int_dec_spin_update_cb(GtkSpinButton * spin,gpointer data)634 static void int_dec_spin_update_cb(GtkSpinButton *spin, gpointer data)
635 {
636 	struct iio_channel *chn = data;
637 	double fpga, freq, trx;
638 
639 	freq = mhz_scale * gtk_spin_button_get_value(spin);
640 	iio_channel_attr_read_double(chn, "sampling_frequency", &fpga);
641 	trx = mhz_scale * gtk_spin_button_get_value(
642 		GTK_SPIN_BUTTON(tx_widgets[tx_sample_freq].widget));
643 
644 	gtk_spin_button_set_value(GTK_SPIN_BUTTON(tx_widgets[tx_sample_freq].widget),
645 		 (trx/fpga * freq) / mhz_scale);
646 
647 }
648 
update_widgets(void)649 static void update_widgets(void)
650 {
651 	iio_update_widgets_of_device(widgets, num_glb + num_tx + num_rx, dev);
652 	if (dds)
653 		iio_update_widgets_of_device(fpga_widgets, num_fpga, dds);
654 	if (cap)
655 		iio_update_widgets_of_device(fpga_widgets, num_fpga, cap);
656 	dac_data_manager_update_iio_widgets(dac_tx_manager);
657 	dcxo_widgets_update();
658 }
659 
filter_fir_update(void)660 static void filter_fir_update(void)
661 {
662 	bool rx = false, tx = false, rxtx;
663 	struct iio_channel *chn;
664 	int stat;
665 
666 	ad9361_get_trx_fir_enable(dev, &stat);
667 	rxtx = !!stat;
668 
669 	chn = iio_device_find_channel(dev, "voltage0", false);
670 	if (chn)
671 		iio_channel_attr_read_bool(chn, "filter_fir_en", &rx);
672 	chn = iio_device_find_channel(dev, "voltage0", true);
673 	if (chn)
674 		iio_channel_attr_read_bool(chn, "filter_fir_en", &tx);
675 
676 	if (rxtx) {
677 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (enable_fir_filter_rx_tx), rxtx);
678 	} else if (!rx && !tx) {
679 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (disable_all_fir_filters), true);
680 	} else {
681 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (enable_fir_filter_rx), rx);
682 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (fir_filter_en_tx), tx);
683 	}
684 }
685 
filter_fir_enable(GtkToggleButton * button,gpointer data)686 static void filter_fir_enable(GtkToggleButton *button, gpointer data)
687 {
688 	bool rx, tx, rxtx, disable;
689 
690 	if (gtk_toggle_button_get_active(button))
691 		return;
692 
693 	rx = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (enable_fir_filter_rx));
694 	tx = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (fir_filter_en_tx));
695 	rxtx = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (enable_fir_filter_rx_tx));
696 	disable = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (disable_all_fir_filters));
697 
698 	if (rxtx || disable) {
699 		ad9361_set_trx_fir_enable(dev, rxtx);
700 	} else {
701 		struct iio_channel *chn;
702 		if (rx) {
703 			chn = iio_device_find_channel(dev, "voltage0", true);
704 			if (chn)
705 				iio_channel_attr_write_bool(chn, "filter_fir_en", tx);
706 
707 			chn = iio_device_find_channel(dev, "voltage0", false);
708 			if (chn)
709 				iio_channel_attr_write_bool(chn, "filter_fir_en", rx);
710 
711 		}
712 
713 		if (tx) {
714 			chn = iio_device_find_channel(dev, "voltage0", false);
715 			if (chn)
716 				iio_channel_attr_write_bool(chn, "filter_fir_en", rx);
717 
718 			chn = iio_device_find_channel(dev, "voltage0", true);
719 			if (chn)
720 				iio_channel_attr_write_bool(chn, "filter_fir_en", tx);
721 
722 		}
723 	}
724 
725 	if (plugin_osc_running_state() == true) {
726 		plugin_osc_stop_capture();
727 		plugin_osc_start_capture();
728 	}
729 
730 	filter_fir_update();
731 	glb_settings_update_labels();
732 	update_widgets();
733 	rx_freq_info_update();
734 }
735 
reload_button_clicked(GtkButton * btn,gpointer data)736 static void reload_button_clicked(GtkButton *btn, gpointer data)
737 {
738 	update_widgets();
739 
740 	filter_fir_update();
741 	rx_freq_info_update();
742 	glb_settings_update_labels();
743 	rssi_update_labels();
744 	rx_phase_rotation_update();
745 }
746 
747 #ifndef _WIN32
dcxo_cal_to_eeprom_clicked(GtkButton * btn,gpointer data)748 static int dcxo_cal_to_eeprom_clicked(GtkButton *btn, gpointer data)
749 {
750 	unsigned coarse, fine;
751 	char cmd[256];
752 	const char *eeprom_path = find_eeprom(NULL);
753 	FILE *fp = NULL;
754 	const char *failure_msg = NULL;
755 	int ret = 0;
756 
757 	if (!eeprom_path) {
758 		failure_msg = "Can't find EEPROM file in the sysfs";
759 		goto cleanup;
760 	}
761 
762 	coarse = gtk_spin_button_get_value(GTK_SPIN_BUTTON(glb_widgets[dcxo_coarse_num].widget));
763 	fine = gtk_spin_button_get_value(GTK_SPIN_BUTTON(glb_widgets[dcxo_fine_num].widget));
764 	sprintf(cmd, "fru-dump -i \"%s\" -o \"%s\" -t %.02x%.04x 2>&1", eeprom_path,
765 			eeprom_path, coarse, fine);
766 	fp = popen(cmd, "r");
767 
768 	if (!fp || pclose(fp) != 0) {
769 		failure_msg = "Error running fru-dump to write to EEPROM";
770 		fprintf(stderr, "Error running fru-dump: %s\n", cmd);
771 		goto cleanup;
772 	}
773 
774 cleanup:
775 	if (failure_msg) {
776 		GtkWidget *toplevel = gtk_widget_get_toplevel(fmcomms2_panel);
777 		if (!gtk_widget_is_toplevel(toplevel))
778 			toplevel = NULL;
779 		GtkWidget *dcxo_cal_eeprom_fail = gtk_message_dialog_new(
780 			GTK_WINDOW(toplevel),
781 			GTK_DIALOG_MODAL,
782 			GTK_MESSAGE_ERROR,
783 			GTK_BUTTONS_CLOSE,
784 			"%s", failure_msg);
785 		gtk_window_set_title(GTK_WINDOW(dcxo_cal_eeprom_fail), "Save to EEPROM");
786 		if (gtk_dialog_run(GTK_DIALOG(dcxo_cal_eeprom_fail)))
787 			gtk_widget_destroy(dcxo_cal_eeprom_fail);
788 		ret = -1;
789 	}
790 
791 	g_free((void *)eeprom_path);
792 
793 	return ret;
794 }
795 
dcxo_cal_from_eeprom_clicked(GtkButton * btn,gpointer data)796 static int dcxo_cal_from_eeprom_clicked(GtkButton *btn, gpointer data)
797 {
798 	const char *eeprom_path = find_eeprom(NULL);
799 	unsigned char *raw_eeprom = NULL;
800 	struct FRU_DATA *fru = NULL;
801 	FILE *fp;
802 	size_t bytes;
803 	const char *failure_msg = NULL;
804 	char coarse_str[3], fine_str[5];
805 	int coarse, fine, ret = 0;
806 
807 	if (!eeprom_path) {
808 		failure_msg = "Can't find EEPROM file in the sysfs";
809 		goto cleanup;
810 	}
811 
812 	fp = fopen(eeprom_path, "rb");
813 	if (!fp) {
814 		failure_msg = "Can't open EEPROM file";
815 		goto cleanup;
816 	}
817 
818 	raw_eeprom = g_malloc(FAB_SIZE_FRU_EEPROM);
819 	bytes = fread(raw_eeprom, 1, FAB_SIZE_FRU_EEPROM, fp);
820 
821 	/* FRU format specifies a 256 byte file size. */
822 	if (ferror(fp) || bytes != FAB_SIZE_FRU_EEPROM) {
823 		failure_msg = "Failed to read EEPROM file";
824 		fclose(fp);
825 		goto cleanup;
826 	}
827 	fclose(fp);
828 
829 	fru = parse_FRU(raw_eeprom);
830 	if (!fru) {
831 		failure_msg = "Failed to parse EEPROM";
832 		goto cleanup;
833 	}
834 
835 	/* The tuning parameters are stored as a single, concatenated hex string,
836 	 * with the first two characters being the coarse value and the last four
837 	 * characters being the fine value.
838 	 *
839 	 * Note that there are two header bytes that must be skipped first.
840 	 */
841 	memcpy(coarse_str, &fru->Board_Area->custom[4][2], 2);
842 	coarse_str[2] = '\0';
843 	memcpy(fine_str, &fru->Board_Area->custom[4][4], 4);
844 	fine_str[4] = '\0';
845 
846 	coarse = strtol(coarse_str, NULL, 16);
847 	fine = strtol(fine_str, NULL, 16);
848 	if (errno == ERANGE || errno == EINVAL) {
849 		failure_msg = "Failed parsing coarse and/or fine values from EEPROM";
850 		goto cleanup;
851 	}
852 
853 	gtk_spin_button_set_value(GTK_SPIN_BUTTON(
854 		glb_widgets[dcxo_coarse_num].widget), coarse);
855 	gtk_spin_button_set_value(GTK_SPIN_BUTTON(
856 		glb_widgets[dcxo_fine_num].widget), fine);
857 
858 cleanup:
859 	if (failure_msg) {
860 		GtkWidget *toplevel = gtk_widget_get_toplevel(fmcomms2_panel);
861 		if (!gtk_widget_is_toplevel(toplevel))
862 			toplevel = NULL;
863 		GtkWidget *dcxo_cal_eeprom_fail = gtk_message_dialog_new(
864 			GTK_WINDOW(toplevel),
865 			GTK_DIALOG_MODAL,
866 			GTK_MESSAGE_ERROR,
867 			GTK_BUTTONS_CLOSE,
868 			"%s", failure_msg);
869 		gtk_window_set_title(GTK_WINDOW(dcxo_cal_eeprom_fail), "Load from EEPROM");
870 		if (gtk_dialog_run(GTK_DIALOG(dcxo_cal_eeprom_fail)))
871 			gtk_widget_destroy(dcxo_cal_eeprom_fail);
872 		ret = -1;
873 	}
874 
875 	g_free((void *)eeprom_path);
876 	g_free(raw_eeprom);
877 	g_free(fru);
878 
879 	return ret;
880 }
881 
xo_freq_to_eeprom(void)882 static int xo_freq_to_eeprom(void)
883 {
884 	const char *eeprom_path = find_eeprom(NULL);
885 	char cmd[256];
886 	FILE *fp = NULL, *cmdfp = NULL;
887 	const char *failure_msg = NULL;
888 	double current_freq, target_freq;
889 	int ret = 0;
890 
891 	if (!eeprom_path) {
892 		failure_msg = "Can't find EEPROM file in the sysfs";
893 		goto cleanup;
894 	}
895 
896 	if (!strcmp(iio_context_get_name(ctx), "network")) {
897 		target_freq = REFCLK_RATE;
898 	} else if (!strcmp(iio_context_get_name(ctx), "local")) {
899 		fp = fopen("/sys/kernel/debug/clk/ad9361_ext_refclk/clk_rate", "r");
900 		if (!fp || fscanf(fp, "%lf", &target_freq) != 1) {
901 			failure_msg = "Unable to read AD9361 reference clock rate from debugfs.";
902 			if (fp)
903 				fclose(fp);
904 			goto cleanup;
905 		}
906 		if (fp) {
907 			fclose(fp);
908 		}
909 	} else {
910 		failure_msg = "AD9361 Reference clock rate missing from debugfs.";
911 		goto cleanup;
912 	}
913 
914 	if (scpi_connect_counter() != 0) {
915 		failure_msg = "Failed to connect to Programmable Counter device.";
916 		goto cleanup;
917 	}
918 
919 	if (scpi_counter_get_freq(&current_freq, &target_freq) != 0) {
920 		failure_msg = "Error retrieving counter frequency. "
921 		"Make sure the counter has the correct input attached.";
922 		goto cleanup;
923 	}
924 
925 	sprintf(cmd, "fru-dump -i \"%s\" -o \"%s\" -t %x 2>&1", eeprom_path,
926 		eeprom_path, (unsigned int)current_freq);
927 	cmdfp = popen(cmd, "r");
928 
929 	if (!cmdfp || pclose(cmdfp) != 0) {
930 		failure_msg = "Error running fru-dump to write to EEPROM";
931 		fprintf(stderr, "Error running fru-dump: %s\n", cmd);
932 		goto cleanup;
933 	}
934 
935 	cleanup:
936 	if (failure_msg) {
937 		fprintf(stderr, "SCPI failed: %s\n", failure_msg);
938 		GtkWidget *toplevel = gtk_widget_get_toplevel(fmcomms2_panel);
939 		if (!gtk_widget_is_toplevel(toplevel))
940 			toplevel = NULL;
941 		GtkWidget *dcxo_to_eeprom_fail = gtk_message_dialog_new(
942 			GTK_WINDOW(toplevel),
943 									GTK_DIALOG_MODAL,
944 							  GTK_MESSAGE_ERROR,
945 							  GTK_BUTTONS_CLOSE,
946 							  "%s", failure_msg);
947 		gtk_window_set_title(GTK_WINDOW(dcxo_to_eeprom_fail), "Save to EEPROM");
948 		if (gtk_dialog_run(GTK_DIALOG(dcxo_to_eeprom_fail)))
949 			gtk_widget_destroy(dcxo_to_eeprom_fail);
950 		ret = -1;
951 	}
952 
953 	g_free((void *)eeprom_path);
954 
955 	return ret;
956 }
957 
958 #endif /* _WIN32 */
959 
dcxo_cal_clicked(GtkButton * btn,gpointer data)960 static int dcxo_cal_clicked(GtkButton *btn, gpointer data)
961 {
962 	double current_freq, target_freq = 0, diff = 0, orig_diff = 0, prev_diff = 0;
963 	int coarse = 0, fine = 4095, tune_step = 1, direction = 0, ret = 0;
964 	GQueue *tuning_elems = NULL;
965 	struct tuning_param *tuning_elem = NULL;
966 	bool fine_tune = false;
967 	char *failure_msg = NULL;
968 
969 	FILE *fp;
970 
971 	if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(btn)))
972 		goto dcxo_cleanup;
973 
974 	switch (gtk_combo_box_get_active(GTK_COMBO_BOX(dcxo_cal_type))) {
975 		case 0: /* REFCLK */
976 			/* Force the correct clock output mode. */
977 			iio_device_debug_attr_write_longlong(dev, "adi,clk-output-mode-select", 1);
978 			iio_device_debug_attr_write_longlong(dev, "initialize", 1);
979 
980 			if (!strcmp(iio_context_get_name(ctx), "network")) {
981 				target_freq = REFCLK_RATE;
982 			} else if (!strcmp(iio_context_get_name(ctx), "local")) {
983 				fp = fopen("/sys/kernel/debug/clk/ad9361_ext_refclk/clk_rate", "r");
984 				if (!fp || fscanf(fp, "%lf", &target_freq) != 1) {
985 					failure_msg = "Unable to read AD9361 reference clock rate from debugfs.";
986 					if (fp)
987 						fclose(fp);
988 					goto dcxo_cleanup;
989 				}
990 				if (fp)
991 					fclose(fp);
992 			} else {
993 				failure_msg = "AD9361 Reference clock rate missing from debugfs.";
994 				goto dcxo_cleanup;
995 			}
996 			break;
997 		case 1: /* RF Output */
998 			target_freq = mhz_scale * (
999 				gtk_spin_button_get_value(GTK_SPIN_BUTTON(tx_widgets[tx_lo].widget)) +
1000 				gtk_spin_button_get_value(GTK_SPIN_BUTTON(
1001 					dac_data_manager_get_widget(dac_tx_manager, dac_data_manager_dds_tone(0, TONE_1, TONE_I), WIDGET_FREQUENCY))));
1002 			break;
1003 		case 2: /* RF Input */
1004 			failure_msg = "RF Input is not supported yet for DCXO calibration.";
1005 			goto dcxo_cleanup;
1006 			break;
1007 		default:
1008 			failure_msg = "Unsupported calibration method selected.";
1009 			goto dcxo_cleanup;
1010 	}
1011 
1012 	if (scpi_connect_counter() != 0) {
1013 		failure_msg = "Failed to connect to Programmable Counter device.";
1014 		goto dcxo_cleanup;
1015 	}
1016 
1017 	/* Alter toggle button text on start and disable user input for certain
1018 	 * widgets during calibration.
1019 	 */
1020 	gtk_button_set_label(btn, "Stop calibration");
1021 	gtk_widget_set_sensitive(dcxo_cal_type, FALSE);
1022 	gtk_widget_set_sensitive(glb_widgets[dcxo_coarse_num].widget, FALSE);
1023 	gtk_widget_set_sensitive(glb_widgets[dcxo_fine_num].widget, FALSE);
1024 
1025 	tuning_elems = g_queue_new();
1026 	target_freq = roundf(target_freq);
1027 
1028 	while (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(btn))) {
1029 		gtk_widget_show(dcxo_cal_progressbar);
1030 		gtk_spin_button_set_value(GTK_SPIN_BUTTON(glb_widgets[dcxo_coarse_num].widget), coarse);
1031 		gtk_spin_button_set_value(GTK_SPIN_BUTTON(glb_widgets[dcxo_fine_num].widget), fine);
1032 		dcxo_widgets_update();
1033 		while (gtk_events_pending())
1034 			gtk_main_iteration();
1035 
1036 		/* Querying frequency counters via SCPI too quickly leads to failures. */
1037 		sleep(1);
1038 
1039 		if (scpi_counter_get_freq(&current_freq, &target_freq) != 0) {
1040 			failure_msg = "Error retrieving counter frequency. "
1041 				"Make sure the counter has the correct input attached.";
1042 			goto dcxo_cleanup;
1043 		}
1044 
1045 		/* Sometimes the frequency counter returns entirely wrong values that
1046 		 * are orders of magnitude off. In those cases we trigger a new
1047 		 * measurement request and hope the device returns the correct value
1048 		 * this time.
1049 		 */
1050 		if (prev_diff != 0 && fabs(target_freq - current_freq) > 10 * fabs(prev_diff)) {
1051 			fprintf(stderr, "Skipping likely erroneous response from SCPI device. "
1052 				"Previous difference to target frequency was %lf Hz, possible bad value's "
1053 				"difference is %lf Hz.\n", prev_diff, (target_freq - current_freq));
1054 			continue;
1055 		}
1056 
1057 		prev_diff = diff;
1058 		diff = target_freq - current_freq;
1059 
1060 		/* Show progress towards the target frequency in relation to the
1061 		 * original frequency measurement.
1062 		 */
1063 		if (orig_diff == 0) {
1064 			orig_diff = fabs(diff);
1065 			direction = (int)fabs(diff)/diff;
1066 		} else {
1067 			gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(
1068 				dcxo_cal_progressbar), (orig_diff-fabs(diff))/orig_diff);
1069 		}
1070 
1071 		/* Store the past ten tuning value pairs and related frequencies. This
1072 		 * is used to determine the final values that are the closest to the
1073 		 * target frequency.
1074 		 */
1075 		if (g_queue_get_length(tuning_elems) >= 10)
1076 			g_queue_pop_head(tuning_elems);
1077 		tuning_elem = g_new(struct tuning_param, 1);
1078 		tuning_elem->frequency = current_freq;
1079 		tuning_elem->coarse = coarse;
1080 		tuning_elem->fine = fine;
1081 		g_queue_push_tail(tuning_elems, tuning_elem);
1082 
1083 		if (fine_tune) {
1084 			/* Stop once we go past our target frequency. */
1085 			if (diff != 0) {
1086 				if (direction < 0 && current_freq < target_freq)
1087 					break;
1088 				else if (direction > 0 && current_freq > target_freq)
1089 					break;
1090 			}
1091 
1092 			tune_step = (int)roundf(-1 * (diff / 2));
1093 
1094 			/* Force the next tuning step to be at least positive or negative 1. */
1095 			if (tune_step == 0)
1096 				tune_step = -1 * direction;
1097 
1098 			fine += tune_step;
1099 		} else {
1100 			/* Do a binary search for the closest approaching coarse tune value
1101 			 * in relation to the target frequency. When the difference to the
1102 			 * target frequency is below another coarse tune step, switch to
1103 			 * fine tuning.
1104 			 */
1105 			if (tune_step != 0) {
1106 				if (prev_diff != 0)
1107 					tune_step = (int)nearbyintf(-1 * ((tune_step * diff) / fabs(diff - prev_diff)) / 2);
1108 				coarse += tune_step;
1109 			} else {
1110 				fine_tune = true;
1111 			}
1112 		}
1113 
1114 		if (coarse < 0 || coarse > 63 || fine < 0 || fine > 8191) {
1115 			failure_msg = "Outside of tuning bounds. Make sure you have the "
1116 				"correct calibration method selected.\n";
1117 			goto dcxo_cleanup;
1118 		}
1119 	}
1120 
1121 	/* Determine the median tuning value from the list of acceptable values.
1122 	 * Values are first removed from the beginning of the queue if they have a
1123 	 * higher difference to the target frequency in comparison to the last
1124 	 * added element.
1125 	 */
1126 	if (g_queue_get_length(tuning_elems) > 1) {
1127 		tuning_elem = g_queue_peek_tail(tuning_elems);
1128 		diff = fabs(tuning_elem->frequency - target_freq);
1129 
1130 		while (g_queue_get_length(tuning_elems) > 1) {
1131 			tuning_elem = g_queue_peek_head(tuning_elems);
1132 			if (fabs(tuning_elem->frequency - target_freq) > diff)
1133 				g_queue_pop_head(tuning_elems);
1134 			else
1135 				break;
1136 		}
1137 
1138 		/* Set final tuning values using the median value of the remaining
1139 		 * range.
1140 		 */
1141 		tuning_elem = g_queue_peek_nth(
1142 			tuning_elems, ceil(g_queue_get_length(tuning_elems)/2));
1143 		gtk_spin_button_set_value(GTK_SPIN_BUTTON(
1144 			glb_widgets[dcxo_coarse_num].widget), tuning_elem->coarse);
1145 		gtk_spin_button_set_value(GTK_SPIN_BUTTON(
1146 			glb_widgets[dcxo_fine_num].widget), tuning_elem->fine);
1147 	}
1148 
1149 dcxo_cleanup:
1150 	if (failure_msg) {
1151 		GtkWidget *toplevel = gtk_widget_get_toplevel(fmcomms2_panel);
1152 		if (!gtk_widget_is_toplevel(toplevel))
1153 			toplevel = NULL;
1154 		GtkWidget *dcxo_cal_dialog_done = gtk_message_dialog_new(
1155 			GTK_WINDOW(toplevel),
1156 			GTK_DIALOG_MODAL,
1157 			GTK_MESSAGE_ERROR,
1158 			GTK_BUTTONS_CLOSE,
1159 			"%s", failure_msg);
1160 		gtk_window_set_title(GTK_WINDOW(dcxo_cal_dialog_done), "DCXO calibration");
1161 		if (gtk_dialog_run(GTK_DIALOG(dcxo_cal_dialog_done)))
1162 			gtk_widget_destroy(dcxo_cal_dialog_done);
1163 		ret = -1;
1164 	}
1165 
1166 	gtk_widget_hide(dcxo_cal_progressbar);
1167 
1168 	/* reset calibration buttons */
1169 	gtk_button_set_label(btn, "Calibrate DCXO");
1170 	g_signal_handlers_block_by_func(btn, G_CALLBACK(dcxo_cal_clicked), NULL);
1171 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(btn), FALSE);
1172 	g_signal_handlers_unblock_by_func(btn, G_CALLBACK(dcxo_cal_clicked), NULL);
1173 
1174 	gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(dcxo_cal_progressbar), 0);
1175 	gtk_widget_set_sensitive(dcxo_cal_type, TRUE);
1176 	gtk_widget_set_sensitive(glb_widgets[dcxo_coarse_num].widget, TRUE);
1177 	gtk_widget_set_sensitive(glb_widgets[dcxo_fine_num].widget, TRUE);
1178 
1179 	auto_calibrate = 1;
1180 
1181 	if (tuning_elems)
1182 		g_queue_free_full(tuning_elems, (GDestroyNotify)g_free);
1183 
1184 	return ret;
1185 }
1186 
hide_section_cb(GtkToggleToolButton * btn,GtkWidget * section)1187 static void hide_section_cb(GtkToggleToolButton *btn, GtkWidget *section)
1188 {
1189 	GtkWidget *toplevel;
1190 
1191 	if (gtk_toggle_tool_button_get_active(btn)) {
1192 		g_object_set(GTK_OBJECT(btn), "stock-id", "gtk-go-down", NULL);
1193 		gtk_widget_show(section);
1194 	} else {
1195 		g_object_set(GTK_OBJECT(btn), "stock-id", "gtk-go-up", NULL);
1196 		gtk_widget_hide(section);
1197 		toplevel = gtk_widget_get_toplevel(GTK_WIDGET(btn));
1198 		if (gtk_widget_is_toplevel(toplevel))
1199 			gtk_window_resize (GTK_WINDOW(toplevel), 1, 1);
1200 	}
1201 }
1202 
write_int(struct iio_channel * chn,const char * attr,int val)1203 static int write_int(struct iio_channel *chn, const char *attr, int val)
1204 {
1205 	return iio_channel_attr_write_longlong(chn, attr, (long long) val);
1206 }
1207 
fastlock_clicked(GtkButton * btn,gpointer data)1208 static void fastlock_clicked(GtkButton *btn, gpointer data)
1209 {
1210 	int profile;
1211 
1212 	switch ((uintptr_t) data) {
1213 		case 1: /* RX Store */
1214 			iio_widget_save(&rx_widgets[rx_lo]);
1215 			profile = gtk_combo_box_get_active(GTK_COMBO_BOX(rx_fastlock_profile));
1216 			write_int(iio_device_find_channel(dev, "altvoltage0", true),
1217 					rx_fastlock_store_name, profile);
1218 			break;
1219 		case 2: /* TX Store */
1220 			iio_widget_save(&tx_widgets[tx_lo]);
1221 			profile = gtk_combo_box_get_active(GTK_COMBO_BOX(tx_fastlock_profile));
1222 			write_int(iio_device_find_channel(dev, "altvoltage1", true),
1223 					tx_fastlock_store_name, profile);
1224 			break;
1225 		case 3: /* RX Recall */
1226 			profile = gtk_combo_box_get_active(GTK_COMBO_BOX(rx_fastlock_profile));
1227 			write_int(iio_device_find_channel(dev, "altvoltage0", true),
1228 					rx_fastlock_recall_name, profile);
1229 			iio_widget_update(&rx_widgets[rx_lo]);
1230 			break;
1231 		case 4: /* TX Recall */
1232 			profile = gtk_combo_box_get_active(GTK_COMBO_BOX(tx_fastlock_profile));
1233 			write_int(iio_device_find_channel(dev, "altvoltage1", true),
1234 					tx_fastlock_recall_name, profile);
1235 			iio_widget_update(&tx_widgets[tx_lo]);
1236 			break;
1237 	}
1238 }
1239 
filter_fir_config_file_set_cb(GtkFileChooser * chooser,gpointer data)1240 static void filter_fir_config_file_set_cb (GtkFileChooser *chooser, gpointer data)
1241 {
1242 	int ret;
1243 	char *file_name = gtk_file_chooser_get_filename(chooser);
1244 
1245 	ret = load_fir_filter(file_name, dev, NULL, fmcomms2_panel, chooser,
1246 			fir_filter_en_tx, enable_fir_filter_rx,
1247 			enable_fir_filter_rx_tx, disable_all_fir_filters,
1248 			last_fir_filter);
1249 
1250 	if (ret >= 0)
1251 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (enable_auto_filter), FALSE);
1252 }
1253 
1254 static int compare_gain(const char *a, const char *b) __attribute__((unused));
compare_gain(const char * a,const char * b)1255 static int compare_gain(const char *a, const char *b)
1256 {
1257 	double val_a, val_b;
1258 	sscanf(a, "%lf", &val_a);
1259 	sscanf(b, "%lf", &val_b);
1260 
1261 	if (val_a < val_b)
1262 		return -1;
1263 	else if(val_a > val_b)
1264 		return 1;
1265 	else
1266 		return 0;
1267 }
1268 
rx_phase_rotation_set(GtkSpinButton * spinbutton,gpointer user_data)1269 static void rx_phase_rotation_set(GtkSpinButton *spinbutton, gpointer user_data)
1270 {
1271 	uintptr_t offset = (uintptr_t) user_data;
1272 	struct iio_channel *out0, *out1;
1273 	gdouble val, phase;
1274 
1275 	if (!cap)
1276 		return;
1277 
1278 	val = gtk_spin_button_get_value(spinbutton);
1279 
1280 	phase = val * 2 * M_PI / 360.0;
1281 
1282 	if (offset == 2) {
1283 		out0 = iio_device_find_channel(cap, "voltage2", false);
1284 		out1 = iio_device_find_channel(cap, "voltage3", false);
1285 	} else {
1286 		out0 = iio_device_find_channel(cap, "voltage0", false);
1287 		out1 = iio_device_find_channel(cap, "voltage1", false);
1288 	}
1289 
1290 	if (out1 && out0) {
1291 		iio_channel_attr_write_double(out0, "calibscale", (double) cos(phase));
1292 		iio_channel_attr_write_double(out0, "calibphase", (double) (-1 * sin(phase)));
1293 		iio_channel_attr_write_double(out1, "calibscale", (double) cos(phase));
1294 		iio_channel_attr_write_double(out1, "calibphase", (double) sin(phase));
1295 	}
1296 }
1297 
1298 /* Check for a valid two channels combination (ch0->ch1, ch2->ch3, ...)
1299  *
1300  * struct iio_device *dev - the iio device that owns the channels
1301  * char* ch_name - output parameter: stores the names of to the
1302  *                 enabled channels, useful for reporting for which
1303  *                 channels the combination is valid or not.
1304  * Return 1 if the channel combination is valid and 0 otherwise.
1305  */
channel_combination_check(struct iio_device * dev,const char ** ch_names)1306 static int channel_combination_check(struct iio_device *dev, const char **ch_names)
1307 {
1308 	bool consecutive_ch = FALSE;
1309 	unsigned int i, k;
1310 	GArray *channels = get_iio_channels_naturally_sorted(dev);
1311 
1312 	for (i = 0, k = 0; i < channels->len; ++i) {
1313 		struct iio_channel *ch = g_array_index(channels, struct iio_channel *, i);
1314 		struct extra_info *info = iio_channel_get_data(ch);
1315 
1316 		if (info->may_be_enabled) {
1317 			const char *name = iio_channel_get_name(ch) ?: iio_channel_get_id(ch);
1318 			ch_names[k++] = name;
1319 
1320 			if (i > 0) {
1321 				struct extra_info *prev = iio_channel_get_data(g_array_index(channels, struct iio_channel *, i - 1));
1322 
1323 				if (prev->may_be_enabled) {
1324 					consecutive_ch = TRUE;
1325 					break;
1326 				}
1327 			}
1328 		}
1329 	}
1330 	g_array_free(channels, FALSE);
1331 
1332 	if (!consecutive_ch)
1333 		return 0;
1334 
1335 	if (!(i & 0x1))
1336 		return 0;
1337 
1338 	return 1;
1339 }
1340 
save_widget_value(GtkWidget * widget,struct iio_widget * iio_w)1341 static void save_widget_value(GtkWidget *widget, struct iio_widget *iio_w)
1342 {
1343 	iio_w->save(iio_w);
1344 }
1345 
make_widget_update_signal_based(struct iio_widget * widgets,unsigned int num_widgets)1346 static void make_widget_update_signal_based(struct iio_widget *widgets,
1347 	unsigned int num_widgets)
1348 {
1349 	char signal_name[25];
1350 	unsigned int i;
1351 
1352 	for (i = 0; i < num_widgets; i++) {
1353 		if (GTK_IS_CHECK_BUTTON(widgets[i].widget))
1354 			sprintf(signal_name, "%s", "toggled");
1355 		else if (GTK_IS_TOGGLE_BUTTON(widgets[i].widget))
1356 			sprintf(signal_name, "%s", "toggled");
1357 		else if (GTK_IS_SPIN_BUTTON(widgets[i].widget))
1358 			sprintf(signal_name, "%s", "value-changed");
1359 		else if (GTK_IS_COMBO_BOX_TEXT(widgets[i].widget))
1360 			sprintf(signal_name, "%s", "changed");
1361 		else
1362 			printf("unhandled widget type, attribute: %s\n", widgets[i].attr_name);
1363 
1364 		if (GTK_IS_SPIN_BUTTON(widgets[i].widget) &&
1365 			widgets[i].priv_progress != NULL) {
1366 				iio_spin_button_progress_activate(&widgets[i]);
1367 		} else {
1368 			g_signal_connect(G_OBJECT(widgets[i].widget), signal_name, G_CALLBACK(save_widget_value), &widgets[i]);
1369 		}
1370 	}
1371 }
1372 
handle_external_request(struct osc_plugin * plugin,const char * request)1373 static int handle_external_request (struct osc_plugin *plugin, const char *request)
1374 {
1375 	int ret = 0;
1376 
1377 	if (!strcmp(request, "Reload Settings")) {
1378 		reload_button_clicked(NULL, 0);
1379 		ret = 1;
1380 	}
1381 
1382 	return ret;
1383 }
1384 
fmcomms2_handle_driver(struct osc_plugin * plugin,const char * attrib,const char * value)1385 static int fmcomms2_handle_driver(struct osc_plugin *plugin, const char *attrib, const char *value)
1386 {
1387 	int ret = 0;
1388 
1389 	if (MATCH_ATTRIB("load_fir_filter_file")) {
1390 		if (value[0]) {
1391 			load_fir_filter(value, dev, NULL, fmcomms2_panel,
1392 					GTK_FILE_CHOOSER(filter_fir_config),
1393 					fir_filter_en_tx, enable_fir_filter_rx,
1394 					enable_fir_filter_rx_tx,
1395 					disable_all_fir_filters,
1396 					last_fir_filter);
1397 		}
1398 	} else if (MATCH_ATTRIB("dds_mode_tx1")) {
1399 		dac_data_manager_set_dds_mode(dac_tx_manager,
1400 				DDS_DEVICE, 1, atoi(value));
1401 	} else if (MATCH_ATTRIB("dds_mode_tx2")) {
1402 		dac_data_manager_set_dds_mode(dac_tx_manager,
1403 				DDS_DEVICE, 2, atoi(value));
1404 	} else if (MATCH_ATTRIB("global_settings_show")) {
1405 		gtk_toggle_tool_button_set_active(
1406 				section_toggle[SECTION_GLOBAL], !!atoi(value));
1407 		hide_section_cb(section_toggle[SECTION_GLOBAL],
1408 				section_setting[SECTION_GLOBAL]);
1409 	} else if (MATCH_ATTRIB("tx_show")) {
1410 		gtk_toggle_tool_button_set_active(
1411 				section_toggle[SECTION_TX], !!atoi(value));
1412 		hide_section_cb(section_toggle[SECTION_TX],
1413 				section_setting[SECTION_TX]);
1414 	} else if (MATCH_ATTRIB("rx_show")) {
1415 		gtk_toggle_tool_button_set_active(
1416 				section_toggle[SECTION_RX], !!atoi(value));
1417 		hide_section_cb(section_toggle[SECTION_RX],
1418 				section_setting[SECTION_RX]);
1419 	} else if (MATCH_ATTRIB("fpga_show")) {
1420 		gtk_toggle_tool_button_set_active(
1421 				section_toggle[SECTION_FPGA], !!atoi(value));
1422 		hide_section_cb(section_toggle[SECTION_FPGA],
1423 				section_setting[SECTION_FPGA]);
1424 	} else if (MATCH_ATTRIB("up_down_converter")) {
1425 		gtk_toggle_button_set_active(
1426 				(GtkToggleButton *)up_down_converter, !!atoi(value));
1427 	} else if (!strncmp(attrib, "tx_channel_", sizeof("tx_channel_") - 1)) {
1428 		int tx = atoi(attrib + sizeof("tx_channel_") - 1);
1429 		dac_data_manager_set_tx_channel_state(
1430 				dac_tx_manager, tx, !!atoi(value));
1431 	} else if (MATCH_ATTRIB("dac_buf_filename")) {
1432 		dac_data_manager_set_buffer_chooser_filename(
1433 				dac_tx_manager, value);
1434 #ifndef _WIN32
1435 	} else if (MATCH_ATTRIB("dcxo_calibrate")) {
1436 		/* calibration button needs to be active for the function to run */
1437 		g_signal_handlers_block_by_func(
1438 			GTK_TOGGLE_BUTTON(dcxo_cal), G_CALLBACK(dcxo_cal_clicked), NULL);
1439 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dcxo_cal), TRUE);
1440 		g_signal_handlers_unblock_by_func(
1441 			GTK_TOGGLE_BUTTON(dcxo_cal), G_CALLBACK(dcxo_cal_clicked), NULL);
1442 		ret = dcxo_cal_clicked(GTK_BUTTON(dcxo_cal), NULL);
1443 		while (!auto_calibrate)
1444 			gtk_main_iteration();
1445 	} else if (MATCH_ATTRIB("dcxo_to_eeprom")) {
1446 		ret = dcxo_cal_to_eeprom_clicked(NULL, NULL);
1447 	} else if (MATCH_ATTRIB("xo_freq_to_eeprom")) {
1448 		ret = xo_freq_to_eeprom();
1449 #endif /* _WIN32 */
1450 	} else if (MATCH_ATTRIB("SYNC_RELOAD")) {
1451 		if (can_update_widgets)
1452 			reload_button_clicked(NULL, NULL);
1453 	} else {
1454 		return -EINVAL;
1455 	}
1456 
1457 	return ret;
1458 }
1459 
fmcomms2_handle(struct osc_plugin * plugin,int line,const char * attrib,const char * value)1460 static int fmcomms2_handle(struct osc_plugin *plugin, int line, const char *attrib, const char *value)
1461 {
1462 	return osc_plugin_default_handle(ctx, line, attrib, value,
1463 			fmcomms2_handle_driver, NULL);
1464 }
1465 
load_profile(struct osc_plugin * plugin,const char * ini_fn)1466 static void load_profile(struct osc_plugin *plugin, const char *ini_fn)
1467 {
1468 	struct iio_channel *ch;
1469 	char *value;
1470 	unsigned int i;
1471 
1472 	for (i = 0; i < ARRAY_SIZE(fmcomms2_driver_attribs); i++) {
1473 		char *value = read_token_from_ini(ini_fn, THIS_DRIVER,
1474 				fmcomms2_driver_attribs[i]);
1475 		if (value) {
1476 			fmcomms2_handle_driver(NULL,
1477 					fmcomms2_driver_attribs[i], value);
1478 			free(value);
1479 		}
1480 	}
1481 
1482 	/* The gain_control_mode iio attribute should be set prior to setting
1483 	 * hardwaregain iio attribute. This is neccessary due to the fact that
1484 	 * some control modes change the hardwaregain automatically. */
1485 	ch = iio_device_find_channel(dev, "voltage0", false);
1486 	value = read_token_from_ini(ini_fn, THIS_DRIVER,
1487 				PHY_DEVICE".in_voltage0_gain_control_mode");
1488 	if (ch && value) {
1489 		iio_channel_attr_write(ch, "gain_control_mode", value);
1490 		free(value);
1491 	}
1492 
1493 	ch = iio_device_find_channel(dev, "voltage1", false);
1494 	value = read_token_from_ini(ini_fn, THIS_DRIVER,
1495 				PHY_DEVICE".in_voltage1_gain_control_mode");
1496 	if (ch && value) {
1497 		iio_channel_attr_write(ch, "gain_control_mode", value);
1498 		free(value);
1499 	}
1500 
1501 	update_from_ini(ini_fn, THIS_DRIVER, dev, fmcomms2_sr_attribs,
1502 			ARRAY_SIZE(fmcomms2_sr_attribs));
1503 	if (dds)
1504 		update_from_ini(ini_fn, THIS_DRIVER, dds, fmcomms2_sr_attribs,
1505 				ARRAY_SIZE(fmcomms2_sr_attribs));
1506 	if (udc_rx)
1507 		update_from_ini(ini_fn, THIS_DRIVER, udc_rx, fmcomms2_sr_attribs,
1508 				ARRAY_SIZE(fmcomms2_sr_attribs));
1509 	if (udc_tx)
1510 		update_from_ini(ini_fn, THIS_DRIVER, udc_tx, fmcomms2_sr_attribs,
1511 				ARRAY_SIZE(fmcomms2_sr_attribs));
1512 
1513 	if (can_update_widgets)
1514 		reload_button_clicked(NULL, NULL);
1515 }
1516 
fmcomms2_init(struct osc_plugin * plugin,GtkWidget * notebook,const char * ini_fn)1517 static GtkWidget * fmcomms2_init(struct osc_plugin *plugin, GtkWidget *notebook, const char *ini_fn)
1518 {
1519 	GtkBuilder *builder;
1520 	GtkWidget *dds_container;
1521 	struct iio_channel *ch0, *ch1;
1522 
1523 	can_update_widgets = false;
1524 
1525 	ctx = osc_create_context();
1526 	if (!ctx)
1527 		return NULL;
1528 
1529 	dev = iio_context_find_device(ctx, PHY_DEVICE);
1530 	dds = iio_context_find_device(ctx, DDS_DEVICE);
1531 	cap = iio_context_find_device(ctx, CAP_DEVICE);
1532 	udc_rx = iio_context_find_device(ctx, UDC_RX_DEVICE);
1533 	udc_tx = iio_context_find_device(ctx, UDC_TX_DEVICE);
1534 	has_udc_driver = (udc_rx && udc_tx);
1535 
1536 	ch0 = iio_device_find_channel(dev, "voltage0", false);
1537 	ch1 = iio_device_find_channel(dev, "voltage1", false);
1538 
1539 	dac_tx_manager = dac_data_manager_new(dds, NULL, ctx);
1540 
1541 	const char *env_freq_span = getenv("OSC_UPDN_FREQ_SPAN");
1542 	const char *env_freq_mix_sign = getenv("OSC_UPDN_FREQ_MIX_SIGN");
1543 
1544 	if(!env_freq_span) {
1545 		updn_freq_span = 2;
1546 	} else {
1547 		errno = 0;
1548 		updn_freq_span = g_strtod(env_freq_span, NULL);
1549 		if (errno)
1550 			updn_freq_span = 2;
1551 	}
1552 
1553 	if(!env_freq_mix_sign) {
1554 		updn_freq_mix_sign = 1;
1555 	} else {
1556 		if (!strncmp(env_freq_mix_sign, "-", 1))
1557 			updn_freq_mix_sign = -1;
1558 		else
1559 			updn_freq_mix_sign = 1;
1560 	}
1561 
1562 	builder = gtk_builder_new();
1563 	nbook = GTK_NOTEBOOK(notebook);
1564 
1565 	if (osc_load_glade_file(builder, "fmcomms2") < 0) {
1566 		osc_destroy_context(ctx);
1567 		return NULL;
1568 	}
1569 
1570 	is_2rx_2tx = ch1 && iio_channel_find_attr(ch1, "hardwaregain");
1571 
1572 	fmcomms2_panel = GTK_WIDGET(gtk_builder_get_object(builder, "fmcomms2_panel"));
1573 
1574 	/* Hide DCXO calibration support if the scpi plugin isn't loaded. */
1575 	if (!scpi_connect_functions())
1576 		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(builder, "dcxo_cal_grid")));
1577 
1578 #ifndef _WIN32
1579 	/* Disable EEPROM functionality if not running locally. */
1580 	if (strcmp(iio_context_get_name(ctx), "local") != 0) {
1581 		gtk_widget_set_sensitive(GTK_WIDGET(
1582 			gtk_builder_get_object(builder, "dcxo_cal_to_eeprom")), FALSE);
1583 		gtk_widget_set_sensitive(GTK_WIDGET(
1584 			gtk_builder_get_object(builder, "dcxo_cal_from_eeprom")), FALSE);
1585 	}
1586 
1587 	/* Disable saving to EEPROM if not running as root. */
1588 	if (getuid() != 0) {
1589 		gtk_widget_set_sensitive(GTK_WIDGET(
1590 			gtk_builder_get_object(builder, "dcxo_cal_to_eeprom")), FALSE);
1591 	}
1592 #endif
1593 
1594 	/* Global settings */
1595 
1596 	ensm_mode = GTK_WIDGET(gtk_builder_get_object(builder, "ensm_mode"));
1597 	ensm_mode_available = GTK_WIDGET(gtk_builder_get_object(builder, "ensm_mode_available"));
1598 	calib_mode = GTK_WIDGET(gtk_builder_get_object(builder, "calib_mode"));
1599 	calib_mode_available = GTK_WIDGET(gtk_builder_get_object(builder, "calib_mode_available"));
1600 	trx_rate_governor = GTK_WIDGET(gtk_builder_get_object(builder, "trx_rate_governor"));
1601 	trx_rate_governor_available = GTK_WIDGET(gtk_builder_get_object(builder, "trx_rate_governor_available"));
1602 	tx_path_rates = GTK_WIDGET(gtk_builder_get_object(builder, "label_tx_path"));
1603 	rx_path_rates = GTK_WIDGET(gtk_builder_get_object(builder, "label_rx_path"));
1604 	filter_fir_config = GTK_WIDGET(gtk_builder_get_object(builder, "filter_fir_config"));
1605 	enable_fir_filter_rx = GTK_WIDGET(gtk_builder_get_object(builder, "enable_fir_filter_rx"));
1606 	fir_filter_en_tx = GTK_WIDGET(gtk_builder_get_object(builder, "fir_filter_en_tx"));
1607 	enable_fir_filter_rx_tx = GTK_WIDGET(gtk_builder_get_object(builder, "enable_fir_filter_tx_rx"));
1608 	disable_all_fir_filters = GTK_WIDGET(gtk_builder_get_object(builder, "disable_all_fir_filters"));
1609 	up_down_converter = GTK_WIDGET(gtk_builder_get_object(builder, "checkbox_up_down_converter"));
1610 	dcxo_cal_progressbar = GTK_WIDGET(gtk_builder_get_object(builder, "dcxo_cal_progressbar"));
1611 	dcxo_cal_type = GTK_WIDGET(gtk_builder_get_object(builder, "dcxo_cal_type"));
1612 	dcxo_cal = GTK_WIDGET(gtk_builder_get_object(builder, "dcxo_cal"));
1613 	enable_auto_filter = GTK_WIDGET(gtk_builder_get_object(builder, "enable_auto_filter"));
1614 	dcxo_cal_tab = GTK_WIDGET(gtk_builder_get_object(builder, "dcxo_tab"));
1615 
1616 	section_toggle[SECTION_GLOBAL] = GTK_TOGGLE_TOOL_BUTTON(gtk_builder_get_object(builder, "global_settings_toggle"));
1617 	section_setting[SECTION_GLOBAL] = GTK_WIDGET(gtk_builder_get_object(builder, "global_settings"));
1618 	section_toggle[SECTION_TX] = GTK_TOGGLE_TOOL_BUTTON(gtk_builder_get_object(builder, "tx_toggle"));
1619 	section_setting[SECTION_TX] = GTK_WIDGET(gtk_builder_get_object(builder, "tx_settings"));
1620 	section_toggle[SECTION_RX] = GTK_TOGGLE_TOOL_BUTTON(gtk_builder_get_object(builder, "rx_toggle"));
1621 	section_setting[SECTION_RX] = GTK_WIDGET(gtk_builder_get_object(builder, "rx_settings"));
1622 	section_toggle[SECTION_FPGA] = GTK_TOGGLE_TOOL_BUTTON(gtk_builder_get_object(builder, "fpga_toggle"));
1623 	section_setting[SECTION_FPGA] = GTK_WIDGET(gtk_builder_get_object(builder, "fpga_settings"));
1624 
1625 	/* Receive Chain */
1626 
1627 	rf_port_select_rx = GTK_WIDGET(gtk_builder_get_object(builder, "rf_port_select_rx"));
1628 	rx_gain_control_rx1 = GTK_WIDGET(gtk_builder_get_object(builder, "gain_control_mode_rx1"));
1629 	rx_gain_control_rx2 = GTK_WIDGET(gtk_builder_get_object(builder, "gain_control_mode_rx2"));
1630 	rx_gain_control_modes_rx1 = GTK_WIDGET(gtk_builder_get_object(builder, "gain_control_mode_available_rx1"));
1631 	rx_gain_control_modes_rx2 = GTK_WIDGET(gtk_builder_get_object(builder, "gain_control_mode_available_rx2"));
1632 	rx1_rssi = GTK_WIDGET(gtk_builder_get_object(builder, "rssi_rx1"));
1633 	rx2_rssi = GTK_WIDGET(gtk_builder_get_object(builder, "rssi_rx2"));
1634 	rx_fastlock_profile = GTK_WIDGET(gtk_builder_get_object(builder, "rx_fastlock_profile"));
1635 	fpga_rx_frequency_available = GTK_WIDGET(gtk_builder_get_object(builder, "fpga_rx_frequency_available"));
1636 	sampling_freq_rx_decim = GTK_WIDGET(gtk_builder_get_object(builder, "sampling_freq_rx_decim"));
1637 
1638 	/* Transmit Chain */
1639 
1640 	rf_port_select_tx = GTK_WIDGET(gtk_builder_get_object(builder, "rf_port_select_tx"));
1641 	tx_fastlock_profile = GTK_WIDGET(gtk_builder_get_object(builder, "tx_fastlock_profile"));
1642 	tx1_rssi = GTK_WIDGET(gtk_builder_get_object(builder, "rssi_tx1"));
1643 	tx2_rssi = GTK_WIDGET(gtk_builder_get_object(builder, "rssi_tx2"));
1644 	fpga_tx_frequency_available = GTK_WIDGET(gtk_builder_get_object(builder, "fpga_tx_frequency_available"));
1645 	sampling_freq_tx_inter = GTK_WIDGET(gtk_builder_get_object(builder, "sampling_freq_tx_inter"));
1646 
1647 	dds_container = GTK_WIDGET(gtk_builder_get_object(builder, "dds_transmit_block"));
1648 
1649 	if (dac_tx_manager)
1650 		gtk_container_add(GTK_CONTAINER(dds_container),
1651 			dac_data_manager_get_gui_container(dac_tx_manager));
1652 	gtk_widget_show_all(dds_container);
1653 
1654 	rx_phase_rotation[0] = GTK_WIDGET(gtk_builder_get_object(builder, "rx1_phase_rotation"));
1655 	rx_phase_rotation[1] = GTK_WIDGET(gtk_builder_get_object(builder, "rx2_phase_rotation"));
1656 
1657 	gtk_combo_box_set_active(GTK_COMBO_BOX(ensm_mode_available), 0);
1658 	gtk_combo_box_set_active(GTK_COMBO_BOX(trx_rate_governor_available), 0);
1659 	gtk_combo_box_set_active(GTK_COMBO_BOX(rx_gain_control_modes_rx1), 0);
1660 	gtk_combo_box_set_active(GTK_COMBO_BOX(rx_gain_control_modes_rx2), 0);
1661 	gtk_combo_box_set_active(GTK_COMBO_BOX(rf_port_select_rx), 0);
1662 	gtk_combo_box_set_active(GTK_COMBO_BOX(rf_port_select_tx), 0);
1663 	gtk_combo_box_set_active(GTK_COMBO_BOX(rx_fastlock_profile), 0);
1664 	gtk_combo_box_set_active(GTK_COMBO_BOX(tx_fastlock_profile), 0);
1665 	gtk_combo_box_set_active(GTK_COMBO_BOX(dcxo_cal_type), 0);
1666 	gtk_combo_box_set_active(GTK_COMBO_BOX(fpga_rx_frequency_available), 0);
1667 	gtk_combo_box_set_active(GTK_COMBO_BOX(fpga_tx_frequency_available), 0);
1668 
1669 	/* Bind the IIO device files to the GUI widgets */
1670 
1671 	glb_widgets = widgets;
1672 
1673 	/* Global settings */
1674 	iio_combo_box_init(&glb_widgets[num_glb++],
1675 		dev, NULL, "ensm_mode", "ensm_mode_available",
1676 		ensm_mode_available, NULL);
1677 	iio_combo_box_init(&glb_widgets[num_glb++],
1678 		dev, NULL, "calib_mode", "calib_mode_available",
1679 		calib_mode_available, NULL);
1680 	iio_combo_box_init(&glb_widgets[num_glb++],
1681 		dev, NULL, "trx_rate_governor", "trx_rate_governor_available",
1682 		trx_rate_governor_available, NULL);
1683 
1684 	dcxo_coarse_num = num_glb;
1685 	iio_spin_button_int_init_from_builder(&glb_widgets[num_glb++],
1686 		dev, NULL, "dcxo_tune_coarse", builder, "dcxo_coarse_tune",
1687 		0);
1688 	dcxo_fine_num = num_glb;
1689 	iio_spin_button_int_init_from_builder(&glb_widgets[num_glb++],
1690 		dev, NULL, "dcxo_tune_fine", builder, "dcxo_fine_tune",
1691 		0);
1692 
1693 	iio_spin_button_int_init_from_builder(&glb_widgets[num_glb++],
1694 		dev, NULL, "xo_correction", builder, "xo_correction",
1695 		0);
1696 
1697 	rx_widgets = &glb_widgets[num_glb];
1698 
1699 	/* Receive Chain */
1700 
1701 	iio_combo_box_init(&rx_widgets[num_rx++],
1702 		dev, ch0, "gain_control_mode",
1703 		"gain_control_mode_available",
1704 		rx_gain_control_modes_rx1, NULL);
1705 
1706 	iio_combo_box_init(&rx_widgets[num_rx++],
1707 		dev, ch0, "rf_port_select",
1708 		"rf_port_select_available",
1709 		rf_port_select_rx, NULL);
1710 
1711 	if (is_2rx_2tx)
1712 		iio_combo_box_init(&rx_widgets[num_rx++],
1713 			dev, ch1, "gain_control_mode",
1714 			"gain_control_mode_available",
1715 			rx_gain_control_modes_rx2, NULL);
1716 	rx1_gain = num_rx;
1717 	iio_spin_button_int_init_from_builder(&rx_widgets[num_rx++],
1718 		dev, ch0, "hardwaregain", builder,
1719 		"hardware_gain_rx1", NULL);
1720 
1721 	if (is_2rx_2tx) {
1722 		rx2_gain = num_rx;
1723 		iio_spin_button_int_init_from_builder(&rx_widgets[num_rx++],
1724 			dev, ch1, "hardwaregain", builder,
1725 			"hardware_gain_rx2", NULL);
1726 	}
1727 	rx_sample_freq = num_rx;
1728 	iio_spin_button_int_init_from_builder(&rx_widgets[num_rx++],
1729 		dev, ch0, "sampling_frequency", builder,
1730 		"sampling_freq_rx", &mhz_scale);
1731 	iio_spin_button_add_progress(&rx_widgets[num_rx - 1]);
1732 
1733 	iio_spin_button_int_init_from_builder(&rx_widgets[num_rx++],
1734 		dev, ch0, "rf_bandwidth", builder, "rf_bandwidth_rx",
1735 		&mhz_scale);
1736 	iio_spin_button_add_progress(&rx_widgets[num_rx - 1]);
1737 	rx_lo = num_rx;
1738 
1739 	ch1 = iio_device_find_channel(dev, "altvoltage0", true);
1740 	if (iio_channel_find_attr(ch1, "frequency"))
1741 		freq_name = "frequency";
1742 	else
1743 		freq_name = "RX_LO_frequency";
1744 	iio_spin_button_s64_init_from_builder(&rx_widgets[num_rx++],
1745 		dev, ch1, freq_name, builder,
1746 		"rx_lo_freq", &mhz_scale);
1747 	iio_spin_button_add_progress(&rx_widgets[num_rx - 1]);
1748 
1749 	iio_toggle_button_init_from_builder(&rx_widgets[num_rx++],
1750 		dev, ch1, "external", builder,
1751 		"rx_lo_external", 0);
1752 
1753 	iio_toggle_button_init_from_builder(&rx_widgets[num_rx++],
1754 		dev, ch0, "quadrature_tracking_en", builder,
1755 		"quad", 0);
1756 	iio_toggle_button_init_from_builder(&rx_widgets[num_rx++],
1757 		dev, ch0, "rf_dc_offset_tracking_en", builder,
1758 		"rfdc", 0);
1759 	iio_toggle_button_init_from_builder(&rx_widgets[num_rx++],
1760 		dev, ch0, "bb_dc_offset_tracking_en", builder,
1761 		"bbdc", 0);
1762 
1763 	ch0 = iio_device_find_channel(dev, "altvoltage0", true);
1764 
1765 	if (iio_channel_find_attr(ch0, "fastlock_store"))
1766 		rx_fastlock_store_name = "fastlock_store";
1767 	else
1768 		rx_fastlock_store_name = "RX_LO_fastlock_store";
1769 	if (iio_channel_find_attr(ch0, "fastlock_recall"))
1770 		rx_fastlock_recall_name = "fastlock_recall";
1771 	else
1772 		rx_fastlock_recall_name = "RX_LO_fastlock_recall";
1773 
1774 	/* Transmit Chain */
1775 
1776 	tx_widgets = &rx_widgets[num_rx];
1777 
1778 	ch0 = iio_device_find_channel(dev, "voltage0", true);
1779 	if (is_2rx_2tx)
1780 		ch1 = iio_device_find_channel(dev, "voltage1", true);
1781 
1782 	tx_rssi_available = ch0 && iio_channel_find_attr(ch0, "rssi");
1783 	if (is_2rx_2tx)
1784 		tx_rssi_available = tx_rssi_available &&
1785 				(ch1 && iio_channel_find_attr(ch1, "rssi"));
1786 
1787 	iio_combo_box_init(&tx_widgets[num_tx++],
1788 		dev, ch0, "rf_port_select",
1789 		"rf_port_select_available",
1790 		rf_port_select_tx, NULL);
1791 
1792 	iio_spin_button_init_from_builder(&tx_widgets[num_tx++],
1793 		dev, ch0, "hardwaregain", builder,
1794 		"hardware_gain_tx1", &inv_scale);
1795 
1796 	if (is_2rx_2tx)
1797 		iio_spin_button_init_from_builder(&tx_widgets[num_tx++],
1798 			dev, ch1, "hardwaregain", builder,
1799 			"hardware_gain_tx2", &inv_scale);
1800 	tx_sample_freq = num_tx;
1801 	iio_spin_button_int_init_from_builder(&tx_widgets[num_tx++],
1802 		dev, ch0, "sampling_frequency", builder,
1803 		"sampling_freq_tx", &mhz_scale);
1804 	iio_spin_button_add_progress(&tx_widgets[num_tx - 1]);
1805 	iio_spin_button_int_init_from_builder(&tx_widgets[num_tx++],
1806 		dev, ch0, "rf_bandwidth", builder,
1807 		"rf_bandwidth_tx", &mhz_scale);
1808 	iio_spin_button_add_progress(&tx_widgets[num_tx - 1]);
1809 
1810 	tx_lo = num_tx;
1811 	ch1 = iio_device_find_channel(dev, "altvoltage1", true);
1812 
1813 	if (iio_channel_find_attr(ch1, "frequency"))
1814 		freq_name = "frequency";
1815 	else
1816 		freq_name = "TX_LO_frequency";
1817 	iio_spin_button_s64_init_from_builder(&tx_widgets[num_tx++],
1818 		dev, ch1, freq_name, builder, "tx_lo_freq", &mhz_scale);
1819 	iio_spin_button_add_progress(&tx_widgets[num_tx - 1]);
1820 
1821 	iio_toggle_button_init_from_builder(&tx_widgets[num_tx++],
1822 		dev, ch1, "external", builder,
1823 		"tx_lo_external", 0);
1824 
1825 	/* FPGA widgets */
1826 	fpga_widgets = &tx_widgets[num_tx];
1827 
1828 	if (dds) {
1829 		ch0 = iio_device_find_channel(dds, "voltage0", true);
1830 	} else {
1831 		ch0 = NULL;
1832 	}
1833 	if (ch0 && iio_channel_find_attr(ch0, "sampling_frequency_available")) {
1834 		iio_combo_box_init(&fpga_widgets[num_fpga++],
1835 				dds, ch0, "sampling_frequency",
1836 			"sampling_frequency_available",
1837 			fpga_tx_frequency_available, NULL);
1838 
1839 		g_signal_connect_after(sampling_freq_tx_inter, "value-changed",
1840 				       G_CALLBACK(int_dec_spin_update_cb), ch0);
1841 
1842 
1843 	} else {
1844 		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(builder,
1845 				"transmit_frame_dma_buf")));
1846 
1847 		gtk_widget_hide(sampling_freq_tx_inter);
1848 	}
1849 
1850 	if (cap) {
1851 		ch0 = iio_device_find_channel(cap, "voltage0", false);
1852 	} else {
1853 		ch0 = NULL;
1854 	}
1855 	if (ch0 && iio_channel_find_attr(ch0, "sampling_frequency_available")) {
1856 		iio_combo_box_init(&fpga_widgets[num_fpga++],
1857 				cap, ch0, "sampling_frequency",
1858 			"sampling_frequency_available",
1859 			fpga_rx_frequency_available, NULL);
1860 
1861 		g_signal_connect_after(sampling_freq_rx_decim, "value-changed",
1862 				       G_CALLBACK(int_dec_spin_update_cb), ch0);
1863 
1864 	} else {
1865 		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(builder,
1866 				"receive_frame_dma_buf")));
1867 		gtk_widget_hide(sampling_freq_rx_decim);
1868 
1869 	}
1870 
1871 	ch1 = iio_device_find_channel(dev, "altvoltage1", true);
1872 
1873 	/* Widgets bindings */
1874 	g_builder_bind_property(builder, "rssi_tx1", "visible",
1875 		"label_rssi_tx1", "sensitive", G_BINDING_DEFAULT);
1876 	g_builder_bind_property(builder, "rssi_tx2", "visible",
1877 		"label_rssi_tx2", "sensitive", G_BINDING_DEFAULT);
1878 	g_builder_bind_property(builder, "rx_lo_external", "active",
1879 		"rx_fastlock_profile", "visible", G_BINDING_INVERT_BOOLEAN);
1880 	g_builder_bind_property(builder, "rx_lo_external", "active",
1881 		"rx_fastlock_label", "visible", G_BINDING_INVERT_BOOLEAN);
1882 	g_builder_bind_property(builder, "rx_lo_external", "active",
1883 		"rx_fastlock_actions", "visible", G_BINDING_INVERT_BOOLEAN);
1884 	g_builder_bind_property(builder, "tx_lo_external", "active",
1885 		"tx_fastlock_profile", "visible", G_BINDING_INVERT_BOOLEAN);
1886 	g_builder_bind_property(builder, "tx_lo_external", "active",
1887 		"tx_fastlock_label", "visible", G_BINDING_INVERT_BOOLEAN);
1888 	g_builder_bind_property(builder, "tx_lo_external", "active",
1889 		"tx_fastlock_actions", "visible", G_BINDING_INVERT_BOOLEAN);
1890 
1891 	if (ini_fn)
1892 		load_profile(NULL, ini_fn);
1893 
1894 	/* Update all widgets with current values */
1895 	printf("Updating widgets...\n");
1896 	update_widgets();
1897 	sample_frequency_changed_cb(NULL);
1898 	printf("Updating FIR filter...\n");
1899 	filter_fir_update();
1900 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(disable_all_fir_filters), true);
1901 	glb_settings_update_labels();
1902 	rssi_update_labels();
1903 	dac_data_manager_freq_widgets_range_update(dac_tx_manager,
1904 		get_gui_tx_sampling_freq() / 2.0);
1905 	dac_data_manager_update_iio_widgets(dac_tx_manager);
1906 
1907 	/* Connect signals */
1908 
1909 	if (iio_channel_find_attr(ch1, "fastlock_store"))
1910 		tx_fastlock_store_name = "fastlock_store";
1911 	else
1912 		tx_fastlock_store_name = "TX_LO_fastlock_store";
1913 	if (iio_channel_find_attr(ch1, "fastlock_recall"))
1914 		tx_fastlock_recall_name = "fastlock_recall";
1915 	else
1916 		tx_fastlock_recall_name = "TX_LO_fastlock_recall";
1917 
1918 
1919 	g_builder_connect_signal(builder, "rx1_phase_rotation", "value-changed",
1920 			G_CALLBACK(rx_phase_rotation_set), (gpointer *)0);
1921 
1922 	g_builder_connect_signal(builder, "rx2_phase_rotation", "value-changed",
1923 			G_CALLBACK(rx_phase_rotation_set), (gpointer *)2);
1924 
1925 	g_builder_connect_signal(builder, "fmcomms2_settings_reload", "clicked",
1926 		G_CALLBACK(reload_button_clicked), NULL);
1927 
1928 	g_builder_connect_signal(builder, "filter_fir_config", "file-set",
1929 		G_CALLBACK(filter_fir_config_file_set_cb), NULL);
1930 
1931 	g_builder_connect_signal(builder, "dcxo_cal", "clicked",
1932 		G_CALLBACK(dcxo_cal_clicked), NULL);
1933 #ifndef _WIN32
1934 	g_builder_connect_signal(builder, "dcxo_cal_to_eeprom", "clicked",
1935 		G_CALLBACK(dcxo_cal_to_eeprom_clicked), NULL);
1936 	g_builder_connect_signal(builder, "dcxo_cal_from_eeprom", "clicked",
1937 		G_CALLBACK(dcxo_cal_from_eeprom_clicked), NULL);
1938 #endif
1939 
1940 	g_builder_connect_signal(builder, "rx_fastlock_store", "clicked",
1941 		G_CALLBACK(fastlock_clicked), (gpointer) 1);
1942 	g_builder_connect_signal(builder, "tx_fastlock_store", "clicked",
1943 		G_CALLBACK(fastlock_clicked), (gpointer) 2);
1944 	g_builder_connect_signal(builder, "rx_fastlock_recall", "clicked",
1945 		G_CALLBACK(fastlock_clicked), (gpointer) 3);
1946 	g_builder_connect_signal(builder, "tx_fastlock_recall", "clicked",
1947 		G_CALLBACK(fastlock_clicked), (gpointer) 4);
1948 
1949 	g_signal_connect_after(section_toggle[SECTION_GLOBAL], "clicked",
1950 		G_CALLBACK(hide_section_cb), section_setting[SECTION_GLOBAL]);
1951 
1952 	g_signal_connect_after(section_toggle[SECTION_TX], "clicked",
1953 		G_CALLBACK(hide_section_cb), section_setting[SECTION_TX]);
1954 
1955 	g_signal_connect_after(section_toggle[SECTION_RX], "clicked",
1956 		G_CALLBACK(hide_section_cb), section_setting[SECTION_RX]);
1957 
1958 	g_signal_connect_after(section_toggle[SECTION_FPGA], "clicked",
1959 		G_CALLBACK(hide_section_cb), section_setting[SECTION_FPGA]);
1960 
1961 	g_signal_connect_after(ensm_mode_available, "changed",
1962 		G_CALLBACK(glb_settings_update_labels), NULL);
1963 
1964 	g_signal_connect_after(calib_mode_available, "changed",
1965 		G_CALLBACK(glb_settings_update_labels), NULL);
1966 
1967 	g_signal_connect_after(trx_rate_governor_available, "changed",
1968 		G_CALLBACK(glb_settings_update_labels), NULL);
1969 
1970 	g_signal_connect_after(rx_gain_control_modes_rx1, "changed",
1971 		G_CALLBACK(glb_settings_update_labels), NULL);
1972 	g_signal_connect_after(rx_gain_control_modes_rx2, "changed",
1973 		G_CALLBACK(glb_settings_update_labels), NULL);
1974 
1975 	g_signal_connect_after(fpga_rx_frequency_available, "changed",
1976 			       G_CALLBACK(int_dec_update_cb), sampling_freq_rx_decim);
1977 
1978 	g_signal_connect_after(fpga_tx_frequency_available, "changed",
1979 			       G_CALLBACK(int_dec_update_cb), sampling_freq_tx_inter);
1980 
1981 
1982 	if (tx_rssi_available)
1983 		g_signal_connect(rf_port_select_rx, "changed",
1984 			G_CALLBACK(rf_port_select_rx_changed_cb), NULL);
1985 
1986 	g_signal_connect_after(enable_fir_filter_rx, "toggled",
1987 		G_CALLBACK(filter_fir_enable), NULL);
1988 	g_signal_connect_after(fir_filter_en_tx, "toggled",
1989 		G_CALLBACK(filter_fir_enable), NULL);
1990 	g_signal_connect_after(enable_fir_filter_rx_tx, "toggled",
1991 		G_CALLBACK(filter_fir_enable), NULL);
1992 	g_signal_connect_after(disable_all_fir_filters, "toggled",
1993 		G_CALLBACK(filter_fir_enable), NULL);
1994 
1995 	g_signal_connect(up_down_converter, "toggled",
1996 		G_CALLBACK(up_down_converter_toggled_cb), NULL);
1997 
1998 	make_widget_update_signal_based(glb_widgets, num_glb);
1999 	make_widget_update_signal_based(rx_widgets, num_rx);
2000 	make_widget_update_signal_based(tx_widgets, num_tx);
2001 	make_widget_update_signal_based(fpga_widgets, num_fpga);
2002 
2003 	iio_spin_button_set_on_complete_function(&rx_widgets[rx_sample_freq],
2004 		tx_sample_frequency_changed_cb, (void *) FALSE);
2005 	iio_spin_button_set_on_complete_function(&tx_widgets[tx_sample_freq],
2006 		tx_sample_frequency_changed_cb, (void *) TRUE);
2007 	iio_spin_button_set_on_complete_function(&rx_widgets[rx_lo],
2008 		sample_frequency_changed_cb, NULL);
2009 	iio_spin_button_set_on_complete_function(&tx_widgets[tx_lo],
2010 		sample_frequency_changed_cb, NULL);
2011 
2012 	/* Things are saved in tx_sample_frequency_changed_cb() */
2013 	iio_spin_button_skip_save_on_complete(&rx_widgets[rx_sample_freq], TRUE);
2014 	iio_spin_button_skip_save_on_complete(&tx_widgets[tx_sample_freq], TRUE);
2015 
2016 	add_ch_setup_check_fct("cf-ad9361-lpc", channel_combination_check);
2017 
2018 	struct iio_device *adc_dev;
2019 	struct extra_dev_info *adc_info;
2020 
2021 	adc_dev = iio_context_find_device(get_context_from_osc(), CAP_DEVICE);
2022 	if (adc_dev) {
2023 		adc_info = iio_device_get_data(adc_dev);
2024 		if (adc_info) /* TO DO: use osc preferences instead */
2025 			adc_info->plugin_fft_corr = 20 * log10(1/sqrt(HANNING_ENBW));
2026 	}
2027 
2028 	block_diagram_init(builder, 2, "AD9361.svg", "AD_FMCOMM2S2_RevC.jpg");
2029 
2030 	gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER(filter_fir_config), OSC_FILTER_FILE_PATH);
2031 	dac_data_manager_set_buffer_chooser_current_folder(dac_tx_manager, OSC_WAVEFORM_FILE_PATH);
2032 
2033 	if (!is_2rx_2tx) {
2034 		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(builder, "frame_rx2")));
2035 		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(builder, "frame_fpga_rx2")));
2036 		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(builder, "table_hw_gain_tx2")));
2037 	}
2038 	if (!tx_rssi_available) {
2039 		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(builder, "rssi_tx1")));
2040 		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(builder, "rssi_tx2")));
2041 		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(builder, "label_rssi_tx1")));
2042 		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(builder, "label_rssi_tx2")));
2043 	}
2044 	gtk_widget_set_visible(up_down_converter, has_udc_driver);
2045 
2046 	if (!dac_tx_manager)
2047 		gtk_widget_hide(gtk_widget_get_parent(section_setting[SECTION_FPGA]));
2048 
2049 	g_timeout_add(1000, (GSourceFunc) update_display, ctx);
2050 	can_update_widgets = true;
2051 
2052 	return fmcomms2_panel;
2053 }
2054 
update_active_page(struct osc_plugin * plugin,gint active_page,gboolean is_detached)2055 static void update_active_page(struct osc_plugin *plugin, gint active_page, gboolean is_detached)
2056 {
2057 	this_page = active_page;
2058 	plugin_detached = is_detached;
2059 }
2060 
fmcomms2_get_preferred_size(const struct osc_plugin * plugin,int * width,int * height)2061 static void fmcomms2_get_preferred_size(const struct osc_plugin *plugin, int *width, int *height)
2062 {
2063 	if (width)
2064 		*width = 1100;
2065 	if (height)
2066 		*height = 800;
2067 }
2068 
save_widgets_to_ini(FILE * f)2069 static void save_widgets_to_ini(FILE *f)
2070 {
2071 	fprintf(f, "load_fir_filter_file = %s\n"
2072 			"dds_mode_tx1 = %i\n"
2073 			"dds_mode_tx2 = %i\n"
2074 			"tx_channel_0 = %i\n"
2075 			"tx_channel_1 = %i\n"
2076 			"tx_channel_2 = %i\n"
2077 			"tx_channel_3 = %i\n"
2078 			"dac_buf_filename = %s\n"
2079 			"up_down_converter = %i\n"
2080 			"global_settings_show = %i\n"
2081 			"tx_show = %i\n"
2082 			"rx_show = %i\n"
2083 			"fpga_show = %i\n",
2084 			last_fir_filter,
2085 			dac_data_manager_get_dds_mode(dac_tx_manager, DDS_DEVICE, 1),
2086 			dac_data_manager_get_dds_mode(dac_tx_manager, DDS_DEVICE, 2),
2087 			dac_data_manager_get_tx_channel_state(dac_tx_manager, 0),
2088 			dac_data_manager_get_tx_channel_state(dac_tx_manager, 1),
2089 			dac_data_manager_get_tx_channel_state(dac_tx_manager, 2),
2090 			dac_data_manager_get_tx_channel_state(dac_tx_manager, 3),
2091 			dac_data_manager_get_buffer_chooser_filename(dac_tx_manager),
2092 			!!gtk_toggle_button_get_active((GtkToggleButton *)up_down_converter),
2093 			!!gtk_toggle_tool_button_get_active(section_toggle[SECTION_GLOBAL]),
2094 			!!gtk_toggle_tool_button_get_active(section_toggle[SECTION_TX]),
2095 			!!gtk_toggle_tool_button_get_active(section_toggle[SECTION_RX]),
2096 			!!gtk_toggle_tool_button_get_active(section_toggle[SECTION_FPGA]));
2097 }
2098 
save_profile(const struct osc_plugin * plugin,const char * ini_fn)2099 static void save_profile(const struct osc_plugin *plugin, const char *ini_fn)
2100 {
2101 	FILE *f = fopen(ini_fn, "a");
2102 	if (f) {
2103 		save_to_ini(f, THIS_DRIVER, dev, fmcomms2_sr_attribs,
2104 				ARRAY_SIZE(fmcomms2_sr_attribs));
2105 		if (dds)
2106 			save_to_ini(f, NULL, dds, fmcomms2_sr_attribs,
2107 					ARRAY_SIZE(fmcomms2_sr_attribs));
2108 		if (udc_rx)
2109 			save_to_ini(f, NULL, udc_rx, fmcomms2_sr_attribs,
2110 					ARRAY_SIZE(fmcomms2_sr_attribs));
2111 		if (udc_tx)
2112 			save_to_ini(f, NULL, udc_tx, fmcomms2_sr_attribs,
2113 					ARRAY_SIZE(fmcomms2_sr_attribs));
2114 		save_widgets_to_ini(f);
2115 		fclose(f);
2116 	}
2117 }
2118 
context_destroy(struct osc_plugin * plugin,const char * ini_fn)2119 static void context_destroy(struct osc_plugin *plugin, const char *ini_fn)
2120 {
2121 	g_source_remove_by_user_data(ctx);
2122 
2123 	if (ini_fn)
2124 		save_profile(NULL, ini_fn);
2125 
2126 	if (dac_tx_manager) {
2127 		dac_data_manager_free(dac_tx_manager);
2128 		dac_tx_manager = NULL;
2129 	}
2130 
2131 	osc_destroy_context(ctx);
2132 }
2133 
2134 struct osc_plugin plugin;
2135 
fmcomms2_identify(const struct osc_plugin * plugin)2136 static bool fmcomms2_identify(const struct osc_plugin *plugin)
2137 {
2138 	/* Use the OSC's IIO context just to detect the devices */
2139 	struct iio_context *osc_ctx = get_context_from_osc();
2140 
2141 	if (!iio_context_find_device(osc_ctx, PHY_DEVICE))
2142 		return false;
2143 
2144 	/* Check if FMComms5 is used */
2145 	return !iio_context_find_device(osc_ctx, "ad9361-phy-B");
2146 }
2147 
get_dac_dev_names(const struct osc_plugin * plugin)2148 GSList* get_dac_dev_names(const struct osc_plugin *plugin) {
2149 	GSList *list = NULL;
2150 
2151 	list = g_slist_append (list, (gpointer) DDS_DEVICE);
2152 
2153 	return list;
2154 }
2155 
2156 struct osc_plugin plugin = {
2157 	.name = THIS_DRIVER,
2158 	.identify = fmcomms2_identify,
2159 	.init = fmcomms2_init,
2160 	.handle_item = fmcomms2_handle,
2161 	.handle_external_request = handle_external_request,
2162 	.update_active_page = update_active_page,
2163 	.get_preferred_size = fmcomms2_get_preferred_size,
2164 	.save_profile = save_profile,
2165 	.load_profile = load_profile,
2166 	.destroy = context_destroy,
2167 	.get_dac_dev_names = get_dac_dev_names,
2168 };
2169