Mercurial > hg > fxanalyse
view FXAnalyse.c @ 265:da38cbbc7ec8
Add DDS clients test code
To verify the portabiolity of the clients code and to make testing
easier the test code is independent of the CVI environment and
runtime.
author | Daniele Nicolodi <daniele.nicolodi@obspm.fr> |
---|---|
date | Sun, 21 Jun 2015 14:44:33 +0200 |
parents | 8cbfce046d41 |
children | dfbee05fe464 |
line wrap: on
line source
#include <zmq.h> #include <tcpsupp.h> #include <utility.h> #include <ansi_c.h> #include <lowlvlio.h> #include <cvirte.h> #include <userint.h> #include <formatio.h> #include <inifile.h> #include <string.h> #include "FXAnalyse.h" #include "Plot.h" #include "Allan.h" #include "ad9912.h" #include "ad9956.h" #include "muParserDLL.h" #include "utils.h" #include "stat.h" #include "future.h" #include "data-provider.h" #include "sr-data-logger.h" #include "config.h" #include "logging.h" #define FREP_STEP_SIZE 50000.0 #define SPEED_OF_LIGHT 299792458.0 // m/s #define SR_FREQUENCY 429.228293 // THz #define SR_WAVELENGTH (SPEED_OF_LIGHT / SR_FREQUENCY / 1.0e3) // nm #define HG_FREQUENCY 282.143622 // THz #define HG_WAVELENGTH (SPEED_OF_LIGHT / HG_FREQUENCY / 1.0e3) // nm // select which data provider to use #ifdef NDEBUG #define DataProvider KKDataProvider #else #define DataProvider FakeDataProvider #endif // data acquisition status int acquiring; // data queue CmtTSQHandle dataQueue; // data provider thread CmtThreadFunctionID dataProviderThread; // ZMQ void *zmqcontext; void *zmqsocket; // utility function to send data through ZMQ socket framed by an envelope // see "Pub-Sub Message Envelopes" in chapter 2 "Sockets and Patterns" // of "ZMQ The Guide" http://zguide.zeromq.org/page:all#toc49 int zmq_xpub(void *socket, char *envelope, void *data, size_t len) { int r; r = zmq_send(socket, envelope, strlen(envelope), ZMQ_SNDMORE); if (r < 0) return zmq_errno(); r = zmq_send(socket, data, len, 0); if (r < 0) return zmq_errno(); return 0; } struct event ev; double utc; #define Ch1 ev.data[0] #define Ch2 ev.data[1] #define Ch3 ev.data[2] #define Ch4 ev.data[3] double Math1, Math2, Math3, Math4, Math5; double N1, N2, N3; double Ndiv = 8.0; double Sign1 = 1, Sign2 = 1, Sign3 = 1; void *MathParser1, *MathParser2, *MathParser3, *MathParser4, *MathParser5; // panels static int MainPanel; static int CalcNPanel; static int EstimateNPanel; struct adev { Allan_Data allan; double *data; const char *title; double normalization; int control; }; #define ADEV(__channel, __normalization) \ { \ .data = & ## __channel, \ .title = "Adev " #__channel, \ .normalization = __normalization, \ .control = PANEL_ADEV_ ## __channel \ } static int adev_toggle(struct adev *adev) { if (adev->allan.active) Allan_ClosePanel(&(adev->allan)); else Allan_InitPanel(&(adev->allan), adev->title, adev->normalization, MainPanel, adev->control); return adev->allan.active; } static inline void adev_update(struct adev *adev) { if (adev->allan.active) Allan_AddFrequency(&(adev->allan), *(adev->data)); } struct adev adevs[] = { ADEV(Ch1, 1.80e12), ADEV(Ch2, 282.143e12), ADEV(Ch3, 429.228e12), ADEV(Ch4, 275.0e3), ADEV(Math1, 250.0e6), ADEV(Math2, 194.400e12), ADEV(Math3, 282.143e12), ADEV(Math4, 429.228e12), ADEV(Math5, 1.0), { NULL } }; struct plot { Plot_Data plot; double *data; const char *title; double min; double max; int control; }; #define PLOT(__channel, __min, __max) \ { \ .data = & ## __channel, \ .title = "Plot " #__channel, \ .min = __min, \ .max = __max, \ .control = PANEL_PLOT_ ## __channel \ } static int plot_toggle(struct plot *plot) { if (plot->plot.active) Plot_ClosePanel(&(plot->plot)); else Plot_InitPanel(&(plot->plot), plot->title, plot->min, plot->max, MainPanel, plot->control); return plot->plot.active; } static inline void plot_update(struct plot *plot) { if (plot->plot.active) Plot_AddFrequency(&(plot->plot), *(plot->data)); } struct plot plots[] = { PLOT(Ch1, 54.999e6, 55.001e6), PLOT(Ch2, 0.0, 0.0), PLOT(Ch3, 0.0, 0.0), PLOT(Ch4, 0.0, 0.0), PLOT(Math1, 0.0, 0.0), PLOT(Math2, 0.0, 0.0), PLOT(Math3, 0.0, 0.0), PLOT(Math4, 0.0, 0.0), PLOT(Math5, 0.0, 0.0), { NULL } }; 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; } static inline int ad9956_set_sweep_rate_w(struct ad9956 *d, double s) { int r = ad9956_set_sweep_rate(d, s); if (r) logmessage(ERROR, "ad9956 set sweep rate error=%d", -r); return r; } static int ad9956_set_w(struct ad9956 *d, double f, double s) { int r; r = ad9956_sweep_stop(d); if (r) { logmessage(ERROR, "ad9956 sweep stop error=%d", -r); return r; } r = ad9956_set_frequency(d, f); if (r) { logmessage(ERROR, "ad9956 set frequency error=%d", -r); return r; } r = ad9956_set_sweep_rate(d, s); if (r) { logmessage(ERROR, "ad9956 set sweep rate error=%d", -r); return r; } r = ad9956_sweep_start(d); if (r) { logmessage(ERROR, "ad9956 sweep start error=%d", -r); return r; } return 0; } enum { LO, HG, SR, _N_BEATS, }; enum { N_MEASUREMENT_NONE, N_MEASUREMENT_INIT, N_MEASUREMENT_SLOPE, N_MEASUREMENT_ADJUST_FREQ_PLUS, N_MEASUREMENT_FREP_PLUS, N_MEASUREMENT_ADJUST_FREQ_MINUS, N_MEASUREMENT_FREP_MINUS, }; int n_measurement_1 = N_MEASUREMENT_NONE; int n_measurement_2 = N_MEASUREMENT_NONE; int n_measurement_3 = N_MEASUREMENT_NONE; int nobs = 0; int settling = 0; double f0_DDS1 = 110000000.0, f0_DDS2, f0_DDS3, f0_DDS4, df_DDS3; double slope_time_1 = 40.0, integration_time_1 = 40.0, delta_f_lock_1 = 500e3; double slope_time_2 = 40.0, integration_time_2 = 40.0, delta_f_lock_2 = 500e3; double slope_time_3 = 40.0, integration_time_3 = 40.0, delta_f_lock_3 = 500e3; double t1, t2, t3; double f_rep_slope, f_beat_slope; double f_rep_plus, f_rep_minus; double f_beat_plus, f_beat_minus; // Beatnote sign determination is done stepping the repetition rate by // stepping the comb phase-lock offset frequency f_lock generated by // DDS1. A lock frequency step delta_f_lock determines a change in the // repetition rate given by: // // abs(delta_f_rep) = Ndiv * delta_f_lock / N1 // // where Ndiv = 8 and N1 ~= 8 x 10^5 obtaining that // // abs(delta_f_rep) ~= delta_f_lock / 10^5 // // For the determination of the comb locking beatnote sign we detect // the sign of delta_f_rep caused by a positive delta_f_lock. f_rep is // measured should be small enough to do not exceed the 200x PLL // bandwidth but still be clearly identified. // // For the optical beatnotes we detect the sign of delta_f_beat caused // by a positive delta_f_lock thus we need to take into account the // sign of the comb locking beatnote. The optical beatnote frequency // change is given by // // abs(delta_f_beat) = abs(delta_f_rep) * Nx // // where Nx ~= 10^6 obtaining that // // abs(delta_f_beat) ~= delta_f_lock * 10 // // this need to do not exceed the beatnote filters bandwidth. Given // those contraints the following f_lock steps are chosen: double f_lock_step_1 = 10000.0; double f_lock_step_2 = 10.0; double f_lock_step_3 = 10.0; struct beatsign { int measure; // which beatnote sign is being measured double f0_DDS1; // DDS1 frequency before stepping double t0; // measurement start time double f_rep_zero; // repetition rate before stepping double f_beat_zero; // beatnote frequwncy before stepping }; struct beatsign beatsign = { .measure = 0, }; struct stat stat_math1, stat_ch2, stat_ch3; struct rollmean rollmean_ch1, rollmean_ch2, rollmean_ch3, rollmean_ch4; // dedrift enum { DEDRIFT_REFERENCE_MICROWAVE = 0, DEDRIFT_REFERENCE_HG = 1, }; struct dedrift { int enabled; // dedrift enabled int proportional; // enable proportional correction int reference; // reference frequency int sign; // sign of the correction int x2; // double the applied correction int keep_freq; // keep current frequency value when dedrift is disabled int keep_slope; // keep current slope value when dedrift is disabled double f0; // target frequency double fDDS; // DDS center frequency double applied; // currently applied slope double interval; // measurement duration double t0; // beginning of currrent measurement interval double threshold; // maximum allowed frequency change int badcount; // number of bad data points encountered consecutively int badcountmax; // maximum number of consecutive bad data points int safety; // stop slope update when too many consecutive bad data points are detected struct stat stat; // frequency mean and slope }; struct dedrift dedrift = { .enabled = FALSE, .proportional = FALSE, .reference = DEDRIFT_REFERENCE_MICROWAVE, .sign = +1, .x2 = FALSE, .keep_freq = TRUE, .keep_slope = TRUE, .f0 = 0.0, .fDDS = 70e6, .applied = 0.0, .interval = 30.0, .t0 = 0.0, .threshold = 20.0, // corresponding to a relative frequnecy stability of ~1e-13 .badcount = 0, .badcountmax = 10, .safety = TRUE, }; void dedrift_update_enable() { logmsg("dedrift: automatic slope update enabled"); dedrift.enabled = TRUE; dedrift.t0 = utc; stat_zero(&dedrift.stat); dedrift.stat.previous = NaN; } void dedrift_update_disable() { logmsg("dedrift: automatic slope update disabled"); dedrift.enabled = FALSE; stat_zero(&dedrift.stat); if (! dedrift.keep_slope) { dedrift.applied = 0.0; ad9956_set_sweep_rate_w(&ad9956, dedrift.applied); } if (! dedrift.keep_freq) { ad9956_set_w(&ad9956, dedrift.fDDS, dedrift.applied); } SetCtrlVal(MainPanel, PANEL_SLOPE_APPLIED, dedrift.applied); SetCtrlVal(MainPanel, PANEL_SLOPE_MEASURED, dedrift.stat.slope); SetCtrlVal(MainPanel, PANEL_MEASURE_SLOPE, 0); } // Wrapper around stat_accumulate() that updates the statistic only if // the new datapoint `v` is within `threshold` from the data point // considered in the previous update. If the data point fails this // criteria it does not contribute to the collected statistics and the // previous data point is used instead and `count` is incremented by // one. If the data point is accepted `count` is reset to zero. int stat_accumulate_resilient(struct stat *stat, double v, double threshold, int *count) { if (!isnan(stat->previous) && (fabs(v - stat->previous) > threshold)) { // bad data point stat_accumulate(stat, stat->previous); *count += 1; return TRUE; } else { // good data point stat_accumulate(stat, v); *count = 0; return FALSE; } } void dedrift_update(double f) { if (! dedrift.enabled) return; // update measurement stat_accumulate_resilient(&dedrift.stat, f, dedrift.threshold, &dedrift.badcount); if (dedrift.badcount) { // bad data point detected logmsg("dedrift: bad data point detected"); // too many consecutive bad data points detected if (dedrift.safety && (dedrift.badcount > dedrift.badcountmax)) { logmsg("dedrift: maximum number of consecutive bad data points exceeded"); dedrift_update_disable(); } } // check if the previous check disabled slope update if (! dedrift.enabled) return; // update display SetCtrlVal(MainPanel, PANEL_SLOPE_MEASURED, dedrift.stat.slope); // update applied slope if ((utc - dedrift.t0) > dedrift.interval) { // target frequency if (dedrift.f0 == 0.0) dedrift.f0 = dedrift.stat.mean; // compute correction double dt = utc - dedrift.t0; double corr = dedrift.stat.slope \ + dedrift.proportional * ((dedrift.stat.mean - dedrift.f0) / dt + 0.5 * dedrift.stat.slope); // update dedrift.applied += dedrift.sign * corr * (dedrift.x2 ? 2 : 1); ad9956_set_sweep_rate_w(&ad9956, dedrift.applied); SetCtrlVal(MainPanel, PANEL_SLOPE_APPLIED, dedrift.applied); logmsg("dedrift: update correction=%+3e slope=%+3e", corr, dedrift.applied); // start over. keep track of the last updated data point to // avoid gaps in the detectrion of bad data points based on // threshold on the difference between current data point and // previous one double prev = dedrift.stat.previous; stat_zero(&dedrift.stat); dedrift.stat.previous = prev; dedrift.t0 = utc; } } // recenter struct recenter { int active; // recenter enabled int enabled[_N_BEATS]; // which beatnotes to recenter double threshold[_N_BEATS]; // maximum frequency correction double interval; // interval double t0; // beginning of current interval }; struct recenter recenter = { .active = FALSE, .enabled = { FALSE, FALSE, FALSE }, .threshold = { 10.0, 2000.0, 2000.0 }, .interval = 1800.0, .t0 = 0.0 }; int recenter_enabled() { if (! recenter.active) return FALSE; for (int i = 0; i < _N_BEATS; i++) if (recenter.enabled[i]) return TRUE; return FALSE; } void recenter_update() { if (! recenter_enabled()) return; rollmean_accumulate(&rollmean_ch2, Ch2); rollmean_accumulate(&rollmean_ch3, Ch3); rollmean_accumulate(&rollmean_ch4, Ch4); if ((utc - recenter.t0) > recenter.interval) { if (recenter.enabled[LO]) { // adjust DDS2 frequency to keep Ch4 reading at 275 kHz double freq = ad9912.frequency[1]; double adj = 275000.0 - rollmean_ch4.mean; if (fabs(adj) > recenter.threshold[LO]) { logmessage(WARNING, "not recenter ch4 to 275 kHz: DDS2 adjustment=%+3e exceeds threshold", adj); } else { freq = freq + adj; 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.enabled[HG]) { // adjust DDS3 frequency to keep Ch2 reading at 10 kHz double freq = ad9912.frequency[2]; double adj = 10000 - rollmean_ch2.mean; if (fabs(adj) > recenter.threshold[HG]) { logmessage(WARNING, "not recenter Hg beatnote (ch2) to 10 kHz: DDS3 adjustment=%+3e exceeds threshold", adj); } else { freq = freq + adj; 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.enabled[SR]) { // adjust DDS4 frequency to keep Ch3 reading at 10 kHz double freq = ad9912.frequency[3]; double adj = 10000 - rollmean_ch3.mean; if (fabs(adj) > recenter.threshold[SR]) { logmessage(WARNING, "not recenter Sr beatnote (ch3) to 10 kHz: DDS4 adjustment=%+3e exceeds threshold", adj); } else { freq = freq + adj; ad9912_set_frequency_w(&ad9912, 3, freq); SetCtrlVal(MainPanel, PANEL_DDS4, ad9912.frequency[3]); logmsg("recenter Sr beatnote (ch3) to 10 kHz: DDS4 adjustment=%+3e", adj); } } recenter.t0 = utc; rollmean_zero(&rollmean_ch2); rollmean_zero(&rollmean_ch3); rollmean_zero(&rollmean_ch4); } } // data loggging static char *datafolder; struct datafile { char *name; double *data; int nchan; int control; int write; }; #define DATAFILE(__name, __data, __nchan, __control, __write) \ { \ .name = __name, \ .data = __data, \ .nchan = __nchan, \ .control = __control, \ .write = __write, \ } struct datafile datafiles[] = { // set the counter channels number to zero. it will // be updated when the configuration file is read DATAFILE("Raw", ev.data, 0, PANEL_SAVE_RAW, TRUE), 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), DATAFILE("Ex", &Math5, 1, PANEL_SAVE_EXTRA, FALSE), { NULL, } }; static void write_data(const char *folder, const char *name, const char *id, const char *timestr, double utc, double *v, int nchan) { int i, fd, len; char line[1024]; char filename[FILENAME_MAX]; // construct filename in the form folder\\id-name.txt snprintf(filename, sizeof(filename), "%s\\%s-%s.txt", folder, id, name); fd = open(filename, O_CREAT|O_WRONLY|O_APPEND, S_IRUSR|S_IWUSR|S_IRGRP); if (fd < 0) { logmessage(ERROR, "open data file %s: %s", filename, strerror(errno)); return; } // timestamp len = snprintf(line, sizeof(line), "%s\t%.3f", timestr, utc); // data channels for (i = 0; i < nchan; i++) len += snprintf(line + len, sizeof(line) - len, "\t%.16e", v[i]); // newline line[len++] = '\r'; line[len++] = '\n'; // write to file write(fd, line, len); close(fd); } static inline void datafile_append(struct datafile *d, char *id, char *timestr) { if (d->write) write_data(datafolder, d->name, id, timestr, utc, d->data, d->nchan); } static struct datalogger datalogger; static void onerror(int level, const char *msg) { SetCtrlVal(MainPanel, PANEL_ERROR, 1); } static void * muParserNew() { void *parser = mupCreate(); mupDefineOprtChars(parser, "abcdefghijklmnopqrstuvwxyzµ" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "+-*^/?<>=#!$%&|~'_"); mupDefineVar(parser, "Ch1", &Ch1); mupDefineVar(parser, "Ch2", &Ch2); mupDefineVar(parser, "Ch3", &Ch3); mupDefineVar(parser, "Ch4", &Ch4); 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); mupDefineVar(parser, "Sign1", &Sign1); mupDefineVar(parser, "Sign2", &Sign2); mupDefineVar(parser, "Sign3", &Sign3); mupDefineVar(parser, "Ndiv", &Ndiv); mupDefinePostfixOprt(parser, "P", &Peta, 1); mupDefinePostfixOprt(parser, "T", &Tera, 1); mupDefinePostfixOprt(parser, "G", &Giga, 1); mupDefinePostfixOprt(parser, "M", &Mega, 1); mupDefinePostfixOprt(parser, "k", &kilo, 1); mupDefinePostfixOprt(parser, "m", &milli, 1); mupDefinePostfixOprt(parser, "u", µ, 1); mupDefinePostfixOprt(parser, "µ", µ, 1); mupDefinePostfixOprt(parser, "n", &nano, 1); mupDefinePostfixOprt(parser, "p", &pico, 1); mupDefinePostfixOprt(parser, "f", &femto, 1); return parser; } void CVICALLBACK DataAvailableCB (CmtTSQHandle queueHandle, unsigned int event, int value, void *callbackData); int main (int argc, char *argv[]) { int i, rv, nchan; double frequency, clock; char expr[1024]; char host[256]; int PANEL_DDS[4] = { PANEL_DDS1, PANEL_DDS2, PANEL_DDS3, PANEL_DDS4 }; if ((MainPanel = LoadPanel (0, "FXAnalyse.uir", PANEL)) < 0) return -1; if ((CalcNPanel = LoadPanel (MainPanel, "FXAnalyse.uir", CALCN)) < 0) return -1; if ((EstimateNPanel = LoadPanel (MainPanel, "FXAnalyse.uir", ESTIMATEN)) < 0) return -1; // logging logger_init(&onerror); // load configuration file char path[MAX_PATHNAME_LEN]; GetIniFilePath(path); IniText configuration = Ini_New(TRUE); Ini_ReadFromFile(configuration, path); // KK counter channel number rv = Ini_GetInt(configuration, "KK", "nchan", &nchan); if (rv < 1) nchan = 4; // update number of channels to save to disk datafiles[0].nchan = nchan; // data folder rv = Ini_GetStringCopy(configuration, "data", "folder", &datafolder); if (rv > 0) { logmessage(INFO, "writing data files in '%s'", datafolder); } else { logmessage(ERROR, "data folder not configured in %s", path); // do not allow to start the acquisition SetCtrlAttribute(MainPanel, PANEL_STARTBUTTON, ATTR_DIMMED, TRUE); } // ad9956 configuration parameters rv = Ini_GetStringIntoBuffer(configuration, "AD9956", "host", host, sizeof(host)); if (! rv) return -1; rv = Ini_GetDouble(configuration, "AD9956", "clock", &clock); if (! rv) return -1; // initialize AD9956 dedrift DDS rv = ad9956_init(&ad9956, host, clock); if (rv) logmessage(ERROR, "ad9956 init erorr=%d", -rv); ad9956_set_w(&ad9956, dedrift.fDDS, dedrift.applied); // AD9912 configuration parameters rv = Ini_GetStringIntoBuffer(configuration, "AD9912", "host", host, sizeof(host)); if (! rv) return -1; rv = Ini_GetDouble(configuration, "AD9912", "clock", &clock); if (! rv) return -1; // initialize AD9912 DDS box rv = ad9912_init(&ad9912, host, clock); if (rv) logmessage(ERROR, "ad9912 init erorr=%d", -rv); // try to read back current frequency from DDS for (i = 0; i < 4; i++) { rv = ad9912_get_frequency(&ad9912, i, &frequency); if ((rv) || (frequency == 0.0)) { logmessage(WARNING, "reset DDS%d frequency to default value", i + 1); GetCtrlVal(MainPanel, PANEL_DDS[i], &frequency); ad9912_set_frequency_w(&ad9912, i, frequency); } SetCtrlVal(MainPanel, PANEL_DDS[i], frequency); } // setup ZMQ pub socket char *socket; rv = Ini_GetStringCopy(configuration, "ZMQ", "socket", &socket); if (! rv) socket = strdup("tcp://127.0.0.1:3456"); logmessage(INFO, "data sent to ZMQ socket '%s'", socket); zmqcontext = zmq_ctx_new(); zmqsocket = zmq_socket(zmqcontext, ZMQ_PUB); rv = zmq_bind(zmqsocket, socket); if (rv) logmessage(ERROR, "cannot bind ZMQ socket '%s': %s", socket, zmq_strerror(zmq_errno())); free(socket); // dispose configuration Ini_Dispose(configuration); // Sr data logger sr_datalogger_init(&datalogger); GetCtrlVal(MainPanel, PANEL_N1, &N1); GetCtrlVal(MainPanel, PANEL_N2, &N2); GetCtrlVal(MainPanel, PANEL_N3, &N3); MathParser1 = muParserNew(); GetCtrlVal(MainPanel, PANEL_MATHSTRING1, expr); mupSetExpr(MathParser1, expr); MathParser2 = muParserNew(); mupDefineVar(MathParser2, "Math1", &Math1); GetCtrlVal(MainPanel, PANEL_MATHSTRING2, expr); mupSetExpr(MathParser2, expr); MathParser3 = muParserNew(); mupDefineVar(MathParser3, "Math1", &Math1); mupDefineVar(MathParser3, "Math2", &Math2); GetCtrlVal(MainPanel, PANEL_MATHSTRING3, expr); mupSetExpr(MathParser3, expr); MathParser4 = muParserNew(); mupDefineVar(MathParser4, "Math1", &Math1); mupDefineVar(MathParser4, "Math2", &Math2); mupDefineVar(MathParser4, "Math3", &Math3); GetCtrlVal(MainPanel, PANEL_MATHSTRING4, expr); mupSetExpr(MathParser4, expr); MathParser5 = muParserNew(); mupDefineVar(MathParser5, "Math1", &Math1); mupDefineVar(MathParser5, "Math2", &Math2); mupDefineVar(MathParser5, "Math3", &Math3); mupDefineVar(MathParser5, "Math4", &Math4); GetCtrlVal(MainPanel, PANEL_MATHSTRING5, expr); mupSetExpr(MathParser5, expr); // data queue CmtNewTSQ(128, sizeof(struct event), 0, &dataQueue); // register callback to execute when data will be in the data queue CmtInstallTSQCallback(dataQueue, EVENT_TSQ_ITEMS_IN_QUEUE, 1, DataAvailableCB, NULL, CmtGetCurrentThreadID(), NULL); DisplayPanel(MainPanel); RunUserInterface(); DiscardPanel(MainPanel); return 0; } int CVICALLBACK QuitCallback (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_COMMIT: QuitUserInterface(0); break; } return 0; } int CVICALLBACK CB_OnEventMain(int panel, int event, void *callbackData, int eventData1, int eventData2) { int control, index; double step; #define do_arrow(__DDS, __STEP) \ do { \ GetCtrlIndex(panel, __STEP, &index); \ if ((eventData1 == VAL_RIGHT_ARROW_VKEY) && (index < 14)) \ SetCtrlIndex(panel, __STEP, index + 1); \ if ((eventData1 == VAL_LEFT_ARROW_VKEY) && (index > 0)) \ SetCtrlIndex(panel, __STEP, index - 1); \ GetCtrlVal(panel, __STEP, &step); \ SetCtrlAttribute(panel, __DDS, ATTR_INCR_VALUE, step); \ } while (0) switch (event) { case EVENT_KEYPRESS: /* key code */ switch (eventData1) { case VAL_RIGHT_ARROW_VKEY: case VAL_LEFT_ARROW_VKEY: control = GetActiveCtrl(panel); switch (control) { case PANEL_DDS1: case PANEL_DDS1STEP: do_arrow(PANEL_DDS1, PANEL_DDS1STEP); break; case PANEL_DDS2: case PANEL_DDS2STEP: do_arrow(PANEL_DDS2, PANEL_DDS2STEP); break; case PANEL_DDS3: case PANEL_DDS3STEP: do_arrow(PANEL_DDS3, PANEL_DDS3STEP); break; case PANEL_DDS4: case PANEL_DDS4STEP: do_arrow(PANEL_DDS4, PANEL_DDS4STEP); break; } break; case VAL_F2_VKEY : SetActiveCtrl(panel, PANEL_DDS1); break; case VAL_F3_VKEY : SetActiveCtrl(panel, PANEL_DDS2); break; case VAL_F4_VKEY : SetActiveCtrl(panel, PANEL_DDS3); break; case VAL_F5_VKEY : SetActiveCtrl(panel, PANEL_DDS4); break; } break; } return 0; } int CVICALLBACK CB_OnStart (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_COMMIT: if (acquiring) break; logmsg("start"); SetCtrlAttribute(panel, PANEL_STARTBUTTON, ATTR_DIMMED, TRUE); acquiring = 1; // start data provider thread CmtScheduleThreadPoolFunctionAdv( DEFAULT_THREAD_POOL_HANDLE, DataProvider, NULL, THREAD_PRIORITY_HIGHEST, NULL, 0, NULL, 0, &dataProviderThread); break; } return 0; } int CVICALLBACK CB_OnStop (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_COMMIT: if (! acquiring) break; logmsg("stop"); acquiring = 0; // wait for data provider thread to terminate CmtWaitForThreadPoolFunctionCompletion( DEFAULT_THREAD_POOL_HANDLE, dataProviderThread, OPT_TP_PROCESS_EVENTS_WHILE_WAITING); CmtReleaseThreadPoolFunctionID( DEFAULT_THREAD_POOL_HANDLE, dataProviderThread); SetCtrlAttribute(panel, PANEL_STARTBUTTON, ATTR_DIMMED, FALSE); break; } return 0; } void CVICALLBACK DataAvailableCB (CmtTSQHandle queueHandle, unsigned int event, int value, void *callbackData) { int read; switch (event) { case EVENT_TSQ_ITEMS_IN_QUEUE: // read data from the data queue while (value > 0) { read = CmtReadTSQData(queueHandle, &ev, 1, TSQ_INFINITE_TIMEOUT, 0); if (read != 1) logmsg("Error!"); value = value - read; // unpack event utc = ev.time.tv_sec + ev.time.tv_usec * 1e-6; // update display SetCtrlVal(MainPanel, PANEL_UTC, utc); SetCtrlVal(MainPanel, PANEL_CH1, Ch1); SetCtrlVal(MainPanel, PANEL_CH2, Ch2); SetCtrlVal(MainPanel, PANEL_CH3, Ch3); SetCtrlVal(MainPanel, PANEL_CH4, Ch4); // compute Math1 = mupEval(MathParser1); Math2 = mupEval(MathParser2); Math3 = mupEval(MathParser3); Math4 = mupEval(MathParser4); Math5 = mupEval(MathParser5); // update display. numeric controllers do not format values // with a thousands separator: use string controllers and a // custom formatting function char buffer[256]; SetCtrlVal(MainPanel, PANEL_MATH1, thousands(buffer, sizeof(buffer), "%.6f", Math1)); SetCtrlVal(MainPanel, PANEL_MATH2, thousands(buffer, sizeof(buffer), "%.3f", Math2)); SetCtrlVal(MainPanel, PANEL_MATH3, thousands(buffer, sizeof(buffer), "%.3f", Math3)); SetCtrlVal(MainPanel, PANEL_MATH4, thousands(buffer, sizeof(buffer), "%.3f", Math4)); SetCtrlVal(MainPanel, PANEL_MATH5, thousands(buffer, sizeof(buffer), "%.3f", Math5)); // update timeseries plots for (struct plot *plot = plots; plot->data; plot++) plot_update(plot); // update allan deviation plots for (struct adev *adev = adevs; adev->data; adev++) adev_update(adev); // N measurement switch (n_measurement_1) { case N_MEASUREMENT_NONE: // not measuring break; case N_MEASUREMENT_INIT: // initialization step // set DDS1 to nominal frequency ad9912_set_frequency_w(&ad9912, 0, f0_DDS1); SetCtrlVal(MainPanel, PANEL_DDS1, ad9912.frequency[0]); // record current DDS frequencies f0_DDS2 = ad9912.frequency[1]; t1 = utc; t2 = t3 = 0.0; nobs = 0; stat_zero(&stat_math1); f_rep_plus = f_rep_minus = 0.0; // next step n_measurement_1 += 1; break; case N_MEASUREMENT_SLOPE: // slope measurement stat_accumulate(&stat_math1, Math1); if ((utc - t1) > slope_time_1) { f_rep_slope = stat_math1.slope; // frep positive step 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; // next step n_measurement_1 += 1; } break; case N_MEASUREMENT_ADJUST_FREQ_PLUS: case N_MEASUREMENT_ADJUST_FREQ_MINUS: // adjust DDS frequency to keep beatnote within the bandpass filter if (settling-- > 0) break; 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; // next step n_measurement_1 += 1; break; case N_MEASUREMENT_FREP_PLUS: // frep positive step if (settling-- > 0) break; if (t2 == 0.0) t2 = utc; f_rep_plus += Math1 - f_rep_slope * (utc - t2); nobs += 1; if ((utc - t2) > integration_time_1) { f_rep_plus = f_rep_plus / nobs; nobs = 0; // frep negative step 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; // next step n_measurement_1 += 1; } break; case N_MEASUREMENT_FREP_MINUS: // frep negative step if (settling-- > 0) break; if (t3 == 0.0) t3 = utc; f_rep_minus += Math1 - f_rep_slope * (utc - t2); nobs += 1; if ((utc - t3) > integration_time_1) { f_rep_minus = f_rep_minus / nobs; nobs = 0; // compute N1 double delta_f_rep = f_rep_minus - f_rep_plus; double measured = Sign1 * 2 * Ndiv * delta_f_lock_1 / delta_f_rep; SetCtrlVal(CalcNPanel, CALCN_N, measured); // back to nominal frep 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 n_measurement_1 = N_MEASUREMENT_NONE; } break; } switch (n_measurement_2) { case N_MEASUREMENT_NONE: // not measuring break; case N_MEASUREMENT_INIT: // initialization step // set DDS1 to nominal frequency ad9912_set_frequency_w(&ad9912, 0, f0_DDS1); SetCtrlVal(MainPanel, PANEL_DDS1, ad9912.frequency[0]); // record current DDS frequencies f0_DDS2 = ad9912.frequency[1]; f0_DDS3 = ad9912.frequency[2]; t1 = utc; t2 = t3 = 0.0; nobs = 0; stat_zero(&stat_math1); stat_zero(&stat_ch2); f_rep_plus = f_rep_minus = 0.0; f_beat_plus = f_beat_minus = 0.0; // next step n_measurement_2 += 1; break; case N_MEASUREMENT_SLOPE: // slope measurement stat_accumulate(&stat_math1, Math1); stat_accumulate(&stat_ch2, Ch2); if ((utc - t1) > slope_time_2) { f_rep_slope = stat_math1.slope; f_beat_slope = stat_ch2.slope; // frep positive step double fDDS1 = f0_DDS1 + delta_f_lock_2; 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 - ad9912.frequency[2]; ad9912_set_frequency_w(&ad9912, 2, fDDS3); SetCtrlVal(MainPanel, PANEL_DDS3, ad9912.frequency[2]); // allow counter to settle settling = 3; // next step n_measurement_2 += 1; } break; case N_MEASUREMENT_ADJUST_FREQ_PLUS: case N_MEASUREMENT_ADJUST_FREQ_MINUS: // adjust DDS frequency to keep beatnote within the bandpass filter if (settling-- > 0) break; double fDDS2 = ad9912.frequency[1] + 275000 - Ch4; ad9912_set_frequency_w(&ad9912, 1, fDDS2); SetCtrlVal(MainPanel, PANEL_DDS2, ad9912.frequency[1]); double fDDS3 = ad9912.frequency[2] + 10000 - Ch2; df_DDS3 = df_DDS3 + 10000 - Ch2; ad9912_set_frequency_w(&ad9912, 2, fDDS3); SetCtrlVal(MainPanel, PANEL_DDS3, ad9912.frequency[2]); // allow counter to settle settling = 3; // next step n_measurement_2 += 1; break; case N_MEASUREMENT_FREP_PLUS: // frep positive step if (settling-- > 0) break; if (t2 == 0.0) t2 = utc; f_rep_plus += Math1 + 250000000 - f_rep_slope * (utc - t2); f_beat_plus += Ch2 - f_beat_slope * (utc - t2); nobs += 1; if ((utc - t2) > integration_time_2) { f_rep_plus = f_rep_plus / nobs; f_beat_plus = f_beat_plus / nobs; nobs = 0; // negative frequency step double fDDS1 = f0_DDS1 - delta_f_lock_2; 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 - ad9912.frequency[2]; ad9912_set_frequency_w(&ad9912, 2, fDDS3); SetCtrlVal(MainPanel, PANEL_DDS3, ad9912.frequency[2]); // allow counter to settle settling = 3; // next step n_measurement_2 += 1; } break; case N_MEASUREMENT_FREP_MINUS: // frep negative step if (settling-- > 0) break; if (t3 == 0.0) t3 = utc; f_rep_minus += Math1 + 250000000 - f_rep_slope * (utc - t2); f_beat_minus += Ch2 + f_beat_slope * (utc - t2); nobs += 1; if ((utc -t3) > integration_time_2) { f_rep_minus = f_rep_minus / nobs; f_beat_minus = f_beat_minus / nobs; nobs = 0; // compute N2 double delta_f_rep_m = f_rep_minus - f_rep_plus; 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 rel=%e", delta_f_rep_m, delta_f_rep, delta, delta / delta_f_rep); double measured = -Sign2 * (df_DDS3 + f_beat_minus - f_beat_plus) / delta_f_rep; SetCtrlVal(CalcNPanel, CALCN_N, measured); // back to nominal frequency 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 n_measurement_2 = N_MEASUREMENT_NONE; } break; } switch (n_measurement_3) { case N_MEASUREMENT_NONE: // not measuring N3 break; case N_MEASUREMENT_INIT: // init // set DDS1 to nominal frequency ad9912_set_frequency_w(&ad9912, 0, f0_DDS1); SetCtrlVal(MainPanel, PANEL_DDS1, ad9912.frequency[0]); // record current DDS frequencies f0_DDS2 = ad9912.frequency[1]; f0_DDS4 = ad9912.frequency[3]; t1 = utc; t2 = t3 = 0.0; nobs = 0; stat_zero(&stat_math1); stat_zero(&stat_ch3); f_rep_plus = f_rep_minus = 0.0; f_beat_plus = f_beat_minus = 0.0; // next step n_measurement_3 += 1; break; case N_MEASUREMENT_SLOPE: // slope measurement if (settling-- > 0) break; stat_accumulate(&stat_math1, Math1); stat_accumulate(&stat_ch3, Ch3); if (utc - t1 > slope_time_3) { // slope measurement f_rep_slope = stat_math1.slope; f_beat_slope = stat_ch3.slope; logmsg("f_rep_slope=%e Hz/s", f_rep_slope); logmsg("f_beat_slope=%e Hz/s", f_rep_slope); // frep positive step 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 fDDS4 = f0_DDS4 + Sign1 * Sign3 * N3/N1 * Ndiv * delta_f_lock_3; ad9912_set_frequency_w(&ad9912, 3, fDDS4); SetCtrlVal(MainPanel, PANEL_DDS4, ad9912.frequency[3]); // allow counter to settle settling = 3; // next step n_measurement_3 += 1; } break; case N_MEASUREMENT_ADJUST_FREQ_PLUS: case N_MEASUREMENT_ADJUST_FREQ_MINUS: // adjust DDS frequency to keep beatnote within the bandpass filter if (settling-- > 0) break; // adjust DDS frequency to keep 55 MHz tracker oscillator locked 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; // next step n_measurement_3 += 1; break; case N_MEASUREMENT_FREP_PLUS: // frep positive step if (settling-- > 0) break; if (t2 == 0.0) t2 = utc; f_rep_plus += Math1 + 250000000 - f_rep_slope * (utc - t2); f_beat_plus += Ch3 - f_beat_slope * (utc - t2); nobs += 1; if (utc - t2 > integration_time_3) { f_rep_plus = f_rep_plus / nobs; f_beat_plus = f_beat_plus / nobs; nobs = 0; // frep negative step 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 fDDS4 = f0_DDS4 - Sign1 * Sign3 * N3/N1 * Ndiv * delta_f_lock_3; ad9912_set_frequency_w(&ad9912, 3, fDDS4); SetCtrlVal(MainPanel, PANEL_DDS4, ad9912.frequency[3]); // allow counter to settle settling = 3; // next step n_measurement_3 += 1; } break; case N_MEASUREMENT_FREP_MINUS: // frep negative step if (settling-- > 0) break; if (t3 == 0.0) t3 = utc; f_rep_minus += Math1 + 250000000 - f_rep_slope * (utc - t2); f_beat_minus += Ch3 - f_beat_slope * (utc - t2); nobs += 1; if (utc - t3 > integration_time_3) { f_rep_minus = f_rep_minus / nobs; f_beat_minus = f_beat_minus / nobs; nobs = 0; // check delta frep 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 = 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); // compute N3 double delta_f_beat = f_beat_minus - f_beat_plus + 2.0 * Sign1 * Sign3 * N3/N1 * Ndiv * delta_f_lock_3; double delta_f_beat_expected = delta_f_rep * N3; logmsg("delta fbeat: measured=%e expected=%e difference=%e", delta_f_beat, delta_f_beat_expected, delta_f_beat - delta_f_beat_expected); double measured = delta_f_beat / delta_f_rep; SetCtrlVal(CalcNPanel, CALCN_N, measured); logmsg("measured N3=%.3f", measured); // back to nominal frep ad9912_ramp_frequency_w(&ad9912, 0, f0_DDS1, FREP_STEP_SIZE); ad9912_set_frequency_w(&ad9912, 1, f0_DDS2); ad9912_set_frequency_w(&ad9912, 3, f0_DDS4); SetCtrlVal(MainPanel, PANEL_DDS1, ad9912.frequency[0]); SetCtrlVal(MainPanel, PANEL_DDS2, ad9912.frequency[1]); SetCtrlVal(MainPanel, PANEL_DDS4, ad9912.frequency[3]); // done n_measurement_3 = N_MEASUREMENT_NONE; } break; } // beatnote sign determination if ((beatsign.measure) && (utc > beatsign.t0 + 2.0)) { int f_beat_sign, f_rep_sign = 0; switch (beatsign.measure) { case LO: f_rep_sign = (Math1 > beatsign.f_rep_zero) ? -1 : 1; Sign1 = f_rep_sign; SetCtrlVal(MainPanel, PANEL_SIGN1, Sign1); break; case HG: f_rep_sign = (Math1 > beatsign.f_rep_zero) ? -1 : 1; f_beat_sign = (Ch2 > beatsign.f_beat_zero) ? -1 : 1; Sign2 = f_rep_sign * f_beat_sign; SetCtrlVal(MainPanel, PANEL_SIGN2, Sign2); break; case SR: f_rep_sign = (Math1 > beatsign.f_rep_zero) ? -1 : 1; f_beat_sign = (Ch3 > beatsign.f_beat_zero) ? -1 : 1; Sign3 = f_rep_sign * f_beat_sign; SetCtrlVal(MainPanel, PANEL_SIGN3, Sign3); break; } // back to original repetition rate ad9912_set_frequency_w(&ad9912, 0, beatsign.f0_DDS1); SetCtrlVal(MainPanel, PANEL_DDS1, ad9912.frequency[0]); // measurement done beatsign.measure = 0; // in the case of the optical beatnotes sign measurement // we induce fairly small steps in f_rep therefore it is // good to check that we get the sign of the comb locking // beatnote right in those cases if (f_rep_sign != Sign1) logmessage(ERROR, "merasured f_rep_sign does not agree with previous determination!"); } // select dedrift reference double f = 0.0; switch (dedrift.reference) { case DEDRIFT_REFERENCE_MICROWAVE: f = Math2; break; case DEDRIFT_REFERENCE_HG: f = Ch2 * 1062.5 / 1542.2; break; } // dedrift dedrift_update(f); // recenter recenter_update(); struct tm *time = gmtime(&ev.time.tv_sec); // round to milliseconds int msec = round(ev.time.tv_usec / 1000.0); while (msec >= 1000) { time->tm_sec += 1; msec -= 1000; } // format time char timestr[24]; int len = strftime(timestr, sizeof(timestr), "%d/%m/%Y %H:%M:%S", time); snprintf(timestr + len, sizeof(timestr) - len, ".%03d", msec); // display local time SetCtrlVal(MainPanel, PANEL_TIME, timestr); // run id derived from current date in the form YYMMDD char id[7]; strftime(id, sizeof(id), "%y%m%d", time); // write datafiles for (struct datafile *d = datafiles; d->data; d++) datafile_append(d, id, timestr); // send Sr frequency (Math4) to Sr data logger sr_datalogger_send(&datalogger, utc, Math4); // publish data through ZMQ int r = zmq_xpub(zmqsocket, "RAW", &ev, sizeof(ev)); if (r) logmessage(ERROR, "cannot send data through ZMQ socket: %s", zmq_strerror(r)); } break; } } int CVICALLBACK CB_OnFreqPlot (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_COMMIT: for (struct plot *plot = plots; plot->data; plot++) { if (plot->control == control) plot_toggle(plot); } break; } return 0; } int CVICALLBACK CB_OnAllanPlot (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_COMMIT: for (struct adev *adev = adevs; adev->data; adev++) { if (adev->control == control) adev_toggle(adev); } break; } return 0; } int CVICALLBACK CB_ChangeDDSOut (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_COMMIT: double frequency; GetCtrlVal(MainPanel, control, &frequency); switch (control) { case PANEL_DDS1: ad9912_set_frequency_w(&ad9912, 0, frequency); SetCtrlVal(MainPanel, PANEL_DDS1, ad9912.frequency[0]); break; case PANEL_DDS2: ad9912_set_frequency_w(&ad9912, 1, frequency); SetCtrlVal(MainPanel, PANEL_DDS2, ad9912.frequency[1]); break; case PANEL_DDS3: ad9912_set_frequency_w(&ad9912, 2, frequency); SetCtrlVal(MainPanel, PANEL_DDS3, ad9912.frequency[2]); break; case PANEL_DDS4: ad9912_set_frequency_w(&ad9912, 3, frequency); SetCtrlVal(MainPanel, PANEL_DDS4, ad9912.frequency[3]); break; } break; } return 0; } int CVICALLBACK CB_ChangeDDSStep (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_COMMIT: double step; GetCtrlVal(panel, control, &step); switch (control) { case PANEL_DDS1STEP: SetCtrlAttribute(panel, PANEL_DDS1, ATTR_INCR_VALUE, step); break; case PANEL_DDS2STEP: SetCtrlAttribute(panel, PANEL_DDS2, ATTR_INCR_VALUE, step); break; case PANEL_DDS3STEP: SetCtrlAttribute(panel, PANEL_DDS3, ATTR_INCR_VALUE, step); break; case PANEL_DDS4STEP: SetCtrlAttribute(panel, PANEL_DDS4, ATTR_INCR_VALUE, step); break; } break; } return 0; } int CVICALLBACK CB_ChangeMath (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { int len; char *string; switch (event) { case EVENT_COMMIT: GetCtrlAttribute(panel, control, ATTR_STRING_TEXT_LENGTH, &len); string = (char *)malloc(sizeof(char) * (len + 1)); GetCtrlVal(panel, control, string); switch (control) { case PANEL_MATHSTRING1: mupSetExpr(MathParser1, string); break; case PANEL_MATHSTRING2: mupSetExpr(MathParser2, string); break; case PANEL_MATHSTRING3: mupSetExpr(MathParser3, string); break; case PANEL_MATHSTRING4: mupSetExpr(MathParser4, string); break; case PANEL_MATHSTRING5: mupSetExpr(MathParser5, string); break; } free(string); break; } return 0; } int CVICALLBACK CB_ChangeN (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_COMMIT: switch (control) { case PANEL_N1: GetCtrlVal(panel, control, &N1); break; case PANEL_N2: GetCtrlVal(panel, control, &N2); break; case PANEL_N3: GetCtrlVal(panel, control, &N3); break; } break; } return 0; } int CVICALLBACK CB_OnAcceptN (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { int measure; double measured; switch (event) { case EVENT_COMMIT: GetPanelAttribute(panel, ATTR_CALLBACK_DATA, &measure); GetCtrlVal(panel, CALCN_N, &measured); switch (measure) { case LO: N1 = round(measured); SetCtrlVal(MainPanel, PANEL_N1, N1); break; case HG: N2 = round(measured); SetCtrlVal(MainPanel, PANEL_N2, N2); break; case SR: N3 = round(measured); SetCtrlVal(MainPanel, PANEL_N3, N3); break; } break; } return 0; } int CVICALLBACK CB_OnNCalculus (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { int visible; switch (event) { case EVENT_COMMIT: switch (control) { case PANEL_N1CALCULUS: GetPanelAttribute(CalcNPanel, ATTR_VISIBLE, &visible); if (! visible) { SetPanelAttribute(CalcNPanel, ATTR_CALLBACK_DATA, INT_TO_PTR(LO)); SetPanelAttribute(CalcNPanel, ATTR_TITLE, "Measure N_Lo"); SetCtrlVal(CalcNPanel, CALCN_INTEGRATIONTIME, integration_time_1); SetCtrlVal(CalcNPanel, CALCN_SLOPETIME, slope_time_1); SetCtrlVal(CalcNPanel, CALCN_DELTAFREQ, delta_f_lock_1 / 1000.0); SetCtrlVal(CalcNPanel, CALCN_N, 0.0); DisplayPanel(CalcNPanel); } break; case PANEL_N2CALCULUS: GetPanelAttribute(CalcNPanel, ATTR_VISIBLE, &visible); if (! visible) { SetPanelAttribute(CalcNPanel, ATTR_CALLBACK_DATA, INT_TO_PTR(HG)); SetPanelAttribute(CalcNPanel, ATTR_TITLE, "Measure N_Hg"); SetCtrlVal(CalcNPanel, CALCN_INTEGRATIONTIME, integration_time_2); SetCtrlVal(CalcNPanel, CALCN_SLOPETIME, slope_time_2); SetCtrlVal(CalcNPanel, CALCN_DELTAFREQ, delta_f_lock_2 / 1000.0); SetCtrlVal(CalcNPanel, CALCN_N, 0.0); DisplayPanel(CalcNPanel); } break; case PANEL_N3CALCULUS: GetPanelAttribute(CalcNPanel, ATTR_VISIBLE, &visible); if (! visible) { SetPanelAttribute(CalcNPanel, ATTR_CALLBACK_DATA, INT_TO_PTR(SR)); SetPanelAttribute(CalcNPanel, ATTR_TITLE, "Measure N_Sr"); SetCtrlVal(CalcNPanel, CALCN_INTEGRATIONTIME, integration_time_3); SetCtrlVal(CalcNPanel, CALCN_SLOPETIME, slope_time_3); SetCtrlVal(CalcNPanel, CALCN_DELTAFREQ, delta_f_lock_3 / 1000.0); SetCtrlVal(CalcNPanel, CALCN_N, 0.0); DisplayPanel(CalcNPanel); } break; } break; } return 0; } int CVICALLBACK CB_OnStartNCalculus (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { void *v; int measuring; switch (event) { case EVENT_COMMIT: GetPanelAttribute(panel, ATTR_CALLBACK_DATA, &v); measuring = PTR_TO_INT(v); switch (measuring) { case LO: GetCtrlVal(CalcNPanel, CALCN_INTEGRATIONTIME, &integration_time_1); GetCtrlVal(CalcNPanel, CALCN_SLOPETIME, &slope_time_1); GetCtrlVal(CalcNPanel, CALCN_DELTAFREQ, &delta_f_lock_1); // convert from kHz to Hz delta_f_lock_1 = delta_f_lock_1 * 1000.0; n_measurement_1 = TRUE; break; case HG: GetCtrlVal(CalcNPanel, CALCN_INTEGRATIONTIME, &integration_time_2); GetCtrlVal(CalcNPanel, CALCN_SLOPETIME, &slope_time_2); GetCtrlVal(CalcNPanel, CALCN_DELTAFREQ, &delta_f_lock_2); // convert from kHz to Hz delta_f_lock_2 = delta_f_lock_2 * 1000.0; n_measurement_2 = TRUE; break; case SR: GetCtrlVal(CalcNPanel, CALCN_INTEGRATIONTIME, &integration_time_3); GetCtrlVal(CalcNPanel, CALCN_SLOPETIME, &slope_time_3); GetCtrlVal(CalcNPanel, CALCN_DELTAFREQ, &delta_f_lock_3); // convert from kHz to Hz delta_f_lock_3 = delta_f_lock_3 * 1000.0; n_measurement_3 = TRUE; break; } break; } return 0; } int CVICALLBACK CB_OnNStop (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { void *v; int measuring; switch (event) { case EVENT_COMMIT: HidePanel(CalcNPanel); GetPanelAttribute(panel, ATTR_CALLBACK_DATA, &v); measuring = PTR_TO_INT(v); switch (measuring) { case LO: n_measurement_1 = FALSE; ad9912_ramp_frequency_w(&ad9912, 0, f0_DDS1, FREP_STEP_SIZE); ad9912_set_frequency_w(&ad9912, 1, f0_DDS2); break; case HG: n_measurement_2 = FALSE; 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: n_measurement_3 = FALSE; ad9912_ramp_frequency_w(&ad9912, 0, f0_DDS1, FREP_STEP_SIZE); ad9912_set_frequency_w(&ad9912, 1, f0_DDS2); ad9912_set_frequency_w(&ad9912, 3, f0_DDS4); break; } // update DDS frequencies display 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; } return 0; } int CVICALLBACK CB_OnFindSign (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { double step = 0.0; switch (event) { case EVENT_COMMIT: switch (control) { case PANEL_FINDSIGN1: beatsign.measure = LO; beatsign.f_beat_zero = 0.0; step = f_lock_step_1; break; case PANEL_FINDSIGN2: beatsign.measure = HG; beatsign.f_beat_zero = Ch2; step = f_lock_step_2; break; case PANEL_FINDSIGN3: beatsign.measure = SR; beatsign.f_beat_zero = Ch3; step = f_lock_step_3; break; } beatsign.t0 = utc; beatsign.f_rep_zero = Math1; // step the repetition rate beatsign.f0_DDS1 = ad9912.frequency[0]; ad9912_set_frequency_w(&ad9912, 0, beatsign.f0_DDS1 + step); SetCtrlVal(MainPanel, PANEL_DDS1, ad9912.frequency[0]); break; } return 0; } int CVICALLBACK CB_AdjustDDSFreq (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { double frequency; switch (event) { case EVENT_COMMIT: switch (control) { case PANEL_ADJUST_DDS2: frequency = ad9912.frequency[1] + 275000 - Ch4; ad9912_set_frequency_w(&ad9912, 1, frequency); SetCtrlVal(MainPanel, PANEL_DDS2, ad9912.frequency[1]); break; case PANEL_ADJUST_DDS3: frequency = ad9912.frequency[2] + 10000 - Ch2; ad9912_set_frequency_w(&ad9912, 2, frequency); SetCtrlVal(MainPanel, PANEL_DDS3, ad9912.frequency[2]); break; case PANEL_ADJUST_DDS4: frequency = ad9912.frequency[3] + 10000 - Ch3; ad9912_set_frequency_w(&ad9912, 3, frequency); SetCtrlVal(MainPanel, PANEL_DDS4, ad9912.frequency[3]); break; } break; } return 0; } int CVICALLBACK CB_OnChangeNdiv (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_COMMIT: GetCtrlVal(MainPanel, PANEL_CHANGENDIV, &Ndiv); f0_DDS1 = 880000000.0 / Ndiv; ad9912_set_frequency_w(&ad9912, 0, f0_DDS1); SetCtrlVal(MainPanel, PANEL_DDS1, ad9912.frequency[0]); break; } return 0; } int CVICALLBACK CB_MeasureSlope (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { int enable; switch (event) { case EVENT_COMMIT: GetCtrlVal(panel, control, &enable); enable ? dedrift_update_enable() : dedrift_update_disable(); break; } return 0; } int CVICALLBACK CB_OnResetSlope (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_COMMIT: dedrift.applied = 0.0; SetCtrlVal(panel, PANEL_SLOPE_APPLIED, dedrift.applied); ad9956_set_w(&ad9956, dedrift.fDDS, dedrift.applied); logmsg("dedrift: reset"); break; } return 0; } int CVICALLBACK CB_ChangeSlopeTime (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_COMMIT: GetCtrlVal(MainPanel, PANEL_SLOPETIME, &dedrift.interval); break; } return 0; } int CVICALLBACK CB_OnDedriftSettingsChange (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_COMMIT: switch (control) { case PANEL_DEDRIFT_PROPORTIONAL: // include correction proportional to frequency GetCtrlVal(panel, control, &dedrift.proportional); break; case PANEL_DEDRIFT_DOUBLE_CORR: // double slope correction GetCtrlVal(panel, control, &dedrift.x2); break; case PANEL_DEDRIFT_KEEP_FREQ: // keep current dedrifting frequency when dedrifting is disabled GetCtrlVal(panel, control, &dedrift.keep_freq); break; case PANEL_DEDRIFT_KEEP_SLOPE: // keep current dedrifting slope when dedrifting is disabled GetCtrlVal(panel, control, &dedrift.keep_slope); break; } break; } return 0; } int CVICALLBACK CB_RecenterEnable (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_COMMIT: GetCtrlVal(panel, control, &recenter.active); recenter.t0 = utc; rollmean_zero(&rollmean_ch2); rollmean_zero(&rollmean_ch3); rollmean_zero(&rollmean_ch4); break; } return 0; } int CVICALLBACK CB_OnStopSlopeCancellingOnUnlocked (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_COMMIT: GetCtrlVal(panel, control, &dedrift.safety); break; } return 0; } int CVICALLBACK CB_OnSlopeReference (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_COMMIT: GetCtrlVal(panel, control, &dedrift.reference); break; } return 0; } int CVICALLBACK CB_SetSlope (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_COMMIT: GetCtrlVal(panel, control, &dedrift.applied); ad9956_set_sweep_rate_w(&ad9956, dedrift.applied); break; } return 0; } int CVICALLBACK CB_InvertSlopeSign (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { int invert; switch (event) { case EVENT_COMMIT: GetCtrlVal(panel, control, &invert); dedrift.sign = invert ? -1 : +1; break; } return 0; } int CVICALLBACK CB_ResetDedriftDDS (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_COMMIT: // stop slope measurement and reset slope dedrift.enabled = FALSE; SetCtrlVal(panel, PANEL_MEASURE_SLOPE, 0); dedrift.applied = 0.0; SetCtrlVal(panel, PANEL_SLOPE_APPLIED, dedrift.applied); // reset DDS ad9956_set_w(&ad9956, dedrift.fDDS, dedrift.applied); break; } return 0; } int CVICALLBACK CB_ShowLog (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { int visible; switch (event) { case EVENT_COMMIT: GetCtrlVal(panel, control, &visible); logger_panel_visible(visible); break; } return 0; } int CVICALLBACK CB_ShowError (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_COMMIT: logger_panel_visible(TRUE); SetCtrlVal(panel, control, FALSE); SetCtrlVal(panel, PANEL_SHOWLOG, TRUE); break; } return 0; } int CVICALLBACK CB_OnLoggingPanelEvent(int panel, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_CLOSE: logger_panel_visible(0); SetCtrlVal(MainPanel, PANEL_SHOWLOG, 0); break; } return 0; } int CVICALLBACK CB_BeatnoteSign (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_COMMIT: switch(control) { case PANEL_SIGN1: GetCtrlVal(panel, control, &Sign1); break; case PANEL_SIGN2: GetCtrlVal(panel, control, &Sign2); break; case PANEL_SIGN3: GetCtrlVal(panel, control, &Sign3); break; } break; } return 0; } int CVICALLBACK CB_SaveData (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_COMMIT: for (struct datafile *d = datafiles; d->data; d++) { if (d->control == control) GetCtrlVal(panel, control, &(d->write)); } break; } return 0; } int CVICALLBACK CB_RecenterInterval (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_COMMIT: GetCtrlVal(panel, control, &recenter.interval); break; } return 0; } int CVICALLBACK CB_RecenterChannel (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_COMMIT: switch (control) { case PANEL_RECENTER_LO: GetCtrlVal(panel, control, &recenter.enabled[LO]); break; case PANEL_RECENTER_HG: GetCtrlVal(panel, control, &recenter.enabled[HG]); break; case PANEL_RECENTER_SR: GetCtrlVal(panel, control, &recenter.enabled[SR]); break; } break; } return 0; } int CVICALLBACK CB_RecenterThreshold (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_COMMIT: switch (control) { case PANEL_RECENTER_THRESHOLD_LO: GetCtrlVal(panel, control, &recenter.threshold[LO]); break; case PANEL_RECENTER_THRESHOLD_HG: GetCtrlVal(panel, control, &recenter.threshold[HG]); break; case PANEL_RECENTER_THRESHOLD_SR: GetCtrlVal(panel, control, &recenter.threshold[SR]); break; } break; } return 0; } int CVICALLBACK CB_SrDatalogger (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_COMMIT: GetCtrlVal(panel, control, &datalogger.enabled); break; } return 0; } int CVICALLBACK CB_DedriftDDSFreq (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_COMMIT: GetCtrlVal(panel, control, &dedrift.fDDS); ad9956_set_w(&ad9956, dedrift.fDDS, dedrift.applied); break; } return 0; } // // N estimate // static void estimateN (void) { double nu, fbeat, frep, N; int sign; GetCtrlVal(EstimateNPanel, ESTIMATEN_FREQUENCY, &nu); GetCtrlVal(EstimateNPanel, ESTIMATEN_FREP, &frep); GetCtrlVal(EstimateNPanel, ESTIMATEN_FBEAT, &fbeat); GetCtrlVal(EstimateNPanel, ESTIMATEN_SIGN, &sign); N = (nu * 1.0e12 - sign * fbeat) / frep; SetCtrlVal(EstimateNPanel, ESTIMATEN_N, N); } int CVICALLBACK cb_onEstimateN (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { int visible; switch (event) { case EVENT_COMMIT: // reset N estimate SetCtrlVal(EstimateNPanel, ESTIMATEN_N, 0.0); // set current frep SetCtrlVal(EstimateNPanel, ESTIMATEN_FREP, 250e6 + Math1); switch (control) { case PANEL_ESTIMATE_N2: // expected frequency SetCtrlVal(EstimateNPanel, ESTIMATEN_FREQUENCY, HG_FREQUENCY); SetCtrlVal(EstimateNPanel, ESTIMATEN_WAVELENGTH, HG_WAVELENGTH); // sign SetCtrlVal(EstimateNPanel, ESTIMATEN_SIGN, (int)Sign2); // f_DDS SetCtrlVal(EstimateNPanel, ESTIMATEN_FDDS, ad9912.frequency[2]); // f_counter SetCtrlVal(EstimateNPanel, ESTIMATEN_FDDS, Ch2); // f_beat SetCtrlVal(EstimateNPanel, ESTIMATEN_FBEAT, ad9912.frequency[2] - Ch2); SetPanelAttribute(EstimateNPanel, ATTR_TITLE, "Estimate N_Hg"); SetPanelAttribute(EstimateNPanel, ATTR_CALLBACK_DATA, INT_TO_PTR(HG)); break; case PANEL_ESTIMATE_N3: // expected frequency SetCtrlVal(EstimateNPanel, ESTIMATEN_FREQUENCY, SR_FREQUENCY); SetCtrlVal(EstimateNPanel, ESTIMATEN_WAVELENGTH, SR_WAVELENGTH); // sign SetCtrlVal(EstimateNPanel, ESTIMATEN_SIGN, (int)Sign3); // f_DDS SetCtrlVal(EstimateNPanel, ESTIMATEN_FDDS, ad9912.frequency[3]); // f_counter SetCtrlVal(EstimateNPanel, ESTIMATEN_FDDS, Ch3); // f_beat SetCtrlVal(EstimateNPanel, ESTIMATEN_FBEAT, ad9912.frequency[3] - Ch3); SetPanelAttribute(EstimateNPanel, ATTR_TITLE, "Estimate N_Sr"); SetPanelAttribute(EstimateNPanel, ATTR_CALLBACK_DATA, INT_TO_PTR(SR)); break; } // display dialog GetPanelAttribute(EstimateNPanel, ATTR_VISIBLE , &visible); if (! visible) DisplayPanel(EstimateNPanel); // compute estimateN(); break; } return 0; } int CVICALLBACK cb_onEstimateNWaveleght (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { double wavelenght, frequency; switch (event) { case EVENT_COMMIT: GetCtrlVal(panel, control, &wavelenght); frequency = SPEED_OF_LIGHT / (wavelenght * 1.0e-9) / 1.0e12; SetCtrlVal(panel, ESTIMATEN_FREQUENCY, frequency); estimateN(); break; } return 0; } int CVICALLBACK cb_onEstimateNFrequency (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { double wavelenght, frequency; switch (event) { case EVENT_COMMIT: GetCtrlVal(panel, control, &frequency); wavelenght = SPEED_OF_LIGHT / (frequency * 1.0e12) / 1.0e-9; SetCtrlVal(panel, ESTIMATEN_WAVELENGTH, wavelenght); estimateN(); break; } return 0; } int CVICALLBACK cb_onEstimateNChange (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_COMMIT: estimateN(); break; } return 0; } int CVICALLBACK cb_onEstimateNClose (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { int visible; switch (event) { case EVENT_COMMIT: GetPanelAttribute(panel, ATTR_VISIBLE, &visible); if (visible) HidePanel(panel); break; } return 0; } int CVICALLBACK cb_onEstimateNSet (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { void *v; double n; int estimate = 0; switch (event) { case EVENT_COMMIT: GetPanelAttribute(panel, ATTR_CALLBACK_DATA, &v); estimate = PTR_TO_INT(v); switch (estimate) { case HG: GetCtrlVal(panel, ESTIMATEN_N, &n); N2 = round(n); SetCtrlVal(MainPanel, PANEL_N2, N2); break; case SR: GetCtrlVal(panel, ESTIMATEN_N, &n); N3 = round(n); SetCtrlVal(MainPanel, PANEL_N3, N3); break; } HidePanel(panel); break; } return 0; }