Index: trunk/FACT++/src/pwrctrl.cc
===================================================================
--- trunk/FACT++/src/pwrctrl.cc	(revision 14516)
+++ trunk/FACT++/src/pwrctrl.cc	(revision 14518)
@@ -1,7 +1,5 @@
 #include <boost/bind.hpp>
 
-#include <string>    // std::string
-#include <algorithm> // std::transform
-#include <cctype>    // std::tolower
+#include <string>
 
 #include <QtXml/QDomDocument>
@@ -18,5 +16,5 @@
 #include "tools.h"
 
-#include "HeadersLid.h"
+#include "HeadersPower.h"
 
 namespace ba = boost::asio;
@@ -29,83 +27,5 @@
 {
 protected:
-
-    struct Status
-    {
-        bool fWaterFlowOk;
-        bool fWaterLevelOk;
-
-        bool fPwrBiasOn;
-        bool fPwr24VOn;
-        bool fPwrPumpOn;
-        bool fPwrDriveOn;
-
-        bool fDriveMainSwitchOn;
-        bool fDriveFeedbackOn;
-
-        Status() { }
-
-        bool Set(bool &rc, const QString &value)
-        {
-            rc = value.toInt();
-            return true;
-        }
-
-        bool Set(const QDomNamedNodeMap &map)
-        {
-            if (!map.contains("id") || !map.contains("title"))
-                return false;
-
-            QString item  = map.namedItem("id").nodeValue();
-            QString value = map.namedItem("title").nodeValue();
-
-            if (item==(QString("flow_meter")))
-                return Set(fWaterFlowOk, value);
-
-            if (item==(QString("level")))
-                return Set(fWaterLevelOk, value);
-
-            if (item==(QString("bias_power")))
-                return Set(fPwrBiasOn, value);
-
-            if (item==(QString("power_24v")))
-                return Set(fPwr24VOn, value);
-
-            if (item==(QString("pump")))
-                return Set(fPwrPumpOn, value);
-
-            if (item==(QString("drive_power")))
-                return Set(fPwrDriveOn, value);
-
-            if (item==(QString("drive_on")))
-                return Set(fDriveMainSwitchOn, value);
-
-            if (item==(QString("drive_enable")))
-                return Set(fDriveFeedbackOn, value);
-
-            return false;
-        }
-
-        void Print(ostream &out, const string &title, const bool &val, const string &t="enabled", const string &f="disabled")
-        {
-            out << setw(15) << (title+":");
-            if (val)
-                out << kGreen << t << endl;
-            else
-                out << kRed   << f << endl;
-        }
-
-        void Print(ostream &out)
-        {
-            Print(out, "Water flow",     fWaterFlowOk,  "ok", "low");
-            Print(out, "Water level",    fWaterLevelOk, "ok", "low");
-            Print(out, "Power bias",     fPwrBiasOn);
-            Print(out, "Power 24V",      fPwr24VOn);
-            Print(out, "Power pump",     fPwrPumpOn);
-            Print(out, "Power drive",    fPwrDriveOn);
-            Print(out, "Drive main",     fDriveMainSwitchOn, "on", "off");
-            Print(out, "Drive feedback", fDriveFeedbackOn,   "on", "off");
-        }
-
-    };
+    bool fIsValid;
 
 private:
@@ -113,4 +33,5 @@
 
     bool fIsVerbose;
+    bool fDebugRx;
 
     string fSite;
@@ -123,7 +44,7 @@
     Time fLastReport;
 
-    Status fStatus;
-
-    virtual void Update(const Status &)
+    Power::Status fStatus;
+
+    virtual void Update(const Power::Status &)
     {
     }
@@ -132,5 +53,5 @@
     void ProcessAnswer()
     {
-        if (fIsVerbose)
+        if (fDebugRx)
         {
             Out() << "------------------------------------------------------" << endl;
@@ -139,34 +60,5 @@
         }
 
-        /*
-        fRdfData =
-            "HTTP/1.1 200 OK\n"
-            "Content-Type: text/html\n"
-            "Connnection: close\r\n"
-            "\r\n"
-            "<!DOCTYPE HTML>\n"
-            "<html><head>\n"
-            "<meta http-equiv=\"refresh\" content=\"1 URL=index.html\"/>\n"
-            "<title>FACT camera power interlock control</title>\n"
-            "</head><body>\n"
-            "<FORM NAME=\"Form\">"
-            "<P/><INPUT TYPE=\"SUBMIT\" NAME=\"D2off\"    VALUE=\"Disable Pump\"/>--> FC_OFF HIGH for 0.5 seconds <br/>\n"
-            "<P/><INPUT TYPE=\"SUBMIT\" NAME=\"D2on\"     VALUE=\"Enable Pump\" />--> FC_ON  HIGH for 3.0 seconds <br/>\n"
-            "<P/><INPUT TYPE=\"SUBMIT\" NAME=\"toggle_x\" VALUE=\"Toggle X\"    />--> ... well it toggles X       <br/>\n"
-            "<P/><INPUT TYPE=\"SUBMIT\" NAME=\"toggle_y\" VALUE=\"Toggle Y\"    />--> ... well it toggles Y       <br/>\n"
-            "FC_OK :2  is <font color=\"red\"   size=\"20\"><span id=\"FC_OK\" value=\"0\">LOW  </span></font><br />\n"
-            "BP_ON :3  is <font color=\"red\"   size=\"20\"><span id=\"BP_ON\" value=\"0\">LOW  </span></font><br />\n"
-            "IL_ON :14 is <font color=\"green\" size=\"20\"><span id=\"IL_ON\" value=\"1\">HIGH </span></font><br />\n"
-            "FL_OK :15 is <font color=\"green\" size=\"20\"><span id=\"FL_OK\" value=\"1\">HIGH </span></font><br />\n"
-            "FP_EN :16 is <font color=\"red\"   size=\"20\"><span id=\"FP_EN\" value=\"0\">LOW  </span></font><br />\n"
-            "X_ON  :17 is <font color=\"red\"   size=\"20\"><span id=\"X_ON\"  value=\"0\">LOW  </span></font><br />\n"
-            "Y_ON  :18 is <font color=\"red\"   size=\"20\"><span id=\"Y_ON\"  value=\"0\">LOW  </span></font><br />\n"
-            "Z_OK  :19 is <font color=\"red\"   size=\"20\"><span id=\"Z_OK\"  value=\"0\">LOW  </span></font><br />\n"
-            "</FORM>\n"
-            "</body></html>\n";
-        */
-
         const size_t p1 = fRdfData.find("\r\n\r\n");
-        //const size_t p1 = fRdfData.find("\n\n");
         if (p1==string::npos)
         {
@@ -187,56 +79,25 @@
         }
 
+        if (fDebugRx)
+            Out() << "Parsed:\n-------\n" << doc.toString().toStdString() << endl;
+
+        const QDomNodeList imageElems = doc.elementsByTagName("span");
+
+        for (unsigned int i=0; i<imageElems.length(); i++)
+        {
+            const QDomElement e = imageElems.item(i).toElement();
+
+            const QDomNamedNodeMap att = e.attributes();
+
+            if (fStatus.Set(att))
+                fIsValid = true;
+        }
+
         if (fIsVerbose)
-        {
-            Out() << "Parsed:\n-------\n" << doc.toString().toStdString() << endl;
-            Out() << "------------------------------------------------------" << endl;
-        }
-
-        const QDomNodeList imageElems = doc.elementsByTagName("span"); // "input"
-
-        /*
-        // elementById
-        for (unsigned int i=0; i<imageElems.length(); i++)
-        {
-            QDomElement e = imageElems.item(i).toElement();
-            Out() << "<" << e.tagName().toStdString() << " ";
-
-            QDomNamedNodeMap att = e.attributes();
-
-            for (int j=0; j<att.size(); j++)
-            {
-                Out() << att.item(j).nodeName().toStdString() << "=";
-                Out() << att.item(j).nodeValue().toStdString() << " ";
-            }
-            Out() << "> " << e.text().toStdString() << endl;
-        }*/
-
-        for (unsigned int i=0; i<imageElems.length(); i++)
-        {
-            const QDomElement e = imageElems.item(i).toElement();
-
-            const QDomNamedNodeMap att = e.attributes();
-
-            fStatus.Set(att);
-        }
-
-        if (fIsVerbose)
-        {
             fStatus.Print(Out());
-            Out() << "------------------------------------------------------" << endl;
-        }
 
         Update(fStatus);
 
         fRdfData = "";
-
-        /*
-        if ((fLid1.status!="Open" && fLid1.status!="Closed" && fLid1.status!="Unknown") ||
-            (fLid2.status!="Open" && fLid2.status!="Closed" && fLid2.status!="Unknown"))
-        {
-            Warn("Lid status unknown ("+fLid1.status+"/"+fLid2.status+")");
-            PostClose(false);
-            return;
-        }*/
 
         fLastReport = Time();
@@ -251,5 +112,6 @@
             if (err==ba::error::eof)
             {
-                ProcessAnswer();
+                if (!fRdfData.empty())
+                    ProcessAnswer();
                 return;
             }
@@ -273,6 +135,4 @@
         fRdfData += string(fArray.data(), bytes_received);
 
-        //cout << "." << flush;
-
         // Does the message contain a header?
         const size_t p1 = fRdfData.find("\r\n\r\n");
@@ -282,7 +142,5 @@
             const size_t p2 = fRdfData.find("\r\n\r\n", p1+4);
             if (p2!=string::npos)
-            {
                 ProcessAnswer();
-            }
         }
 
@@ -369,5 +227,5 @@
 public:
     ConnectionInterlock(ba::io_service& ioservice, MessageImp &imp) : Connection(ioservice, imp()),
-        fIsVerbose(true), fLastReport(Time::none), fKeepAlive(ioservice)
+        fIsValid(false), fIsVerbose(true), fDebugRx(false), fLastReport(Time::none), fKeepAlive(ioservice)
     {
         SetLogStream(&imp);
@@ -377,4 +235,9 @@
     {
         fIsVerbose = b;
+    }
+
+    void SetDebugRx(bool b)
+    {
+        fDebugRx = b;
         Connection::SetVerbose(b);
     }
@@ -393,5 +256,4 @@
     {
         fNextCommand = post;
-        //PostRequest("POST", post);
     }
 
@@ -400,7 +262,4 @@
         PostRequest("POST", fNextCommand);
         fNextCommand = "";
-
-        //fLid1.status = "";
-        //fLid2.status = "";
 
         fKeepAlive.expires_from_now(boost::posix_time::seconds(fInterval));
@@ -416,28 +275,34 @@
     int GetState() const
     {
-        using namespace Lid;
+        using namespace Power::State;
 
         // Timeout
         if (fLastReport.IsValid() && fLastReport+boost::posix_time::seconds(fInterval*2)<Time())
-            return State::kDisconnected;
+            return Power::State::kDisconnected;
+
+        // No dat areceived yet
+        if (!fIsValid)
+            return Power::State::kConnected;
 
         /*
-        // Inconsistency
-        if (fLid1.status!=fLid2.status)
-            return State::kInconsistent;
-
-        // Unknown
-        if (fLid1.status=="Unknown")
-            return State::kUnknown;
-
-        // Closed
-        if (fLid1.status=="Closed")
-            return State::kClosed;
-
-        // Open
-        if (fLid1.status=="Open")
-            return State::kOpen;
-         */
-        return State::kConnected;
+         bool fWaterFlowOk;
+         bool fWaterLevelOk;
+         bool fPwrBiasOn;
+         bool fPwr24VOn;
+         bool fPwrPumpOn;
+         bool fPwrDriveOn;
+         bool fDriveMainSwitchOn;
+         bool fDriveFeedbackOn;
+        */
+
+        if (!fStatus.fWaterLevelOk || (fStatus.fPwrPumpOn && !fStatus.fWaterFlowOk))
+            return kCoolingFailure;
+
+        const int rc =
+            (fStatus.fPwrBiasOn       ? kBiasOn   : 0) |
+            (fStatus.fPwrPumpOn       ? kCameraOn : 0) |
+            (fStatus.fDriveFeedbackOn ? kDriveOn  : 0);
+
+        return rc==0 ? kSystemOff : rc;
     }
 };
@@ -452,48 +317,25 @@
 {
 private:
-    //DimDescribedService fDim;
+    DimDescribedService fDim;
 
 public:
     ConnectionDimWeather(ba::io_service& ioservice, MessageImp &imp) :
-        ConnectionInterlock(ioservice, imp)/*,
-        fDim("PWR_CONTROL/DATA", "S:2;F:2;F:2",
-             "|status[bool]:Lid1/2 open or closed"
-             "|I[A]:Lid1/2 current"
-             "|P[dac]:Lid1/2 hall sensor position in averaged dac counts")*/
-    {
-    }
-
-    void Update(const Status &status)
-    {
-            /*
-        struct DimData
-        {
-            int16_t status[2];
-            float   current[2];
-            float   position[2];
-
-            DimData() { status[0] = status[1] = -1; }
-
-        } __attribute__((__packed__));
-
-        DimData data;
-
-        if (l1.status=="Open")
-            data.status[0] = 1;
-        if (l1.status=="Closed")
-            data.status[0] = 0;
-
-        if (l2.status=="Open")
-            data.status[1] = 1;
-        if (l2.status=="Closed")
-            data.status[1] = 0;
-
-        data.current[0]  = l1.current;
-        data.current[1]  = l2.current;
-
-        data.position[0] = l1.position;
-        data.position[1] = l2.position;
-
-        fDim.Update(data);*/
+        ConnectionInterlock(ioservice, imp),
+        fDim("PWR_CONTROL/DATA", "B:1;B:1;B:1;B:1;B:1;B:1;B:1;B:1",
+             "|water_lvl[bool]:Water level ok"
+             "|water_flow[bool]:Water flowing"
+             "|pwr_24V[bool]:24V power enabled"
+             "|pwr_pump[bool]:Pump power enabled"
+             "|pwr_bias[bool]:Bias power enabled"
+             "|pwr_drive[bool]:Drive power enabled (command value)"
+             "|main_drive[bool]:Drive manual main switch on"
+             "|feedback_drive[bool]:Drive power on (feedback value)")
+    {
+    }
+
+    void Update(const Power::Status &status)
+    {
+        fDim.setQuality(status.GetVal());
+        fDim.Update(status);
     }
 };
@@ -505,5 +347,5 @@
 {
 private:
-    S fLid;
+    S fPower;
     Time fLastCommand;
 
@@ -524,46 +366,42 @@
             return T::kSM_FatalError;
 
-        fLid.SetVerbose(evt.GetBool());
+        fPower.SetVerbose(evt.GetBool());
 
         return T::GetCurrentState();
     }
 
+    int SetDebugRx(const EventImp &evt)
+    {
+        if (!CheckEventSize(evt.GetSize(), "SetDebugRx", 1))
+            return T::kSM_FatalError;
+
+        fPower.SetDebugRx(evt.GetBool());
+
+        return T::GetCurrentState();
+    }
+
     int Post(const EventImp &evt)
     {
-        fLid.Post(evt.GetText());
+        fPower.Post(evt.GetText());
         return T::GetCurrentState();
     }
 
-    int Open()
-    {
+    int SetCameraPower(const EventImp &evt)
+    {
+        if (!CheckEventSize(evt.GetSize(), "SetCameraPower", 1))
+            return T::kSM_FatalError;
+
         fLastCommand = Time();
-        fLid.Post("Button5=");
-        return Lid::State::kMoving;
-    }
-    int Close()
+        fPower.Post(evt.GetBool() ? "cam_on=" : "cam_off=");
+        return T::GetCurrentState();
+    }
+
+    int ToggleDrive()
     {
         fLastCommand = Time();
-        fLid.Post("Button6=");
-        return Lid::State::kMoving;
-
-    }
-    /*
-    int MoveMotor(const EventImp &evt, int mid)
-    {
-        if (!CheckEventSize(evt.GetSize(), "MoveMotor", 2))
-            return T::kSM_FatalError;
-
-        if (evt.GetUShort()>0xfff)
-        {
-            ostringstream msg;
-            msg << "Position " << evt.GetUShort() << " for motor " << mid+1 << " out of range [0,1023].";
-            T::Error(msg);
-            return T::GetCurrentState();
-        }
-
-        fLid.MoveMotor(mid, evt.GetUShort());
-
+        fPower.Post("dt=");
         return T::GetCurrentState();
-    }*/
+
+    }
 
     int Execute()
@@ -576,12 +414,5 @@
         poll_one();
 
-        const int rc = fLid.GetState();
-
-        if (T::GetCurrentState()==Lid::State::kMoving &&
-            (rc==Lid::State::kConnected || rc==Lid::State::kDisconnected) &&
-            fLastCommand+boost::posix_time::seconds(6*fLid.GetInterval()) < Time())
-            return Lid::State::kMoving;
-
-        return rc==Lid::State::kConnected ? T::GetCurrentState() : rc;
+        return fPower.GetState();
     }
 
