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