changeset 196:87dae6d62a61

New AD9912 client code to communicate with improved server code
author Daniele Nicolodi <daniele.nicolodi@obspm.fr>
date Mon, 31 Mar 2014 17:03:32 +0200
parents d841dfb30b0b
children 79db2c87d1b0
files DDS_Fox.h FXAnalyse.c ad9912.c ad9912.h
diffstat 4 files changed, 440 insertions(+), 163 deletions(-) [+]
line wrap: on
line diff
--- a/DDS_Fox.h	Mon Mar 31 17:03:32 2014 +0200
+++ b/DDS_Fox.h	Mon Mar 31 17:03:32 2014 +0200
@@ -1,11 +1,13 @@
-typedef struct {
+struct ad9956 {
 	char ip[255];
 	int Port;
 	double Clock;
 	double SweepRate;
 	double Delta_T;
 	unsigned int Profil;
-} DDSParameter;
+};
+
+typedef struct ad9956 DDSParameter;
 
 void DDSFox_Init(DDSParameter *Param, char *ip, int port);
 void DDSFox_Reset(DDSParameter * Param, double frequency);
--- a/FXAnalyse.c	Mon Mar 31 17:03:32 2014 +0200
+++ b/FXAnalyse.c	Mon Mar 31 17:03:32 2014 +0200
@@ -11,7 +11,7 @@
 #include "FXAnalyse.h" 
 #include "Plot.h"
 #include "Allan.h"
-#include "DDS4xAD9912.h"
+#include "ad9912.h"
 #include "DDS_Fox.h" 
 #include "muParserDLL.h"
 #include "utils.h"
@@ -28,6 +28,7 @@
 #define SR_WAVELENGTH  698.4460    // nm
 #define HG_WAVELENGTH 1062.4000    // nm
 
+
 // select which data provider to use
 #ifdef NDEBUG
 #define DataProvider KKDataProvider
@@ -161,10 +162,26 @@
 };
 
 
-// dedrift DDS
-DDSParameter DDS1xAD9956;
-// 4xAD9912 DDS box
-DDS4xAD9912_Data DDS4xAD9912;
+struct ad9956 ad9956;
+struct ad9912 ad9912;
+
+
+static inline int ad9912_set_frequency_w(struct ad9912 *d, unsigned c, double f)
+{
+	int r = ad9912_set_frequency(d, c, f);
+	if (r)
+		logmessage(ERROR, "ad9912 set frequency channel=%d error=%d", c, -r);
+	return r;
+}
+
+
+static inline int ad9912_ramp_frequency_w(struct ad9912 *d, unsigned c, double f, double s)
+{
+	int r = ad9912_ramp_frequency(d, c, f, s);
+	if (r)
+		logmessage(ERROR, "ad9912 ramp frequency channel=%d error=%d", c, -r);
+	return r;
+}
 
 
 enum {
@@ -192,9 +209,9 @@
 
 double f0_DDS1 = 110000000.0, f0_DDS2, f0_DDS3, df_DDS3;
 
-double SlopeTime1=40.0, DeltaT_1=20.0, delta_f_lock_1=500.0;
-double SlopeTime2=40.0, DeltaT_2=20.0, delta_f_lock_2=500.0;
-double SlopeTime3=40.0, DeltaT_3=20.0, delta_f_lock_3=500.0;
+double SlopeTime1 = 40.0, DeltaT_1 = 40.0, delta_f_lock_1 = 500e3;
+double SlopeTime2 = 40.0, DeltaT_2 = 40.0, delta_f_lock_2 = 500e3;
+double SlopeTime3 = 40.0, DeltaT_3 = 40.0, delta_f_lock_3 = 500e3;
 
 double t1, t2, t3;
 double f_rep_slope, f_beat_slope;
@@ -284,12 +301,12 @@
 		.data = __data,											\
 		.nchan = __nchan,										\
 		.control = __control,									\
-		.write = __write										\
+		.write = __write,										\
 	}
 
 struct datafile datafiles[] = {
      DATAFILE("Raw", event.data, 4, PANEL_SAVE_RAW, TRUE),
-     DATAFILE("DDS", DDS4xAD9912.frequency, 4, PANEL_SAVE_DDS, FALSE),
+     DATAFILE("DDS", ad9912.frequency, 4, PANEL_SAVE_DDS, FALSE),
      DATAFILE("Lo", &Math2, 1, PANEL_SAVE_LO, FALSE),
      DATAFILE("Hg", &Math3, 1, PANEL_SAVE_HG, FALSE),
      DATAFILE("Sr", &Math4, 1, PANEL_SAVE_SR, FALSE),
@@ -354,10 +371,10 @@
 	mupDefineVar(parser, "Ch2", &Ch2);
 	mupDefineVar(parser, "Ch3", &Ch3);
 	mupDefineVar(parser, "Ch4", &Ch4);
-	mupDefineVar(parser, "DDS1", &(DDS4xAD9912.frequency[0]));
-	mupDefineVar(parser, "DDS2", &(DDS4xAD9912.frequency[1]));
-	mupDefineVar(parser, "DDS3", &(DDS4xAD9912.frequency[2]));
-	mupDefineVar(parser, "DDS4", &(DDS4xAD9912.frequency[3]));
+	mupDefineVar(parser, "DDS1", &(ad9912.frequency[0]));
+	mupDefineVar(parser, "DDS2", &(ad9912.frequency[1]));
+	mupDefineVar(parser, "DDS3", &(ad9912.frequency[2]));
+	mupDefineVar(parser, "DDS4", &(ad9912.frequency[3]));
 	mupDefineVar(parser, "N1", &N1);
 	mupDefineVar(parser, "N2", &N2);
 	mupDefineVar(parser, "N3", &N3);
@@ -421,7 +438,7 @@
 		SetCtrlAttribute(MainPanel, PANEL_STARTBUTTON, ATTR_DIMMED, TRUE);
 	}
 	
-	// AD9956 configuration parameters
+	// ad9956 configuration parameters
 	rv = Ini_GetStringIntoBuffer(configuration, "AD9956", "host", host, sizeof(host));
 	if (! rv)
 		return -1;
@@ -433,9 +450,9 @@
 		return -1;
 	
 	// dedrift DDS
-	DDSFox_Init(&DDS1xAD9956, host, port);
+	DDSFox_Init(&ad9956, host, port);
 	
-	// AD9912 configuration parameters
+	// ad9912 configuration parameters
 	rv = Ini_GetStringIntoBuffer(configuration, "AD9912", "host", host, sizeof(host));
 	if (! rv)
 		return -1;
@@ -443,17 +460,16 @@
 	if (! rv)
 		return -1;
 	
-	// initialize 4x AD9912 DDS box
-	DDS4xAD9912_Init(&DDS4xAD9912, host, clock);
-	DDS4xAD9912_Reset(&DDS4xAD9912);
+	// initialize AD9912 DDS box
+	ad9912_init(&ad9912, host, clock);
 	GetCtrlVal(MainPanel, PANEL_DDS1, &frequency);
