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

Last change on this file since 10442 was 10442, checked in by lyard, 9 years ago
Added dataLogger services and use only one file for fits runs
File size: 45.1 KB
Line 
1//****************************************************************
2/** @class DataLogger
3 
4  @brief Logs all message and infos between the services
5 
6  This is the main logging class facility.
7  It derives from StateMachineDim and DimInfoHandler. the first parent is here to enforce
8  a state machine behaviour, while the second one is meant to make the dataLogger receive
9  dim services to which it subscribed from.
10  The possible states and transitions of the machine are:
11  \dot
12  digraph datalogger {
13                node [shape=record, fontname=Helvetica, fontsize=10];
14        e [label="Error" color="red"];
15   r [label="Ready"]
16   d [label="DailyOpen"]
17   w [label="WaitingRun"]
18        l [label="Logging"]
19   b [label="BadDailyconfig" color="red"]
20   c [label="BadRunConfig" color="red"]
21 
22  e -> r
23  r -> e
24  r -> d
25  r -> b
26  d -> w
27  d -> r
28  w -> r
29  l -> r
30  l -> w
31  b -> d
32  w -> c
33  w -> l
34  b -> r
35  c -> r
36  c -> l
37  }
38  \enddot
39 
40  @todo
41        - Retrieve also the messages, not only the infos
42 */
43 //****************************************************************
44#include "Event.h"
45#include "Time.h"
46#include "StateMachineDim.h"
47#include "WindowLog.h"
48#include "Configuration.h"
49#include "ServiceList.h"
50#include "Converter.h"
51#include "MessageImp.h"
52#include "LocalControl.h"
53
54#include "Description.h"
55
56//for getting stat of opened files
57#include <unistd.h>
58//for getting disk free space
59#include <sys/statvfs.h>
60//for getting files sizes
61#include <sys/stat.h>
62
63//#define HAS_FITS
64
65#include <fstream>
66
67#include <boost/bind.hpp>
68#include <boost/thread.hpp>
69
70#ifdef HAS_FITS
71//#include <astroroot.h>
72#include "Fits.h"
73#endif
74
75class DataLogger : public StateMachineDim, DimInfoHandler
76{
77public:
78        /// The list of existing states specific to the DataLogger
79        enum
80        {
81                kSM_DailyOpen = 20, ///< Daily file openned and writing
82                kSM_WaitingRun = 30, ///< waiting for the run number to open the run file
83                kSM_Logging = 40, ///< both files openned and writing
84                kSM_BadDailyConfig = 0x101, ///< the folder specified for daily logging does not exist or has bad permissions
85                kSM_BadRunConfig = 0x102, ///<  the folder specified for the run logging does not exist or has wrong permissions or no run number
86        } localstates_t;
87       
88        DataLogger(std::ostream &out);
89        ~DataLogger(); 
90       
91private:
92        //Define all the data structure specific to the DataLogger here
93        /// ofstream for the dailyLogfile
94        std::ofstream fDailyLogFile;
95        /// ofstream for the run-specific Log file
96        std::ofstream fRunLogFile; 
97
98        /// ofstream for the daily report file
99        std::ofstream fDailyReportFile;
100        /// ofstream for the run-specific report file
101        std::ofstream fRunReportFile;
102        /// base path of the dailyfile
103        std::string fDailyFileName; 
104        ///base path of the run file
105        std::string fRunFileName; 
106        ///run number (-1 means no run number specified)
107        int fRunNumber; 
108        ///Current year
109//      short fYear;
110        ///Current Month
111//      short fMonth;
112        ///Current Day
113//      short fDay;
114        ///Current Hour
115//      short fHour;
116        ///Current Minute
117//      short fMin;
118        ///Current Second
119//      short fSec;
120        ///Current Milliseconds
121//      int fMs;
122        ///Current Service Quality
123        int fQuality;
124        ///Modified Julian Date
125        double fMjD;
126       
127        ///Define all the static names
128        static const char* fConfigDay;
129        static const char* fConfigRun;
130        static const char* fConfigRunNumber;
131        static const char* fConfigLog;
132        static const char* fTransStart;
133        static const char* fTransStop;
134        static const char* fTransStartRun;
135        static const char* fTransStopRun;
136        static const char* fTransReset;
137        static const char* fTransWait;
138        static const char* fRunNumberInfo; ///< This is the name of the dimInfo received to specify the run number. It must be updated once the final name will be defined
139        ///Inherited from state machine impl
140        int Execute(); 
141       
142        ///Inherited from state machine impl
143        int Transition(const Event& evt); 
144       
145        ///Inherited from state machine impl
146        int Configure(const Event& evt); 
147       
148        //overloading of DIM's infoHandler function
149        void infoHandler(); 
150       
151        ///for obtaining the name of the existing services
152        ServiceList fServiceList;
153       
154       
155        ///A std pair to store both the DimInfo name and the actual DimInfo pointer
156//      typedef std::pair<std::string, DimStampedInfo*> subscriptionType;
157        ///All the services to which we've subscribed to. Sorted by server name
158//      std::map<const std::string, std::vector<subscriptionType > > fServiceSubscriptions;
159
160        ///A std pair to store both the DimInfo pointer and the corresponding outputted fits file
161        struct SubscriptionType
162        { 
163#ifdef HAS_FITS
164                ///daily FITS output file
165                Fits    dailyFile;
166                ///run-specific FITS output file
167                Fits    runFile;
168#endif
169                ///the actual dimInfo pointer
170                DimStampedInfo* dimInfo;
171                ///the converter for outputting the data according to the format
172                Converter* fConv;
173                ///the number of existing handlers to this structure.
174                ///This is required otherwise I MUST handle the deleting of dimInfo outside from the destructor
175                int* numCopies;
176                void operator = (const SubscriptionType& other)
177                {
178#ifdef HAS_FITS
179                        dailyFile = other.dailyFile;
180                        runFile = other.runFile;
181#endif
182                        dimInfo = other.dimInfo;       
183                        numCopies = other.numCopies;
184                        fConv = other.fConv;
185                        (*numCopies)++;
186                }
187                SubscriptionType(const SubscriptionType& other)
188                {
189#ifdef HAS_FITS
190                        dailyFile = other.dailyFile;
191                        runFile = other.runFile;
192#endif
193                        dimInfo = other.dimInfo;
194                        numCopies = other.numCopies;
195                        fConv = other.fConv;
196                        (*numCopies)++; 
197                }
198                SubscriptionType(DimStampedInfo* info)
199                {
200                        dimInfo = info; 
201                        fConv = NULL;
202                        numCopies = new int(1);
203                }
204                SubscriptionType()
205                {
206                        dimInfo = NULL;
207                        fConv = NULL;
208                        numCopies = new int(1);
209                }
210                ~SubscriptionType()
211                {
212                        if (numCopies)
213                        (*numCopies)--;
214                        if (numCopies)
215                        if (*numCopies < 1)
216                        {
217#ifdef HAS_FITS
218                                if (dailyFile.IsOpen())
219                                        dailyFile.Close();
220                                if (runFile.IsOpen())
221                                        runFile.Close();
222#endif
223                                if (dimInfo)
224                                delete dimInfo;
225                                if (numCopies) 
226                                delete numCopies;
227                                delete fConv;
228                                fConv = NULL;
229                                dimInfo = NULL;
230                                numCopies = NULL;
231                        }
232                }
233        };
234        typedef std::map<const std::string, std::map<std::string, SubscriptionType>> SubscriptionsListType;
235        ///All the services to which we have subscribed to, sorted by server name.
236        SubscriptionsListType fServiceSubscriptions;
237
238
239        ///Reporting method for the services info received
240        void ReportPlease(DimInfo* I, SubscriptionType& sub); 
241
242        ///Configuration of the daily file path
243        int ConfigureDailyFileName(const Event& evt); 
244        ///Configuration fo the file name
245        int ConfigureRunFileName(const Event& evt); 
246        ///DEPREC - configuration of the run number
247        int ConfigureRunNumber(const Event& evt); 
248        ///logging method for the messages
249        int LogMessagePlease(const Event& evt); 
250        ///checks whether or not the current info being treated is a run number
251        void CheckForRunNumber(DimInfo* I); 
252        /// start transition
253        int StartPlease(); 
254        ///from waiting to logging transition
255        int StartRunPlease(); 
256        /// from logging to waiting transition
257        int StopRunPlease(); 
258        ///stop and reset transition
259        int GoToReadyPlease(); 
260        ///from dailyOpen to waiting transition
261        int DailyToWaitRunPlease(); 
262#ifdef HAS_FITS
263        ///Open fits files
264        void OpenFITSFilesPlease(SubscriptionType& sub);
265        ///Write data to FITS files
266        void WriteToFITS(SubscriptionType& sub);
267        ///Allocate the buffers required for fits
268        void AllocateFITSBuffers(SubscriptionType& sub);
269        ///FITS file for runs. only one, hence dealt with in the dataLogger itself
270        FITS* fRunFitsFile;
271#endif
272public: 
273        ///checks with fServiceList whether or not the services got updated
274        void CheckForServicesUpdate(); 
275
276private:       
277        ///monitoring notification loop
278        void ServicesMonitoring();
279        ///services notification thread
280        boost::thread fMonitoringThread;
281        ///end of the monitoring
282        bool fContinueMonitoring;
283        ///required for accurate monitoring
284        std::map<std::string, long long> fFileSizesMap;
285        std::string fFullDailyLogFileName;
286        std::string fFullDailyReportFileName;
287        std::string fFullRunLogFileName;
288        std::string fFullRunReportFileName;
289        long long fBaseSizeDaily;
290        long long fPreviousSize;
291        long long fBaseSizeRun;
292        ///Service for opened files
293        DimService* fOpenedFiles;
294        char* fDimBuffer;
295        inline void NotifyOpenedFile(std::string name, int type);
296       
297}; //DataLogger
298
299//static members initialization
300//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 ?
301const char* DataLogger::fConfigDay = "CONFIG_DAY";
302const char* DataLogger::fConfigRun = "CONFIG_RUN";
303const char* DataLogger::fConfigRunNumber = "CONFIG_RUN_NUMBER";
304const char* DataLogger::fConfigLog = "LOG";
305const char* DataLogger::fTransStart = "START";
306const char* DataLogger::fTransStop = "STOP";
307const char* DataLogger::fTransStartRun = "START_RUN";
308const char* DataLogger::fTransStopRun = "STOP_RUN";
309const char* DataLogger::fTransReset = "RESET";
310const char* DataLogger::fTransWait = "WAIT_RUN_NUMBER";
311const char* DataLogger::fRunNumberInfo = "RUN_NUMBER";
312
313void DataLogger::ServicesMonitoring()
314{
315                //create the DIM service
316                int dataSize = 2*sizeof(long long) + sizeof(long);
317                char* data = new char[dataSize];
318                memset(data, 0, dataSize);
319                DimService srvc("DATALOGGER/STATS", "x:2;l:1", static_cast<void*>(data), dataSize);
320                double deltaT = 1;
321                fPreviousSize = 0;
322
323                long long& targetSize  = reinterpret_cast<long long*>(data)[0];
324                long long& targetFreeSpace  = reinterpret_cast<long long*>(data)[1];
325                long& targetRate = reinterpret_cast<long*>(data + 2*sizeof(long long))[0];
326                //loop-wait for broadcast
327                while (fContinueMonitoring)
328                {
329                        sleep(deltaT);
330                        //update the fits files sizes
331#ifdef HAS_FITS
332                        SubscriptionsListType::iterator x;
333                        std::map<std::string, SubscriptionType>::iterator y;
334                        bool runFileDone = false;
335                        for (x=fServiceSubscriptions.begin(); x != fServiceSubscriptions.end(); x++)
336                        {
337                                for (y=x->second.begin(); y != x->second.end(); y++)
338                                {
339                                        if (y->second.runFile.IsOpen() && !runFileDone)
340                                        {
341                                                        fFileSizesMap[y->second.runFile.fFileName] = y->second.runFile.GetWrittenSize();
342                                                        runFileDone = true;
343                                        }
344                                        if (y->second.dailyFile.IsOpen())
345                                                fFileSizesMap[y->second.dailyFile.fFileName] = y->second.dailyFile.GetWrittenSize();
346                                }
347                        }
348#endif
349                        struct stat st;
350                        //gather log and report files sizes on disk
351                        if (fDailyLogFile.is_open())
352                        {
353                                stat(fFullDailyLogFileName.c_str(), &st);
354                                fFileSizesMap[fFullDailyLogFileName] = st.st_size;     
355                        }
356                        if (fDailyReportFile.is_open())
357                        {
358                                stat(fFullDailyReportFileName.c_str(), &st);
359                                fFileSizesMap[fFullDailyReportFileName] = st.st_size;   
360                        }
361                        if (fRunLogFile.is_open())
362                        {
363                                stat(fFullRunLogFileName.c_str(), &st);
364                                fFileSizesMap[fFullRunLogFileName] = st.st_size;       
365                        }
366                        if (fRunReportFile.is_open())
367                        {
368                                stat(fFullRunReportFileName.c_str(), &st);
369                                fFileSizesMap[fFullRunReportFileName] = st.st_size;
370                        }       
371                        if (fDailyLogFile.is_open())
372                        {
373                                struct statvfs vfs;
374                                statvfs(fDailyFileName.c_str(), &vfs);
375                                targetFreeSpace = vfs.f_bsize*vfs.f_bavail;
376                        }
377                        //sum up all the file sizes. past and present
378                        targetSize = 0;
379                        for (std::map<std::string, long long>::iterator it=fFileSizesMap.begin(); it != fFileSizesMap.end();  it++)
380                                targetSize += it->second;
381                        targetSize -= fBaseSizeDaily;
382                        targetSize -= fBaseSizeRun;
383                        //FIXME get the actual time elapsed
384                        targetRate = (targetSize - fPreviousSize)/deltaT; 
385                        fPreviousSize = targetSize;
386                        if (targetRate != 0) //if data has been written
387                        {
388std::cout << "fBaseSizeDaily: " << fBaseSizeDaily << " fBaseSizeRun: " << fBaseSizeRun << std::endl;
389//std::cout << "Written Size: " << targetSize << ", free space: " << targetFreeSpace << ", data rate: " << targetRate << " Bytes/s" << std::endl;
390
391                                srvc.updateService(static_cast<void*>(data), dataSize);
392                        }
393                }
394                delete[] data;
395}
396
397
398// --------------------------------------------------------------------------
399//
400//! Default constructor. The name of the machine is given DATA_LOGGER
401//! and the state is set to kSM_Ready at the end of the function.
402//
403//!Setup the allows states, configs and transitions for the data logger
404//
405DataLogger::DataLogger(std::ostream &out) : StateMachineDim(out, "DATA_LOGGER")
406{       
407                //initialize member data
408                fDailyFileName = "/home/lyard/log";
409                fRunFileName = "/home/lyard/log";
410                fRunNumber = 12345;
411#ifdef HAS_FITS
412                fRunFitsFile = NULL;
413#endif
414                //Give a name to this machine's specific states
415                AddStateName(kSM_DailyOpen,      "DailyFileOpen");
416                AddStateName(kSM_WaitingRun,     "WaitForRun");
417                AddStateName(kSM_Logging,        "Logging");
418                AddStateName(kSM_BadDailyConfig, "ErrDailyFolder");
419                AddStateName(kSM_BadRunConfig,   "ErrRunFolder");
420
421        /*Add the possible transitions for this machine*/
422
423        //start the daily logging. daily file location must be specified already
424                AddTransition(kSM_DailyOpen, fTransStart, kSM_Ready, kSM_BadDailyConfig). 
425                    AssignFunction(boost::bind(&DataLogger::StartPlease, this));
426
427        //stop the data logging
428                AddTransition(kSM_Ready, fTransStop, kSM_DailyOpen, kSM_WaitingRun, kSM_Logging). 
429                    AssignFunction(boost::bind(&DataLogger::GoToReadyPlease, this));
430
431        //start the run logging. run file location must be specified already.
432        AddTransition(kSM_Logging, fTransStartRun, kSM_WaitingRun, kSM_BadRunConfig).
433                    AssignFunction(boost::bind(&DataLogger::StartRunPlease, this));
434
435        AddTransition(kSM_WaitingRun, fTransStopRun, kSM_Logging).
436                    AssignFunction(boost::bind(&DataLogger::StopRunPlease, this));
437
438        //transition to exit error states. dunno if required or not, would close the daily file if already openned.
439                AddTransition(kSM_Ready, fTransReset, kSM_Error, kSM_BadDailyConfig, kSM_BadRunConfig, kSM_Error).
440                    AssignFunction(boost::bind(&DataLogger::GoToReadyPlease, this));
441
442        AddTransition(kSM_WaitingRun, fTransWait, kSM_DailyOpen).
443                    AssignFunction(boost::bind(&DataLogger::DailyToWaitRunPlease, this));
444
445        /*Add the possible configurations for this machine*/
446       
447        //configure the daily file location. cannot be done before the file is actually opened
448                AddConfiguration(fConfigDay, "C", kSM_Ready, kSM_BadDailyConfig).
449                    AssignFunction(boost::bind(&DataLogger::ConfigureDailyFileName, this, _1));
450
451        //configure the run file location. cannot be done before the file is actually opened, and not in a dailly related error.
452                AddConfiguration(fConfigRun, "C", kSM_Ready, kSM_BadDailyConfig, kSM_DailyOpen, kSM_WaitingRun, kSM_BadRunConfig).
453                    AssignFunction(boost::bind(&DataLogger::ConfigureRunFileName, this, _1));
454
455                //Provide a logging command
456                //I get the feeling that I should be going through the EventImp
457                //instead of DimCommand directly, mainly because the commandHandler
458                //is already done in StateMachineImp.cc
459                //Thus I'll simply add a configuration, which I will treat as the logging command
460                AddConfiguration(fConfigLog, "C", kSM_DailyOpen, kSM_Logging, kSM_WaitingRun, kSM_BadRunConfig).
461                    AssignFunction(boost::bind(&DataLogger::LogMessagePlease, this, _1));
462
463                fServiceList.SetHandler(this);
464                CheckForServicesUpdate();
465               
466                //start the monitoring service
467                fContinueMonitoring = true;
468                fMonitoringThread = boost::thread(boost::bind(&DataLogger::ServicesMonitoring, this));
469                fBaseSizeDaily = 0;
470                fBaseSizeRun = 0;
471                //start the open files service
472                fDimBuffer = new char[256];
473                memset(fDimBuffer, 0, sizeof(int));
474                fDimBuffer[sizeof(int)] = '\0';
475                //gives the entire buffer size. Otherwise, dim overwrites memory at bizarre locations if smaller size is given at creation time.
476                fOpenedFiles =  new DimService("DATALOGGER/FILENAME", "i:1;C", static_cast<void*>(fDimBuffer), 256);
477               
478               
479}
480// --------------------------------------------------------------------------
481//
482//! Checks for changes in the existing services.
483//! Any new service will be added to the service list, while the ones which disappeared are removed.
484//! @todo
485//!     add the configuration (using the conf class ?)
486//
487//FIXME The service must be udpated so that I get the first notification. This should not be
488void DataLogger::CheckForServicesUpdate()
489{ 
490
491        //get the current server list
492        const std::vector<std::string> serverList = fServiceList.GetServerList();
493        //first let's remove the servers that may have disapeared
494        //can't treat the erase on maps the same way as for vectors. Do it the safe way instead
495        std::vector<std::string> toBeDeleted;
496        for (SubscriptionsListType::iterator cListe = fServiceSubscriptions.begin(); cListe != fServiceSubscriptions.end(); cListe++)
497        {
498                std::vector<std::string>::const_iterator givenServers;
499                for (givenServers=serverList.begin(); givenServers!= serverList.end(); givenServers++)
500                        if (cListe->first == *givenServers)
501                                break;
502                if (givenServers == serverList.end())//server vanished. Remove it
503                        toBeDeleted.push_back(cListe->first);
504        }
505        for (std::vector<std::string>::const_iterator it = toBeDeleted.begin(); it != toBeDeleted.end(); it++)
506                fServiceSubscriptions.erase(*it);
507
508        //now crawl through the list of servers, and see if there was some updates
509        for (std::vector<std::string>::const_iterator i=serverList.begin(); i!=serverList.end();i++)
510        {
511                //skip the two obvious excluded services
512                if ((i->find("DIS_DNS") != std::string::npos) ||
513                    (i->find("DATA_LOGGER") != std::string::npos))
514                        continue;
515                //find the current server in our subscription list     
516                SubscriptionsListType::iterator cSubs = fServiceSubscriptions.find(*i);
517                //get the service list of the current server
518                std::vector<std::string> cServicesList = fServiceList.GetServiceList(*i);
519                if (cSubs != fServiceSubscriptions.end())//if the current server already is in our subscriptions
520                {                                                                                //then check and update our list of subscriptions
521                        //first, remove the services that may have dissapeared.
522                        std::map<std::string, SubscriptionType>::iterator serverSubs;
523                        std::vector<std::string>::const_iterator givenSubs;
524                        toBeDeleted.clear();
525                        for (serverSubs=cSubs->second.begin(); serverSubs != cSubs->second.end(); serverSubs++)
526                        {
527                                for (givenSubs = cServicesList.begin(); givenSubs != cServicesList.end(); givenSubs++)
528                                        if (serverSubs->first == *givenSubs)
529                                                break;
530                                if (givenSubs == cServicesList.end())
531                                {
532                                        toBeDeleted.push_back(serverSubs->first);
533                                }       
534                        }
535                        for (std::vector<std::string>::const_iterator it = toBeDeleted.begin(); it != toBeDeleted.end(); it++)
536                                cSubs->second.erase(*it);
537                        //now check for new services
538                        for (givenSubs = cServicesList.begin(); givenSubs != cServicesList.end(); givenSubs++)
539                        {
540                                if (*givenSubs == "SERVICE_LIST")
541                                        continue;
542                                if (cSubs->second.find(*givenSubs) == cSubs->second.end())
543                                {//service not found. Add it
544                                        cSubs->second[*givenSubs].dimInfo = new DimStampedInfo(((*i) + "/" + *givenSubs).c_str(), const_cast<char*>(""), this);
545                                }       
546                        }
547                }
548                else //server not found in our list. Create its entry
549                {
550                        fServiceSubscriptions[*i] = std::map<std::string, SubscriptionType>();
551                        std::map<std::string, SubscriptionType>& liste = fServiceSubscriptions[*i];
552                        for (std::vector<std::string>::const_iterator j = cServicesList.begin(); j!= cServicesList.end(); j++)
553                        {
554                                if (*j == "SERVICE_LIST")
555                                        continue;
556                                liste[*j].dimInfo = new DimStampedInfo(((*i) + "/" + (*j)).c_str(), const_cast<char*>(""), this);
557                        }
558                }       
559        }
560}
561// --------------------------------------------------------------------------
562//
563//! Destructor
564//
565DataLogger::~DataLogger()
566{
567        //exit the monitoring loop
568        fContinueMonitoring = false;
569        delete[] fDimBuffer;
570        delete fOpenedFiles;
571        fMonitoringThread.join();
572        //close the files
573        if (fDailyLogFile.is_open())
574                fDailyLogFile.close();
575        if (fDailyReportFile.is_open())
576                fDailyReportFile.close();
577        if (fRunLogFile.is_open())
578                fRunLogFile.close();
579        if (fRunReportFile.is_open())
580                fRunReportFile.close();
581        //release the services subscriptions
582        fServiceSubscriptions.clear();
583#ifdef HAS_FITS
584        if (fRunFitsFile != NULL)
585                delete fRunFitsFile;
586        fRunFitsFile = NULL;
587#endif
588}
589// --------------------------------------------------------------------------
590//
591//! Execute
592//! Shouldn't be run as we use callbacks instead
593//
594int DataLogger::Execute()
595{
596        //due to the callback mecanism, this function should never be called
597        return kSM_FatalError;
598       
599        switch (GetCurrentState())
600        {
601        case kSM_Error:
602        case kSM_Ready:
603        case kSM_DailyOpen:
604        case kSM_WaitingRun:
605        case kSM_Logging:
606        case kSM_BadDailyConfig:
607        case kSM_BadRunConfig:
608                return GetCurrentState();
609        }
610        //this line below should never be hit. It here mainly to remove warnings at compilation
611        return kSM_FatalError;
612}
613// --------------------------------------------------------------------------
614//
615//! Shouldn't be run as we use callbacks instead
616//
617 int DataLogger::Transition(const Event& evt)
618{
619        //due to the callback mecanism, this function should never be called
620        return kSM_FatalError;
621       
622        switch (evt.GetTargetState())
623        {
624                case kSM_Ready:
625                /*here we must figure out whether the STOP or RESET command was sent*/
626                /*close opened files and go back to ready state*/
627                        switch (GetCurrentState())
628                        {
629                                case kSM_BadDailyConfig:
630                                case kSM_BadRunConfig:
631                                case kSM_Error:
632                                        return GoToReadyPlease();
633                                       
634                                case kSM_Logging:
635                                case kSM_WaitingRun:
636                                case kSM_DailyOpen:
637                                        return GoToReadyPlease();
638                        }
639                break;
640               
641                case kSM_DailyOpen:
642                        /*Attempt to open the daily file */
643                        switch (GetCurrentState())
644                        {
645                                case kSM_Ready:
646                                case kSM_BadDailyConfig:
647                                        return StartPlease();   
648                        }
649                break;
650               
651                case kSM_WaitingRun:
652                        /*either close the run file, or just go to the waitingrun state (if coming from daily open*/
653                        switch (GetCurrentState())
654                        {
655                                case kSM_DailyOpen:
656                                        return kSM_WaitingRun;
657                               
658                                case kSM_Logging:
659                                        return StopRunPlease(); 
660                        }
661                break;
662               
663                case kSM_Logging:
664                        /*Attempt to open run file */
665                        switch (GetCurrentState())
666                        {
667                                case kSM_WaitingRun:
668                                case kSM_BadRunConfig:
669                                        return StartRunPlease();
670                        }       
671                break;
672        }
673        //Getting here means that an invalid transition has been asked.
674        //TODO Log an error message
675        //and return the fatal error state
676        return kSM_FatalError;
677}
678// --------------------------------------------------------------------------
679//
680//! Shouldn't be run as we use callbacks instead
681//
682 int DataLogger::Configure(const Event& evt)
683{
684        //due to the callback mecanism, this function should never be called
685        return kSM_FatalError;
686
687        switch (evt.GetTargetState())
688        {
689                case kSM_Ready:
690                case kSM_BadDailyConfig:
691                        return ConfigureDailyFileName(evt);
692                break;
693               
694                case kSM_WaitingRun:
695                case kSM_BadRunConfig:
696                        return ConfigureRunFileName(evt);       
697                break;
698               
699                case kSM_Logging:
700                case kSM_DailyOpen:
701                                return 0;
702                break;
703
704        }       
705
706        return kSM_FatalError;
707}
708// --------------------------------------------------------------------------
709//
710//! Inherited from DimInfo. Handles all the Infos to which we subscribed, and log them
711//
712void DataLogger::infoHandler()
713{
714        DimInfo* I = getInfo();
715        if (I==NULL)
716        {
717                CheckForServicesUpdate();
718                return;
719        }
720        //check if the service pointer corresponds to something that we subscribed to
721        //this is a fix for a bug that provides bad Infos when a server starts
722        bool found = false;
723        SubscriptionsListType::iterator x;
724        std::map<std::string, SubscriptionType>::iterator y;
725        for (x=fServiceSubscriptions.begin(); x != fServiceSubscriptions.end(); x++)
726        {//find current service is subscriptions
727                for (y=x->second.begin(); y!=x->second.end();y++)
728                        if (y->second.dimInfo == I)
729                        {
730                                found = true;   
731                                break;
732                        }
733                if (found)
734                        break;
735        }
736        if (!found)
737                return;
738        if (I->getSize() <= 0)
739                return;
740        //check that the message has been updated by something, i.e. must be different from its initial value
741        if (I->getTimestamp() == 0)
742                return;
743
744        CheckForRunNumber(I);
745        ReportPlease(I, y->second);
746
747}
748
749// --------------------------------------------------------------------------
750//
751//! Checks whether or not the current info is a run number.
752//! If so, then remember it. A run number is required to open the run-log file
753//! @param I
754//!             the current DimInfo
755//
756void DataLogger::CheckForRunNumber(DimInfo* I)
757{
758        if (strstr(I->getName(), fRunNumberInfo) != NULL)
759        {//assumes that the run number is an integer
760                //TODO check the format here
761                fRunNumber = I->getInt();       
762        }
763}
764
765// --------------------------------------------------------------------------
766//
767//! write infos to log files.
768//! @param I
769//!     The current DimInfo
770//
771void DataLogger::ReportPlease(DimInfo* I, SubscriptionType& sub)
772{
773        //should we log or report this info ? (i.e. is it a message ?)
774        bool isItaReport = ((strstr(I->getName(), "Message") == NULL) && (strstr(I->getName(), "MESSAGE") == NULL));
775       
776        //TODO add service exclusion
777       
778        if (!fDailyReportFile.is_open())
779                return;
780
781        //create the converter for that service
782        if (sub.fConv == NULL)
783        {
784                sub.fConv = new Converter(Out(), I->getFormat());       
785                if (!sub.fConv)
786                {
787                        Error("Couldn't properly parse the format... service ignored.");
788                        return; 
789                }
790        }
791               
792        //construct the header
793        std::stringstream header;
794        Time cTime(I->getTimestamp(), I->getTimestampMillisecs()*1000);
795        fQuality = I->getQuality();
796        fMjD = cTime.Mjd();
797
798        if (isItaReport)
799        {
800                //write text header
801                header << I->getName() << " " << fQuality << " ";
802                header << cTime.Y() << " " << cTime.M() << " " << cTime.D() << " ";
803                header << cTime.h() << " " << cTime.m() << " " << cTime.s() << " ";
804                header << cTime.ms() << " " << I->getTimestamp() << " ";
805
806                std::string text;
807        try
808        {
809                text = sub.fConv->GetString(I->getData(), I->getSize());
810        }
811        catch (const std::runtime_error &e)
812        {
813                Out() << kRed << e.what() << endl;
814            Error("Couldn't properly parse the data... ignored.");
815            return;
816        }
817
818                if (text.empty())
819                return;
820
821        //replace bizarre characters by white space
822        replace(text.begin(), text.end(), '\n', '\\');
823        replace_if(text.begin(), text.end(), std::ptr_fun<int, int>(&std::iscntrl), ' ');
824       
825                if (fDailyReportFile.is_open())
826                        fDailyReportFile << header.str();
827                if (fRunReportFile.is_open())
828                        fRunReportFile << header.str();
829
830        if (fDailyReportFile.is_open())
831                        fDailyReportFile << text << std::endl;
832                if (fRunReportFile.is_open())
833                        fRunReportFile << text << std::endl;
834        }
835        else
836        {
837                std::string n = I->getName();
838                std::stringstream msg;
839                msg << n.substr(0, n.find_first_of('/')) << ": " << I->getString();
840                MessageImp dailyMess(fDailyLogFile);
841                dailyMess.Write(cTime, msg.str().c_str(), fQuality);
842                if (fRunLogFile.is_open())
843                {
844                        MessageImp runMess(fRunLogFile);
845                        runMess.Write(cTime, msg.str().c_str(), fQuality);
846                }
847        }
848
849#ifdef HAS_FITS
850        if (!sub.dailyFile.IsOpen() || !sub.runFile.IsOpen())
851                OpenFITSFilesPlease(sub);       
852        WriteToFITS(sub);
853               
854#endif
855
856}
857// --------------------------------------------------------------------------
858//
859//! write messages to logs.
860//! @param evt
861//!             the current event to log
862//! @returns
863//!             the new state. Currently, always the current state
864//!
865//! @deprecated
866//!    I guess that this function should not be any longer
867//
868//TODO isn't that function not used any longer ? If so I guess that we should get rid of it...
869int DataLogger::LogMessagePlease(const Event& evt)
870{
871        if (!fDailyLogFile.is_open())
872                return GetCurrentState();
873       
874        std::stringstream header;
875        const Time& cTime = evt.GetTime();
876        header << evt.GetName() << " " << cTime.Y() << " " << cTime.M() << " " << cTime.D() << " ";
877        header << cTime.h() << " " << cTime.m() << " " << cTime.s() << " ";
878        header << cTime.ms() << " ";
879               
880    const Converter conv(Out(), evt.GetFormat());
881    if (!conv)
882    {
883        Error("Couldn't properly parse the format... ignored.");
884        return GetCurrentState();
885    }
886
887    std::string text;
888    try
889    {
890        text = conv.GetString(evt.GetData(), evt.GetSize());
891    }
892    catch (const std::runtime_error &e)
893    {
894        Out() << kRed << e.what() << endl;
895        Error("Couldn't properly parse the data... ignored.");
896        return GetCurrentState();
897    }
898
899        if (text.empty())
900        return GetCurrentState();
901
902    //replace bizarre characters by white space
903    replace(text.begin(), text.end(), '\n', '\\');
904    replace_if(text.begin(), text.end(), std::ptr_fun<int, int>(&std::iscntrl), ' ');
905
906        if (fDailyLogFile.is_open())
907                fDailyLogFile << header;
908        if (fRunLogFile.is_open())
909                fRunLogFile << header;
910
911        if (fDailyLogFile.is_open())
912                fDailyLogFile << text;
913        if (fRunLogFile.is_open())
914                fRunLogFile << text;
915
916        return GetCurrentState();
917}
918// --------------------------------------------------------------------------
919//
920//!     Sets the path to use for the daily log file.
921//! @param evt
922//!     the event transporting the path
923//! @returns
924//!             currently only the current state.
925//
926int DataLogger::ConfigureDailyFileName(const Event& evt)
927{
928        if (evt.GetText() != NULL)
929                fDailyFileName = std::string(evt.GetText());   
930        else
931                Error("Empty daily folder");
932
933        return GetCurrentState();
934}
935// --------------------------------------------------------------------------
936//
937//! Sets the path to use for the run log file.
938//! @param evt
939//!             the event transporting the path
940//! @returns
941//!     currently only the current state
942int DataLogger::ConfigureRunFileName(const Event& evt)
943{
944        if (evt.GetText() != NULL)
945                fRunFileName = std::string(evt.GetText());
946        else
947                Error("Empty daily folder");
948
949        return GetCurrentState();
950}
951// --------------------------------------------------------------------------
952//
953//! Sets the run number.
954//! @param evt
955//!             the event transporting the run number
956//! @returns
957//!     currently only the current state
958int DataLogger::ConfigureRunNumber(const Event& evt)
959{
960        fRunNumber = evt.GetInt();
961
962        return GetCurrentState();
963}
964// --------------------------------------------------------------------------
965//
966//! Notifies the DIM service that a particular file was opened
967//! @ param name the base name of the opened file, i.e. without path nor extension.
968//!     WARNING: use string instead of string& because I pass values that do not convert to string&.
969//!             this is not a problem though because file are not opened so often.
970//! @ param type the type of the opened file. 0 = none open, 1 = log, 2 = text, 4 = fits
971inline void DataLogger::NotifyOpenedFile(std::string name, int type)
972{
973//std::cout << "name: " << name << " size: " << name.size() << std::endl;
974        reinterpret_cast<int*>(fDimBuffer)[0] = type;
975        strcpy(&fDimBuffer[sizeof(int)], name.c_str());
976        fOpenedFiles->updateService(static_cast<void*>(fDimBuffer), name.size() + 1 + sizeof(int));
977}
978// --------------------------------------------------------------------------
979//
980//! Implements the Start transition.
981//! Concatenates the given path for the daily file and the filename itself (based on the day),
982//! and tries to open it.
983//! @returns
984//!             kSM_DailyOpen if success, kSM_BadDailyConfig if failure
985int DataLogger::StartPlease()
986{
987        //TODO concatenate the dailyFileName and the formatted date and extension to obtain the full file name
988        Time time;//(Time::utc);
989        std::stringstream sTime;
990        sTime << time.Y() << "_" << time.M() << "_" << time.D();
991        fFullDailyLogFileName = fDailyFileName + '/' + sTime.str() + ".log"; 
992       
993        fDailyLogFile.open(fFullDailyLogFileName.c_str(), std::ios_base::out | std::ios_base::app); //maybe should be "app" instead of "ate" ??
994        fFullDailyReportFileName = fDailyFileName + '/' + sTime.str() + ".rep";
995        fDailyReportFile.open(fFullDailyReportFileName.c_str(), std::ios_base::out | std::ios_base::app);
996       
997        if (!fDailyLogFile.is_open() || !fDailyReportFile.is_open())
998        {       
999                //TODO send an error message   
1000            return kSM_BadDailyConfig;
1001        }
1002        //get the size of the newly opened file.
1003        struct stat st;
1004        stat(fFullDailyLogFileName.c_str(), &st);
1005        fBaseSizeDaily = st.st_size;   
1006        stat(fFullDailyReportFileName.c_str(), &st);
1007        fBaseSizeDaily += st.st_size;
1008        fFileSizesMap.clear();
1009        fBaseSizeRun = 0;
1010        fPreviousSize = 0;
1011        //notify that files were opened
1012        NotifyOpenedFile(sTime.str(), 3);
1013       
1014       
1015        return kSM_DailyOpen;   
1016}
1017
1018#ifdef HAS_FITS
1019// --------------------------------------------------------------------------
1020//
1021//! open if required a the FITS files corresponding to a given subscription
1022//! @param sub
1023//!     the current DimInfo subscription being examined
1024void DataLogger::OpenFITSFilesPlease(SubscriptionType& sub)
1025{
1026        std::string serviceName(sub.dimInfo->getName());
1027        for (unsigned int i=0;i<serviceName.size(); i++)
1028        {
1029                if (serviceName[i] == '/')
1030                {
1031                        serviceName[i] = '_';
1032                        break; 
1033                }       
1034        }
1035        Time time;
1036        std::stringstream sTime;
1037        sTime << time.Y() << "_" << time.M() << "_" << time.D();
1038        //we open the dailyFile anyway, otherwise this function shouldn't have been called.
1039        if (!sub.dailyFile.IsOpen())
1040        {
1041                std::string partialName = fDailyFileName + '/' + sTime.str() + '_' + serviceName + ".fits";
1042                AllocateFITSBuffers(sub);
1043                //get the size of the file we're about to open
1044                if (fFileSizesMap.find(partialName) == fFileSizesMap.end())
1045                {
1046                        struct stat st;
1047                        if (!stat(partialName.c_str(), &st))
1048                                fBaseSizeDaily += st.st_size;
1049                        fFileSizesMap[partialName] = 0;
1050                }
1051                sub.dailyFile.Open(partialName, serviceName, NULL);
1052                //notify the opening
1053                NotifyOpenedFile(sTime.str() + '_' + serviceName, 4);
1054               
1055        }
1056        if (!sub.runFile.IsOpen() && (GetCurrentState() == kSM_Logging))
1057        {//buffer for the run file have already been allocated when doing the daily file
1058                std::stringstream sRun;
1059                sRun << fRunNumber;
1060                std::string partialName = fRunFileName + '/' + sRun.str() + ".fits";//'_' + serviceName + ".fits";
1061                if (fRunFitsFile == NULL)
1062                {
1063                        //get the size of the file we're about to open
1064                        if (fFileSizesMap.find(partialName) == fFileSizesMap.end())
1065                        {
1066                                struct stat st;
1067                                if (!stat(partialName.c_str(), &st))
1068                                        fBaseSizeRun += st.st_size;
1069                                else
1070                                        fBaseSizeRun = 0;
1071                                fFileSizesMap[partialName] = 0; 
1072                        }
1073                        try
1074                        {
1075                                fRunFitsFile = new FITS(partialName, RWmode::Write);   
1076                        }       
1077                        catch (CCfits::FitsError e)
1078                        {
1079                                std::ostringstream err;
1080                                err << "Could not open run file " << partialName;
1081                                throw runtime_error(err.str()); 
1082                        }
1083                        NotifyOpenedFile(sRun.str(), 4);// + '_' + serviceName, 4);
1084                }
1085                sub.runFile.Open(partialName, serviceName, fRunFitsFile);
1086        }
1087}       
1088// --------------------------------------------------------------------------
1089//
1090void DataLogger::AllocateFITSBuffers(SubscriptionType& sub)
1091{
1092        int size = sub.dimInfo->getSize();
1093         
1094        //Init the time columns of the file
1095        Description dateDesc(std::string("Time"), std::string("Modified Julian Date"), std::string("MjD"));
1096        sub.dailyFile.AddStandardColumn(dateDesc, "1D", &fMjD, sizeof(double));
1097        sub.runFile.AddStandardColumn(dateDesc, "1D", &fMjD, sizeof(double));
1098
1099        Description QoSDesc("Qos", "Quality of service", "None");
1100        sub.dailyFile.AddStandardColumn(QoSDesc, "1J", &fQuality, sizeof(int));
1101        sub.runFile.AddStandardColumn(QoSDesc, "1J", &fQuality, sizeof(int));
1102
1103        const Converter::FormatList flist = sub.fConv->GetList();
1104    // Compilation failed
1105    if (flist.empty() || flist.back().first.second!=0)
1106    {
1107        Error("Compilation of format string failed.");
1108        return;
1109    }
1110
1111        //we've got a nice structure describing the format of this service's messages.
1112        //Let's create the appropriate FITS columns
1113        std::vector<std::string> dataFormatsLocal;
1114        for (unsigned int i=0;i<flist.size()-1;i++)
1115        {
1116                std::stringstream dataQualifier; 
1117
1118                dataQualifier << flist[i].second.first;
1119                switch (flist[i].first.first->name()[0])
1120                {//TODO handle all the data format cases
1121                        case 'c':
1122                                dataQualifier <<  "S";
1123                        break;
1124                        case 's':
1125                                dataQualifier << "I";
1126                        break;
1127                        case 'i':
1128                                dataQualifier << "J";
1129                        break;
1130                        case 'l':
1131                                dataQualifier << "J";
1132                                //TODO triple check that in FITS, long = int
1133                        break;
1134                        case 'f':
1135                                dataQualifier << "E";
1136                        break;
1137                        case 'd':
1138                                dataQualifier << "D";
1139                        break;
1140                        case 'x':
1141                        case 'X':
1142                                dataQualifier << "K";
1143                        break;
1144                        case 'S':
1145                                //for strings, the number of elements I get is wrong. Correct it
1146                                dataQualifier.str(""); //clear
1147                                dataQualifier << size-1 <<  "A";
1148                                size = size-1;
1149                        break;
1150                       
1151                        default:
1152                                Error("THIS SHOULD NEVER BE REACHED. dataLogger.cc ln 948.");
1153                };
1154                dataFormatsLocal.push_back(dataQualifier.str());
1155         }
1156
1157         sub.dailyFile.InitDataColumns(fServiceList.GetDescriptions(sub.dimInfo->getName()), dataFormatsLocal, sub.dimInfo->getData(), size);
1158         sub.runFile.InitDataColumns(fServiceList.GetDescriptions(sub.dimInfo->getName()), dataFormatsLocal, sub.dimInfo->getData(), size);
1159}
1160// --------------------------------------------------------------------------
1161//
1162//! write a dimInfo data to its corresponding FITS files
1163//
1164void DataLogger::WriteToFITS(SubscriptionType& sub)
1165{
1166                //dailyFile status (open or not) already checked
1167                if (sub.dailyFile.IsOpen())
1168                        sub.dailyFile.Write(sub.fConv);
1169                if (sub.runFile.IsOpen())
1170                        sub.runFile.Write(sub.fConv);
1171}
1172#endif //if has_fits
1173// --------------------------------------------------------------------------
1174//
1175//! Implements the StartRun transition.
1176//! Concatenates the given path for the run file and the filename itself (based on the run number),
1177//! and tries to open it.
1178//! @returns
1179//!             kSM_Logging if success, kSM_BadRunConfig if failure.
1180int DataLogger::StartRunPlease()
1181{
1182        //attempt to open run file with current parameters
1183        if (fRunNumber == -1)
1184                return kSM_BadRunConfig;
1185        std::stringstream sRun;
1186        sRun << fRunNumber;
1187        fFullRunLogFileName = fRunFileName + '/' + sRun.str() + ".log";
1188        fRunLogFile.open(fFullRunLogFileName.c_str(), std::ios_base::out | std::ios_base::app); //maybe should be app instead of ate
1189
1190        fFullRunReportFileName = fRunFileName + '/' + sRun.str() + ".rep";
1191        fRunReportFile.open(fFullRunReportFileName.c_str(), std::ios_base::out | std::ios_base::app);
1192       
1193        if (!fRunLogFile.is_open() || !fRunReportFile.is_open())
1194        {
1195                //TODO send an error message
1196                return kSM_BadRunConfig;       
1197        }
1198        //get the size of the newly opened file.
1199        struct stat st;
1200        fBaseSizeRun = 0;
1201        if (fFileSizesMap.find(fFullRunLogFileName) == fFileSizesMap.end())
1202        {
1203                stat(fFullRunLogFileName.c_str(), &st);
1204                fBaseSizeRun += st.st_size;
1205                fFileSizesMap[fFullRunLogFileName] = 0;
1206        }
1207        if (fFileSizesMap.find(fFullRunReportFileName) == fFileSizesMap.end())
1208        {
1209                stat(fFullRunReportFileName.c_str(), &st);
1210                fBaseSizeRun += st.st_size;
1211                fFileSizesMap[fFullRunReportFileName] = 0;
1212        }
1213        NotifyOpenedFile(sRun.str(), 3);
1214       
1215        return kSM_Logging;
1216}
1217// --------------------------------------------------------------------------
1218//
1219//! Implements the StopRun transition.
1220//! Attempts to close the run file.
1221//! @returns
1222//!             kSM_WaitingRun if success, kSM_FatalError otherwise
1223int DataLogger::StopRunPlease()
1224{
1225        if (!fRunLogFile.is_open() || !fRunReportFile.is_open())
1226                return kSM_FatalError;
1227       
1228        fRunLogFile.close();
1229        fRunReportFile.close();
1230#ifdef HAS_FITS
1231        for (SubscriptionsListType::iterator i = fServiceSubscriptions.begin(); i != fServiceSubscriptions.end(); i++)
1232                for (std::map<std::string, SubscriptionType>::iterator j = i->second.begin(); j != i->second.end(); j++)
1233                {
1234                                if (j->second.runFile.IsOpen())
1235                                        j->second.runFile.Close();     
1236                }
1237        if (fRunFitsFile != NULL)
1238        {
1239                delete fRunFitsFile;
1240                fRunFitsFile = NULL;   
1241        }
1242#endif
1243        return kSM_WaitingRun;
1244
1245}
1246// --------------------------------------------------------------------------
1247//
1248//! Implements the Stop and Reset transitions.
1249//! Attempts to close any openned file.
1250//! @returns
1251//!     kSM_Ready
1252int DataLogger::GoToReadyPlease()
1253{
1254        if (fDailyLogFile.is_open())
1255                fDailyLogFile.close();
1256        if (fDailyReportFile.is_open())
1257                fDailyReportFile.close();
1258
1259        if (fRunLogFile.is_open())
1260                fRunLogFile.close();
1261        if (fRunReportFile.is_open())
1262                fRunReportFile.close();
1263               
1264#ifdef HAS_FITS
1265        for (SubscriptionsListType::iterator i = fServiceSubscriptions.begin(); i != fServiceSubscriptions.end(); i++)
1266                for (std::map<std::string, SubscriptionType>::iterator j = i->second.begin(); j != i->second.end(); j++)
1267                {
1268                                if (j->second.dailyFile.IsOpen())
1269                                        j->second.dailyFile.Close();
1270                                if (j->second.runFile.IsOpen())
1271                                        j->second.runFile.Close();     
1272                }
1273        if (fRunFitsFile != NULL)
1274        {
1275                delete fRunFitsFile;
1276                fRunFitsFile = NULL;   
1277        }
1278#endif
1279        return kSM_Ready;
1280}
1281// --------------------------------------------------------------------------
1282//
1283//! Implements the transition towards kSM_WaitingRun
1284//! Does nothing really.
1285//!     @returns
1286//!             kSM_WaitingRun
1287int DataLogger::DailyToWaitRunPlease()
1288{
1289        return kSM_WaitingRun; 
1290}
1291
1292// --------------------------------------------------------------------------
1293
1294int RunDim(Configuration &conf)
1295{
1296    WindowLog wout;
1297
1298    //log.SetWindow(stdscr);
1299    if (conf.Has("log"))
1300        if (!wout.OpenLogFile(conf.Get<std::string>("log")))
1301            wout << kRed << "ERROR - Couldn't open log-file " << conf.Get<std::string>("log") << ": " << strerror(errno) << std::endl;
1302
1303    // Start io_service.Run to use the StateMachineImp::Run() loop
1304    // Start io_service.run to only use the commandHandler command detaching
1305    DataLogger logger(wout);
1306    logger.Run(true);
1307
1308    return 0;
1309}
1310
1311template<class T>
1312int RunShell(Configuration &conf)
1313{
1314    static T shell(conf.GetName().c_str(), conf.Get<int>("console")!=1);
1315
1316    WindowLog &win  = shell.GetStreamIn();
1317    WindowLog &wout = shell.GetStreamOut();
1318
1319    if (conf.Has("log"))
1320        if (!wout.OpenLogFile(conf.Get<std::string>("log")))
1321            win << kRed << "ERROR - Couldn't open log-file " << conf.Get<std::string>("log") << ": " << strerror(errno) << std::endl;
1322
1323    DataLogger logger(wout);
1324
1325    shell.SetReceiver(logger);
1326
1327    logger.SetReady();
1328 //  logger.StartPlease();
1329    shell.Run();                 // Run the shell
1330     logger.SetNotReady();
1331
1332    return 0;
1333}
1334
1335/*
1336 Extract usage clause(s) [if any] for SYNOPSIS.
1337 Translators: "Usage" and "or" here are patterns (regular expressions) which
1338 are used to match the usage synopsis in program output.  An example from cp
1339 (GNU coreutils) which contains both strings:
1340  Usage: cp [OPTION]... [-T] SOURCE DEST
1341    or:  cp [OPTION]... SOURCE... DIRECTORY
1342    or:  cp [OPTION]... -t DIRECTORY SOURCE...
1343 */
1344void PrintUsage()
1345{
1346    cout << "\n"
1347        "The data logger connects to all available Dim services and "
1348        "writes them to ascii and fits files.\n"
1349        "\n"
1350        "Usage: dataLogger [-c type] [OPTIONS]\n"
1351        "  or:  dataLogger [OPTIONS]\n"
1352        "\n"
1353        "Options:\n"
1354        "The following describes the available commandline options. "
1355        "For further details on how command line option are parsed "
1356        "and in which order which configuration sources are accessed "
1357        "please refer to the class reference of the Configuration class.";
1358    cout << endl;
1359
1360}
1361
1362void PrintHelp()
1363{
1364    cout << "\n"
1365        "The default is that the program is started without user interaction. "
1366        "All actions are supposed to arrive as DimCommands. Using the -c "
1367        "option, a local shell can be initialized. With h or help a short "
1368        "help message about the usuage can be brought to the screen."
1369        << endl;
1370
1371    /*
1372     cout << "bla bla bla" << endl << endl;
1373     cout << endl;
1374     cout << "Environment:" << endl;
1375     cout << "environment" << endl;
1376     cout << endl;
1377     cout << "Examples:" << endl;
1378     cout << "test exam" << endl;
1379     cout << endl;
1380     cout << "Files:" << endl;
1381     cout << "files" << endl;
1382     cout << endl;
1383     */
1384}
1385
1386/*
1387 The first line of the --version information is assumed to be in one
1388 of the following formats:
1389
1390   <version>
1391   <program> <version>
1392   {GNU,Free} <program> <version>
1393   <program> ({GNU,Free} <package>) <version>
1394   <program> - {GNU,Free} <package> <version>
1395
1396 and separated from any copyright/author details by a blank line.
1397
1398 Handle multi-line bug reporting sections of the form:
1399
1400   Report <program> bugs to <addr>
1401   GNU <package> home page: <url>
1402   ...
1403*/
1404void PrintVersion(const char *name)
1405{
1406    cout <<
1407        name << " - "PACKAGE_STRING"\n"
1408        "\n"
1409        "Written by Thomas Bretz et al.\n"
1410        "\n"
1411        "Report bugs to <"PACKAGE_BUGREPORT">\n"
1412        "Home page: "PACKAGE_URL"\n"
1413        "\n"
1414        "Copyright (C) 2011 by the FACT Collaboration.\n"
1415        "This is free software; see the source for copying conditions.\n"
1416        << endl;
1417}
1418
1419
1420void SetupConfiguration(Configuration &conf)
1421{
1422    const string n = conf.GetName()+".log";
1423
1424    po::options_description config("Program options");
1425    config.add_options()
1426        ("dns",       var<string>("localhost"),  "Dim nameserver host name (Overwites DIM_DNS_NODE environment variable)")
1427        ("log,l",     var<string>(n), "Write log-file")
1428        ("console,c", var<int>(),     "Use console (0=shell, 1=simple buffered, X=simple unbuffered)")
1429        ;
1430
1431    conf.AddEnv("dns", "DIM_DNS_NODE");
1432
1433    conf.AddOptions(config);
1434}
1435
1436int main(int argc, const char* argv[])
1437{
1438    Configuration conf(argv[0]);
1439    conf.SetPrintUsage(PrintUsage);
1440    SetupConfiguration(conf);
1441
1442    po::variables_map vm;
1443    try
1444    {
1445        vm = conf.Parse(argc, argv);
1446    }
1447    catch (std::exception &e)
1448    {
1449#if BOOST_VERSION > 104000
1450        po::multiple_occurrences *MO = dynamic_cast<po::multiple_occurrences*>(&e);
1451        if (MO)
1452            cout << "Error: " << e.what() << " of '" << MO->get_option_name() << "' option." << endl;
1453        else
1454#endif
1455            cout << "Error: " << e.what() << endl;
1456        cout << endl;
1457
1458        return -1;
1459    }
1460
1461    if (conf.HasPrint())
1462        return -1;
1463
1464    if (conf.HasVersion())
1465    {
1466        PrintVersion(argv[0]);
1467        return -1;
1468    }
1469
1470    if (conf.HasHelp())
1471    {
1472        PrintHelp();
1473        return -1;
1474    }
1475
1476    setenv("DIM_DNS_NODE", conf.Get<string>("dns").c_str(), 1);
1477
1478    try
1479    {
1480        // No console access at all
1481        if (!conf.Has("console"))
1482            return RunDim(conf);
1483
1484        // Console access w/ and w/o Dim
1485        if (conf.Get<int>("console")==0)
1486            return RunShell<LocalShell>(conf);
1487        else
1488            return RunShell<LocalConsole>(conf);
1489    }
1490    catch (std::exception& e)
1491    {
1492        cerr << "Exception: " << e.what() << endl;
1493        return -1;
1494    }
1495
1496    return 0;
1497}
Note: See TracBrowser for help on using the repository browser.