1 /**
2  * Copyright (C) 2012-2013 Analog Devices, Inc.
3  *
4  * Licensed under the GPL-2.
5  *
6  **/
7 #include <stdio.h>
8 
9 #include <gtk/gtk.h>
10 #include <glib.h>
11 #include <gtkdatabox.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 "../libini2.h"
26 #include "../osc.h"
27 #include "../iio_widget.h"
28 #include "../osc_plugin.h"
29 #include "../config.h"
30 #include "../eeprom.h"
31 #include "scpi.h"
32 #include "dac_data_manager.h"
33 
34 #ifndef MAXFLOAT
35 #define MAXFLOAT HUGE
36 #endif
37 
38 #define THIS_DRIVER "FMComms1"
39 
40 #define ARRAY_SIZE(x) (!sizeof(x) ?: sizeof(x) / sizeof((x)[0]))
41 
42 static const gdouble mhz_scale = 1000000.0;
43 
44 static OscPlot *plot_fft_2ch;
45 static struct dac_data_manager *dac_tx_manager;
46 
47 #define VERSION_SUPPORTED 1
48 static struct fmcomms1_calib_data_v1 *cal_data = NULL;
49 static struct fmcomms1_calib_header_v1 *cal_header = NULL;
50 
51 static GtkWidget *vga_gain0, *vga_gain1;
52 static GtkAdjustment *adj_gain0, *adj_gain1;
53 static GtkWidget *rf_out;
54 static GtkWidget *gain_locked;
55 
56 static GtkWidget *dds1_freq, *dds2_freq, *dds3_freq, *dds4_freq;
57 static GtkWidget *dds1_scale, *dds2_scale, *dds3_scale, *dds4_scale;
58 static GtkWidget *dds1_phase, *dds2_phase, *dds3_phase, *dds4_phase;
59 static int rx_lo_powerdown, tx_lo_powerdown;
60 
61 static GtkWidget *dac_data_clock;
62 static GtkWidget *dac_interpolation;
63 static GtkWidget *dac_shift;
64 
65 static GtkWidget *rx_lo_freq, *tx_lo_freq;
66 
67 static GtkWidget *avg_I, *avg_Q;
68 static GtkWidget *span_I, *span_Q;
69 static GtkWidget *radius_IQ, *angle_IQ;
70 
71 static GtkWidget *load_eeprom;
72 
73 static struct iio_context *ctx;
74 static struct iio_device *dac, *adc, *txpll, *rxpll, *vga;
75 
76 static struct iio_widget tx_widgets[100];
77 static struct iio_widget rx_widgets[100];
78 static struct iio_widget cal_widgets[100];
79 static unsigned int num_tx, num_rx, num_cal,
80 		num_adc_freq, num_dac_freq, num_dac_shift,
81 		num_dac_interpolation;
82 
83 static struct iio_device *adc_freq_device;
84 static struct iio_channel *adc_freq_channel;
85 static const char *adc_freq_file;
86 
87 static int num_tx_pll, num_rx_pll;
88 
89 static bool can_update_widgets;
90 
91 typedef struct _Dialogs Dialogs;
92 struct _Dialogs
93 {
94 	GtkWidget *calibrate;
95 	GtkWidget *filechooser;
96 };
97 static Dialogs dialogs;
98 static GtkWidget *cal_save, *cal_open, *cal_tx, *cal_rx;
99 static GtkWidget *I_dac_pha_adj, *I_dac_offs, *I_dac_fs_adj;
100 static GtkWidget *Q_dac_pha_adj, *Q_dac_offs, *Q_dac_fs_adj;
101 static GtkWidget *I_adc_offset_adj, *I_adc_gain_adj, *I_adc_phase_adj;
102 static GtkWidget *Q_adc_offset_adj, *Q_adc_gain_adj, *Q_adc_phase_adj;
103 static double cal_rx_level = 0;
104 static struct marker_type *rx_marker = NULL;
105 
106 static GtkWidget *ad9122_temp;
107 
108 static const char *fmcomms1_sr_attribs[] = {
109 	"cf-ad9122-core-lpc.out_altvoltage_1A_sampling_frequency",
110 	"cf-ad9122-core-lpc.out_altvoltage_sampling_frequency",
111 	"cf-ad9122-core-lpc.out_altvoltage_interpolation_frequency",
112 	"cf-ad9122-core-lpc.out_altvoltage_interpolation_center_shift_frequency",
113 	"cf-ad9122-core-lpc.out_altvoltage0_1A_frequency",
114 	"cf-ad9122-core-lpc.out_altvoltage2_2A_frequency",
115 	"cf-ad9122-core-lpc.out_altvoltage1_1B_frequency",
116 	"cf-ad9122-core-lpc.out_altvoltage3_2B_frequency",
117 	"cf-ad9122-core-lpc.out_altvoltage0_1A_scale",
118 	"cf-ad9122-core-lpc.out_altvoltage2_2A_scale",
119 	"cf-ad9122-core-lpc.out_altvoltage1_1B_scale",
120 	"cf-ad9122-core-lpc.out_altvoltage3_2B_scale",
121 	"cf-ad9122-core-lpc.out_altvoltage0_1A_phase",
122 	"cf-ad9122-core-lpc.out_altvoltage1_1B_phase",
123 	"cf-ad9122-core-lpc.out_altvoltage2_2A_phase",
124 	"cf-ad9122-core-lpc.out_altvoltage3_2B_phase",
125 	"adf4351-tx-lpc.out_altvoltage0_frequency",
126 	"adf4351-tx-lpc.out_altvoltage0_powerdown",
127 	"adf4351-tx-lpc.out_altvoltage0_frequency_resolution",
128 	"cf-ad9122-core-lpc.out_voltage0_calibbias",
129 	"cf-ad9122-core-lpc.out_voltage0_calibscale",
130 	"cf-ad9122-core-lpc.out_voltage0_phase",
131 	"cf-ad9122-core-lpc.out_voltage1_calibbias",
132 	"cf-ad9122-core-lpc.out_voltage1_calibscale",
133 	"cf-ad9122-core-lpc.out_voltage1_phase",
134 	"cf-ad9643-core-lpc.in_voltage_sampling_frequency",
135 	"cf-ad9643-core-lpc.in_voltage0_calibbias",
136 	"cf-ad9643-core-lpc.in_voltage1_calibbias",
137 	"cf-ad9643-core-lpc.in_voltage0_calibscale",
138 	"cf-ad9643-core-lpc.in_voltage1_calibscale",
139 	"cf-ad9643-core-lpc.in_voltage0_calibphase",
140 	"cf-ad9643-core-lpc.in_voltage1_calibphase",
141 	"adf4351-rx-lpc.out_altvoltage0_frequency_resolution",
142 	"adf4351-rx-lpc.out_altvoltage0_frequency",
143 	"adf4351-rx-lpc.out_altvoltage0_powerdown",
144 	"ad8366-lpc.out_voltage0_hardwaregain",
145 	"ad8366-lpc.out_voltage1_hardwaregain",
146 };
147 
148 static const char *fmcomms1_driver_attribs[] = {
149 	"dds_mode",
150 	"tx_channel_0",
151 	"tx_channel_1",
152 	"dac_buf_filename",
153 	"calibrate_rx_level",
154 	"cal_clear",
155 	"cal_add",
156 	"cal_save",
157 	"calibrate_rx",
158 	"calibrate_tx",
159 	"gain_locked",
160 };
161 
162 static int kill_thread;
163 static int fmcomms1_cal_eeprom(void);
164 
165 static struct s_cal_eeprom_v1 {
166 	struct fmcomms1_calib_header_v1 header;
167 	struct fmcomms1_calib_data_v1 data[
168 		(MAX_SIZE_CAL_EEPROM - sizeof(struct fmcomms1_calib_header_v1)) /
169 		sizeof(struct fmcomms1_calib_data_v1)];
170 } __attribute__((packed)) cal_eeprom_v1;
171 
172 static unsigned short temp_calibbias;
173 
oneover(const gchar * num)174 static int oneover(const gchar *num)
175 {
176 	float close;
177 
178 	close = powf(2.0, roundf(log2f(1.0 / atof(num))));
179 	return (int)close;
180 
181 }
182 
dac_interpolation_update(void)183 static void dac_interpolation_update(void)
184 {
185 	tx_widgets[num_dac_interpolation].update(&tx_widgets[num_dac_interpolation]);
186 }
187 
dac_shift_update(void)188 static void dac_shift_update(void)
189 {
190 	tx_widgets[num_dac_shift].update(&tx_widgets[num_dac_shift]);
191 }
192 
rf_out_update(void)193 static void rf_out_update(void)
194 {
195 	char buf[1024], dds1_m[16], dds2_m[16];
196 	static GtkTextBuffer *tbuf = NULL;
197 	GtkTextIter iter;
198 	float dac_shft = 0, dds1, dds2, tx_lo;
199 	unsigned dds_mode;
200 	int val;
201 
202 	if (tbuf == NULL) {
203 		tbuf = gtk_text_buffer_new(NULL);
204 		gtk_text_view_set_buffer(GTK_TEXT_VIEW(rf_out), tbuf);
205 	}
206 
207 	memset(buf, 0, 1024);
208 
209 	sprintf(buf, "\n");
210 	gtk_text_buffer_set_text(tbuf, buf, -1);
211 	gtk_text_buffer_get_iter_at_line(tbuf, &iter, 1);
212 
213 	tx_lo = gtk_spin_button_get_value (GTK_SPIN_BUTTON(tx_lo_freq));
214 	dds1 = gtk_spin_button_get_value(GTK_SPIN_BUTTON(dds1_freq));
215 	dds2 = gtk_spin_button_get_value(GTK_SPIN_BUTTON(dds2_freq));
216 	gchar *dac_shift_text = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(dac_shift));
217 	if (dac_shift_text) {
218 		dac_shft = atof(dac_shift_text)/1000000.0;
219 		g_free(dac_shift_text);
220 	}
221 
222 	val = -1;
223 	if (GTK_IS_COMBO_BOX_TEXT(dds1_scale)) {
224 		gchar *dds1_scale_text = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(dds1_scale));
225 		if(dds1_scale_text) {
226 			val = oneover(dds1_scale_text);
227 			g_free(dds1_scale_text);
228 		}
229 	} else if (GTK_IS_SPIN_BUTTON(dds1_scale)) {
230 		val = oneover(gtk_entry_get_text(GTK_ENTRY(dds1_scale)));
231 	}
232 
233 	if (!(val < 0))
234 		sprintf(dds1_m, "1/%i", val);
235 	else
236 		sprintf(dds1_m, "?");
237 
238 	val = -1;
239 	if (GTK_IS_COMBO_BOX_TEXT(dds2_scale)) {
240 		gchar *dds2_scale_text = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(dds2_scale));
241 		if (dds2_scale_text) {
242 			val = oneover(dds2_scale_text);
243 			g_free(dds2_scale_text);
244 		}
245 	} else if (GTK_IS_SPIN_BUTTON(dds2_scale)) {
246 		val = oneover(gtk_entry_get_text(GTK_ENTRY(dds2_scale)));
247 	}
248 
249 	if (!(val < 0))
250 		sprintf(dds2_m, "1/%i", val);
251 	else
252 		sprintf(dds2_m, "?");
253 
254 
255 	dds_mode = dac_data_manager_get_dds_mode(dac_tx_manager, "cf-ad9122-core-lpc", 1);
256 	if (dds_mode == DDS_ONE_TONE ||
257 			dds_mode == DDS_TWO_TONE) {
258 		sprintf(buf, "%4.3f MHz : Image\n", tx_lo - dds1 - dac_shft);
259 		gtk_text_buffer_insert(tbuf, &iter, buf, -1);
260 	}
261 	if (dds_mode == 2) {
262 		sprintf(buf, "%4.3f MHz : Image\n", tx_lo - dds2 - dac_shft);
263 		gtk_text_buffer_insert(tbuf, &iter, buf, -1);
264 	}
265 
266 	sprintf(buf, "%4.3f MHz : LO Leakage\n", tx_lo);
267 	gtk_text_buffer_insert(tbuf, &iter, buf, -1);
268 
269 	switch(dds_mode) {
270 	case 0:
271 		break;
272 	case 1:
273 		sprintf(buf, "%4.3f MHz : Signal %s\n", tx_lo + dds1 + dac_shft, dds1_m);
274 		gtk_text_buffer_insert(tbuf, &iter, buf, -1);
275 		break;
276 	case 2:
277 		sprintf(buf, "%4.3f MHz : Signal %s\n", tx_lo + dds1 + dac_shft, dds1_m);
278 		gtk_text_buffer_insert(tbuf, &iter, buf, -1);
279 		sprintf(buf, "%4.3f MHz : Signal %s\n", tx_lo + dds2 + dac_shft, dds2_m);
280 		gtk_text_buffer_insert(tbuf, &iter, buf, -1);
281 		break;
282 	case 3:
283 	case 4:
284 		sprintf(buf, "\n");
285 		gtk_text_buffer_insert(tbuf, &iter, buf, -1);
286 		break;
287 
288 	}
289 
290 }
291 
rx_freq_info_update(void)292 static void rx_freq_info_update(void)
293 {
294 	double lo_freq;
295 
296 	if (!adc)
297 		return;
298 
299 	rx_update_device_sampling_freq("cf-ad9643-core-lpc",
300 		USE_INTERN_SAMPLING_FREQ);
301 	lo_freq = mhz_scale * gtk_spin_button_get_value(
302 				GTK_SPIN_BUTTON(rx_lo_freq));
303 	rx_update_channel_lo_freq("cf-ad9643-core-lpc", "all", lo_freq);
304 }
305 
rf_out_update_on_complete(void * data)306 static void rf_out_update_on_complete(void *data)
307 {
308 	rf_out_update();
309 }
310 
rx_update_labels_on_complete(void * data)311 static void rx_update_labels_on_complete(void *data)
312 {
313 	rx_freq_info_update();
314 }
315 
tx_update_values(void)316 static void tx_update_values(void)
317 {
318 	iio_update_widgets(tx_widgets, num_tx);
319 	rf_out_update();
320 }
321 
rx_update_values(void)322 static void rx_update_values(void)
323 {
324 	iio_update_widgets(rx_widgets, num_rx);
325 	rx_freq_info_update();
326 }
327 
cal_update_values(void)328 static void cal_update_values(void)
329 {
330 	iio_update_widgets(cal_widgets, num_cal);
331 }
332 
cal_save_values(void)333 static void cal_save_values(void)
334 {
335 	iio_save_widgets(cal_widgets, num_cal);
336 	iio_update_widgets(cal_widgets, num_cal);
337 }
338 
tx_sample_rate_changed(void * data)339 static void tx_sample_rate_changed(void *data)
340 {
341 	GtkSpinButton *dac_freq_spin;
342 	gdouble rate;
343 	GtkWidget *tone_freq;
344 	unsigned tone;
345 
346 	dac_freq_spin = GTK_SPIN_BUTTON(tx_widgets[num_dac_freq].widget);
347 	rate = gtk_spin_button_get_value(dac_freq_spin) / 2.0;
348 	dac_data_manager_freq_widgets_range_update(dac_tx_manager, rate);
349 
350 	for (tone = dac_data_manager_dds_tone(0, TONE_1, TONE_I);
351 		tone <= dac_data_manager_dds_tone(0, TONE_2, TONE_Q); tone++) {
352 		tone_freq = dac_data_manager_get_widget(dac_tx_manager,
353 				tone, WIDGET_FREQUENCY);
354 		g_signal_emit_by_name(tone_freq, "value-changed", NULL);
355 	}
356 }
357 
find_entry(struct fmcomms1_calib_data_v1 * data,struct fmcomms1_calib_header_v1 * header,unsigned f)358 static struct fmcomms1_calib_data_v1 *find_entry(struct fmcomms1_calib_data_v1 *data,
359 					 struct fmcomms1_calib_header_v1 *header,
360 					 unsigned f)
361 {
362 	int ind = 0;
363 	int delta, gindex = 0;
364 	int min_delta = 2147483647;
365 
366 	if (!header && !data)
367 		return NULL;
368 
369 	for (ind = 0; ind < header->num_entries; ind++) {
370 			if (f > data->cal_frequency_MHz)
371 				delta = f - data->cal_frequency_MHz;
372 			else
373 				delta = data->cal_frequency_MHz - f;
374 			if (delta < min_delta) {
375 				gindex = ind;
376 				min_delta = delta;
377 			}
378 	}
379 
380 	return &data[gindex];
381 }
382 
store_entry_hw(struct fmcomms1_calib_data_v1 * data,unsigned tx,unsigned rx)383 static void store_entry_hw(struct fmcomms1_calib_data_v1 *data, unsigned tx, unsigned rx)
384 {
385 	if (!data)
386 		return;
387 
388 	if (tx) {
389 		struct iio_channel *ch0 = iio_device_find_channel(dac, "voltage0", true),
390 				   *ch1 = iio_device_find_channel(dac, "voltage1", true);
391 		iio_channel_attr_write_longlong(ch0, "calibbias", data->i_dac_offset);
392 		iio_channel_attr_write_longlong(ch0, "calibscale", data->i_dac_fs_adj);
393 		iio_channel_attr_write_longlong(ch0, "phase", data->i_phase_adj);
394 		iio_channel_attr_write_longlong(ch1, "calibbias", data->q_dac_offset);
395 		iio_channel_attr_write_longlong(ch1, "calibscale", data->q_dac_fs_adj);
396 		iio_channel_attr_write_longlong(ch1, "phase", data->q_phase_adj);
397 		cal_update_values();
398 	}
399 
400 	if (rx) {
401 		struct iio_channel *ch0 = iio_device_find_channel(adc, "voltage0", false),
402 				   *ch1 = iio_device_find_channel(adc, "voltage1", false);
403 		iio_channel_attr_write_longlong(ch0, "calibbias", data->i_adc_offset_adj);
404 		iio_channel_attr_write_double(ch0, "calibscale", fract1_1_14_to_float(data->i_adc_gain_adj));
405 		iio_channel_attr_write_longlong(ch1, "calibbias", data->q_adc_offset_adj);
406 		iio_channel_attr_write_double(ch1, "calibscale", fract1_1_14_to_float(data->q_adc_gain_adj));
407 		iio_channel_attr_write_double(ch0, "calibphase", fract1_1_14_to_float(data->i_adc_phase_adj));
408 		cal_update_values();
409 	}
410 }
411 
pll_get_freq(struct iio_widget * widget)412 static gdouble pll_get_freq(struct iio_widget *widget)
413 {
414 	gdouble freq;
415 
416 	gdouble scale = widget->priv ? *(gdouble *)widget->priv : 1.0;
417 	freq = gtk_spin_button_get_value(GTK_SPIN_BUTTON (widget->widget));
418 	freq *= scale;
419 
420 	return freq;
421 }
422 
gain_amp_locked_cb(GtkToggleButton * btn,gpointer data)423 static void gain_amp_locked_cb(GtkToggleButton *btn, gpointer data)
424 {
425 	gdouble tmp;
426 
427 	if(gtk_toggle_button_get_active(btn)) {
428 		tmp = gtk_spin_button_get_value(GTK_SPIN_BUTTON(vga_gain0));
429 		gtk_spin_button_set_value(GTK_SPIN_BUTTON(vga_gain1), tmp);
430 		gtk_spin_button_set_adjustment(GTK_SPIN_BUTTON(vga_gain1), adj_gain0);
431 	} else {
432 		tmp = gtk_spin_button_get_value(GTK_SPIN_BUTTON(vga_gain0));
433 		gtk_adjustment_set_value(adj_gain1, tmp);
434 		gtk_spin_button_set_adjustment(GTK_SPIN_BUTTON(vga_gain1), adj_gain1);
435 	}
436 }
437 
load_cal_eeprom()438 static void load_cal_eeprom()
439 {
440 	gdouble freq;
441 	freq = pll_get_freq(&tx_widgets[num_tx_pll]);
442 	store_entry_hw(find_entry(cal_data, cal_header,
443 			(unsigned) (freq / mhz_scale)), 1, 0);
444 
445 	freq = pll_get_freq(&rx_widgets[num_rx_pll]);
446 	store_entry_hw(find_entry(cal_data, cal_header,
447 			(unsigned) (freq / mhz_scale)), 0, 1);
448 }
449 
450 static bool cal_rx_flag = false;
451 static gfloat knob_max, knob_min, knob_steps;
452 static int delay;
453 
find_min(GtkSpinButton * spin_button,int marker,gfloat min,gfloat max,gfloat step,gfloat noise_floor)454 static double find_min(GtkSpinButton *spin_button, int marker, gfloat min, gfloat max, gfloat step, gfloat noise_floor)
455 {
456 	gdouble i, level, min_level = FLT_MAX, min_value = 0;
457 	gdouble nfloor_min = max, nfloor_max = min;
458 	int bigger = -1;
459 	gdouble last_val = FLT_MAX;
460 
461 	for (i = min; i <= max; i += (max - min)/step) {
462 		gdk_threads_enter();
463 		gtk_spin_button_set_value(spin_button, i);
464 		gdk_threads_leave();
465 
466 		scpi_rx_trigger_sweep();
467 		scpi_rx_get_marker_level(1, true, &level);
468 		if (level <= min_level) {
469 			if (min_level != FLT_MAX)
470 				bigger = 0;
471 			min_level = level;
472 			min_value = i;
473 		}
474 
475 		if (min_value != 0 && bigger != -1) {
476 			if (level > last_val)
477 				bigger++;
478 			else
479 				bigger = 0;
480 		}
481 
482 		if (bigger == 5)
483 			break;
484 
485 		if (level <= noise_floor) {
486 			if (nfloor_min > i)
487 				nfloor_min = i;
488 			if (nfloor_max < i)
489 				nfloor_max = i;
490 		}
491 		last_val = level;
492 	}
493 
494 	/* wandering around the noise floor - pick the middle */
495 	if (nfloor_min != max && nfloor_max != min)
496 		min_value = (nfloor_min + nfloor_max) / 2;
497 
498 	gdk_threads_enter();
499 	gtk_spin_button_set_value(spin_button, min_value);
500 	gdk_threads_leave();
501 
502 	return min_value;
503 }
504 
tx_thread_cal(void * ptr)505 static void tx_thread_cal(void *ptr)
506 {
507 	gdouble min_i, min_q, tmp, min_fsi, min_fsq, noise;
508 	unsigned long long lo, sig;
509 
510 	gdk_threads_enter();
511 	/* LO Leakage */
512 	lo = (unsigned long long)gtk_spin_button_get_value (GTK_SPIN_BUTTON(tx_lo_freq)) * 1000000;
513 	sig = (unsigned long long)gtk_spin_button_get_value(GTK_SPIN_BUTTON(dds1_freq)) * 1000000;
514 
515 	/* set some default values */
516 	gtk_spin_button_set_value(GTK_SPIN_BUTTON(I_dac_offs), 0.0);
517 	gtk_spin_button_set_value(GTK_SPIN_BUTTON(Q_dac_offs), 0.0);
518 	gtk_spin_button_set_value(GTK_SPIN_BUTTON(I_dac_pha_adj), 0.0);
519 	gtk_spin_button_set_value(GTK_SPIN_BUTTON(Q_dac_pha_adj), 0.0);
520 	gtk_spin_button_set_value(GTK_SPIN_BUTTON(I_dac_fs_adj), 512.0);
521 	gtk_spin_button_set_value(GTK_SPIN_BUTTON(Q_dac_fs_adj), 512.0);
522 
523 	gdk_threads_leave();
524 
525 	scpi_rx_trigger_sweep();
526 	scpi_rx_trigger_sweep();
527 
528 	/* find the noise floor */
529 	scpi_rx_trigger_sweep();
530 	scpi_rx_set_center_frequency(lo);
531 	scpi_rx_set_span_frequency(sig * 2);
532 	scpi_rx_set_marker_freq(1, lo + sig / 2);
533 	scpi_rx_get_marker_level(1, true, &noise);
534 	/* noise thresold is 2dB up */
535 	noise += 2;
536 
537 	/* rough approximation of carrier supression */
538 	scpi_rx_set_center_frequency(lo);
539 	scpi_rx_set_span_frequency(2000000);
540 	scpi_rx_set_marker_freq(1, lo);
541 
542 	min_i = find_min(GTK_SPIN_BUTTON(I_dac_offs), 1, -500, 500, 25, noise);
543 	min_q = find_min(GTK_SPIN_BUTTON(Q_dac_offs), 1, -500, 500, 25, noise);
544 
545 	/* side band supression */
546 	scpi_rx_set_center_frequency(lo - sig);
547 	scpi_rx_set_marker_freq(1, lo - sig);
548 
549 	tmp = find_min(GTK_SPIN_BUTTON(I_dac_pha_adj), 1, -512, 512, 25, noise);
550 	tmp += find_min(GTK_SPIN_BUTTON(Q_dac_pha_adj), 1, -512, 512, 25, noise);
551 
552 	min_fsi = find_min(GTK_SPIN_BUTTON(I_dac_fs_adj), 1, 400, 600, 10, noise);
553 	min_fsq = find_min(GTK_SPIN_BUTTON(Q_dac_fs_adj), 1, 400, 600, 10, noise);
554 
555 	find_min(GTK_SPIN_BUTTON(I_dac_fs_adj), 1, min_fsi - 10, min_fsi + 10, 20, noise);
556 	find_min(GTK_SPIN_BUTTON(Q_dac_fs_adj), 1, min_fsq - 10, min_fsq + 10, 20, noise);
557 
558 	if (tmp != -1024) {
559 		gdk_threads_enter();
560 		gtk_spin_button_set_value(GTK_SPIN_BUTTON(I_dac_pha_adj), tmp / 2);
561 		gtk_spin_button_set_value(GTK_SPIN_BUTTON(Q_dac_pha_adj), tmp / 2);
562 		gdk_threads_leave();
563 
564 		find_min(GTK_SPIN_BUTTON(I_dac_pha_adj), 1, tmp / 2 - 20, tmp / 2 + 20, 40, noise);
565 		find_min(GTK_SPIN_BUTTON(Q_dac_pha_adj), 1, tmp / 2 - 20, tmp / 2 + 20, 40, noise);
566 	}
567 
568 	/* go back to carrier, and do it in smaller steps */
569 	scpi_rx_set_center_frequency(lo);
570 	scpi_rx_set_marker_freq(1, lo);
571 
572 	min_i = find_min(GTK_SPIN_BUTTON(I_dac_offs), 1, min_i - 40, min_i + 40, 20.0, noise);
573 	min_q = find_min(GTK_SPIN_BUTTON(Q_dac_offs), 1, min_q - 40, min_q + 40, 20.0, noise);
574 
575 	find_min(GTK_SPIN_BUTTON(I_dac_offs), 1, min_i - 10, min_i + 10, 20.0, noise);
576 	find_min(GTK_SPIN_BUTTON(Q_dac_offs), 1, min_q - 10, min_q + 10, 20.0, noise);
577 
578 	scpi_rx_set_span_frequency(3 * sig);
579 	scpi_rx_trigger_sweep();
580 	scpi_rx_trigger_sweep();
581 
582 	kill_thread = 1;
583 }
584 
cal_tx_button_clicked(void)585 static GThread * cal_tx_button_clicked(void)
586 {
587 	if (!scpi_rx_connected()) {
588 		printf("not connected\n");
589 		return NULL;
590 	}
591 
592 	/* make sure it's a single tone */
593 	if ((gtk_spin_button_get_value(GTK_SPIN_BUTTON(dds1_freq)) !=
594 				gtk_spin_button_get_value(GTK_SPIN_BUTTON(dds2_freq))) ||
595 			(gtk_spin_button_get_value(GTK_SPIN_BUTTON(dds1_freq)) !=
596 				gtk_spin_button_get_value(GTK_SPIN_BUTTON(dds3_freq))) ||
597 			(gtk_spin_button_get_value(GTK_SPIN_BUTTON(dds1_freq)) !=
598 				gtk_spin_button_get_value(GTK_SPIN_BUTTON(dds4_freq)))) {
599 		printf("not a tone\n");
600 		return NULL;
601 	}
602 
603 	scpi_rx_setup();
604 	scpi_rx_set_center_frequency(gtk_spin_button_get_value (GTK_SPIN_BUTTON(tx_lo_freq)) * 1000000 + 1000000);
605 	scpi_rx_set_span_frequency(3 * gtk_spin_button_get_value(GTK_SPIN_BUTTON(dds1_freq)) * 1000000);
606 	scpi_rx_set_bandwith(200, 10);
607 	scpi_rx_set_averaging(2);
608 	scpi_rx_trigger_sweep();
609 
610 	return g_thread_new("Tx calibration thread", (void *) &tx_thread_cal, NULL);
611 }
612 
cal_rx_button_clicked(void)613 static void cal_rx_button_clicked(void)
614 {
615 	OscPlot *fft_plot = plugin_find_plot_with_domain(FFT_PLOT);
616 	cal_rx_flag = true;
617 
618 	delay = 2 * plugin_data_capture_size(NULL) *
619 		plugin_get_plot_fft_avg(fft_plot, NULL);
620 
621 	gtk_spin_button_set_value(GTK_SPIN_BUTTON(Q_adc_phase_adj), 0);
622 
623 	knob_steps = 10;
624 	knob_max = 1;
625 	knob_min = -1;
626 	gtk_widget_hide(cal_rx);
627 }
628 
display_temp(void * ptr)629 static gboolean display_temp(void *ptr)
630 {
631 	double temp, tmp;
632 	struct iio_channel *chn = iio_device_find_channel(dac, "temp0", false);
633 
634 	if (kill_thread)
635 		return FALSE;
636 
637 	if (iio_channel_attr_read_double(chn, "input", &temp) < 0) {
638 		/* Just assume it's 25C, units are in milli-degrees C */
639 		temp = 25 * 1000;
640 		iio_channel_attr_write_double(chn, "input", temp);
641 		iio_channel_attr_read_double(chn, "calibbias", &tmp);
642 		/* This will eventually be stored in the EEPROM */
643 		temp_calibbias = (unsigned short) tmp;
644 		printf("AD9122 temp cal value : %hu\n", temp_calibbias);
645 	} else {
646 		char buf[25];
647 		sprintf(buf, "%2.1f", temp/1000);
648 		gtk_label_set_text(GTK_LABEL(ad9122_temp), buf);
649 	}
650 
651 	return TRUE;
652 }
653 
654 #define RX_CAL_THRESHOLD -75
655 
display_cal(void * ptr)656 static void display_cal(void *ptr)
657 {
658 	int size, channels, num_samples, i;
659 	gfloat **cooked_data = NULL;
660 	struct marker_type *markers = NULL;
661 	gfloat *channel_I, *channel_Q;
662 	gfloat max_x, min_x, avg_x;
663 	gfloat max_y, min_y, avg_y;
664 	gfloat max_r, min_r, max_theta, min_theta, rad;
665 	GtkSpinButton *knob;
666 	gfloat knob_value, knob_min_value, knob_min_knob = 0.0, knob_dc_value = 0.0, knob_twist;
667 	gfloat span_I_val, span_Q_val;
668 	gfloat gain = 1.0;
669 	char cbuf[256];
670 	bool show = false;
671 	const char *device_ref;
672 	int ret, attempt = 0;
673 	OscPlot *fft_plot = NULL;
674 	double ln10 = log(10.0);
675 
676 	device_ref = plugin_get_device_by_reference("cf-ad9643-core-lpc");
677 	if (!device_ref)
678 		goto display_call_ret;
679 
680 	if (!rx_marker) {
681 		rx_marker = g_new(struct marker_type, 3);
682 		rx_marker[0].active = false;
683 	}
684 
685 	while (!kill_thread) {
686 		size = plugin_data_capture_size(device_ref);
687 		channels = plugin_data_capture_num_active_channels(device_ref);
688 		i = plugin_data_capture_bytes_per_sample(device_ref);
689 		if (i)
690 			num_samples = size / i;
691 		else
692 			num_samples = 0;
693 
694 		fft_plot = plot_fft_2ch;
695 
696 		if (size != 0 && channels == 2) {
697 			gdk_threads_enter();
698 			if (show && !cal_rx_flag)
699 				gtk_widget_show(cal_rx);
700 			else
701 				gtk_widget_hide(cal_rx);
702 			gdk_threads_leave();
703 
704 			/* grab the data */
705 			if (cal_rx_flag && cal_rx_level &&
706 					plugin_get_plot_marker_type(fft_plot, device_ref) == MARKER_IMAGE) {
707 				do {
708 					ret = plugin_data_capture_of_plot(fft_plot, device_ref, &cooked_data, &markers);
709 				} while ((ret == -EBUSY) && !kill_thread);
710 			} else {
711 				do {
712 					ret = plugin_data_capture_of_plot(fft_plot, device_ref, &cooked_data, NULL);
713 				} while ((ret == -EBUSY) && !kill_thread);
714 			}
715 
716 			/* If the lock is broken, then die nicely */
717 			if (kill_thread || ret != 0) {
718 				size = 0;
719 				kill_thread = 1;
720 				break;
721 			}
722 
723 			channel_I = cooked_data[0];
724 			channel_Q = cooked_data[1];
725 			avg_x = avg_y = 0.0;
726 			max_x = max_y = -MAXFLOAT;
727 			min_x = min_y = MAXFLOAT;
728 			max_r = max_theta = -MAXFLOAT;
729 			min_r = min_theta = MAXFLOAT;
730 
731 			for (i = 0; i < num_samples; i++) {
732 				avg_x += channel_Q[i];
733 				avg_y += channel_I[i];
734 				rad = sqrtf((channel_I[i] * channel_I[i]) +
735 						(channel_Q[i] * channel_Q[i]));
736 
737 				if (max_x <= channel_Q[i])
738 					max_x = channel_Q[i];
739 				if (min_x >= channel_Q[i])
740 					min_x = channel_Q[i];
741 				if (max_y <= channel_I[i])
742 					max_y = channel_I[i];
743 				if (min_y >= channel_I[i])
744 					min_y = channel_I[i];
745 
746 				if (max_r <= rad) {
747 					max_r = rad;
748 					if (channel_I[i])
749 						max_theta = asinf(channel_Q[i]/rad);
750 					else
751 						max_theta = 0.0f;
752 				}
753 				if (min_r >= rad) {
754 					min_r = rad;
755 					if (channel_I[i])
756 						min_theta = asinf(channel_Q[i]/rad);
757 					else
758 						min_theta = 0.0f;
759 				}
760 			}
761 
762 			avg_x /= num_samples;
763 			avg_y /= num_samples;
764 
765 			if (min_r >= 10)
766 				show = true;
767 			else
768 				show = false;
769 
770 			gdk_threads_enter();
771 
772 			sprintf(cbuf, "avg: %3.0f | mid : %3.0f", avg_y, (min_y + max_y)/2);
773 			gtk_label_set_text(GTK_LABEL(avg_I), cbuf);
774 
775 			sprintf(cbuf, "avg: %3.0f | mid : %3.0f", avg_x, (min_x + max_x)/2);
776 			gtk_label_set_text(GTK_LABEL(avg_Q), cbuf);
777 
778 			sprintf(cbuf, "%3.0f <-> %3.0f (%3.0f)", max_y, min_y, (max_y - min_y));
779 			gtk_label_set_text(GTK_LABEL(span_I), cbuf);
780 
781 			sprintf(cbuf, "%3.0f <-> %3.0f (%3.0f)", max_x, min_x, (max_x - min_x));
782 			gtk_label_set_text(GTK_LABEL(span_Q), cbuf);
783 
784 			sprintf(cbuf, "max: %3.0f | min: %3.0f", max_r, min_r);
785 			gtk_label_set_text(GTK_LABEL(radius_IQ), cbuf);
786 
787 			sprintf(cbuf, "max: %0.3f | min: %0.3f", max_theta * 180 / M_PI, min_theta * 180 / M_PI);
788 			gtk_label_set_text(GTK_LABEL(angle_IQ), cbuf);
789 
790 			gdk_threads_leave();
791 
792 			if (cal_rx_flag) {
793 				gfloat span_I_set, span_Q_set;
794 
795 				gdk_threads_enter();
796 				/* DC correction */
797 				gtk_spin_button_set_value(GTK_SPIN_BUTTON(I_adc_offset_adj),
798 					gtk_spin_button_get_value(GTK_SPIN_BUTTON(I_adc_offset_adj)) -
799 					avg_y);
800 				gtk_spin_button_set_value(GTK_SPIN_BUTTON(Q_adc_offset_adj),
801 					gtk_spin_button_get_value(GTK_SPIN_BUTTON(Q_adc_offset_adj)) -
802 					avg_x);
803 
804 				/* Scale connection */
805 				span_I_set = gtk_spin_button_get_value(GTK_SPIN_BUTTON(I_adc_gain_adj));
806 				span_Q_set = gtk_spin_button_get_value(GTK_SPIN_BUTTON(Q_adc_gain_adj));
807 				span_I_val = (max_y - min_y) / span_I_set;
808 				span_Q_val = (max_x - min_x) / span_Q_set;
809 
810 				if (cal_rx_level &&
811 						plugin_get_plot_marker_type(fft_plot, device_ref) == MARKER_IMAGE) {
812 					if (attempt == 0)
813 						gain = (span_I_set + span_I_set) / 2;
814 					gain *= 1.0 / exp(ln10 * (double) ((markers[0].y - cal_rx_level) / 20));
815 				}
816 
817 				gtk_spin_button_set_value(GTK_SPIN_BUTTON(I_adc_gain_adj),
818 					(span_I_val + span_Q_val)/(2.0 * span_I_val) * gain);
819 				gtk_spin_button_set_value(GTK_SPIN_BUTTON(Q_adc_gain_adj),
820 					(span_I_val + span_Q_val)/(2.0 * span_Q_val) * gain);
821 				cal_save_values();
822 				gdk_threads_leave ();
823 
824 				usleep(delay);
825 				if (plugin_get_plot_marker_type(fft_plot, device_ref) != MARKER_IMAGE)
826 					cal_rx_flag = false;
827 			}
828 
829 			if (cal_rx_flag) {
830 				int bigger = 0;
831 				gfloat last_val = FLT_MAX;
832 
833 				if (attempt == 0) {
834 					/* if the current value is OK, we leave it alone */
835 					do {
836 						ret = plugin_data_capture_of_plot(fft_plot, device_ref, NULL, &markers);
837 					} while ((ret == -EBUSY) && !kill_thread);
838 
839 					/* If the lock is broken, then die nicely */
840 					if (kill_thread || ret != 0) {
841 						size = 0;
842 						kill_thread = 1;
843 						break;
844 					}
845 
846 					/* make sure image, and DC are below */
847 					if ((markers[2].y <= RX_CAL_THRESHOLD) && (markers[1].y <= RX_CAL_THRESHOLD)) {
848 						if (rx_marker)
849 							memcpy(rx_marker, markers, sizeof(struct marker_type) * 3);
850 						goto skip_rx_cal;
851 					}
852 				}
853 
854 				gdk_threads_enter();
855 				gtk_spin_button_set_value(GTK_SPIN_BUTTON(Q_adc_phase_adj), 0);
856 				knob = GTK_SPIN_BUTTON(I_adc_phase_adj);
857 				gdk_threads_leave();
858 
859 				attempt++;
860 				knob_min_value = 0;
861 
862 				knob_twist = (knob_max - knob_min)/knob_steps;
863 				for (knob_value = knob_min;
864 						knob_value <= knob_max;
865 						knob_value += knob_twist) {
866 
867 					gdk_threads_enter();
868 					gtk_spin_button_set_value(knob, knob_value);
869 					gdk_threads_leave();
870 					usleep(delay);
871 
872 					/* grab the data */
873 					do {
874 						ret = plugin_data_capture_of_plot(fft_plot, device_ref, NULL, &markers);
875 					} while ((ret == -EBUSY) && !kill_thread);
876 
877 					/* If the lock is broken, then die nicely */
878 					if (kill_thread || ret != 0) {
879 						size = 0;
880 						kill_thread = 1;
881 						break;
882 					}
883 
884 					if (markers[2].y <= knob_min_value) {
885 						if (rx_marker)
886 							memcpy(rx_marker, markers, sizeof(struct marker_type) * 3);
887 						knob_min_value = markers[2].y;
888 						knob_dc_value = markers[1].y;
889 						knob_min_knob = knob_value;
890 						bigger = 0;
891 					}
892 
893 					if (markers[2].y > last_val)
894 						bigger++;
895 
896 					if (bigger == 2)
897 						break;
898 
899 					last_val = markers[2].y;
900 				}
901 
902 				knob_max = knob_min_knob + (1 * knob_twist);
903 				if (knob_max >= 1.0)
904 					knob_max = 1.0;
905 
906 				knob_min = knob_min_knob - (1 * knob_twist);
907 				if (knob_min <= -1.0)
908 					knob_min = -1.0;
909 
910 				gdk_threads_enter();
911 				gtk_spin_button_set_value(knob, knob_min_knob);
912 				gdk_threads_leave();
913 				usleep(delay);
914 
915 				if (attempt >= 5 || ((knob_min_value <= RX_CAL_THRESHOLD) &&
916 						    (knob_dc_value <= RX_CAL_THRESHOLD))) {
917 skip_rx_cal:
918 					attempt = 0;
919 					cal_rx_flag = false;
920 					if (ptr) {
921 						kill_thread = 1;
922 						size = 0;
923 						break;
924 					}
925 				}
926 			}
927 		} else {
928 			/* wait 10 ms */
929 			usleep(10000);
930 		}
931 	}
932 
933 display_call_ret:
934 	/* free the buffers */
935 	if (cooked_data || markers)
936 		plugin_data_capture_of_plot(fft_plot, NULL, &cooked_data, &markers);
937 	kill_thread = 1;
938 	g_thread_exit(NULL);
939 }
940 
941 
get_filename(char * name,bool load)942 static char * get_filename(char *name, bool load)
943 {
944 	gint ret;
945 	char *filename, buf[256];
946 
947 	if (load) {
948 		gtk_widget_hide(cal_save);
949 		gtk_widget_show(cal_open);
950 	} else {
951 		gtk_widget_hide(cal_open);
952 		gtk_widget_show(cal_save);
953 		gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialogs.filechooser), true);
954 		if (name)
955 			gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialogs.filechooser), name);
956 		else {
957 			sprintf(buf, "%03.0f.txt", gtk_spin_button_get_value (GTK_SPIN_BUTTON(rx_lo_freq)));
958 			gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialogs.filechooser), buf);
959 		}
960 	}
961 	ret = gtk_dialog_run(GTK_DIALOG(dialogs.filechooser));
962 	filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialogs.filechooser));
963 
964 	if (filename) {
965 		switch(ret) {
966 			/* Response Codes encoded in glade file */
967 			case GTK_RESPONSE_CANCEL:
968 				g_free(filename);
969 				filename = NULL;
970 				break;
971 			case 2: /* open */
972 			case 1: /* save */
973 				break;
974 			default:
975 				printf("unknown ret (%i) in %s\n", ret, __func__);
976 				g_free(filename);
977 				filename = NULL;
978 				break;
979 		}
980 	}
981 	gtk_widget_hide(dialogs.filechooser);
982 
983 	return filename;
984 }
985 
986 
987 #define MATCH_SECT(s) (strcmp(section, s) == 0)
988 #define MATCH_NAME(n) (strcmp(name, n) == 0)
989 #define RX_F   "Rx_Frequency"
990 #define TX_F   "Tx_Frequency"
991 #define DDS1_F "DDS1_Frequency"
992 #define DDS1_S "DDS1_Scale"
993 #define DDS1_P "DDS1_Phase"
994 #define DDS2_F "DDS2_Frequency"
995 #define DDS2_S "DDS2_Scale"
996 #define DDS2_P "DDS2_Phase"
997 #define DDS3_F "DDS3_Frequency"
998 #define DDS3_S "DDS3_Scale"
999 #define DDS3_P "DDS3_Phase"
1000 #define DDS4_F "DDS4_Frequency"
1001 #define DDS4_S "DDS4_Scale"
1002 #define DDS4_P "DDS4_Phase"
1003 
1004 #define DAC_I_P "I_pha_adj"
1005 #define DAC_I_O "I_dac_offs"
1006 #define DAC_I_G "I_fs_adj"
1007 #define DAC_Q_P "Q_pha_adj"
1008 #define DAC_Q_O "Q_dac_offs"
1009 #define DAC_Q_G "Q_fs_adj"
1010 
1011 #define ADC_I_O "I_adc_offset_adj"
1012 #define ADC_I_G "I_adc_gain_adj"
1013 #define ADC_I_P "I_adc_phase_adj"
1014 #define ADC_Q_O "Q_adc_offset_adj"
1015 #define ADC_Q_G "Q_adc_gain_adj"
1016 #define ADC_Q_P "Q_adc_phase_adj"
1017 
combo_box_set_active_text(GtkWidget * combobox,const char * text)1018 static void combo_box_set_active_text(GtkWidget *combobox, const char* text)
1019 {
1020 	GtkTreeModel *tree = gtk_combo_box_get_model(GTK_COMBO_BOX(combobox));
1021 	gboolean valid;
1022 	GtkTreeIter iter;
1023 	gint i = 0;
1024 
1025 	valid = gtk_tree_model_get_iter_first (tree, &iter);
1026 	while (valid) {
1027 		gchar *str_data;
1028 
1029 		gtk_tree_model_get(tree, &iter, 0, &str_data, -1);
1030 		if (!strcmp(str_data, text)) {
1031 			gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), i);
1032 			break;
1033 		}
1034 
1035 		i++;
1036 		g_free (str_data);
1037 		valid = gtk_tree_model_iter_next (tree, &iter);
1038 	}
1039 }
1040 
dds_scale_set_string_value(GtkWidget * scale,const char * value)1041 static void dds_scale_set_string_value(GtkWidget *scale, const char *value)
1042 {
1043 	if (GTK_IS_COMBO_BOX_TEXT(scale)) {
1044 		combo_box_set_active_text(scale, value);
1045 	} else if (GTK_IS_SPIN_BUTTON(scale)){
1046 		gtk_entry_set_text(GTK_ENTRY(scale), value);
1047 	}
1048 }
1049 
dds_scale_get_string_value(GtkWidget * scale)1050 static gchar *dds_scale_get_string_value(GtkWidget *scale)
1051 {
1052 	if (GTK_IS_COMBO_BOX_TEXT(scale)) {
1053 		return gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(scale));
1054 	} else if (GTK_IS_SPIN_BUTTON(scale)) {
1055 		return g_strdup(gtk_entry_get_text(GTK_ENTRY(scale)));
1056 	}
1057 
1058 	return NULL;
1059 }
1060 
parse_cal_handler(int line,const char * section,const char * name,const char * value)1061 static int parse_cal_handler(int line, const char* section,
1062 		const char* name, const char* value)
1063 {
1064 
1065 	if (MATCH_SECT("SYS_SETTINGS")) {
1066 		if(MATCH_NAME(RX_F))
1067 			gtk_spin_button_set_value(GTK_SPIN_BUTTON(rx_lo_freq), atof(value));
1068 		else if (MATCH_NAME(TX_F))
1069 			gtk_spin_button_set_value(GTK_SPIN_BUTTON(tx_lo_freq), atof(value));
1070 
1071 		else if (MATCH_NAME(DDS1_F))
1072 			gtk_spin_button_set_value(GTK_SPIN_BUTTON(dds1_freq), atof(value));
1073 		else if (MATCH_NAME(DDS1_S))
1074 			dds_scale_set_string_value(dds1_scale, value);
1075 		else if (MATCH_NAME(DDS1_P))
1076 			gtk_spin_button_set_value(GTK_SPIN_BUTTON(dds1_phase), atof(value));
1077 		else if (MATCH_NAME(DDS2_F))
1078 			gtk_spin_button_set_value(GTK_SPIN_BUTTON(dds2_freq), atof(value));
1079 		else if (MATCH_NAME(DDS2_S))
1080 			dds_scale_set_string_value(dds2_scale, value);
1081 		else if (MATCH_NAME(DDS2_P))
1082 			gtk_spin_button_set_value(GTK_SPIN_BUTTON(dds2_phase), atof(value));
1083 
1084 		else if (MATCH_NAME(DDS3_F))
1085 			gtk_spin_button_set_value(GTK_SPIN_BUTTON(dds3_freq), atof(value));
1086 		else if (MATCH_NAME(DDS3_S))
1087 			dds_scale_set_string_value(dds3_scale, value);
1088 		else if (MATCH_NAME(DDS3_P))
1089 			gtk_spin_button_set_value(GTK_SPIN_BUTTON(dds3_phase), atof(value));
1090 
1091 		else if (MATCH_NAME(DDS4_F))
1092 			gtk_spin_button_set_value(GTK_SPIN_BUTTON(dds4_freq), atof(value));
1093 		else if (MATCH_NAME(DDS4_S))
1094 			dds_scale_set_string_value(dds4_scale, value);
1095 		else if (MATCH_NAME(DDS4_P))
1096 			gtk_spin_button_set_value(GTK_SPIN_BUTTON(dds4_phase), atof(value));
1097 	} else if (MATCH_SECT("DAC_SETTINGS")) {
1098 		if(MATCH_NAME(DAC_I_P))
1099 			gtk_spin_button_set_value(GTK_SPIN_BUTTON(I_dac_pha_adj), atof(value));
1100 		else if (MATCH_NAME(DAC_I_O))
1101 			gtk_spin_button_set_value(GTK_SPIN_BUTTON(I_dac_offs), atof(value));
1102 		else if (MATCH_NAME(DAC_I_G))
1103 			gtk_spin_button_set_value(GTK_SPIN_BUTTON(I_dac_fs_adj), atof(value));
1104 		else if(MATCH_NAME(DAC_Q_P))
1105 			gtk_spin_button_set_value(GTK_SPIN_BUTTON(Q_dac_pha_adj), atof(value));
1106 		else if(MATCH_NAME(DAC_Q_O))
1107 			gtk_spin_button_set_value(GTK_SPIN_BUTTON(Q_dac_offs), atof(value));
1108 		else if(MATCH_NAME(DAC_Q_G))
1109 			gtk_spin_button_set_value(GTK_SPIN_BUTTON(Q_dac_fs_adj), atof(value));
1110 	} else if (MATCH_SECT("ADC_SETTINGS")) {
1111 		if(MATCH_NAME(ADC_I_O))
1112 			gtk_spin_button_set_value(GTK_SPIN_BUTTON(I_adc_offset_adj), (gfloat)atoi(value));
1113 		else if (MATCH_NAME(ADC_Q_O))
1114 			gtk_spin_button_set_value(GTK_SPIN_BUTTON(Q_adc_offset_adj), (gfloat)atoi(value));
1115 		else if (MATCH_NAME(ADC_I_G))
1116 			gtk_spin_button_set_value(GTK_SPIN_BUTTON(I_adc_gain_adj), atof(value));
1117 		else if (MATCH_NAME(ADC_Q_G))
1118 			gtk_spin_button_set_value(GTK_SPIN_BUTTON(Q_adc_gain_adj), atof(value));
1119 		else if (MATCH_NAME(ADC_I_P))
1120 			gtk_spin_button_set_value(GTK_SPIN_BUTTON(I_adc_phase_adj), atof(value));
1121 		else if (MATCH_NAME(ADC_Q_P))
1122 			gtk_spin_button_set_value(GTK_SPIN_BUTTON(Q_adc_phase_adj), atof(value));
1123 	}
1124 	return 0;
1125 }
1126 
load_cal(char * resfile)1127 static void load_cal(char * resfile)
1128 {
1129 	foreach_in_ini(resfile, parse_cal_handler);
1130 }
1131 
cal_entry_add(struct s_cal_eeprom_v1 * eeprom)1132 static int cal_entry_add(struct s_cal_eeprom_v1 *eeprom)
1133 {
1134 	int i = eeprom->header.num_entries;
1135 
1136 	eeprom->data[i].cal_frequency_MHz = (short) gtk_spin_button_get_value (GTK_SPIN_BUTTON(rx_lo_freq));
1137 
1138 	eeprom->data[i].i_phase_adj       = (short) gtk_spin_button_get_value(GTK_SPIN_BUTTON(I_dac_pha_adj));
1139 	eeprom->data[i].q_phase_adj       = (short) gtk_spin_button_get_value(GTK_SPIN_BUTTON(Q_dac_pha_adj));
1140 	eeprom->data[i].i_dac_offset      = (short) gtk_spin_button_get_value(GTK_SPIN_BUTTON(I_dac_offs));
1141 	eeprom->data[i].q_dac_offset      = (short) gtk_spin_button_get_value(GTK_SPIN_BUTTON(Q_dac_offs));
1142 	eeprom->data[i].i_dac_fs_adj      = (unsigned short) gtk_spin_button_get_value(GTK_SPIN_BUTTON(I_dac_fs_adj));
1143 	eeprom->data[i].q_dac_fs_adj      = (unsigned short) gtk_spin_button_get_value(GTK_SPIN_BUTTON(Q_dac_fs_adj));
1144 
1145 	eeprom->data[i].i_adc_offset_adj  = (short) gtk_spin_button_get_value(GTK_SPIN_BUTTON(I_adc_offset_adj));
1146 	eeprom->data[i].q_adc_offset_adj  = (short) gtk_spin_button_get_value(GTK_SPIN_BUTTON(Q_adc_offset_adj));
1147 	eeprom->data[i].i_adc_gain_adj    = float_to_fract1_1_14(gtk_spin_button_get_value(GTK_SPIN_BUTTON(I_adc_gain_adj)));
1148 	eeprom->data[i].q_adc_gain_adj    = float_to_fract1_1_14(gtk_spin_button_get_value(GTK_SPIN_BUTTON(Q_adc_gain_adj)));
1149 	eeprom->data[i].i_adc_phase_adj   = float_to_fract1_1_14(gtk_spin_button_get_value(GTK_SPIN_BUTTON(I_adc_phase_adj)));
1150 
1151 	eeprom->header.num_entries++;
1152 
1153 	eeprom->header.adi_magic0 = ADI_MAGIC_0;
1154 	eeprom->header.adi_magic1 = ADI_MAGIC_1;
1155 	eeprom->header.version = ADI_VERSION(VERSION_SUPPORTED);
1156 	eeprom->header.temp_calibbias = temp_calibbias;
1157 
1158 	return 0;
1159 }
1160 
cal_save_to_eeprom(struct s_cal_eeprom_v1 * eeprom)1161 static int cal_save_to_eeprom(struct s_cal_eeprom_v1 *eeprom)
1162 {
1163 	FILE* file;
1164 	size_t num;
1165 
1166 	file = fopen("/sys/bus/i2c/devices/1-0054/eeprom", "w"); /* FIXME */
1167 	if (!file)
1168 		return -errno;
1169 
1170 	num = fwrite(eeprom, sizeof(*eeprom), 1, file);
1171 
1172 	fclose(file);
1173 
1174 	if (num != sizeof(*eeprom))
1175 		return -EIO;
1176 
1177 	return 0;
1178 }
1179 
save_cal(char * resfile)1180 static void save_cal(char * resfile)
1181 {
1182 	FILE* file;
1183 	time_t clock = time(NULL);
1184 
1185 	file = fopen(resfile, "w");
1186 	if (!file)
1187 		return;
1188 
1189 	gchar *dds1_scale_text = dds_scale_get_string_value(dds1_scale);
1190 	gchar *dds2_scale_text = dds_scale_get_string_value(dds2_scale);
1191 	gchar *dds3_scale_text = dds_scale_get_string_value(dds3_scale);
1192 	gchar *dds4_scale_text = dds_scale_get_string_value(dds4_scale);
1193 
1194 	fprintf(file, ";Calibration time: %s\n", ctime(&clock));
1195 
1196 	fprintf(file, "[SYS_SETTINGS]\n");
1197 	fprintf(file, "%s = %f\n", RX_F, gtk_spin_button_get_value (GTK_SPIN_BUTTON(rx_lo_freq)));
1198 	fprintf(file, "%s = %f\n", TX_F, gtk_spin_button_get_value (GTK_SPIN_BUTTON(tx_lo_freq)));
1199 	fprintf(file, "dds_mode = %i", dac_data_manager_get_dds_mode(dac_tx_manager, "cf-ad9122-core-lpc", 1));
1200 	fprintf(file, "%s = %f\n", DDS1_F, gtk_spin_button_get_value(GTK_SPIN_BUTTON(dds1_freq)));
1201 	fprintf(file, "%s = %s\n", DDS1_S, dds1_scale_text);
1202 	fprintf(file, "%s = %f\n", DDS1_P, gtk_spin_button_get_value(GTK_SPIN_BUTTON(dds1_phase)));
1203 	fprintf(file, "%s = %f\n", DDS2_F, gtk_spin_button_get_value(GTK_SPIN_BUTTON(dds2_freq)));
1204 	fprintf(file, "%s = %s\n", DDS2_S, dds2_scale_text);
1205 	fprintf(file, "%s = %f\n", DDS2_P, gtk_spin_button_get_value(GTK_SPIN_BUTTON(dds2_phase)));
1206 	fprintf(file, "%s = %f\n", DDS3_F, gtk_spin_button_get_value(GTK_SPIN_BUTTON(dds3_freq)));
1207 	fprintf(file, "%s = %s\n", DDS3_S, dds3_scale_text);
1208 	fprintf(file, "%s = %f\n", DDS3_P, gtk_spin_button_get_value(GTK_SPIN_BUTTON(dds3_phase)));
1209 	fprintf(file, "%s = %f\n", DDS4_F, gtk_spin_button_get_value(GTK_SPIN_BUTTON(dds4_freq)));
1210 	fprintf(file, "%s = %s\n", DDS4_S, dds4_scale_text);
1211 	fprintf(file, "%s = %f\n", DDS4_P, gtk_spin_button_get_value(GTK_SPIN_BUTTON(dds4_phase)));
1212 
1213 	fprintf(file, "\n[DAC_SETTINGS]\n");
1214 	fprintf(file, "%s = %f\n", DAC_I_P, gtk_spin_button_get_value(GTK_SPIN_BUTTON(I_dac_pha_adj)));
1215 	fprintf(file, "%s = %f\n", DAC_Q_P, gtk_spin_button_get_value(GTK_SPIN_BUTTON(Q_dac_pha_adj)));
1216 	fprintf(file, "%s = %f\n", DAC_I_O, gtk_spin_button_get_value(GTK_SPIN_BUTTON(I_dac_offs)));
1217 	fprintf(file, "%s = %f\n", DAC_Q_O, gtk_spin_button_get_value(GTK_SPIN_BUTTON(Q_dac_offs)));
1218 	fprintf(file, "%s = %f\n", DAC_I_G, gtk_spin_button_get_value(GTK_SPIN_BUTTON(I_dac_fs_adj)));
1219 	fprintf(file, "%s = %f\n", DAC_Q_G, gtk_spin_button_get_value(GTK_SPIN_BUTTON(Q_dac_fs_adj)));
1220 
1221 	if (0) {
1222 		 fprintf(file, "\n[TX_RESULTS]\n");
1223 	}
1224 
1225 	fprintf(file, "\n[ADC_SETTINGS]\n");
1226 	fprintf(file, "%s = %i\n", ADC_I_O, (int)gtk_spin_button_get_value(GTK_SPIN_BUTTON(I_adc_offset_adj)));
1227 	fprintf(file, "%s = %i\n", ADC_Q_O, (int)gtk_spin_button_get_value(GTK_SPIN_BUTTON(Q_adc_offset_adj)));
1228 	fprintf(file, "%s = %f #0x%x\n", ADC_I_G, gtk_spin_button_get_value(GTK_SPIN_BUTTON(I_adc_gain_adj)),
1229 				float_to_fract1_1_14(gtk_spin_button_get_value(GTK_SPIN_BUTTON(I_adc_gain_adj))));
1230 	fprintf(file, "%s = %f #0x%x\n", ADC_Q_G, gtk_spin_button_get_value(GTK_SPIN_BUTTON(Q_adc_gain_adj)),
1231 				float_to_fract1_1_14(gtk_spin_button_get_value(GTK_SPIN_BUTTON(Q_adc_gain_adj))));
1232 	fprintf(file, "%s = %f #0x%x\n", ADC_I_P, gtk_spin_button_get_value(GTK_SPIN_BUTTON(I_adc_phase_adj)),
1233 				float_to_fract1_1_14(gtk_spin_button_get_value(GTK_SPIN_BUTTON(I_adc_phase_adj))));
1234 	fprintf(file, "%s = %f #0x%x\n", ADC_Q_P, gtk_spin_button_get_value(GTK_SPIN_BUTTON(Q_adc_phase_adj)),
1235 				float_to_fract1_1_14(gtk_spin_button_get_value(GTK_SPIN_BUTTON(Q_adc_phase_adj))));
1236 
1237 	if (rx_marker && rx_marker[0].active) {
1238 		fprintf(file, "\n[RX_RESULTS]\n");
1239 		fprintf(file, "Signal = %lf dBFS @ %lf MHz from carrier\n", rx_marker[0].y, rx_marker[0].x);
1240 		fprintf(file, "Carrier = %lf dBFS\n", rx_marker[1].y);
1241 		fprintf(file, "Sideband = %lf dBFS\n", rx_marker[2].y);
1242 		fprintf(file, "Carrier Suppression = %lf dBc\n", rx_marker[1].y - rx_marker[0].y);
1243 		fprintf(file, "Sideband Suppression = %lf dBc\n", rx_marker[2].y - rx_marker[0].y);
1244 	}
1245 
1246 	/* Don't have this info yet
1247 	 * fprintf(file, "\n[SAVE]\n");
1248 	 * fprintf(file, "PlotFile = %s\n", plotfile);
1249 	 */
1250 
1251 	fclose(file);
1252 	g_free(dds1_scale_text);
1253 	g_free(dds2_scale_text);
1254 	g_free(dds3_scale_text);
1255 	g_free(dds4_scale_text);
1256 	return;
1257 
1258 }
1259 
1260 static bool calib_plot_exists;
1261 
calib_plot_destroyed_cb(OscPlot * plot)1262 static void calib_plot_destroyed_cb(OscPlot *plot)
1263 {
1264 	calib_plot_exists = false;
1265 	g_signal_emit_by_name(GTK_DIALOG(dialogs.calibrate), "response", -7);
1266 }
1267 
cal_dialog(GtkButton * btn,Dialogs * data)1268 static void cal_dialog(GtkButton *btn, Dialogs *data)
1269 {
1270 	gint ret;
1271 	char *filename = NULL;
1272 	GThread *thid_rx = NULL;
1273 
1274 	kill_thread = 0;
1275 
1276 	/* Create a fft plot to run in background while calibrating */
1277 	plot_fft_2ch = plugin_get_new_plot();
1278 	if (!plot_fft_2ch) {
1279 		printf("Could not open a new plot\n");
1280 		goto hide_calib;
1281 	}
1282 	calib_plot_exists = true;
1283 	g_signal_connect(plot_fft_2ch, "osc-destroy-event", G_CALLBACK(calib_plot_destroyed_cb), NULL);
1284 
1285 	osc_plot_set_channel_state(plot_fft_2ch, "cf-ad9643-core-lpc", 0, true);
1286 	osc_plot_set_channel_state(plot_fft_2ch, "cf-ad9643-core-lpc", 1, true);
1287 	osc_plot_set_domain(plot_fft_2ch, FFT_PLOT);
1288 	osc_plot_set_marker_type(plot_fft_2ch, MARKER_IMAGE);
1289 	osc_plot_draw_start(plot_fft_2ch);
1290 
1291 	/* Only start the thread if the LO is set */
1292 	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(rx_widgets[rx_lo_powerdown].widget)))
1293 		thid_rx = g_thread_new("Display_thread", (void *) &display_cal, NULL);
1294 
1295 	gtk_widget_show(dialogs.calibrate);
1296 
1297 	gtk_widget_hide(cal_rx);
1298 
1299 	if (!scpi_connect_functions())
1300 		gtk_widget_hide(cal_tx);
1301 
1302 	if (fmcomms1_cal_eeprom() < 0)
1303 		gtk_widget_hide(load_eeprom);
1304 
1305 	g_timeout_add(500, &display_temp, data);
1306 
1307 	do {
1308 		ret = gtk_dialog_run(GTK_DIALOG(dialogs.calibrate));
1309 		switch (ret) {
1310 			case 1: /* Load data from EEPROM */
1311 				load_cal_eeprom();
1312 				break;
1313 			case 2: /* Save data to EEPROM */
1314 				/* TODO */
1315 				printf("sorry, not implmented yet\n");
1316 				break;
1317 			case 3: /* Load data from file */
1318 				filename = get_filename(filename, true);
1319 				if (filename) {
1320 					load_cal(filename);
1321 				}
1322 				break;
1323 			case 4: /* Save data to file */
1324 				filename = get_filename(filename, false);
1325 				if (filename) {
1326 					save_cal(filename);
1327 				}
1328 				break;
1329 			case 5: /* Cal Tx side */
1330 				cal_tx_button_clicked();
1331 				break;
1332 			case 6: /* Cal Rx side */
1333 				cal_rx_button_clicked();
1334 				break;
1335 			case GTK_RESPONSE_APPLY:
1336 				cal_save_values();
1337 				break;
1338 			case GTK_RESPONSE_CLOSE:
1339 			case GTK_RESPONSE_DELETE_EVENT:
1340 				/* Closing */
1341 				break;
1342 			default:
1343 				printf("unhandled event code : %i\n", ret);
1344 				break;
1345 		}
1346 
1347 	} while (ret != GTK_RESPONSE_CLOSE &&		/* Clicked on the close button */
1348 		 ret != GTK_RESPONSE_DELETE_EVENT);	/* Clicked on the close icon */
1349 
1350 	kill_thread = 1;
1351 	/* Stop capturing in order to unlock the buffer_full mutex otherwise
1352 	 this thread will suspend the capture while waiting for the display_cal
1353 	 to die which won't die until it will get one last batch of data. */
1354 	if (calib_plot_exists)
1355 		osc_plot_draw_stop(plot_fft_2ch);
1356 	g_source_remove_by_user_data(data);
1357 
1358 	if (thid_rx)
1359 		g_thread_join(thid_rx);
1360 
1361 	if (filename)
1362 		g_free(filename);
1363 	if (calib_plot_exists) {
1364 		osc_plot_destroy(plot_fft_2ch);
1365 	}
1366 
1367 hide_calib:
1368 	gtk_widget_hide(dialogs.calibrate);
1369 }
1370 
fmcomms1_cal_eeprom_v0_convert(char * ptr)1371 static int fmcomms1_cal_eeprom_v0_convert(char *ptr)
1372 {
1373 	char tmp[FAB_SIZE_CAL_EEPROM];
1374 	struct fmcomms1_calib_data *data;
1375 	struct fmcomms1_calib_header_v1 *header =
1376 		(struct fmcomms1_calib_header_v1 *) ptr;
1377 	struct fmcomms1_calib_data_v1 *data_v1 =
1378 		(struct fmcomms1_calib_data_v1 *)(ptr + sizeof(*header));
1379 	unsigned ind = 0;
1380 
1381 	memcpy(tmp, ptr, FAB_SIZE_CAL_EEPROM);
1382 	memset(ptr, 0, FAB_SIZE_CAL_EEPROM);
1383 
1384 	data = (struct fmcomms1_calib_data *) tmp;
1385 
1386 	do {
1387 		if (data->adi_magic0 != ADI_MAGIC_0 || data->adi_magic1 != ADI_MAGIC_1) {
1388 			fprintf (stderr, "invalid magic detected\n");
1389 			return -EINVAL;
1390 		}
1391 		if (data->version != ADI_VERSION(0)) {
1392 			fprintf (stderr, "unsupported version detected %c\n", data->version);
1393 			return -EINVAL;
1394 		}
1395 
1396 		data_v1->cal_frequency_MHz = data->cal_frequency_MHz;
1397 		data_v1->i_phase_adj       = data->i_phase_adj;
1398 		data_v1->q_phase_adj       = data->q_phase_adj;
1399 		data_v1->i_dac_offset      = data->i_dac_offset;
1400 		data_v1->q_dac_offset      = data->q_dac_offset;
1401 		data_v1->i_dac_fs_adj      = data->i_dac_fs_adj;
1402 		data_v1->q_dac_fs_adj      = data->q_dac_fs_adj;
1403 		data_v1->i_adc_offset_adj  = data->i_adc_offset_adj;
1404 		data_v1->q_adc_offset_adj  = data->q_adc_offset_adj;
1405 		data_v1->i_adc_gain_adj    = float_to_fract1_1_14(fract1_15_to_float(data->i_adc_gain_adj));
1406 		data_v1->q_adc_gain_adj    = float_to_fract1_1_14(fract1_15_to_float(data->q_adc_gain_adj));
1407 		data_v1->i_adc_phase_adj   = 0.0;
1408 		data_v1++;
1409 		ind++;
1410 	} while (data++->next);
1411 
1412 	header->adi_magic0 = ADI_MAGIC_0;
1413 	header->adi_magic1 = ADI_MAGIC_1;
1414 	header->version = ADI_VERSION(VERSION_SUPPORTED);
1415 	header->num_entries = ind;
1416 	header->temp_calibbias = 0;
1417 
1418 	return 0;
1419 }
1420 
fmcomms1_cal_eeprom(void)1421 static int fmcomms1_cal_eeprom(void)
1422 {
1423 	char eprom_names[512];
1424 	FILE *efp, *fp;
1425 	int tmp;
1426 
1427 	/* flushes all open output streams */
1428 	fflush(NULL);
1429 
1430 	if (!cal_header)
1431 		cal_header = malloc(FAB_SIZE_CAL_EEPROM);
1432 
1433 	if (cal_header == NULL) {
1434 		return -ENOMEM;
1435 	}
1436 
1437 	fp = popen("find /sys -name eeprom 2>/dev/null", "r");
1438 
1439 	if(fp == NULL) {
1440 		fprintf(stderr, "can't execute find\n");
1441 		return -errno;
1442 	}
1443 
1444 	while(fgets(eprom_names, sizeof(eprom_names), fp) != NULL){
1445 		/* strip trailing new lines */
1446 		if (eprom_names[strlen(eprom_names) - 1] == '\n')
1447 			eprom_names[strlen(eprom_names) - 1] = '\0';
1448 
1449 		efp = fopen(eprom_names, "rb");
1450 		if(efp == NULL)
1451 			return -errno;
1452 
1453 		memset(cal_header, 0, FAB_SIZE_CAL_EEPROM);
1454 		tmp = fread(cal_header, FAB_SIZE_CAL_EEPROM, 1, efp);
1455 		fclose(efp);
1456 
1457 		if (!tmp || cal_header->adi_magic0 != ADI_MAGIC_0 || cal_header->adi_magic1 != ADI_MAGIC_1) {
1458 			continue;
1459 		}
1460 
1461 		if (cal_header->version != ADI_VERSION(VERSION_SUPPORTED)) {
1462 			if (cal_header->version == ADI_VERSION(0)) {
1463 				if (fmcomms1_cal_eeprom_v0_convert((char*) cal_header))
1464 					continue;
1465 			} else {
1466 				continue;
1467 			}
1468 		}
1469 
1470 		cal_data = (struct fmcomms1_calib_data_v1 *)((void *)cal_header + sizeof(*cal_header));
1471 
1472 		fprintf (stdout, "Found Calibration EEPROM @ %s\n", eprom_names);
1473 		pclose(fp);
1474 
1475 		return 0;
1476 	}
1477 
1478 	pclose(fp);
1479 
1480 	return -ENODEV;
1481 }
1482 
dac_cal_spin_helper(GtkRange * range,struct iio_channel * chn,const char * attr)1483 static void dac_cal_spin_helper(GtkRange *range,
1484 		struct iio_channel *chn, const char *attr)
1485 {
1486 	gdouble inc, val = gtk_spin_button_get_value(GTK_SPIN_BUTTON(range));
1487 	gtk_spin_button_get_increments(GTK_SPIN_BUTTON(range), &inc, NULL);
1488 
1489 	if (inc == 1.0)
1490 		iio_channel_attr_write_longlong(chn, attr, (long long) val);
1491 	else
1492 		iio_channel_attr_write_double(chn, attr, val);
1493 }
1494 
dac_cal_spin0(GtkRange * range,gpointer user_data)1495 static void dac_cal_spin0(GtkRange *range, gpointer user_data)
1496 {
1497 	dac_cal_spin_helper(range,
1498 			iio_device_find_channel(dac, "voltage0", true),
1499 			(const char *) user_data);
1500 }
1501 
dac_cal_spin1(GtkRange * range,gpointer user_data)1502 static void dac_cal_spin1(GtkRange *range, gpointer user_data)
1503 {
1504 	dac_cal_spin_helper(range,
1505 			iio_device_find_channel(dac, "voltage1", true),
1506 			(const char *) user_data);
1507 }
1508 
adc_cal_spin_helper(GtkRange * range,struct iio_channel * chn,const char * attr)1509 static void adc_cal_spin_helper(GtkRange *range,
1510 		struct iio_channel *chn, const char *attr)
1511 {
1512 	gdouble val, inc;
1513 
1514 	val = gtk_spin_button_get_value(GTK_SPIN_BUTTON(range));
1515 	gtk_spin_button_get_increments(GTK_SPIN_BUTTON(range), &inc, NULL);
1516 
1517 	if (inc == 1.0)
1518 		iio_channel_attr_write_longlong(chn, attr, (long long) val);
1519 	else
1520 		iio_channel_attr_write_double(chn, attr, val);
1521 }
1522 
adc_cal_spin0(GtkRange * range,gpointer user_data)1523 static void adc_cal_spin0(GtkRange *range, gpointer user_data)
1524 {
1525 	adc_cal_spin_helper(range,
1526 			iio_device_find_channel(adc, "voltage0", false),
1527 			(const char *) user_data);
1528 }
1529 
adc_cal_spin1(GtkRange * range,gpointer user_data)1530 static void adc_cal_spin1(GtkRange *range, gpointer user_data)
1531 {
1532 	adc_cal_spin_helper(range,
1533 			iio_device_find_channel(adc, "voltage1", false),
1534 			(const char *) user_data);
1535 }
1536 
save_widget_value(GtkWidget * widget,struct iio_widget * iio_w)1537 static void save_widget_value(GtkWidget *widget, struct iio_widget *iio_w)
1538 {
1539 	iio_w->save(iio_w);
1540 }
1541 
make_widget_update_signal_based(struct iio_widget * widgets,unsigned int num_widgets)1542 static void make_widget_update_signal_based(struct iio_widget *widgets,
1543 	unsigned int num_widgets)
1544 {
1545 	char signal_name[25];
1546 	unsigned int i;
1547 
1548 	for (i = 0; i < num_widgets; i++) {
1549 		if (GTK_IS_CHECK_BUTTON(widgets[i].widget))
1550 			sprintf(signal_name, "%s", "toggled");
1551 		else if (GTK_IS_TOGGLE_BUTTON(widgets[i].widget))
1552 			sprintf(signal_name, "%s", "toggled");
1553 		else if (GTK_IS_SPIN_BUTTON(widgets[i].widget))
1554 			sprintf(signal_name, "%s", "value-changed");
1555 		else if (GTK_IS_COMBO_BOX_TEXT(widgets[i].widget))
1556 			sprintf(signal_name, "%s", "changed");
1557 		else
1558 			printf("unhandled widget type, attribute: %s\n", widgets[i].attr_name);
1559 
1560 		if (GTK_IS_SPIN_BUTTON(widgets[i].widget) &&
1561 			widgets[i].priv_progress != NULL) {
1562 				iio_spin_button_progress_activate(&widgets[i]);
1563 		} else {
1564 			g_signal_connect(G_OBJECT(widgets[i].widget), signal_name, G_CALLBACK(save_widget_value), &widgets[i]);
1565 		}
1566 	}
1567 }
1568 
fmcomms1_handle_driver(struct osc_plugin * plugin,const char * attrib,const char * value)1569 static int fmcomms1_handle_driver(struct osc_plugin *plugin, const char *attrib, const char *value)
1570 {
1571 	if (MATCH_ATTRIB("dds_mode")) {
1572 		dac_data_manager_set_dds_mode(dac_tx_manager,
1573 				"cf-ad9122-core-lpc", 1, atoi(value));
1574 	} else if (MATCH_ATTRIB("tx_channel_0")) {
1575 		dac_data_manager_set_tx_channel_state(dac_tx_manager,
1576 				0, !!atoi(value));
1577 	} else if (MATCH_ATTRIB("tx_channel_1")) {
1578 		dac_data_manager_set_tx_channel_state(dac_tx_manager,
1579 				1, !!atoi(value));
1580 	} else if (MATCH_ATTRIB("dac_buf_filename")) {
1581 		if (dac_data_manager_get_dds_mode(dac_tx_manager,
1582 					"cf-ad9122-core-lpc", 1) == DDS_BUFFER)
1583 			dac_data_manager_set_buffer_chooser_filename(
1584 					dac_tx_manager, value);
1585 	} else if (MATCH_ATTRIB("calibrate_rx_level")) {
1586 		cal_rx_level = atof(value);
1587 	} else if (MATCH_ATTRIB("cal_clear")) {
1588 		memset(&cal_eeprom_v1, 0, sizeof(cal_eeprom_v1));
1589 	} else if (MATCH_ATTRIB("cal_add")) {
1590 		cal_entry_add(&cal_eeprom_v1);
1591 	} else if (MATCH_ATTRIB("cal_save")) {
1592 		cal_save_to_eeprom(&cal_eeprom_v1);
1593 	} else if (MATCH_ATTRIB("calibrate_rx")) {
1594 		if (atoi(value) == 1) {
1595 			GThread *thr;
1596 			unsigned int i = 0;
1597 
1598 			gtk_widget_show(dialogs.calibrate);
1599 			kill_thread = 0;
1600 			cal_rx_button_clicked();
1601 			thr = g_thread_new("Display_thread",
1602 					(void *) &display_cal, (gpointer *) 1);
1603 			while (i <= 20) {
1604 				i += kill_thread;
1605 				gtk_main_iteration();
1606 			}
1607 			g_thread_join(thr);
1608 			cal_rx_flag = false;
1609 			gtk_widget_hide(dialogs.calibrate);
1610 		}
1611 	} else if (MATCH_ATTRIB("calibrate_tx")) {
1612 		if (atoi(value) == 1) {
1613 			GThread *thr, *thid;
1614 			unsigned int i = 0;
1615 
1616 			scpi_connect_functions();
1617 			gtk_widget_show(dialogs.calibrate);
1618 			kill_thread = 0;
1619 			thid = cal_tx_button_clicked();
1620 			thr = g_thread_new("Display_thread",
1621 					(void *) &display_cal, (gpointer *) 1);
1622 			while (i <= 20) {
1623 				i += kill_thread;
1624 				gtk_main_iteration();
1625 			}
1626 			g_thread_join(thid);
1627 			g_thread_join(thr);
1628 			gtk_widget_hide(dialogs.calibrate);
1629 		}
1630 	} else if (MATCH_ATTRIB("gain_locked")) {
1631 		gtk_toggle_button_set_active(
1632 				GTK_TOGGLE_BUTTON(gain_locked), atoi(value));
1633 	} else if (MATCH_ATTRIB("SYNC_RELOAD")) {
1634 		tx_update_values();
1635 		rx_update_values();
1636 		dac_data_manager_update_iio_widgets(dac_tx_manager);
1637 	} else {
1638 		return -EINVAL;
1639 	}
1640 
1641 	return 0;
1642 }
1643 
fmcomms1_handle(struct osc_plugin * plugin,int line,const char * attrib,const char * value)1644 static int fmcomms1_handle(struct osc_plugin *plugin, int line, const char *attrib, const char *value)
1645 {
1646 	return osc_plugin_default_handle(ctx, line, attrib, value,
1647 			fmcomms1_handle_driver, NULL);
1648 }
1649 
load_profile(struct osc_plugin * plugin,const char * ini_fn)1650 static void load_profile(struct osc_plugin *plugin, const char *ini_fn)
1651 {
1652 	unsigned int i;
1653 
1654 	update_from_ini(ini_fn, THIS_DRIVER, dac, fmcomms1_sr_attribs,
1655 			ARRAY_SIZE(fmcomms1_sr_attribs));
1656 	if (adc)
1657 		update_from_ini(ini_fn, THIS_DRIVER, adc, fmcomms1_sr_attribs,
1658 				ARRAY_SIZE(fmcomms1_sr_attribs));
1659 	if (txpll)
1660 		update_from_ini(ini_fn, THIS_DRIVER, txpll,
1661 				fmcomms1_sr_attribs,
1662 				ARRAY_SIZE(fmcomms1_sr_attribs));
1663 	if (rxpll)
1664 		update_from_ini(ini_fn, THIS_DRIVER, rxpll,
1665 				fmcomms1_sr_attribs,
1666 				ARRAY_SIZE(fmcomms1_sr_attribs));
1667 	if (vga)
1668 		update_from_ini(ini_fn, THIS_DRIVER, vga,
1669 				fmcomms1_sr_attribs,
1670 				ARRAY_SIZE(fmcomms1_sr_attribs));
1671 
1672 	for (i = 0; i < ARRAY_SIZE(fmcomms1_driver_attribs); i++) {
1673 		char *value = read_token_from_ini(ini_fn, THIS_DRIVER,
1674 				fmcomms1_driver_attribs[i]);
1675 		if (value) {
1676 			fmcomms1_handle_driver(NULL,
1677 					fmcomms1_driver_attribs[i], value);
1678 			free(value);
1679 		}
1680 	}
1681 
1682 	if (can_update_widgets) {
1683 		tx_update_values();
1684 		rx_update_values();
1685 		cal_update_values();
1686 		dac_data_manager_update_iio_widgets(dac_tx_manager);
1687 	}
1688 }
1689 
fmcomms1_init(struct osc_plugin * plugin,GtkWidget * notebook,const char * ini_fn)1690 static GtkWidget * fmcomms1_init(struct osc_plugin *plugin, GtkWidget *notebook, const char *ini_fn)
1691 {
1692 	GtkBuilder *builder;
1693 	GtkWidget *fmcomms1_panel;
1694 	GtkWidget *dds_container;
1695 	const char *dac_sampling_freq_file;
1696 	struct iio_channel *ch0, *ch1;
1697 
1698 	ctx = osc_create_context();
1699 	if (!ctx)
1700 		return NULL;
1701 
1702 	dac = iio_context_find_device(ctx, "cf-ad9122-core-lpc");
1703 	adc = iio_context_find_device(ctx, "cf-ad9643-core-lpc");
1704 	txpll = iio_context_find_device(ctx, "adf4351-tx-lpc"),
1705 	rxpll = iio_context_find_device(ctx, "adf4351-rx-lpc"),
1706 	vga = iio_context_find_device(ctx, "ad8366-lpc");
1707 
1708 	dac_tx_manager = dac_data_manager_new(dac, NULL, ctx);
1709 	if (!dac_tx_manager) {
1710 		osc_destroy_context(ctx);
1711 		return NULL;
1712 	}
1713 
1714 	builder = gtk_builder_new();
1715 
1716 	if (osc_load_glade_file(builder, "fmcomms1") < 0) {
1717 		osc_destroy_context(ctx);
1718 		return NULL;
1719 	}
1720 
1721 	rx_lo_freq = GTK_WIDGET(gtk_builder_get_object(builder, "rx_lo_freq"));
1722 	tx_lo_freq = GTK_WIDGET(gtk_builder_get_object(builder, "tx_lo_freq"));
1723 
1724 	fmcomms1_panel = GTK_WIDGET(gtk_builder_get_object(builder, "fmcomms1_panel"));
1725 
1726 	load_eeprom = GTK_WIDGET(gtk_builder_get_object(builder, "LoadCal2eeprom"));
1727 
1728 	avg_I = GTK_WIDGET(gtk_builder_get_object(builder, "avg_I"));
1729 	avg_Q = GTK_WIDGET(gtk_builder_get_object(builder, "avg_Q"));
1730 	span_I = GTK_WIDGET(gtk_builder_get_object(builder, "span_I"));
1731 	span_Q = GTK_WIDGET(gtk_builder_get_object(builder, "span_Q"));
1732 	radius_IQ = GTK_WIDGET(gtk_builder_get_object(builder, "radius_IQ"));
1733 	angle_IQ = GTK_WIDGET(gtk_builder_get_object(builder, "angle_IQ"));
1734 
1735 	vga_gain0 = GTK_WIDGET(gtk_builder_get_object(builder, "adc_gain0"));
1736 	adj_gain0 = gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(vga_gain0));
1737 
1738 	vga_gain1 = GTK_WIDGET(gtk_builder_get_object(builder, "adc_gain1"));
1739 	adj_gain1 = gtk_spin_button_get_adjustment(GTK_SPIN_BUTTON(vga_gain1));
1740 
1741 	gain_locked = GTK_WIDGET(gtk_builder_get_object(builder, "gain_amp_together"));
1742 
1743 	dds_container = GTK_WIDGET(gtk_builder_get_object(builder, "dds_transmit_block"));
1744 	gtk_container_add(GTK_CONTAINER(dds_container), dac_data_manager_get_gui_container(dac_tx_manager));
1745 	gtk_widget_show_all(dds_container);
1746 
1747 	dialogs.calibrate =  GTK_WIDGET(gtk_builder_get_object(builder, "cal_dialog"));
1748 	dialogs.filechooser = GTK_WIDGET(gtk_builder_get_object(builder, "filechooser"));
1749 
1750 	cal_save = GTK_WIDGET(gtk_builder_get_object(builder, "Save"));
1751 	cal_open = GTK_WIDGET(gtk_builder_get_object(builder, "Open"));
1752 	cal_rx = GTK_WIDGET(gtk_builder_get_object(builder, "Cal_Rx"));
1753 	cal_tx = GTK_WIDGET(gtk_builder_get_object(builder, "Cal_Tx"));
1754 
1755 	I_dac_pha_adj = GTK_WIDGET(gtk_builder_get_object(builder, "dac_calibphase0"));
1756 	I_dac_offs = GTK_WIDGET(gtk_builder_get_object(builder, "dac_calibbias0"));
1757 	I_dac_fs_adj = GTK_WIDGET(gtk_builder_get_object(builder, "dac_calibscale0"));
1758 
1759 	Q_dac_pha_adj = GTK_WIDGET(gtk_builder_get_object(builder, "dac_calibphase1"));
1760 	Q_dac_offs = GTK_WIDGET(gtk_builder_get_object(builder, "dac_calibbias1"));
1761 	Q_dac_fs_adj = GTK_WIDGET(gtk_builder_get_object(builder, "dac_calibscale1"));
1762 
1763 	I_adc_offset_adj = GTK_WIDGET(gtk_builder_get_object(builder, "adc_calibbias0"));
1764 	I_adc_gain_adj = GTK_WIDGET(gtk_builder_get_object(builder, "adc_calibscale0"));
1765 	I_adc_phase_adj = GTK_WIDGET(gtk_builder_get_object(builder, "adc_calibphase0"));
1766 
1767 	Q_adc_offset_adj = GTK_WIDGET(gtk_builder_get_object(builder, "adc_calibbias1"));
1768 	Q_adc_gain_adj = GTK_WIDGET(gtk_builder_get_object(builder, "adc_calibscale1"));
1769 	Q_adc_phase_adj = GTK_WIDGET(gtk_builder_get_object(builder, "adc_calibphase1"));
1770 
1771 	ad9122_temp = GTK_WIDGET(gtk_builder_get_object(builder, "dac_temp"));
1772 
1773 	rf_out =  GTK_WIDGET(gtk_builder_get_object(builder, "RF_out"));
1774 	dac_data_clock = GTK_WIDGET(gtk_builder_get_object(builder, "dac_data_clock"));
1775 	dac_interpolation = GTK_WIDGET(gtk_builder_get_object(builder, "dac_interpolation_clock"));
1776 	dac_shift = GTK_WIDGET(gtk_builder_get_object(builder, "dac_fcenter_shift"));
1777 
1778 	if (!adc) {
1779 		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(builder, "adc_frame")));
1780 		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(builder, "calibrate_dialog")));
1781 	}
1782 	if (!vga)
1783 		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(builder, "vga_frame")));
1784 	if (!rxpll)
1785 		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(builder, "rx_lo_frame")));
1786 	if (!adc && !vga && !rxpll)
1787 		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(builder, "rx_chain_frame")));
1788 	if (!txpll)
1789 		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(builder, "tx_lo_box")));
1790 
1791 	if (ini_fn)
1792 		load_profile(NULL, ini_fn);
1793 
1794 	dds1_freq = dac_data_manager_get_widget(dac_tx_manager, dac_data_manager_dds_tone(0, TONE_1, TONE_I), WIDGET_FREQUENCY);
1795 	dds2_freq = dac_data_manager_get_widget(dac_tx_manager, dac_data_manager_dds_tone(0, TONE_2, TONE_I), WIDGET_FREQUENCY);
1796 	dds3_freq = dac_data_manager_get_widget(dac_tx_manager, dac_data_manager_dds_tone(0, TONE_1, TONE_Q), WIDGET_FREQUENCY);
1797 	dds4_freq = dac_data_manager_get_widget(dac_tx_manager, dac_data_manager_dds_tone(0, TONE_2, TONE_Q), WIDGET_FREQUENCY);
1798 
1799 	dds1_scale = dac_data_manager_get_widget(dac_tx_manager, dac_data_manager_dds_tone(0, TONE_1, TONE_I), WIDGET_SCALE);
1800 	dds2_scale = dac_data_manager_get_widget(dac_tx_manager, dac_data_manager_dds_tone(0, TONE_2, TONE_I), WIDGET_SCALE);
1801 	dds3_scale = dac_data_manager_get_widget(dac_tx_manager, dac_data_manager_dds_tone(0, TONE_1, TONE_Q), WIDGET_SCALE);
1802 	dds4_scale = dac_data_manager_get_widget(dac_tx_manager, dac_data_manager_dds_tone(0, TONE_2, TONE_Q), WIDGET_SCALE);
1803 
1804 	dds1_phase = dac_data_manager_get_widget(dac_tx_manager, dac_data_manager_dds_tone(0, TONE_1, TONE_I), WIDGET_PHASE);
1805 	dds2_phase = dac_data_manager_get_widget(dac_tx_manager, dac_data_manager_dds_tone(0, TONE_2, TONE_I), WIDGET_PHASE);
1806 	dds3_phase = dac_data_manager_get_widget(dac_tx_manager, dac_data_manager_dds_tone(0, TONE_1, TONE_Q), WIDGET_PHASE);
1807 	dds4_phase = dac_data_manager_get_widget(dac_tx_manager, dac_data_manager_dds_tone(0, TONE_2, TONE_Q), WIDGET_PHASE);
1808 
1809 	ch0 = iio_device_find_channel(dac, "altvoltage0", true);
1810 	if (!adc)
1811 		goto dac_freq_attribs;
1812 	ch1 = iio_device_find_channel(adc, "voltage0", false);
1813 	if (iio_channel_find_attr(ch1, "sampling_frequency")) {
1814 		adc_freq_device = adc;
1815 		adc_freq_channel = ch1;
1816 		adc_freq_file = "sampling_frequency";
1817 	} else {
1818 		adc_freq_device = iio_context_find_device(ctx, "ad9523-lpc");
1819 		adc_freq_channel = iio_device_find_channel(adc_freq_device, "altvoltage2", true);
1820 		adc_freq_file = "ADC_CLK_frequency";
1821 	}
1822 
1823 dac_freq_attribs:
1824 	dac_sampling_freq_file = iio_channel_find_attr(ch0,
1825 			"1A_sampling_frequency") ?: "sampling_frequency";
1826 
1827 	/* Bind the IIO device files to the GUI widgets */
1828 
1829 	/* The next free frequency related widgets - keep in this order! */
1830 	num_dac_freq = num_tx;
1831 	iio_spin_button_init_from_builder(&tx_widgets[num_tx++],
1832 			dac, ch0, dac_sampling_freq_file,
1833 			builder, "dac_data_clock", &mhz_scale);
1834 	iio_spin_button_add_progress(&tx_widgets[num_tx - 1]);
1835 	num_dac_interpolation = num_tx;
1836 	iio_combo_box_init_from_builder(&tx_widgets[num_tx++],
1837 			dac, ch0, "interpolation_frequency",
1838 			"interpolation_frequency_available",
1839 			builder, "dac_interpolation_clock", NULL);
1840 	num_dac_shift = num_tx;
1841 	iio_combo_box_init_from_builder(&tx_widgets[num_tx++],
1842 			dac, ch0, "interpolation_center_shift_frequency",
1843 			"interpolation_center_shift_frequency_available",
1844 			builder, "dac_fcenter_shift", NULL);
1845 
1846 	num_tx_pll = num_tx;
1847 
1848 	if (!txpll)
1849 		goto dac_calib_attribs;
1850 	ch0 = iio_device_find_channel(txpll, "altvoltage0", true);
1851 
1852 	iio_spin_button_int_init(&tx_widgets[num_tx++],
1853 			txpll, ch0, "frequency", tx_lo_freq, &mhz_scale);
1854 	iio_spin_button_add_progress(&tx_widgets[num_tx - 1]);
1855 
1856 	tx_lo_powerdown = num_tx;
1857 	iio_toggle_button_init_from_builder(&tx_widgets[num_tx++],
1858 			txpll, ch0, "powerdown", builder, "tx_lo_powerdown", 1);
1859 
1860 	iio_spin_button_int_init_from_builder(&tx_widgets[num_tx++],
1861 			txpll, ch0, "frequency_resolution", builder, "tx_lo_spacing", NULL);
1862 
1863 dac_calib_attribs:
1864 	/* Calibration */
1865 	ch0 = iio_device_find_channel(dac, "voltage0", true);
1866 	ch1 = iio_device_find_channel(dac, "voltage1", true);
1867 	iio_spin_button_s64_init(&cal_widgets[num_cal++],
1868 			dac, ch0, "calibbias", I_dac_offs, NULL);
1869 	iio_spin_button_s64_init(&cal_widgets[num_cal++],
1870 			dac, ch0, "calibscale", I_dac_fs_adj, NULL);
1871 	iio_spin_button_s64_init(&cal_widgets[num_cal++],
1872 			dac, ch0, "phase", I_dac_pha_adj, NULL);
1873 	iio_spin_button_s64_init(&cal_widgets[num_cal++],
1874 			dac, ch1, "calibbias", Q_dac_offs, NULL);
1875 	iio_spin_button_s64_init(&cal_widgets[num_cal++],
1876 			dac, ch1, "calibscale", Q_dac_fs_adj, NULL);
1877 	iio_spin_button_s64_init(&cal_widgets[num_cal++],
1878 			dac, ch1, "phase", Q_dac_pha_adj, NULL);
1879 
1880 	g_signal_connect(I_dac_offs, "value-changed",
1881 			G_CALLBACK(dac_cal_spin0), "calibbias");
1882 	g_signal_connect(I_dac_fs_adj, "value-changed",
1883 			G_CALLBACK(dac_cal_spin0), "calibscale");
1884 	g_signal_connect(I_dac_pha_adj, "value-changed",
1885 			G_CALLBACK(dac_cal_spin0), "phase");
1886 	g_signal_connect(Q_dac_offs, "value-changed",
1887 			G_CALLBACK(dac_cal_spin1), "calibbias");
1888 	g_signal_connect(Q_dac_fs_adj, "value-changed",
1889 			G_CALLBACK(dac_cal_spin1), "calibscale");
1890 	g_signal_connect(Q_dac_pha_adj, "value-changed",
1891 			G_CALLBACK(dac_cal_spin1), "phase");
1892 
1893 	if (!adc)
1894 		goto rx_attribs;
1895 	ch0 = iio_device_find_channel(adc, "voltage0", false);
1896 	ch1 = iio_device_find_channel(adc, "voltage1", false);
1897 	iio_spin_button_s64_init(&cal_widgets[num_cal++],
1898 			adc, ch0, "calibbias", I_adc_offset_adj, NULL);
1899 	iio_spin_button_s64_init(&cal_widgets[num_cal++],
1900 			adc, ch1, "calibbias", Q_adc_offset_adj, NULL);
1901 	iio_spin_button_init(&cal_widgets[num_cal++],
1902 			adc, ch0, "calibscale", I_adc_gain_adj, NULL);
1903 	iio_spin_button_init(&cal_widgets[num_cal++],
1904 			adc, ch1, "calibscale", Q_adc_gain_adj, NULL);
1905 	iio_spin_button_init(&cal_widgets[num_cal++],
1906 			adc, ch0, "calibphase", I_adc_phase_adj, NULL);
1907 	iio_spin_button_init(&cal_widgets[num_cal++],
1908 			adc, ch1, "calibphase", Q_adc_phase_adj, NULL);
1909 
1910 	g_signal_connect(I_adc_gain_adj  , "value-changed",
1911 			G_CALLBACK(adc_cal_spin0), "calibscale");
1912 	g_signal_connect(I_adc_offset_adj, "value-changed",
1913 			G_CALLBACK(adc_cal_spin0), "calibbias");
1914 	g_signal_connect(I_adc_phase_adj , "value-changed",
1915 			G_CALLBACK(adc_cal_spin0), "calibphase");
1916 	g_signal_connect(Q_adc_gain_adj  , "value-changed",
1917 			G_CALLBACK(adc_cal_spin1), "calibscale");
1918 	g_signal_connect(Q_adc_offset_adj, "value-changed",
1919 			G_CALLBACK(adc_cal_spin1), "calibbias");
1920 	g_signal_connect(Q_adc_phase_adj , "value-changed",
1921 			G_CALLBACK(adc_cal_spin1), "calibphase");
1922 
1923 rx_attribs:
1924 	/* Rx Widgets */
1925 	if (!rxpll)
1926 		goto adc_freq_attribs;
1927 	ch0 = iio_device_find_channel(rxpll, "altvoltage0", true);
1928 	iio_spin_button_int_init_from_builder(&rx_widgets[num_rx++],
1929 			txpll, ch0, "frequency_resolution",
1930 			builder, "rx_lo_spacing", NULL);
1931 
1932 	num_rx_pll = num_rx;
1933 	iio_spin_button_int_init(&rx_widgets[num_rx++],
1934 			txpll, ch0, "frequency", rx_lo_freq, &mhz_scale);
1935 	iio_spin_button_add_progress(&rx_widgets[num_rx - 1]);
1936 	rx_lo_powerdown = num_rx;
1937 	iio_toggle_button_init_from_builder(&rx_widgets[num_rx++],
1938 			txpll, ch0, "powerdown", builder, "rx_lo_powerdown", 1);
1939 	num_adc_freq = num_rx;
1940 
1941 adc_freq_attribs:
1942 	if (!adc)
1943 		goto vga_attribs;
1944 	iio_spin_button_int_init_from_builder(&rx_widgets[num_rx++],
1945 			adc_freq_device, adc_freq_channel, adc_freq_file,
1946 			builder, "adc_freq", &mhz_scale);
1947 	iio_spin_button_add_progress(&rx_widgets[num_rx - 1]);
1948 
1949 vga_attribs:
1950 	if (!vga)
1951 		goto calib_dialog;
1952 	ch0 = iio_device_find_channel(vga, "voltage0", true);
1953 	ch1 = iio_device_find_channel(vga, "voltage1", true);
1954 
1955 	iio_spin_button_init(&rx_widgets[num_rx++],
1956 			vga, ch0, "hardwaregain", vga_gain0, NULL);
1957 	iio_spin_button_add_progress(&rx_widgets[num_rx - 1]);
1958 	iio_spin_button_init(&rx_widgets[num_rx++],
1959 			vga, ch1, "hardwaregain", vga_gain1, NULL);
1960 	iio_spin_button_add_progress(&rx_widgets[num_rx - 1]);
1961 
1962 calib_dialog:
1963 	g_builder_connect_signal(builder, "calibrate_dialog", "clicked",
1964 		G_CALLBACK(cal_dialog), NULL);
1965 
1966 	g_signal_connect(
1967 		GTK_WIDGET(gtk_builder_get_object(builder, "gain_amp_together")),
1968 		"toggled", G_CALLBACK(gain_amp_locked_cb), NULL);
1969 
1970 	g_signal_connect_after(dac_data_clock, "changed", G_CALLBACK(dac_interpolation_update), NULL);
1971 	g_signal_connect_after(dac_interpolation, "changed", G_CALLBACK(dac_shift_update), NULL);
1972 	g_signal_connect_after(dac_shift, "changed", G_CALLBACK(rf_out_update), NULL);
1973 	g_signal_connect_after(dds1_scale, "changed", G_CALLBACK(rf_out_update), NULL);
1974 	g_signal_connect_after(dds2_scale, "changed", G_CALLBACK(rf_out_update), NULL);
1975 	g_signal_connect_after(dds3_scale, "changed", G_CALLBACK(rf_out_update), NULL);
1976 	g_signal_connect_after(dds4_scale, "changed", G_CALLBACK(rf_out_update), NULL);
1977 
1978 	make_widget_update_signal_based(rx_widgets, num_rx);
1979 	make_widget_update_signal_based(tx_widgets, num_tx);
1980 
1981 	if (txpll)
1982 		iio_spin_button_set_on_complete_function(&tx_widgets[num_tx_pll],
1983 			rf_out_update_on_complete, NULL);
1984 	if (rxpll)
1985 		iio_spin_button_set_on_complete_function(&rx_widgets[num_rx_pll],
1986 			rx_update_labels_on_complete, NULL);
1987 	if (adc)
1988 		iio_spin_button_set_on_complete_function(&rx_widgets[num_adc_freq],
1989 			rx_update_labels_on_complete, NULL);
1990 	iio_spin_button_set_on_complete_function(&tx_widgets[num_dac_freq],
1991 			tx_sample_rate_changed, NULL);
1992 
1993 	if (!rxpll)
1994 		goto update_widgets;
1995 	g_object_bind_property(GTK_TOGGLE_BUTTON(rx_widgets[rx_lo_powerdown].widget), "active", avg_I, "visible", 0);
1996 	g_object_bind_property(GTK_TOGGLE_BUTTON(rx_widgets[rx_lo_powerdown].widget), "active", avg_Q, "visible", 0);
1997 	g_object_bind_property(GTK_TOGGLE_BUTTON(rx_widgets[rx_lo_powerdown].widget), "active", span_I, "visible", 0);
1998 	g_object_bind_property(GTK_TOGGLE_BUTTON(rx_widgets[rx_lo_powerdown].widget), "active", span_Q, "visible", 0);
1999 	g_object_bind_property(GTK_TOGGLE_BUTTON(rx_widgets[rx_lo_powerdown].widget), "active", radius_IQ, "visible", 0);
2000 	g_object_bind_property(GTK_TOGGLE_BUTTON(rx_widgets[rx_lo_powerdown].widget), "active", angle_IQ, "visible", 0);
2001 
2002 update_widgets:
2003 	fmcomms1_cal_eeprom();
2004 	tx_update_values();
2005 	rx_update_values();
2006 	cal_update_values();
2007 	tx_sample_rate_changed(NULL);
2008 	dac_data_manager_update_iio_widgets(dac_tx_manager);
2009 
2010 	dac_data_manager_set_buffer_chooser_current_folder(dac_tx_manager, OSC_WAVEFORM_FILE_PATH);
2011 
2012 	can_update_widgets = true;
2013 
2014 	return fmcomms1_panel;
2015 }
2016 
save_widgets_to_ini(FILE * f)2017 static void save_widgets_to_ini(FILE *f)
2018 {
2019 	fprintf(f, "dds_mode = %i\n"
2020 			"dac_buf_filename = %s\n"
2021 			"tx_channel_0 = %i\n"
2022 			"tx_channel_1 = %i\n"
2023 			"gain_locked = %i\n",
2024 			dac_data_manager_get_dds_mode(dac_tx_manager, "cf-ad9122-core-lpc", 1),
2025 			dac_data_manager_get_buffer_chooser_filename(dac_tx_manager),
2026 			dac_data_manager_get_tx_channel_state(dac_tx_manager, 0),
2027 			dac_data_manager_get_tx_channel_state(dac_tx_manager, 1),
2028 			!!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gain_locked)));
2029 }
2030 
save_profile(const struct osc_plugin * plugin,const char * ini_fn)2031 static void save_profile(const struct osc_plugin *plugin, const char *ini_fn)
2032 {
2033 	FILE *f = fopen(ini_fn, "a");
2034 	if (f) {
2035 		/* Write the section header */
2036 		save_to_ini(f, THIS_DRIVER, dac, fmcomms1_sr_attribs,
2037 				ARRAY_SIZE(fmcomms1_sr_attribs));
2038 		if (adc)
2039 			save_to_ini(f, NULL, adc, fmcomms1_sr_attribs,
2040 					ARRAY_SIZE(fmcomms1_sr_attribs));
2041 		if (txpll)
2042 			save_to_ini(f, NULL, txpll, fmcomms1_sr_attribs,
2043 					ARRAY_SIZE(fmcomms1_sr_attribs));
2044 		if (rxpll)
2045 			save_to_ini(f, NULL, rxpll, fmcomms1_sr_attribs,
2046 					ARRAY_SIZE(fmcomms1_sr_attribs));
2047 		if (vga)
2048 			save_to_ini(f, NULL, vga, fmcomms1_sr_attribs,
2049 					ARRAY_SIZE(fmcomms1_sr_attribs));
2050 		save_widgets_to_ini(f);
2051 		fclose(f);
2052 	}
2053 }
2054 
context_destroy(struct osc_plugin * plugin,const char * ini_fn)2055 static void context_destroy(struct osc_plugin *plugin, const char *ini_fn)
2056 {
2057 	save_profile(NULL, ini_fn);
2058 
2059 	if (dac_tx_manager) {
2060 		dac_data_manager_free(dac_tx_manager);
2061 		dac_tx_manager = NULL;
2062 	}
2063 
2064 	osc_destroy_context(ctx);
2065 }
2066 
fmcomms1_identify(const struct osc_plugin * plugin)2067 static bool fmcomms1_identify(const struct osc_plugin *plugin)
2068 {
2069 	/* Use the OSC's IIO context just to detect the devices */
2070 	struct iio_context *osc_ctx = get_context_from_osc();
2071 	return !!iio_context_find_device(osc_ctx, "cf-ad9122-core-lpc");
2072 }
2073 
get_dac_dev_names(const struct osc_plugin * plugin)2074 GSList* get_dac_dev_names(const struct osc_plugin *plugin) {
2075 	GSList *list = NULL;
2076 
2077 	list = g_slist_append (list, (gpointer) "cf-ad9122-core-lpc");
2078 
2079 	return list;
2080 }
2081 
2082 struct osc_plugin plugin = {
2083 	.name = THIS_DRIVER,
2084 	.identify = fmcomms1_identify,
2085 	.init = fmcomms1_init,
2086 	.handle_item = fmcomms1_handle,
2087 	.save_profile = save_profile,
2088 	.load_profile = load_profile,
2089 	.destroy = context_destroy,
2090 	.get_dac_dev_names = get_dac_dev_names,
2091 };
2092