-	DDS4xAD9912_SetFrequency(&DDS4xAD9912, 1, frequency);
+	ad9912_set_frequency_w(&ad9912, 0, frequency);
 	GetCtrlVal(MainPanel, PANEL_DDS2, &frequency);
-	DDS4xAD9912_SetFrequency(&DDS4xAD9912, 2, frequency);
+	ad9912_set_frequency_w(&ad9912, 1, frequency);
 	GetCtrlVal(MainPanel, PANEL_DDS3, &frequency);
-	DDS4xAD9912_SetFrequency(&DDS4xAD9912, 3, frequency);
+	ad9912_set_frequency_w(&ad9912, 2, frequency);
 	GetCtrlVal(MainPanel, PANEL_DDS4, &frequency);
-	DDS4xAD9912_SetFrequency(&DDS4xAD9912, 4, frequency);
+	ad9912_set_frequency_w(&ad9912, 3, frequency);
 	
 	// dispose configuration
 	Ini_Dispose(configuration);
@@ -461,9 +477,9 @@
 	// Sr data logger
 	sr_datalogger_init(&datalogger);
 	
-	GetCtrlVal(MainPanel, PANEL_N1CHOICE, &N1);
-	GetCtrlVal(MainPanel, PANEL_N2CHOICE, &N2);
-	GetCtrlVal(MainPanel, PANEL_N3CHOICE, &N3);
+	GetCtrlVal(MainPanel, PANEL_N1, &N1);
+	GetCtrlVal(MainPanel, PANEL_N2, &N2);
+	GetCtrlVal(MainPanel, PANEL_N3, &N3);
 
 	MathParser1 = muParserNew();
 	GetCtrlVal(MainPanel, PANEL_MATHSTRING1, expr);
@@ -696,11 +712,11 @@
 						// initialization step
 						
 						// set DDS1 to nominal frequency
-						DDS4xAD9912_SetFrequency(&DDS4xAD9912, 1, f0_DDS1);
-						SetCtrlVal(MainPanel, PANEL_DDS1, DDS4xAD9912.frequency[0]);
+						ad9912_set_frequency_w(&ad9912, 0, f0_DDS1);
+						SetCtrlVal(MainPanel, PANEL_DDS1, ad9912.frequency[0]);
 						
 						// record current DDS frequencies
-						f0_DDS2 = DDS4xAD9912_GetFrequency(&DDS4xAD9912, 2);
+						f0_DDS2 = ad9912.frequency[1];
 						
 						t1 = utc;
 						t2 = t3 = 0.0;
@@ -721,8 +737,8 @@
 							f_rep_slope = stat_math1.slope;
 							
 							// frep positive step
-							DDS4xAD9912_RampFrequency(&DDS4xAD9912, 1, f0_DDS1 + delta_f_lock_1, FREP_STEP_SIZE);
-							SetCtrlVal(MainPanel, PANEL_DDS1, DDS4xAD9912.frequency[0]);
+							ad9912_ramp_frequency_w(&ad9912, 0, f0_DDS1 + delta_f_lock_1, FREP_STEP_SIZE);
+							SetCtrlVal(MainPanel, PANEL_DDS1, ad9912.frequency[0]);
 							
 							// allow counter to settle
 							settling = 3;
@@ -739,9 +755,9 @@
 						if (settling-- > 0)
 							break;
 						
-						double fDDS2 = DDS4xAD9912_GetFrequency(&DDS4xAD9912, 2);
-						DDS4xAD9912_SetFrequency(&DDS4xAD9912, 2, fDDS2 + 275000 - Ch4);
-						SetCtrlVal(MainPanel, PANEL_DDS2, DDS4xAD9912.frequency[1]);
+						double fDDS2 = ad9912.frequency[1];
+						ad9912_set_frequency_w(&ad9912, 1, fDDS2 + 275000 - Ch4);
+						SetCtrlVal(MainPanel, PANEL_DDS2, ad9912.frequency[1]);
 						
 						// allow counter to settle
 						settling = 3;
@@ -767,8 +783,8 @@
 							nobs = 0;
 							
 							// frep negative step
-							DDS4xAD9912_RampFrequency(&DDS4xAD9912, 1, f0_DDS1 - delta_f_lock_1, FREP_STEP_SIZE);
-							SetCtrlVal(MainPanel, PANEL_DDS1, DDS4xAD9912.frequency[0]);
+							ad9912_ramp_frequency_w(&ad9912, 0, f0_DDS1 - delta_f_lock_1, FREP_STEP_SIZE);
+							SetCtrlVal(MainPanel, PANEL_DDS1, ad9912.frequency[0]);
 							
 							// allow counter to settle
 							settling = 3;
@@ -800,10 +816,10 @@
 							SetCtrlVal(CalcNPanel, CALCN_N, N_measured);
 							
 							// back to nominal frep
-							DDS4xAD9912_RampFrequency(&DDS4xAD9912, 1, f0_DDS1, FREP_STEP_SIZE);
-							DDS4xAD9912_SetFrequency(&DDS4xAD9912, 2, f0_DDS2);
-							SetCtrlVal(MainPanel, PANEL_DDS1, DDS4xAD9912.frequency[0]);
-							SetCtrlVal(MainPanel, PANEL_DDS2, DDS4xAD9912.frequency[1]);
+							ad9912_ramp_frequency_w(&ad9912, 0, f0_DDS1, FREP_STEP_SIZE);
+							ad9912_set_frequency_w(&ad9912, 1, f0_DDS2);
+							SetCtrlVal(MainPanel, PANEL_DDS1, ad9912.frequency[0]);
+							SetCtrlVal(MainPanel, PANEL_DDS2, ad9912.frequency[1]);
 							
 							// done
 							Measuring_1 = N_MEASUREMENT_NONE;
@@ -821,12 +837,12 @@
 						// initialization step
 						
 						// set DDS1 to nominal frequency
-						DDS4xAD9912_SetFrequency(&DDS4xAD9912, 1, f0_DDS1);
-						SetCtrlVal(MainPanel, PANEL_DDS1, DDS4xAD9912.frequency[0]);
+						ad9912_set_frequency_w(&ad9912, 0, f0_DDS1);
+						SetCtrlVal(MainPanel, PANEL_DDS1, ad9912.frequency[0]);
 						
 						// record current DDS frequencies
-						f0_DDS2 = DDS4xAD9912_GetFrequency(&DDS4xAD9912, 2);
-						f0_DDS3 = DDS4xAD9912_GetFrequency(&DDS4xAD9912, 3);
+						f0_DDS2 = ad9912.frequency[1];
+						f0_DDS3 = ad9912.frequency[2];
 						
 						t1 = utc;
 						t2 = t3 = 0.0;