@@ -589,6 +420,6 @@
 public:
     StateMachinePowerControl(ostream &out=cout) :
-        T(out, "LID_CONTROL"), ba::io_service::work(static_cast<ba::io_service&>(*this)),
-        fLid(*this, *this)
+        T(out, "PWR_CONTROL"), ba::io_service::work(static_cast<ba::io_service&>(*this)),
+        fPower(*this, *this)
     {
         // ba::io_service::work is a kind of keep_alive for the loop.
@@ -600,21 +431,33 @@
 
         // State names
-        T::AddStateName(Lid::State::kDisconnected, "NoConnection",
+        T::AddStateName(Power::State::kDisconnected, "NoConnection",
                      "No connection to web-server could be established recently");
 
-        T::AddStateName(Lid::State::kConnected, "Connected",
+        T::AddStateName(Power::State::kConnected, "Connected",
                      "Connection established, but status still not known");
 
-        T::AddStateName(Lid::State::kInconsistent, "Inconsistent",
-                     "Both lids show different states");
-
-        T::AddStateName(Lid::State::kUnknown, "Unknown",
-                     "Arduino resports both lids in an unknown status");
-
-        T::AddStateName(Lid::State::kClosed, "Closed",
-                     "Both lids are closed");
-
-        T::AddStateName(Lid::State::kOpen, "Open",
-                     "Both lids are open");
+        T::AddStateName(Power::State::kSystemOff, "PowerOff",
+                     "Camera, Bias and Drive power off");
+
+        T::AddStateName(Power::State::kBiasOn, "BiasOn",
+                     "Camera and Drive power off, Bias on");
+
+        T::AddStateName(Power::State::kDriveOn, "DriveOn",
+                     "Camera and Bias power off, Drive on");
+
+        T::AddStateName(Power::State::kCameraOn, "CameraOn",
+                     "Drive and Bias power off, Camera on");
+
+        T::AddStateName(Power::State::kDriveOn|Power::State::kCameraOn, "BiasOff",
+                     "Camera and Drive power on, Bias off");
+
+        T::AddStateName(Power::State::kBiasOn|Power::State::kCameraOn, "DriveOff",
+                     "Camera and Bias power on, Drive off");
+
+        T::AddStateName(Power::State::kDriveOn|Power::State::kBiasOn, "CameraOff",
+                     "Drive and Bias power on, Camera off");
+
+        T::AddStateName(Power::State::kDriveOn|Power::State::kBiasOn|Power::State::kCameraOn, "SystemOn",
+                     "Camera, Bias and drive power on");
 
 
@@ -623,11 +466,16 @@
             (bind(&StateMachinePowerControl::SetVerbosity, this, placeholders::_1))
             ("set verbosity state"
-             "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
-
-        T::AddEvent("OPEN", Lid::State::kInconsistent, Lid::State::kClosed)
-            (bind(&StateMachinePowerControl::Open, this));
-
-        T::AddEvent("CLOSE", Lid::State::kInconsistent, Lid::State::kOpen)
-            (bind(&StateMachinePowerControl::Close, this));
+             "|verbosity[bool]:disable or enable verbosity for interpreted data (yes/no)");
+
+        T::AddEvent("SET_DEBUG_RX", "B")
+            (bind(&StateMachinePowerControl::SetDebugRx, this, placeholders::_1))
+            ("set debux-rx state"
+             "|debug[bool]:dump received text and parsed text to console (yes/no)");
+
+        T::AddEvent("CAMERA_POWER", "B")
+            (bind(&StateMachinePowerControl::SetCameraPower, this, placeholders::_1));
+
+        T::AddEvent("TOGGLE_DRIVE")
+            (bind(&StateMachinePowerControl::ToggleDrive, this));
 
         T::AddEvent("POST", "C")
@@ -639,10 +487,11 @@
     int EvalOptions(Configuration &conf)
     {
-        fLid.SetVerbose(!conf.Get<bool>("quiet"));
-        fLid.SetInterval(conf.Get<uint16_t>("interval"));
-        fLid.SetDebugTx(conf.Get<bool>("debug-tx"));
-        fLid.SetSite(conf.Get<string>("url"));
-        fLid.SetEndpoint(conf.Get<string>("addr"));
-        fLid.StartConnect();
+        fPower.SetVerbose(!conf.Get<bool>("quiet"));
+        fPower.SetInterval(conf.Get<uint16_t>("interval"));
+        fPower.SetDebugTx(conf.Get<bool>("debug-tx"));
+        fPower.SetDebugRx(conf.Get<bool>("debug-rx"));
+        fPower.SetSite(conf.Get<string>("url"));
+        fPower.SetEndpoint(conf.Get<string>("addr"));
+        fPower.StartConnect();
 
         return -1;
@@ -671,4 +520,5 @@
         ("interval,i", var<uint16_t>(5), "Interval between two updates on the server in seconds")
         ("debug-tx",   po_bool(), "Enable debugging of ethernet transmission.")
+        ("debug-rx",   po_bool(), "Enable debugging for received data.")
         ;
 
