static void calibrate (gpointer button)
{
	GtkProgressBar *calib_progress;
	double rx_phase_lpc, rx_phase_hpc, tx_phase_hpc;
	long long cal_tone, cal_freq;
	int ret, samples;

	if (!cf_ad9361_lpc || !cf_ad9361_hpc) {
		printf("could not find capture cores\n");
		ret = -ENODEV;
		auto_calibrate = -1;
		goto calibrate_fail;
	}

	if (!dev_dds_master || !dev_dds_slave) {
		printf("could not find dds cores\n");
		ret = -ENODEV;
		auto_calibrate = -1;
		goto calibrate_fail;
	}

	calib_progress = GTK_PROGRESS_BAR(gtk_builder_get_object(builder, "progress_calibration"));
	set_calibration_progress(calib_progress, 0.00);

	mcs_cb(NULL, NULL);

	/*
	 * set some logical defaults / assumptions
	 */

	ret = default_dds(get_cal_tone(), CAL_SCALE);
	if (ret < 0) {
		printf("could not set dds cores\n");
		auto_calibrate = -1;
		goto calibrate_fail;
	}

	iio_channel_attr_read_longlong(dds_out[0][0], "frequency", &cal_tone);
	iio_channel_attr_read_longlong(dds_out[0][0], "sampling_frequency", &cal_freq);

	samples = get_cal_samples(cal_tone, cal_freq);

	DBG("cal_tone %u cal_freq %u samples %d", cal_tone, cal_freq, samples);

	gdk_threads_enter();
	osc_plot_set_sample_count(plot_xcorr_4ch, samples);
	osc_plot_draw_start(plot_xcorr_4ch);
	gdk_threads_leave();


	iio_device_attr_write(dev, "in_voltage_quadrature_tracking_en", "0");
	iio_device_attr_write(dev_slave, "in_voltage_quadrature_tracking_en", "0");

	trx_phase_rotation(cf_ad9361_lpc, 0.0);
	trx_phase_rotation(cf_ad9361_hpc, 0.0);
	set_calibration_progress(calib_progress, 0.16);

	/*
	 * Calibrate RX:
	 * 1 TX1B_B (HPC) -> RX1C_B (HPC) : BIST_LOOPBACK on A
	 */
	osc_plot_xcorr_revert(plot_xcorr_4ch, true);
	__cal_switch_ports_enable_cb(1);
	rx_phase_hpc = tune_trx_phase_offset(cf_ad9361_hpc, &ret, cal_freq, cal_tone, 1.0, 0.01, trx_phase_rotation);
	if (ret < 0) {
		printf("Failed to tune phase\n");
		auto_calibrate = -1;
		goto calibrate_fail;
	}
	set_calibration_progress(calib_progress, 0.40);
	DBG("rx_phase_hpc %f", rx_phase_hpc);

	/*
	 * Calibrate RX:
	 * 3 TX1B_B (HPC) -> RX1C_A (LPC) : BIST_LOOPBACK on B
	 */

	osc_plot_xcorr_revert(plot_xcorr_4ch, false);
	trx_phase_rotation(cf_ad9361_hpc, 0.0);
	__cal_switch_ports_enable_cb(3);
	rx_phase_lpc = tune_trx_phase_offset(cf_ad9361_lpc, &ret, cal_freq, cal_tone, 1.0, 0.01, trx_phase_rotation);
	if (ret < 0) {
		printf("Failed to tune phase\n");
		auto_calibrate = -1;
		goto calibrate_fail;
	}
	set_calibration_progress(calib_progress, 0.64);
	DBG("rx_phase_lpc %f", rx_phase_lpc);

	/*
	 * Calibrate TX:
	 * 4 TX1B_A (LPC) -> RX1C_A (LPC) : BIST_LOOPBACK on B
	 */

	osc_plot_xcorr_revert(plot_xcorr_4ch, false);
	trx_phase_rotation(cf_ad9361_hpc, 0.0);
	__cal_switch_ports_enable_cb(4);
	tx_phase_hpc = tune_trx_phase_offset(dev_dds_slave, &ret, cal_freq, cal_tone, -1.0 , 0.001, trx_phase_rotation);
	if (ret < 0) {
		printf("Failed to tune phase\n");
		auto_calibrate = -1;
		goto calibrate_fail;
	}
	set_calibration_progress(calib_progress, 0.88);
	DBG("tx_phase_hpc %f", tx_phase_hpc);

	trx_phase_rotation(cf_ad9361_hpc, rx_phase_hpc);

	gtk_range_set_value(GTK_RANGE(GTK_WIDGET(gtk_builder_get_object(builder,
			"tx_phase"))), scale_phase_0_360(tx_phase_hpc));

	ret = 0;
	set_calibration_progress(calib_progress, 1.0);

calibrate_fail:

	osc_plot_xcorr_revert(plot_xcorr_4ch, false);
	__cal_switch_ports_enable_cb(0);

	iio_device_attr_write(dev, "in_voltage_quadrature_tracking_en", "1");
	iio_device_attr_write(dev_slave, "in_voltage_quadrature_tracking_en", "1");

	gdk_threads_enter();
	reload_settings();

	create_blocking_popup(GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
			"FMCOMMS5", "Calibration finished %s",
			ret ? "with Error" : "Successfully");
	auto_calibrate = 1;

	osc_plot_destroy(plot_xcorr_4ch);
	if (button)
		gtk_widget_show(GTK_WIDGET(button));
	gdk_threads_leave();

	g_thread_exit(NULL);
}
static void cal_switch_ports_enable_cb (GtkWidget *widget, gpointer data)
{
	__cal_switch_ports_enable_cb(gtk_combo_box_get_active(GTK_COMBO_BOX(widget)));
}
static void calibrate (gpointer button)
{
	GtkProgressBar *calib_progress = NULL;
	double rx_phase_lpc, rx_phase_hpc, tx_phase_hpc;
	struct iio_channel *in0, *in0_slave;
	long long cal_tone, cal_freq;
	int ret, samples;

	in0 = iio_device_find_channel(dev, "voltage0", false);
	in0_slave = iio_device_find_channel(dev_slave, "voltage0", false);
	if (!in0 || !in0_slave) {
		printf("could not find channels\n");
		ret = -ENODEV;
		goto calibrate_fail;
	}

	if (!cf_ad9361_lpc || !cf_ad9361_hpc) {
		printf("could not find capture cores\n");
		ret = -ENODEV;
		goto calibrate_fail;
	}

	if (!dev_dds_master || !dev_dds_slave) {
		printf("could not find dds cores\n");
		ret = -ENODEV;
		goto calibrate_fail;
	}

	calib_progress = GTK_PROGRESS_BAR(gtk_builder_get_object(builder, "progress_calibration"));
	set_calibration_progress(calib_progress, 0.00);

	mcs_cb(NULL, NULL);

	/*
	 * set some logical defaults / assumptions
	 */

	ret = default_dds(get_cal_tone(), CAL_SCALE);
	if (ret < 0) {
		printf("could not set dds cores\n");
		goto calibrate_fail;
	}

	iio_channel_attr_read_longlong(dds_out[0][0], "frequency", &cal_tone);
	iio_channel_attr_read_longlong(dds_out[0][0], "sampling_frequency", &cal_freq);

	samples = get_cal_samples(cal_tone, cal_freq);

	DBG("cal_tone %lld cal_freq %lld samples %d", cal_tone, cal_freq, samples);

	gdk_threads_enter();
	osc_plot_set_sample_count(plot_xcorr_4ch, samples);
	osc_plot_draw_start(plot_xcorr_4ch);
	gdk_threads_leave();

	/* Turn off quadrature tracking while the sync is going on */
	iio_channel_attr_write(in0, "quadrature_tracking_en", "0");
	iio_channel_attr_write(in0_slave, "quadrature_tracking_en", "0");

	/* reset any Tx rotation to zero */
	trx_phase_rotation(cf_ad9361_lpc, 0.0);
	trx_phase_rotation(cf_ad9361_hpc, 0.0);
	set_calibration_progress(calib_progress, 0.16);

	/*
	 * Calibrate RX:
	 * 1 TX1B_B (HPC) -> RX1C_B (HPC) : BIST_LOOPBACK on A
	 */
	osc_plot_xcorr_revert(plot_xcorr_4ch, true);
	__cal_switch_ports_enable_cb(1);
	rx_phase_hpc = tune_trx_phase_offset(cf_ad9361_hpc, &ret, cal_freq, cal_tone, 1.0, 0.01, trx_phase_rotation);
	if (ret < 0) {
		printf("Failed to tune phase : %s:%i\n", __func__, __LINE__);
		goto calibrate_fail;
	}
	set_calibration_progress(calib_progress, 0.40);
	DBG("rx_phase_hpc %f", rx_phase_hpc);

	/*
	 * Calibrate RX:
	 * 3 TX1B_B (HPC) -> RX1C_A (LPC) : BIST_LOOPBACK on B
	 */

	osc_plot_xcorr_revert(plot_xcorr_4ch, false);
	trx_phase_rotation(cf_ad9361_hpc, 0.0);
	__cal_switch_ports_enable_cb(3);
	rx_phase_lpc = tune_trx_phase_offset(cf_ad9361_lpc, &ret, cal_freq, cal_tone, 1.0, 0.01, trx_phase_rotation);
	if (ret < 0) {
		printf("Failed to tune phase : %s:%i\n", __func__, __LINE__);
		goto calibrate_fail;
	}
	set_calibration_progress(calib_progress, 0.64);

	(void) rx_phase_lpc; /* Avoid compiler warnings */
	DBG("rx_phase_lpc %f", rx_phase_lpc);

	/*
	 * Calibrate TX:
	 * 4 TX1B_A (LPC) -> RX1C_A (LPC) : BIST_LOOPBACK on B
	 */

	osc_plot_xcorr_revert(plot_xcorr_4ch, false);
	trx_phase_rotation(cf_ad9361_hpc, 0.0);
	__cal_switch_ports_enable_cb(4);
	tx_phase_hpc = tune_trx_phase_offset(dev_dds_slave, &ret, cal_freq, cal_tone, -1.0 , 0.001, trx_phase_rotation);
	if (ret < 0) {
		printf("Failed to tune phase : %s:%i\n", __func__, __LINE__);
		goto calibrate_fail;
	}
	set_calibration_progress(calib_progress, 0.88);
	DBG("tx_phase_hpc %f", tx_phase_hpc);

	trx_phase_rotation(cf_ad9361_hpc, rx_phase_hpc);

	gtk_range_set_value(GTK_RANGE(GTK_WIDGET(gtk_builder_get_object(builder,
			"tx_phase"))), scale_phase_0_360(tx_phase_hpc));

	ret = 0;
	set_calibration_progress(calib_progress, 1.0);

calibrate_fail:

	osc_plot_xcorr_revert(plot_xcorr_4ch, false);
	__cal_switch_ports_enable_cb(0);

	if (in0 && in0_slave) {
		iio_channel_attr_write(in0, "quadrature_tracking_en", "1");
		iio_channel_attr_write(in0_slave, "quadrature_tracking_en", "1");
	}

	gdk_threads_enter();
	reload_settings();

	if (ret) {
		create_blocking_popup(GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
			"FMCOMMS5", "Calibration failed");
		auto_calibrate = -1;
	} else {
		/* set completed flag for testing */
		auto_calibrate = 1;
	}

	osc_plot_destroy(plot_xcorr_4ch);
	if (button)
		gtk_widget_show(GTK_WIDGET(button));
	gdk_threads_leave();

	/* reset progress bar */
	gtk_progress_bar_set_fraction(calib_progress, 0.0);
	gtk_progress_bar_set_text(calib_progress, "Calibration Progress");

	/* Disable the channels that were enabled at the beginning of the calibration */
	struct iio_device *iio_dev;
	iio_dev = iio_context_find_device(get_context_from_osc(), CAP_DEVICE_ALT);
	if (iio_dev && cap_device_channels_enabled) {
		iio_channels_change_shadow_of_enabled(iio_dev, false);
		cap_device_channels_enabled = false;
	}

	g_thread_exit(NULL);
}
static GtkWidget * fmcomms2adv_init(GtkWidget *notebook, const char *ini_fn)
{
	GtkWidget *fmcomms2adv_panel;

	ctx = osc_create_context();
	if (!ctx)
		return NULL;

	dev = iio_context_find_device(ctx, PHY_DEVICE);
	dev_slave = iio_context_find_device(ctx, PHY_SLAVE_DEVICE);

	if (dev_slave) {
		cf_ad9361_lpc = iio_context_find_device(ctx, CAP_DEVICE_ALT);
		cf_ad9361_hpc = iio_context_find_device(ctx, CAP_SLAVE_DEVICE);

		dev_dds_master = iio_context_find_device(ctx, DDS_DEVICE);
		dev_dds_slave = iio_context_find_device(ctx, DDS_SLAVE_DEVICE);
		if (get_dds_channels())
			return NULL;
	}

	if (ini_fn) {
		load_profile(ini_fn);
		calibrate_from_ini(ini_fn);
	}

	builder = gtk_builder_new();
	nbook = GTK_NOTEBOOK(notebook);

	if (!gtk_builder_add_from_file(builder, "fmcomms2_adv.glade", NULL))
		gtk_builder_add_from_file(builder, OSC_GLADE_FILE_PATH "fmcomms2_adv.glade", NULL);

	fmcomms2adv_panel = GTK_WIDGET(gtk_builder_get_object(builder, "fmcomms2adv_panel"));

	connect_widgets(builder);

	gtk_combo_box_set_active(GTK_COMBO_BOX(
		GTK_WIDGET(gtk_builder_get_object(builder, "bist_tone"))), 0);
	gtk_combo_box_set_active(GTK_COMBO_BOX(
		GTK_WIDGET(gtk_builder_get_object(builder, "bist_tone_frequency"))), 0);
	gtk_combo_box_set_active(GTK_COMBO_BOX(
		GTK_WIDGET(gtk_builder_get_object(builder, "tone_level"))), 0);
	gtk_combo_box_set_active(GTK_COMBO_BOX(
		GTK_WIDGET(gtk_builder_get_object(builder, "bist_prbs"))), 0);
	gtk_combo_box_set_active(GTK_COMBO_BOX(
		GTK_WIDGET(gtk_builder_get_object(builder, "loopback"))), 0);

	g_builder_connect_signal(builder, "bist_tone", "changed",
		G_CALLBACK(bist_tone_cb), builder);

	g_builder_connect_signal(builder, "bist_tone_frequency", "changed",
		G_CALLBACK(bist_tone_cb), builder);

	g_builder_connect_signal(builder, "tone_level", "changed",
		G_CALLBACK(bist_tone_cb), builder);

	g_builder_connect_signal(builder, "c2q", "toggled",
		G_CALLBACK(bist_tone_cb), builder);

	g_builder_connect_signal(builder, "c1q", "toggled",
		G_CALLBACK(bist_tone_cb), builder);

	g_builder_connect_signal(builder, "c2i", "toggled",
		G_CALLBACK(bist_tone_cb), builder);

	g_builder_connect_signal(builder, "c1i", "toggled",
		G_CALLBACK(bist_tone_cb), builder);

	if (dev_slave) {
		g_builder_connect_signal(builder, "mcs_sync", "clicked",
			G_CALLBACK(mcs_cb), builder);

		gtk_combo_box_set_active(
				GTK_COMBO_BOX(gtk_builder_get_object(builder, "calibration_switch_control")), 0);
		__cal_switch_ports_enable_cb(0);

		g_builder_connect_signal(builder, "calibration_switch_control", "changed",
			G_CALLBACK(cal_switch_ports_enable_cb), builder);

		g_builder_connect_signal(builder, "tx_phase", "value-changed",
			G_CALLBACK(tx_phase_hscale_value_changed), 0);


		g_builder_connect_signal(builder, "do_fmcomms5_cal", "clicked",
				G_CALLBACK(do_calibration), gtk_builder_get_object(builder, "do_fmcomms5_cal"));

		g_builder_connect_signal(builder, "undo_fmcomms5_cal", "clicked",
				G_CALLBACK(undo_calibration), NULL);

		g_object_bind_property(gtk_builder_get_object(builder, "silent_calibration"), "active",
		gtk_builder_get_object(builder, "progress_calibration"), "visible", G_BINDING_DEFAULT);
	} else {
		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(builder, "mcs_sync")));
		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(builder, "frame_fmcomms5")));
	}

	g_builder_connect_signal(builder, "notebook1", "switch-page",
		G_CALLBACK(change_page_cb),
		GTK_WIDGET(gtk_builder_get_object(builder, "initialize")));

	return fmcomms2adv_panel;
}
static int fmcomms2adv_init(GtkWidget *notebook)
{
	GtkWidget *fmcomms2adv_panel;
	int i;

	builder = gtk_builder_new();
	nbook = GTK_NOTEBOOK(notebook);

	if (!gtk_builder_add_from_file(builder, "fmcomms2_adv.glade", NULL))
		gtk_builder_add_from_file(builder, OSC_GLADE_FILE_PATH "fmcomms2_adv.glade", NULL);

	fmcomms2adv_panel = GTK_WIDGET(gtk_builder_get_object(builder, "fmcomms2adv_panel"));

	for (i = 0; i < ARRAY_SIZE(attrs); i++)
		connect_widget(builder, &attrs[i]);

	gtk_combo_box_set_active(GTK_COMBO_BOX(
		GTK_WIDGET(gtk_builder_get_object(builder, "bist_tone"))), 0);
	gtk_combo_box_set_active(GTK_COMBO_BOX(
		GTK_WIDGET(gtk_builder_get_object(builder, "bist_tone_frequency"))), 0);
	gtk_combo_box_set_active(GTK_COMBO_BOX(
		GTK_WIDGET(gtk_builder_get_object(builder, "tone_level"))), 0);
	gtk_combo_box_set_active(GTK_COMBO_BOX(
		GTK_WIDGET(gtk_builder_get_object(builder, "bist_prbs"))), 0);
	gtk_combo_box_set_active(GTK_COMBO_BOX(
		GTK_WIDGET(gtk_builder_get_object(builder, "loopback"))), 0);

	g_builder_connect_signal(builder, "bist_tone", "changed",
		G_CALLBACK(bist_tone_cb), builder);

	g_builder_connect_signal(builder, "bist_tone_frequency", "changed",
		G_CALLBACK(bist_tone_cb), builder);

	g_builder_connect_signal(builder, "tone_level", "changed",
		G_CALLBACK(bist_tone_cb), builder);

	g_builder_connect_signal(builder, "c2q", "toggled",
		G_CALLBACK(bist_tone_cb), builder);

	g_builder_connect_signal(builder, "c1q", "toggled",
		G_CALLBACK(bist_tone_cb), builder);

	g_builder_connect_signal(builder, "c2i", "toggled",
		G_CALLBACK(bist_tone_cb), builder);

	g_builder_connect_signal(builder, "c1i", "toggled",
		G_CALLBACK(bist_tone_cb), builder);


	if (dev_slave) {
		g_builder_connect_signal(builder, "mcs_sync", "clicked",
			G_CALLBACK(mcs_cb), builder);

		gtk_combo_box_set_active(
				GTK_COMBO_BOX(gtk_builder_get_object(builder, "calibration_switch_control")), 0);
		__cal_switch_ports_enable_cb(0);

		g_builder_connect_signal(builder, "calibration_switch_control", "changed",
			G_CALLBACK(cal_switch_ports_enable_cb), builder);

		g_builder_connect_signal(builder, "tx_phase", "value-changed",
			G_CALLBACK(tx_phase_hscale_value_changed), 0);


		g_builder_connect_signal(builder, "do_fmcomms5_cal", "clicked",
				G_CALLBACK(do_calibration), gtk_builder_get_object(builder, "do_fmcomms5_cal"));

		g_builder_connect_signal(builder, "undo_fmcomms5_cal", "clicked",
				G_CALLBACK(undo_calibration), NULL);
	} else {
		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(builder, "mcs_sync")));
		gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object(builder, "frame_fmcomms5")));
	}

	this_page = gtk_notebook_append_page(GTK_NOTEBOOK(notebook), fmcomms2adv_panel, NULL);
	gtk_notebook_set_tab_label_text(GTK_NOTEBOOK(notebook), fmcomms2adv_panel, "FMComms2 Advanced");

	g_builder_connect_signal(builder, "notebook1", "switch-page",
		G_CALLBACK(change_page_cb),
		GTK_WIDGET(gtk_builder_get_object(builder, "initialize")));

	return 0;
}