@@ -852,14 +868,14 @@
 							
 							// frep positive step
 							double fDDS1 = f0_DDS1 + delta_f_lock_2;
-							DDS4xAD9912_RampFrequency(&DDS4xAD9912, 1, fDDS1, FREP_STEP_SIZE);
-							SetCtrlVal(MainPanel, PANEL_DDS1, DDS4xAD9912.frequency[0]);
+							ad9912_ramp_frequency_w(&ad9912, 0, fDDS1, FREP_STEP_SIZE);
+							SetCtrlVal(MainPanel, PANEL_DDS1, ad9912.frequency[0]);
 							
 							// adjust DDS3 to keep beatnote within the bandpass filter. prediction
 							double fDDS3 = f0_DDS3 + Sign1 * Sign2 * N2/N1 * Ndiv * delta_f_lock_2;
-							df_DDS3 = fDDS3 - DDS4xAD9912_GetFrequency(&DDS4xAD9912, 3);
-							DDS4xAD9912_SetFrequency(&DDS4xAD9912, 3, fDDS3);
-							SetCtrlVal(MainPanel, PANEL_DDS3, DDS4xAD9912.frequency[2]);
+							df_DDS3 = fDDS3 - ad9912.frequency[2];
+							ad9912_set_frequency_w(&ad9912, 2, fDDS3);
+							SetCtrlVal(MainPanel, PANEL_DDS3, ad9912.frequency[2]);
 						
 							// allow counter to settle
 							settling = 3;
@@ -876,14 +892,14 @@
 						if (settling-- > 0)
 							break;
 						
-						double fDDS2 = DDS4xAD9912_GetFrequency(&DDS4xAD9912, 2) + 275000 - Ch4;
-						DDS4xAD9912_SetFrequency(&DDS4xAD9912, 2, fDDS2);
-						SetCtrlVal(MainPanel, PANEL_DDS2, DDS4xAD9912.frequency[1]);
+						double fDDS2 = ad9912.frequency[1] + 275000 - Ch4;
+						ad9912_set_frequency_w(&ad9912, 1, fDDS2);
+						SetCtrlVal(MainPanel, PANEL_DDS2, ad9912.frequency[1]);
 						
-						double fDDS3 = DDS4xAD9912_GetFrequency(&DDS4xAD9912, 3) + 10000 - Ch2;
+						double fDDS3 = ad9912.frequency[2] + 10000 - Ch2;
 						df_DDS3 = df_DDS3 + 10000 - Ch2;
-						DDS4xAD9912_SetFrequency(&DDS4xAD9912, 3, fDDS3);
-						SetCtrlVal(MainPanel, PANEL_DDS3, DDS4xAD9912.frequency[2]);
+						ad9912_set_frequency_w(&ad9912, 2, fDDS3);
+						SetCtrlVal(MainPanel, PANEL_DDS3, ad9912.frequency[2]);
 
 						// allow counter to settle
 						settling = 3;
@@ -912,14 +928,14 @@
 
 							// negative frequency step
 							double fDDS1 = f0_DDS1 - delta_f_lock_2;
-							DDS4xAD9912_RampFrequency(&DDS4xAD9912, 1, fDDS1, FREP_STEP_SIZE);
-							SetCtrlVal(MainPanel, PANEL_DDS1, DDS4xAD9912.frequency[0]);
+							ad9912_ramp_frequency_w(&ad9912, 0, fDDS1, FREP_STEP_SIZE);
+							SetCtrlVal(MainPanel, PANEL_DDS1, ad9912.frequency[0]);
 							
 							// adjust DDS3 to keep beatnote within the bandpass filter. prediction
 							double fDDS3 = f0_DDS3 - Sign1 * Sign2 * N2/N1 * Ndiv * delta_f_lock_2;
-							df_DDS3 = fDDS3 - DDS4xAD9912_GetFrequency(&DDS4xAD9912, 3);
-							DDS4xAD9912_SetFrequency(&DDS4xAD9912, 3, fDDS3);
-							SetCtrlVal(MainPanel, PANEL_DDS3, DDS4xAD9912.frequency[2]);
+							df_DDS3 = fDDS3 - ad9912.frequency[2];
+							ad9912_set_frequency_w(&ad9912, 2, fDDS3);
+							SetCtrlVal(MainPanel, PANEL_DDS3, ad9912.frequency[2]);
 
 							// allow counter to settle
 							settling = 3;
@@ -949,21 +965,22 @@
 
 							// compute N2
 							double delta_f_rep_m = f_rep_minus - f_rep_plus;
-							double delta_f_rep = Sign1 * Ndiv * 2.0 * delta_f_lock_3 / N1;
+							double delta_f_rep = Sign1 * Ndiv * 2.0 * delta_f_lock_2 / N1;
+							double delta = delta_f_rep_m - delta_f_rep;
 							
-							logmsg("delta frep: measured=%e expected=%e difference=%e",
-								delta_f_rep_m, delta_f_rep, delta_f_rep_m - delta_f_rep);
+							logmsg("delta frep: measured=%e expected=%e difference=%e rel=%e",
+								delta_f_rep_m, delta_f_rep, delta, delta / delta_f_rep);
 							
 							N_measured = -Sign2 * (df_DDS3 + f_beat_minus - f_beat_plus) / delta_f_rep;
 							SetCtrlVal(CalcNPanel, CALCN_N, N_measured);
 							
 							// back to nominal frequency
-							DDS4xAD9912_RampFrequency(&DDS4xAD9912, 1, f0_DDS1, FREP_STEP_SIZE);
-							DDS4xAD9912_SetFrequency(&DDS4xAD9912, 2, f0_DDS2);
-							DDS4xAD9912_SetFrequency(&DDS4xAD9912, 3, f0_DDS3);
-							SetCtrlVal(MainPanel, PANEL_DDS1, DDS4xAD9912.frequency[0]);
-							SetCtrlVal(MainPanel, PANEL_DDS2, DDS4xAD9912.frequency[1]);
-							SetCtrlVal(MainPanel, PANEL_DDS3, DDS4xAD9912.frequency[2]);
+							ad9912_ramp_frequency_w(&ad9912, 0, f0_DDS1, FREP_STEP_SIZE);
+							ad9912_set_frequency_w(&ad9912, 1, f0_DDS2);
+							ad9912_set_frequency_w(&ad9912, 2, f0_DDS3);
+							SetCtrlVal(MainPanel, PANEL_DDS1, ad9912.frequency[0]);
+							SetCtrlVal(MainPanel, PANEL_DDS2, ad9912.frequency[1]);
+							SetCtrlVal(MainPanel, PANEL_DDS3, ad9912.frequency[2]);
 							
 							// done
 							Measuring_2 = N_MEASUREMENT_NONE;
@@ -981,12 +998,12 @@
 						// init
 						
 						// set DDS1 to nominal frequency
