#include #include "Dim.h" #include "Event.h" #include "Shell.h" #include "StateMachineDim.h" #include "Connection.h" #include "Configuration.h" #include "Console.h" #include "tools.h" #include "LocalControl.h" #include "HeadersFTM.h" #include "HeadersRateScan.h" #include "HeadersRateControl.h" namespace ba = boost::asio; namespace bs = boost::system; namespace dummy = ba::placeholders; using namespace std; // ------------------------------------------------------------------------ #include "DimDescriptionService.h" #include "DimState.h" // ------------------------------------------------------------------------ class StateMachineRateControl : public StateMachineDim//, public DimInfoHandler { private: bool fTriggerOn; vector fBlock; DimVersion fDim; DimDescribedState fDimFTM; DimDescribedState fDimRS; DimDescribedService fDimThreshold; float fTargetRate; float fTriggerRate; uint16_t fThresholdMin; uint16_t fThresholdReference; bool fVerbose; uint64_t fCounter; bool CheckEventSize(const EventImp &evt, size_t size) { if (size_t(evt.GetSize())==size) return true; if (evt.GetSize()==0) return false; ostringstream msg; msg << evt.GetName() << " - Received event has " << evt.GetSize() << " bytes, but expected " << size << "."; Fatal(msg); return false; } vector fThresholds; void PrintThresholds(const FTM::DimStaticData &sdata) { //if (!fVerbose) // return; if (fThresholds.size()==0) return; Out() << "Min. DAC=" << fThresholdMin << endl; int t=0; for (t=0; t<160; t++) if (sdata.fThreshold[t]!=fThresholds[t]) break; if (t==160) return; for (int j=0; j<10; j++) { for (int k=0; k<4; k++) { for (int i=0; i<4; i++) if (fThresholds[i+k*4+j*16]!=fThresholdMin) Out() << setw(3) << fThresholds[i+k*4+j*16] << " "; else Out() << " - "; Out() << " "; } Out() << endl; } Out() << endl; } void Step(int idx, float step) { uint16_t diff = fThresholds[idx]+int16_t(truncf(step)); if (diff0 ? " += " : " -= "); Out() << fabs(step) << " (" << diff << ")" << endl; } const uint32_t val[2] = { idx, diff }; DimClient::sendCommandNB("FTM_CONTROL/SET_THRESHOLD", (void*)val, 8); fBlock[idx/4] = true; } void ProcessPatches(const FTM::DimTriggerRates &sdata) { // Caluclate Median and deviation vector medb(sdata.fBoardRate, sdata.fBoardRate+40); vector medp(sdata.fPatchRate, sdata.fPatchRate+160); sort(medb.begin(), medb.end()); sort(medp.begin(), medp.end()); vector devb(40); for (int i=0; i<40; i++) devb[i] = fabs(sdata.fBoardRate[i]-medb[i]); vector devp(160); for (int i=0; i<160; i++) devp[i] = fabs(sdata.fPatchRate[i]-medp[i]); sort(devb.begin(), devb.end()); sort(devp.begin(), devp.end()); double mb = (medb[19]+medb[20])/2; double mp = (medp[79]+medp[80])/2; double db = devb[27]; double dp = devp[109]; // If any is zero there is something wrong if (mb==0 || mp==0 || db==0 || dp==0) return; if (fVerbose) { Out() << "Patch: Median=" << mp << " Dev=" << dp << endl; Out() << "Board: Median=" << mb << " Dev=" << db << endl; } for (int i=0; i<40; i++) { if (fBlock[i]) { fBlock[i] = false; continue; } int maxi = -1; const float dif = fabs(sdata.fBoardRate[i]-mb)/db; if (dif>5) { if (fVerbose) Out() << "B" << i << ": " << dif << endl; float max = sdata.fPatchRate[i*4]; maxi = 0; for (int j=1; j<4; j++) if (sdata.fPatchRate[i*4+j]>max) { max = sdata.fPatchRate[i*4+j]; maxi = j; } } for (int j=0; j<4; j++) { // For the noise pixel correct down to median+3*deviation if (maxi==j) { // This is the step which has to be performed to go from // a NSB rate of sdata.fPatchRate[i*4+j] const float step = (log10(sdata.fPatchRate[i*4+j])-log10(mp+5*dp))/0.039; // * (dif-5)/dif Step(i*4+j, step); continue; } // For pixels below the meadian correct also back to median+3*deviation if (sdata.fPatchRate[i*4+j] medb(sdata.fBoardRate, sdata.fBoardRate+40); sort(medb.begin(), medb.end()); vector devb(40); for (int i=0; i<40; i++) devb[i] = fabs(sdata.fBoardRate[i]-medb[i]); sort(devb.begin(), devb.end()); double mb = (medb[19]+medb[20])/2; double db = devb[27]; // If any is zero there is something wrong if (mb==0 || db==0) { Warn("The median or the deviation of all board rates is zero... cannot calibrate."); return GetCurrentState(); } double avg = 0; int num = 0; for (int i=0; i<40; i++) { if ( fabs(sdata.fBoardRate[i]-mb)<2.5*db) { avg += sdata.fBoardRate[i]; num++; } } fTriggerRate = avg/num * 40; if (fVerbose) { Out() << "Board: Median=" << mb << " Dev=" << db << endl; Out() << "Camera: " << fTriggerRate << " (" << sdata.fTriggerRate << ", n=" << num << ")" << endl; Out() << "Target: " << fTargetRate << endl; } if (sdata.fTriggerRate0 && avg0 && fTriggerRate0 ? " += " : " -= "); Out() << step << " (" << diff << ")" << endl; } const uint32_t val[2] = { -1, diff }; DimClient::sendCommandNB("FTM_CONTROL/SET_THRESHOLD", (void*)val, 8); fThresholdMin = diff; return GetCurrentState(); } int HandleStaticData(const EventImp &evt) { if (!CheckEventSize(evt, sizeof(FTM::DimStaticData))) return GetCurrentState(); const FTM::DimStaticData &sdata = *static_cast(evt.GetData()); fTriggerOn = sdata.HasTrigger(); PrintThresholds(sdata); fThresholds.assign(sdata.fThreshold, sdata.fThreshold+160); return GetCurrentState(); } int HandleTriggerRates(const EventImp &evt) { if (fThresholds.size()==0) return GetCurrentState(); if (GetCurrentState()<=RateControl::State::kConnected || GetCurrentState()==RateControl::State::kGlobalThresholdSet) return GetCurrentState(); if (!CheckEventSize(evt, sizeof(FTM::DimTriggerRates))) return GetCurrentState(); const FTM::DimTriggerRates &sdata = *static_cast(evt.GetData()); if (GetCurrentState()==RateControl::State::kSettingGlobalThreshold) return ProcessCamera(sdata); if (GetCurrentState()==RateControl::State::kInProgress) ProcessPatches(sdata); return GetCurrentState(); } int Calibrate() { if (!fTriggerOn) { Info("Trigger not switched on... CALIBRATE command ignored."); return RateControl::State::kGlobalThresholdSet; } const int32_t val[2] = { -1, fThresholdReference }; Dim::SendCommand("FTM_CONTROL/SET_THRESHOLD", val); fThresholds.assign(160, fThresholdReference); fThresholdMin = fThresholdReference; fTriggerRate = -1; fCounter = 0; ostringstream out; out << "Rate calibration started at a threshold of " << fThresholdReference << " with a target rate of " << fTargetRate << " Hz"; Info(out); return RateControl::State::kSettingGlobalThreshold; } int StopRC() { return RateControl::State::kConnected; } int SetMinThreshold(const EventImp &evt) { if (!CheckEventSize(evt, 4)) return kSM_FatalError; // FIXME: Check missing fThresholdReference = evt.GetUShort(); return GetCurrentState(); } int SetTargetRate(const EventImp &evt) { if (!CheckEventSize(evt, 4)) return kSM_FatalError; fTargetRate = evt.GetFloat(); return GetCurrentState(); } int Print() const { Out() << fDim << endl; Out() << fDimFTM << endl; Out() << fDimRS << endl; return GetCurrentState(); } int SetVerbosity(const EventImp &evt) { if (!CheckEventSize(evt, 1)) return kSM_FatalError; fVerbose = evt.GetBool(); return GetCurrentState(); } int Execute() { if (!fDim.online()) return RateControl::State::kDimNetworkNA; // All subsystems are not connected if (fDimFTM.state()("quiet"); fThresholdReference = 300; fThresholdMin = 300; fTargetRate = 75; return -1; } }; // ------------------------------------------------------------------------ #include "Main.h" template int RunShell(Configuration &conf) { return Main::execute(conf); } void SetupConfiguration(Configuration &conf) { po::options_description control("Rate control options"); control.add_options() ("quiet,q", po_bool(), "Disable printing more informations during rate control.") //("max-wait", var(150), "The maximum number of seconds to wait to get the anticipated resolution for a point.") // ("resolution", var(0.05) , "The minimum resolution required for a single data point.") ; conf.AddOptions(control); } /* Extract usage clause(s) [if any] for SYNOPSIS. Translators: "Usage" and "or" here are patterns (regular expressions) which are used to match the usage synopsis in program output. An example from cp (GNU coreutils) which contains both strings: Usage: cp [OPTION]... [-T] SOURCE DEST or: cp [OPTION]... SOURCE... DIRECTORY or: cp [OPTION]... -t DIRECTORY SOURCE... */ void PrintUsage() { cout << "The ratecontrol program is a keep the rate reasonable low.\n" "\n" "Usage: ratecontrol [-c type] [OPTIONS]\n" " or: ratecontrol [OPTIONS]\n"; cout << endl; } void PrintHelp() { Main::PrintHelp(); /* Additional help text which is printed after the configuration options goes here */ /* cout << "bla bla bla" << endl << endl; cout << endl; cout << "Environment:" << endl; cout << "environment" << endl; cout << endl; cout << "Examples:" << endl; cout << "test exam" << endl; cout << endl; cout << "Files:" << endl; cout << "files" << endl; cout << endl; */ } int main(int argc, const char* argv[]) { Configuration conf(argv[0]); conf.SetPrintUsage(PrintUsage); Main::SetupConfiguration(conf); SetupConfiguration(conf); if (!conf.DoParse(argc, argv, PrintHelp)) return 127; if (!conf.Has("console")) return RunShell(conf); if (conf.Get("console")==0) return RunShell(conf); else return RunShell(conf); return 0; }