Add base support for BMC state management

This is the starting code needing to
build the application.  Still more to do,
this is just the layout for the additional
commits that will be done for the state
management.

Change-Id: Ief1dc96c84b34630e60ef40c99d4faf5b6f6e02e
Signed-off-by: Josh D. King <jdking@us.ibm.com>
diff --git a/xyz.openbmc_project.State.BMC.cpp b/xyz.openbmc_project.State.BMC.cpp
new file mode 100644
index 0000000..6495d52
--- /dev/null
+++ b/xyz.openbmc_project.State.BMC.cpp
@@ -0,0 +1,271 @@
+#include <algorithm>
+#include <sdbusplus/server.hpp>
+#include <sdbusplus/exception.hpp>
+#include <xyz/openbmc_project/State/BMC/server.hpp>
+
+namespace sdbusplus
+{
+namespace xyz
+{
+namespace openbmc_project
+{
+namespace State
+{
+namespace server
+{
+
+BMC::BMC(bus::bus& bus, const char* path)
+        : _xyz_openbmc_project_State_BMC_interface(
+                bus, path, _interface, _vtable, this)
+{
+}
+
+
+
+auto BMC::requestedBMCTransition() const ->
+        Transition
+{
+    return _requestedBMCTransition;
+}
+
+int BMC::_callback_get_RequestedBMCTransition(
+        sd_bus* bus, const char* path, const char* interface,
+        const char* property, sd_bus_message* reply, void* context,
+        sd_bus_error* error)
+{
+    using sdbusplus::server::binding::details::convertForMessage;
+
+    try
+    {
+        auto m = message::message(sd_bus_message_ref(reply));
+
+        auto o = static_cast<BMC*>(context);
+        m.append(convertForMessage(o->requestedBMCTransition()));
+    }
+    catch(sdbusplus::internal_exception_t& e)
+    {
+        sd_bus_error_set_const(error, e.name(), e.description());
+        return -EINVAL;
+    }
+
+    return true;
+}
+
+auto BMC::requestedBMCTransition(Transition value) ->
+        Transition
+{
+    if (_requestedBMCTransition != value)
+    {
+        _requestedBMCTransition = value;
+        _xyz_openbmc_project_State_BMC_interface.property_changed("RequestedBMCTransition");
+    }
+
+    return _requestedBMCTransition;
+}
+
+int BMC::_callback_set_RequestedBMCTransition(
+        sd_bus* bus, const char* path, const char* interface,
+        const char* property, sd_bus_message* value, void* context,
+        sd_bus_error* error)
+{
+    try
+    {
+        auto m = message::message(sd_bus_message_ref(value));
+
+        auto o = static_cast<BMC*>(context);
+
+        std::string v{};
+        m.read(v);
+        o->requestedBMCTransition(convertTransitionFromString(v));
+    }
+    catch(sdbusplus::internal_exception_t& e)
+    {
+        sd_bus_error_set_const(error, e.name(), e.description());
+        return -EINVAL;
+    }
+
+    return true;
+}
+
+namespace details
+{
+namespace BMC
+{
+static const auto _property_RequestedBMCTransition =
+    utility::tuple_to_array(message::types::type_id<
+            std::string>());
+}
+}
+auto BMC::currentBMCState() const ->
+        BMCState
+{
+    return _currentBMCState;
+}
+
+int BMC::_callback_get_CurrentBMCState(
+        sd_bus* bus, const char* path, const char* interface,
+        const char* property, sd_bus_message* reply, void* context,
+        sd_bus_error* error)
+{
+    using sdbusplus::server::binding::details::convertForMessage;
+
+    try
+    {
+        auto m = message::message(sd_bus_message_ref(reply));
+
+        auto o = static_cast<BMC*>(context);
+        m.append(convertForMessage(o->currentBMCState()));
+    }
+    catch(sdbusplus::internal_exception_t& e)
+    {
+        sd_bus_error_set_const(error, e.name(), e.description());
+        return -EINVAL;
+    }
+
+    return true;
+}
+
+auto BMC::currentBMCState(BMCState value) ->
+        BMCState
+{
+    if (_currentBMCState != value)
+    {
+        _currentBMCState = value;
+        _xyz_openbmc_project_State_BMC_interface.property_changed("CurrentBMCState");
+    }
+
+    return _currentBMCState;
+}
+
+int BMC::_callback_set_CurrentBMCState(
+        sd_bus* bus, const char* path, const char* interface,
+        const char* property, sd_bus_message* value, void* context,
+        sd_bus_error* error)
+{
+    try
+    {
+        auto m = message::message(sd_bus_message_ref(value));
+
+        auto o = static_cast<BMC*>(context);
+
+        std::string v{};
+        m.read(v);
+        o->currentBMCState(convertBMCStateFromString(v));
+    }
+    catch(sdbusplus::internal_exception_t& e)
+    {
+        sd_bus_error_set_const(error, e.name(), e.description());
+        return -EINVAL;
+    }
+
+    return true;
+}
+
+namespace details
+{
+namespace BMC
+{
+static const auto _property_CurrentBMCState =
+    utility::tuple_to_array(message::types::type_id<
+            std::string>());
+}
+}
+
+
+namespace
+{
+/** String to enum mapping for BMC::Transition */
+static const std::tuple<const char*, BMC::Transition> mappingBMCTransition[] =
+        {
+            std::make_tuple( "xyz.openbmc_project.State.BMC.Transition.Reboot",                 BMC::Transition::Reboot ),
+            std::make_tuple( "xyz.openbmc_project.State.BMC.Transition.None",                 BMC::Transition::None ),
+        };
+
+} // anonymous namespace
+
+auto BMC::convertTransitionFromString(std::string& s) ->
+        Transition
+{
+    auto i = std::find_if(
+            std::begin(mappingBMCTransition),
+            std::end(mappingBMCTransition),
+            [&s](auto& e){ return 0 == strcmp(s.c_str(), std::get<0>(e)); } );
+    if (std::end(mappingBMCTransition) == i)
+    {
+        throw sdbusplus::exception::InvalidEnumString();
+    }
+    else
+    {
+        return std::get<1>(*i);
+    }
+}
+
+std::string convertForMessage(BMC::Transition v)
+{
+    auto i = std::find_if(
+            std::begin(mappingBMCTransition),
+            std::end(mappingBMCTransition),
+            [v](auto& e){ return v == std::get<1>(e); });
+    return std::get<0>(*i);
+}
+
+namespace
+{
+/** String to enum mapping for BMC::BMCState */
+static const std::tuple<const char*, BMC::BMCState> mappingBMCBMCState[] =
+        {
+            std::make_tuple( "xyz.openbmc_project.State.BMC.BMCState.Ready",                 BMC::BMCState::Ready ),
+            std::make_tuple( "xyz.openbmc_project.State.BMC.BMCState.NotReady",                 BMC::BMCState::NotReady ),
+        };
+
+} // anonymous namespace
+
+auto BMC::convertBMCStateFromString(std::string& s) ->
+        BMCState
+{
+    auto i = std::find_if(
+            std::begin(mappingBMCBMCState),
+            std::end(mappingBMCBMCState),
+            [&s](auto& e){ return 0 == strcmp(s.c_str(), std::get<0>(e)); } );
+    if (std::end(mappingBMCBMCState) == i)
+    {
+        throw sdbusplus::exception::InvalidEnumString();
+    }
+    else
+    {
+        return std::get<1>(*i);
+    }
+}
+
+std::string convertForMessage(BMC::BMCState v)
+{
+    auto i = std::find_if(
+            std::begin(mappingBMCBMCState),
+            std::end(mappingBMCBMCState),
+            [v](auto& e){ return v == std::get<1>(e); });
+    return std::get<0>(*i);
+}
+
+const vtable::vtable_t BMC::_vtable[] = {
+    vtable::start(),
+    vtable::property("RequestedBMCTransition",
+                     details::BMC::_property_RequestedBMCTransition
+                        .data(),
+                     _callback_get_RequestedBMCTransition,
+                     _callback_set_RequestedBMCTransition,
+                     vtable::property_::emits_change),
+    vtable::property("CurrentBMCState",
+                     details::BMC::_property_CurrentBMCState
+                        .data(),
+                     _callback_get_CurrentBMCState,
+                     _callback_set_CurrentBMCState,
+                     vtable::property_::emits_change),
+    vtable::end()
+};
+
+} // namespace server
+} // namespace State
+} // namespace openbmc_project
+} // namespace xyz
+} // namespace sdbusplus
+