-						DDS4xAD9912_SetFrequency(&DDS4xAD9912, 1, f0_DDS1);
-						SetCtrlVal(MainPanel, PANEL_DDS1, DDS4xAD9912.frequency[0]);
+						ad9912_set_frequency_w(&ad9912, 0, f0_DDS1);
+						SetCtrlVal(MainPanel, PANEL_DDS1, ad9912.frequency[0]);
 						
 						// record current DDS frequencies
-						f0_DDS2 = DDS4xAD9912_GetFrequency(&DDS4xAD9912, 2);
-						f0_DDS3 = DDS4xAD9912_GetFrequency(&DDS4xAD9912, 3);
+						f0_DDS2 = ad9912.frequency[1];
+						f0_DDS3 = ad9912.frequency[2];
 						
 						t1 = utc;
 						t2 = t3 = 0.0;
@@ -1018,13 +1035,13 @@
 							logmsg("f_beat_slope=%e Hz/s", f_rep_slope);
 							
 							// frep positive step
-							DDS4xAD9912_RampFrequency(&DDS4xAD9912, 1, f0_DDS1 + delta_f_lock_3, FREP_STEP_SIZE);
-							SetCtrlVal(MainPanel, PANEL_DDS1, DDS4xAD9912.frequency[0]);
+							ad9912_ramp_frequency_w(&ad9912, 0, f0_DDS1 + delta_f_lock_3, FREP_STEP_SIZE);
+							SetCtrlVal(MainPanel, PANEL_DDS1, ad9912.frequency[0]);
 							
 							// adjust DDS3 to keep beatnote within the bandpass filter
 							double fDDS3 = f0_DDS3 + Sign1 * Sign3 * N3/N1 * Ndiv * delta_f_lock_3;
-							DDS4xAD9912_SetFrequency(&DDS4xAD9912, 3, fDDS3);
-							SetCtrlVal(MainPanel, PANEL_DDS3, DDS4xAD9912.frequency[2]);
+							ad9912_set_frequency_w(&ad9912, 2, fDDS3);
+							SetCtrlVal(MainPanel, PANEL_DDS3, ad9912.frequency[2]);
 							
 							// allow counter to settle
 							settling = 3;
@@ -1042,9 +1059,9 @@
 							break;
 						
 						// adjust DDS frequency to keep 55 MHz tracker oscillator locked
-						double fDDS2 = DDS4xAD9912_GetFrequency(&DDS4xAD9912, 2) + 275000 - Ch4;
-						DDS4xAD9912_SetFrequency(&DDS4xAD9912, 2, fDDS2);
-						SetCtrlVal(MainPanel, PANEL_DDS2, DDS4xAD9912.frequency[1]);
+						double fDDS2 = ad9912.frequency[1] + 275000 - Ch4;
+						ad9912_set_frequency_w(&ad9912, 1, fDDS2);
+						SetCtrlVal(MainPanel, PANEL_DDS2, ad9912.frequency[1]);
 						
 						// allow counter to settle
 						settling = 3;
@@ -1072,13 +1089,13 @@
 							nobs = 0;
 							
 							// frep negative step
-							DDS4xAD9912_RampFrequency(&DDS4xAD9912, 1, f0_DDS1 - delta_f_lock_3, FREP_STEP_SIZE);
-							SetCtrlVal(MainPanel, PANEL_DDS1, DDS4xAD9912.frequency[0]);
+							ad9912_ramp_frequency_w(&ad9912, 0, f0_DDS1 - delta_f_lock_3, FREP_STEP_SIZE);
+							SetCtrlVal(MainPanel, PANEL_DDS1, ad9912.frequency[0]);
 
 							// adjust DDS3 to keep beatnote within the bandpass filter
 							double fDDS3 = f0_DDS3 - Sign1 * Sign3 * N3/N1 * Ndiv * delta_f_lock_3;
-							DDS4xAD9912_SetFrequency(&DDS4xAD9912, 3, fDDS3);
-							SetCtrlVal(MainPanel, PANEL_DDS3, DDS4xAD9912.frequency[2]);
+							ad9912_set_frequency_w(&ad9912, 2, fDDS3);
+							SetCtrlVal(MainPanel, PANEL_DDS3, ad9912.frequency[2]);
 							
 							// allow counter to settle
 							settling = 3;
@@ -1109,12 +1126,10 @@
 							// check delta frep
 							double delta_f_rep_m = f_rep_plus - f_rep_minus;
 							double delta_f_rep = Sign1 * Ndiv * 2.0 * delta_f_lock_3 / N1;
+							double delta = delta_f_rep_m - delta_f_rep;
 							
-							logmsg("delta frep: measured=%e expected=%e difference=%e",
-								delta_f_rep_m, delta_f_rep, delta_f_rep_m - delta_f_rep);
-							
-							logmsg("f_beat_minus=%e", f_beat_minus);
-							logmsg("f_beat_plus =%e", f_beat_plus);
+							logmsg("delta frep: measured=%e expected=%e difference=%e rel=%e",
+								delta_f_rep_m, delta_f_rep, delta, delta / delta_f_rep);
 							
 							// compute N3
 							double delta_f_beat = f_beat_plus - f_beat_minus + 2.0 * Sign1 * Sign3 * N3/N1 * Ndiv * delta_f_lock_3;
@@ -1129,12 +1144,12 @@
 							logmsg("measured N3=%.3f", N_measured);
 							
 							// back to nominal frep
-							DDS4xAD9912_RampFrequency(&DDS4xAD9912, 1, f0_DDS1, FREP_STEP_SIZE);
-							DDS4xAD9912_SetFrequency(&DDS4xAD9912, 2, f0_DDS2);
-							DDS4xAD9912_SetFrequency(&DDS4xAD9912, 3, f0_DDS3);
-							SetCtrlVal(MainPanel, PANEL_DDS1, DDS4xAD9912.frequency[0]);
-							SetCtrlVal(MainPanel, PANEL_DDS2, DDS4xAD9912.frequency[1]);
-							SetCtrlVal(MainPanel, PANEL_DDS3, DDS4xAD9912.frequency[2]);
+							ad9912_ramp_frequency_w(&ad9912, 0, f0_DDS1, FREP_STEP_SIZE);
+							ad9912_set_frequency_w(&ad9912, 1, f0_DDS2);
+							ad9912_set_frequency_w(&ad9912, 2, f0_DDS3);
+							SetCtrlVal(MainPanel, PANEL_DDS1, ad9912.frequency[0]);
+							SetCtrlVal(MainPanel, PANEL_DDS2, ad9912.frequency[1]);
+							SetCtrlVal(MainPanel, PANEL_DDS3, ad9912.frequency[2]);
 							
 							// done
 							Measuring_3 = N_MEASUREMENT_NONE;
@@ -1150,7 +1165,7 @@
 							Sign1 = -1.0;
 						else
 							Sign1 = +1.0;
