Index: trunk/FACT++/src/HeadersFPGAFTM.h
===================================================================
--- trunk/FACT++/src/HeadersFPGAFTM.h	(revision 20069)
+++ trunk/FACT++/src/HeadersFPGAFTM.h	(revision 20069)
@@ -0,0 +1,395 @@
+#ifndef FACT_HeadersFPGAFTM
+#define FACT_HeadersFPGAFTM
+
+#include <iosfwd>
+#include <stdint.h>
+#include <numeric>   // accumulate
+#include <algorithm>
+
+#include "HeadersFTM.h"
+
+namespace FPGAFTM
+{
+    namespace State
+    {
+        /*********** FTM **********
+        enum StateMachine
+        {
+            kDisconnected = 1,
+            kConnected,
+            kIdle,
+            kValid,
+            kTriggerOn,
+            kConfiguring1,
+            kConfiguring2,
+            kConfigured1,
+            kConfigured2,
+
+            kConfigError1 = 0x101,
+            kConfigError2 = 0x102,
+            //kConfigError3 = 0x103,
+        };
+        */
+
+        enum states_t
+        {
+            kDisconnected = FTM::State::kDisconnected,
+            kConnected    = FTM::State::kConnected,
+            //kIdle
+            kValid        = FTM::State::kValid,
+            kTriggerOn    = FTM::State::kTriggerOn,
+            kConfiguring  = FTM::State::kConfiguring1,
+            //kConfiguring2,
+            kConfigured   = FTM::State::kConfigured1,
+            //kConfigured2,
+
+            //kConfigError1 = 0x101,
+            //kConfigError2 = 0x102,
+            //kConfigError3 = 0x103,
+        };
+    };
+
+    // ----------------------------------------------------------------------
+
+    struct BusData
+    {
+        uint16_t fStartBits;
+        uint8_t  fReadWrite;
+        uint16_t fCommand;
+        uint64_t fData;
+        uint8_t  fCrc;
+        uint16_t fStopBits;
+
+        BusData(uint8_t rw, uint16_t cmd, uint64_t dat)
+            : fStartBits(0xffff), fReadWrite(rw), fCommand(cmd),
+            fData(dat), fStopBits(0xffff)
+        {
+            fCrc = calcCrc();
+        }
+
+        uint32_t id() const { return (fReadWrite<<16)|fCommand; }
+
+        uint8_t calcCrc() const
+        {
+            // FIXME: FIX IN minifrmctrl -- old!
+            return std::accumulate(&fReadWrite, &fReadWrite+11, uint8_t(0));
+        }
+
+        bool isCrcValid() const
+        {
+            return fCrc == calcCrc();
+        }
+
+        void print(std::ostream &out) const
+        {
+            out << std::hex;
+            out << Tools::Form("%04x|%02x|%04x|%016lx|%02x|%04x",
+                               fStartBits, fReadWrite, fCommand, fData, fCrc, fStopBits);
+            out << std::dec;
+        }
+    } __attribute__((__packed__));
+
+    inline std::ostream &operator<<(std::ostream &out, const BusData &d)
+    {
+        d.print(out);
+        return out;
+    }
+
+    enum readwrite_t
+    {
+        kCmdRead  = 0x00, // Command: Read
+        kCmdWrite = 0x04, // Command: Write
+        kCmdADM   = 0x0e, // Automatic data mode (ADM) package
+        kCmdError = 0xff,
+    };
+
+    enum trigger_t
+    {
+        kInternal = 0x00,
+        kExternal = 0x01,
+        kShutdown = 0x02,
+        //kRandom    = 0x10,
+
+        kEnable   = 0x00,
+        kDisable  = 0x01,
+    };
+
+    enum mask_t
+    {
+        kMaskExtIn      = 0x02,
+        kMaskDspIn      = 0x04,
+        kMaskExtInDelay = 0x08,
+        kMaskDspInDelay = 0x10,
+        kMaskInternal   = 0x20,
+        kMaskButton     = 0x40,
+        kMaskSingle     = 0x80
+    };
+
+    enum command_t
+    {
+        kRegProductId         = 0x0000,  // read only
+        kRegFirmwareId        = 0x0100,  // read only
+
+        kClockState           = 0x0010,
+        kClockEnable          = kClockState|(kEnable<<8),
+        kClockDisable         = kClockState|(kDisable<<8),
+        kClockShutdown        = kClockState|(kShutdown<<8),
+
+        kClockFrequency       = 0x0011,  // 2 byte, 14 bit
+        kClockMeasure         = 0x0012,  // 2 byte, 14 bit
+
+        kTimerState           = 0x0014,  // read/write
+        kTimerEnable          = kTimerState|(kEnable<<8),
+        kTimerDisable         = kTimerState|(kDisable<<8),
+        kTimerShutdown        = kTimerState|(kShutdown<<8),
+
+        kTimerFrequency       = 0x0015,
+        kTimerMeasure         = 0x0016,
+
+        kTriggerState         = 0x0020,
+        kTriggerInternal      = kTriggerState|(kInternal<<8),
+        kTriggerExternal      = kTriggerState|(kExternal<<8),
+        kTriggerShutdown      = kTriggerState|(kShutdown<<8),
+        //kTriggerRandom        = kTriggerState|(kRandom<<8),
+
+        kTriggerPeriod        = 0x0021,
+        kTriggerSourceMask    = 0x0022,
+
+/*
+        kTriggerOutState      = 0x0024,
+        kTriggerOutInt        = kTriggerOutState|(...),
+        kTriggerOutExt        = kTriggerOutState|(...),
+        kTriggerOutIntDelayed = kTriggerOutState|(...),
+        kTriggerOutExtDelayed = kTriggerOutState|(...),
+*/
+
+        kTriggerHoldOff       = 0x0025,
+
+        kTriggerOutSourceMask = 0x0026,
+
+        kTriggerDspDelay      = 0x0028, // 10bit
+        kTriggerExtDelay      = 0x0029, // 10bit
+        kTriggerOutDelay      = 0x002e, // 10bit
+
+        kFadResetLo           = 0x0030,
+        kFadResetHi           = 0x0130,
+
+        kTriggerInhibitState  = 0x0032,
+        kTriggerInhibitEnable = 0x0132,
+        kTriggerInhibitDisable= 0x0032,
+        kTriggerInhibitTime   = 0x0033,
+
+
+        kADC1                 = 0x0040, // read only (2 byte,   10 bit)
+
+        kRS485Data            = 0x0050, // 56 bit (last data sent, but counter increased by 1)
+
+        kSingleTrigger        = 0x005e, // read only
+
+        kOnTime               = 0x0060, // Automatic data transmission
+
+        kSoftReset            = 0x01ff,
+        kHardReset            = 0x02ff,
+    };
+
+    enum error_t
+    {
+        kErrFrameStart   =  0xba,  // Start bytes wrong
+        kErrFrameStop    =  0xbb,  // Stop bytes wrong
+        kErrFrameCrc     =  0xaa,  // Checksum wrong
+        kErrUnknownCmd   =  0x18,  // Unknown command
+        kErrForbiddenCmd =  0x11,  // Command not allowed
+        kErrTempReadCmd  =  0x20,  // Temperature reading failes (ignored)
+        kErrTempReadBusy =  0x40,  // Temperature reading busy (ignored)
+    };
+
+    // --------------------------------------------------------------------------
+
+    struct Config
+    {
+        // WARNING: Update the DIM service if you do any update to this header!
+        uint64_t fFirmwareId;
+        uint64_t fProductId;
+        uint8_t  fClockState;
+        uint64_t fClockFrequency64;
+        double   fClockFrequencyD;
+        uint8_t  fTimerState;
+        uint64_t fTimerFrequency64;
+        double   fTimerFrequencyD;
+        uint8_t  fTriggerState;
+        uint8_t  fTriggerSourceMask;
+        uint8_t  fTriggerOutSourceMask;
+        uint16_t fTriggerDspDelay; // 2.5ns
+        uint16_t fTriggerExtDelay; // 2.5ns
+        uint16_t fTriggerOutDelay; // 2.5ns
+        uint32_t fTriggerPeriod32;
+        uint32_t fTriggerHoldOff24;
+        uint8_t  fTriggerInhibitState;
+        uint16_t fTriggerInhibitTime; //5ns
+
+        Config() { memset(this, 0, sizeof(Config)); fClockState=0xff; fTriggerState=0xff; }
+
+        std::string mask(const uint8_t &mask) const
+        {
+            std::string rc;
+
+            if (mask&kMaskExtIn)
+                rc += "EXTin ";
+            if (mask&kMaskDspIn)
+                rc += "DSPin ";
+            if (mask&kMaskExtInDelay)
+                rc += "EXTin-delay ";
+            if (mask&kMaskDspInDelay)
+                rc += "DSPin-delay ";
+            if (mask&kMaskInternal)
+                rc += "internal ";
+            if (mask&kMaskButton)
+                rc += "button ";
+            if (mask&kMaskSingle)
+                rc += "single ";
+
+            return rc;
+        }
+
+        void print(std::ostream &out) const
+        {
+            out << std::hex;
+            out << "Indentification:    Product=0x" << fFirmwareId << " / Firmware=0x" << fProductId << '\n';
+            out << "Clock state:        ";
+            switch (fClockState)
+            {
+            case kEnable:   out << "<enabled>";  break;
+            case kDisable:  out << "<disabled>"; break;
+            case kShutdown: out << "<shutdown>"; break;
+            default:             out << "<unknown>";
+            }
+            out << " [0x" << uint16_t(fClockState) << "]\n";
+            out << "Clock frequency:    " << fClockFrequencyD << " Hz [0x" << fClockFrequency64 << "]  (DRS=" << fClockFrequencyD*2.048 << " kHz)\n";
+            out << "Timer state:        ";
+            switch (fTimerState)
+            {
+            case kEnable:   out << "<enabled>";  break;
+            case kDisable:  out << "<disabled>"; break;
+            case kShutdown: out << "<shutdown>"; break;
+            default:             out << "<unknown>";
+            }
+            out << " [0x" << uint16_t(fTimerState) << "]\n";
+            out << "Timer frequency:    " << fTimerFrequencyD << " Hz [0x" << fTimerFrequency64 << "]\n";
+            out << "Trigger state:      ";
+            switch (fTriggerState)
+            {
+            case kInternal: out << "<internal>"; break;
+            case kExternal: out << "<external>"; break;
+            case kShutdown: out << "<off>";      break;
+            //case kRandom:    out << "<random>";   break;
+            default:        out << "<unknown>";
+            }
+            out << " [0x" << uint16_t(fTriggerState) << "]\n";
+            out << "Trigger frequency:  " << 1e6/fTriggerPeriod32 << "Hz [" << fTriggerPeriod32 << "]\n";
+            out << "Trigger Masks:      ";
+
+            out << std::hex;
+            out << "[source:"     << uint32_t(fTriggerSourceMask)    << "] " << mask(fTriggerSourceMask);
+            out << "[out-source:" << uint32_t(fTriggerOutSourceMask) << "] " << mask(fTriggerOutSourceMask);
+            out << '\n';
+
+            out << "Trigger hold off:   " << fTriggerHoldOff24 << " us\n";
+            out << "Trigger delays:     ";
+            out << "DSP=" << fTriggerDspDelay*2.5 << "ns ";
+            out << "EXT=" << fTriggerExtDelay*2.5 << "ns ";
+            out << "OUT=" << fTriggerOutDelay*2.5 << "ns\n";
+            
+            out << "Trig.inhibit state: ";
+            switch (fTriggerInhibitState)
+            {
+            case kEnable:  out << "<enabled>"; break;
+            case kDisable: out << "<disabled>"; break;
+            default:       out << "<unknown>";
+            }
+            out << '\n';
+            out << "Trig.inhibit time:  "<< fTriggerInhibitTime*5.0 << "ns ";
+            out << std::endl;
+/*
+            out << "Configuration:      Trigger ";
+            switch (fConfiguration&0x6)
+            {
+            case 0x02:
+                out << (fConfiguration?"<random>":"<fixed rate>");
+                break;
+            case 0x04:
+                out << "<external>";
+                break;
+
+            case 0x06:
+                out << (fConfiguration&0x10?"<off[hi]>":"<off[lo]>");
+                break;
+            }
+            out << " [" << fConfiguration << "]   RS485 <" << (fConfiguration&1?"on":"off") << ">\n";
+*/
+            out << std::dec;
+            out << std::flush;
+        }
+    } __attribute__((__packed__));
+
+    inline std::ostream &operator<<(std::ostream &out, const Config &c)
+    {
+        c.print(out);
+        return out;
+    }
+
+    struct Data
+    {
+        // WARNING: Update the DIM service if you do any update to this header!
+        uint32_t fRunTime;         // [10ns]
+        uint32_t fDeadTime;        // [10ns]
+
+        uint32_t fTriggerCounter;  // As sent through RS485
+
+        uint32_t fClockFrequency;  // measured Hz
+        uint32_t fTimerFrequency;  // measured Hz
+
+        uint16_t fADC1; // 10 bit
+        float    fTemp1;
+
+        Data() { memset(this, 0, sizeof(Data)); }
+
+        void SetADC1(const uint16_t &adc)
+        {
+            fADC1  = adc;
+            fTemp1 = adc*0.0625;//-(adc*3300./1024-2633)/13.6;
+        }
+
+        void print(std::ostream &out) const
+        {
+            out << Tools::Form("On Time:     Total=%.2fus Veto=%.2fus (%.1f%%)\n", fRunTime*0.01, fDeadTime*0.01, 100.*fDeadTime/fRunTime);
+            out << Tools::Form("Trigger:     Counter= %016lx\n", fTriggerCounter);
+            out << Tools::Form("Drequencies: Clock=%d Hz, Timer=%d Hz\n", fClockFrequency, fTimerFrequency);
+            out << Tools::Form("Temperature: %.1f degC\n", fTemp1);
+            out << std::flush;
+        }
+
+    } __attribute__((__packed__));
+
+    inline std::ostream &operator<<(std::ostream &out, const Data &d)
+    {
+        d.print(out);
+        return out;
+    }
+
+    // ---------------------------------------------------------------
+
+    struct RunType
+    {
+        std::string fTriggerType;
+
+        uint32_t fTriggerPeriod;
+        uint16_t fTriggerSourceMask;
+        uint16_t fTriggerOutSourceMask;
+        uint16_t fTriggerDspDelay;
+        uint16_t fTriggerExtDelay;
+        uint16_t fTriggerOutDelay;
+        uint32_t fTriggerHoldOff;
+    };
+
+};
+#endif
Index: trunk/FACT++/src/fpgaftmctrl.cc
===================================================================
--- trunk/FACT++/src/fpgaftmctrl.cc	(revision 20069)
+++ trunk/FACT++/src/fpgaftmctrl.cc	(revision 20069)
@@ -0,0 +1,1626 @@
+/* ToDo:
+ * 1) Delay TriggerDataTimer
+ * 2)
+ * 
+ * 
+ * 
+ * 
+ * 
+ */
+
+#include <boost/array.hpp>
+
+#include <string>
+#include <queue>
+
+#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
+{
+private:
+    bool fIsVerbose;
+    bool fDebugRx;
+
+    uint32_t fInterval;
+
+    boost::asio::deadline_timer fRxTimeout;
+    boost::asio::deadline_timer fDataTimer;
+
+    vector<uint8_t> 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<FPGAFTM::BusData> 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<FPGAFTM::BusData*>(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<FPGAFTM::BusData>();
+
+        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();
+    }
+};
+
+// ------------------------------------------------------------------------
+
+#include "DimDescriptionService.h"
+
+class ConnectionDimFPGAFTM : public ConnectionFPGAFTM
+{
+private:
+    DimDescribedService fDimConfig;
+    DimDescribedService fDimData;
+
+public:
+    ConnectionDimFPGAFTM(ba::io_service& ioservice, MessageImp &imp) :
+        ConnectionFPGAFTM(ioservice, imp),
+        fDimConfig("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("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 T, class S>
+class StateMachineFPGAFTM : public StateMachineAsio<T>
+{
+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<uint64_t>(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<uint64_t>());
+
+        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<uint16_t>(0);
+        const uint16_t e = evt.Get<uint16_t>(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<uint16_t>(0);
+        const uint16_t e = evt.Get<uint16_t>(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<uint8_t>();
+
+        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()<FPGAFTM::State::kValid)
+            return fFTM.GetState();
+
+        switch (T::GetCurrentState())
+        {
+        case FPGAFTM::State::kConfiguring:
+            return fFTM.GetQueueSize()==0 ? FPGAFTM::State::kConfigured : FPGAFTM::State::kConfiguring;
+
+        case FPGAFTM::State::kConfigured:
+            return fFTM.IsTriggerOn() ? FPGAFTM::State::kTriggerOn : FPGAFTM::State::kConfigured;
+
+        case FPGAFTM::State::kTriggerOn:
+            return fFTM.IsTriggerOn() ? FPGAFTM::State::kTriggerOn : FPGAFTM::State::kValid;
+        }
+
+        return fFTM.GetState();
+    }
+
+public:
+    StateMachineFPGAFTM(ostream &out=cout) :
+        StateMachineAsio<T>(out, "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 <host:port>");
+    }
+
+    map<string, FPGAFTM::RunType> fRunTypes;
+
+    template<typename _t>
+    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<bool>("quiet"));
+        fFTM.SetDebugTx(conf.Get<bool>("debug-tx"));
+        fFTM.SetDebugRx(conf.Get<bool>("debug-rx"));
+        fFTM.SetEndpoint(conf.Get<string>("addr"));
+        fFTM.SetInterval(conf.Get<uint32_t>("interval"));
+
+        // ---------- Setup run types ---------
+        const vector<string> types = conf.Vec<string>("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<class T, class S, class R>
+int RunShell(Configuration &conf)
+{
+    return Main::execute<T, StateMachineFPGAFTM<S, R>>(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<string>(""), "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<uint32_t>(1000), "Interval in which dynamic data is requested [ms]")
+        ;
+
+    po::options_description runtype("Run type configuration");
+    runtype.add_options()
+        ("run-type",            vars<string>(),  "Name of run-types (replace the * in the following configuration by the case-sensitive names defined here)")
+        ("trigger-type.*",      var<string>(),   "Calibration type ('internal', 'external', 'off')")
+        ("trigger-period.*",    var<uint32_t>(), "Target rate for calibration by rate")
+        ("trigger-mask.*",      var<uint16_t>(), "Trigger mask")
+        ("trigger-out-mask.*",  var<uint16_t>(), "Trigger mask")
+        ("trigger-delay-dsp.*", var<uint16_t>(), "")
+        ("trigger-delay-ext.*", var<uint16_t>(), "")
+        ("trigger-delay-out.*", var<uint16_t>(), "")
+        ("trigger-hold-off.*",  var<uint32_t>(), "")
+    ;
+
+    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<StateMachineFPGAFTM<StateMachine, ConnectionFPGAFTM>>();
+
+    /* 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<bool>("no-dim"))
+            return RunShell<LocalStream, StateMachine, ConnectionFPGAFTM>(conf);
+        else
+            return RunShell<LocalStream, StateMachineDim, ConnectionDimFPGAFTM>(conf);
+    }
+    // Cosole access w/ and w/o Dim
+    if (conf.Get<bool>("no-dim"))
+    {
+        if (conf.Get<int>("console")==0)
+            return RunShell<LocalShell, StateMachine, ConnectionFPGAFTM>(conf);
+        else
+            return RunShell<LocalConsole, StateMachine, ConnectionFPGAFTM>(conf);
+    }
+    else
+    {
+        if (conf.Get<int>("console")==0)
+            return RunShell<LocalShell, StateMachineDim, ConnectionDimFPGAFTM>(conf);
+        else
+            return RunShell<LocalConsole, StateMachineDim, ConnectionDimFPGAFTM>(conf);
+    }
+
+    return 0;
+}
