Mercurial > hg > fxanalyse
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) |