00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00016 #include <fstream>
00017 #include <sstream>
00018 #include <iostream>
00019 #include <iomanip>
00020 #include <stdarg.h>
00021 #include <stdlib.h>
00022 #include <stdio.h>
00023 #include <string.h>
00024 #include <errno.h>
00025 #include <math.h>
00026
00027 #include <unistd.h>
00028 #include <getopt.h>
00029 #include <time.h>
00030 #include <sys/time.h>
00031 typedef struct timespec timespec_t;
00032 typedef struct tm tm_t;
00033 #include <ctime>
00034
00035
00036 #include "WebAPI.h"
00037 #include "ifbeam.h"
00038
00039 #include "BeamData/python/bdp/BeamData.h"
00040 #include "BeamData/python/bdp/BeamData.cc"
00041 #include "OnlineUtil/rototalk.h"
00042
00043 #include <algorithm>
00044 #include <map>
00045
00046 const char* exename = "ifbtorr";
00047
00049
00050
00051
00052
00054 class ifbConfig {
00055 public:
00056 ifbConfig();
00057 ~ifbConfig() { ; }
00058 void ParseArgv(int argc, char** argv);
00059 void Usage(std::string msg, int exitval);
00060 void PrintConfig();
00061 public:
00062 int Verbose;
00063 bool PrintAndQuit;
00064 bool CountAndQuit;
00065 bool AllowRotoErrors;
00066 double TimeStamp;
00067 double WindowSize;
00068 std::string BundleName;
00069 std::string RotoNode;
00070 std::string URLifbeam;
00071 double CacheWindow;
00072 double Epsilon;
00073 double DeltaCacheTime;
00074 int TClkTriggerEvent;
00075 int TClkTriggerDelay;
00076 int DtTolerance;
00077 std::string PrintOpts;
00078 };
00079
00081
00082
00083
00084
00085
00087 class ifbProcBase {
00088 public:
00089 ifbProcBase(ifbConfig cfgIn);
00090 virtual ~ifbProcBase() { ; }
00091
00092
00093 virtual int Init();
00094 virtual int SpillInit(double when);
00095 virtual int SpillDevice(double when, std::string device);
00096 virtual int SpillFinish(double when);
00097 virtual int Finish();
00098
00099
00100 virtual int NewCache(double cacheStart);
00101 virtual int ScanWindow(double t1, double t2);
00102 virtual int ProcessTime(double when);
00103 virtual int Run();
00104
00105 size_t SpillCount() { return nspills; }
00106
00107 protected:
00108 BeamFolder* bf;
00109 ifbConfig cfg;
00110 size_t nspills;
00111
00112
00113 std::vector<double> cacheTimes;
00114 std::vector<std::string> cacheDevices;
00115 };
00116
00118
00119
00120
00121
00123 class ifbProcRoto : public ifbProcBase {
00124 public:
00125 ifbProcRoto(ifbConfig cfgIn) : ifbProcBase(cfgIn), maxDt(-99999999), minDt(999999) { ; }
00126 virtual ~ifbProcRoto() { ; }
00127
00128 virtual int Init();
00129 virtual int SpillInit(double when);
00130 virtual int SpillDevice(double when, std::string device);
00131 virtual int SpillFinish(double when);
00132 virtual int Finish();
00133
00134 std::map<std::string,size_t>& DeviceCount() { return devcnt; }
00135
00136 private:
00137 void CompareSpillDeviceTimes(const std::string& devname,
00138 int spillSec, int spillMSec,
00139 int devSec, int devMSec);
00140
00141 BeamData bd;
00142
00143 std::map<std::string,size_t> devcnt;
00144
00145 int maxDt;
00146 int minDt;
00147 };
00148
00150
00151
00152
00154 double ParseTimeString(const char*);
00155 std::string UTCTimeString(double);
00156 std::string LocalTimeString(double);
00157 std::vector<std::string> UniqueNames(std::vector<std::string>, int verbose);
00158
00159 inline void DoubleToSecMSec(double t, int& sec, int& msec)
00160 {
00161
00162 sec = (int)t; msec = int((t - int(sec))*1.0e3+0.5);
00163 }
00164
00166 int main(int argc, char** argv)
00167 {
00168 exename = argv[0];
00169
00170
00171
00172
00173 ifbConfig cfg;
00174 cfg.ParseArgv(argc,argv);
00175 if ( cfg.PrintAndQuit || cfg.Verbose > 0 ) cfg.PrintConfig();
00176 if ( cfg.PrintAndQuit ) exit(0);
00177
00178 ifbProcBase* ifbp = 0;
00179 if ( cfg.CountAndQuit ) ifbp = new ifbProcBase(cfg);
00180 else ifbp = new ifbProcRoto(cfg);
00181
00182 ifbp->Run();
00183
00184 }
00185
00187
00188 ifbConfig::ifbConfig()
00189 : Verbose(0)
00190 , PrintAndQuit(false)
00191 , CountAndQuit(false)
00192 , AllowRotoErrors(false)
00193 , TimeStamp(0)
00194 , WindowSize(8*60*60)
00195 , BundleName("NuMI_all")
00196 , RotoNode("minos-nearline.fnal.gov")
00197
00198
00199 , URLifbeam("")
00200 , CacheWindow(-1)
00201 , Epsilon(0.05)
00202 , DeltaCacheTime(0.0001)
00203 , TClkTriggerEvent(169)
00204 , TClkTriggerDelay(500)
00205 , DtTolerance(500)
00206
00207 , PrintOpts("")
00208 {
00209
00210
00211
00212
00213 }
00214 void ifbConfig::PrintConfig() {
00215
00216 long long tsec = (int)TimeStamp;
00217 long long tns = (int)((TimeStamp - tsec)*1000000000);
00218
00219 std::cout << exename << ": current configuration:" << std::endl
00220 << " Verbose " << Verbose
00221 << " " << ( (PrintAndQuit) ? "PrintAndQuit" : "" )
00222 << " " << ( (CountAndQuit) ? "CountAndQuit" : "" )
00223 << " " << ( (AllowRotoErrors) ? "AllowRotoErrors" : "" )
00224 << std::endl
00225 << " TimeStamp " << TimeStamp
00226 << " (" << tsec << "."
00227 << std::setfill('0') << std::setw(9) << tns
00228 << std::setfill(' ') << ")" << std::endl
00229 << " " << UTCTimeString(TimeStamp) << std::endl
00230 << " " << LocalTimeString(TimeStamp) << std::endl
00231 << " WindowSize " << WindowSize << " (seconds)" << std::endl
00232 << " BundleName \"" << BundleName << "\"" << std::endl
00233 << " RotoNode \"" << RotoNode << "\"" << std::endl
00234 << " URLifbeam \"" << URLifbeam << "\"" << std::endl
00235 << " BeamFolder CacheWindow " << CacheWindow
00236 << " Epsilon " << Epsilon
00237 << " DeltaCacheTime " << DeltaCacheTime << std::endl
00238 << " TClkTrigger Event " << TClkTriggerEvent
00239 << " Delay " << TClkTriggerDelay << std::endl
00240 << " DtTolerance " << DtTolerance << std::endl
00241 << " PrintOpts \"" << PrintOpts << "\"" << std::endl
00242 << std::endl;
00243 }
00244 void ifbConfig::ParseArgv(int argc, char** argv) {
00245
00246
00247
00248
00249
00250
00251 static struct option long_opts[] = {
00252 { "help", no_argument, 0, 'h' },
00253 { "timestamp", required_argument, 0, 't' },
00254 { "timestring", required_argument, 0, 'T' },
00255 { "window", required_argument, 0, 'w' },
00256 { "bundle", required_argument, 0, 'b' },
00257 { "rotonode", required_argument, 0, 'r' },
00258 { "url", required_argument, 0, 'u' },
00259 { "print-config", no_argument, 0, 'C' },
00260 { "count-spills", no_argument, 0, 'c' },
00261 { "verbose", no_argument, 0, 'v' },
00262 { "bypass-roto", no_argument, 0, 'A' },
00263 { "cache-window", required_argument, 0, 'z' },
00264 { "cache-delta", required_argument, 0, 'd' },
00265 { "epsilon", required_argument, 0, 'e' },
00266 { "tclk-event", required_argument, 0, 'E' },
00267 { "tclk-delay", required_argument, 0, 'D' },
00268 { "dt-tolerance", required_argument, 0, 'q' },
00269 { "print-opts", required_argument, 0, 'P' },
00270 { 0, 0, 0, 0 }
00271 };
00272 const char short_opts[] = "ht:T:w:W:b:r:u:CcvAz:d:e:E:D:q:P:";
00273
00274
00275
00276
00277
00278
00279
00280 #ifndef MACOSX
00281 optind = 0;
00282 #else
00283 optind = 1;
00284 #endif
00285 int opt_index = 0;
00286 int c;
00287 while ((c = getopt_long(argc,argv,short_opts,long_opts,&opt_index)) != -1 ) {
00288 if (Verbose>1) {
00289 std::cout << " c from getopt_long " << c << " '" << (char)c << "'"
00290 << " optarg \"" << (optarg?optarg:"") << "\""
00291 << std::endl;
00292 }
00293 switch ( c ) {
00294 case 0: {
00295
00296 if ( long_opts[opt_index].flag != 0 ) {
00297 if (Verbose>1) {
00298 std::cout << " c==0 opt_index " << opt_index
00299 << " flag " << long_opts[opt_index].flag << std::endl;
00300 }
00301 break;
00302 }
00303 std::string opt_name = long_opts[opt_index].name;
00304 if (Verbose>1) {
00305 std::cout << "c==0 opt_index " << opt_index
00306 << " opt_name=\"" << opt_name
00307 << "\" optarg=\"" << optarg << "\"" << std::endl;
00308 }
00309 break;
00310 }
00311 case 'h': {
00312 Usage("",0);
00313 break;
00314 }
00315 case 'C': {
00316 PrintAndQuit = true;
00317 break;
00318 }
00319 case 'c': {
00320 CountAndQuit = true;
00321 break;
00322 }
00323 case 'v': {
00324 ++Verbose;
00325 break;
00326 }
00327 case 'A': {
00328 AllowRotoErrors = true;
00329 break;
00330 }
00331 case 't': {
00332 TimeStamp = atof(optarg);
00333 break;
00334 }
00335 case 'T': {
00336 TimeStamp = ParseTimeString(optarg);
00337 break;
00338 }
00339 case 'w': {
00340 float wval;
00341 char units[128] = { 0 };
00342
00343 sscanf(optarg,"%f%s",&wval,units);
00344 switch ( units[0] ) {
00345 case 's':
00346 WindowSize = wval;
00347 break;
00348 case 'm':
00349 WindowSize = wval*60;
00350 break;
00351 case 'h':
00352 WindowSize = wval*60*60;
00353 break;
00354 case '\0':
00355
00356 WindowSize = wval*60*60;
00357 break;
00358 default:
00359 std::ostringstream oss;
00360 oss << "ERROR, --window set with unknown units"
00361 << " \"" << units << "\"";
00362 Usage(oss.str(),1);
00363 break;
00364 }
00365 break;
00366 }
00367 case 'b': {
00368 BundleName = optarg;
00369 break;
00370 }
00371 case 'r': {
00372 RotoNode = optarg;
00373 break;
00374 }
00375 case 'u': {
00376 URLifbeam = optarg;
00377 break;
00378 }
00379 case 'd': {
00380 DeltaCacheTime = atof(optarg);
00381 break;
00382 }
00383 case 'z': {
00384 CacheWindow = atof(optarg);
00385 break;
00386 }
00387 case 'e': {
00388 Epsilon = atof(optarg);
00389 break;
00390 }
00391 case 'E': {
00392 TClkTriggerEvent = atoi(optarg);
00393 break;
00394 }
00395 case 'D': {
00396 TClkTriggerDelay = atoi(optarg);
00397 break;
00398 }
00399 case 'q': {
00400 DtTolerance = atoi(optarg);
00401 break;
00402 }
00403 case 'P': {
00404 PrintOpts = optarg;
00405 break;
00406 }
00407 default: {
00408 std::ostringstream oss;
00409 oss << "ERROR, unhandled/unrecognized option '" << (char)optopt << "' ("
00410 << optopt << ")";
00411 Usage(oss.str(),1);
00412 }
00413
00414 }
00415 }
00416
00417 if ( CountAndQuit ) {
00418 if ( PrintOpts != "" ) PrintOpts += ",";
00419 PrintOpts += "spillcnt";
00420 }
00421
00422
00423
00424
00425
00426 if ( optind < argc ) {
00427 if (Verbose>1) {
00428 std::cout << "non-option (positional) ARGV-elements: " << std::endl;
00429 }
00430 int posindx = -1;
00431 while ( optind < argc ) {
00432 ++posindx;
00433 std::string arg = argv[optind++];
00434
00435 if (Verbose>1) {
00436 std::string posname[] = { "TimeStamp", "WindowSize",
00437 "BundleName", "UNKNOWN" };
00438 std::string name = (posindx<3) ? posname[posindx] : "UNKNOWN";
00439 std::cout << "Set " << setw(10) << name
00440 << " from positional arg[" << posindx
00441 << "] \"" << arg << "\"" << std::endl;
00442 }
00443
00444 switch ( posindx ) {
00445 case 0: {
00446
00447 TimeStamp = atof(arg.c_str());
00448 break;
00449 }
00450 case 1: {
00451
00452 WindowSize = atof(arg.c_str())*60*60;
00453 break;
00454 }
00455 case 2: {
00456 BundleName = arg;
00457 break;
00458 }
00459 default: {
00460 Usage("ERROR, unexpected extra positional argument",1);
00461 break;
00462 }
00463 }
00464 }
00465 }
00466
00467 }
00468 void ifbConfig::Usage(std::string msg, int exitval) {
00469
00470 std::cout
00471 << std::endl
00472 << "Usage: " << exename << " [OPTIONS] [ timestamp [ window(hours) [ bundle ]]]\n"
00473 << " Read data from IFBeam DB, reformat and send to MINOS beam rotorooter.\n"
00474 << "Mandatory arguments to long options are mandatory for short options.\n"
00475 << " -h, --help display this help and exit\n"
00476 << " -t, --timestamp=TIME starting time in seconds since epoch\n"
00477 << " -T, --timestring='YYYY-MM-DD hh:mm:ss'\n"
00478 << " -w, --window=VAL window time (default units hours)\n"
00479 << " use VALs or VALm for sec, min; e.g. 3600s\n"
00480 << " -b, --bundle=NAME bundle name\n"
00481 << " -r, --rotonode=MACHINE node where rotorooter is running\n"
00482 << " -u, --url=IFB_URL URL for IF Beam DB connection\n"
00483 << " -C, --print-config print configuration and exit\n"
00484 << " -v, --verbose increase verbosity\n"
00485 << " -c, --count-spills simply count spills w/ no rotorooter\n"
00486 << " -z, --cache-window BeamFolder cache window size (-1=default[1200])\n"
00487 << " -d, --cache-delta start new BF cache Delta after previous\n"
00488 << " -e, --epsilon BeamFolder epsilon\n"
00489 << " -E, --tclk-event=EVENT 'event' (A9?) associated w/ block [169]\n"
00490 << " -D, --tclk-delay=DELAY 'delay' associated w/ block [500]\n"
00491 << " -q, --dt-tolerance=MS complain about spill/device time diff\n"
00492 << " -P, --print-opts=POPTS what extra to print\n"
00493 << " --bypass-roto continue after rotorooter connection/file errors\n"
00494
00495
00496 << "Use of positional arguments is a deprecated feature, use flags instead.\n"
00497 << "PrintOpts POPTS is a comma separated string of things to print\n"
00498 << " times = all timestamps\n"
00499 << " devices = final list of devices w/ spill counts\n"
00500 << " missing = device only if it was missing from some spills\n"
00501 << " dt = excursion extremes between spill and device time (ms)\n"
00502 << " spillcnt = # of spills\n"
00503 << std::endl;
00504 PrintConfig();
00505 if ( msg != "" ) std::cout << exename << ": " << msg << std::endl;
00506 if ( exitval >= 0 ) exit(exitval);
00507 }
00508
00510
00511 std::vector<std::string> UniqueNames(std::vector<std::string> names,
00512 int verbose)
00513 {
00514
00515
00516
00517 std::map<std::string,int> namecnt;
00518 for ( size_t iname = 0; iname < names.size(); ++iname ) {
00519 namecnt[names[iname]]++;
00520 }
00521 if ( names.size() != namecnt.size() ) {
00522 if ( verbose > 3 ) {
00523 std::cout << exename << ": bfp.GetDeviceList() returned "
00524 << names.size() << " devices, "
00525 << namecnt.size() << " unique"
00526 << std::endl;
00527 }
00528
00529 names.clear();
00530
00531 std::map<std::string,int>::const_iterator ncitr = namecnt.begin();
00532 for ( ; ncitr != namecnt.end(); ++ncitr ) {
00533 names.push_back(ncitr->first);
00534 int cnt = ncitr->second;
00535 if ( cnt > 1 && verbose > 4 ) {
00536 std::cout << " " << std::left << std::setw(12)
00537 << ncitr->first << std::right
00538 << " was in device list " << cnt
00539 << " times." << std::endl;
00540 }
00541 }
00542 }
00543 return names;
00544 }
00546 ifbProcBase::ifbProcBase(ifbConfig cfgIn)
00547 : bf(0), cfg(cfgIn), nspills(0)
00548 {
00549
00550
00551
00552
00553
00554 if ( cfg.CacheWindow > 1.0 ) {
00555 bf = new BeamFolder(cfg.BundleName, cfg.URLifbeam, cfg.CacheWindow);
00556 } else {
00557 bf = new BeamFolder(cfg.BundleName, cfg.URLifbeam);
00558 }
00559 bf->set_epsilon(cfg.Epsilon);
00560 }
00561
00562 int ifbProcBase::Init()
00563 {
00564 return 0;
00565 }
00566 int ifbProcBase::SpillInit(double)
00567 {
00568 return 0;
00569 }
00570 int ifbProcBase::SpillDevice(double,std::string)
00571 {
00572 return 0;
00573 }
00574 int ifbProcBase::SpillFinish(double)
00575 {
00576 return 0;
00577 }
00578 int ifbProcBase::Finish()
00579 {
00580 return 0;
00581 }
00582 int ifbProcBase::NewCache(double cacheStart)
00583 {
00584 cacheTimes.clear();
00585 cacheDevices.clear();
00586
00587 try {
00588 bf->FillCache(cacheStart);
00589 cacheTimes = bf->GetTimeList();
00590 std::sort(cacheTimes.begin(),cacheTimes.end());
00591 cacheDevices = UniqueNames( bf->GetDeviceList(), cfg.Verbose );
00592 } catch(WebAPIException we) {
00593 if ( cfg.Verbose > 0 ) {
00594 std::cout << exename << ": no spills in BeamFolder cache "
00595 << std::fixed << std::setprecision(3) << cacheStart;
00596 if ( cfg.CacheWindow > 1 ) {
00597 std::cout << " (+ " << cfg.CacheWindow << ")";
00598 } else {
00599 std::cout << " (+ default BeamFolder window " << 1200 << "?)";
00600 }
00601 std::cout << std::endl;
00602 }
00603 }
00604 return 0;
00605 }
00606 int ifbProcBase::ScanWindow(double t1, double t2)
00607 {
00608 bool printTime = ( cfg.PrintOpts.find("times") != std::string::npos );
00609
00610 double tCache = t1;
00611 while ( tCache < t2 ) {
00612 NewCache( tCache );
00613 for (size_t it=0; it < cacheTimes.size(); ++it) {
00614 double t = cacheTimes[it];
00615 if ( t < t2 ) {
00616 if ( printTime ) {
00617 std::cout << " [" << std::setw(6) << nspills << "] "
00618 << std::fixed << std::setprecision(3) << t
00619 << " = " << UTCTimeString(t) << std::endl;
00620 }
00621 ++nspills;
00622 ProcessTime(t);
00623 }
00624 }
00625
00626 tCache = bf->GetCacheEndTime() + cfg.DeltaCacheTime;
00627 }
00628 return 0;
00629 }
00630 int ifbProcBase::ProcessTime(double t)
00631 {
00632 SpillInit(t);
00633 for (size_t idevice=0; idevice < cacheDevices.size(); ++idevice) {
00634 std::string devname = cacheDevices[idevice];
00635 SpillDevice(t,devname);
00636 }
00637 SpillFinish(t);
00638 return 0;
00639 }
00640 int ifbProcBase::Run()
00641 {
00642 int istat_init = Init();
00643 if ( istat_init != 0 ) {
00644 cfg.PrintConfig();
00645 std::cout << exename << ": init config returned " << istat_init
00646 << std::endl;
00647 exit(istat_init);
00648 }
00649
00650 double t1 = cfg.TimeStamp;
00651 double t2 = t1 + cfg.WindowSize;
00652 int istat_scan = ScanWindow( t1, t2 );
00653 if ( istat_scan != 0 ) {
00654 cfg.PrintConfig();
00655 std::cout << exename << ": scan returned " << istat_scan
00656 << std::endl;
00657 exit(istat_scan);
00658 }
00659
00660 int istat_finish = Finish();
00661 if ( istat_finish != 0 ) {
00662 cfg.PrintConfig();
00663 std::cout << exename << ": Finish() returned " << istat_init
00664 << std::endl;
00665 exit(istat_init);
00666 }
00667
00668 if ( cfg.PrintOpts.find("spillcnt") != std::string::npos ) {
00669 std::cout << exename << ": saw " << nspills << " spills" << std::endl;
00670 }
00671 return 0;
00672 }
00673
00675 int ifbProcRoto::Init()
00676 {
00677
00678
00679
00680
00681 int conn_status = bd.open_connection(cfg.RotoNode.c_str());
00682 if ( conn_status != 0 ) {
00683 std::cerr << exename << ": failed to make rotorooter connection ("
00684 << conn_status << ")" << std::endl << std::flush;
00685 if ( ! cfg.AllowRotoErrors ) return conn_status;
00686 }
00687
00688
00689
00690
00691
00692
00693
00694
00695 int file_status = bd.open_file((int)cfg.TimeStamp,0);
00696
00697 if ( file_status != 0 ) {
00698 std::cerr << exename << ": failed to open rotorooter file ("
00699 << file_status << ")" << std::endl << std::flush;
00700 if ( ! cfg.AllowRotoErrors ) return file_status;
00701 }
00702
00703 return 0;
00704 }
00705 int ifbProcRoto::SpillInit(double tstamp)
00706 {
00707 int secs = (int)tstamp;
00708 int secs_2ns = (tstamp - (int)tstamp)*1e9;
00709
00710
00711
00712
00713 bd.start_block(secs, secs_2ns, nspills,
00714 cfg.TClkTriggerEvent, cfg.TClkTriggerDelay);
00715
00716 return 0;
00717 }
00718 int ifbProcRoto::SpillDevice(double tstamp, std::string devName)
00719 {
00720 int spillSec, spillMSec;
00721 DoubleToSecMSec(tstamp,spillSec,spillMSec);
00722
00723 if ( devName.find("[]") != std::string::npos ) {
00724
00725
00726
00727 std::vector<double> vDeviceValue;
00728 try {
00729
00730
00731 double devTime;
00732 vDeviceValue = bf->GetNamedVector(tstamp,devName,&devTime);
00733 devcnt[devName]++;
00734
00735 int devSec, devMSec;
00736 DoubleToSecMSec(devTime,devSec,devMSec);
00737 CompareSpillDeviceTimes(devName,spillSec,spillMSec,devSec,devMSec);
00738
00739
00740
00741
00742 bd.set_device_header(devName.c_str(), devSec, devMSec);
00743
00744
00745 for ( size_t ih=0; ih < vDeviceValue.size(); ++ih ) {
00746 bd.add_device_value(devName.c_str(),vDeviceValue[ih]);
00747 }
00748
00749 } catch(WebAPIException we) {
00750
00751 if ( cfg.Verbose > 3 ) {
00752 std::cout << "... skipping device " << devName
00753 << " (" << (int)tstamp << " - not able to read)"
00754 << std::endl;
00755 }
00756 }
00757
00758 } else {
00759
00760
00761
00762 double DeviceValue;
00763 try {
00764
00765
00766
00767
00768 std::string devNameAndTime = devName + "@";
00769 double devTime;
00770 bf->GetNamedData(tstamp,devNameAndTime,&DeviceValue,&devTime);
00771 devcnt[devName]++;
00772
00773 int devSec, devMSec;
00774 DoubleToSecMSec(devTime,devSec,devMSec);
00775 CompareSpillDeviceTimes(devName,spillSec,spillMSec,devSec,devMSec);
00776
00777
00778
00779 bd.set_device_header(devName.c_str(), devSec, devMSec);
00780
00781
00782 bd.add_device_value(devName.c_str(),DeviceValue);
00783
00784 } catch(WebAPIException we) {
00785
00786 if ( cfg.Verbose > 3 ) {
00787 std::cout << "... skipping device " << devName
00788 << " (" << (int)tstamp << " - not able to read)"
00789 << std::endl;
00790 }
00791 }
00792 }
00793 return 0;
00794 }
00795 int ifbProcRoto::SpillFinish(double)
00796 {
00797
00798
00799
00800 bd.send_data();
00801 return 0;
00802 }
00803 int ifbProcRoto::Finish()
00804 {
00805
00806
00807
00808 bd.close_file();
00809
00810
00811
00812
00813 bd.close_connection();
00814
00815
00816
00817
00818 bool printDt = ( cfg.PrintOpts.find("times") != std::string::npos );
00819 if ( printDt ) {
00820 std::cout << exename << ": excursions spill vs. device time ( "
00821 << minDt << " " << maxDt << " )" << std::endl;
00822 }
00823 bool printDevices = ( cfg.PrintOpts.find("devices") != std::string::npos );
00824 bool printMissing = ( cfg.PrintOpts.find("missing") != std::string::npos );
00825 if ( printDevices || printMissing ) {
00826 std::cout << exename << ": "
00827 << devcnt.size() << " devices " << nspills
00828 << " spills";
00829 if ( ! printDevices ) cout << ", print only those missing from "
00830 << "1 or more spills";
00831 std::cout << std::endl;
00832 int nMissingDevices = 0;
00833 std::map<std::string,size_t>::const_iterator itr = devcnt.begin();
00834 for ( ; itr != devcnt.end(); ++itr ) {
00835 size_t devSpills = itr->second;
00836 size_t missedSpills = ( nspills - devSpills);
00837 bool printDev = printDevices || ( missedSpills != 0 );
00838 if ( printDev ) {
00839 std::cout << " "
00840 << std::left << std::setw(12) << itr->first << std::right
00841 << " " << std::setw(6) << devSpills;
00842 if ( missedSpills > 0 ) {
00843 std::cout << ", missing from " << missedSpills;
00844 ++nMissingDevices;
00845 }
00846 std::cout << std::endl;
00847 }
00848 }
00849 std::cout << exename << ": " << nMissingDevices
00850 << " of " << devcnt.size()
00851 << " devices missed at least one spill" << std::endl;
00852
00853 }
00854
00855 return 0;
00856 }
00857
00858 void ifbProcRoto::CompareSpillDeviceTimes(const std::string& devname,
00859 int spillSec, int spillMSec,
00860 int devSec, int devMSec)
00861 {
00862 int diff = ( spillSec - devSec )*1000 + ( spillMSec - devMSec );
00863 if ( abs(diff) > cfg.DtTolerance ) {
00864 std::cout << "CompareSpillDeviceTimes "
00865 << std::setw(12) << devname
00866 << " sec " << std::setw(10) << spillSec
00867 << "|" << std::setw(10) <<devSec
00868 << " msec " << std::setw(3) << spillMSec
00869 << "|" << std::setw(3) << devMSec << " (delta "
00870 << (diff) << ") " << std::endl;
00871 }
00872 if ( diff < minDt ) minDt = diff;
00873 if ( diff > maxDt ) maxDt = diff;
00874
00875 }
00876
00878
00879
00880 bool IsLeapYear(int year)
00881 {
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894 if (year%4 != 0) {
00895 return false;
00896 }
00897 else {
00898 if (year%400 == 0) {
00899 return true;
00900 }
00901 else {
00902 if (year%100 == 0) {
00903 return false;
00904 }
00905 else {
00906 return true;
00907 }
00908 }
00909 }
00910
00911 }
00912
00913
00914 time_t MktimeFromUTC(tm_t *tmstruct)
00915 {
00916
00917
00918
00919
00920
00921
00922
00923
00924
00925
00926
00927 const int days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
00928 const int daysLeap[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
00929
00930 int year = tmstruct->tm_year + 1900;
00931 bool isleap = IsLeapYear(year);
00932
00933 const int *daysInMonth = days;
00934 if (isleap) daysInMonth = daysLeap;
00935
00936
00937
00938 int &ref_tm_mon = tmstruct->tm_mon;
00939 int &ref_tm_mday = tmstruct->tm_mday;
00940
00941 tmstruct->tm_yday = 0;
00942 for (int imonth = 0; imonth < ref_tm_mon; imonth++) {
00943 tmstruct->tm_yday += daysInMonth[imonth];
00944 }
00945 tmstruct->tm_yday += ref_tm_mday - 1;
00946
00947
00948 while (ref_tm_mday > daysInMonth[ref_tm_mon]) {
00949 ref_tm_mday -= daysInMonth[ref_tm_mon];
00950 ref_tm_mon++;
00951 }
00952
00953
00954
00955
00956 tmstruct->tm_isdst = 0;
00957
00958
00959
00960
00961 int utc_sec = tmstruct->tm_sec +
00962 tmstruct->tm_min*60 +
00963 tmstruct->tm_hour*3600 +
00964 tmstruct->tm_yday*86400 +
00965 (tmstruct->tm_year-70)*31536000 +
00966 ((tmstruct->tm_year-69)/4)*86400;
00967
00968 return utc_sec;
00969 }
00970
00971
00972 void DumpTMStruct(const tm_t &tmstruct)
00973 {
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985 printf(" tm { year %4d, mon %2d, day %2d,\n",
00986 tmstruct.tm_year,
00987 tmstruct.tm_mon,
00988 tmstruct.tm_mday);
00989 printf(" hour %2d, min %2d, sec %2d,\n",
00990 tmstruct.tm_hour,
00991 tmstruct.tm_min,
00992 tmstruct.tm_sec);
00993 printf(" wday %2d, yday %3d, isdst %2d",
00994 tmstruct.tm_wday,
00995 tmstruct.tm_yday,
00996 tmstruct.tm_isdst);
00997 #ifdef linux
00998
00999
01000 printf(",\n tm_gmtoff %7ld, tm_zone \"%s\"",
01001 #ifdef __USE_BSD
01002 tmstruct.tm_gmtoff,tmstruct.tm_zone);
01003 #else
01004 tmstruct.__tm_gmtoff,tmstruct.__tm_zone);
01005 #endif
01006 #endif
01007 printf("}\n");
01008 }
01009
01010
01011 double ParseTimeString(const char* s)
01012 {
01013
01014 bool isUTC = true;
01015
01016 int year=0, month=0, day=0;
01017 int hour=0, min=0, sec=0;
01018 float fltsec=0, frac_sec;
01019 char buff[128] = {0};
01020
01021 int nitems = sscanf(s,"%d-%d-%d %d:%d:%f%s",
01022 &year,&month,&day,&hour,&min,&fltsec,buff);
01023
01024
01025 if ( nitems != 6 ) {
01026 std::cout << "ParseTimeString only got " << nitems << " items"
01027 << std::endl;
01028 }
01029
01030 sec = (int)fltsec;
01031 frac_sec = ( fltsec - sec );
01032
01033
01034
01035
01036 std::string tzstr(buff);
01037
01038 if( tzstr.find_first_not_of(" ()[]{}\n") != 0)
01039 tzstr.erase( 0, tzstr.find_first_not_of(" ()[]{}\n") );
01040 if( tzstr.find_last_not_of(" ()[]{}\n") != tzstr.length() )
01041 tzstr.erase( tzstr.find_last_not_of(" ()[]{}\n")+1, tzstr.length() );
01042
01043 isUTC = ( tzstr == "" || tzstr == "Z" || tzstr == "UTC" || tzstr == "GMT" );
01044
01045
01046
01047
01048
01049
01050
01051
01052
01053
01054
01055
01056
01057 if (year <= 37) year += 2000;
01058 if (year >= 70 && year <= 137) year += 1900;
01059
01060 if (year >= 1900) year -= 1900;
01061
01062 struct tm tmstruct;
01063 tmstruct.tm_year = year;
01064 tmstruct.tm_mon = month-1;
01065 tmstruct.tm_mday = day;
01066 tmstruct.tm_hour = hour;
01067 tmstruct.tm_min = min;
01068 tmstruct.tm_sec = sec;
01069 tmstruct.tm_isdst = -1;
01070
01071
01072
01073
01074
01075
01076 time_t utc_sec = (isUTC) ? MktimeFromUTC(&tmstruct) : mktime(&tmstruct);
01077
01078 double atime = utc_sec + frac_sec;
01079 return atime;
01080 }
01081
01082 std::string UTCTimeString(double ts)
01083 {
01084 char buffergmt[80];
01085 time_t gmttime = (time_t)ts;
01086 struct tm * timeinfogmt = gmtime( &gmttime );
01087 strftime (buffergmt,80,"%F %T (UTC)",timeinfogmt);
01088 return std::string( buffergmt );
01089 }
01090
01091 std::string LocalTimeString(double ts)
01092 {
01093 char bufferloc[80];
01094 time_t loctime = (time_t)ts;
01095 struct tm * timeinfoloc = localtime( &loctime );
01096 strftime (bufferloc,80,"%F %T (local)",timeinfoloc);
01097 return std::string( bufferloc );
01098 }
01099
01101