incremental
diff --git a/boost-dbus/CMakeLists.txt b/boost-dbus/CMakeLists.txt
index 9d07a5b..736d030 100644
--- a/boost-dbus/CMakeLists.txt
+++ b/boost-dbus/CMakeLists.txt
@@ -20,7 +20,11 @@
###############
# import Boost
+add_definitions(-DBOOST_ERROR_CODE_HEADER_ONLY)
+add_definitions(-DBOOST_SYSTEM_NO_DEPRECATED)
+add_definitions(-DBOOST_ALL_NO_LIB)
find_package(Boost REQUIRED)
+
include_directories(${Boost_INCLUDE_DIRS})
link_directories(${Boost_LIBRARY_DIRS})
diff --git a/boost-dbus/include/dbus/element.hpp b/boost-dbus/include/dbus/element.hpp
index 276b593..32cdcdc 100644
--- a/boost-dbus/include/dbus/element.hpp
+++ b/boost-dbus/include/dbus/element.hpp
@@ -8,7 +8,9 @@
#include <dbus/dbus.h>
#include <string>
+#include <vector>
#include <boost/cstdint.hpp>
+#include <boost/variant.hpp>
namespace dbus {
@@ -31,6 +33,11 @@
// unix_fd
typedef std::string string;
+
+typedef boost::variant<std::string, bool, byte, int16, uint16, int32, uint32, int64,
+ uint64, double>
+ dbus_variant;
+
struct object_path {
string value;
};
@@ -97,6 +104,16 @@
static const int code = DBUS_TYPE_STRING;
};
+template <typename Element>
+struct element<std::vector<Element>> {
+ static const int code = DBUS_TYPE_ARRAY;
+};
+
+template <>
+struct element<dbus_variant> {
+ static const int code = DBUS_TYPE_VARIANT;
+};
+
template <>
struct element<object_path> {
static const int code = DBUS_TYPE_OBJECT_PATH;
diff --git a/boost-dbus/include/dbus/impl/message_iterator.hpp b/boost-dbus/include/dbus/impl/message_iterator.hpp
index 44bcf2e..6969b8b 100644
--- a/boost-dbus/include/dbus/impl/message_iterator.hpp
+++ b/boost-dbus/include/dbus/impl/message_iterator.hpp
@@ -34,7 +34,8 @@
bool next();
bool has_next();
- int get_arg_type();
+ char get_arg_type();
+ int get_element_count();
void get_basic(void *value);
diff --git a/boost-dbus/include/dbus/impl/message_iterator.ipp b/boost-dbus/include/dbus/impl/message_iterator.ipp
index eb2584f..034f658 100644
--- a/boost-dbus/include/dbus/impl/message_iterator.ipp
+++ b/boost-dbus/include/dbus/impl/message_iterator.ipp
@@ -58,7 +58,12 @@
return dbus_message_iter_has_next(&DBusMessageIter_);
}
-inline int message_iterator::get_arg_type()
+inline int message_iterator::get_element_count()
+{
+ return dbus_message_iter_get_element_count(&DBusMessageIter_);
+}
+
+inline char message_iterator::get_arg_type()
{
return dbus_message_iter_get_arg_type(&DBusMessageIter_);
}
diff --git a/boost-dbus/include/dbus/message.hpp b/boost-dbus/include/dbus/message.hpp
index aa5e89c..695e1fc 100644
--- a/boost-dbus/include/dbus/message.hpp
+++ b/boost-dbus/include/dbus/message.hpp
@@ -104,6 +104,7 @@
struct packer {
impl::message_iterator iter_;
packer(message& m) { impl::message_iterator::init_append(m, iter_); }
+ packer(){};
template <typename Element>
packer& pack(const Element& e) {
return *this << e;
@@ -112,6 +113,7 @@
struct unpacker {
impl::message_iterator iter_;
unpacker(message& m) { impl::message_iterator::init(m, iter_); }
+ unpacker() {}
template <typename Element>
unpacker& unpack(Element& e) {
@@ -147,16 +149,106 @@
return p;
}
+template <typename Key, typename Value>
+message::packer& operator<<(message::packer& p,
+ const std::vector<std::pair<Key, Value>>& v) {
+ message::packer sub;
+ char signature[] = {'{', element<Key>::code, element<Value>::code, '}', 0};
+
+ p.iter_.open_container(DBUS_TYPE_ARRAY, signature, sub.iter_);
+ for (auto& element : v) {
+ sub << element;
+ }
+
+ p.iter_.close_container(sub.iter_);
+ return p;
+}
+
+template <typename Element>
+message::packer& operator<<(message::packer& p, const std::vector<Element>& v) {
+ message::packer sub;
+ char signature[] = {element<Element>::code, 0};
+ p.iter_.open_container(element<std::vector<Element>>::code, signature,
+ sub.iter_);
+ for (auto& element : v) {
+ sub << element;
+ }
+
+ p.iter_.close_container(sub.iter_);
+ return p;
+}
+
inline message::packer& operator<<(message::packer& p, const char* c) {
p.iter_.append_basic(element<string>::code, &c);
return p;
}
+template <typename Key, typename Value>
+inline message::packer& operator<<(message::packer& p,
+ const std::pair<Key, Value> element) {
+ message::packer dict_entry;
+ p.iter_.open_container(DBUS_TYPE_DICT_ENTRY, NULL, dict_entry.iter_);
+ dict_entry << element.first;
+ dict_entry << element.second;
+ p.iter_.close_container(dict_entry.iter_);
+ return p;
+}
+
inline message::packer& operator<<(message::packer& p, const string& e) {
const char* c = e.c_str();
return p << c;
}
+inline message::packer& operator<<(message::packer& p, const dbus_variant& v) {
+ message::packer sub;
+ char type = 0;
+ // TODO(ed) there must be a better (more typesafe) way to do this
+ switch (v.which()) {
+ case 0:
+ type = element<std::string>::code;
+ break;
+ case 1:
+ type = element<bool>::code;
+ break;
+ case 2:
+ type = element<byte>::code;
+ break;
+ case 3:
+ type = element<int16>::code;
+ break;
+ case 4:
+ type = element<uint16>::code;
+ break;
+ case 5:
+ type = element<int32>::code;
+ break;
+ case 6:
+ type = element<uint32>::code;
+ break;
+ case 7:
+ type = element<int64>::code;
+ break;
+ case 8:
+ type = element<uint64>::code;
+ break;
+ case 9:
+ type = element<double>::code;
+ break;
+
+ default:
+ // TODO(ed) throw exception
+ break;
+ }
+ char signature[] = {type, 0};
+
+ p.iter_.open_container(element<dbus_variant>::code, signature, sub.iter_);
+ boost::apply_visitor([&](auto val) { sub << val; }, v);
+ // sub << element;
+ p.iter_.close_container(sub.iter_);
+
+ return p;
+}
+
template <typename Element>
message::unpacker operator>>(message m, Element& e) {
return message::unpacker(m).unpack(e);
@@ -178,32 +270,98 @@
return u;
}
+inline message::unpacker& operator>>(message::unpacker& u, dbus_variant& v) {
+ message::unpacker sub;
+ u.iter_.recurse(sub.iter_);
+
+ auto arg_type = sub.iter_.get_arg_type();
+ // sub.iter_.get_basic(&c);
+ // Todo(ed) find a better way to do this lookup table
+ switch (arg_type) {
+ case element<std::string>::code: {
+ std::string s;
+ sub >> s;
+ v = s;
+ } break;
+ case element<bool>::code: {
+ bool b;
+ sub >> b;
+ v = b;
+ } break;
+ case element<byte>::code: {
+ byte b;
+ sub >> b;
+ v = b;
+ } break;
+ case element<int16>::code: {
+ int16 b;
+ sub >> b;
+ v = b;
+ } break;
+ case element<uint16>::code: {
+ uint16 b;
+ sub >> b;
+ v = b;
+ } break;
+ case element<int32>::code: {
+ int32 b;
+ sub >> b;
+ v = b;
+ } break;
+ case element<uint32>::code: {
+ uint32 b;
+ sub >> b;
+ v = b;
+ } break;
+ case element<int64>::code: {
+ int64 b;
+ sub >> b;
+ v = b;
+ } break;
+ case element<uint64>::code: {
+ uint64 b;
+ sub >> b;
+ v = b;
+ } break;
+ case element<double>::code: {
+ double b;
+ sub >> b;
+ v = b;
+ } break;
+
+ default:
+ // TODO(ed) throw exception
+ break;
+ }
+ u.iter_.next();
+ return u;
+}
+
+template <typename Key, typename Value>
+inline message::unpacker& operator>>(message::unpacker& u,
+ std::pair<Key, Value>& v) {
+ message::unpacker sub;
+ u.iter_.recurse(sub.iter_);
+ sub >> v.first;
+ sub >> v.second;
+
+ u.iter_.next();
+ return u;
+}
+
template <typename Element>
inline message::unpacker& operator>>(message::unpacker& u,
std::vector<Element>& s) {
- static_assert(std::is_same<Element, std::string>::value,
- "only std::vector<std::string> is implemented for now");
- impl::message_iterator sub;
- u.iter_.recurse(sub);
+ message::unpacker sub;
- const char* c;
- while (sub.has_next()) {
- sub.get_basic(&c);
- s.emplace_back(c);
- sub.next();
- }
-
- // TODO(ed)
- // Make this generic for all types. The below code is close, but there's
- // template issues and things I don't understand;
- /*
- auto e = message::unpacker(sub);
- while (sub.has_next()) {
+ u.iter_.recurse(sub.iter_);
+ auto arg_type = sub.iter_.get_arg_type();
+ while (arg_type != DBUS_TYPE_INVALID) {
s.emplace_back();
- Element& element = s.back();
- e.unpack(element);
+ sub >> s.back();
+ arg_type = sub.iter_.get_arg_type();
}
-*/
+ u.iter_.next();
return u;
}
diff --git a/boost-dbus/test/avahi.cpp b/boost-dbus/test/avahi.cpp
index debbff3..8cbb82f 100644
--- a/boost-dbus/test/avahi.cpp
+++ b/boost-dbus/test/avahi.cpp
@@ -150,27 +150,114 @@
}
}
-TEST(BOOST_DBUS, ListObjects) {
+TEST(BOOST_DBUS, SingleSensorChanged) {
boost::asio::io_service io;
dbus::connection system_bus(io, dbus::bus::system);
- dbus::endpoint test_daemon("org.freedesktop.DBus", "/",
- "org.freedesktop.DBus");
+ dbus::match ma(system_bus,
+ "type='signal',path_namespace='/xyz/openbmc_project/sensors'");
+ dbus::filter f(system_bus, [](dbus::message& m) {
+ auto member = m.get_member();
+ return member == "PropertiesChanged";
+ });
- // create new service browser
- dbus::message m = dbus::message::new_call(test_daemon, "ListNames");
- auto r = system_bus.send(m);
+ // std::function<void(boost::system::error_code, dbus::message)> event_handler
+ // =
- std::vector<std::string> services;
- r.unpack(services);
- // todo(ed) find out why this needs to be static
- static std::atomic<int> dbus_count(0);
- std::cout << dbus_count << " Callers\n";
- auto names = std::make_shared<std::vector<std::string>>();
- for (auto& service : services) {
- std::string name = "/";
- query_interfaces(system_bus, service, name);
- }
+ f.async_dispatch([&](boost::system::error_code ec, dbus::message s) {
+ std::string object_name;
+ EXPECT_EQ(s.get_path(),
+ "/xyz/openbmc_project/sensors/temperature/LR_Brd_Temp");
+
+ std::vector<std::pair<std::string, dbus::dbus_variant>> values;
+ s.unpack(object_name).unpack(values);
+
+ EXPECT_EQ(object_name, "xyz.openbmc_project.Sensor.Value");
+
+ EXPECT_EQ(values.size(), 1);
+ auto expected = std::pair<std::string, dbus::dbus_variant>("Value", 42);
+ EXPECT_EQ(values[0], expected);
+
+ io.stop();
+ });
+
+ dbus::endpoint test_endpoint(
+ "org.freedesktop.Avahi",
+ "/xyz/openbmc_project/sensors/temperature/LR_Brd_Temp",
+ "org.freedesktop.DBus.Properties");
+
+ auto signal_name = std::string("PropertiesChanged");
+ auto m = dbus::message::new_signal(test_endpoint, signal_name);
+
+ m.pack("xyz.openbmc_project.Sensor.Value");
+
+ std::vector<std::pair<std::string, dbus::dbus_variant>> map2;
+
+ map2.emplace_back("Value", 42);
+
+ m.pack(map2);
+
+ auto removed = std::vector<uint32_t>();
+ m.pack(removed);
+ system_bus.async_send(m,
+ [&](boost::system::error_code ec, dbus::message s) {});
io.run();
}
+
+TEST(BOOST_DBUS, MultipleSensorChanged) {
+ boost::asio::io_service io;
+ dbus::connection system_bus(io, dbus::bus::system);
+
+ dbus::match ma(system_bus,
+ "type='signal',path_namespace='/xyz/openbmc_project/sensors'");
+ dbus::filter f(system_bus, [](dbus::message& m) {
+ auto member = m.get_member();
+ return member == "PropertiesChanged";
+ });
+
+ int count = 0;
+ f.async_dispatch([&](boost::system::error_code ec, dbus::message s) {
+ std::string object_name;
+ EXPECT_EQ(s.get_path(),
+ "/xyz/openbmc_project/sensors/temperature/LR_Brd_Temp");
+
+ std::vector<std::pair<std::string, dbus::dbus_variant>> values;
+ s.unpack(object_name).unpack(values);
+
+ EXPECT_EQ(object_name, "xyz.openbmc_project.Sensor.Value");
+
+ EXPECT_EQ(values.size(), 1);
+ auto expected = std::pair<std::string, dbus::dbus_variant>("Value", 42);
+ EXPECT_EQ(values[0], expected);
+ count++;
+ if (count == 2) {
+ io.stop();
+ }
+
+ });
+
+ dbus::endpoint test_endpoint(
+ "org.freedesktop.Avahi",
+ "/xyz/openbmc_project/sensors/temperature/LR_Brd_Temp",
+ "org.freedesktop.DBus.Properties");
+
+ auto signal_name = std::string("PropertiesChanged");
+ auto m = dbus::message::new_signal(test_endpoint, signal_name);
+
+ m.pack("xyz.openbmc_project.Sensor.Value");
+
+ std::vector<std::pair<std::string, dbus::dbus_variant>> map2;
+
+ map2.emplace_back("Value", 42);
+
+ m.pack(map2);
+
+ auto removed = std::vector<uint32_t>();
+ m.pack(removed);
+ system_bus.async_send(m,
+ [&](boost::system::error_code ec, dbus::message s) {});
+ system_bus.async_send(m,
+ [&](boost::system::error_code ec, dbus::message s) {});
+ io.run();
+}
\ No newline at end of file
diff --git a/boost-dbus/test/message.cpp b/boost-dbus/test/message.cpp
index d591f61..8c8169f 100644
--- a/boost-dbus/test/message.cpp
+++ b/boost-dbus/test/message.cpp
@@ -3,9 +3,9 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-#include <dbus/error.hpp>
#include <dbus/connection.hpp>
#include <dbus/endpoint.hpp>
+#include <dbus/error.hpp>
#include <dbus/filter.hpp>
#include <dbus/match.hpp>
#include <dbus/message.hpp>
@@ -35,6 +35,21 @@
// m.get_sender();
}
+TEST(MessageTest, Misc) {
+ auto signal_name = std::string("PropertiesChanged");
+ dbus::endpoint test_endpoint(
+ "org.freedesktop.Avahi",
+ "/xyz/openbmc_project/sensors/temperature/LR_Brd_Temp",
+ "org.freedesktop.DBus.Properties");
+ auto m = dbus::message::new_signal(test_endpoint, signal_name);
+
+ dbus::dbus_variant v(std::string("hello world"));
+ m.pack(v);
+
+ std::vector<dbus::dbus_variant> av{{std::string("hello world"), 1, 42}};
+ m.pack(av);
+}
+
// I actually don't know what to do with these yet.
/*
TEST(MessageTest, ErrorMessage)