Index: trunk/FACT++/src/drivectrl.cc
===================================================================
--- trunk/FACT++/src/drivectrl.cc	(revision 12806)
+++ trunk/FACT++/src/drivectrl.cc	(revision 12807)
@@ -14,4 +14,9 @@
 #include "tools.h"
 
+#define HAS_SQL
+
+#ifdef HAS_SQL
+#include <mysql++/mysql++.h>
+#endif
 
 namespace ba = boost::asio;
@@ -140,5 +145,5 @@
     {
     }
-    virtual void UpdateSource(const array<double, 6> &)
+    virtual void UpdateSource(const array<double, 6> &, const string& = "")
     {
     }
@@ -149,5 +154,6 @@
     ba::streambuf fBuffer;
 
-    Time ReadTime(istream &in)
+public:
+    static Time ReadTime(istream &in)
     {
         uint16_t y, m, d, hh, mm, ss, ms;
@@ -157,5 +163,5 @@
     }
 
-    double ReadAngle(istream &in)
+    static double ReadAngle(istream &in)
     {
         char     sgn;
@@ -169,4 +175,5 @@
     }
 
+protected:
     void HandleReceivedReport(const boost::system::error_code& err, size_t bytes_received)
     {
@@ -643,5 +650,5 @@
                      "|dZd[deg]:Control deviation Zd"
                      "|dAz[deg]:Control deviation Az"),
-        fDimSource("DRIVE_CONTROL/SOURCE_POSITION", "D:1;D:1;D:1;D:1;D:1;D:1",
+        fDimSource("DRIVE_CONTROL/SOURCE_POSITION", "D:1;D:1;D:1;D:1;D:1;D:1;C:31",
                      "|Ra_cmd[h]:Command right ascension"
                      "|Dec_cmd[deg]:Command declination"
@@ -649,5 +656,6 @@
                      "|Dec_src[deg]:Source declination"
                      "|Offfset[deg]:Wobble offset"
-                     "|Angle[deg]:Wobble angle"),
+                     "|Angle[deg]:Wobble angle"
+                     "|Name[string]:Source name if available"),
         fDimTPoint("DRIVE_CONTROL/TPOINT", "D:1;D:1;D:1;D:1;D:1;D:1;D:1;D:1;S:1;D:1;D:1;D:1;D:1;D:1;D:1;D:1;C",
                    "|Ra[h]:Command right ascension"
@@ -675,13 +683,17 @@
     void UpdateSource()
     {
-        const array<double, 6> arr = {{ 0, 0, 0, 0, 0, 0 }};
+        const vector<char> empty(6*sizeof(double)+31, 0);
         fDimSource.setQuality(0);
-        fDimSource.Update(arr);
-    }
-
-    void UpdateSource(const array<double, 6> &arr)
-    {
+        fDimSource.Update(empty);
+    }
+
+    void UpdateSource(const array<double, 6> &arr, const string &name="")
+    {
+        vector<char> dat(6*sizeof(double)+31, 0);
+        memcpy(dat.data(), arr.data(), 6*sizeof(double));
+        strncpy(dat.data()+6*sizeof(double), name.c_str(), 30);
+
         fDimSource.setQuality(1);
-        fDimSource.Update(arr);
+        fDimSource.Update(dat);
     }
 
@@ -719,4 +731,7 @@
     };
 
+    typedef map<string,pair<double,double>> sources;
+    sources fSources;
+
     // Status 0: Error
     // Status 1: Unlocked
@@ -801,15 +816,12 @@
     }
 
-    int Wobble(const EventImp &evt)
-    {
-        if (!CheckEventSize(evt.GetSize(), "Wobble", 32))
-            return T::kSM_FatalError;
-
-        const double *dat = evt.Ptr<double>();
-
-        const double ra  = dat[0]*M_PI/12;
-        const double dec = dat[1]*M_PI/180;
-        const double off = dat[2]*M_PI/180;
-        const double dir = dat[3]*M_PI/180;
+    int StartWobble(const double &srcra,  const double &srcdec,
+                    const double &woboff, const double &wobang,
+                    const string name="")
+    {
+        const double ra  = srcra *M_PI/12;
+        const double dec = srcdec*M_PI/180;
+        const double off = woboff*M_PI/180;
+        const double dir = wobang*M_PI/180;
 
         const double cosdir = cos(dir);
@@ -823,8 +835,8 @@
         {
             const array<double, 6> dim = {{ ra, dec, ra, dec, 0, 0 }};
-            fDrive.UpdateSource(dim);
+            fDrive.UpdateSource(dim, name);
 
             string command = "RADEC ";
-            command += AngleToStr(dat[0]) + ' ' + AngleToStr(dat[1]);
+            command += AngleToStr(srcra) + ' ' + AngleToStr(srcdec);
             return SendCommand(command, false);
         }
@@ -846,5 +858,5 @@
 
         const array<double, 6> dim = {{ ra, dec, nra, ndec, off, dir }};
-        fDrive.UpdateSource(dim);
+        fDrive.UpdateSource(dim, name);
 
         string command = "RADEC ";
@@ -853,4 +865,29 @@
     }
 
+    int Wobble(const EventImp &evt)
+    {
+        if (!CheckEventSize(evt.GetSize(), "Wobble", 32))
+            return T::kSM_FatalError;
+
+        const double *dat = evt.Ptr<double>();
+
+        return StartWobble(dat[0], dat[1], dat[2], dat[3]);
+    }
+
+    int Track(const EventImp &evt)
+    {
+        const double *dat = evt.Ptr<double>();
+        const string name = evt.Ptr<char>(16);
+
+        const sources::const_iterator it = fSources.find(name);
+        if (it==fSources.end())
+            return T::Error("Source '"+name+"'not found in list.");
+
+        const double &ra   = it->second.first;
+        const double &dec  = it->second.second;
+
+        return StartWobble(ra, dec, dat[0], dat[1], name);
+    }
+
     int SetLedBrightness(const EventImp &evt)
     {
@@ -873,4 +910,18 @@
         fDrive.SetVerbose(evt.GetBool());
 
+        return T::GetCurrentState();
+    }
+
+    int Print()
+    {
+        for (sources::const_iterator it=fSources.begin();
+             it!=fSources.end(); it++)
+        {
+            const string &name = it->first;
+            const double &ra   = it->second.first;
+            const double &dec  = it->second.second;
+
+            T::Out() << name << "," << ra << "," << dec << endl;
+        }
         return T::GetCurrentState();
     }
@@ -999,4 +1050,11 @@
              "|Offset[deg]:Wobble offset"
              "|Angle[deg]:Wobble angle");