-						DDS4xAD9912_SetFrequency(&DDS4xAD9912, 1, Frequency1);
+						ad9912_set_frequency_w(&ad9912, 0, Frequency1);
 						Getsign1 = FALSE;
 						SetCtrlVal(MainPanel, PANEL_SIGN1, Sign1);
 					}
@@ -1168,7 +1183,7 @@
 							else 
 								Sign2 = +1.0;
 						}
-						DDS4xAD9912_SetFrequency(&DDS4xAD9912, 1, Frequency2);
+						ad9912_set_frequency_w(&ad9912, 0, Frequency2);
 						Getsign2 = FALSE;
 						SetCtrlVal(MainPanel, PANEL_SIGN2, Sign2);
 					}
@@ -1179,7 +1194,7 @@
 							Sign3 = -1.0;
 						else
 							Sign3 = +1.0;
-						DDS4xAD9912_SetFrequency(&DDS4xAD9912, 4, Frequency3);
+						ad9912_set_frequency_w(&ad9912, 3, Frequency3);
 						Getsign3 = FALSE;
 						SetCtrlVal(MainPanel, PANEL_SIGN3, Sign3);
 					}
@@ -1204,11 +1219,11 @@
 						
 					if (! dedrift.keep_slope) {
 						dedrift.applied = 0.0;
-						DDSFox_SetSweepRate(&DDS1xAD9956, dedrift.applied);
+						DDSFox_SetSweepRate(&ad9956, dedrift.applied);
 						SetCtrlVal(MainPanel, PANEL_SLOPE_APPLIED, dedrift.applied);
 					}
 					if (! dedrift.keep_freq) {
-						DDSFox_Set(&DDS1xAD9956, dedrift.freq0, dedrift.applied);
+						DDSFox_Set(&ad9956, dedrift.freq0, dedrift.applied);
 					}
 					
 					stat_zero(&freq);
@@ -1237,9 +1252,9 @@
 						SetCtrlVal(MainPanel, PANEL_SLOPE_APPLIED, dedrift.applied);
 						
 						if (dedrift.doubleslope)
-							DDSFox_SetSweepRate(&DDS1xAD9956, dedrift.applied * 2.0);
+							DDSFox_SetSweepRate(&ad9956, dedrift.applied * 2.0);
 						else
-							DDSFox_SetSweepRate(&DDS1xAD9956, dedrift.applied);
+							DDSFox_SetSweepRate(&ad9956, dedrift.applied);
 						
 						logmsg("dedrift update: adjustment=%+3e slope=%+3e", freq.slope, dedrift.applied);
 						
@@ -1259,31 +1274,31 @@
 		
 						if (recenter.lo) {
 							// adjust DDS2 frequency to keep Ch4 reading at 275 kHz
-							double freq = DDS4xAD9912_GetFrequency(&DDS4xAD9912, 2);
+							double freq = ad9912.frequency[1];
 							double adj = 275000.0 - rollmean_ch4.mean;
 							freq = freq + adj;
-							DDS4xAD9912_SetFrequency(&DDS4xAD9912, 2, freq);
-							SetCtrlVal(MainPanel, PANEL_DDS2, DDS4xAD9912.frequency[1]);
+							ad9912_set_frequency_w(&ad9912, 1, freq);
+							SetCtrlVal(MainPanel, PANEL_DDS2, ad9912.frequency[1]);
 							logmsg("recenter ch4 to 275 kHz: DDS2 adjustment=%+3e", adj);
 						}
 					
 						if (recenter.hg) {
 							// adjust DDS3 frequency to keep Ch2 reading at 10 kHz
-							double freq = DDS4xAD9912_GetFrequency(&DDS4xAD9912, 3);
+							double freq = ad9912.frequency[2];
 							double adj = 10000 - rollmean_ch2.mean;
 							freq = freq + adj;
-							DDS4xAD9912_SetFrequency(&DDS4xAD9912, 3, freq);
-							SetCtrlVal(MainPanel, PANEL_DDS3, DDS4xAD9912.frequency[2]);
+							ad9912_set_frequency_w(&ad9912, 2, freq);
+							SetCtrlVal(MainPanel, PANEL_DDS3, ad9912.frequency[2]);
 							logmsg("recenter Hg beatnote (ch2) to 10 kHz: DDS3 adjustment=%+3e", adj);
 						}
 					
 						if (recenter.sr) {
 							// adjust DDS3 frequency to keep Ch3 reading at 10 kHz
-							double freq = DDS4xAD9912_GetFrequency(&DDS4xAD9912, 3);
+							double freq = ad9912.frequency[2];
 							double adj = 10000 - rollmean_ch3.mean;
 							freq = freq + adj;
-							DDS4xAD9912_SetFrequency(&DDS4xAD9912, 3, freq);
-							SetCtrlVal(MainPanel, PANEL_DDS3, DDS4xAD9912.frequency[2]);
+							ad9912_set_frequency_w(&ad9912, 2, freq);
+							SetCtrlVal(MainPanel, PANEL_DDS3, ad9912.frequency[2]);
 							logmsg("recenter Sr beatnote (ch3) to 10 kHz: DDS3 adjustment=%+3e", adj);
 						}
 					
@@ -1363,20 +1378,20 @@
 			GetCtrlVal(MainPanel, control, &frequency);
 			switch (control) {
 				case PANEL_DDS1:
-					DDS4xAD9912_SetFrequency(&DDS4xAD9912, 1, frequency);
-					SetCtrlVal(MainPanel, PANEL_DDS1, DDS4xAD9912.frequency[0]);
+					ad9912_set_frequency_w(&ad9912, 0, frequency);
+					SetCtrlVal(MainPanel, PANEL_DDS1, ad9912.frequency[0]);
 					break;
 				case PANEL_DDS2:
-					DDS4xAD9912_SetFrequency(&DDS4xAD9912, 2, frequency);
-					SetCtrlVal(MainPanel, PANEL_DDS2, DDS4xAD9912.frequency[1]);
+					ad9912_set_frequency_w(&ad9912, 1, frequency);
+					SetCtrlVal(MainPanel, PANEL_DDS2, ad9912.frequency[1]);
 					break;
 				case PANEL_DDS3:
-					DDS4xAD9912_SetFrequency(&DDS4xAD9912, 3, frequency);
-					SetCtrlVal(MainPanel, PANEL_DDS3, DDS4xAD9912.frequency[2]);
+					ad9912_set_frequency_w(&ad9912, 2, frequency);
+					SetCtrlVal(MainPanel, PANEL_DDS3, ad9912.frequency[2]);
 					break;
 				case PANEL_DDS4:
-					DDS4xAD9912_SetFrequency(&DDS4xAD9912, 4, frequency);
-					SetCtrlVal(MainPanel, PANEL_DDS4, DDS4xAD9912.frequency[3]);
+					ad9912_set_frequency_w(&ad9912, 3, frequency);
+					SetCtrlVal(MainPanel, PANEL_DDS4, ad9912.frequency[3]);
 					break;
 			}
 			break;
