|
From: <tho...@us...> - 2012-02-19 23:13:02
|
Revision: 710
http://openautomation.svn.sourceforge.net/openautomation/?rev=710&view=rev
Author: thomas_s
Date: 2012-02-19 23:12:54 +0000 (Sun, 19 Feb 2012)
Log Message:
-----------
- refactored determinatoritems
- added determinator actions (not fully implemented)
- refactored xplhandler to use asio for calling xPL_process_messages
WIP!
Modified Paths:
--------------
xPLHAL/branches/thomas_s_dev/CMakeLists.txt
xPLHAL/branches/thomas_s_dev/src/determinator.cpp
xPLHAL/branches/thomas_s_dev/src/determinator.h
xPLHAL/branches/thomas_s_dev/src/determinatoritems.cpp
xPLHAL/branches/thomas_s_dev/src/determinatoritems.h
xPLHAL/branches/thomas_s_dev/src/globals.h
xPLHAL/branches/thomas_s_dev/src/main.cpp
xPLHAL/branches/thomas_s_dev/src/xplhandler.cpp
xPLHAL/branches/thomas_s_dev/src/xplhandler.h
xPLHAL/branches/thomas_s_dev/src/xplmessagequeue.cpp
xPLHAL/branches/thomas_s_dev/src/xplmessagequeue.h
xPLHAL/branches/thomas_s_dev/test/determinator1.xml
xPLHAL/branches/thomas_s_dev/test/test_determinator.cpp
Added Paths:
-----------
xPLHAL/branches/thomas_s_dev/src/actions/
xPLHAL/branches/thomas_s_dev/src/conditions/
xPLHAL/branches/thomas_s_dev/test/pugi.h
Modified: xPLHAL/branches/thomas_s_dev/CMakeLists.txt
===================================================================
--- xPLHAL/branches/thomas_s_dev/CMakeLists.txt 2012-02-19 12:22:04 UTC (rev 709)
+++ xPLHAL/branches/thomas_s_dev/CMakeLists.txt 2012-02-19 23:12:54 UTC (rev 710)
@@ -37,7 +37,7 @@
#set(Boost_USE_STATIC_LIBS ON)
set(Boost_USE_MULTITHREADED ON)
-find_package(Boost 1.38 COMPONENTS thread system filesystem date_time regex unit_test_framework)
+find_package(Boost 1.38 COMPONENTS thread system filesystem date_time regex unit_test_framework program_options)
find_package(xPL REQUIRED)
set(LIBS ${LIBS} ${Boost_LIBRARIES} ${xPL_LIBRARIES} pthread)
Modified: xPLHAL/branches/thomas_s_dev/src/determinator.cpp
===================================================================
--- xPLHAL/branches/thomas_s_dev/src/determinator.cpp 2012-02-19 12:22:04 UTC (rev 709)
+++ xPLHAL/branches/thomas_s_dev/src/determinator.cpp 2012-02-19 23:12:54 UTC (rev 710)
@@ -3,11 +3,14 @@
#include <cxxabi.h>
#include <typeinfo>
#include <memory>
+#include <functional>
using std::string;
using std::vector;
using std::cerr;
using std::endl;
+using std::thread;
+using std::bind;
void Determinator::printDeterminator() const
{
@@ -38,7 +41,8 @@
registerCondition(BaseDeterminatorItemConstPtr(new DayCondition));
registerCondition(BaseDeterminatorItemConstPtr(new TimeCondition));
- registerAction(BaseDeterminatorItemConstPtr(new LogAction));
+ registerAction(BaseDeterminatorItemConstPtr(new logAction));
+ registerAction(BaseDeterminatorItemConstPtr(new xplAction));
pugi::xml_parse_result result = m_doc.load_file(filename.c_str());
cerr << "Load result: " << result.description() << "\n";
@@ -70,6 +74,11 @@
d.enabled = base_d.attribute("guid").value() == "Y";
pugi::xml_node input = base_d.child("input");
+ d.input_match_type = Determinator::match_type::ALL;
+ if (input.attribute("match").value() == "any") {
+ d.input_match_type = Determinator::match_type::ANY;
+ }
+
pugi::xml_node output = base_d.child("output");
for(auto condition : m_conditionmap) {
@@ -81,7 +90,8 @@
for(auto action : m_actionmap) {
pugi::xml_node action_node = output.child(action.first.c_str());
if (action_node) {
- d.outputs.insert({action.first, BaseDeterminatorItemPtr(action.second->createNew(action_node))} );
+ BaseDeterminatorItemPtr actionObject(action.second->createNew(action_node));
+ d.outputs.insert({action.first, actionObject});
}
}
@@ -108,4 +118,59 @@
}
return node;
}
+
+Determinator::Determinator()
+{
+}
+Determinator::~Determinator()
+{
+ if (mExecuteThread) {
+ mExecuteThread->join();
+ }
+}
+
+bool Determinator::checkInputs() const
+{
+ for (auto input : inputs) {
+ bool match = input.second->match();
+ switch(input_match_type) {
+ case match_type::ALL: if (!match) return false;
+ case match_type::ANY: if (match) return true;
+ }
+ }
+ return (input_match_type == match_type::ALL);
+}
+
+void Determinator::executeOutputs() const
+{
+ std::multimap<string, BaseDeterminatorItemPtr> orderd_outputs;
+ for (auto output : outputs) {
+ string execOrder;
+ auto execOrderIter = output.second->attributes.find("executeOrder");
+ if (execOrderIter != output.second->attributes.end()) {
+ execOrder = execOrderIter->second;
+ }
+ orderd_outputs.insert({execOrder, output.second});
+ }
+
+ for (auto output : orderd_outputs) {
+ cerr << "execute output:" << output.second->display_name << endl;
+ output.second->execute();
+ }
+}
+
+/**
+ * Check if input conditions are met, then start a thread to execute actions
+ */
+void Determinator::execute()
+{
+ if (checkInputs()) {
+ if (mExecuteThread) {
+ mExecuteThread->join();
+ }
+ cerr << "determinator start thread" << endl;
+ mExecuteThread.reset(new thread(bind(&Determinator::executeOutputs, this)));
+ }
+}
+
Modified: xPLHAL/branches/thomas_s_dev/src/determinator.h
===================================================================
--- xPLHAL/branches/thomas_s_dev/src/determinator.h 2012-02-19 12:22:04 UTC (rev 709)
+++ xPLHAL/branches/thomas_s_dev/src/determinator.h 2012-02-19 23:12:54 UTC (rev 710)
@@ -4,14 +4,20 @@
#include <string>
#include <vector>
#include <map>
+#include <thread>
class Determinator
{
public:
+ explicit Determinator();
+ virtual ~Determinator();
+
enum class match_type { ALL, ANY };
void printDeterminator() const;
+ void execute();
+
std::string guid;
std::string name;
std::string description;
@@ -20,6 +26,12 @@
std::multimap<std::string, BaseDeterminatorItemPtr> inputs;
std::multimap<std::string, BaseDeterminatorItemPtr> outputs;
+
+ private:
+ bool checkInputs() const;
+ void executeOutputs() const;
+
+ std::unique_ptr<std::thread> mExecuteThread;
};
class DeterminatorXmlParser
Modified: xPLHAL/branches/thomas_s_dev/src/determinatoritems.cpp
===================================================================
--- xPLHAL/branches/thomas_s_dev/src/determinatoritems.cpp 2012-02-19 12:22:04 UTC (rev 709)
+++ xPLHAL/branches/thomas_s_dev/src/determinatoritems.cpp 2012-02-19 23:12:54 UTC (rev 710)
@@ -3,21 +3,12 @@
#include <iostream>
#include <typeinfo>
#include <iostream>
+#include "log.h"
using std::string;
using std::vector;
+using std::map;
-ConditionParseException::ConditionParseException(const string& text)
-:m_text(text)
-{
-}
-
-const char* ConditionParseException::what() const throw()
-{
- return m_text.c_str();
-
-}
-
DeterminatorParseException::DeterminatorParseException(const string& text)
:m_text(text)
{
@@ -32,18 +23,21 @@
class ScopedXmlAttributeGetter
{
public:
- ScopedXmlAttributeGetter(const pugi::xml_node& basenode) :m_basenode(basenode) {}
+ ScopedXmlAttributeGetter(const pugi::xml_node& basenode, map<string, string> &attributemap)
+ :m_basenode(basenode),m_attributemap(attributemap) {}
string get(const string& attribute_name) const {
pugi::xml_attribute xml_attribute = m_basenode.attribute(attribute_name.c_str());
if (!xml_attribute) {
string error_text = string("In node '") + m_basenode.name() + "'";
error_text += " attribute '" + attribute_name + "' was not found";
- throw ConditionParseException(error_text);
+ throw DeterminatorParseException(error_text);
}
+ m_attributemap.insert({attribute_name, xml_attribute.value()});
return xml_attribute.value();
}
private:
const pugi::xml_node& m_basenode;
+ map<string, string> &m_attributemap;
};
BaseDeterminatorItem::BaseDeterminatorItem(const string& name)
@@ -54,10 +48,19 @@
BaseDeterminatorItem::BaseDeterminatorItem(const pugi::xml_node& basenode, const string& name)
:item_name(name)
{
- ScopedXmlAttributeGetter a(basenode);
+ ScopedXmlAttributeGetter a(basenode, attributes);
display_name = a.get("display_name");
}
+
+bool BaseDeterminatorItem::match() const
+{
+ return true;
+}
+void BaseDeterminatorItem::execute() const
+{
+}
+
/*
* Determinator Conditions
*/
@@ -80,7 +83,7 @@
void XplCondition::parseFromXml(const pugi::xml_node& basenode)
{
- ScopedXmlAttributeGetter helper(basenode);
+ ScopedXmlAttributeGetter helper(basenode, attributes);
msg_type = helper.get("msg_type");
source_vendor = helper.get("source_vendor");
source_device = helper.get("source_device");
@@ -94,7 +97,7 @@
for(const auto node : basenode) {
if (node.name() == string("param")) {
struct parameter p;
- ScopedXmlAttributeGetter pa(node);
+ ScopedXmlAttributeGetter pa(node, attributes);
p.name = pa.get("name");
p.op = pa.get("operator");
p.value = pa.get("value");
@@ -120,8 +123,7 @@
}
return ret;
}
-
-
+
GlobalCondition::GlobalCondition()
:BaseDeterminatorItem("globalCondition")
{
@@ -140,9 +142,10 @@
void GlobalCondition::parseFromXml(const pugi::xml_node& basenode)
{
- name = basenode.attribute("name").value();
- op = basenode.attribute("operator").value();
- value = basenode.attribute("value").value();
+ ScopedXmlAttributeGetter helper(basenode, attributes);
+ name = helper.get("name");
+ op = helper.get("operator");
+ value = helper.get("value");
}
string GlobalCondition::toString() const
@@ -172,7 +175,8 @@
void GlobalChanged::parseFromXml(const pugi::xml_node& basenode)
{
- name = basenode.attribute("name").value();
+ ScopedXmlAttributeGetter helper(basenode, attributes);
+ name = helper.get("name");
}
string GlobalChanged::toString() const
@@ -201,7 +205,8 @@
void DayCondition::parseFromXml(const pugi::xml_node& basenode)
{
- dow = basenode.attribute("dow").value();
+ ScopedXmlAttributeGetter helper(basenode, attributes);
+ dow = helper.get("dow");
}
string DayCondition::toString() const
@@ -229,8 +234,9 @@
void TimeCondition::parseFromXml(const pugi::xml_node& basenode)
{
- op = basenode.attribute("operator").value();
- value = basenode.attribute("value").value();
+ ScopedXmlAttributeGetter helper(basenode, attributes);
+ op = helper.get("operator");
+ value = helper.get("value");
}
string TimeCondition::toString() const
@@ -245,33 +251,54 @@
* Determinator Actions
*/
-LogAction::LogAction()
-:BaseDeterminatorItem("logAction")
+void logAction::parseFromXml(const pugi::xml_node& basenode)
{
+ ScopedXmlAttributeGetter helper(basenode, attributes);
+ logText = helper.get("logText");
+ executeOrder = helper.get("executeOrder");
}
-LogAction::LogAction(const pugi::xml_node& basenode)
-:BaseDeterminatorItem(basenode, "logAction")
+std::string logAction::toString() const
{
- parseFromXml(basenode);
+ string ret = item_name + ":";
+ ret += "\nlogText.....: " + logText;
+ ret += "\nexecuteOrder: " + executeOrder;
+ return ret;
}
-BaseDeterminatorItemPtr LogAction::createNew(const pugi::xml_node& basenode) const
+void logAction::execute() const
{
- return BaseDeterminatorItemPtr(new LogAction(basenode));
+ writeLog(logText, logLevel::debug);
}
-void LogAction::parseFromXml(const pugi::xml_node& basenode)
+//-----
+
+void xplAction::parseFromXml(const pugi::xml_node& basenode)
{
- logText = basenode.attribute("logText").value();
- executeOrder = basenode.attribute("executeOrder").value();
+ ScopedXmlAttributeGetter helper(basenode, attributes);
+ executeOrder = helper.get("executeOrder");
+ msgType = helper.get("msgType");
+ msgTarget = helper.get("msgTarget");
+ msgSchema = helper.get("msgSchema");
+
+ for(const auto node : basenode) {
+ if (node.name() == string("xplActionParam")) {
+ string expression = node.attribute("expression").value();
+ }
+ }
}
-std::string LogAction::toString() const
+std::string xplAction::toString() const
{
string ret = item_name + ":";
- ret += "\nlogText.....: " + logText;
ret += "\nexecuteOrder: " + executeOrder;
+ ret += "\nmsgType.....: " + msgType;
+ ret += "\nmsgTarget...: " + msgTarget;
+ ret += "\nmsgSchema...: " + msgSchema;
return ret;
}
+void xplAction::execute() const
+{
+}
+
Modified: xPLHAL/branches/thomas_s_dev/src/determinatoritems.h
===================================================================
--- xPLHAL/branches/thomas_s_dev/src/determinatoritems.h 2012-02-19 12:22:04 UTC (rev 709)
+++ xPLHAL/branches/thomas_s_dev/src/determinatoritems.h 2012-02-19 23:12:54 UTC (rev 710)
@@ -3,17 +3,8 @@
#include <string>
#include <vector>
#include <memory>
+#include <map>
-class ConditionParseException: public std::exception
-{
- public:
- ConditionParseException(const std::string& text);
- virtual ~ConditionParseException() throw() {}
- const char* what() const throw();
- private:
- std::string m_text;
-};
-
class DeterminatorParseException: public std::exception
{
public:
@@ -37,13 +28,40 @@
virtual void parseFromXml(const pugi::xml_node& basenode) = 0;
virtual BaseDeterminatorItemPtr createNew(const pugi::xml_node& basenode) const = 0;
virtual std::string toString() const = 0;
+ virtual bool match() const;
+ virtual void execute() const;
std::string item_name;
std::string display_name;
+ std::map<std::string, std::string> attributes;
+
//boost::signal2::signal<void ()> sigChanged;
};
+template<typename T>
+class DeterminatorAction: public BaseDeterminatorItem
+{
+ public:
+ DeterminatorAction() :BaseDeterminatorItem(typeid(T).name()) { }
+ DeterminatorAction(const pugi::xml_node& basenode)
+ :BaseDeterminatorItem(basenode, std::string(typeid(T).name())) {
+ executeOrder = basenode.attribute("executeOrder").value();
+ attributes["executeOrder"] = executeOrder;
+ }
+
+ BaseDeterminatorItemPtr createNew(const pugi::xml_node& basenode) const {
+ return BaseDeterminatorItemPtr(new T(basenode));
+ }
+
+ std::string executeOrder;
+};
+
+
+/*
+ * Conditions
+ */
+
class XplCondition: public BaseDeterminatorItem
{
public:
@@ -134,16 +152,128 @@
std::string value;
};
-class LogAction: public BaseDeterminatorItem
+/*
+ * Actions
+ */
+
+class logAction: public DeterminatorAction<logAction>
{
public:
- LogAction();
- LogAction(const pugi::xml_node& basenode);
+ logAction() {}
+ logAction(const pugi::xml_node& basenode) : DeterminatorAction(basenode) {
+ parseFromXml(basenode);
+ }
- virtual BaseDeterminatorItemPtr createNew(const pugi::xml_node& basenode) const;
+ void execute() const;
void parseFromXml(const pugi::xml_node& basenode);
std::string toString() const;
std::string logText;
std::string executeOrder;
};
+
+class xplAction: public DeterminatorAction<xplAction>
+{
+ public:
+ xplAction() {}
+ xplAction(const pugi::xml_node& basenode) : DeterminatorAction(basenode) {
+ parseFromXml(basenode);
+ }
+
+ void execute() const;
+ void parseFromXml(const pugi::xml_node& basenode);
+ std::string toString() const;
+
+ std::string msgType;
+ std::string msgTarget;
+ std::string msgSchema;
+ std::multimap<std::string, std::string> actionParams;
+};
+
+class globalAction: public DeterminatorAction<globalAction>
+{
+ public:
+ globalAction();
+ globalAction(const pugi::xml_node& basenode);
+ void execute() const;
+
+ virtual BaseDeterminatorItemPtr createNew(const pugi::xml_node& basenode) const;
+ void parseFromXml(const pugi::xml_node& basenode);
+ std::string toString() const;
+
+ std::string name;
+ std::string value;
+};
+
+class delayAction: public DeterminatorAction<delayAction>
+{
+ public:
+ delayAction();
+ delayAction(const pugi::xml_node& basenode);
+ void execute() const;
+
+ virtual BaseDeterminatorItemPtr createNew(const pugi::xml_node& basenode) const;
+ void parseFromXml(const pugi::xml_node& basenode);
+ std::string toString() const;
+
+ std::string delaySeconds;
+};
+
+class stopAction: public DeterminatorAction<stopAction>
+{
+ public:
+ stopAction();
+ stopAction(const pugi::xml_node& basenode);
+ void execute() const;
+
+ virtual BaseDeterminatorItemPtr createNew(const pugi::xml_node& basenode) const;
+ void parseFromXml(const pugi::xml_node& basenode);
+ std::string toString() const;
+
+};
+
+class suspendAction: public DeterminatorAction<suspendAction>
+{
+ public:
+ suspendAction();
+ suspendAction(const pugi::xml_node& basenode);
+ void execute() const;
+
+ virtual BaseDeterminatorItemPtr createNew(const pugi::xml_node& basenode) const;
+ void parseFromXml(const pugi::xml_node& basenode);
+ std::string toString() const;
+
+ std::string suspendMinutes;
+ std::string suspendTime;
+ std::string suspendRandomise;
+};
+
+class execRuleAction: public DeterminatorAction<execRuleAction>
+{
+ public:
+ execRuleAction();
+ execRuleAction(const pugi::xml_node& basenode);
+ void execute() const;
+
+ virtual BaseDeterminatorItemPtr createNew(const pugi::xml_node& basenode) const;
+ void parseFromXml(const pugi::xml_node& basenode);
+ std::string toString() const;
+
+ std::string ruleName;
+};
+
+class runScriptAction: public DeterminatorAction<runScriptAction>
+{
+ public:
+ runScriptAction();
+ runScriptAction(const pugi::xml_node& basenode);
+ void execute() const;
+
+ virtual BaseDeterminatorItemPtr createNew(const pugi::xml_node& basenode) const;
+ void parseFromXml(const pugi::xml_node& basenode);
+ std::string toString() const;
+
+ std::string scriptName;
+ std::string parameter;
+};
+
Modified: xPLHAL/branches/thomas_s_dev/src/globals.h
===================================================================
--- xPLHAL/branches/thomas_s_dev/src/globals.h 2012-02-19 12:22:04 UTC (rev 709)
+++ xPLHAL/branches/thomas_s_dev/src/globals.h 2012-02-19 23:12:54 UTC (rev 710)
@@ -31,9 +31,6 @@
class xPLHandler;
extern xPLHandler *xPL;
-class xPLMessageQueueClass;
-extern xPLMessageQueueClass *xPLMessageQueue;
-
/** The working directories */
extern boost::filesystem::path xPLHalRootFolder;
extern boost::filesystem::path DataFileFolder;
Modified: xPLHAL/branches/thomas_s_dev/src/main.cpp
===================================================================
--- xPLHAL/branches/thomas_s_dev/src/main.cpp 2012-02-19 12:22:04 UTC (rev 709)
+++ xPLHAL/branches/thomas_s_dev/src/main.cpp 2012-02-19 23:12:54 UTC (rev 710)
@@ -16,17 +16,26 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <signal.h>
+#include <boost/program_options.hpp>
#include "log.h"
-#include "xplcache.h"
#include "devicemanager.h"
#include "xhcp.h"
#include "recurring_timer.h"
+#include "xplhandler.h"
+#include "xplcache.h"
// load globas and give them their space to live
#include "globals.h"
using boost::filesystem::path;
using boost::filesystem::initial_path;
+using boost::program_options::options_description;
+using boost::program_options::variables_map;
+using boost::program_options::store;
+using boost::program_options::parse_command_line;
+using boost::program_options::notify;
+using std::cout;
+using std::endl;
path xPLHalRootFolder;
path DataFileFolder;
@@ -35,7 +44,6 @@
xPLCacheClass *xPLCache;
xPLHandler *xPL;
-xPLMessageQueueClass *xPLMessageQueue;
static boost::asio::io_service* g_ioservice = nullptr;
@@ -43,22 +51,20 @@
{
public:
XplHalApplication()
- :mXplMessageQueue(new xPLMessageQueueClass)
- ,mXplCache(new xPLCacheClass)
+ :mXplCache(new xPLCacheClass)
,mDeviceManager(mXplCache)
,mXHCPServer(new XHCPServer(m_ioservice, &mDeviceManager))
- ,mXpl(new xPLHandler( boost::asio::ip::host_name() ))
+ ,mXpl(new xPLHandler(m_ioservice, boost::asio::ip::host_name() ))
,mTimerListAllObjects(m_ioservice, boost::posix_time::seconds(60), true)
,mTimerFlushExpiredEntries(m_ioservice, boost::posix_time::minutes(5), true)
{
- mDeviceManager.m_sigSendXplMessage.connect(boost::bind(&xPLMessageQueueClass::add, mXplMessageQueue, _1));
+ mDeviceManager.m_sigSendXplMessage.connect(boost::bind(&xPLHandler::sendMessage, mXpl, _1));
mXpl->m_sigRceivedXplMessage.connect(boost::bind(&DeviceManager::processXplMessage, &mDeviceManager, _1));
installTimer();
/* set global variables */
xPLCache = mXplCache;
xPL = mXpl;
- xPLMessageQueue = mXplMessageQueue;
writeLog( "initialized", logLevel::all );
}
@@ -97,7 +103,7 @@
int exec()
{
// force everyone to send their configuration so that we start up to date...
- xPLMessageQueue->add(xPLMessagePtr( new xPLMessage(xPL_MESSAGE_COMMAND, "*", "config", "current", {{"command", "request"}}) ));
+ mXpl->sendMessage(xPLMessagePtr( new xPLMessage(xPL_MESSAGE_COMMAND, "*", "config", "current", {{"command", "request"}}) ));
writeLog( "started, run mainloop", logLevel::all );
m_ioservice.run();
@@ -113,7 +119,6 @@
private:
static boost::asio::io_service m_ioservice;
- xPLMessageQueueClass *mXplMessageQueue;
xPLCacheClass *mXplCache;
DeviceManager mDeviceManager;
XHCPServer *mXHCPServer;
@@ -146,6 +151,20 @@
//vendorFileFolder = DataFileFolder / "vendors";
//ConfigFileFolder = DataFileFolder / "configs";
+ options_description desc("Allowed options");
+ desc.add_options()
+ ("help", "help message")
+ ("datadir","location of data directory");
+
+ variables_map vm;
+ store(parse_command_line(argc, argv, desc), vm);
+ notify(vm);
+
+ if (vm.count("help")) {
+ cout << desc << endl;
+ return 1;
+ }
+
signal(SIGINT, handle_signal);
signal(SIGTERM, handle_signal);
Modified: xPLHAL/branches/thomas_s_dev/src/xplhandler.cpp
===================================================================
--- xPLHAL/branches/thomas_s_dev/src/xplhandler.cpp 2012-02-19 12:22:04 UTC (rev 709)
+++ xPLHAL/branches/thomas_s_dev/src/xplhandler.cpp 2012-02-19 23:12:54 UTC (rev 710)
@@ -16,14 +16,15 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "xplhandler.h"
+#include "xplmessagequeue.h"
+
#include <boost/algorithm/string/replace.hpp>
using std::string;
#include "log.h"
-#include "xplhandler.h"
-#include "globals.h"
/** Handle a change to the logger service configuration */
/* static void configChangedHandler(xPL_ServicePtr theService, xPL_ObjectPtr userData) {
@@ -31,12 +32,14 @@
int xPLHandler::m_refcount = 0;
-xPLHandler::xPLHandler( const string& host_name)
+xPLHandler::xPLHandler(boost::asio::io_service& ioservice, const std::string& host_name)
: xPLService(0)
-, m_exit_thread(false)
, vendor( "CHRISM" )
, deviceID( "xplhalqt" )
, instanceID( host_name )
+, m_xplSocket(ioservice)
+, m_xplWriteSocket(ioservice)
+, mXplMessageQueue(new XplMessageQueue)
{
writeLog( "xPLHandler::xPLHandler( "+host_name+" )", logLevel::debug );
//xPL_setDebugging(TRUE);
@@ -54,7 +57,7 @@
writeLog("Unable to start xPL", logLevel::debug);
}
}
-
+
/* And a listener for all xPL messages */
xPL_addMessageListener( xpl_message_callback, this );
@@ -82,16 +85,17 @@
xPL_addServiceConfigChangedListener(loggerService, configChangedHandler, NULL);*/
//xPL_setServiceEnabled(loggerService, TRUE);
xPL_setServiceEnabled(xPLService, TRUE);
-
- m_thread = new boost::thread(boost::bind(&xPLHandler::run, this));
+
+ m_xplSocket.assign(boost::asio::ip::tcp::v4(), xPL_getFD());
+ m_xplWriteSocket.assign(boost::asio::ip::tcp::v4(), mXplMessageQueue->getFD());
+ startAsyncRead();
+ startAsyncWrite();
}
xPLHandler::~xPLHandler()
{
writeLog( "xPLHandler::~xPLHandler()", logLevel::debug );
- m_exit_thread = true;
- m_thread->join();
- delete m_thread;
+ m_xplSocket.close();
if (xPLService) {
xPL_releaseService(xPLService);
}
@@ -100,56 +104,30 @@
}
}
-void xPLHandler::run()
+void xPLHandler::sendBroadcastMessage( const string& msgClass, const string& msgType, const xPLMessage::namedValueList& namedValues )
{
- writeLog( "xPLHandler::run()", logLevel::debug );
- // writeLog( "xPLHandler::run() - ready", logLevel::debug );
-
- // Hand control over to xPLLib
- while( ! m_exit_thread )
- {
- // get exclusive access to xPLib
- //lock_guard locker( xPLLock );
-
- // send waiting messages
- while( xPL_MessagePtr theMessage = xPLMessageQueue->consume( xPLService ) )
- {
- writeLog("Found xPL message at " + lexical_cast<string>(theMessage)+ " to send...", logLevel::debug);
- if ( !xPL_sendMessage( theMessage ) )
- writeLog("Unable to send xPL message", logLevel::debug);
- else
- writeLog( "xPL Message sent...", logLevel::debug );
- }
-
- // handle messages - and return after 100 ms
- xPL_processMessages(100);
- }
-}
-
-void xPLHandler::sendBroadcastMessage( const string& msgClass, const string& msgType, const xPLMessage::namedValueList& namedValues ) const
-{
writeLog( "xPLHandler::sendBroadcastMessage( "+msgClass+", "+msgType+" )", logLevel::debug );
- xPLMessageQueue->add( xPLMessagePtr( new xPLMessage( xPL_MESSAGE_COMMAND, "*", "", "", msgClass, msgType, namedValues ) ) );
+ sendMessage( xPLMessagePtr( new xPLMessage( xPL_MESSAGE_COMMAND, "*", "", "", msgClass, msgType, namedValues ) ) );
}
void xPLHandler::sendMessage( const xPL_MessageType type, const string& tgtVendor, const string& tgtDeviceID,
const string& tgtInstanceID, const string& msgClass, const string& msgType,
- const xPLMessage::namedValueList& namedValues ) const
+ const xPLMessage::namedValueList& namedValues )
{
writeLog( "xPLHandler::sendMessage( "+lexical_cast<string>(type)+", "+tgtVendor+", "+tgtDeviceID+", "+tgtInstanceID+", "+msgClass+", "+msgType+" )", logLevel::debug );
- xPLMessageQueue->add( xPLMessagePtr( new xPLMessage( type, tgtVendor, tgtDeviceID, tgtInstanceID, msgClass, msgType, namedValues ) ) );
+ sendMessage( xPLMessagePtr( new xPLMessage( type, tgtVendor, tgtDeviceID, tgtInstanceID, msgClass, msgType, namedValues ) ) );
}
void xPLHandler::sendMessage( const xPL_MessageType type, const string& VDI,
const string& msgClass, const string& msgType,
- const xPLMessage::namedValueList& namedValues ) const
+ const xPLMessage::namedValueList& namedValues )
{
size_t marker1 = VDI.find( "-" );
size_t marker2 = VDI.find( "." );
string vendor = VDI.substr( 0, marker1 );
string device = VDI.substr( marker1+1, marker2 - (marker1+1) );
string instance = VDI.substr( marker2+1 );
- xPLMessageQueue->add( xPLMessagePtr( new xPLMessage( type, vendor, device, instance, msgClass, msgType, namedValues ) ) );
+ sendMessage( xPLMessagePtr( new xPLMessage( type, vendor, device, instance, msgClass, msgType, namedValues ) ) );
}
void xPLHandler::xpl_message_callback( xPL_MessagePtr theMessage, void *userValue )
@@ -196,3 +174,43 @@
m_sigRceivedXplMessage(msg);
}
+
+void xPLHandler::startAsyncRead()
+{
+ m_xplSocket.async_read_some(boost::asio::null_buffers(), boost::bind(&xPLHandler::handleReadableXplSocket, this, _1));
+}
+
+void xPLHandler::startAsyncWrite()
+{
+ m_xplWriteSocket.async_read_some(boost::asio::null_buffers(), boost::bind(&xPLHandler::handleReadableXplMessagequeue, this, _1));
+}
+
+void xPLHandler::handleReadableXplMessagequeue(boost::system::error_code ec)
+{
+ if (!ec) {
+ // send waiting messages
+ while( xPL_MessagePtr theMessage = mXplMessageQueue->consume( xPLService ) )
+ {
+ writeLog("Found xPL message at " + lexical_cast<string>(theMessage)+ " to send...", logLevel::debug);
+ if ( !xPL_sendMessage( theMessage ) )
+ writeLog("Unable to send xPL message", logLevel::debug);
+ else
+ writeLog( "xPL Message sent...", logLevel::debug );
+ }
+ startAsyncWrite();
+ }
+}
+
+void xPLHandler::handleReadableXplSocket(boost::system::error_code ec)
+{
+ if (!ec) {
+ // handle messages - and return
+ xPL_processMessages(0);
+ startAsyncRead();
+ }
+}
+
+void xPLHandler::sendMessage( const xPLMessagePtr& message )
+{
+ mXplMessageQueue->add(message);
+}
Modified: xPLHAL/branches/thomas_s_dev/src/xplhandler.h
===================================================================
--- xPLHAL/branches/thomas_s_dev/src/xplhandler.h 2012-02-19 12:22:04 UTC (rev 709)
+++ xPLHAL/branches/thomas_s_dev/src/xplhandler.h 2012-02-19 23:12:54 UTC (rev 710)
@@ -20,57 +20,61 @@
#include <vector>
#include <string>
-#include <boost/thread.hpp>
-#include <boost/thread/locks.hpp>
#include <boost/signals2/signal.hpp>
+#include <boost/asio.hpp>
+#include "xplmessage.h"
-// this is also including the xPL.h
-#include "xplmessagequeue.h"
+class XplMessageQueue;
/**
* \brief Handle all xPL communication.
*/
class xPLHandler
{
- /** \brief variable to ensure that the xPL library is only called at the same time... */
- //mutable boost::mutex xPLLock;
- //typedef boost::lock_guard<boost::mutex> lock_guard;
public:
typedef boost::signals2::signal<void (xPLMessagePtr)> signal_t;
public:
- xPLHandler( const std::string& host_name);
+ xPLHandler(boost::asio::io_service& ioservice, const std::string& host_name);
~xPLHandler();
void run();
+
+ void sendMessage( const xPLMessagePtr& message );
/** \brief Broadcast one message to the xPL network. */
- void sendBroadcastMessage( const std::string& msgClass, const std::string& msgType, const xPLMessage::namedValueList& namedValues ) const;
+ void sendBroadcastMessage( const std::string& msgClass, const std::string& msgType, const xPLMessage::namedValueList& namedValues );
/** \brief Send a directed message to the xPL network. */
void sendMessage( const xPL_MessageType type, const std::string& tgtVendor, const std::string& tgtDeviceID,
const std::string& tgtInstanceID, const std::string& msgClass, const std::string& msgType,
- const xPLMessage::namedValueList& namedValues ) const;
+ const xPLMessage::namedValueList& namedValues );
/** \brief Send a directed message to the xPL network. */
void sendMessage( const xPL_MessageType type, const std::string& VDI,
- const std::string& msgClass, const std::string& msgType, const xPLMessage::namedValueList& namedValues ) const;
+ const std::string& msgClass, const std::string& msgType, const xPLMessage::namedValueList& namedValues );
public:
signal_t m_sigRceivedXplMessage;
private:
+ void startAsyncRead();
+ void handleReadableXplSocket(boost::system::error_code ec);
+ void startAsyncWrite();
+ void handleReadableXplMessagequeue(boost::system::error_code ec);
+
/** \brief Handle an incomming xPL message. */
void handleXPLMessage( xPL_MessagePtr theMessage);
/** \brief Handle an incomming xPL message. */
static void xpl_message_callback( xPL_MessagePtr theMessage, xPL_ObjectPtr userValue );
- xPL_ServicePtr xPLService;
- std::string vendor;
- std::string deviceID;
- std::string instanceID;
- boost::thread* m_thread;
- static int m_refcount;
- bool m_exit_thread;
+ xPL_ServicePtr xPLService;
+ std::string vendor;
+ std::string deviceID;
+ std::string instanceID;
+ static int m_refcount;
+ boost::asio::ip::tcp::socket m_xplSocket;
+ boost::asio::ip::tcp::socket m_xplWriteSocket;
+ std::shared_ptr<XplMessageQueue> mXplMessageQueue;
};
Modified: xPLHAL/branches/thomas_s_dev/src/xplmessagequeue.cpp
===================================================================
--- xPLHAL/branches/thomas_s_dev/src/xplmessagequeue.cpp 2012-02-19 12:22:04 UTC (rev 709)
+++ xPLHAL/branches/thomas_s_dev/src/xplmessagequeue.cpp 2012-02-19 23:12:54 UTC (rev 710)
@@ -16,20 +16,40 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "xplmessagequeue.h"
#include "log.h"
-#include "xplmessagequeue.h"
+#include <unistd.h>
+
using std::mutex;
using std::lock_guard;
+
+XplMessageQueue::XplMessageQueue()
+:mPipeFD({0})
+{
+ pipe(mPipeFD);
+}
-void xPLMessageQueueClass::add( const xPLMessagePtr& message )
+XplMessageQueue::~XplMessageQueue()
{
- writeLog("xPLMessageQueueClass::add", logLevel::debug);
+ close(mPipeFD[0]);
+ close(mPipeFD[1]);
+}
+
+int XplMessageQueue::getFD() const
+{
+ return mPipeFD[0];
+}
+
+void XplMessageQueue::add( const xPLMessagePtr& message )
+{
+ writeLog("XplMessageQueue::add", logLevel::debug);
lock_guard<mutex> locker( queueLock ); // get exclusive access to the queue
xPLMessages.push( message );
+ write(mPipeFD[1], "1", 1);
}
-xPL_MessagePtr xPLMessageQueueClass::consume( const xPL_ServicePtr& service )
+xPL_MessagePtr XplMessageQueue::consume( const xPL_ServicePtr& service )
{
xPLMessagePtr message;
{
@@ -38,8 +58,10 @@
return 0;
message = xPLMessages.front(); // and release is as soon as possible
xPLMessages.pop();
+ char dummy[1];
+ read(mPipeFD[0], dummy, 1);
}
- writeLog("xPLMessageQueueClass::consume", logLevel::debug);
+ writeLog("XplMessageQueue::consume", logLevel::debug);
xPL_MessagePtr theMessage = 0;
if( "*" == message->vendor )
Modified: xPLHAL/branches/thomas_s_dev/src/xplmessagequeue.h
===================================================================
--- xPLHAL/branches/thomas_s_dev/src/xplmessagequeue.h 2012-02-19 12:22:04 UTC (rev 709)
+++ xPLHAL/branches/thomas_s_dev/src/xplmessagequeue.h 2012-02-19 23:12:54 UTC (rev 710)
@@ -27,20 +27,27 @@
/**
* Thread save store for xPL messages to send
*/
-class xPLMessageQueueClass
+class XplMessageQueue
{
- /** \brief variable to ensure that the queue is thread save... */
- mutable std::mutex queueLock;
- std::queue<xPLMessagePtr> xPLMessages;
+ public:
+ XplMessageQueue();
+ ~XplMessageQueue();
- public:
- /** \brief Add an message to the queue that'll be send on the next
- occasion and return a reference to fill it. */
- void add( const xPLMessagePtr& message );
+ int getFD() const;
- /** \brief Convert the next message to an xPL message and delete
- it from the queue. The caller has to ensure that the
- xPLLib is currently not called elsewhere, i.e. locked!
- \returns Returns 0 if no message available or the message. */
- xPL_MessagePtr consume( const xPL_ServicePtr& service );
+ /** \brief Add an message to the queue that'll be send on the next
+ occasion and return a reference to fill it. */
+ void add( const xPLMessagePtr& message );
+
+ /** \brief Convert the next message to an xPL message and delete
+ it from the queue. The caller has to ensure that the
+ xPLLib is currently not called elsewhere, i.e. locked!
+ \returns Returns 0 if no message available or the message. */
+ xPL_MessagePtr consume( const xPL_ServicePtr& service );
+ private:
+ /** \brief variable to ensure that the queue is thread save... */
+ mutable std::mutex queueLock;
+ std::queue<xPLMessagePtr> xPLMessages;
+ int mPipeFD[2];
};
+
Modified: xPLHAL/branches/thomas_s_dev/test/determinator1.xml
===================================================================
--- xPLHAL/branches/thomas_s_dev/test/determinator1.xml 2012-02-19 12:22:04 UTC (rev 709)
+++ xPLHAL/branches/thomas_s_dev/test/determinator1.xml 2012-02-19 23:12:54 UTC (rev 710)
@@ -13,6 +13,10 @@
<xplActionParam expression="level=30" />
<xplActionParam expression="fade-rate=30" />
</xplAction>
+ <logAction display_name="logAction"
+ logText="text to log"
+ executeOrder="nnn"
+ />
</output>
</determinator>
</xplDeterminator>
Added: xPLHAL/branches/thomas_s_dev/test/pugi.h
===================================================================
--- xPLHAL/branches/thomas_s_dev/test/pugi.h (rev 0)
+++ xPLHAL/branches/thomas_s_dev/test/pugi.h 2012-02-19 23:12:54 UTC (rev 710)
@@ -0,0 +1,183 @@
+#include <iostream>
+#include <pugixml.hpp>
+#include <string>
+#include <vector>
+//#include <boost/shared_ptr.hpp>
+#include <cxxabi.h>
+#include <typeinfo>
+#include <memory>
+#include <map>
+
+using std::string;
+using std::vector;
+
+
+class Determinator
+{
+ public:
+ enum class match_type { ALL, ANY };
+
+ string guid;
+ string name;
+ string description;
+ bool enabled;
+ match_type input_match_type;
+
+ vector<BaseConditionPtr> inputs;
+};
+
+
+void printDeterminator(const Determinator& d)
+{
+ std::cout << "Determinator '" << d.name << "'";
+ std::cout << "\n guid: " << d.guid;
+ std::cout << "\n name: " << d.name;
+ std::cout << "\n description: " << d.description;
+ std::cout << "\n enabled: " << d.enabled;
+
+ std::cout << "\n Inputs:\n";
+ for (auto input : d.inputs) {
+ std::cout << " " << input->toString() << std::endl;
+ }
+
+ std::cout << std::endl;
+}
+
+class DeterminatorXmlParser
+{
+ public:
+ DeterminatorXmlParser(const string& filename)
+ {
+ registerCondition(BaseConditionConstPtr(new XplCondition));
+ registerCondition(BaseConditionConstPtr(new GlobalCondition));
+ registerCondition(BaseConditionConstPtr(new GlobalChanged));
+ registerCondition(BaseConditionConstPtr(new DayCondition));
+ registerCondition(BaseConditionConstPtr(new TimeCondition));
+
+ pugi::xml_parse_result result = m_doc.load_file(filename.c_str());
+ std::cout << "Load result: " << result.description() << "\n";
+ }
+
+ void registerCondition(BaseConditionConstPtr condition) {
+ m_conditionmap[condition->condition_name] = condition;
+ }
+
+ void parse() {
+ try {
+ pugi::xml_node base = getNode(m_doc, "xplDeterminator");
+ pugi::xml_node base_d = getNode(base, "determinator");
+
+ bool isGroup = base_d.attribute("isGroup").value() == "Y";
+
+ if (isGroup == false) {
+ Determinator d;
+ d.guid = base_d.attribute("guid").value();
+ d.name = base_d.attribute("name").value();
+ d.description = base_d.attribute("description").value();
+ d.enabled = base_d.attribute("guid").value() == "Y";
+
+ pugi::xml_node input = base_d.child("input");
+
+ for(auto condition : m_conditionmap) {
+ pugi::xml_node action_node = input.child(condition.first.c_str());
+ if (action_node) {
+ d.inputs.push_back( BaseConditionPtr(condition.second->createNew(action_node)) );
+ }
+ }
+
+ printDeterminator(d);
+ }
+
+ }
+ catch(const std::exception& e) {
+ int status;
+ char* realname = abi::__cxa_demangle(typeid(e).name(), 0, 0, &status);
+ std::cout << "Exception: " << realname << " => " << e.what() << std::endl;
+ throw;
+ }
+
+ }
+
+
+ private:
+ pugi::xml_node getNode(const pugi::xml_node& base, const string& childname) {
+ pugi::xml_node node = base.child(childname.c_str());
+ if (!node) {
+ throw DeterminatorParseException("node '" + childname +"' not found");
+ }
+ return node;
+ }
+
+ pugi::xml_document m_doc;
+ std::map<string, std::shared_ptr<const BaseCondition>> m_conditionmap;
+};
+
+int main()
+{
+ DeterminatorXmlParser parser("determinatorDesc.xml");
+ parser.parse();
+
+ /*
+ try {
+ pugi::xml_document doc;
+ pugi::xml_parse_result result = doc.load_file("determinatorDesc.xml");
+
+ std::cout << "Load result: " << result.description() << "\n";
+
+ pugi::xml_node base = doc.child("xplDeterminator");
+ pugi::xml_node base_d = base.child("determinator");
+
+ bool isGroup = base_d.attribute("isGroup").value() == "Y";
+
+ if (isGroup == false) {
+ vector<string> actions = {"xplCondition", "globalCondition", "globalChanged", "dayCondition", "timeCondition"};
+
+ Determinator d;
+ d.guid = base_d.attribute("guid").value();
+ d.name = base_d.attribute("name").value();
+ d.description = base_d.attribute("description").value();
+ d.enabled = base_d.attribute("guid").value() == "Y";
+
+ pugi::xml_node input = base_d.child("input");
+
+ for(auto action : actions) {
+ pugi::xml_node action_node = input.child(action.c_str());
+ if (action_node) {
+ if (action == "globalCondition") {
+ d.inputs.push_back(DCPtr(new DeterminatorConditionGlobal(action_node)));
+ }
+ else if (action == "xplCondition") {
+ XplCondition xplcond(action_node);
+
+ }
+ }
+ }
+
+ printDeterminator(d);
+ }
+
+ }
+ catch(const std::exception& e) {
+ int status;
+ char* realname = abi::__cxa_demangle(typeid(e).name(), 0, 0, &status);
+ std::cout << "Exception: " << realname << " => " << e.what() << std::endl;
+ }
+ */
+
+
+}
+
+/*
+
+ <output>
+ <logAction display_name="display-name"
+ <xplAction display_name="action-name"
+ <globalAction
+ <delayAction
+ <stopAction
+ <suspendAction
+ <executeAction
+ <execRuleAction
+ <runScriptAction
+ </output>
+*/
Modified: xPLHAL/branches/thomas_s_dev/test/test_determinator.cpp
===================================================================
--- xPLHAL/branches/thomas_s_dev/test/test_determinator.cpp 2012-02-19 12:22:04 UTC (rev 709)
+++ xPLHAL/branches/thomas_s_dev/test/test_determinator.cpp 2012-02-19 23:12:54 UTC (rev 710)
@@ -121,4 +121,13 @@
}
}
+
+BOOST_AUTO_TEST_CASE( execute1 )
+{
+ DeterminatorXmlParser parser("determinator1.xml");
+ Determinator d(parser.parse());
+
+ d.execute();
+}
+
BOOST_AUTO_TEST_SUITE_END();
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|