+
+        T::AddEvent("TRACK", "D:2;C", kStateArmed)   // ->RADEC/GRB
+            (bind(&StateMachineDrive::Track, this, placeholders::_1))
+            ("Move the telescope to the given wobble position around the given source and start tracking"
+             "|Offset[deg]:Wobble offset"
+             "|Angle[deg]:Wobble angle"
+             "|Name[string]:Source name");
 
         T::AddEvent("MOON", kStateArmed)
@@ -1055,4 +1113,9 @@
              "|[host][string]:new ethernet address in the form <host:port>");
 
+
+        T::AddEvent("PRINT")
+            (bind(&StateMachineDrive::Print, this))
+            ("Print source list.");
+
         fDrive.StartConnect();
     }
@@ -1063,4 +1126,67 @@
     }
 
+    void ReadDatabase(const string &database)
+    {
+        //static const boost::regex expr("(([[:word:].-]+)(:(.+))?@)?([[:word:].-]+)(:([[:digit:]]+))?(/([[:word:].-]+))?");
+        static const boost::regex expr("(([[:word:].-]+)(:(.+))?@)?([[:word:].-]+)(:([[:digit:]]+))?(/([[:word:].-]+))");
+        // 2: user
+        // 4: pass
+        // 5: server
+        // 7: port
+        // 9: db
+
+        boost::smatch what;
+        if (!boost::regex_match(database, what, expr, boost::match_extra))
+            throw runtime_error("Couldn't parse '"+database+"'.");
+
+        if (what.size()!=10)
+            throw runtime_error("Error parsing '"+database+"'.");
+
+        const string user   = what[2];
+        const string passwd = what[4];
+        const string server = what[5];
+        const string db     = what[9];
+        const int port      = atoi(string(what[7]).c_str());
+
+        ostringstream out;
+        out << "Connecting to '";
+        if (!user.empty())
+            out << user << "@";
+        out << server;
+        if (port)
+            out << ":" << port;
+        if (!db.empty())
+            out << "/" << db;
+
+        T::Message(out);
+
+        mysqlpp::Connection conn(db.c_str(), server.c_str(), user.c_str(), passwd.c_str(), port);
+        /* throws exceptions
+         if (!conn.connected())
+         {
+             cout << "MySQL connection error: " << conn.error() << endl;
+             throw;
+         }*/
+
+        const mysqlpp::StoreQueryResult res =
+            conn.query("SELECT fSourceName, fRightAscension, fDeclination FROM scheduling.source").store();
+        /* throws exceptions
+        if (!res)
+        {
+            cout << "MySQL query failed: " << query.error() << endl;
+            throw;
+        }*/
+
+        for (vector<mysqlpp::Row>::const_iterator v=res.begin(); v<res.end(); v++)
+        {
+            const string name = (*v)[0].c_str();
+            const double ra   = (*v)[1];
+            const double dec  = (*v)[2];
+
+            // FIXME: Check double names
+            fSources[name] = make_pair(ra, dec);
+        }
+    }
+
     int EvalOptions(Configuration &conf)
     {
@@ -1068,4 +1194,42 @@
 
         fDrive.SetVerbose(!conf.Get<bool>("quiet"));
+
+        const vector<string> &vec = conf.Vec<string>("source");
+
+        for (vector<string>::const_iterator it=vec.begin(); it!=vec.end(); it++)
+        {
+            istringstream stream(*it);
+
+            string name;
+            double ra=0;
+            double dec=0;
+
+            int i=0;
+
+            string buffer;
+            while (getline(stream, buffer, ','))
+            {
+                istringstream is(buffer);
+
+                switch (i++)
+                {
+                case 0: name = buffer; break;
+                case 1: ra   = ConnectionDrive::ReadAngle(is); break;
+                case 2: dec  = ConnectionDrive::ReadAngle(is); break;
+                }
+
+                if (is.fail())
+                    break;
+            }
+
+            if (i==3)
+            {
+                // FIXME: Check double names
+                fSources[name] = make_pair(ra, dec);
+            }
+        }
+
+        if (conf.Has("source-database"))
+            ReadDatabase(conf.Get<string>("source-database"));
 
         return -1;
@@ -1091,4 +1255,6 @@
         ("addr,a",  var<string>("localhost:7404"),  "Network address of Cosy")
         ("quiet,q", po_bool(true),  "Disable printing contents of all received messages (except dynamic data) in clear text.")
+        ("source-database", var<string>(), "Database link as in\n\tuser:password@server[:port]/database.")
+        ("source", vars<string>(), "Additional source entry in the form \"name,hh:mm:ss,dd:mm:ss\"")
         ;
 