@@ -1455,13 +1470,13 @@
 		case EVENT_COMMIT:
 			switch (control)
 			{
-				case PANEL_N1CHOICE:
+				case PANEL_N1:
 					GetCtrlVal(panel, control, &N1);
 					break;
-				case PANEL_N2CHOICE:
+				case PANEL_N2:
 					GetCtrlVal(panel, control, &N2);
 					break;
-				case PANEL_N3CHOICE:
+				case PANEL_N3:
 					GetCtrlVal(panel, control, &N3);
 					break;
 			}
@@ -1481,15 +1496,15 @@
 			switch (measure) {
 				case LO:
 					N1 = round(N_measured);
-					SetCtrlVal(MainPanel, PANEL_N1CHOICE, N1);
+					SetCtrlVal(MainPanel, PANEL_N1, N1);
 					break;
 				case HG:
 					N2 = round(N_measured);
-					SetCtrlVal(MainPanel, PANEL_N2CHOICE, N2);
+					SetCtrlVal(MainPanel, PANEL_N2, N2);
 					break;
 				case SR:
 					N3 = round(N_measured);
-					SetCtrlVal(MainPanel, PANEL_N3CHOICE, N3);
+					SetCtrlVal(MainPanel, PANEL_N3, N3);
 					break;
 			} 
 			break;
@@ -1508,7 +1523,7 @@
 				case PANEL_N1CALCULUS:
 					GetPanelAttribute(CalcNPanel, ATTR_VISIBLE, &visible);
 					if (! visible) {
-						SetPanelAttribute(panel, ATTR_CALLBACK_DATA, LO);
+						SetPanelAttribute(CalcNPanel, ATTR_CALLBACK_DATA, LO);
 						SetPanelAttribute(CalcNPanel, ATTR_TITLE, "Measure N_Lo");
 						SetCtrlVal(CalcNPanel, CALCN_INTEGRATIONTIME, DeltaT_1);
 						SetCtrlVal(CalcNPanel, CALCN_SLOPETIME, SlopeTime1);
@@ -1520,7 +1535,7 @@
 				case PANEL_N2CALCULUS:
 					GetPanelAttribute(CalcNPanel, ATTR_VISIBLE, &visible);
 					if (! visible) {
-						SetPanelAttribute(panel, ATTR_CALLBACK_DATA, HG);
+						SetPanelAttribute(CalcNPanel, ATTR_CALLBACK_DATA, HG);
 						SetPanelAttribute(CalcNPanel, ATTR_TITLE, "Measure N_Hg");
 						SetCtrlVal(CalcNPanel, CALCN_INTEGRATIONTIME, DeltaT_2);
 						SetCtrlVal(CalcNPanel, CALCN_SLOPETIME, SlopeTime2);
@@ -1532,7 +1547,7 @@
 				case PANEL_N3CALCULUS:
 					GetPanelAttribute(CalcNPanel, ATTR_VISIBLE, &visible);
 					if (! visible) {
-						SetPanelAttribute(panel, ATTR_CALLBACK_DATA, SR);
+						SetPanelAttribute(CalcNPanel, ATTR_CALLBACK_DATA, SR);
 						SetPanelAttribute(CalcNPanel, ATTR_TITLE, "Measure N_Sr");
 						SetCtrlVal(CalcNPanel, CALCN_INTEGRATIONTIME, DeltaT_3);
 						SetCtrlVal(CalcNPanel, CALCN_SLOPETIME, SlopeTime3);
@@ -1598,28 +1613,28 @@
 			switch (measuring) {
 				case LO:
 					Measuring_1 = FALSE;
-					DDS4xAD9912_RampFrequency(&DDS4xAD9912, 1, f0_DDS1, FREP_STEP_SIZE);
-					DDS4xAD9912_SetFrequency(&DDS4xAD9912, 2, f0_DDS2);
+					ad9912_ramp_frequency_w(&ad9912, 0, f0_DDS1, FREP_STEP_SIZE);
+					ad9912_set_frequency_w(&ad9912, 1, f0_DDS2);
 					break;
 				case HG:
 					Measuring_2 = FALSE;
-					DDS4xAD9912_RampFrequency(&DDS4xAD9912, 1, f0_DDS1, FREP_STEP_SIZE);
-					DDS4xAD9912_SetFrequency(&DDS4xAD9912, 2, f0_DDS2);
-					DDS4xAD9912_SetFrequency(&DDS4xAD9912, 3, f0_DDS3);
+					ad9912_ramp_frequency_w(&ad9912, 0, f0_DDS1, FREP_STEP_SIZE);
+					ad9912_set_frequency_w(&ad9912, 1, f0_DDS2);
+					ad9912_set_frequency_w(&ad9912, 2, f0_DDS3);
 					break;
 				case SR:
 					Measuring_3 = FALSE;
-					DDS4xAD9912_RampFrequency(&DDS4xAD9912, 1, f0_DDS1, FREP_STEP_SIZE);
-					DDS4xAD9912_SetFrequency(&DDS4xAD9912, 2, f0_DDS2);
-					DDS4xAD9912_SetFrequency(&DDS4xAD9912, 3, f0_DDS3);
+					ad9912_ramp_frequency_w(&ad9912, 0, f0_DDS1, FREP_STEP_SIZE);
+					ad9912_set_frequency_w(&ad9912, 1, f0_DDS2);
+					ad9912_set_frequency_w(&ad9912, 2, f0_DDS3);
 					break;
 			}
 			
 			// update DDS frequencies display
-			SetCtrlVal(MainPanel, PANEL_DDS1, DDS4xAD9912.frequency[0]);
-			SetCtrlVal(MainPanel, PANEL_DDS2, DDS4xAD9912.frequency[1]);
-			SetCtrlVal(MainPanel, PANEL_DDS3, DDS4xAD9912.frequency[2]);
-			SetCtrlVal(MainPanel, PANEL_DDS4, DDS4xAD9912.frequency[3]);
+			SetCtrlVal(MainPanel, PANEL_DDS1, ad9912.frequency[0]);
+			SetCtrlVal(MainPanel, PANEL_DDS2, ad9912.frequency[1]);
+			SetCtrlVal(MainPanel, PANEL_DDS3, ad9912.frequency[2]);
+			SetCtrlVal(MainPanel, PANEL_DDS4, ad9912.frequency[3]);
 			
 			break;
 	}
@@ -1639,7 +1654,7 @@
 					Frepbefore1 = Math1;
 					GetCtrlVal(MainPanel, PANEL_DDS1, &Frequency1) ;
 					SetCtrlVal(MainPanel, PANEL_DDS1, Frequency1+Frequencystep1) ;  
-					DDS4xAD9912_SetFrequency(&DDS4xAD9912, 1, Frequency1+Frequencystep1);
+					ad9912_set_frequency_w(&ad9912, 0, Frequency1+Frequencystep1);
 					Getsign1 = TRUE;
 					break;
 				case PANEL_FINDSIGN2:
@@ -1648,7 +1663,7 @@
 					Ch2before = Ch2;
 					GetCtrlVal(MainPanel, PANEL_DDS1, &Frequency2) ;
 					SetCtrlVal(MainPanel, PANEL_DDS1, Frequency2+Frequencystep2) ;
-					DDS4xAD9912_SetFrequency(&DDS4xAD9912, 1, Frequency2+Frequencystep2);
+					ad9912_set_frequency_w(&ad9912, 0, Frequency2+Frequencystep2);
 					Getsign2 = TRUE;
 					break;
 				case PANEL_FINDSIGN3:
@@ -1656,7 +1671,7 @@
 					Frepbefore3 = Math1;
 					GetCtrlVal(MainPanel, PANEL_DDS4, &Frequency3) ;
 					SetCtrlVal(MainPanel, PANEL_DDS4, Frequency3+Frequencystep3) ; 
-					DDS4xAD9912_SetFrequency(&DDS4xAD9912, 4, Frequency3+Frequencystep3);
+					ad9912_set_frequency_w(&ad9912, 3, Frequency3+Frequencystep3);
 					Getsign3 = TRUE;
 					break;
 			}
@@ -1669,21 +1684,20 @@
 		 void *callbackData, int eventData1, int eventData2)
 {
 	double frequency;
-	
 	switch (event)
 	{
 		case EVENT_COMMIT:
 			switch (control)
 			{
 				case PANEL_FIND275K2:
-					frequency = DDS4xAD9912_GetFrequency(&DDS4xAD9912, 2) + 275000 - Ch4;
-					DDS4xAD9912_SetFrequency(&DDS4xAD9912, 2, frequency);
-					SetCtrlVal(MainPanel, PANEL_DDS2, DDS4xAD9912.frequency[1]);
+					frequency = ad9912.frequency[1] + 275000 - Ch4;
+					ad9912_set_frequency_w(&ad9912, 1, frequency);
+					SetCtrlVal(MainPanel, PANEL_DDS2, ad9912.frequency[1]);
 					break;
 				case PANEL_FIND10K3:
-					frequency = DDS4xAD9912_GetFrequency(&DDS4xAD9912, 3) + 10000 - Ch2;
-					DDS4xAD9912_SetFrequency(&DDS4xAD9912, 3, frequency);
-					SetCtrlVal(MainPanel, PANEL_DDS3, DDS4xAD9912.frequency[2]);
+					frequency = ad9912.frequency[2] + 10000 - Ch2;
+					ad9912_set_frequency_w(&ad9912, 2, frequency);
+					SetCtrlVal(MainPanel, PANEL_DDS3, ad9912.frequency[2]);
 					break;
 			}
 			break;
@@ -1699,8 +1713,8 @@
 		case EVENT_COMMIT:
 			GetCtrlVal(MainPanel, PANEL_CHANGENDIV, &Ndiv);
 			f0_DDS1 = 880000000.0 / Ndiv;
-			DDS4xAD9912_SetFrequency(&DDS4xAD9912, 1, f0_DDS1);
-			SetCtrlVal(MainPanel, PANEL_DDS1, DDS4xAD9912.frequency[0]);
+			ad9912_set_frequency_w(&ad9912, 0, f0_DDS1);
+			SetCtrlVal(MainPanel, PANEL_DDS1, ad9912.frequency[0]);
 			break;
 	}
 	return 0;
@@ -1720,11 +1734,11 @@
 			} else {
 				if (! dedrift.keep_slope) {
 					dedrift.applied = 0.0;
-					DDSFox_SetSweepRate(&DDS1xAD9956, dedrift.applied);
+					DDSFox_SetSweepRate(&ad9956, dedrift.applied);
 					SetCtrlVal(MainPanel, PANEL_SLOPE_APPLIED, dedrift.applied);
 				}
 				if (! dedrift.keep_freq) {
-					DDSFox_Set(&DDS1xAD9956, dedrift.freq0, dedrift.applied);
+					DDSFox_Set(&ad9956, dedrift.freq0, dedrift.applied);
 				}
 				stat_zero(&freq);
 				SetCtrlVal(panel, PANEL_SLOPE_MEASURED, freq.slope);
@@ -1743,7 +1757,7 @@
 		case EVENT_COMMIT:
 			dedrift.applied = 0.0; 
 			SetCtrlVal(panel, PANEL_SLOPE_APPLIED, dedrift.applied);
-			DDSFox_Set(&DDS1xAD9956, dedrift.freq0, dedrift.applied);
+			DDSFox_Set(&ad9956, dedrift.freq0, dedrift.applied);
 			logmsg("dedrift reset");
 			break;
 	}
