/* ToDo: * 1) Delay TriggerDataTimer * 2) * * * * * */ #include #include #include #include "FACT.h" #include "Dim.h" #include "Event.h" #include "StateMachineDim.h" #include "StateMachineAsio.h" #include "Connection.h" #include "LocalControl.h" #include "Configuration.h" #include "Console.h" #include "tools.h" #include "HeadersFPGAFTM.h" namespace ba = boost::asio; namespace bs = boost::system; namespace dummy = ba::placeholders; using namespace std; class ConnectionFPGAFTM : public Connection { public: static bool fIsFACT; private: bool fIsVerbose; bool fDebugRx; uint32_t fInterval; boost::asio::deadline_timer fRxTimeout; boost::asio::deadline_timer fDataTimer; vector fBuffer; bool fIsInitializing; FPGAFTM::Config fConf; FPGAFTM::Data fData; virtual void UpdateConfiguration(const FPGAFTM::Config &) { } virtual void UpdateData(uint8_t, const FPGAFTM::Data &) { } virtual void UpdateTrigger(uint8_t, const uint64_t &) { } queue fQueue; void HandleReadTimeout(const bs::error_code &error) { if (error==ba::error::basic_errors::operation_aborted) return; if (error) { ostringstream str; str << "Read timeout: " << error.message() << " (" << error << ")"; Error(str); PostClose(false); return; } if (!is_open()) { // For example: Here we could schedule a new accept if we // would not want to allow two connections at the same time. return; } // Check whether the deadline has passed. We compare the deadline // against the current time since a new asynchronous operation // may have moved the deadline before this actor had a chance // to run. //if (fRxTimeout.expires_at() > ba::deadline_timer::traits_type::now()) // return; Error("Timeout ("+to_simple_string(fRxTimeout.expires_from_now())+") reading data."); PostClose(false); } void HandleDataTimer(const bs::error_code &error) { if (error==ba::error::basic_errors::operation_aborted) return; if (error) { ostringstream str; str << "Data timer: " << error.message() << " (" << error << ")"; Error(str); PostClose(false); return; } if (!is_open()) return; SendWrite(FPGAFTM::kOnTime); SendRead(FPGAFTM::kRS485Data); SendRead(FPGAFTM::kClockMeasure); SendRead(FPGAFTM::kTimerMeasure); SendRead(FPGAFTM::kADC1); TriggerDataTimer(); } void HandleReceivedData(const boost::system::error_code& err, size_t bytes_received, int) { // Do not schedule a new read if the connection failed. if (err) { // 107: Transport endpoint is not connected (bs::error_code(107, bs::system_category)) // 125: Operation canceled if (err && err!=ba::error::eof && // Connection closed by remote host err!=ba::error::basic_errors::not_connected && // Connection closed by remote host err!=ba::error::basic_errors::operation_aborted) // Connection closed by us { ostringstream str; str << "Reading from " << URL() << ": " << err.message() << " (" << err << ")";// << endl; Error(str); } PostClose(err!=ba::error::basic_errors::operation_aborted); return; } if (bytes_received!=16) { Error(Tools::Form("Number of received bytes (%d) does not match 16", bytes_received)); PostClose(false); return; } // Keep time of (async) data reception const Time time; bool _ignore = false; //Ignore temperature read errors FPGAFTM::BusData &data = *reinterpret_cast(fBuffer.data()); // Print raw message in verbose mode if (fDebugRx) Out() << "RX|" << data << endl; // Some sanity checks if (data.fStartBits!=0xffff || data.fStopBits!=0xffff) { Error(Tools::Form("Frame bytes mismatch (%04x|%04x)", data.fStartBits, data.fStopBits)); PostClose(false); return; } if (!data.isCrcValid()) { Error(Tools::Form("Checksum mismatch (Received: %d, Expected: %d)", data.fCrc, data.calcCrc())); PostClose(false); return; } if (data.fReadWrite==FPGAFTM::kCmdError) { ostringstream msg; msg << "FPGA returned an error: "; switch (data.fData) { case FPGAFTM::kErrFrameStart: msg << "Start bytes wrong"; break; case FPGAFTM::kErrFrameStop: msg << "Stop bytes wrong"; break; case FPGAFTM::kErrFrameCrc: msg << "Checksum error"; break; case FPGAFTM::kErrUnknownCmd: msg << "Command unknown"; break; case FPGAFTM::kErrForbiddenCmd: msg << "Command not allowed"; break; case FPGAFTM::kErrTempReadCmd: msg << "Temperature read failed"; _ignore = true; break; case FPGAFTM::kErrTempReadBusy: msg << "Temperature read busy"; _ignore = true; break; default: msg << "Unknwon error"; break; } msg << Tools::Form(" [%04x]", data.fData); if (!_ignore) { Error(msg); PostClose(false); return; } Warn(msg); } if (fQueue.empty() && data.fReadWrite!=FPGAFTM::kCmdADM) { Error(Tools::Form("Unexpected answer [%02x|%04x] received.", data.fReadWrite, data.fCommand)); PostClose(false); return; } if (!fQueue.empty() && data.fReadWrite!=FPGAFTM::kCmdADM && fQueue.front().id() != data.id() && !_ignore) { Error(Tools::Form("Command mismatch (Received: %06x, Expected: %06x)", data.id(), fQueue.front().id())); PostClose(false); return; } // Requested Message received -> cancel timeout if (!fQueue.empty() && data.fReadWrite!=FPGAFTM::kCmdADM) fRxTimeout.cancel(); switch (data.fCommand) { case FPGAFTM::kRegProductId: fConf.fProductId = data.fData; UpdateConfiguration(fConf); Info(Tools::Form("Product ID = 0x%x", data.fData)); // FIXME: Check for validity break; case FPGAFTM::kRegFirmwareId: fConf.fFirmwareId = data.fData; UpdateConfiguration(fConf); Info(Tools::Form("Firmware = 0x%x", data.fData)); // FIXME: Check for validity break; case FPGAFTM::kClockEnable: fConf.fClockState = data.fCommand>>8; UpdateConfiguration(fConf); Info("Clock enabled."); break; case FPGAFTM::kClockDisable: fConf.fClockState = data.fCommand>>8; UpdateConfiguration(fConf); Info("Clock disabled."); break; case FPGAFTM::kClockShutdown: fConf.fClockState = data.fCommand>>8; UpdateConfiguration(fConf); Info("Clock shut down."); break; case FPGAFTM::kTimerEnable: fConf.fTimerState = data.fCommand>>8; UpdateConfiguration(fConf); Info("TIM timer enabled."); break; case FPGAFTM::kTimerDisable: fConf.fTimerState = data.fCommand>>8; UpdateConfiguration(fConf); Info("TIM timer disabled."); break; case FPGAFTM::kTimerShutdown: fConf.fTimerState = data.fCommand>>8; UpdateConfiguration(fConf); Info("TIM timer shut down."); break; case FPGAFTM::kClockFrequency: { const uint16_t dac = (data.fData>>2) &0x3ff; const uint16_t oct = (data.fData>>12)&0xf; const double freq = pow(2, oct)*2078/(2-dac/1024.)/1000; fConf.fClockFrequency64 = data.fData; fConf.fClockFrequencyD = freq; UpdateConfiguration(fConf); Info(Tools::Form("Clock frequency = %.2f kHz [dac=%d; oct=%d]", freq, dac, oct)); } break; case FPGAFTM::kTimerFrequency: { const uint16_t dac = (data.fData>>2) &0x3ff; const uint16_t oct = (data.fData>>12)&0xf; const double freq = pow(2, oct)*2078/(2-dac/1024.)/1000; fConf.fTimerFrequency64 = data.fData; fConf.fTimerFrequencyD = freq; UpdateConfiguration(fConf); Info(Tools::Form("Timer frequency = %.2f kHz [dac=%d; oct=%d]", freq, dac, oct)); } break; case FPGAFTM::kTriggerInternal: fConf.fTriggerState = data.fCommand>>8; UpdateConfiguration(fConf); Info("Internal trigger turned on ["+to_string(fConf.fTriggerState)+"]"); break; case FPGAFTM::kTriggerExternal: fConf.fTriggerState = data.fCommand>>8; UpdateConfiguration(fConf); Info("External trigger turned on ["+to_string(fConf.fTriggerState)+"]"); break; /* case FPGAFTM::kTriggerRandom: fConf.fTriggerState = data.fCommand>>8; UpdateConfiguration(fConf); Info("Random trigger turned on ["+to_string(fConf.fTriggerState)+"]"); break; */ case FPGAFTM::kTriggerShutdown: fConf.fTriggerState = data.fCommand>>8; UpdateConfiguration(fConf); Info("Trigger turned off ["+to_string(fConf.fTriggerState)+"]"); break; case FPGAFTM::kTriggerSourceMask: fConf.fTriggerSourceMask = data.fData; UpdateConfiguration(fConf); Info(Tools::Form("Trigger source mask set [%x]", data.fData)); break; case FPGAFTM::kTriggerOutSourceMask: fConf.fTriggerOutSourceMask = data.fData; UpdateConfiguration(fConf); Info(Tools::Form("Trigger-out source mask set [%x]", data.fData)); break; /* case FPGAFTM::kTriggerOutputMask: fConf.fTriggerOutputMask = data.fData; UpdateConfiguration(fConf); Info(Tools::Form("Trigger output mask set [%x]", data.fData)); break; */ case FPGAFTM::kTriggerHoldOff: fConf.fTriggerHoldOff24 = data.fData&0xffffff; UpdateConfiguration(fConf); Info(Tools::Form("Trigger hold off = %d us", fConf.fTriggerHoldOff24)); break; /* case FPGAFTM::kTriggerRS485On: fConf.fRS485OnOff = data.fCommand>>8; UpdateConfiguration(fConf); Info("RS485 communication turned on."); break; case FPGAFTM::kTriggerRS485Off: fConf.fRS485OnOff = data.fCommand>>8; UpdateConfiguration(fConf); Info("RS485 communication turned off."); break; */ case FPGAFTM::kTriggerPeriod: { const double freq = 1e6/data.fData; // old: 2*4150. fConf.fTriggerPeriod32 = data.fData; UpdateConfiguration(fConf); Info(Tools::Form("Trigger period = %.2f Hz (%d)", freq, data.fData)); break; } case FPGAFTM::kTriggerDspDelay: fConf.fTriggerDspDelay = data.fData; UpdateConfiguration(fConf); Info(Tools::Form("Trigger dsp delay = %.1f ns (%d)", data.fData*2.5, data.fData)); break; case FPGAFTM::kTriggerExtDelay: fConf.fTriggerExtDelay = data.fData; UpdateConfiguration(fConf); Info(Tools::Form("Trigger ext delay = %.1f ns (%d)", data.fData*2.5, data.fData)); break; case FPGAFTM::kTriggerOutDelay: fConf.fTriggerOutDelay = data.fData; UpdateConfiguration(fConf); Info(Tools::Form("Trigger out delay = %.1f ns (%d)", data.fData*2.5, data.fData)); break; case FPGAFTM::kTriggerInhibitState: // Looks like the current state of the line rather than the state is returned fConf.fTriggerInhibitState = data.fData; UpdateConfiguration(fConf); Info(Tools::Form("Trigger inhibit state = %d ", data.fData)); break; case FPGAFTM::kTriggerInhibitEnable: //fConf.fTriggerInhibitState = data.fData; //UpdateConfiguration(fConf); // The value returned is always 0 Info(Tools::Form("INH_HACK! Trigger inhibit state = %d ", data.fData)); break; case FPGAFTM::kTriggerInhibitTime: fConf.fTriggerInhibitTime = data.fData; UpdateConfiguration(fConf); Info(Tools::Form("Trigger inhibit time = %.1f ns (%d)", data.fData*5.0, data.fData)); break; case FPGAFTM::kFadResetLo: case FPGAFTM::kFadResetHi: Info("FAD reset signal="+to_string(data.fCommand)); break; case FPGAFTM::kSingleTrigger: Info("Single trigger."); break; case FPGAFTM::kOnTime: { const uint32_t total = data.fData>>32; // 10ns const uint32_t dead = data.fData; // 10ns fData.fRunTime = total; fData.fDeadTime = dead; UpdateData(0, fData); if (fIsVerbose || fIsInitializing) Info(Tools::Form("Dead time counter: Total=%.2fus Veto=%.2fus (%.1f%%)", total*0.01, dead*0.01, 100.*dead/total)); //fDimConf.set(PSU::kBitADM, data[0]); //UpdateConfig(time, data.id(), fDimConf); } break; case FPGAFTM::kRS485Data: fData.fTriggerCounter = data.fData; UpdateData(1, fData); if (fIsVerbose || fIsInitializing) Info(Tools::Form("RS485 data = %016lx", data.fData)); break; case FPGAFTM::kClockMeasure: fData.fClockFrequency = data.fData; UpdateData(2, fData); if (fIsVerbose || fIsInitializing) Info(Tools::Form("Measured clock frequency = %d Hz", data.fData)); break; case FPGAFTM::kTimerMeasure: fData.fTimerFrequency = data.fData; UpdateData(3, fData); if (fIsVerbose || fIsInitializing) Info(Tools::Form("Measured timer frequency = %d Hz", data.fData)); break; case FPGAFTM::kADC1: fData.SetADC1(data.fData); UpdateData(4, fData); if (fIsVerbose || fIsInitializing) Info(Tools::Form("ADC1 = %.1f degC (%04x)", fData.fTemp1, fData.fADC1)); break; default: if(!_ignore) { Error(Tools::Form("Unknown command byte received (%d)", data.fCommand)); PostClose(false); return; } else { break; } } // Start reading of next package AsyncRead(ba::buffer(fBuffer)); // If this was an automatic package no further handling should be done if (data.fReadWrite==FPGAFTM::kCmdADM) return; // Remove the request for which we just processed the answer from // the queue. This could have a check for an empty queue, but an // empty queue here should never happen! fQueue.pop(); // If this is the answer to the last sent initialization request // Initialization is done if (fQueue.empty() && fIsInitializing) { PrintConfig(); fIsInitializing = false; StartDataTimer(); return; } // send next request if queue not empty PostCommandFromQueue(); } void PostCommandFromQueue() { if (fQueue.empty()) return; const FPGAFTM::BusData &dat = fQueue.front(); PostMessage(&dat, sizeof(dat)); if (GetDebugTx()) Out() << "TX|" << dat << endl; AsyncWait(fRxTimeout, 1000, &Connection::HandleReadTimeout); } public: void SendCommand(uint8_t rw, uint16_t cmd, uint64_t d0=0) { fQueue.emplace(rw, cmd, d0); if (fQueue.size()==1) PostCommandFromQueue(); } void SendWrite(uint16_t cmd, uint64_t val=0) { SendCommand(FPGAFTM::kCmdWrite, cmd, val); } void SendRead(uint16_t cmd, uint64_t val=0) { SendCommand(FPGAFTM::kCmdRead, cmd, val); } // This is called when a connection was established void ConnectionEstablished() { Info("Connection established to "+URL()+"..."); fQueue = queue(); SendRead(FPGAFTM::kRegProductId); SendRead(FPGAFTM::kRegFirmwareId); // SendRead(FPGAFTM::kRegError); SendRead(FPGAFTM::kClockFrequency); SendRead(FPGAFTM::kClockMeasure); SendWrite(FPGAFTM::kClockEnable); // SendRead(FPGAFTM::kClockFrequency); // SendRead(FPGAFTM::kTimerState); SendRead(FPGAFTM::kTimerFrequency); // SendRead(FPGAFTM::kTimerMeasure); // The default is to report 'enabled' but no frequency is shown SendRead(FPGAFTM::kTimerShutdown); SendWrite(FPGAFTM::kTriggerSourceMask); SendWrite(FPGAFTM::kTriggerOutSourceMask); //SendWrite(FPGAFTM::kTriggerOutputMask); SendWrite(FPGAFTM::kTriggerHoldOff); SendWrite(FPGAFTM::kTriggerDspDelay); SendWrite(FPGAFTM::kTriggerExtDelay); SendWrite(FPGAFTM::kTriggerOutDelay); SendWrite(FPGAFTM::kTriggerShutdown); SendRead(FPGAFTM::kTriggerPeriod); fIsInitializing = true; AsyncRead(ba::buffer(fBuffer)); } public: ConnectionFPGAFTM(ba::io_service& ioservice, MessageImp &imp) : Connection(ioservice, imp()), fIsVerbose(true), fDebugRx(false), fRxTimeout(ioservice), fDataTimer(ioservice), fBuffer(16), fIsInitializing(false) { SetLogStream(&imp); } void SetVerbose(bool b) { fIsVerbose = b; } void SetDebugRx(bool b) { fDebugRx = b; Connection::SetVerbose(b); } void SetDebugTx(bool b) { Connection::SetDebugTx(b); } int GetState() const { if (!IsConnected()) return FPGAFTM::State::kDisconnected; if (fIsInitializing) return FPGAFTM::State::kConnected; return FPGAFTM::State::kValid; } size_t GetQueueSize() const { return fQueue.size(); } uint8_t GetTriggerState() const { return fConf.fTriggerState; } uint8_t IsTriggerOn() const { return fConf.fTriggerState!=FPGAFTM::kShutdown; } int PrintConfig() { Out() << fConf; return StateMachineImp::kSM_KeepState; } int PrintDynamicData() { Out() << fData; return StateMachineImp::kSM_KeepState; } void TriggerDataTimer() { if (fInterval==0) return; fDataTimer.expires_at(fDataTimer.expires_at()+boost::posix_time::milliseconds(fInterval)); fDataTimer.async_wait(boost::bind(&ConnectionFPGAFTM::HandleDataTimer, this, dummy::error)); } void StartDataTimer() { fDataTimer.cancel(); if (fInterval>0 && IsConnected() && !fIsInitializing) { SendWrite(FPGAFTM::kOnTime); fDataTimer.expires_at(Time()+boost::posix_time::milliseconds(fInterval)); fDataTimer.async_wait(boost::bind(&ConnectionFPGAFTM::HandleDataTimer, this, dummy::error)); } } void SetInterval(uint32_t i=0) { fInterval = i; StartDataTimer(); } }; bool ConnectionFPGAFTM::fIsFACT = true; // ------------------------------------------------------------------------ #include "DimDescriptionService.h" class ConnectionDimFPGAFTM : public ConnectionFPGAFTM { private: DimDescribedService fDimConfig; DimDescribedService fDimData; public: ConnectionDimFPGAFTM(ba::io_service& ioservice, MessageImp &imp) : ConnectionFPGAFTM(ioservice, imp), fDimConfig(fIsFACT?"FPGAFTM_CONTROL/CONFIGURATION":"FTM_CONTROL/CONFIGURATION", "X:1;X:1;C:1;X:1;D:1;C:1;X:1;D:1;C:1;C:1;C:1;S:1;S:1;S:1;I:1;I:1;C:1;S:1", "|firmware[uint64]:Firmware ID" "|product[uint64]:Product ID" "|clk_state[uint8]:Clock state" "|clk_freq_raw[uint64]:Clock frequency (raw)" "|clk_freq[Hz]:Clock frequency" "|tim_state[uint8]:Timer state" "|tim_freq_raw[uint64]:Timer frequency (raw)" "|tim_freq[Hz]:Timer frequency" "|trg_mode[uint8]:Trigger Mode" "|trg_mask[uint8]:Trigger Source-Mask" "|trg_out_mask[uint8]:Trigger Out Source-Mask" "|trg_delay_dsp[2.5ns]:Trigger Delay DSP" "|trg_delay_ext[2.5ns]:Trigger Delay EXT" "|trg_delay_out[2.5ns]:Trigger Delay OUT" "|trg_period[uint32]:Trigger Period" "|trg_hold_off[uint24]:Trigger Hold Off" "|trg_inhibit_state[uint8]:" "|trg_inhibit_time[5ns]:"), fDimData(fIsFACT?"FPGAFTM_CONTROL/DATA":"FTM_CONTROL/DATA", "I:1;I:1;I:1;I:1;I:1;S:1;F:1", "|run_time[10ns]:Absolute Run Time" "|dead_time[10ns]:Measured Dead Time" "|trg_counter[uint32]:Trigger counter" "|clk_freq[Hz]:Clock frequency measured" "|tim_freq[Hz]:Timer frequency measured" "|adc[uint10]:ADC value (raw)" "|temp[degC]:Temperature corresponding to ADC value") { } void UpdateConfiguration(const FPGAFTM::Config &conf) { //fDim.setQuality(status.GetVal()); fDimConfig.setData(conf); fDimConfig.Update(); } void UpdateData(uint8_t qos, const FPGAFTM::Data &data) { fDimData.setQuality(qos); fDimData.setData(data); fDimData.Update(); } }; // ------------------------------------------------------------------------ template class StateMachineFPGAFTM : public StateMachineAsio { private: S fFTM; Time fLastCommand; 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 << "."; T::Fatal(msg); return false; } int SetVerbosity(const EventImp &evt) { if (!CheckEventSize(evt.GetSize(), "SetVerbosity", 1)) return T::kSM_FatalError; fFTM.SetVerbose(evt.GetBool()); return T::GetCurrentState(); } int SetDebugRx(const EventImp &evt) { if (!CheckEventSize(evt.GetSize(), "SetDebugRx", 1)) return T::kSM_FatalError; fFTM.SetDebugRx(evt.GetBool()); return T::GetCurrentState(); } int SetDebugTx(const EventImp &evt) { if (!CheckEventSize(evt.GetSize(), "SetDebugTx", 1)) return T::kSM_FatalError; fFTM.SetDebugTx(evt.GetBool()); return T::GetCurrentState(); } int Disconnect() { // Close all connections fFTM.PostClose(false); /* // Now wait until all connection have been closed and // all pending handlers have been processed poll(); */ return T::GetCurrentState(); } int Reconnect(const EventImp &evt) { // Close all connections to supress the warning in SetEndpoint fFTM.PostClose(false); // Now wait until all connection have been closed and // all pending handlers have been processed ba::io_service::poll(); if (evt.GetBool()) fFTM.SetEndpoint(evt.GetString()); // Now we can reopen the connection fFTM.PostClose(true); return T::GetCurrentState(); } uint16_t fTriggerMode; // Kommand to be sent to turn the trigger on int Configure(const EventImp &evt) { const string name = evt.GetText(); auto it = fRunTypes.find(name); if (it==fRunTypes.end()) { T::Info("Configure - Run-type '"+name+"' not found... trying 'default'."); it = fRunTypes.find("default"); if (it==fRunTypes.end()) { T::Error("Configure - Run-type 'default' not found."); return T::GetCurrentState(); } } Dim::SendCommand("FTU_CONTROL/ENABLE_PRESCALING", uint8_t(0)); fFTM.SendWrite(FPGAFTM::kTriggerShutdown); //fFTM.SendWrite(FPGAFTM::kTriggerRS485On); fFTM.SendWrite(FPGAFTM::kTriggerPeriod, it->second.fTriggerPeriod); fFTM.SendWrite(FPGAFTM::kTriggerSourceMask, it->second.fTriggerSourceMask); fFTM.SendWrite(FPGAFTM::kTriggerOutSourceMask, it->second.fTriggerOutSourceMask); fFTM.SendWrite(FPGAFTM::kTriggerDspDelay, it->second.fTriggerDspDelay); fFTM.SendWrite(FPGAFTM::kTriggerExtDelay, it->second.fTriggerExtDelay); fFTM.SendWrite(FPGAFTM::kTriggerOutDelay, it->second.fTriggerOutDelay); fFTM.SendWrite(FPGAFTM::kTriggerHoldOff, it->second.fTriggerHoldOff); //fFTM.SendWrite(FPGAFTM::kRS485Data); fTriggerMode = FPGAFTM::kTriggerShutdown; if (it->second.fTriggerType=="internal") fTriggerMode = FPGAFTM::kTriggerInternal; if (it->second.fTriggerType=="external") fTriggerMode = FPGAFTM::kTriggerExternal; //if (it->second.fTriggerType=="random") // fTriggerMode = FPGAFTM::kTriggerRandom; return FPGAFTM::State::kConfiguring; } int ResetConfig() { return fFTM.GetState(); } int StartTrigger() { fFTM.StartDataTimer(); fFTM.SendWrite(fTriggerMode); return T::GetCurrentState();//FPGAFTM::State::kTriggerOn; } int ReadRegister(uint16_t cmd) { fFTM.SendRead(cmd); return T::GetCurrentState(); } int WriteRegister(uint16_t cmd) { fFTM.SendWrite(cmd); return T::GetCurrentState(); } int ReadReg(const EventImp &evt) { if (!CheckEventSize(evt.GetSize(), "Read", 2)) return T::kSM_FatalError; fFTM.SendRead(evt.GetUShort()); return T::GetCurrentState(); } int WriteReg(const EventImp &evt) { if (!CheckEventSize(evt.GetSize(), "Write", 10)) return T::kSM_FatalError; fFTM.SendWrite(evt.GetUShort(), evt.Get(2)); return T::GetCurrentState(); } int WriteRegister64(const EventImp &evt, uint16_t cmd) { if (!CheckEventSize(evt.GetSize(), "WriteRegister64", 8)) return T::kSM_FatalError; fFTM.SendWrite(cmd, evt.Get()); return T::GetCurrentState(); } int ShutdownTrigger(const EventImp &evt) { if (!CheckEventSize(evt.GetSize(), "ShutdownTrigger", 1)) return T::kSM_FatalError; fFTM.SendWrite(FPGAFTM::kTriggerShutdown, evt.GetBool()); return T::GetCurrentState(); } int SetFADReset(const EventImp &evt) { if (!CheckEventSize(evt.GetSize(), "SetFADReset", 1)) return T::kSM_FatalError; fFTM.SendWrite(evt.GetBool() ? FPGAFTM::kFadResetHi : FPGAFTM::kFadResetLo); return T::GetCurrentState(); } int SendFADReset(const EventImp &evt) { if (!CheckEventSize(evt.GetSize(), "SendFADReset", 0)) return T::kSM_FatalError; fFTM.SendWrite(FPGAFTM::kFadResetHi); fFTM.SendWrite(FPGAFTM::kFadResetLo); return T::GetCurrentState(); } int SetClockFrequency(const EventImp &evt) { if (!CheckEventSize(evt.GetSize(), "SetClockFrequency", 4)) return T::kSM_FatalError; const uint16_t m = evt.Get(0); const uint16_t e = evt.Get(2); if (m>0x3ff) { T::Warn("Clock frequency matinsse exceeds allowed range (10 bit)... ignored."); return T::GetCurrentState(); } if (e>0xf) { T::Warn("Clock frequency exponent exceeds allowed range (4 bit)... ignored."); return T::GetCurrentState(); } fFTM.SendWrite(FPGAFTM::kClockFrequency, (e<<12)|(m<<2)); return T::GetCurrentState(); } int SetTimerFrequency(const EventImp &evt) { if (!CheckEventSize(evt.GetSize(), "SetTimerFrequency", 4)) return T::kSM_FatalError; const uint16_t m = evt.Get(0); const uint16_t e = evt.Get(2); if (m>0x3ff) { T::Warn("Timer frequency matinsse exceeds allowed range (10 bit)... ignored."); return T::GetCurrentState(); } if (e>0xf) { T::Warn("Timer frequency exponent exceeds allowed range (4 bit)... ignored."); return T::GetCurrentState(); } fFTM.SendWrite(FPGAFTM::kTimerFrequency, (e<<12)|(m<<2)); return T::GetCurrentState(); } int SetTriggerPeriod(const EventImp &evt) { if (!CheckEventSize(evt.GetSize(), "SetTriggerPeriod", 8)) return T::kSM_FatalError; if (evt.GetXtra()<0 || evt.GetXtra()>0xffffffff) { T::Warn("Trigger period out of range (32bit)... ignored."); return T::GetCurrentState(); } fFTM.SendWrite(FPGAFTM::kTriggerPeriod, evt.GetUInt()); return T::GetCurrentState(); } int SetTriggerHoldOff(const EventImp &evt) { if (!CheckEventSize(evt.GetSize(), "SetTriggerHoldOff", 4)) return T::kSM_FatalError; if (evt.GetInt()<0 || evt.GetInt()>0xffffff) { T::Warn("Trigger hold off out of range (24bit)... ignored."); return T::GetCurrentState(); } fFTM.SendWrite(FPGAFTM::kTriggerHoldOff, evt.GetUInt()); return T::GetCurrentState(); } /* int SetRS485Mode(const EventImp &evt) { if (!CheckEventSize(evt.GetSize(), "SetRS485Mode", 8)) return T::kSM_FatalError; const uint8_t *ptr = evt.Ptr(); uint64_t data = 0; data |= uint64_t(ptr[0])<<40; // baud (word2) data |= uint64_t(ptr[1])<<32; // baud (word2) data |= uint64_t(ptr[2])<<24; // baud (word3) data |= uint64_t(ptr[3])<<16; // baud (word3) data |= uint64_t(ptr[4]&1)<<(40+15); // PEN data |= uint64_t(ptr[5]&1)<<(40+14); // PAR data |= uint64_t(ptr[6]&1)<<(40+13); // SPB data |= uint64_t(ptr[7]&1)<<(40+11); // MSB fFTM.SendWrite(FPGAFTM::kRS485Mode, data); return T::GetCurrentState(); } */ int SetInterval(const EventImp &evt) { if (!CheckEventSize(evt.GetSize(), "SetInterval", 8)) return T::kSM_FatalError; if (evt.GetUXtra()>0xffffffff) { T::Warn("Interval out of allowed range [32 bit]... ignored."); return T::GetCurrentState(); } fFTM.SetInterval(evt.GetUXtra()); return T::GetCurrentState(); } int Execute() { if (fFTM.GetState()(out, ConnectionFPGAFTM::fIsFACT?"FPGAFTM_CONTROL":"FTM_CONTROL"), fFTM(*this, *this) { // State names T::AddStateName(FPGAFTM::State::kDisconnected, "Disconnected", "No ethernet connection established"); T::AddStateName(FPGAFTM::State::kConnected, "Connected", "Connection established, requesting configuration"); T::AddStateName(FPGAFTM::State::kValid, "Valid", "Connection established, valid configuration received"); T::AddStateName(FPGAFTM::State::kConfiguring, "Configuring", "Configuring FTM for data taking"); T::AddStateName(FPGAFTM::State::kConfigured, "Configured", "Ready for data taking, ready to enable trigger"); T::AddStateName(FPGAFTM::State::kTriggerOn, "TriggerOn", "Trigger enabled"); // Verbosity commands T::AddEvent("SET_VERBOSE", "B:1") (bind(&StateMachineFPGAFTM::SetVerbosity, this, placeholders::_1)) ("Set verbosity state" "|verbosity[bool]:disable or enable verbosity for interpreted data (yes/no)"); T::AddEvent("SET_DEBUG_RX", "B:1") (bind(&StateMachineFPGAFTM::SetDebugRx, this, placeholders::_1)) ("Set debux-rx state" "|debug[bool]:dump received message to console (yes/no)"); T::AddEvent("SET_DEBUG_TX", "B:1") (bind(&StateMachineFPGAFTM::SetDebugTx, this, placeholders::_1)) ("Set debux-tx state" "|debug[bool]:dump outgoing message to console (yes/no)"); T::AddEvent("READ", "S:1", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::ReadReg, this, placeholders::_1)) ("Read a register" "|id[uint16]:Register ID"); T::AddEvent("WRITE", "S:1;X:1", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::WriteReg, this, placeholders::_1)) ("Write a register" "|id[uint16]:Register ID" "|val[uint64]:Data value"); // Device control T::AddEvent("READ_PRODUCT_ID", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::ReadRegister, this, FPGAFTM::kRegProductId)) ("Read product identification"); T::AddEvent("READ_FIRMWARE_ID", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::ReadRegister, this, FPGAFTM::kRegFirmwareId)) ("Read firmware version"); T::AddEvent("READ_CLOCK_STATE", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::ReadRegister, this, FPGAFTM::kClockState)) ("Read clock state"); T::AddEvent("READ_TIMER_STATE", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::ReadRegister, this, FPGAFTM::kTimerState)) ("Read timer state"); T::AddEvent("READ_CLOCK_FREQUENCY", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::ReadRegister, this, FPGAFTM::kClockFrequency)) ("Read comment clock frequency"); T::AddEvent("READ_CLOCK_MEASURE", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::ReadRegister, this, FPGAFTM::kClockMeasure)) ("Read measured clock frequency"); T::AddEvent("READ_TIMER_FREQUENCY", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::ReadRegister, this, FPGAFTM::kTimerFrequency)) ("Read comment timer frequency"); T::AddEvent("READ_TIMER_MEASURE", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::ReadRegister, this, FPGAFTM::kTimerMeasure)) ("Read measured timer frequency"); //T::AddEvent("READ_TRIGGER_MODE", FPGAFTM::State::kValid) // (bind(&StateMachineFPGAFTM::ReadRegister, this, FPGAFTM::kTriggerState)) // ("Read trigger mode"); T::AddEvent("READ_TRIGGER_PERIOD", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::ReadRegister, this, FPGAFTM::kTriggerPeriod)) ("Read trigger period"); /* T::AddEvent("READ_CONFIGURATION", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::ReadRegister, this, FPGAFTM::kConfiguration)) ("Read some configuration bits"); */ T::AddEvent("SET_FAD_RESET", "B:1", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::SetFADReset, this, placeholders::_1)) ("Set the FAD reset line to the provided logic signal" "|hilo[bool]:Set hi or lo state"); T::AddEvent("FAD_RESET", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::SendFADReset, this, placeholders::_1)) ("Emit both, an up and down of the FAD reset line"); T::AddEvent("READ_ADC1", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::ReadRegister, this, FPGAFTM::kADC1)) ("Read ADC1 (Temp1)"); /* T::AddEvent("READ_ADC2", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::ReadRegister, this, FPGAFTM::kADC2)) ("Read ADC2 (Temp2)"); T::AddEvent("READ_TEMPERATURES", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::ReadRegister, this, FPGAFTM::kADCs)) ("Read both temperatures (ADCs)"); T::AddEvent("READ_FAD_RESET_CYCLES", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::ReadRegister, this, FPGAFTM::kFadResetCycles)) ("Read number of cycles of FAD reset"); T::AddEvent("READ_FAD_RESET_ACTIVE_HI", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::ReadRegister, this, FPGAFTM::kFadResetActiveHi)) ("Set when FAD reset is active hi"); */ T::AddEvent("SET_CLOCK_FREQUENCY", "S:1;S:1", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::SetClockFrequency, this, placeholders::_1)) ("Set clock frequency 2^oct*2078Hz/(2-dac/1024)" "|dac[uint16]:Value DAC (10 bit)" "|oct[uint16]:Value OCT (4 bit)"); T::AddEvent("SET_TIMER_FREQUENCY", "S:1;S:1", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::SetTimerFrequency, this, placeholders::_1)) ("Set timer (TIM) frequency 2^oct*2078Hz/(2-dac/1024)" "|dac[uint16]:Value DAC (10 bit)" "|oct[uint16]:Value OCT (4 bit)"); T::AddEvent("SET_TRIGGER_PERIOD", "X:1", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::SetTriggerPeriod, this, placeholders::_1)) ("Set trigger period" "|period[us]:Trigger frequency (32 bit)"); T::AddEvent("SET_TRIGGER_HOLDOFF", "I:1", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::SetTriggerHoldOff, this, placeholders::_1)) ("Set trigger hold off period" "|period[us]:Trigger hold off (24 bit)"); T::AddEvent("ENABLE_CLOCK", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::WriteRegister, this, FPGAFTM::kClockEnable)) ("Enable clock"); T::AddEvent("DISABLE_CLOCK", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::WriteRegister, this, FPGAFTM::kClockDisable)) ("Disable clock"); T::AddEvent("SHUTDOWN_CLOCK", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::WriteRegister, this, FPGAFTM::kClockShutdown)) ("Shutdown clock"); T::AddEvent("ENABLE_TIMER", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::WriteRegister, this, FPGAFTM::kTimerEnable)) ("Enable timer"); T::AddEvent("DISABLE_TIMER", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::WriteRegister, this, FPGAFTM::kTimerDisable)) ("Disable timer"); T::AddEvent("SHUTDOWN_TIMER", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::WriteRegister, this, FPGAFTM::kTimerShutdown)) ("Shutdown timer"); T::AddEvent("ENABLE_INTERNAL_TRIGGER", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::WriteRegister, this, FPGAFTM::kTriggerInternal)) ("Enable internal trigger"); T::AddEvent("ENABLE_EXTERNAL_TRIGGER", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::WriteRegister, this, FPGAFTM::kTriggerExternal)) ("Enable external trigger"); /* T::AddEvent("ENABLE_RANDOM_TRIGGER", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::WriteRegister, this, FPGAFTM::kTriggerRandom)) ("Enable random trigger"); */ T::AddEvent("SHUTDOWN_TRIGGER", "B:1", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::ShutdownTrigger, this, placeholders::_1)) ("Shutdown trigger" "|hilo[bool]:Set hi or lo state after shutdown"); T::AddEvent("SET_TRIGGER_SOURCE_MASK", "X:1", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::WriteRegister64, this, placeholders::_1, FPGAFTM::kTriggerSourceMask)) ("Trigger Source Mask (128=SINGLE, 64=BUTTON, 32=FIXRATE, 16=DSP_IN_delay, 8=EXT_IN_delay, 4=DSP_IN, 2=EXT_IN, 1=NOT_USED)" "|mask[uint8]:"); T::AddEvent("SET_TRIGGER_OUT_SOURCE_MASK", "X:1", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::WriteRegister64, this, placeholders::_1, FPGAFTM::kTriggerOutSourceMask)) ("Trigger-out Source Mask (128=SINGLE, 64=BUTTON, 32=FIXRATE, 16=DSP_IN_delay, 8=EXT_IN_delay, 4=DSP_IN, 2=EXT_IN, 1=NOT_USED)" "|mask[uint8]:"); T::AddEvent("SET_TRIGGER_DSP_DELAY", "X:1", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::WriteRegister64, this, placeholders::_1, FPGAFTM::kTriggerDspDelay)) ("Trigger DSP Delay" "|delay[2.5ns]:"); T::AddEvent("SET_TRIGGER_EXT_DELAY", "X:1", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::WriteRegister64, this, placeholders::_1, FPGAFTM::kTriggerExtDelay)) ("Trigger Ext Delay" "|delay[2.5ns]:"); T::AddEvent("SET_TRIGGER_OUT_DELAY", "X:1", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::WriteRegister64, this, placeholders::_1, FPGAFTM::kTriggerOutDelay)) ("Trigger Out Delay" "|delay[2.5ns]:"); /* T::AddEvent("SET_TRIGGER_OUTPUT_MASK", "X:1", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::WriteRegister64, this, placeholders::_1, FPGAFTM::kTriggerOutputMask)) ("Trigger Output Mask" "|mask[uint8]:"); */ /* T::AddEvent("SET_RS485_MODE", "S:2;B:4", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::SetRS485Mode, this, placeholders::_1)) ("Set the RS485 mode" "|BAUD0[uint16]:Baud rate (word 2)" "|BAUD1[uint16]:Baud rate (word 3)" "|PEN[bool]:Parity enabled (0: disabled, 1: enabled)" "|PAR[bool]:Parity even (0: odd, 1: even)" "|SPB[bool]:Stop bits (0: one, 1: two)" "|MSB[bool]:Most Significant Bit First (MSB) (0: LSB, 1: MSB)"); T::AddEvent("ENABLE_RS485", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::WriteRegister, this, FPGAFTM::kTriggerRS485On)) ("Enable RS485 communication."); T::AddEvent("DISABLE_RS485", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::WriteRegister, this, FPGAFTM::kTriggerRS485Off)) ("Disable RS485 communication."); */ T::AddEvent("READ_RS485_DATA", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::ReadRegister, this, FPGAFTM::kRS485Data)) ("Read RS485 data"); T::AddEvent("SET_RS485_DATA", "X:1", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::WriteRegister64, this, placeholders::_1, FPGAFTM::kRS485Data)) ("Set RS485 data"); /* T::AddEvent("SET_FAD_RESET_CYCLES", "X:1", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::WriteRegister64, this, placeholders::_1, FPGAFTM::kFadResetCycles)) ("Set number of Cycles of FAD reset" "|cycles[uint16]:Number of cycles (min: 10, 16 bit)"); T::AddEvent("SET_FAD_RESET_ACTIVE_HI", "X:1", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::WriteRegister64, this, placeholders::_1, FPGAFTM::kFadResetActiveHi)) ("Set whether FAD reset is active hi" "|hi[bool]:Active hi"); */ T::AddEvent("SINGLE_TRIGGER", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::WriteRegister, this, FPGAFTM::kSingleTrigger)) ("Issue single trigger"); T::AddEvent("ERROR", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::WriteRegister, this, 0x9999)) ("Send an errorneous command (debugging purpose)"); T::AddEvent("PRINT_CONFIGURATION") (bind(&S::PrintConfig, &fFTM)) ("Print the current configuration as available in memory"); T::AddEvent("PRINT_DYNAMIC_DATA") (bind(&S::PrintDynamicData, &fFTM)) ("Print the current dynamic data as available in memory"); // A new configure will first stop the FTM this means // we can allow it in idle _and_ taking data T::AddEvent("CONFIGURE", "C", FPGAFTM::State::kValid, FPGAFTM::State::kTriggerOn) (bind(&StateMachineFPGAFTM::Configure, this, placeholders::_1)) ("Configure a new run"); T::AddEvent("RESET_CONFIGURE", FPGAFTM::State::kConfiguring, FPGAFTM::State::kConfigured) (bind(&StateMachineFPGAFTM::ResetConfig, this)) ("Reset states during a configuration or in case of configuration error"); T::AddEvent("START_TRIGGER", FPGAFTM::State::kConfigured) (bind(&StateMachineFPGAFTM::StartTrigger, this)) ("Start trigger as configured by CONFIGURE"); T::AddEvent("STOP_TRIGGER", FPGAFTM::State::kTriggerOn) (bind(&StateMachineFPGAFTM::WriteRegister, this, FPGAFTM::kTriggerShutdown)) ("Disable all triggers"); T::AddEvent("READ_TRIGGER_INHIBIT_STATE", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::ReadRegister, this, FPGAFTM::kTriggerInhibitState)) ("Read trigger inhibit state"); T::AddEvent("READ_TRIGGER_INHIBIT_TIME", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::ReadRegister, this, FPGAFTM::kTriggerInhibitTime)) ("Read trigger inhibit time"); T::AddEvent("SET_TRIGGER_INHIBIT_ON", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::WriteRegister, this, FPGAFTM::kTriggerInhibitEnable)) ("Set BUSY (active low)"); T::AddEvent("SET_TRIGGER_INHIBIT_OFF", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::WriteRegister, this, FPGAFTM::kTriggerInhibitDisable)) ("Free BUSY (high impedance)"); T::AddEvent("SET_TRIGGER_INHIBIT_TIME", "X:1", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::WriteRegister64, this, placeholders::_1, FPGAFTM::kTriggerInhibitTime)) ("Trigger inhibit time" "|time[5.0ns]:"); T::AddEvent("SOFT_RESET", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::WriteRegister, this, FPGAFTM::kSoftReset)) ("Soft reset FPGA"); T::AddEvent("HARD_RESET", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::WriteRegister, this, FPGAFTM::kHardReset)) ("Hard reset FPGA"); T::AddEvent("SET_INTERVAL", "X:1", FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::SetInterval, this, placeholders::_1)) ("Set temperature request interval" "|dt[uint32]:Interval in ms (0=off)"); // Conenction commands T::AddEvent("DISCONNECT", FPGAFTM::State::kConnected, FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::Disconnect, this)) ("Disconnect from ethernet"); T::AddEvent("RECONNECT", "O", FPGAFTM::State::kDisconnected, FPGAFTM::State::kConnected, FPGAFTM::State::kValid) (bind(&StateMachineFPGAFTM::Reconnect, this, placeholders::_1)) ("(Re)connect ethernet connection, a new address can be given" "|[host][string]:new ethernet address in the form "); } map fRunTypes; template bool GetConfig(Configuration &conf, const string &name, const string &sub, _t &rc) { if (conf.HasDef(name, sub)) { rc = conf.GetDef<_t>(name, sub); return true; } T::Error("Neither "+name+"default nor "+name+sub+" found."); return false; } int EvalOptions(Configuration &conf) { fFTM.SetVerbose(!conf.Get("quiet")); fFTM.SetDebugTx(conf.Get("debug-tx")); fFTM.SetDebugRx(conf.Get("debug-rx")); fFTM.SetEndpoint(conf.Get("addr")); fFTM.SetInterval(conf.Get("interval")); // ---------- Setup run types --------- const vector types = conf.Vec("run-type"); if (types.empty()) T::Warn("No run-types defined."); else T::Message("Defining run-types"); for (auto it=types.begin(); it!=types.end(); it++) { T::Message(" -> "+ *it); if (fRunTypes.count(*it)>0) { T::Error("Run-type "+*it+" defined twice."); return 1; } FPGAFTM::RunType &c = fRunTypes[*it]; if (!GetConfig(conf, "trigger-period.", *it, c.fTriggerPeriod) || !GetConfig(conf, "trigger-type.", *it, c.fTriggerType) || !GetConfig(conf, "trigger-mask.", *it, c.fTriggerSourceMask) || !GetConfig(conf, "trigger-out-mask.", *it, c.fTriggerOutSourceMask) || !GetConfig(conf, "trigger-delay-dsp.", *it, c.fTriggerDspDelay) || !GetConfig(conf, "trigger-delay-ext.", *it, c.fTriggerExtDelay) || !GetConfig(conf, "trigger-delay-out.", *it, c.fTriggerOutDelay) || !GetConfig(conf, "trigger-hold-off.", *it, c.fTriggerHoldOff) ) return 2; } // ----------------------------------- fFTM.StartConnect(); return -1; } }; // ------------------------------------------------------------------------ #include "Main.h" template int RunShell(Configuration &conf) { #if BOOST_VERSION < 104600 const string fname = boost::filesystem::path(conf.GetName()).filename(); #else const string fname = boost::filesystem::path(conf.GetName()).filename().string(); #endif ConnectionFPGAFTM::fIsFACT = fname!="ftmctrl"; return Main::execute>(conf); } void SetupConfiguration(Configuration &conf) { po::options_description control("Interlock control"); control.add_options() ("no-dim,d", po_switch(), "Disable dim services") ("addr,a", var(""), "Network address of the lid controling Arduino including port") ("quiet,q", po_bool(true), "Disable printing contents of all received messages (except dynamic data) in clear text.") ("debug-tx", po_bool(), "Enable debugging of ethernet transmission.") ("debug-rx", po_bool(), "Enable debugging for received data.") ("interval", var(1000), "Interval in which dynamic data is requested [ms]") ; po::options_description runtype("Run type configuration"); runtype.add_options() ("run-type", vars(), "Name of run-types (replace the * in the following configuration by the case-sensitive names defined here)") ("trigger-type.*", var(), "Calibration type ('internal', 'external', 'off')") ("trigger-period.*", var(), "Target rate for calibration by rate") ("trigger-mask.*", var(), "Trigger mask") ("trigger-out-mask.*", var(), "Trigger mask") ("trigger-delay-dsp.*", var(), "") ("trigger-delay-ext.*", var(), "") ("trigger-delay-out.*", var(), "") ("trigger-hold-off.*", var(), "") ; conf.AddOptions(control); conf.AddOptions(runtype); } /* 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 ftmctrl is a hardware interface to the FPGAFTM board built for FAMOUS" "\n" "The default is that the program is started with 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: ftmctrl [-c type] [OPTIONS]\n" " or: ftmctrl [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; // 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); } return 0; }