#include "Dim.h" #include "Event.h" #include "Shell.h" #include "StateMachineDim.h" #include "Connection.h" #include "Configuration.h" #include "Console.h" #include "Converter.h" #include "DimServiceInfoList.h" #include "PixelMap.h" #include "tools.h" #include "DimData.h" #include "LocalControl.h" #include "HeadersFAD.h" #include "HeadersBIAS.h" #include "HeadersFTM.h" using namespace std; // ------------------------------------------------------------------------ #include "DimDescriptionService.h" // ------------------------------------------------------------------------ const static string kHtmlWhite = "#ffffff"; const static string kHtmlYellow = "#fffff0"; const static string kHtmlRed = "#fff8f0"; const static string kHtmlGreen = "#f0fff0"; const static string kHtmlBlue = "#f0f0ff"; class StateMachineSmartFACT : public StateMachineDim, public DimInfoHandler { private: enum states_t { kStateDimNetworkNA = 1, kStateRunning, }; // ------------------------- Internal variables ----------------------- PixelMap fPixelMap; Time fLastUpdate; string fPath; // ----------------------------- Data storage ------------------------- uint32_t fMcpConfigurationState; int64_t fMcpConfigurationMaxTime; int64_t fMcpConfigurationMaxEvents; string fMcpConfigurationName; Time fMcpConfigurationRunStart; enum weather_t { kWeatherBegin=0, kTemp = kWeatherBegin, kDew, kHum, kPress, kWind, kGusts, kDir, kWeatherEnd = kDir+1 }; deque fMagicWeatherHist[kWeatherEnd]; vector fFeedbackCalibration; float fFeedbackTempOffset; float fFeedbackUserOffset; vector fBiasControlVoltageVec; float fBiasControlVoltageMed; float fBiasControlCurrentMed; float fBiasControlCurrentMax; deque fBiasControlCurrentHist; deque fFscControlTemperatureHist; float fFscControlTemperatureAvg; float fFscControlHumidityAvg; float fDriveControlPointingZd; string fDriveControlPointingAz; float fDriveControlTrackingDev; string fDriveControlSourceName; int64_t fFadControlNumEvents; float fFtmControlTriggerRateCam; deque fFtmControlTriggerRateHist; vector fFtmPatchThresholds; uint64_t fRateScanDataId; deque fRateScanDataHist; // ------------- Initialize variables before the Dim stuff ------------ DimServiceInfoList fNetwork; class DimState : public DimInfoHandler { public: DimState(const string &n, const string s="STATE") : server(n), info(make_pair(Time(), -2)), dim((n+"/"+s).c_str(), (void*)NULL, 0, this) { } string server; pair info; string msg; DimStampedInfo dim; void infoHandler() { DimInfo *curr = getInfo(); // get current DimInfo address if (!curr || curr != &dim) return; const bool disconnected = dim.getSize()==0; // Make sure getTimestamp is called _before_ getTimestampMillisecs const int tsec = dim.getTimestamp(); const int tms = dim.getTimestampMillisecs(); info = make_pair(Time(tsec, tms*1000), disconnected ? -2 : dim.getQuality()); msg = disconnected ? "" : dim.getString(); } const Time &time() const { return info.first; } const int &state() const { return info.second; } const string &name() const { return server; } }; class DimVersion : public DimState { public: DimVersion() : DimState("DIS_DNS", "VERSION_NUMBER") { } void infoHandler() { DimInfo *curr = getInfo(); // get current DimInfo address if (!curr || curr != &dim) return; DimState::infoHandler(); info.second = dim.getSize()==4 ? dim.getInt() : 0; } string version() const { if (info.second==0) return "Offline"; ostringstream out; out << "V" << info.second/100 << 'r' << info.second%100; return out.str(); } }; DimVersion fDim; DimState fDimMcp; DimState fDimControl; DimState fDimDataLogger; DimState fDimDriveControl; DimState fDimMagicWeather; DimState fDimFeedback; DimState fDimBiasControl; DimState fDimFtmControl; DimState fDimFadControl; DimState fDimFscControl; DimState fDimRateControl; DimState fDimRateScan; DimState fDimChatServer; DimStampedInfo fDimMcpConfiguration; DimStampedInfo fDimDriveControlPointing; DimStampedInfo fDimDriveControlTracking; DimStampedInfo fDimDriveControlSource; DimStampedInfo fDimFscControlTemperature; DimStampedInfo fDimFscControlHumidity; DimStampedInfo fDimMagicWeatherData; DimStampedInfo fDimFeedbackDeviation; DimStampedInfo fDimFeedbackCalibration; DimStampedInfo fDimBiasControlVoltage; DimStampedInfo fDimBiasControlCurrent; DimStampedInfo fDimFadConnections; DimStampedInfo fDimFadEvents; DimStampedInfo fDimFtmControlTriggerRates; DimStampedInfo fDimFtmControlStaticData; DimStampedInfo fDimRateScanData; DimStampedInfo *fDimFadControlEventData; // ------------------------------------------------------------------- const State GetState(const DimState &s) const { return fNetwork.GetState(s.name(), s.state()); } bool HandleService(DimInfo *curr, const DimInfo &service, void (StateMachineSmartFACT::*handle)(const DimData &)) { if (curr!=&service) return false; (this->*handle)(DimData(curr)); return true; } bool CheckDataSize(const DimData &d, const char *name, size_t size, bool min=false) { if ((!min && d.data.size()==size) || (min && d.data.size()>size)) return true; ostringstream msg; msg << name << " - Received service has " << d.data.size() << " bytes, but expected "; if (min) msg << "more than "; msg << size << "."; Warn(msg); return false; } // ------------------------------------------------------------------- template void WriteBinary(const string &fname, const T &t, double scale, double offset=0) { vector val(t.size(), 0); for (uint64_t i=0; i127) range=127; if (range<0) range=0; val[i] = (uint8_t)range; } const char *ptr = reinterpret_cast(val.data()); ofstream fout(fPath+"/"+fname+".bin"); fout << offset << '\n'; fout << offset+scale << '\n'; fout.write(ptr, val.size()*sizeof(uint8_t)); } // ------------------------------------------------------------------- struct Statistics { float min; float max; float med; float avg; //float rms; template Statistics(const T &t, size_t offset_min=0, size_t offset_max=0) : min(0), max(0), med(0), avg(0) { if (t.size()==0) return; T copy(t); sort(copy.begin(), copy.end()); if (offset_min>t.size()) offset_min = 0; if (offset_max>t.size()) offset_max = 0; min = copy[offset_min]; max = copy[copy.size()-1-offset_max]; avg = accumulate (t.begin(), t.end(), 0.)/t.size(); const size_t p = t.size()/2; med = copy[p]; } }; void HandleMcpConfiguration(const DimData &d) { if (!CheckDataSize(d, "Mcp:Configuration", 16, true)) return; fMcpConfigurationState = d.qos; fMcpConfigurationMaxTime = d.get(); fMcpConfigurationMaxEvents = d.get(8); fMcpConfigurationName = d.ptr(16); if (d.qos==12) fMcpConfigurationRunStart = Time(); } void WriteWeather(const DimData &d, const string &name, int i, float min, float max) { const Statistics stat(fMagicWeatherHist[i]); ostringstream out; out << setprecision(3); out << d.time.JavaDate() << '\n'; out << "#ffffff\t" << fMagicWeatherHist[i].back() << '\n'; out << "#ffffff\t" << stat.min << '\n'; out << "#ffffff\t" << stat.avg << '\n'; out << "#ffffff\t" << stat.max << '\n'; ofstream(fPath+"/"+name+".txt") << out.str(); WriteBinary("magicweather-"+name+"-hist", fMagicWeatherHist[i], max-min, min); } void HandleMagicWeatherData(const DimData &d) { if (!CheckDataSize(d, "MagicWeather:Data", 7*4+2)) return; // Store a history of the last 300 entries for (int i=kWeatherBegin; i(2)[i]); if (fMagicWeatherHist[i].size()>300) fMagicWeatherHist[i].pop_front(); } static const char *dir[] = { "N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW" }; const uint16_t idx = uint16_t(floor(fmod(fMagicWeatherHist[kDir].back()+360+11.25, 360)/22.5)); ostringstream out; out << d.time.JavaDate() << '\n'; for (int i=0; i<6; i++) out << "#ffffff\t" << fMagicWeatherHist[i].back() << '\n'; out << "#ffffff\t" << dir[idx] << '\n'; ofstream(fPath+"/magicweather.txt") << out.str(); WriteWeather(d, "temp", kTemp, -5, 35); WriteWeather(d, "dew", kDew, -5, 35); WriteWeather(d, "hum", kHum, 0, 100); WriteWeather(d, "wind", kWind, 0, 100); WriteWeather(d, "gusts", kGusts, 0, 100); WriteWeather(d, "press", kPress, 700, 1000); } void HandleDriveControlPointing(const DimData &d) { if (!CheckDataSize(d, "DriveControl:Pointing", 16)) return; fDriveControlPointingZd = d.get(); const double az = d.get(8); static const char *dir[] = { "N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW" }; const uint16_t i = uint16_t(floor(fmod(az+360+11.25, 360)/22.5)); fDriveControlPointingAz = dir[i]; ostringstream out; out << d.time.JavaDate() << '\n'; out << setprecision(5); out << fDriveControlPointingZd << '\n'; out << az << '\n'; ofstream(fPath+"/drive-pointing.txt") << out.str(); } void HandleDriveControlTracking(const DimData &d) { if (!CheckDataSize(d, "DriveControl:Tracking", 56)) return; const double zd = d.get(3*8) * M_PI / 180; const double dzd = d.get(5*8) * M_PI / 180; const double daz = d.get(6*8) * M_PI / 180; // Correct: // const double d = cos(del) - sin(zd+dzd)*sin(zd)*(1.-cos(daz)); // Simplified: const double dev = cos(dzd) - sin(zd+dzd)*sin(zd)*(1.-cos(daz)); fDriveControlTrackingDev = acos(dev) * 180 / M_PI * 3600; if (fDriveControlTrackingDev<0.01) fDriveControlTrackingDev=0; } void HandleDriveControlSource(const DimData &d) { if (!CheckDataSize(d, "DriveControl:Source", 7*4+2, true)) return; const double *ptr = d.ptr(); const double ra = ptr[0]; // Ra[h] const double dec = ptr[1]; // Dec[deg] const double woff = ptr[4]; // Wobble offset [deg] const double wang = ptr[5]; // Wobble angle [deg] fDriveControlSourceName = d.ptr(6*8); ostringstream out; out << d.time.JavaDate() << '\n'; out << "#ffffff\t" << fDriveControlSourceName << '\n'; out << setprecision(5); out << "#ffffff\t" << ra << '\n'; out << "#ffffff\t" << dec << '\n'; out << setprecision(3); out << "#ffffff\t" << woff << '\n'; out << "#ffffff\t" << wang << '\n'; ofstream(fPath+"/drive.txt") << out.str(); } void HandleFeedbackCalibration(const DimData &d) { if (!CheckDataSize(d, "Feedback:Calibration", 3*4*416)) { fFeedbackCalibration.clear(); return; } const float *ptr = d.ptr(); fFeedbackCalibration.assign(ptr+2*416, ptr+3*416); } void HandleFeedbackDeviation(const DimData &d) { if (!CheckDataSize(d, "Feedback:Deviation", 2*4*416+8)) return; const float *ptr = d.ptr(); vector dev(ptr+416, ptr+416+320); fFeedbackTempOffset = ptr[2*416]; fFeedbackUserOffset = ptr[2*416+1]; for (int i=0; i<320; i++) dev[i] -= fFeedbackTempOffset+fFeedbackUserOffset; // Write the 160 patch values to a file WriteBinary("feedback-deviation", dev, 1); const Statistics stat(dev, 3); ostringstream out; out << setprecision(3); out << d.time.JavaDate() << '\n'; out << kHtmlWhite << '\t' << fFeedbackUserOffset << '\n'; out << kHtmlWhite << '\t' << fFeedbackTempOffset << '\n'; out << kHtmlWhite << '\t' << stat.min << '\n'; out << kHtmlWhite << '\t' << stat.med << '\n'; out << kHtmlWhite << '\t' << stat.avg << '\n'; out << kHtmlWhite << '\t' << stat.max << '\n'; ofstream(fPath+"/feedback.txt") << out.str(); } void HandleBiasControlVoltage(const DimData &d) { if (!CheckDataSize(d, "BiasControl:Voltage", 1664)) { fBiasControlVoltageVec.clear(); return; } fBiasControlVoltageVec.assign(d.ptr(), d.ptr()+320); const Statistics stat(fBiasControlVoltageVec); fBiasControlVoltageMed = stat.med; vector val(320, 0); for (int i=0; i<320; i++) { const int idx = (fPixelMap.hv(i).hw()/9)*2+fPixelMap.hv(i).group(); val[idx] = fBiasControlVoltageVec[i]; } if (fDimBiasControl.state()==BIAS::kVoltageOn) WriteBinary("biascontrol-voltage", val, 10, 65); else WriteBinary("biascontrol-voltage", val, 75); ostringstream out; out << setprecision(3); out << d.time.JavaDate() << '\n'; out << kHtmlWhite << '\t' << stat.min << '\n'; out << kHtmlWhite << '\t' << stat.med << '\n'; out << kHtmlWhite << '\t' << stat.avg << '\n'; out << kHtmlWhite << '\t' << stat.max << '\n'; ofstream(fPath+"/voltage.txt") << out.str(); } void HandleBiasControlCurrent(const DimData &d) { if (!CheckDataSize(d, "BiasControl:Current", 832)) return; // Convert dac counts to uA vector v(320); for (int i=0; i<320; i++) v[i] = d.ptr()[i] * 5000./4096; const bool cal = fFeedbackCalibration.size()>0 && fBiasControlVoltageVec.size()>0; // Calibrate the data (subtract offset) if (cal) for (int i=0; i<320; i++) { v[i] -= fBiasControlVoltageVec[i]/fFeedbackCalibration[i]*1e6; v[i] /= fPixelMap.hv(i).group() ? 5 : 4; } // Get the maximum of each patch vector val(320, 0); for (int i=0; i<320; i++) { const int idx = (fPixelMap.hv(i).hw()/9)*2+fPixelMap.hv(i).group(); val[idx] = v[i]; } // Write the 160 patch values to a file WriteBinary("biascontrol-current", val, 100); const Statistics stat(v, 0, 3); // Exclude the three crazy channels fBiasControlCurrentMed = stat.med; fBiasControlCurrentMax = stat.max; // Store a history of the last 60 entries fBiasControlCurrentHist.push_back(fBiasControlCurrentMed); if (fBiasControlCurrentHist.size()>360) fBiasControlCurrentHist.pop_front(); // write the history to a file WriteBinary("biascontrol-current-hist", fBiasControlCurrentHist, 100); const string col0 = cal ? kHtmlGreen : kHtmlWhite; string col1 = col0; string col2 = col0; string col3 = col0; string col4 = col0; if (cal && stat.min>65) col1 = kYellow; if (cal && stat.min>80) col1 = kRed; if (cal && stat.med>65) col2 = kYellow; if (cal && stat.med>80) col2 = kRed; if (cal && stat.avg>65) col3 = kYellow; if (cal && stat.avg>80) col3 = kRed; if (cal && stat.max>65) col4 = kYellow; if (cal && stat.max>80) col4 = kRed; ostringstream out; out << setprecision(3); out << d.time.JavaDate() << '\n'; out << col0 << '\t' << (cal?"yes":"no") << '\n'; out << col1 << '\t' << stat.min << '\n'; out << col2 << '\t' << stat.med << '\n'; out << col3 << '\t' << stat.avg << '\n'; out << col4 << '\t' << stat.max << '\n'; ofstream(fPath+"/current.txt") << out.str(); } void HandleFadEvents(const DimData &d) { if (!CheckDataSize(d, "FadControl:Events", 4*4)) { fFadControlNumEvents = -1; return; } fFadControlNumEvents = d.get(); } void HandleFadConnections(const DimData &d) { if (!CheckDataSize(d, "FadControl:Connections", 41)) { //fStatusEventBuilderLabel->setText("Offline"); return; } string rc(40, '-'); // orange/red [45] const uint8_t *ptr = d.ptr(); int c[4] = { '.', '.', '.', '.' }; for (int i=0; i<40; i++) { const uint8_t stat1 = ptr[i]&3; const uint8_t stat2 = ptr[i]>>3; if (stat1==0 && stat2==0) rc[i] = '.'; // gray [46] else if (stat1>=2 && stat2==8) rc[i] = stat1==2?'+':'*'; // green [43] : check [42] if (rc[i](20)<0) return; fFtmControlTriggerRateCam = d.get(20); const float *brates = d.ptr(24); // Board rate const float *prates = d.ptr(24+160); // Patch rate // Store a history of the last 60 entries fFtmControlTriggerRateHist.push_back(fFtmControlTriggerRateCam); if (fFtmControlTriggerRateHist.size()>60) fFtmControlTriggerRateHist.pop_front(); // FIXME: Add statistics for all kind of rates WriteBinary("ftmcontrol-triggerrate-hist", fFtmControlTriggerRateHist, 100); WriteBinary("ftmcontrol-boardrates", vector(brates, brates+40), 10); WriteBinary("ftmcontrol-patchrates", vector(prates, prates+160), 10); ostringstream out; out << setprecision(3); out << d.time.JavaDate() << '\n'; out << "#ffffff\t" << fFtmControlTriggerRateCam << '\n'; ofstream(fPath+"/trigger.txt") << out.str(); const Statistics bstat(vector(brates, brates+40)); const Statistics pstat(vector(prates, prates+160)); out.str(""); out << d.time.JavaDate() << '\n'; out << kHtmlWhite << '\t' << bstat.min << '\n'; out << kHtmlWhite << '\t' << bstat.med << '\n'; out << kHtmlWhite << '\t' << bstat.avg << '\n'; out << kHtmlWhite << '\t' << bstat.max << '\n'; ofstream(fPath+"/boardrates.txt") << out.str(); out.str(""); out << d.time.JavaDate() << '\n'; out << kHtmlWhite << '\t' << pstat.min << '\n'; out << kHtmlWhite << '\t' << pstat.med << '\n'; out << kHtmlWhite << '\t' << pstat.avg << '\n'; out << kHtmlWhite << '\t' << pstat.max << '\n'; ofstream(fPath+"/patchrates.txt") << out.str(); } void HandleFtmControlStaticData(const DimData &d) { if (!CheckDataSize(d, "FtmControl:StaticData", 740)) return; const uint16_t *ptr = d.ptr(260); vector vec(ptr, ptr+160); WriteBinary("ftmcontrol-thresholds", vec, 1000); const Statistics stat(vec); ostringstream out; out << d.time.JavaDate() << '\n'; out << kHtmlWhite << '\t' << stat.min << '\n'; out << kHtmlWhite << '\t' << stat.med << '\n'; out << kHtmlWhite << '\t' << stat.avg << '\n'; out << kHtmlWhite << '\t' << stat.max << '\n'; ofstream(fPath+"/thresholds.txt") << out.str(); } void HandleFadControlEventData(const DimData &d) { if (!CheckDataSize(d, "FadControl:EventData", 23040)) return; //const float *avg = d.ptr(); //const float *rms = d.ptr(1440*sizeof(float)); const float *dat = d.ptr(1440*sizeof(float)*2); //const float *pos = d.ptr(1440*sizeof(float)*3); vector max(320, -2); for (int i=0; i<1440; i++) { if (i%9==8) continue; const int idx = (fPixelMap.hw(i).hw()/9)*2+fPixelMap.hw(i).group(); const double v = dat[i]/1000; if (v>max[idx]) max[idx]=v; } switch (d.qos) { case 0: WriteBinary("fadcontrol-eventdata", max, 2, -1); break; case 1: WriteBinary("fadcontrol-eventdata", max, 2, 0); break; default: WriteBinary("fadcontrol-eventdata", max, 0.25, 0); break; } } void HandleFscControlTemperature(const DimData &d) { if (!CheckDataSize(d, "FscControl:Temperature", 240)) return; const float *ptr = d.ptr(4); double avg = 0; double rms = 0; double min = 99; double max = -99; int num = 0; for (const float *t=ptr; tmax) max = *t; if (*t300) fFscControlTemperatureHist.pop_front(); const Statistics stat(fFscControlTemperatureHist); ostringstream out; out << setprecision(3); out << d.time.JavaDate() << '\n'; out << "#ffffff\t" << min << '\n'; out << "#ffffff\t" << avg << '\n'; out << "#ffffff\t" << max << '\n'; out << "#ffffff\t" << stat.min << '\n'; out << "#ffffff\t" << stat.avg << '\n'; out << "#ffffff\t" << stat.max << '\n'; ofstream(fPath+"/fsc.txt") << out.str(); WriteBinary("fsccontrol-temperature-hist", fFscControlTemperatureHist, 30); } void HandleFscControlHumidity(const DimData &d) { if (!CheckDataSize(d, "FscControl:Humidity", 5*4)) return; const float *ptr = d.ptr(4); double avg = 0; int num = 0; for (const float *t=ptr; t0) { avg += *t; num++; } fFscControlHumidityAvg = avg/num; } void HandleRateScanData(const DimData &d) { if (!CheckDataSize(d, "RateScan:Data", 24+200*40)) return; const uint64_t id = d.get(); const float rate = log10(d.get(20)); if (fRateScanDataId!=id) { fRateScanDataHist.clear(); fRateScanDataId = id; } fRateScanDataHist.push_back(rate); WriteBinary("ratescan-hist", fRateScanDataHist, 10, -1); } // ------------------------------------------------------------------- void infoHandler() { DimInfo *curr = getInfo(); // get current DimInfo address if (!curr) return; if (HandleService(curr, fDimMcpConfiguration, &StateMachineSmartFACT::HandleMcpConfiguration)) return; if (HandleService(curr, fDimMagicWeatherData, &StateMachineSmartFACT::HandleMagicWeatherData)) return; if (HandleService(curr, fDimDriveControlPointing, &StateMachineSmartFACT::HandleDriveControlPointing)) return; if (HandleService(curr, fDimDriveControlTracking, &StateMachineSmartFACT::HandleDriveControlTracking)) return; if (HandleService(curr, fDimDriveControlSource, &StateMachineSmartFACT::HandleDriveControlSource)) return; if (HandleService(curr, fDimFeedbackDeviation, &StateMachineSmartFACT::HandleFeedbackDeviation)) return; if (HandleService(curr, fDimFeedbackCalibration, &StateMachineSmartFACT::HandleFeedbackCalibration)) return; if (HandleService(curr, fDimBiasControlVoltage, &StateMachineSmartFACT::HandleBiasControlVoltage)) return; if (HandleService(curr, fDimBiasControlCurrent, &StateMachineSmartFACT::HandleBiasControlCurrent)) return; if (HandleService(curr, fDimFadConnections, &StateMachineSmartFACT::HandleFadConnections)) return; if (HandleService(curr, fDimFadEvents, &StateMachineSmartFACT::HandleFadEvents)) return; if (HandleService(curr, fDimFtmControlTriggerRates, &StateMachineSmartFACT::HandleFtmControlTriggerRates)) return; if (HandleService(curr, fDimFtmControlStaticData, &StateMachineSmartFACT::HandleFtmControlStaticData)) return; if (HandleService(curr, *fDimFadControlEventData, &StateMachineSmartFACT::HandleFadControlEventData)) return; if (HandleService(curr, fDimFscControlTemperature, &StateMachineSmartFACT::HandleFscControlTemperature)) return; if (HandleService(curr, fDimFscControlHumidity, &StateMachineSmartFACT::HandleFscControlHumidity)) return; if (HandleService(curr, fDimRateScanData, &StateMachineSmartFACT::HandleRateScanData)) return; } bool CheckEventSize(size_t has, const char *name, size_t size) { if (has==size) return true; ostringstream msg; msg << name << " - Received event has " << has << " bytes, but expected " << size << "."; Fatal(msg); return false; } void PrintState(const DimState &state) const { const State rc = GetState(state); Out() << state.time().GetAsStr("%H:%M:%S.%f").substr(0, 12) << " - "; Out() << kBold << state.name() << ": "; if (rc.index==-2) { Out() << kReset << "Offline" << endl; return; } Out() << rc.name << "[" << rc.index << "]"; Out() << kReset << " - " << kBlue << rc.comment << endl; } int Print() const { Out() << fDim.time().GetAsStr("%H:%M:%S.%f").substr(0, 12) << " - "; Out() << kBold << "DIM_DNS: " << fDim.version() << endl; PrintState(fDimMcp); PrintState(fDimControl); PrintState(fDimDataLogger); PrintState(fDimDriveControl); PrintState(fDimFadControl); PrintState(fDimFtmControl); PrintState(fDimBiasControl); PrintState(fDimFeedback); PrintState(fDimRateControl); PrintState(fDimFscControl); PrintState(fDimMagicWeather); PrintState(fDimRateScan); PrintState(fDimChatServer); return GetCurrentState(); } string GetStateHtml(const DimState &state, int green) const { const State rc = GetState(state); if (rc.index==-2 && state.state()>-2) { ostringstream out; out << kWhite << '\t' << state.state() << '\n'; return out.str(); } //ostringstream msg; //msg << kHtmlWhite << '\t' << rc.name << " [" << rc.index << "]\n"; //return msg.str(); if (rc.index<1) return kHtmlWhite + "\t---\n"; return (rc.index=5) // Idle { string col = kHtmlBlue; if (fMcpConfigurationState!= 5 && fMcpConfigurationState!=11 && fMcpConfigurationState!=12) // 9 e.g. Configuring3 col = kHtmlYellow; else if (fDimFadControl.state()==FAD::kWritingData) col = kHtmlGreen; out << col << '\t' << fMcpConfigurationName; if (fMcpConfigurationMaxEvents>0 || fMcpConfigurationMaxTime>0 || fMcpConfigurationState==12) out << " ["; if (fMcpConfigurationMaxEvents>0) { if (fFadControlNumEvents>0 && fMcpConfigurationState==12) out << fMcpConfigurationMaxEvents-fFadControlNumEvents; else out << fMcpConfigurationMaxEvents; } if (fMcpConfigurationMaxEvents>0 && (fMcpConfigurationMaxTime>0 || fMcpConfigurationState==12)) out << '/'; if (fMcpConfigurationMaxTime>0) { if (fMcpConfigurationState==12) { const uint32_t dt = (Time()-fMcpConfigurationRunStart).total_seconds(); if (dt>fMcpConfigurationMaxTime) out << "---"; else out << fMcpConfigurationMaxTime-dt << 's'; } else out << fMcpConfigurationMaxTime << 's'; } else { if (fMcpConfigurationState==12) { ostringstream d; d << Time()-fMcpConfigurationRunStart; out << d.str().substr(3, 5); } } if (fMcpConfigurationMaxEvents>0 || fMcpConfigurationMaxTime>0 || fMcpConfigurationState==12) out << ']'; } else out << kHtmlWhite; out << '\n'; // ------------------ Drive ----------------- if (fDimDriveControl.state()>=5) // Armed, Moving, Tracking { const State rc = GetState(fDimDriveControl); string col = kHtmlGreen; if (rc.index==6) // Moving col = kHtmlBlue; if (rc.index==5) // Armed col = kHtmlWhite; out << col << '\t'; out << rc.name << '\t'; out << fDriveControlPointingZd << '\t'; out << fDriveControlPointingAz << '\t'; if (fDimDriveControl.state()==7) { out << setprecision(2); out << fDriveControlTrackingDev << '\t'; out << setprecision(3); out << fDriveControlSourceName << '\n'; } else out << "\t\n"; } else out << kHtmlWhite << '\n'; // ------------------- FSC ------------------ if (fDimFscControl.state()>1) { out << kHtmlGreen << '\t' << fFscControlTemperatureAvg << '\n'; } else out << kHtmlWhite << '\n'; // --------------- MagicWeather ------------- if (fDimMagicWeather.state()==3 && fMagicWeatherHist[kWeatherBegin].size()>0) { /* const float diff = fMagicWeatherHist[kTemp].back()-fMagicWeatherHist[kDew].back(); string col1 = kHtmlRed; if (diff>0.3) col1 = kHtmlYellow; if (diff>0.7) col1 = kHtmlGreen; */ const float wind = fMagicWeatherHist[kGusts].back(); const float hum = fMagicWeatherHist[kHum].back(); string col = kHtmlGreen; if (wind>35 || hum>95) col = kHtmlYellow; if (wind>50 || hum>98) col = kHtmlRed; out << col << '\t'; out << fMagicWeatherHist[kHum].back() << '\t'; out << fMagicWeatherHist[kGusts].back() << '\n'; } else out << kHtmlWhite << "\n"; // --------------- FtmControl ------------- if (fDimFtmControl.state()>=FTM::kIdle) { string col = kHtmlGreen; if (fFtmControlTriggerRateCam<15) col = kHtmlYellow; if (fFtmControlTriggerRateCam>100) col = kHtmlRed; out << col << '\t' << fFtmControlTriggerRateCam << '\n'; } else out << kHtmlWhite << '\n'; // --------------- BiasControl ------------- if (fDimBiasControl.state()==BIAS::kRamping || fDimBiasControl.state()==BIAS::kOverCurrent || fDimBiasControl.state()==BIAS::kVoltageOn || fDimBiasControl.state()==BIAS::kVoltageOff) { string col = fBiasControlVoltageMed>3?kHtmlGreen:kHtmlWhite; if (fBiasControlCurrentMax>65) col = kHtmlYellow; if (fBiasControlCurrentMax>80) col = kHtmlRed; // Bias in overcurrent => Red if (fDimBiasControl.state()==BIAS::kOverCurrent) col = kHtmlRed; // MCP in ReadyForDatataking/Configuring/Configured/TriggerOn/TakingData // and Bias not in "data-taking state' => Red if (fDimMcp.state()>5 && fDimBiasControl.state()!=BIAS::kVoltageOn && fDimBiasControl.state()!=BIAS::kVoltageOff) col = kHtmlRed; const bool cal = fFeedbackCalibration.size(); // Feedback is currently calibrating => Blue if (fDimFeedback.state()==13) { out << kHtmlBlue << '\t'; out << "***\t"; out << "***\t"; } else { out << col << '\t'; out << fBiasControlCurrentMed << '\t'; if (cal) out << fBiasControlCurrentMax; else out << "— "; out << '\t'; } out << fBiasControlVoltageMed << '\n'; } else out << kHtmlWhite << '\n'; // ------------------------------------------ ofstream(fPath+"/fact.txt") << out.str(); // ========================================== out.str(""); out << now.JavaDate() << '\n'; if (fDim.state()==0) out << kHtmlWhite << "\tOffline\n\n\n\n\n\n\n\n\n\n\n\n"; else { out << kHtmlGreen << '\t' << fDim.version() << '\n'; out << GetStateHtml(fDimMcp, 4); out << kHtmlWhite << '\t' << (fDimControl.state()>-2?fDimControl.msg:"---") << "\n"; out << GetStateHtml(fDimDataLogger, 1); out << GetStateHtml(fDimDriveControl, 2); out << GetStateHtml(fDimFadControl, FAD::kConnected); out << GetStateHtml(fDimFtmControl, FTM::kConnected); out << GetStateHtml(fDimBiasControl, BIAS::kConnected); out << GetStateHtml(fDimFeedback, 4); out << GetStateHtml(fDimRateControl, 4); out << GetStateHtml(fDimFscControl, 2); out << GetStateHtml(fDimMagicWeather, 2); out << GetStateHtml(fDimRateScan, 4); out << GetStateHtml(fDimChatServer, 1); } ofstream(fPath+"/status.txt") << out.str(); return kStateRunning; } public: StateMachineSmartFACT(ostream &out=cout) : StateMachineDim(out, "SMART_FACT"), fPath("www/smartfact/data"), fMcpConfigurationMaxTime(0), fMcpConfigurationMaxEvents(0), fRateScanDataId(0), //--- fDimMcp ("MCP"), fDimControl ("DIM_CONTROL"), fDimDataLogger ("DATA_LOGGER"), fDimDriveControl ("DRIVE_CONTROL"), fDimMagicWeather ("MAGIC_WEATHER"), fDimFeedback ("FEEDBACK"), fDimBiasControl ("BIAS_CONTROL"), fDimFtmControl ("FTM_CONTROL"), fDimFadControl ("FAD_CONTROL"), fDimFscControl ("FSC_CONTROL"), fDimRateControl ("RATE_CONTROL"), fDimRateScan ("RATE_SCAN"), fDimChatServer ("CHAT_SERVER"), //--- fDimMcpConfiguration ("MCP/CONFIGURATION", (void*)NULL, 0, this), //--- fDimDriveControlPointing ("DRIVE_CONTROL/POINTING_POSITION", (void*)NULL, 0, this), fDimDriveControlTracking ("DRIVE_CONTROL/TRACKING_POSITION", (void*)NULL, 0, this), fDimDriveControlSource ("DRIVE_CONTROL/SOURCE_POSITION", (void*)NULL, 0, this), //--- fDimFscControlTemperature ("FSC_CONTROL/TEMPERATURE", (void*)NULL, 0, this), fDimFscControlHumidity ("FSC_CONTROL/HUMIDITY", (void*)NULL, 0, this), //--- fDimMagicWeatherData ("MAGIC_WEATHER/DATA", (void*)NULL, 0, this), //--- fDimFeedbackDeviation ("FEEDBACK/DEVIATION", (void*)NULL, 0, this), fDimFeedbackCalibration ("FEEDBACK/CALIBRATION", (void*)NULL, 0, this), //--- fDimBiasControlVoltage ("BIAS_CONTROL/VOLTAGE", (void*)NULL, 0, this), fDimBiasControlCurrent ("BIAS_CONTROL/CURRENT", (void*)NULL, 0, this), //--- fDimFadConnections ("FAD_CONTROL/CONNECTIONS", (void*)NULL, 0, this), fDimFadEvents ("FAD_CONTROL/EVENTS", (void*)NULL, 0, this), //--- fDimFtmControlTriggerRates("FTM_CONTROL/TRIGGER_RATES", (void*)NULL, 0, this), fDimFtmControlStaticData ("FTM_CONTROL/STATIC_DATA", (void*)NULL, 0, this), //- fDimRateScanData ("RATE_SCAN/DATA", (void*)NULL, 0, this), //- fDimFadControlEventData(0) { // State names AddStateName(kStateDimNetworkNA, "DimNetworkNotAvailable", "The Dim DNS is not reachable."); AddStateName(kStateRunning, "Running", ""); // Verbosity commands // AddEvent("SET_VERBOSE", "B:1") // (bind(&StateMachineMCP::SetVerbosity, this, placeholders::_1)) // ("set verbosity state" // "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data"); AddEvent("PRINT") (bind(&StateMachineSmartFACT::Print, this)) (""); } ~StateMachineSmartFACT() { delete fDimFadControlEventData; } int EvalOptions(Configuration &conf) { if (!fPixelMap.Read(conf.Get("pixel-map-file"))) { Error("Reading mapping table from "+conf.Get("pixel-map-file")+" failed."); return 1; } // First move all the dim services to another class so that // they can be instatiated all at once _after_ path was set //fPath = conf.Get("path"); // Pixel map is needed to deal with this service fDimFadControlEventData=new DimStampedInfo("FAD_CONTROL/EVENT_DATA", (void*)NULL, 0, this); return -1; } }; // ------------------------------------------------------------------------ #include "Main.h" template int RunShell(Configuration &conf) { return Main::execute(conf); } void SetupConfiguration(Configuration &conf) { po::options_description control("Smart FACT"); control.add_options() ("pixel-map-file", var("FACTmapV5a.txt"), "Pixel mapping file. Used here to get the default reference voltage") ("path", var("www/smartfact/data"), "Output path for the data-files") ; 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 << "SmartFACT is a tool writing the files needed for the SmartFACT web interface.\n" "\n" "The default is that the program is started without user intercation. " "All actions are supposed to arrive as DimCommands. Using the -c " "option, a local shell can be initialized. With h or help a short " "help message about the usuage can be brought to the screen.\n" "\n" "Usage: smartfact [-c type] [OPTIONS]\n" " or: smartfact [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 -1; //try { // No console access at all if (!conf.Has("console")) { // if (conf.Get("no-dim")) // return RunShell(conf); // else return RunShell(conf); } // Cosole access w/ and w/o Dim /* if (conf.Get("no-dim")) { if (conf.Get("console")==0) return RunShell(conf); else return RunShell(conf); } else */ { if (conf.Get("console")==0) return RunShell(conf); else return RunShell(conf); } } /*catch (std::exception& e) { cerr << "Exception: " << e.what() << endl; return -1; }*/ return 0; }