@@ -1885,11 +1899,11 @@
 			switch (estimate) {
 				case HG:
 					GetCtrlVal(panel, ESTIMATEN_N, &N2);
-					SetCtrlVal(MainPanel, PANEL_N3CHOICE, N2);
+					SetCtrlVal(MainPanel, PANEL_N2, N2);
 					break;
 				case SR:
 					GetCtrlVal(panel, ESTIMATEN_N, &N3);
-					SetCtrlVal(MainPanel, PANEL_N3CHOICE, N3);
+					SetCtrlVal(MainPanel, PANEL_N3, N3);
 					break;
 			}
 			HidePanel(panel);
@@ -1922,7 +1936,7 @@
 	{
 		case EVENT_COMMIT:
 			GetCtrlVal(panel, control, &dedrift.applied);
-			DDSFox_SetSweepRate(&DDS1xAD9956, dedrift.applied);
+			DDSFox_SetSweepRate(&ad9956, dedrift.applied);
 			break;
 	}
 	return 0;
@@ -1952,7 +1966,7 @@
 			dedrift.applied = 0.0;
 			SetCtrlVal(panel, PANEL_SLOPE_APPLIED, dedrift.applied);
 			// reset DDS
-			DDSFox_Reset(&DDS1xAD9956, dedrift.freq0);
+			DDSFox_Reset(&ad9956, dedrift.freq0);
 			break;
 	}
 	return 0;
@@ -2078,7 +2092,7 @@
 	{
 		case EVENT_COMMIT:
 			GetCtrlVal(panel, control, &dedrift.freq0);
-			DDSFox_Set(&DDS1xAD9956, dedrift.freq0, dedrift.applied);
+			DDSFox_Set(&ad9956, dedrift.freq0, dedrift.applied);
 			break;
 	}
 	return 0;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ad9912.c	Mon Mar 31 17:03:32 2014 +0200
