comparison FXAnalyse.c @ 88:9b7588cd4013

Move data acquisition into separate thread The data acquisition thread transfers data to the main thread trough a Thread Safe Queue. This separation allows for making the data acquisition system pluggable. The old file based communication to the KK counter is implemented along with a very simple fake data provider.
author Daniele Nicolodi <daniele.nicolodi@obspm.fr>
date Thu, 21 Mar 2013 18:24:45 +0100
parents 0950d4b3a45c
children c9e4f63c2033
comparison
equal deleted inserted replaced
87:0950d4b3a45c 88:9b7588cd4013
12 #include "Allan.h" 12 #include "Allan.h"
13 #include "DDS4xAD9912.h" 13 #include "DDS4xAD9912.h"
14 #include "DDS_Fox.h" 14 #include "DDS_Fox.h"
15 #include "muParserDLL.h" 15 #include "muParserDLL.h"
16 16
17 #define FXLINELENGTH 123
18 #define LOGFILEPATH "C:\\Femto\\Software\\FXQE80"
19 #define DATAFOLDER "Z:\\Measures-2013" 17 #define DATAFOLDER "Z:\\Measures-2013"
20 18
21 #define DEDRIFT_DDS_FREQUENCY 70000000 19 #define DEDRIFT_DDS_FREQUENCY 70000000
22 20
23 // panels 21 // panels
24 static int MainPanel; 22 static int MainPanel;
25 static int CalcNPanel; 23 static int CalcNPanel;
26 static int EstimateN3Panel; 24 static int EstimateN3Panel;
27 static int LoggingPanel; 25 static int LoggingPanel;
28 26
29 char LogFileName[MAX_PATHNAME_LEN]; 27 // data acquisition status
30 28 int acquiring;
31 double utc = 0; 29 // data queue
32 30 CmtTSQHandle dataQueue;
31 // data provider thread
32 CmtThreadFunctionID dataProviderThread;
33
34 // data providers
35 int CVICALLBACK FakeDataProvider (void *functionData);
36 int CVICALLBACK FileDataProvider (void *functionData);
37
38 // select which data provider to use
39 #define DataProvider FileDataProvider
40
41
42 double utc;
33 double Ch1, Ch2, Ch3, Ch4; 43 double Ch1, Ch2, Ch3, Ch4;
34 double Math1, Math2, Math3, Math4, Math5; 44 double Math1, Math2, Math3, Math4, Math5;
35 double N1, N2, N3, N4; 45 double N1, N2, N3, N4;
36 46
37 Plot_Data PlotCh1, PlotCh2, PlotCh3, PlotCh4, PlotMath1, PlotMath2, PlotMath3, PlotMath4, PlotMath5 ; 47 Plot_Data PlotCh1, PlotCh2, PlotCh3, PlotCh4, PlotMath1, PlotMath2, PlotMath3, PlotMath4, PlotMath5 ;
42 // 4xAD9912 DDS box 52 // 4xAD9912 DDS box
43 DDS4xAD9912_Data DDS4xAD9912; 53 DDS4xAD9912_Data DDS4xAD9912;
44 54
45 muParserHandle_t MathParser1, MathParser2, MathParser3, MathParser4, MathParser5; 55 muParserHandle_t MathParser1, MathParser2, MathParser3, MathParser4, MathParser5;
46 56
47 int Acquiring = FALSE; 57
48 58
49 long OldLogFilePtr = 0;
50 double Ndiv = 8.0; 59 double Ndiv = 8.0;
51 60
52 int settling = 0; 61 int settling = 0;
53 62
54 enum { 63 enum {
231 240
232 return parser; 241 return parser;
233 } 242 }
234 243
235 244
236 void writeData(char *folder, char *name, char *id, char *date, char *time, double utc, double value) 245 void writeData(const char *folder, const char *name, const char *id,
246 const char *timestr, double utc, double value)
237 { 247 {
238 char line[1024]; 248 char line[1024];
239 char filename[FILENAME_MAX]; 249 char filename[FILENAME_MAX];
240 250
241 // construct filename in the form folder\\id-name.txt 251 // construct filename in the form folder\\id-name.txt
242 snprintf(filename, sizeof(filename), "%s\\%s-%s.txt", folder, id, name); 252 snprintf(filename, sizeof(filename), "%s\\%s-%s.txt", folder, id, name);
243 253
244 int fd = OpenFile(filename, VAL_WRITE_ONLY, VAL_APPEND, VAL_ASCII); 254 int fd = OpenFile(filename, VAL_WRITE_ONLY, VAL_APPEND, VAL_ASCII);
245 Fmt(line, "%s\t%s\t%f[p3]\t%f[p3]", date, time, utc, value); 255 Fmt(line, "%s\t%f[p3]\t%f[p3]", timestr, utc, value);
246 WriteLine(fd, line, -1); 256 WriteLine(fd, line, -1);
247 CloseFile(fd); 257 CloseFile(fd);
248 } 258 }
259
260
261 #define NCHAN 4
262 #define DATA_EVENT_SIZE (NCHAN + 1)
263 #define DATA_QUEUE_SIZE (128 * DATA_EVENT_SIZE)
264
265 void CVICALLBACK DataAvailableCB (CmtTSQHandle queueHandle, unsigned int event,
266 int value, void *callbackData);
249 267
250 268
251 int main (int argc, char *argv[]) 269 int main (int argc, char *argv[])
252 { 270 {
253 double frequency; 271 double frequency;
262 return -1; 280 return -1;
263 if ((EstimateN3Panel = LoadPanel (MainPanel, "FXAnalyse.uir", ESTIMATEN3)) < 0) 281 if ((EstimateN3Panel = LoadPanel (MainPanel, "FXAnalyse.uir", ESTIMATEN3)) < 0)
264 return -1; 282 return -1;
265 if ((LoggingPanel = LoadPanel (0, "FXAnalyse.uir", LOGGING)) < 0) 283 if ((LoggingPanel = LoadPanel (0, "FXAnalyse.uir", LOGGING)) < 0)
266 return -1; 284 return -1;
267
268 DisplayPanel (MainPanel);
269 285
270 // initialize 4x AD9959 DDS box 286 // initialize 4x AD9959 DDS box
271 DDS4xAD9912_Reset(&DDS4xAD9912); 287 DDS4xAD9912_Reset(&DDS4xAD9912);
272 GetCtrlVal(MainPanel, PANEL_DDS1, &frequency); 288 GetCtrlVal(MainPanel, PANEL_DDS1, &frequency);
273 DDS4xAD9912_SetFrequency(&DDS4xAD9912, 1, frequency); 289 DDS4xAD9912_SetFrequency(&DDS4xAD9912, 1, frequency);
316 mupDefineVar(MathParser5, "Math2", &Math2); 332 mupDefineVar(MathParser5, "Math2", &Math2);
317 mupDefineVar(MathParser5, "Math3", &Math3); 333 mupDefineVar(MathParser5, "Math3", &Math3);
318 mupDefineVar(MathParser5, "Math4", &Math4); 334 mupDefineVar(MathParser5, "Math4", &Math4);
319 GetCtrlVal(MainPanel, PANEL_MATHSTRING5, expr); 335 GetCtrlVal(MainPanel, PANEL_MATHSTRING5, expr);
320 mupSetExpr(MathParser5, expr); 336 mupSetExpr(MathParser5, expr);
337
338 // data queue
339 CmtNewTSQ(DATA_QUEUE_SIZE, sizeof(double), 0, &dataQueue);
340
341 // register callback to execute when data will be in the data queue
342 CmtInstallTSQCallback(dataQueue, EVENT_TSQ_ITEMS_IN_QUEUE, DATA_EVENT_SIZE,
343 DataAvailableCB, NULL, CmtGetCurrentThreadID(), NULL);
344
345 DisplayPanel(MainPanel);
321 346
322 RunUserInterface(); 347 RunUserInterface();
323 348
324 DiscardPanel(MainPanel); 349 DiscardPanel(MainPanel);
325 return 0; 350 return 0;
467 } 492 }
468 return 0; 493 return 0;
469 } 494 }
470 495
471 496
472 void CurrentFileName(char *fname)
473 {
474 char day[3], month[3], year[3];
475 char *date = DateStr();
476 Scan(date, "%s>%s[w2]-%s[w2]-20%s[w2]", month, day, year);
477 Fmt(fname, "%s<%s\\%s%s%s_Frequ.txt", LOGFILEPATH, year, month, day);
478 }
479
480
481 int CVICALLBACK CB_OnStart (int panel, int control, int event, 497 int CVICALLBACK CB_OnStart (int panel, int control, int event,
482 void *callbackData, int eventData1, int eventData2) 498 void *callbackData, int eventData1, int eventData2)
483 { 499 {
484 switch (event) 500 switch (event)
485 { 501 {
486 case EVENT_COMMIT: 502 case EVENT_COMMIT:
487 if (Acquiring) { 503 if (acquiring)
488 PlotCh1.IndexPoint = 0; 504 break;
489 PlotCh2.IndexPoint = 0;
490 PlotCh3.IndexPoint = 0;
491 PlotCh4.IndexPoint = 0;
492 PlotMath1.IndexPoint = 0;
493 PlotMath2.IndexPoint = 0;
494 PlotMath3.IndexPoint = 0;
495 PlotMath4.IndexPoint = 0;
496 PlotMath5.IndexPoint = 0;
497 Allan_Reset(&AllanCh1);
498 Allan_Reset(&AllanCh2);
499 Allan_Reset(&AllanCh3);
500 Allan_Reset(&AllanCh4);
501 Allan_Reset(&AllanMath1);
502 Allan_Reset(&AllanMath2);
503 Allan_Reset(&AllanMath3);
504 Allan_Reset(&AllanMath4);
505 Allan_Reset(&AllanMath5);
506 }
507 Acquiring = TRUE;
508 SetCtrlAttribute(MainPanel, PANEL_STARTBUTTON, ATTR_LABEL_TEXT, "__RESET");
509
510 CurrentFileName(LogFileName);
511 GetFileInfo(LogFileName, &OldLogFilePtr);
512 OldLogFilePtr -= OldLogFilePtr%FXLINELENGTH + FXLINELENGTH - 2;
513 505
514 logmsg("Start"); 506 logmsg("Start");
507 acquiring = 1;
515 508
509 // start data provider thread
510 CmtScheduleThreadPoolFunctionAdv(
511 DEFAULT_THREAD_POOL_HANDLE, DataProvider, NULL,
512 THREAD_PRIORITY_HIGHEST, NULL, 0, NULL, 0, &dataProviderThread);
513
516 break; 514 break;
517 } 515 }
518 return 0; 516 return 0;
519 } 517 }
520 518
521 int CVICALLBACK CB_OnStop (int panel, int control, int event, 519 int CVICALLBACK CB_OnStop (int panel, int control, int event,
522 void *callbackData, int eventData1, int eventData2) 520 void *callbackData, int eventData1, int eventData2)
523 { 521 {
524 switch (event) { 522 switch (event) {
525 case EVENT_COMMIT: 523 case EVENT_COMMIT:
526 Acquiring = FALSE ; 524 if (! acquiring)
527 SetCtrlAttribute(MainPanel, PANEL_STARTBUTTON, ATTR_LABEL_TEXT, "__START");
528 break;
529 }
530 return 0;
531 }
532
533 int CVICALLBACK CB_OnTimer (int panel, int control, int event,
534 void *callbackData, int eventData1, int eventData2)
535 {
536 int LogFile;
537 long LogFileSize;
538 char LineBuffer[FXLINELENGTH+10] = "\r\n_1 ";
539
540 char TimeTag[] = "100103 000000.000"; // K+K time tag meaning here 2010 january the 3rd at 00:00:00.000
541 char Date[] = "03/01/2010" ;
542 char Time[] = "00:00:00.000" ;
543 char Year[] = "2010";
544 char ShortYear[] = "10"; // the last 2 digits of calendar year only
545 char Month[] = "01";
546 char Day[] = "03";
547 char Hour[] = "00";
548 char Min[] = "00" ;
549 char Sec[] = "00.000";
550 struct tm LocalTime ;
551 time_t utcTime;
552
553 int BoxChecked = FALSE;
554
555 switch (event) {
556 case EVENT_TIMER_TICK:
557 if (! Acquiring)
558 break; 525 break;
559 526
560 GetFileInfo(LogFileName, &LogFileSize); 527 logmsg("Stop");
561 528 acquiring = 0;
562 if (LogFileSize > OldLogFilePtr+2*FXLINELENGTH-2) { // if a complete newline has been written 529
563 530 // wait for data provider thread to terminate
564 SuspendTimerCallbacks(); 531 CmtWaitForThreadPoolFunctionCompletion(
565 532 DEFAULT_THREAD_POOL_HANDLE, dataProviderThread,
566 // Open Log file and get to the beginning of newly completed line 533 OPT_TP_PROCESS_EVENTS_WHILE_WAITING);
567 LogFile = OpenFile(LogFileName, VAL_READ_ONLY, VAL_OPEN_AS_IS, VAL_ASCII); 534 CmtReleaseThreadPoolFunctionID(
568 OldLogFilePtr += FXLINELENGTH; 535 DEFAULT_THREAD_POOL_HANDLE, dataProviderThread);
569 SetFilePtr(LogFile, OldLogFilePtr, 0); 536
570 537 break;
571 // return the last complete string from the log file and scan it for date and time information 538 }
572 539 return 0;
573 // first, the time tag, and store it in various formats 540 }
574 ReadFile(LogFile, TimeTag, 17); 541
575 542
576 CopyBytes(Date,0,TimeTag,4,2); 543 void CVICALLBACK DataAvailableCB (CmtTSQHandle queueHandle, unsigned int event,
577 CopyBytes(Date,3,TimeTag,2,2); 544 int value, void *callbackData)
578 CopyBytes(Date,8,TimeTag,0,2); 545 {
579 CopyBytes(Time,0,TimeTag,7,2); 546 double data[DATA_EVENT_SIZE];
580 CopyBytes(Time,3,TimeTag,9,2); 547 int BoxChecked = FALSE;
581 CopyBytes(Time,6,TimeTag,11,6); 548 int read;
582 SetCtrlVal(MainPanel, PANEL_DATE, Date); 549
583 SetCtrlVal(MainPanel, PANEL_TIME, Time); 550 switch (event) {
584 551 case EVENT_TSQ_ITEMS_IN_QUEUE:
585 CopyBytes(Year,2,TimeTag,0,2); // first 2 bytes of year string remains "20" 552 /* read data from the data queue */
586 CopyBytes(ShortYear,0,TimeTag,0,2); 553 while (value >= DATA_EVENT_SIZE) {
587 CopyBytes(Month,0,TimeTag,2,2); 554
588 CopyBytes(Day,0,TimeTag,4,2); 555 read = CmtReadTSQData(queueHandle, data, DATA_EVENT_SIZE, TSQ_INFINITE_TIMEOUT, 0);
589 CopyBytes(Hour,0,TimeTag,7,2); 556 if (read != DATA_EVENT_SIZE)
590 CopyBytes(Min,0,TimeTag,9,2); 557 logmsg("Error!");
591 CopyBytes(Sec,0,TimeTag,11,6); 558 value = value - read;
592 Fmt(&LocalTime.tm_year, "%d<%s", Year); 559
593 Fmt(&LocalTime.tm_mon, "%d<%s", Month); 560 utc = data[0];
594 Fmt(&LocalTime.tm_mday, "%d<%s", Day); 561 Ch1 = data[1];
595 Fmt(&LocalTime.tm_hour, "%d<%s", Hour); 562 Ch2 = data[2];
596 Fmt(&LocalTime.tm_min, "%d<%s", Min); 563 Ch3 = data[3];
597 Fmt(&LocalTime.tm_sec, "%d<%s", "00"); // special case to handle non integer number of UTC seconds 564 Ch4 = data[4];
598 LocalTime.tm_hour += 0; 565
599 LocalTime.tm_min -= 0;
600 LocalTime.tm_sec -= 0;
601 LocalTime.tm_mon -= 1; // january is month 0 for tm struct
602 LocalTime.tm_year -= 1900; // year is number of years since 1900 for tm struct
603 LocalTime.tm_isdst = -1; // daylight saving flag MUST be set to -1 (unallocated is bugging and +1 is making 1 hour error in summer)
604 utcTime = mktime (&LocalTime);
605 utc = (double) utcTime + strtod(Sec,NULL);
606 SetCtrlVal(MainPanel, PANEL_UTC, utc); 566 SetCtrlVal(MainPanel, PANEL_UTC, utc);
607
608 // scan the line for counters's channels information
609
610 ReadLine(LogFile, LineBuffer, FXLINELENGTH+9);
611 CloseFile(LogFile);
612
613 Scan(LineBuffer, "%f%f%f%f", &Ch1, &Ch2, &Ch3, &Ch4);
614 Ch1 = 1000*Ch1;
615 Ch2 = 1000*Ch2;
616 Ch3 = 1000*Ch3;
617 Ch4 = 1000*Ch4;
618
619 SetCtrlVal(MainPanel, PANEL_FREQ1, Ch1); 567 SetCtrlVal(MainPanel, PANEL_FREQ1, Ch1);
620 SetCtrlVal(MainPanel, PANEL_FREQ2, Ch2); 568 SetCtrlVal(MainPanel, PANEL_FREQ2, Ch2);
621 SetCtrlVal(MainPanel, PANEL_FREQ3, Ch3); 569 SetCtrlVal(MainPanel, PANEL_FREQ3, Ch3);
622 SetCtrlVal(MainPanel, PANEL_FREQ4, Ch4); 570 SetCtrlVal(MainPanel, PANEL_FREQ4, Ch4);
623 571
1325 CenteringTimeBegin10K = utc; 1273 CenteringTimeBegin10K = utc;
1326 } 1274 }
1327 } 1275 }
1328 1276
1329 int save; 1277 int save;
1278
1330 // run id derived from current date in the form YYMMDD 1279 // run id derived from current date in the form YYMMDD
1331 char id[7]; 1280 char id[7];
1332 snprintf(id, sizeof(id), "%2s%2s%2s", ShortYear, Month, Day); 1281 FormatDateTimeString(utc, "%y%m%d", id, sizeof(id));
1282
1283 // time
1284 char timestr[24];
1285 FormatDateTimeString(utc, "%d/%m/%Y %H:%M:%S.%3f", timestr, sizeof(timestr));
1286 SetCtrlVal(MainPanel, PANEL_TIME, timestr);
1333 1287
1334 // write LO frequency (Math2) to disk 1288 // write LO frequency (Math2) to disk
1335 GetCtrlVal(MainPanel, PANEL_CHECKBOX_MATH2SAVE, &save); 1289 GetCtrlVal(MainPanel, PANEL_CHECKBOX_MATH2SAVE, &save);
1336 if (save) { 1290 if (save) {
1337 writeData(DATAFOLDER, "Lo", id, Date, Time, utc, Math2); 1291 writeData(DATAFOLDER, "Lo", id, timestr, utc, Math2);
1338 writeData("C:\\Femto\\Results", "OptCavity", id, Date, Time, utc, Math2); 1292 writeData("C:\\Femto\\Results", "OptCavity", id, timestr, utc, Math2);
1339 } 1293 }
1340 1294
1341 // write Hg frequency (Math3) to disk 1295 // write Hg frequency (Math3) to disk
1342 GetCtrlVal(MainPanel, PANEL_CHECKBOX_MATH3SAVE, &save); 1296 GetCtrlVal(MainPanel, PANEL_CHECKBOX_MATH3SAVE, &save);
1343 if (save) { 1297 if (save) {
1344 writeData(DATAFOLDER, "Hg", id, Date, Time, utc, Math3); 1298 writeData(DATAFOLDER, "Hg", id, timestr, utc, Math3);
1345 writeData("C:\\Femto\\Results", "HgCavity", id, Date, Time, utc, Math3); 1299 writeData("C:\\Femto\\Results", "HgCavity", id, timestr, utc, Math3);
1346 } 1300 }
1347 1301
1348 // write ExtraMath (Math5) to disk 1302 // write ExtraMath (Math5) to disk
1349 GetCtrlVal(MainPanel, PANEL_CHECKBOX_MATH5SAVE, &save); 1303 GetCtrlVal(MainPanel, PANEL_CHECKBOX_MATH5SAVE, &save);
1350 if (save) { 1304 if (save) {
1351 writeData(DATAFOLDER, "Ex", id, Date, Time, utc, Math5); 1305 writeData(DATAFOLDER, "Ex", id, timestr, utc, Math5);
1352 } 1306 }
1353
1354 // Special case to handle change of day at next second
1355 if ( LocalTime.tm_hour==23 && LocalTime.tm_min==59 && strtod(Sec,NULL)>=58 ) {
1356 Acquiring = FALSE;
1357 do {
1358 Delay(5.1);
1359 CurrentFileName(LogFileName);
1360 } while (!GetFileInfo(LogFileName, &OldLogFilePtr));
1361 Acquiring = TRUE;
1362 OldLogFilePtr = 2;
1363 }
1364
1365 ResumeTimerCallbacks();
1366
1367 } 1307 }
1368 break; 1308 break;
1369 } 1309 }
1370 return 0;
1371 } 1310 }
1372 1311
1373 1312
1374 int CVICALLBACK CB_OnFreqPlot (int panel, int control, int event, 1313 int CVICALLBACK CB_OnFreqPlot (int panel, int control, int event,
1375 void *callbackData, int eventData1, int eventData2) 1314 void *callbackData, int eventData1, int eventData2)