Add time Manager to handle property changes callback
1. Implement time::Manager who registers property change signal for time
mode and owner;
2. Add PropertyChangeListner interface to handle the callback;
3. Make EpochBase to implement the interface.
Change-Id: I185580ae37353e1ed82a47e4905fb22e269ac09d
Signed-off-by: Lei YU <mine260309@gmail.com>
diff --git a/manager.cpp b/manager.cpp
new file mode 100644
index 0000000..c4732f4
--- /dev/null
+++ b/manager.cpp
@@ -0,0 +1,179 @@
+#include "manager.hpp"
+
+#include <phosphor-logging/log.hpp>
+
+namespace rules = sdbusplus::bus::match::rules;
+
+namespace // anonymous
+{
+constexpr auto SETTINGS_SERVICE = "org.openbmc.settings.Host";
+constexpr auto SETTINGS_PATH = "/org/openbmc/settings/host0";
+constexpr auto SETTINGS_INTERFACE = "org.openbmc.settings.Host";
+constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties";
+constexpr auto METHOD_GET = "Get";
+
+constexpr auto PROPERTY_TIME_MODE = "time_mode";
+constexpr auto PROPERTY_TIME_OWNER = "time_owner";
+
+// TODO: Use new settings in xyz.openbmc_project
+const auto MATCH_PROPERTY_CHANGE =
+ rules::type::signal() +
+ rules::member("PropertiesChanged") +
+ rules::path("/org/openbmc/settings/host0") +
+ rules::interface("org.freedesktop.DBus.Properties");
+
+}
+
+namespace phosphor
+{
+namespace time
+{
+
+using namespace phosphor::logging;
+
+const std::set<std::string>
+Manager::managedProperties = {PROPERTY_TIME_MODE, PROPERTY_TIME_OWNER};
+
+const std::map<std::string, Owner> Manager::ownerMap =
+{
+ { "BMC", Owner::BMC },
+ { "HOST", Owner::HOST },
+ { "SPLIT", Owner::SPLIT },
+ { "BOTH", Owner::BOTH },
+};
+
+Manager::Manager(sdbusplus::bus::bus& bus)
+ : bus(bus),
+ propertyChangeMatch(bus, MATCH_PROPERTY_CHANGE, onPropertyChanged, this)
+{
+ setCurrentTimeMode(getSettings(PROPERTY_TIME_MODE));
+ setCurrentTimeOwner(getSettings(PROPERTY_TIME_OWNER));
+}
+
+void Manager::addListener(PropertyChangeListner* listener)
+{
+ // Notify listener about the initial value
+ listener->onModeChanged(timeMode);
+ listener->onOwnerChanged(timeOwner);
+
+ listeners.insert(listener);
+}
+
+void Manager::onPropertyChanged(const std::string& key,
+ const std::string& value)
+{
+ // TODO: Check pgood
+ // If it's off, notify listners;
+ // If it's on, hold the values and store in persistent storage.
+ // And when pgood turns back to off, notify the listners.
+
+ // TODO: Check dhcp_ntp
+
+ if (key == PROPERTY_TIME_MODE)
+ {
+ setCurrentTimeMode(value);
+ for (const auto& listener : listeners)
+ {
+ listener->onModeChanged(timeMode);
+ }
+ }
+ else if (key == PROPERTY_TIME_OWNER)
+ {
+ setCurrentTimeOwner(value);
+ for (const auto& listener : listeners)
+ {
+ listener->onOwnerChanged(timeOwner);
+ }
+ }
+}
+
+int Manager::onPropertyChanged(sd_bus_message* msg,
+ void* userData,
+ sd_bus_error* retError)
+{
+ using properties = std::map < std::string,
+ sdbusplus::message::variant<int, std::string >>;
+ auto m = sdbusplus::message::message(msg);
+ // message type: sa{sv}as
+ std::string ignore;
+ properties props;
+ m.read(ignore, props);
+ for (const auto& item : props)
+ {
+ if (managedProperties.find(item.first) != managedProperties.end())
+ {
+ static_cast<Manager*>(userData)
+ ->onPropertyChanged(item.first, item.second.get<std::string>());
+ }
+ }
+ return 0;
+}
+
+
+void Manager::setCurrentTimeMode(const std::string& mode)
+{
+ log<level::INFO>("Time mode is changed",
+ entry("MODE=%s", mode.c_str()));
+ timeMode = convertToMode(mode);
+}
+
+void Manager::setCurrentTimeOwner(const std::string& owner)
+{
+ log<level::INFO>("Time owner is changed",
+ entry("OWNER=%s", owner.c_str()));
+ timeOwner = convertToOwner(owner);
+}
+
+std::string Manager::getSettings(const char* value) const
+{
+ sdbusplus::message::variant<std::string> mode;
+ auto method = bus.new_method_call(SETTINGS_SERVICE,
+ SETTINGS_PATH,
+ PROPERTY_INTERFACE,
+ METHOD_GET);
+ method.append(SETTINGS_INTERFACE, value);
+ auto reply = bus.call(method);
+ if (reply)
+ {
+ reply.read(mode);
+ }
+ else
+ {
+ log<level::ERR>("Failed to get settings");
+ }
+
+ return mode.get<std::string>();
+}
+
+Mode Manager::convertToMode(const std::string& mode)
+{
+ if (mode == "NTP")
+ {
+ return Mode::NTP;
+ }
+ else if (mode == "MANUAL")
+ {
+ return Mode::MANUAL;
+ }
+ else
+ {
+ log<level::ERR>("Unrecognized mode",
+ entry("%s", mode.c_str()));
+ return Mode::NTP;
+ }
+}
+
+Owner Manager::convertToOwner(const std::string& owner)
+{
+ auto it = ownerMap.find(owner);
+ if (it == ownerMap.end())
+ {
+ log<level::ERR>("Unrecognized owner",
+ entry("%s", owner.c_str()));
+ return Owner::BMC;
+ }
+ return it->second;
+}
+
+}
+}