@@ -0,0 +1,242 @@
+#ifdef _CVI_
+#include <ansi_c.h>
+#include <toolbox.h>
+#include <tcpsupp.h>
+#define TIMEOUT 0
+#define send(fd, buf, len, f)  ClientTCPWrite(fd, buf, len, TIMEOUT)
+#define recv(fd, buf, len, f)  ClientTCPRead(fd, buf, len, TIMEOUT)
+#define usleep(t)  Delay(t / 1000000.0)
+#define strdup(s)  StrDup(s)
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <math.h>
+#include <stdarg.h>
+#endif
+
+#include "ad9912.h"
+
+#define streq(x, y) (strcmp((x), (y)) == 0)
+
+typedef unsigned long long uint64;
+
+
+static inline uint64 ftw(double clock, double freq)
+{
+	uint64 ftw = freq * ((double)(1 << 48) / clock);
+	ftw = ftw & ~1ULL;
+	return ftw;
+}
+
+
+static inline double freq(double clock, uint64 ftw)
+{
+	double freq = (double)ftw * (clock / (double)(1ULL << 48));
+	return freq;
+}
+
+
+static inline int strtouint64(const char *str, uint64 *v)
+{
+	char *end;
+	*v = strtoull(str, &end, 0);
+	if (*end != '\0')
+		return -1;
+	return 0;
+}
+
+
+static int msend(int fd, char *buffer, int n)
+{
+	int r;
+
+	buffer[n++] = '\r';
+	buffer[n++] = '\n';
+
+	r = send(fd, buffer, n, 0);
+	if (r < 0)
+		return r;     
+
+	return 0;
+}
+
+
+static int mrecv(int fd, char *buffer, int len)
+{
+	int n;
+
+	n = recv(fd, buffer, len, 0);
+	if (n < 0)
+		return n;
+
+	if ((buffer[--n] != '\n') || (buffer[--n] != '\r'))
+		return -1;
+
+	buffer[n] = '\0';
+
+	return n;
+}
+
+
+static int command(int fd, char *frmt, ...)
+{
+	int r, n;
+	char buffer[1024];
+	va_list v;
+
+	va_start(v, frmt);
+	n = vsnprintf(buffer, sizeof(buffer) - 2, frmt, v);
+	va_end(v);
+
+	r = msend(fd, buffer, n);
+	if (r < 0)
+		return r;
+
+	r = mrecv(fd, buffer, sizeof(buffer));
+	if (r < 0)
+		return r;
+
+	if (! streq(buffer, "OK"))
+		return -1;
+
+	return 0;
+}
+
+
+int ad9912_init(struct ad9912 *d, const char *hostname, double clock)
+{
+	int n, r;
+	char buffer[256];
+
+	d->hostname = StrDup(hostname);
+	d->port = 1234;
+	d->clock = clock;
+
+#ifdef _CVI_
+	unsigned int sock;
+	r = ConnectToTCPServer(&sock, d->port, d->hostname, NULL, NULL, TIMEOUT);
+	if (r < 0)
+		return -1;
+#else
+	int sock;
+	struct sockaddr_in addr;
+	struct hostent* host;	
+	
+	host = gethostbyname(hostname);
+	if (host == NULL)
+		return -1;
+  
+	sock = socket(AF_INET, SOCK_STREAM, 0);
+	if (sock < 0)
+		return -2;
+
+	addr.sin_family = host->h_addrtype;
+	memcpy(&addr.sin_addr.s_addr, host->h_addr_list[0], host->h_length);
+	addr.sin_port = htons(port);
+
+	r = connect(sock, (struct sockaddr*)&addr, sizeof(addr));
+	if (r < 0)
+		return -3;
+#endif
+
+	d->fd = sock;
+
+	/* check compatibility */
+	n = snprintf(buffer, sizeof(buffer), "REVISION");
+	r = msend(d->fd, buffer, n);
+	if (r < 0)
+		return r;
+	r = mrecv(d->fd, buffer, sizeof(buffer));
+	if (r < 0)
+		return r;
+	if (atoi(buffer) != REVISION)
+		return -1;
+
+	return 0;
+}
+
+
+int ad9912_set_frequency(struct ad9912 *d, unsigned channel, double f)
+{
+	int r;
+	uint64 value = ftw(d->clock, f);
+
+	r = command(d->fd, "SET CH%d:FTW0 0x%llX", channel, f);
+	if (r < 0)
+		return r;
+
+	d->frequency[channel] = freq(d->clock, value);
+     
+	return 0;
+}
+
+
+int ad9912_get_frequency(struct ad9912 *d, unsigned channel, double *f)
+{
+	int r, n;
+	uint64 value;
+	char buffer[256];
+
+	n = snprintf(buffer, sizeof(buffer), "GET CH%d:FTW0", channel);
+
+	r = msend(d->fd, buffer, n);
+	if (r < 0)
+		return r;
+
+	r = mrecv(d->fd, buffer, sizeof(buffer));
+	if (r < 0)
+		return r;
+
+	r = strtouint64(buffer, &value);
+	if (r < 0)
+		return r;
+
+	d->frequency[channel] = freq(d->clock, value);
+	if (f)
+		*f = d->frequency[channel];
+
+	return 0;
+}
+
+
+/**
+ * Ramp DDS frequency from @f1 to @f2 in steps @fstep with 0.01
+ * seconds delay after each step.
+ */
+int ad9912_ramp_frequency2(struct ad9912 *d, unsigned channel, double f1, double f2, double fstep)
+{
+	const int delay = 10000;
+	
+	/* f2 > f1 */
+	while ((f2 - f1) > fstep) {
+		f1 += fstep;
+		ad9912_set_frequency(d, channel, f1);
+		usleep(delay);
+	}
+	
+	/* f2 < f1 */
+	while ((f1 - f2) > fstep) {
+		f1 -= fstep;
+		ad9912_set_frequency(d, channel, f1);
+		usleep(delay);
+	}
+	
+	/* final adjustment */
+	ad9912_set_frequency(d, channel, f2);
+	return 0;
+}
+
+
+int ad9912_ramp_frequency(struct ad9912 *d, unsigned channel, double f, double fstep)
+{
+	return ad9912_ramp_frequency2(d, channel, d->frequency[channel], f, fstep);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ad9912.h	Mon Mar 31 17:03:32 2014 +0200
@@ -0,0 +1,19 @@
+#ifndef __AD9912_H__
+#define __AD9912_H__
+
+#define REVISION 1
+
+struct ad9912 {
+	char *hostname;
+	int port;
+	unsigned fd;
+	double clock;
+	double frequency[4];
+};
+
+int ad9912_init(struct ad9912 *d, const char *hostname, double clock);
+int ad9912_get_frequency(struct ad9912 *d, unsigned channel, double *f);
+int ad9912_set_frequency(struct ad9912 *d, unsigned channel, double f);
+int ad9912_ramp_frequency(struct ad9912 *d, unsigned channel, double f, double step);
+
+#endif