Index: /trunk/FACT++/src/drivectrl.cc
===================================================================
--- /trunk/FACT++/src/drivectrl.cc	(revision 10774)
+++ /trunk/FACT++/src/drivectrl.cc	(revision 10774)
@@ -0,0 +1,1090 @@
+#include <boost/bind.hpp>
+#include <boost/array.hpp>
+#if BOOST_VERSION < 104400
+#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 4))
+#undef BOOST_HAS_RVALUE_REFS
+#endif
+#endif
+#include <boost/thread.hpp>
+#include <boost/asio/error.hpp>
+#include <boost/asio/deadline_timer.hpp>
+
+#include "FACT.h"
+#include "Dim.h"
+#include "Event.h"
+#include "Shell.h"
+#include "StateMachineDim.h"
+#include "Connection.h"
+#include "Configuration.h"
+#include "Timers.h"
+#include "Console.h"
+#include "Converter.h"
+
+#include "tools.h"
+
+#include "LocalControl.h"
+
+
+namespace ba = boost::asio;
+namespace bs = boost::system;
+namespace dummy = ba::placeholders;
+
+using namespace std;
+
+// ------------------------------------------------------------------------
+
+namespace Drive
+{
+    struct DimPointing
+    {
+    } __attribute__((__packed__));
+
+    struct DimTracking
+    {
+    } __attribute__((__packed__));
+
+    struct DimStarguider
+    {
+        double fMissZd;
+        double fMissAz;
+
+        double fNominalZd;
+        double fNominalAz;
+
+        double fCenterX;
+        double fCenterY;
+
+        double fBrightness;
+
+        uint16_t fNumCorrelated;
+        uint16_t fNumLeds;
+        uint16_t fNumRings;
+        uint16_t fNumStars;
+
+    } __attribute__((__packed__));
+
+    struct DimTPoint
+    {
+        double fNominalAlt;
+        double fNominalAz;
+
+        double fCurrentAlt;
+        double fCurrentAz;
+
+        double fDevZd;
+        double fDevAz;
+
+        double fRa;
+        double fDec;
+
+        double fCenterX;
+        double fCenterY;
+        double fCenterMag;
+
+        double fStarX;
+        double fStarY;
+        double fStarMag;
+
+        double fBrightness;
+        double fRealMag;
+
+        uint16_t fNumLeds;
+        uint16_t fNumRings;
+        uint16_t fNumStars;
+        uint16_t fNumCorrelated;
+
+    } __attribute__((__packed__));
+};
+
+
+
+// ------------------------------------------------------------------------
+
+class ConnectionDrive : public Connection
+{
+    int  fState;
+
+    bool fIsVerbose;
+
+    // --verbose
+    // --hex-out
+    // --dynamic-out
+    // --load-file
+    // --leds
+    // --trigger-interval
+    // --physcis-coincidence
+    // --calib-coincidence
+    // --physcis-window
+    // --physcis-window
+    // --trigger-delay
+    // --time-marker-delay
+    // --dead-time
+    // --clock-conditioner-r0
+    // --clock-conditioner-r1
+    // --clock-conditioner-r8
+    // --clock-conditioner-r9
+    // --clock-conditioner-r11
+    // --clock-conditioner-r13
+    // --clock-conditioner-r14
+    // --clock-conditioner-r15
+    // ...
+
+    virtual void UpdatePointing(const Time &, const boost::array<double, 2> &)
+    {
+    }
+
+    virtual void UpdateTracking(const Time &, const boost::array<double, 7> &)
+    {
+    }
+
+    virtual void UpdateStarguider(const Time &, const Drive::DimStarguider &)
+    {
+    }
+
+    virtual void UpdateTPoint(const Time &, const Drive::DimTPoint &)
+    {
+    }
+
+protected:
+    map<uint16_t, int> fCounter;
+
+    ba::streambuf fBuffer;
+
+    Time ReadTime(istream &in)
+    {
+        uint16_t y, m, d, hh, mm, ss, ms;
+        in >> y >> m >> d >> hh >> mm >> ss >> ms;
+
+        return Time(y, m, d, hh, mm, ss, ms*1000);
+    }
+
+    double ReadAngle(istream &in)
+    {
+        char     sgn;
+        uint16_t d, m;
+        float    s;
+
+        in >> sgn >> d >> m >> s;
+
+        const double ret = ((60.0 * (60.0 * (double)d + (double)m) + s))/3600.;
+        return sgn=='-' ? -ret : ret;
+    }
+
+    void HandleReceivedReport(const boost::system::error_code& err, size_t bytes_received)
+    {
+        // Do not schedule a new read if the connection failed.
+        if (bytes_received==0 || err)
+        {
+            if (err==ba::error::eof)
+                Warn("Connection closed by remote host (FTM).");
+
+            // 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
+            {
+                stringstream str;
+                str << "Reading from " << URL() << ": " << err.message() << " (" << err << ")";// << endl;
+                Error(str);
+            }
+            PostClose(err!=ba::error::basic_errors::operation_aborted);
+            return;
+        }
+
+        istream is(&fBuffer);
+
+        string line;
+        getline(is, line);
+
+        if (fIsVerbose)
+            Out() << line << endl;
+
+        StartReadReport();
+
+        if (line.substr(0, 13)=="STARG-REPORT ")
+        {
+            istringstream stream(line.substr(16));
+
+            // 0: Error
+            // 1: Standby
+            // 2: Monitoring
+            uint16_t status1;
+            stream >> status1;
+            const Time t1 = ReadTime(stream);
+
+            uint16_t status2;
+            stream >> status2;
+            const Time t2 = ReadTime(stream);
+
+            double misszd, missaz;
+            stream >> misszd >> missaz;
+
+            const double zd = ReadAngle(stream);
+            const double az = ReadAngle(stream);
+
+            double cx, cy;
+            stream >> cx >> cy;
+
+            int ncor;
+            stream >> ncor;
+
+            double bright, mjd;
+            stream >> bright >> mjd;
+
+            int nled, nring, nstars;
+            stream >> nled >> nring >> nstars;
+
+            if (stream.fail())
+                return;
+
+            Drive::DimStarguider data;
+
+            data.fMissZd = misszd;
+            data.fMissAz = missaz;
+            data.fNominalZd = zd;
+            data.fNominalAz = az;
+            data.fCenterX = cx;
+            data.fCenterY = cy;
+            data.fNumCorrelated = ncor;
+            data.fBrightness = bright;
+            data.fNumLeds = nled;
+            data.fNumRings = nring;
+            data.fNumStars = nstars;
+
+            UpdateStarguider(Time(mjd), data);
+
+            return;
+
+        }
+
+        if (line.substr(0, 14)=="TPOINT-REPORT ")
+        {
+            istringstream stream(line.substr(17));
+
+            uint16_t status1;
+            stream >> status1;
+            const Time t1 = ReadTime(stream);
+
+            uint16_t status2;
+            stream >> status2;
+            const Time t2 = ReadTime(stream);
+
+            double az1, alt1, az2, alt2, ra, dec, dzd, daz;
+            stream >> az1 >> alt1 >> az2 >> alt2 >> ra >> dec >> dzd >> daz;
+
+            // c: center, s:start
+            double mjd, cmag, smag, cx, cy, sx, sy;
+            stream >> mjd >> cmag >> smag >> cx >> cy >> sx >> sy;
+
+            int nled, nring, nstar, ncor;
+            stream >> nled >> nring >> nstar >> ncor;
+
+            double bright, mag;
+            stream >> bright >> mag;
+
+            string name;
+            stream >> name;
+
+            if (stream.fail())
+                return;
+
+            Drive::DimTPoint tpoint;
+
+            tpoint.fNominalAz  = az1;
+            tpoint.fNominalAlt = alt1;
+            tpoint.fCurrentAz  = az2;
+            tpoint.fCurrentAlt = alt2;
+            tpoint.fDevAz      = daz;
+            tpoint.fDevZd      = dzd;
+            tpoint.fRa         = ra;
+            tpoint.fDec        = dec;
+
+            tpoint.fCenterX    = cx;
+            tpoint.fCenterY    = cy;
+            tpoint.fCenterMag  = cmag;
+
+            tpoint.fStarX      = sx;
+            tpoint.fStarY      = sy;
+            tpoint.fStarMag    = smag;
+
+            tpoint.fBrightness = bright;
+
+            tpoint.fNumCorrelated = ncor;
+            tpoint.fNumLeds       = nled;
+            tpoint.fNumRings      = nring;
+            tpoint.fNumStars      = nstar;
+
+            tpoint.fRealMag = mag;
+
+            return;
+        }
+
+        if (line.substr(0, 13)=="DRIVE-REPORT ")
+        {
+            // DRIVE-REPORT M1
+            // 01 2011 05 14 11 31 19 038
+            // 02 1858 11 17 00 00 00 000
+            // + 000 00 000 + 000 00 000
+            // + 000 00 000
+            // 55695.480081
+            // + 000 00 000 + 000 00 000
+            // + 000 00 000 + 000 00 000
+            // 0000.000 0000.000
+            // 0 2
+
+            // status
+            // year month day hour minute seconds millisec
+            // year month day hour minute seconds millisec
+            // ra(+ h m s) dec(+ d m s) ha(+ h m s)
+            // mjd
+            // zd(+ d m s) az(+ d m s)
+            // zd(+ d m s) az(+ d m s)
+            // zd_err az_err
+            // armed(0=unlocked, 1=locked)
+            // stgmd(0=none, 1=starguider, 2=starguider off)
+            istringstream stream(line.substr(16));
+
+            uint16_t status1;
+            stream >> status1;
+            const Time t1 = ReadTime(stream);
+
+            uint16_t status2;
+            stream >> status2;
+            const Time t2 = ReadTime(stream);
+
+            const double ra  = ReadAngle(stream);
+            const double dec = ReadAngle(stream);
+            const double ha  = ReadAngle(stream);
+
+            double mjd;
+            stream >> mjd;
+
+            const double zd1 = ReadAngle(stream);
+            const double az1 = ReadAngle(stream);
+            const double zd2 = ReadAngle(stream);
+            const double az2 = ReadAngle(stream);
+
+            double zd_err, az_err;
+            stream >> zd_err;
+            stream >> az_err;
+
+            uint16_t armed, stgmd;
+            stream >> armed;
+            stream >> stgmd;
+
+            if (stream.fail())
+                return;
+
+            // Status 0: Error
+            // Status 1: Stopped
+            // Status 3: Stopping || Moving
+            // Status 4: Tracking
+            if (status1==0)
+                status1 = 99;
+            fState = status1==1 ? armed+1 : status1;
+
+            const boost::array<double, 2> point = {{ zd2, az2 }};
+            UpdatePointing(t1, point);
+
+            const boost::array<double, 7> track =
+            {{
+                ra, dec, ha,
+                zd1, az1,
+                zd_err, az_err
+            }};
+            UpdateTracking(Time(mjd), track);
+
+            // ---- DIM ----> t1 as event time
+            //                status1
+            //                mjd
+            //                ra/dec/ha
+            //                zd/az (nominal)
+            //                zd/az (current)
+            //                err(zd/az)
+            //                [armed] [stgmd]
+
+            // Maybe:
+            // POINTING_POSITION --> t1, zd/az (current), [armed, stgmd, status1]
+            //
+            // if (mjd>0)
+            // TRACKING_POSITION --> mjd, zd/az (nominal), err(zd/az)
+            //                       ra/dec, ha(not well defined),
+            //                       [Nominal + Error == Current]
+
+            // MJD is the time which corresponds to the nominal position
+            // t1  is the time which corresponds to the current position/HA
+
+            return;
+        }
+    }
+
+    void StartReadReport()
+    {
+        boost::asio::async_read_until(*this, fBuffer, '\n',
+                                      boost::bind(&ConnectionDrive::HandleReceivedReport, this,
+                                                  dummy::error, dummy::bytes_transferred));
+    }
+
+    boost::asio::deadline_timer fKeepAlive;
+
+    void KeepAlive()
+    {
+        PostMessage(string("KEEP_ALIVE"));
+
+        fKeepAlive.expires_from_now(boost::posix_time::seconds(10));
+        fKeepAlive.async_wait(boost::bind(&ConnectionDrive::HandleKeepAlive,
+                                          this, dummy::error));
+    }
+
+    void HandleKeepAlive(const bs::error_code &error)
+    {
+        // 125: Operation canceled (bs::error_code(125, bs::system_category))
+        if (error && error!=ba::error::basic_errors::operation_aborted)
+        {
+            stringstream str;
+            str << "Write timeout of " << URL() << ": " << error.message() << " (" << error << ")";// << endl;
+            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 (fKeepAlive.expires_at() > ba::deadline_timer::traits_type::now())
+            return;
+
+        KeepAlive();
+    }
+
+
+private:
+    // This is called when a connection was established
+    void ConnectionEstablished()
+    {
+        StartReadReport();
+        KeepAlive();
+    }
+
+    /*
+    void HandleReadTimeout(const bs::error_code &error)
+    {
+        if (error && error!=ba::error::basic_errors::operation_aborted)
+        {
+            stringstream str;
+            str << "Read timeout of " << URL() << ": " << error.message() << " (" << error << ")";// << endl;
+            Error(str);
+
+            PostClose();
+            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 (fInTimeout.expires_at() > ba::deadline_timer::traits_type::now())
+            return;
+
+        Error("Timeout reading data from "+URL());
+
+        PostClose();
+    }*/
+
+
+public:
+
+    static const uint16_t kMaxAddr;
+
+public:
+    ConnectionDrive(ba::io_service& ioservice, MessageImp &imp) : Connection(ioservice, imp()),
+        fState(0), fIsVerbose(true), fKeepAlive(ioservice)
+    {
+        SetLogStream(&imp);
+    }
+
+    void SetVerbose(bool b)
+    {
+        fIsVerbose = b;
+    }
+
+    int GetState() const { return IsConnected() ? fState+1 : 1; }
+};
+
+const uint16_t ConnectionDrive::kMaxAddr = 0xfff;
+
+// ------------------------------------------------------------------------
+
+#include "DimDescriptionService.h"
+
+class ConnectionDimDrive : public ConnectionDrive
+{
+private:
+
+    DimDescribedService fDimPointing;
+    DimDescribedService fDimTracking;
+
+    template<size_t N>
+        void Update(DimDescribedService &svc, const Time &t, const boost::array<double, N> &arr) const
+    {
+        svc.setTimestamp(int(t.UnixTime()), t.ms());
+        svc.setData(const_cast<double*>(arr.data()), arr.size()*sizeof(double));
+        svc.updateService();
+    }
+
+    virtual void UpdatePointing(const Time &t,
+                                const boost::array<double, 2> &arr)
+    {
+        Update(fDimPointing, t, arr);
+    }
+
+    virtual void UpdateTracking(const Time &t,
+                                const boost::array<double, 7> &arr)
+    {
+        Update(fDimTracking, t, arr);
+    }
+
+public:
+    ConnectionDimDrive(ba::io_service& ioservice, MessageImp &imp) :
+        ConnectionDrive(ioservice, imp),
+        fDimPointing("FTM_CONTROL/POINTING_POSITION", "D:2", ""),
+        fDimTracking("FTM_CONTROL/TRACKING_POSITION", "D:7", "")
+    {
+    }
+
+    // A B [C] [D] E [F] G H [I] J K [L] M N O P Q R [S] T U V W [X] Y Z
+};
+
+// ------------------------------------------------------------------------
+
+template <class T, class S>
+class StateMachineDrive : public T, public ba::io_service, public ba::io_service::work
+{
+    int Wrap(boost::function<void()> f)
+    {
+        f();
+        return T::GetCurrentState();
+    }
+
+    boost::function<int(const EventImp &)> Wrapper(boost::function<void()> func)
+    {
+        return boost::bind(&StateMachineDrive::Wrap, this, func);
+    }
+
+private:
+    S fDrive;
+
+    enum states_t
+    {
+        kStateDisconnected = 1,
+        kStateConnected,
+        kStateArmed,
+        kStateMoving,
+        kStateTracking,
+    };
+
+    // Status 0: Error
+    // Status 1: Unlocked
+    // Status 2: Locked
+    // Status 3: Stopping || Moving
+    // Status 4: Tracking
+
+    bool CheckEventSize(size_t has, const char *name, size_t size)
+    {
+        if (has==size)
+            return true;
+
+        stringstream msg;
+        msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
+        T::Fatal(msg);
+        return false;
+    }
+
+    enum Coordinates
+    {
+        kPoint,
+        kTrackSlow,
+        kTrackFast
+    };
+
+    string AngleToStr(double angle)
+    {
+        /* Handle sign */
+        const char sgn = angle<0?'-':'+';
+
+        /* Round interval and express in smallest units required */
+        double a = round(3600. * fabs(angle)); // deg to seconds
+
+        /* Separate into fields */
+        const double ad = trunc(a/3600.);
+        a -= ad * 3600.;
+        const double am = trunc(a/60.);
+        a -= am * 60.;
+        const double as = trunc(a);
+
+        /* Return results */
+        ostringstream str;
+        str << sgn << " " << uint16_t(ad) << " " << uint16_t(am) << " " << as;
+        return str.str();
+    }
+
+    int SendCommand(const string &str)
+    {
+        fDrive.PostMessage(str);
+        return T::GetCurrentState();
+    }
+
+    int SendCoordinates(const EventImp &evt, const Coordinates type)
+    {
+        if (!CheckEventSize(evt.GetSize(), "SendCoordinates", 16))
+            return T::kSM_FatalError;
+
+        const double *dat = reinterpret_cast<const double*>(evt.GetData());
+
+        string command;
+
+        switch (type)
+        {
+        case kPoint:      command += "ZDAZ ";  break;
+        case kTrackSlow:  command += "RADEC "; break;
+        case kTrackFast:  command += "GRB ";   break;
+        }
+
+        command += AngleToStr(dat[0]) + ' ' + AngleToStr(dat[1]);
+
+        return SendCommand(command);
+    }
+
+    int SetVerbosity(const EventImp &evt)
+    {
+        if (!CheckEventSize(evt.GetSize(), "SetVerbosity", 1))
+            return T::kSM_FatalError;
+
+        fDrive.SetVerbose(evt.GetText()[0]!=0);
+
+        return T::GetCurrentState();
+    }
+
+    int Disconnect()
+    {
+        // Close all connections
+        fDrive.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
+        fDrive.PostClose(false);
+
+        // Now wait until all connection have been closed and
+        // all pending handlers have been processed
+        poll();
+
+        if (evt.GetText()[0]!=0)
+            fDrive.SetEndpoint(evt.GetString());
+
+        // Now we can reopen the connection
+        fDrive.PostClose(true);
+
+        return T::GetCurrentState();
+    }
+
+    int Execute()
+    {
+        // Dispatch (execute) at most one handler from the queue. In contrary
+        // to run_one(), it doesn't wait until a handler is available
+        // which can be dispatched, so poll_one() might return with 0
+        // handlers dispatched. The handlers are always dispatched/executed
+        // synchronously, i.e. within the call to poll_one()
+        poll_one();
+
+        return fDrive.GetState();
+    }
+
+
+public:
+    StateMachineDrive(ostream &out=cout) :
+        T(out, "DRIVE_CONTROL"), ba::io_service::work(static_cast<ba::io_service&>(*this)),
+        fDrive(*this, *this)
+    {
+        // ba::io_service::work is a kind of keep_alive for the loop.
+        // It prevents the io_service to go to stopped state, which
+        // would prevent any consecutive calls to run()
+        // or poll() to do nothing. reset() could also revoke to the
+        // previous state but this might introduce some overhead of
+        // deletion and creation of threads and more.
+
+        // State names
+        AddStateName(kStateDisconnected, "Disconnected",
+                     "");
+
+        AddStateName(kStateConnected, "Connected",
+                     "");
+
+        AddStateName(kStateArmed, "Armed",
+                     "");
+
+        AddStateName(kStateMoving, "Moving",
+                     "");
+
+        AddStateName(kStateTracking, "Tracking",
+                     "");
+
+        // kStateIdle
+        // kStateArmed
+        // kStateMoving
+        // kStateTracking
+
+        // Init
+        // -----------
+        // "ARM lock"
+        // "STGMD off"
+
+        /*
+         [ ] WAIT   -> WM_WAIT
+         [x] STOP!  -> WM_STOP
+         [x] RADEC  ra(+ d m s.f)  dec(+ d m s.f)
+         [x] GRB    ra(+ d m s.f)  dec(+ d m s.f)
+         [x] ZDAZ   zd(+ d m s.f)  az (+ d m s.f)
+         [ ] CELEST id offset angle
+         [ ] MOON   wobble offset
+         [ ] PREPS  string
+         [ ] TPOIN  star mag
+         [ ] ARM    lock/unlock
+         [ ] STGMD  on/off
+         */
+
+        // Drive Commands
+        T::AddEvent("MOVE_TO", "D:2", kStateArmed)  // ->ZDAZ
+            (boost::bind(&StateMachineDrive::SendCoordinates, this, _1, kPoint))
+            (""
+             "|zd[deg]:"
+             "|az[deg]:");
+
+        T::AddEvent("TRACK", "D:2", kStateArmed)   // ->RADEC/GRB
+            (boost::bind(&StateMachineDrive::SendCoordinates, this, _1, kTrackSlow))
+            (""
+             "|ra[h]:"
+             "|dec[deg]:");
+
+        T::AddEvent("MOON", kStateArmed)
+            (boost::bind(&StateMachineDrive::SendCommand, this, "MOON 0 0"))
+            ("");
+        T::AddEvent("VENUS", kStateArmed)
+            (boost::bind(&StateMachineDrive::SendCommand, this, "CELEST 2 0 0"))
+            ("");
+        T::AddEvent("MARS", kStateArmed)
+            (boost::bind(&StateMachineDrive::SendCommand, this, "CELEST 4 0 0"))
+            ("");
+        T::AddEvent("JUPITER", kStateArmed)
+            (boost::bind(&StateMachineDrive::SendCommand, this, "CELEST 5 0 0"))
+            ("");
+        T::AddEvent("SATURN", kStateArmed)
+            (boost::bind(&StateMachineDrive::SendCommand, this, "CELEST 6 0 0"))
+            ("");
+
+        T::AddEvent("TPOINT")
+            (boost::bind(&StateMachineDrive::SendCommand, this, "TPOIN FACT 0"))
+            ("");
+
+        T::AddEvent("STOP")
+            (boost::bind(&StateMachineDrive::SendCommand, this, "STOP!"))
+            ("");
+
+        T::AddEvent("ARM", kStateConnected)
+            (boost::bind(&StateMachineDrive::SendCommand, this, "ARM lock"))
+            ("");
+
+
+        // Verbosity commands
+        T::AddEvent("SET_VERBOSE", "B")
+            (boost::bind(&StateMachineDrive::SetVerbosity, this, _1))
+            ("set verbosity state"
+             "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
+
+        // Conenction commands
+        AddEvent("DISCONNECT", kStateConnected, kStateArmed)
+            (boost::bind(&StateMachineDrive::Disconnect, this))
+            ("disconnect from ethernet");
+
+        AddEvent("RECONNECT", "O", kStateDisconnected, kStateConnected, kStateArmed)
+            (boost::bind(&StateMachineDrive::Reconnect, this, _1))
+            ("(Re)connect ethernet connection to FTM, a new address can be given"
+             "|[host][string]:new ethernet address in the form <host:port>");
+
+        fDrive.StartConnect();
+    }
+
+    void SetEndpoint(const string &url)
+    {
+        fDrive.SetEndpoint(url);
+    }
+
+    bool SetConfiguration(const Configuration &conf)
+    {
+        SetEndpoint(conf.Get<string>("addr"));
+
+        fDrive.SetVerbose(!conf.Get<bool>("quiet"));
+
+        return true;
+    }
+};
+
+// ------------------------------------------------------------------------
+
+void RunThread(StateMachineImp *io_service)
+{
+    // This is necessary so that the StateMachien Thread can signal the
+    // Readline to exit
+    io_service->Run();
+    Readline::Stop();
+}
+
+template<class S, class T>
+int RunDim(Configuration &conf)
+{
+    WindowLog wout;
+
+    /*
+    static Test shell(conf.GetName().c_str(), conf.Get<int>("console")!=1);
+
+    WindowLog &win  = shell.GetStreamIn();
+    WindowLog &wout = shell.GetStreamOut();
+    */
+
+    if (conf.Has("log"))
+        if (!wout.OpenLogFile(conf.Get<string>("log")))
+            wout << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl;
+
+    // Start io_service.Run to use the StateMachineImp::Run() loop
+    // Start io_service.run to only use the commandHandler command detaching
+    StateMachineDrive<S, T> io_service(wout);
+    if (!io_service.SetConfiguration(conf))
+        return -1;
+
+    io_service.Run();
+
+    /*
+    shell.SetReceiver(io_service);
+
+    boost::thread t(boost::bind(RunThread, &io_service));
+    // boost::thread t(boost::bind(&StateMachineDrive<S>::Run, &io_service));
+
+    shell.Run();                 // Run the shell
+    io_service.Stop();           // Signal Loop-thread to stop
+    // io_service.Close();       // Obsolete, done by the destructor
+
+    // Wait until the StateMachine has finished its thread
+    // before returning and destroying the dim objects which might
+    // still be in use.
+    t.join();
+    */
+
+    return 0;
+}
+
+template<class T, class S, class R>
+int RunShell(Configuration &conf)
+{
+    static T shell(conf.GetName().c_str(), conf.Get<int>("console")!=1);
+
+    WindowLog &win  = shell.GetStreamIn();
+    WindowLog &wout = shell.GetStreamOut();
+
+    if (conf.Has("log"))
+        if (!wout.OpenLogFile(conf.Get<string>("log")))
+            win << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl;
+
+    StateMachineDrive<S, R> io_service(wout);
+    if (!io_service.SetConfiguration(conf))
+        return -1;
+
+    shell.SetReceiver(io_service);
+
+    boost::thread t(boost::bind(RunThread, &io_service));
+    // boost::thread t(boost::bind(&StateMachineDrive<S>::Run, &io_service));
+
+    shell.Run();                 // Run the shell
+    io_service.Stop();           // Signal Loop-thread to stop
+    // io_service.Close();       // Obsolete, done by the destructor
+
+    // Wait until the StateMachine has finished its thread
+    // before returning and destroying the dim objects which might
+    // still be in use.
+    t.join();
+
+    return 0;
+}
+
+void SetupConfiguration(Configuration &conf)
+{
+    const string n = conf.GetName()+".log";
+
+    po::options_description config("Program options");
+    config.add_options()
+        ("dns",       var<string>("localhost"), "Dim nameserver host name (Overwites DIM_DNS_NODE environment variable)")
+        ("log,l",     var<string>(n), "Write log-file")
+        ("no-dim,d",  po_switch(),    "Disable dim services")
+        ("console,c", var<int>(),     "Use console (0=shell, 1=simple buffered, X=simple unbuffered)")
+        ;
+
+    po::options_description control("FTM control options");
+    control.add_options()
+        ("addr,a",  var<string>("localhost:7404"),  "Network address of FTM")
+        ("quiet,q", po_bool(),  "Disable printing contents of all received messages (except dynamic data) in clear text.")
+        ;
+
+    conf.AddEnv("dns", "DIM_DNS_NODE");
+
+    conf.AddOptions(config);
+    conf.AddOptions(control);
+}
+
+/*
+ Extract usage clause(s) [if any] for SYNOPSIS.
+ Translators: "Usage" and "or" here are patterns (regular expressions) which
+ are used to match the usage synopsis in program output.  An example from cp
+ (GNU coreutils) which contains both strings:
+  Usage: cp [OPTION]... [-T] SOURCE DEST
+    or:  cp [OPTION]... SOURCE... DIRECTORY
+    or:  cp [OPTION]... -t DIRECTORY SOURCE...
+ */
+void PrintUsage()
+{
+    cout <<
+        "The drivectrl is an interface to cosy.\n"
+        "\n"
+        "The default is that the program is started without user intercation. "
+        "All actions are supposed to arrive as DimCommands. Using the -c "
+        "option, a local shell can be initialized. With h or help a short "
+        "help message about the usuage can be brought to the screen.\n"
+        "\n"
+        "Usage: drivectrl [-c type] [OPTIONS]\n"
+        "  or:  drivectrl [OPTIONS]\n";
+    cout << endl;
+}
+
+void 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);
+    SetupConfiguration(conf);
+
+    po::variables_map vm;
+    try
+    {
+        vm = conf.Parse(argc, argv);
+    }
+#if BOOST_VERSION > 104000
+    catch (po::multiple_occurrences &e)
+    {
+        cout << "Error: " << e.what() << " of '" << e.get_option_name() << "' option." << endl;
+        cout << endl;
+        return -1;
+    }
+#endif
+    catch (std::exception &e)
+    {
+        cout << "Error: " << e.what() << endl;
+        cout << endl;
+
+        return -1;
+    }
+
+    if (conf.HasPrint())
+        return -1;
+
+    if (conf.HasVersion())
+    {
+        FACT::PrintVersion(argv[0]);
+        return -1;
+    }
+
+    if (conf.HasHelp())
+    {
+        PrintHelp();
+        return -1;
+    }
+
+    Dim::Setup(conf.Get<string>("dns"));
+
+    //try
+    {
+        // No console access at all
+        if (!conf.Has("console"))
+        {
+            if (conf.Get<bool>("no-dim"))
+                return RunDim<StateMachine, ConnectionDrive>(conf);
+            else
+                return RunDim<StateMachineDim, ConnectionDimDrive>(conf);
+        }
+        // Cosole access w/ and w/o Dim
+        if (conf.Get<bool>("no-dim"))
+        {
+            if (conf.Get<int>("console")==0)
+                return RunShell<LocalShell, StateMachine, ConnectionDrive>(conf);
+            else
+                return RunShell<LocalConsole, StateMachine, ConnectionDrive>(conf);
+        }
+        else
+        {
+            if (conf.Get<int>("console")==0)
+                return RunShell<LocalShell, StateMachineDim, ConnectionDimDrive>(conf);
+            else
+                return RunShell<LocalConsole, StateMachineDim, ConnectionDimDrive>(conf);
+        }
+    }
+    /*catch (std::exception& e)
+    {
+        cerr << "Exception: " << e.what() << endl;
+        return -1;
+    }*/
+
+    return 0;
+}
