source: trunk/FACT++/src/dataLogger.cc@ 10211

Last change on this file since 10211 was 10183, checked in by tbretz, 14 years ago
New import.
File size: 22.8 KB
Line 
1
2#include "Event.h"
3#include "Time.h"
4#include "StateMachineDim.h"
5#include "ServiceList.h"
6#include <fstream>
7
8#include <boost/bind.hpp>
9
10//****************************************************************
11/** @class DataLogger
12 *
13 * @brief Logs all message and infos between the services
14 *
15 * This is the main logging class facility.
16 * It derives from StateMachineDim and DimInfoHandler. the first parent is here to enforce
17 * a state machine behaviour, while the second one is meant to make the dataLogger receive
18 * dim services to which it subscribed from.
19 * The possible states and transitions of the machine are:
20 * \dot
21 * digraph datalogger {
22 * node [shape=record, fontname=Helvetica, fontsize=10];
23 * e [label="Error" color="red"];
24 * r [label="Ready"]
25 * d [label="DailyOpen"]
26 * w [label="WaitingRun"]
27 * l [label="Logging"]
28 * b [label="BadDailyconfig" color="red"]
29 * c [label="BadRunConfig" color="red"]
30 *
31 * e -> r
32 * r -> e
33 * r -> d
34 * r -> b
35 * d -> w
36 * d -> r
37 * w -> r
38 * l -> r
39 * l -> w
40 * b -> d
41 * w -> c
42 * w -> l
43 * b -> r
44 * c -> r
45 * c -> l
46 * }
47 * \enddot
48 *
49 * @todo
50 * - A lot
51 ****************************************************************/
52class DataLogger : public StateMachineDim, DimInfoHandler
53{
54public:
55 /// The list of existing states specific to the DataLogger
56 enum
57 {
58 kSM_DailyOpen = 20, ///< Daily file openned and writing
59 kSM_WaitingRun = 30, ///< waiting for the run number to open the run file
60 kSM_Logging = 40, ///< both files openned and writing
61 kSM_BadDailyConfig = 0x101, ///< the folder specified for daily logging does not exist or has bad permissions
62 kSM_BadRunConfig = 0x102, ///< the folder specified for the run logging does not exist or has wrong permissions or no run number
63 } localstates_t;
64
65 DataLogger();
66 ~DataLogger();
67
68private:
69 //Define all the data structure specific to the DataLogger here
70 std::ofstream fDailyFile; /// ofstream for the dailyfile
71 std::ofstream fRunFile; /// ofstream for the run-specific file
72 std::string fDailyFileName; /// base path of the dailyfile
73 std::string fRunFileName; ///base path of the run file
74 int runNumber; ///run number (-1 means no run number specified)
75
76 ///Define all the static names
77 static const char* configDay;
78 static const char* configRun;
79 static const char* configRunNumber;
80 static const char* configLog;
81 static const char* transStart;
82 static const char* transStop;
83 static const char* transStartRun;
84 static const char* transStopRun;
85 static const char* transReset;
86 static const char* transWait;
87 static const char* runNumberInfo; ///< This is the name of the dimInfo received to specify the run number. It must be updated once the final name will be defined
88
89 int Execute(); ///Inherited from state machine impl
90
91 int Transition(const Event& evt); ///Inherited from state machine impl
92
93 int Configure(const Event& evt); ///Inherited from state machine impl
94
95 //overloading of DIM's infoHandler function
96 void infoHandler(); ///Inherited from DimInfoHandler
97
98 ServiceList fServiceList;///for obtaining the name of the existing services
99
100 std::map<std::string, std::vector<DimStampedInfo> > fServiceSubscriptions; ///All the services to which we've subscribed to. Sorted by server name
101
102 //internal methods
103 void LogPlease(DimInfo* I); ///Logging method for the services info received
104 std::string ToString(const char *format, const void *data, int size); ///Convertion from raw format to human-readable string
105 //configure methods
106 int ConfigureDailyFileName(const Event& evt); ///Configuration of the daily file path
107 int ConfigureRunFileName(const Event& evt); ///Configuration fo the file name
108 //TODO this will be given by an info, not a command.
109 int ConfigureRunNumber(const Event& evt); ///DEPREC - configuration of the run number
110 int LogMessagePlease(const Event& evt); ///logging method for the messages
111 void CheckForServicesUpdate(); ///checks with fServiceList whether or not the services got updated
112 void CheckForRunNumber(DimInfo* I); ///checks whether or not the current info being treated is a run number
113 //transitions methods
114 int StartPlease(); /// start transition
115 int StopPlease(); ///stop transition
116 int StartRunPlease(); ///from waiting to logging transition
117 int StopRunPlease(); /// from logging to waiting transition
118 int ResetPlease(); ///reset transition
119 int DailyToWaitRunPlease(); ///from dailyOpen to waiting transition
120
121 void InitServiceSubscription(); ///first subscription to the dim services.
122
123
124
125}; //DataLogger
126
127//static members initialization
128//since I do not check the transition/config names any longer, indeed maybe these could be hard-coded... but who knows what will happen in the future ?
129const char* DataLogger::configDay = "CONFIG_DAY";
130const char* DataLogger::configRun = "CONFIG_RUN";
131const char* DataLogger::configRunNumber = "CONFIG_RUN_NUMBER";
132const char* DataLogger::configLog = "LOG";
133const char* DataLogger::transStart = "START";
134const char* DataLogger::transStop = "STOP";
135const char* DataLogger::transStartRun = "START_RUN";
136const char* DataLogger::transStopRun = "STOP_RUN";
137const char* DataLogger::transReset = "RESET";
138const char* DataLogger::transWait = "WAIT_RUN_NUMBER";
139const char* DataLogger::runNumberInfo = "RUN_NUMBER";
140
141/****************************************************************
142 *
143 * DATA LOGGER CONSTRUCTOR
144 *
145 ****************************************************************/
146 //! Default constructor
147DataLogger::DataLogger() : StateMachineDim(std::cout, "DATA_LOGGER")
148{
149 //initialize member data
150 fDailyFileName = "";
151 fRunFileName = "";
152 runNumber = -1;
153 //Give a name to this machine's specific states
154 AddStateName(kSM_DailyOpen, "Daily_File_Openened");
155 AddStateName(kSM_WaitingRun, "Waiting_Run_Number");
156 AddStateName(kSM_Logging, "Logging data");
157 AddStateName(kSM_BadDailyConfig, "Folder_For_Daily_Logging_Badly_Configured");
158 AddStateName(kSM_BadRunConfig, "Folder_For_Run_Logging_Badly Configured");
159
160 /*Add the possible transitions for this machine*/
161 AddTransition(kSM_DailyOpen, transStart, kSM_Ready, kSM_BadDailyConfig) //start the daily logging. daily file location must be specified already
162 ->AssignFunction(boost::bind(&DataLogger::StartPlease, this));
163 AddTransition(kSM_Ready, transStop, kSM_DailyOpen, kSM_WaitingRun, kSM_Logging) //stop the data logging
164 ->AssignFunction(boost::bind(&DataLogger::StopPlease, this));
165 AddTransition(kSM_Logging, transStartRun, kSM_WaitingRun, kSM_BadRunConfig) //start the run logging. run file location must be specified already.
166 ->AssignFunction(boost::bind(&DataLogger::StartRunPlease, this));
167 AddTransition(kSM_WaitingRun, transStopRun, kSM_Logging)
168 ->AssignFunction(boost::bind(&DataLogger::StopRunPlease, this));
169 AddTransition(kSM_Ready, transReset, kSM_Error, kSM_BadDailyConfig, kSM_BadRunConfig, kSM_Error) //transition to exit error states. dunno if required or not, would close the daily file if already openned.
170 ->AssignFunction(boost::bind(&DataLogger::ResetPlease, this));
171 AddTransition(kSM_WaitingRun, transWait, kSM_DailyOpen)
172 ->AssignFunction(boost::bind(&DataLogger::DailyToWaitRunPlease, this));
173 /*Add the possible configurations for this machine*/
174 AddConfiguration(configDay, kSM_Ready, kSM_BadDailyConfig) //configure the daily file location. cannot be done before the file is actually opened
175 ->AssignFunction(boost::bind(&DataLogger::ConfigureDailyFileName, this, _1));
176 AddConfiguration(configRun, kSM_Ready, kSM_BadDailyConfig, kSM_DailyOpen, kSM_WaitingRun, kSM_BadRunConfig) //configure the run file location. cannot be done before the file is actually opened, and not in a dailly related error.
177 ->AssignFunction(boost::bind(&DataLogger::ConfigureRunFileName, this, _1));
178 /*wait for Dim to finish initializing*/
179 /*just a sleep for now. */
180 /*TODO: add a better way to wait: poll DIM for something I guess. Maybe get the configuration from conf server ? */
181
182 usleep(1000000); //10ms
183
184 //Provide a logging command
185 //I get the feeling that I should be going through the EventImp
186 //instead of DimCommand directly, mainly because the commandHandler
187 //is already done in StateMachineImp.cc
188 //Thus I'll simply add a configuration, which I will treat as the logging command
189 AddConfiguration(configRun, kSM_DailyOpen, kSM_Logging, kSM_WaitingRun, kSM_BadRunConfig)
190 ->AssignFunction(boost::bind(&DataLogger::LogMessagePlease, this, _1));
191
192 InitServiceSubscription();
193
194 //All configuration done, callback funtions set, go to ready state and thus prevent the run loop from being executed
195 SetReady();
196}
197//! Initialization of the subscription to the services.
198void DataLogger::InitServiceSubscription()
199{
200 //assign myself as the info handler
201 fServiceList.SetHandler(this);
202
203 //crawl through the list of services and subscribe to all of them
204 //TODO I still haven't figured out how the update of services shouldbe performed
205 //TODO: I don't think that the reference would work in this case because what is returned is a temporary. but should try anyway in case this works...
206 const std::vector<std::string> serverList = fServiceList.GetServerList();
207 for (unsigned int i=0;i<serverList.size();i++)
208 {//get the service list associated with each server
209 if (strstr(serverList[i].c_str(), "DIS_DNS") || strstr(serverList[i].c_str(), "DATA_LOGGER"))
210 continue;
211 for (std::vector<std::string>::const_iterator j=fServiceList.begin(serverList[i]); j != fServiceList.end(serverList[i]); j++)
212 {//and subscribe to each service !
213 fServiceSubscriptions[serverList[i]].push_back(DimStampedInfo(j->c_str(), const_cast<char*>(""), this));
214 }
215 }
216}
217//! destructor
218DataLogger::~DataLogger()
219{
220 if (fDailyFile.is_open())
221 fDailyFile.close();
222 if (fRunFile.is_open())
223 fRunFile.close();
224;
225}
226/****************************************************************
227 *
228 * DATA LOGGER'S EXECUTE
229 *
230 ****************************************************************/
231 //! Execute
232 //! Shouldn't be run as we use callbacks instead
233int DataLogger::Execute()
234{
235 //due to the callback mecanism, this function should never be called
236 return kSM_FatalError;
237
238 switch (GetCurrentState())
239 {
240 case kSM_Error:
241 case kSM_Ready:
242 case kSM_DailyOpen:
243 case kSM_WaitingRun:
244 case kSM_Logging:
245 case kSM_BadDailyConfig:
246 case kSM_BadRunConfig:
247 return GetCurrentState();
248
249 }
250 //this line below should never be hit. It here mainly to remove warnings at compilation
251 return kSM_FatalError;
252}
253/****************************************************************
254 *
255 * DATA LOGGER'S TRANSITION
256 *
257 ****************************************************************/
258
259 //! Shouldn't be run as we use callbacks instead
260 int DataLogger::Transition(const Event& evt)
261{
262 //due to the callback mecanism, this function should never be called
263 return kSM_FatalError;
264
265 switch (evt.GetTargetState())
266 {
267 case kSM_Ready:
268 /*here we must figure out whether the STOP or RESET command was sent*/
269 /*close opened files and go back to ready state*/
270 switch (GetCurrentState())
271 {
272 case kSM_BadDailyConfig:
273 case kSM_BadRunConfig:
274 case kSM_Error:
275 return ResetPlease();
276
277 case kSM_Logging:
278 case kSM_WaitingRun:
279 case kSM_DailyOpen:
280 return StopPlease();
281 }
282 break;
283
284 case kSM_DailyOpen:
285 /*Attempt to open the daily file */
286 switch (GetCurrentState())
287 {
288 case kSM_Ready:
289 case kSM_BadDailyConfig:
290 return StartPlease();
291 }
292 break;
293
294 case kSM_WaitingRun:
295 /*either close the run file, or just go to the waitingrun state (if coming from daily open*/
296 switch (GetCurrentState())
297 {
298 case kSM_DailyOpen:
299 return kSM_WaitingRun;
300
301 case kSM_Logging:
302 return StopRunPlease();
303 }
304 break;
305
306 case kSM_Logging:
307 /*Attempt to open run file */
308 switch (GetCurrentState())
309 {
310 case kSM_WaitingRun:
311 case kSM_BadRunConfig:
312 return StartRunPlease();
313 }
314 break;
315 }
316 //Getting here means that an invalid transition has been asked.
317 //TODO Log an error message
318 //and return the fatal error state
319 return kSM_FatalError;
320}
321/****************************************************************
322 *
323 * DATA LOGGER'S CONFIGURE
324 *
325 ****************************************************************/
326//! Shouldn't be run as we use callbacks instead
327 int DataLogger::Configure(const Event& evt)
328{
329 //due to the callback mecanism, this function should never be called
330 return kSM_FatalError;
331
332 switch (evt.GetTargetState())
333 {
334 case kSM_Ready:
335 case kSM_BadDailyConfig:
336 return ConfigureDailyFileName(evt);
337 break;
338
339 case kSM_WaitingRun:
340 case kSM_BadRunConfig:
341 return ConfigureRunFileName(evt);
342 break;
343
344 case kSM_Logging:
345 case kSM_DailyOpen:
346 return LogMessagePlease(evt);
347 break;
348
349 }
350 //Getting here means that an invalid configuration has been asked.
351 //TODO Log an error message
352 //and return the fatal error state
353 return kSM_FatalError;
354}
355/****************************************************************
356 *
357 * DATA LOGGER'S INFOHANDLER
358 *
359 ****************************************************************/
360void DataLogger::infoHandler()
361{
362 DimInfo* I = getInfo();
363 //there I should get the services updates. It remains unclear whether I will be getting the new services or not through here
364// CheckForServicesUpdate(); //in this function I will add/remove services subscription
365 CheckForRunNumber(I);
366 LogPlease(I);
367}
368//! Checks for changes in the existingn services
369//! @todo finish this function as most of it is still missing (plus what is already there isn't great)
370void DataLogger::CheckForServicesUpdate()
371{//TODO well... do it...
372 //TODO handle the cases were one server/service was removed and one was added
373 const std::vector<std::string> serverList = fServiceList.GetServerList();
374 if (serverList.size() != fServiceSubscriptions.size())
375 {//some servers were added/deleted. Rebuild the list entirely
376std::cout << "Redoing the server list entirely " << serverList.size() << " " << fServiceSubscriptions.size() << std::endl;
377 std::map<std::string, std::vector<DimStampedInfo> >::iterator it;
378 for (it=fServiceSubscriptions.begin(); it != fServiceSubscriptions.end(); it++)
379 (*it).second.clear();
380 fServiceSubscriptions.clear();
381 InitServiceSubscription();
382 return;
383 }
384 //TODO crawl the list to see if any of the servers has updated its service list
385
386}
387//! Looks whether the currently being processed DimInfo indeed is a run number or not
388void DataLogger::CheckForRunNumber(DimInfo* I)
389{
390 return;
391 if (strstr(I->getName(), runNumberInfo) != NULL)
392 {//assumes that the run number is an integer
393 //TODO check the format here
394 runNumber = I->getInt();
395 }
396}
397/****************************************************************
398 *
399 * DATA LOGGER'S RUN LOG
400 *
401 * write info to run log. Go to error if anything goes wrong
402 *
403 ****************************************************************/
404 //! write info to logs. Go to error if anything goes wrong
405void DataLogger::LogPlease(DimInfo* I)
406{
407 if (I->getSize() == 0)
408 return;
409 //TODO add service exclusion
410
411 if (!fDailyFile.is_open())
412 return;
413 //construct the header
414 std::stringstream header;
415 Time cTime((time_t)(I->getTimestamp()), 0);
416 header << I->getName() << " " << cTime.Y() << " " << cTime.M() << " " << cTime.D() << " ";
417 header << cTime.h() << " " << cTime.m() << " " << cTime.s() << " ";
418 header << cTime.ms() << " " << I->getQuality() << " ";
419
420 if (fDailyFile.is_open())
421 fDailyFile << header;
422 if (fRunFile.is_open())
423 fRunFile << header;
424
425
426 std::string text = ToString(I->getFormat(), I->getData(), I->getSize());
427
428 if (!text.empty())
429 {//replace bizarre characters by white space
430 for (unsigned int i=0; i<text.size(); i++)
431 {
432 if (text[i] == '\n')
433 text[i] = '\\';
434 else
435 if (iscntrl(text[i]))
436 text[i] = ' ';
437 }
438 if (fDailyFile.is_open())
439 fDailyFile << text;
440 if (fRunFile.is_open())
441 fRunFile << text;
442 }
443 else
444 {
445 if (fDailyFile.is_open())
446 fDailyFile << "Cannot interpret service format" << std::endl;
447 if (fRunFile.is_open())
448 fRunFile << "Cannot interpret service format" << std::endl;
449 }
450}
451//! Translates DIM data safely to string (assures no invalid memory accesses are made)
452//! Was mostly copied from DColl.cc
453std::string DataLogger::ToString(const char *format, const void *data, int size) {
454
455 std::ostringstream Text;
456
457 // Structure: print hex representation
458 if (strlen(format) != 1) {
459 for (int i=0; i<size; i++) {
460 Text << std::setw(2) << std::hex << *((char *) data + i) << " ";
461 }
462 return Text.str();
463 }
464
465 // String if format "C" and terminated with \0
466 if (strcmp(format, "C") == 0 && size > 0 && *((char *) data+size-1)=='\0') {
467 return std::string((char *) data);
468 }
469
470 // Number array
471 int ElementSize;
472 switch (*format) {
473 case 'C': ElementSize = sizeof(char); break;
474 case 'I':
475 case 'L': ElementSize = sizeof(int); break;
476 case 'S': ElementSize = sizeof(short); break;
477 case 'F': ElementSize = sizeof(float); break;
478 case 'D': ElementSize = sizeof(double); break;
479 case 'X': ElementSize = sizeof(long long); break;
480 default: return std::string();
481 }
482
483 for (int i=0; i<size/ElementSize; i++) {
484 // Space between entries
485 if (i != 0) Text << " ";
486
487 // Translate data
488 switch (*format) {
489 case 'C': Text << *((char *) data + i); break;
490 case 'I':
491 case 'L': Text << *((int *) data + i); break;
492 case 'S': Text << *((short *) data + i); break;
493 case 'F': Text << *((float *) data + i); break;
494 case 'D': Text << *((double *) data + i); break;
495 case 'X': Text << *((long long *) data + i); break;
496 }
497 }
498
499 return Text.str();
500}
501//! write messages to logs. Go to error if anything goes wrong
502int DataLogger::LogMessagePlease(const Event& evt)
503{
504 if (!fDailyFile.is_open())
505 return GetCurrentState();
506
507 std::stringstream header;
508 const Time& cTime = evt.GetTime();
509 header << evt.GetName() << " " << cTime.Y() << " " << cTime.M() << " " << cTime.D() << " ";
510 header << cTime.h() << " " << cTime.m() << " " << cTime.s() << " ";
511 header << cTime.ms() << " ";
512
513 if (fDailyFile.is_open())
514 fDailyFile << header;
515 if (fRunFile.is_open())
516 fRunFile << header;
517
518 std::string text = ToString(evt.GetFormat().c_str(), evt.GetData(), evt.GetSize());
519
520 if (!text.empty())
521 {//replace bizarre characters by white space
522 for (unsigned int i=0; i<text.size(); i++)
523 {
524 if (text[i] == '\n')
525 text[i] = '\\';
526 else
527 if (iscntrl(text[i]))
528 text[i] = ' ';
529 }
530 if (fDailyFile.is_open())
531 fDailyFile << text;
532 if (fRunFile.is_open())
533 fRunFile << text;
534 }
535 else
536 {
537 if (fDailyFile.is_open())
538 fDailyFile << "Cannot interpret log message format" << std::endl;
539 if (fRunFile.is_open())
540 fRunFile << "Cannot interpret log message format" << std::endl;
541 }
542
543 return GetCurrentState();
544}
545/****************************************************************
546 *
547 * DATA LOGGER'S RUN LOG
548 */
549 //!Set the current daily file name. This will NOT close any file
550 /*
551 ****************************************************************/
552int DataLogger::ConfigureDailyFileName(const Event& evt)
553{
554 fDailyFileName = std::string(evt.GetText());
555 return GetCurrentState();
556}
557/****************************************************************
558 *
559 * DATA LOGGER'S CONFIGURE RUN FILE NAME
560 *
561 */
562 //! Set the current run folder name. This will NOT close any file
563 /*
564 ****************************************************************/
565int DataLogger::ConfigureRunFileName(const Event& evt)
566{
567 fRunFileName = std::string(evt.GetText());
568 return GetCurrentState();
569}
570/****************************************************************
571 *
572 * DATA LOGGER'S CONFIGURE RUN NUMBER
573 *
574 */
575 //! set the current run number. This will NOT close any file.
576 /*
577 ****************************************************************/
578int DataLogger::ConfigureRunNumber(const Event& evt)
579{
580 runNumber = evt.GetInt();
581 //TODO replace the run number in the filename if already exist. Otherwise just append it
582 return GetCurrentState();
583}
584/****************************************************************
585 *
586 * DATA LOGGER'S START PLEASE
587 *
588 */
589 //! Implements the start transition
590 /*
591 ****************************************************************/
592int DataLogger::StartPlease()
593{
594 //TODO concatenate the dailyFileName and the formatted date and extension to obtain the full file name
595 Time time;//(Time::utc);
596 std::stringstream sTime;
597 sTime << time.Y() << "_" << time.M() << "_" << time.D();
598 std::string fullName = fDailyFileName + '/' + sTime.str() + ".log";
599
600 fDailyFile.open(fullName.c_str(), std::ios_base::out | std::ios_base::ate); //maybe should be "app" instead of "ate" ??
601 if (!fDailyFile.is_open())
602 {
603 //TODO send an error message
604 return kSM_BadDailyConfig;
605 }
606 return kSM_DailyOpen;
607}
608/****************************************************************
609 *
610 * DATA LOGGER'S STOP PLEASE
611 *
612 */
613 //! Implements the stop transition
614 /*
615 ****************************************************************/
616int DataLogger::StopPlease()
617{
618 if (fDailyFile.is_open())
619 fDailyFile.close();
620
621 if (fRunFile.is_open())
622 fRunFile.close();
623
624 return kSM_Ready;
625
626}
627/****************************************************************
628 *
629 * DATA LOGGER'S START RUN PLEASE
630 *
631 */
632 //! Implements the start run transtition
633 /*
634 ****************************************************************/
635int DataLogger::StartRunPlease()
636{
637 //attempt to open run file with current parameters
638 if (runNumber == -1)
639 return kSM_BadRunConfig;
640 std::stringstream sRun;
641 sRun << runNumber;
642 std::string fullName = fRunFileName + '/' + sRun.str() + ".log";
643
644 fRunFile.open(fullName.c_str(), std::ios_base::out | std::ios_base::ate); //maybe should be app instead of ate
645 if (!fRunFile.is_open())
646 {
647 //TODO send an error message
648 return kSM_BadRunConfig;
649 }
650
651 return kSM_Logging;
652}
653/****************************************************************
654 *
655 * DATA LOGGER'S STOP RUN PLEASE
656 *
657 */
658 //! Implements the stop run transition
659 /*
660 ****************************************************************/
661int DataLogger::StopRunPlease()
662{
663 if (!fRunFile.is_open())
664 return kSM_FatalError;
665
666 fRunFile.close();
667
668 return kSM_WaitingRun;
669
670}
671/****************************************************************
672 *
673 * DATA LOGGER'S RESET PLEASE
674 *
675 */
676 //! Implements the reset transition
677 /*
678 ****************************************************************/
679int DataLogger::ResetPlease()
680{
681 if (fDailyFile.is_open())
682 fDailyFile.close();
683
684 if (fRunFile.is_open())
685 fRunFile.close();
686
687 return kSM_Ready;
688}
689//! Implements the Daily to WaitRun transition
690int DataLogger::DailyToWaitRunPlease()
691{
692 return kSM_WaitingRun;
693}
694/*
695bool DataLogger::ServiceOk(DimInfo* item)
696{
697 return !((item->getSize() == strlen(NO_LINK)+1) && (memcmp(item->getData(), NO_LINK, item->getSize()) == 0));
698}*/
699/****************************************************************
700 *
701 * MAIN
702 *
703 ****************************************************************/
704extern bool CheckDim(bool=true);
705
706int main()
707{
708 std::cout << "Data Logger Starting" << std::endl;
709
710 if (!CheckDim())
711 return -1;
712
713 std::cout << "Continuing" << std::endl;
714 DataLogger log;
715 std::cout << "DataLogger created. Starting main loop" << std::endl;
716 while (!log.IsRExitRequested())
717 {
718 usleep(1);
719 }
720 return 0;
721
722}
Note: See TracBrowser for help on using the repository browser.