1 /**
2 * Copyright (C) 2012-2014 Analog Devices, Inc.
3 *
4 * Licensed under the GPL-2.
5 *
6 **/
7 #include <stdio.h>
8
9 #include <gtk/gtk.h>
10 #include <gtkdatabox.h>
11 #include <glib.h>
12 #include <gtkdatabox_grid.h>
13 #include <gtkdatabox_points.h>
14 #include <gtkdatabox_lines.h>
15 #include <math.h>
16 #include <stdint.h>
17 #include <errno.h>
18 #include <fcntl.h>
19 #include <stdbool.h>
20 #include <stdlib.h>
21 #include <sys/stat.h>
22 #include <string.h>
23
24 #include "../datatypes.h"
25 #include "../osc.h"
26 #include "../iio_widget.h"
27 #include "../osc_plugin.h"
28 #include "../config.h"
29 #include "../libini2.h"
30
31 #define THIS_DRIVER "FMComms6"
32
33 #define ARRAY_SIZE(x) (!sizeof(x) ?: sizeof(x) / sizeof((x)[0]))
34
35 #define ADC_DEVICE "axi-ad9652-lpc"
36 #define PLL_DEVICE "adf4351-rx-lpc"
37
38 static const gdouble mhz_scale = 1000000.0;
39
40 static struct iio_widget rx_widgets[5];
41 static struct iio_widget cal_widgets[20];
42 static unsigned int num_rx, num_cal;
43
44 static struct iio_context *ctx;
45 static struct iio_device *adc, *pll;
46
47 static unsigned int rx_lo;
48
49 static bool can_update_widgets;
50
51 static gint this_page;
52 static GtkWidget *fmcomms6_panel;
53 static gboolean plugin_detached;
54
55 static const char *fmcomms6_sr_attribs[] = {
56 ADC_DEVICE".in_voltage0_calibbias",
57 ADC_DEVICE".in_voltage1_calibbias",
58 ADC_DEVICE".in_voltage0_calibscale",
59 ADC_DEVICE".in_voltage1_calibscale",
60 ADC_DEVICE".in_voltage0_calibphase",
61 ADC_DEVICE".in_voltage1_calibphase",
62 PLL_DEVICE".out_altvoltage0_frequency_resolution",
63 PLL_DEVICE".out_altvoltage0_frequency",
64 PLL_DEVICE".out_altvoltage0_powerdown",
65 };
66
rx_update_values(void)67 static void rx_update_values(void)
68 {
69 iio_update_widgets(rx_widgets, num_rx);
70 rx_update_device_sampling_freq(ADC_DEVICE,
71 USE_INTERN_SAMPLING_FREQ);
72 }
73
cal_update_values(void)74 static void cal_update_values(void)
75 {
76 iio_update_widgets(cal_widgets, num_cal);
77 }
78
rx_update_labels_on_complete(void * data)79 static void rx_update_labels_on_complete(void *data)
80 {
81 rx_update_device_sampling_freq(ADC_DEVICE,
82 USE_INTERN_SAMPLING_FREQ);
83 }
84
save_widget_value(GtkWidget * widget,struct iio_widget * iio_w)85 static void save_widget_value(GtkWidget *widget, struct iio_widget *iio_w)
86 {
87 iio_w->save(iio_w);
88 }
89
make_widget_update_signal_based(struct iio_widget * widgets,unsigned int num_widgets)90 static void make_widget_update_signal_based(struct iio_widget *widgets,
91 unsigned int num_widgets)
92 {
93 char signal_name[25];
94 unsigned int i;
95
96 for (i = 0; i < num_widgets; i++) {
97 if (GTK_IS_CHECK_BUTTON(widgets[i].widget))
98 sprintf(signal_name, "%s", "toggled");
99 else if (GTK_IS_TOGGLE_BUTTON(widgets[i].widget))
100 sprintf(signal_name, "%s", "toggled");
101 else if (GTK_IS_SPIN_BUTTON(widgets[i].widget))
102 sprintf(signal_name, "%s", "value-changed");
103 else if (GTK_IS_COMBO_BOX_TEXT(widgets[i].widget))
104 sprintf(signal_name, "%s", "changed");
105 else
106 printf("unhandled widget type, attribute: %s\n", widgets[i].attr_name);
107
108 if (GTK_IS_SPIN_BUTTON(widgets[i].widget) &&
109 widgets[i].priv_progress != NULL) {
110 iio_spin_button_progress_activate(&widgets[i]);
111 } else {
112 g_signal_connect(G_OBJECT(widgets[i].widget), signal_name, G_CALLBACK(save_widget_value), &widgets[i]);
113 }
114 }
115 }
116
reload_button_clicked(GtkButton * btn,gpointer data)117 static void reload_button_clicked(GtkButton *btn, gpointer data)
118 {
119 rx_update_values();
120 cal_update_values();
121 }
122
load_profile(struct osc_plugin * plugin,const char * ini_fn)123 static void load_profile(struct osc_plugin *plugin, const char *ini_fn)
124 {
125 update_from_ini(ini_fn, THIS_DRIVER, adc, fmcomms6_sr_attribs,
126 ARRAY_SIZE(fmcomms6_sr_attribs));
127 update_from_ini(ini_fn, THIS_DRIVER, pll, fmcomms6_sr_attribs,
128 ARRAY_SIZE(fmcomms6_sr_attribs));
129
130 if (can_update_widgets)
131 reload_button_clicked(NULL, NULL);
132 }
133
fmcomms6_init(struct osc_plugin * plugin,GtkWidget * notebook,const char * ini_fn)134 static GtkWidget * fmcomms6_init(struct osc_plugin *plugin, GtkWidget *notebook, const char *ini_fn)
135 {
136 GtkBuilder *builder;
137 struct iio_channel *ch0, *ch1;
138 builder = gtk_builder_new();
139
140 ctx = osc_create_context();
141 if (!ctx)
142 return NULL;
143
144 adc = iio_context_find_device(ctx, ADC_DEVICE);
145 pll = iio_context_find_device(ctx, PLL_DEVICE);
146
147 if (ini_fn)
148 load_profile(NULL, ini_fn);
149
150 if (osc_load_glade_file(builder, "fmcomms6") < 0) {
151 osc_destroy_context(ctx);
152 return NULL;
153 }
154
155 fmcomms6_panel = GTK_WIDGET(gtk_builder_get_object(builder, "fmcomms6_panel"));
156
157 /* Bind the IIO device files to the GUI widgets */
158
159 /* Receive Chain */
160 ch0 = iio_device_find_channel(pll, "altvoltage0", true);
161 iio_spin_button_s64_init_from_builder(&rx_widgets[num_rx++],
162 pll, ch0, "frequency", builder,
163 "spin_rx_lo_freq", &mhz_scale);
164 iio_spin_button_add_progress(&rx_widgets[num_rx - 1]);
165
166 /* Calibration */
167 ch0 = iio_device_find_channel(adc, "voltage0", false);
168 ch1 = iio_device_find_channel(adc, "voltage1", false);
169 iio_spin_button_s64_init_from_builder(&cal_widgets[num_cal++],
170 adc, ch0, "calibbias", builder,
171 "adc_calibbias0", NULL);
172 iio_spin_button_init_from_builder(&cal_widgets[num_cal++],
173 adc, ch0, "calibscale", builder,
174 "adc_calibscale0", NULL);
175 iio_spin_button_init_from_builder(&cal_widgets[num_cal++],
176 adc, ch0, "calibphase", builder,
177 "adc_calibphase0", NULL);
178 iio_spin_button_s64_init_from_builder(&cal_widgets[num_cal++],
179 adc, ch1, "calibbias", builder,
180 "adc_calibbias1", NULL);
181 iio_spin_button_init_from_builder(&cal_widgets[num_cal++],
182 adc, ch1, "calibscale", builder,
183 "adc_calibscale1", NULL);
184 iio_spin_button_init_from_builder(&cal_widgets[num_cal++],
185 adc, ch1, "calibphase", builder,
186 "adc_calibphase1", NULL);
187
188 g_builder_connect_signal(builder, "fmcomms6_settings_reload", "clicked",
189 G_CALLBACK(reload_button_clicked), NULL);
190
191 make_widget_update_signal_based(rx_widgets, num_rx);
192 make_widget_update_signal_based(cal_widgets, num_cal);
193
194 iio_spin_button_set_on_complete_function(&rx_widgets[rx_lo],
195 rx_update_labels_on_complete, NULL);
196
197 rx_update_values();
198 cal_update_values();
199
200 can_update_widgets = true;
201
202 return fmcomms6_panel;
203 }
204
update_active_page(struct osc_plugin * plugin,gint active_page,gboolean is_detached)205 static void update_active_page(struct osc_plugin *plugin, gint active_page, gboolean is_detached)
206 {
207 this_page = active_page;
208 plugin_detached = is_detached;
209 }
210
fmcomms6_get_preferred_size(const struct osc_plugin * plugin,int * width,int * height)211 static void fmcomms6_get_preferred_size(const struct osc_plugin *plugin, int *width, int *height)
212 {
213 if (width)
214 *width = 640;
215 if (height)
216 *height = 480;
217 }
218
save_profile(const struct osc_plugin * plugin,const char * ini_fn)219 static void save_profile(const struct osc_plugin *plugin, const char *ini_fn)
220 {
221 FILE *f = fopen(ini_fn, "a");
222 if (f) {
223 save_to_ini(f, THIS_DRIVER, adc, fmcomms6_sr_attribs,
224 ARRAY_SIZE(fmcomms6_sr_attribs));
225 save_to_ini(f, NULL, pll, fmcomms6_sr_attribs,
226 ARRAY_SIZE(fmcomms6_sr_attribs));
227 fclose(f);
228 }
229 }
230
context_destroy(struct osc_plugin * plugin,const char * ini_fn)231 static void context_destroy(struct osc_plugin *plugin, const char *ini_fn)
232 {
233 save_profile(NULL, ini_fn);
234 osc_destroy_context(ctx);
235 }
236
fmcomms6_identify(const struct osc_plugin * plugin)237 static bool fmcomms6_identify(const struct osc_plugin *plugin)
238 {
239 /* Use the OSC's IIO context just to detect the devices */
240 struct iio_context *osc_ctx = get_context_from_osc();
241
242
243 return !!iio_context_find_device(osc_ctx, ADC_DEVICE) &&
244 !!iio_context_find_device(osc_ctx, PLL_DEVICE);
245 }
246
247 struct osc_plugin plugin = {
248 .name = THIS_DRIVER,
249 .identify = fmcomms6_identify,
250 .init = fmcomms6_init,
251 .update_active_page = update_active_page,
252 .get_preferred_size = fmcomms6_get_preferred_size,
253 .save_profile = save_profile,
254 .load_profile = load_profile,
255 .destroy = context_destroy,
256 };
257