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