Intialize new phosphor-time-manager

phosphor-time-manager will be refactored to use sdbusplus interfaces.
This is a initial commit that EpochBase is implemented based on dbus
interface xyz/openbmc_project/Time/EpochTime.interface.yaml.

EpochBase is the base class that wraps EpochTime interface, and is
initialized with time mode and owner from settingsd.

An initial unit test case is added.

Change-Id: Ic944b70f63ec3c0329762cc8874f0f57b09ddce3
Signed-off-by: Lei YU <mine260309@gmail.com>
diff --git a/epoch_base.cpp b/epoch_base.cpp
new file mode 100644
index 0000000..06232bb
--- /dev/null
+++ b/epoch_base.cpp
@@ -0,0 +1,131 @@
+#include "epoch_base.hpp"
+
+#include <phosphor-logging/log.hpp>
+
+#include <iomanip>
+#include <sstream>
+
+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";
+}
+
+namespace phosphor
+{
+namespace time
+{
+
+using namespace phosphor::logging;
+
+const std::map<std::string, EpochBase::Owner>
+EpochBase::ownerMap = {
+    { "BMC", EpochBase::Owner::BMC },
+    { "HOST", EpochBase::Owner::HOST },
+    { "SPLIT", EpochBase::Owner::SPLIT },
+    { "BOTH", EpochBase::Owner::BOTH },
+};
+
+EpochBase::EpochBase(sdbusplus::bus::bus& bus,
+                     const char* objPath)
+    : sdbusplus::server::object::object<EpochTime>(bus, objPath, true),
+      bus(bus)
+{
+    initialize();
+    // Deferred this until we could get our property correct
+    emit_object_added();
+}
+
+void EpochBase::setCurrentTimeMode(const std::string& mode)
+{
+    log<level::INFO>("Time mode is changed",
+                     entry("MODE=%s", mode.c_str()));
+    timeMode = convertToMode(mode);
+}
+
+void EpochBase::setCurrentTimeOwner(const std::string& owner)
+{
+    log<level::INFO>("Time owner is changed",
+                     entry("OWNER=%s", owner.c_str()));
+    timeOwner = convertToOwner(owner);
+}
+
+void EpochBase::initialize()
+{
+    setCurrentTimeMode(getSettings("time_mode"));
+    setCurrentTimeOwner(getSettings("time_owner"));
+    // TODO: subscribe settingsd's property changes callback
+}
+
+std::string EpochBase::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);
+    }
+
+    return mode.get<std::string>();
+}
+
+EpochBase::Mode EpochBase::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;
+    }
+}
+
+EpochBase::Owner EpochBase::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;
+}
+
+using namespace std::chrono;
+void EpochBase::setTime(const microseconds& usec)
+{
+    auto method = bus.new_method_call("org.freedesktop.timedate1",
+                                      "/org/freedesktop/timedate1",
+                                      "org.freedesktop.timedate1",
+                                      "SetTime");
+    method.append(static_cast<int64_t>(usec.count()),
+                  false, // relative
+                  false); // user_interaction
+    bus.call_noreply(method);
+}
+
+microseconds EpochBase::getTime() const
+{
+    auto now = system_clock::now();
+    return duration_cast<microseconds>
+           (now.time_since_epoch());
+}
+
+} // namespace time
+} // namespace phosphor