Initial chassis state management code

This is just the basics to get the generated code
compiling and to verify the basic dbus interfaces.

Change-Id: I335964da456d8173e2ce792c6614770da43303b4
Signed-off-by: Andrew Geissler <andrewg@us.ibm.com>
diff --git a/.gitignore b/.gitignore
index 8954d29..709ac69 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,6 +42,7 @@
 /config.log
 /config.status
 /op-host-state-manager
+/op-chassis-state-manager
 Makefile
 .deps
-arm-openbmc-linux-gnueabi-libtool
+*-libtool
diff --git a/Makefile.am b/Makefile.am
index 9a2ba2f..479df05 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,11 +1,18 @@
 AM_DEFAULT_SOURCE_EXT = .cpp
 
 sbin_PROGRAMS = \
-	op-host-state-manager
+	op-host-state-manager \
+	op-chassis-state-manager
 
 op_host_state_manager_SOURCES = \
 	host_state_manager.cpp \
 	xyz.openbmc_project.State.Host.cpp \
 	host_state_manager_main.cpp
 
-op_host_state_manager_LDFLAGS = $(SYSTEMD_LIBS)
\ No newline at end of file
+op_chassis_state_manager_SOURCES = \
+	chassis_state_manager.cpp \
+	xyz.openbmc_project.State.Chassis.cpp \
+	chassis_state_manager_main.cpp
+
+op_host_state_manager_LDFLAGS = $(SYSTEMD_LIBS)
+op_chassis_state_manager_LDFLAGS = $(SYSTEMD_LIBS)
\ No newline at end of file
diff --git a/chassis_state_manager.cpp b/chassis_state_manager.cpp
new file mode 100644
index 0000000..c146087
--- /dev/null
+++ b/chassis_state_manager.cpp
@@ -0,0 +1,35 @@
+#include <log.hpp>
+#include "chassis_state_manager.hpp"
+
+namespace phosphor
+{
+namespace state
+{
+namespace manager
+{
+
+// When you see server:: you know we're referencing our base class
+namespace server = sdbusplus::xyz::openbmc_project::State::server;
+
+using namespace phosphor::logging;
+
+Chassis::Transition Chassis::requestedPowerTransition(Transition value)
+{
+
+    log<level::INFO>("Change to Chassis Requested Power State",
+                     entry("CHASSIS_REQUESTED_POWER_STATE=%s",
+                           convertForMessage(value).c_str()));
+    return server::Chassis::requestedPowerTransition(value);
+}
+
+Chassis::PowerState Chassis::currentPowerState(PowerState value)
+{
+    log<level::INFO>("Change to Chassis Power State",
+                     entry("CHASSIS_CURRENT_POWER_STATE=%s",
+                           convertForMessage(value).c_str()));
+    return server::Chassis::currentPowerState(value);
+}
+
+} // namespace manager
+} // namespace state
+} // namepsace phosphor
diff --git a/chassis_state_manager.hpp b/chassis_state_manager.hpp
new file mode 100644
index 0000000..f3df078
--- /dev/null
+++ b/chassis_state_manager.hpp
@@ -0,0 +1,50 @@
+#pragma once
+
+#include <sdbusplus/bus.hpp>
+#include "xyz/openbmc_project/State/Chassis/server.hpp"
+
+namespace phosphor
+{
+namespace state
+{
+namespace manager
+{
+
+/** @class Chassis
+ *  @brief OpenBMC chassis state management implementation.
+ *  @details A concrete implementation for xyz.openbmc_project.State.Chassis
+ *  DBus API.
+ */
+class Chassis : public sdbusplus::server::object::object<
+                sdbusplus::xyz::openbmc_project::State::server::Chassis>
+{
+    public:
+        /** @brief Constructs Chassis State Manager
+         *
+         * @param[in] bus       - The Dbus bus object
+         * @param[in] busName   - The Dbus name to own
+         * @param[in] objPath   - The Dbus object path
+         */
+        Chassis(sdbusplus::bus::bus& bus,
+                const char* busName,
+                const char* objPath) :
+                sdbusplus::server::object::object<
+                    sdbusplus::xyz::openbmc_project::State::server::Chassis>(
+                            bus, objPath),
+                bus(bus)
+        {}
+
+        /** @brief Set value of RequestedPowerTransition */
+        Transition requestedPowerTransition(Transition value) override;
+
+        /** @brief Set value of CurrentPowerState */
+        PowerState currentPowerState(PowerState value) override;
+
+    private:
+        /** @brief Persistent sdbusplus DBus connection. */
+        sdbusplus::bus::bus& bus;
+};
+
+} // namespace manager
+} // namespace state
+} // namespace phosphor
diff --git a/chassis_state_manager_main.cpp b/chassis_state_manager_main.cpp
new file mode 100644
index 0000000..27965e0
--- /dev/null
+++ b/chassis_state_manager_main.cpp
@@ -0,0 +1,32 @@
+#include <cstdlib>
+#include <iostream>
+#include <exception>
+#include <sdbusplus/bus.hpp>
+#include "config.h"
+#include "chassis_state_manager.hpp"
+
+
+int main(int argc, char *argv[])
+{
+    auto bus = sdbusplus::bus::new_default();
+
+    // For now, we only have one instance of the chassis
+    auto objPathInst = std::string{CHASSIS_OBJPATH} + '0';
+
+    // Add sdbusplus ObjectManager.
+    sdbusplus::server::manager::manager objManager(bus, objPathInst.c_str());
+
+    phosphor::state::manager::Chassis manager(bus,
+                                              CHASSIS_BUSNAME,
+                                              objPathInst.c_str());
+
+    bus.request_name(CHASSIS_BUSNAME);
+
+    while(true)
+    {
+        bus.process_discard();
+        bus.wait();
+    }
+
+    return 0;
+}
diff --git a/configure.ac b/configure.ac
index 24b0899..0c4f8a8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -17,19 +17,26 @@
 AX_CXX_COMPILE_STDCXX_14([noext])
 AX_APPEND_COMPILE_FLAGS([-Wall -Werror], [CXXFLAGS])
 
-AC_ARG_VAR(BUSNAME, [The Dbus busname to own])
-AS_IF([test "x$BUSNAME" == "x"], [BUSNAME="xyz.openbmc_project.State.Host"])
-AC_DEFINE_UNQUOTED([BUSNAME], ["$BUSNAME"], [The DBus busname to own])
+AC_ARG_VAR(HOST_BUSNAME, [The Host Dbus busname to own])
+AS_IF([test "x$HOST_BUSNAME" == "x"], [HOST_BUSNAME="xyz.openbmc_project.State.Host"])
+AC_DEFINE_UNQUOTED([HOST_BUSNAME], ["$HOST_BUSNAME"], [The Host DBus busname to own])
 
-AC_ARG_VAR(OBJPATH, [The host state manager Dbus root])
-AS_IF([test "x$OBJPATH" == "x"], [OBJPATH="/xyz/openbmc_project/state/host"])
-AC_DEFINE_UNQUOTED([OBJPATH], ["$OBJPATH"], [The host state manager Dbus root])
+AC_ARG_VAR(HOST_OBJPATH, [The host state manager Dbus root])
+AS_IF([test "x$HOST_OBJPATH" == "x"], [HOST_OBJPATH="/xyz/openbmc_project/state/host"])
+AC_DEFINE_UNQUOTED([HOST_OBJPATH], ["$HOST_OBJPATH"], [The host state manager Dbus root])
+
+AC_ARG_VAR(CHASSIS_BUSNAME, [The Chassis Dbus busname to own])
+AS_IF([test "x$CHASSIS_BUSNAME" == "x"], [CHASSIS_BUSNAME="xyz.openbmc_project.State.Chassis"])
+AC_DEFINE_UNQUOTED([CHASSIS_BUSNAME], ["$CHASSIS_BUSNAME"], [The Chassis DBus busname to own])
+
+AC_ARG_VAR(CHASSIS_OBJPATH, [The chassis state manager Dbus root])
+AS_IF([test "x$CHASSIS_OBJPATH" == "x"], [CHASSIS_OBJPATH="/xyz/openbmc_project/state/chassis"])
+AC_DEFINE_UNQUOTED([CHASSIS_OBJPATH], ["$CHASSIS_OBJPATH"], [The chassis state manager Dbus root])
 
 # Check for header files.
 AC_CHECK_HEADER(systemd/sd-bus.h, ,[AC_MSG_ERROR([Could not find systemd/sd-bus.h...systemd developement package required])])
 AC_CHECK_HEADER(sdbusplus/server.hpp, ,[AC_MSG_ERROR([Could not find sdbusplus/server.hpp...openbmc/sdbusplus package required])])
 AC_CHECK_HEADER(log.hpp, ,[AC_MSG_ERROR([Could not find log.hpp...openbmc/phosphor-logging package required])])
 
-
 AC_CONFIG_FILES([Makefile])
 AC_OUTPUT
diff --git a/host_state_manager_main.cpp b/host_state_manager_main.cpp
index 13f2667..2084f36 100644
--- a/host_state_manager_main.cpp
+++ b/host_state_manager_main.cpp
@@ -10,16 +10,16 @@
     auto bus = sdbusplus::bus::new_default();
 
     // For now, we only have one instance of the host
-    auto objPathInst = std::string{OBJPATH} + '0';
-
-    phosphor::state::manager::Host manager(bus,
-                                           BUSNAME,
-                                           objPathInst.c_str());
+    auto objPathInst = std::string{HOST_OBJPATH} + '0';
 
     // Add sdbusplus ObjectManager.
     sdbusplus::server::manager::manager objManager(bus, objPathInst.c_str());
 
-    bus.request_name(BUSNAME);
+    phosphor::state::manager::Host manager(bus,
+                                           HOST_BUSNAME,
+                                           objPathInst.c_str());
+
+    bus.request_name(HOST_BUSNAME);
 
     while(true)
     {
diff --git a/xyz.openbmc_project.State.Chassis.cpp b/xyz.openbmc_project.State.Chassis.cpp
new file mode 100644
index 0000000..21c4343
--- /dev/null
+++ b/xyz.openbmc_project.State.Chassis.cpp
@@ -0,0 +1,271 @@
+#include <algorithm>
+#include <sdbusplus/server.hpp>
+#include <sdbusplus/exception.hpp>
+#include <xyz/openbmc_project/State/Chassis/server.hpp>
+
+namespace sdbusplus
+{
+namespace xyz
+{
+namespace openbmc_project
+{
+namespace State
+{
+namespace server
+{
+
+Chassis::Chassis(bus::bus& bus, const char* path)
+        : _xyz_openbmc_project_State_Chassis_interface(
+                bus, path, _interface, _vtable, this)
+{
+}
+
+
+
+auto Chassis::requestedPowerTransition() const ->
+        Transition
+{
+    return _requestedPowerTransition;
+}
+
+int Chassis::_callback_get_RequestedPowerTransition(
+        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<Chassis*>(context);
+        m.append(convertForMessage(o->requestedPowerTransition()));
+    }
+    catch(sdbusplus::internal_exception_t& e)
+    {
+        sd_bus_error_set_const(error, e.name(), e.description());
+        return -EINVAL;
+    }
+
+    return true;
+}
+
+auto Chassis::requestedPowerTransition(Transition value) ->
+        Transition
+{
+    if (_requestedPowerTransition != value)
+    {
+        _requestedPowerTransition = value;
+        _xyz_openbmc_project_State_Chassis_interface.property_changed("RequestedPowerTransition");
+    }
+
+    return _requestedPowerTransition;
+}
+
+int Chassis::_callback_set_RequestedPowerTransition(
+        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<Chassis*>(context);
+
+        std::string v{};
+        m.read(v);
+        o->requestedPowerTransition(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 Chassis
+{
+static const auto _property_RequestedPowerTransition =
+    utility::tuple_to_array(message::types::type_id<
+            std::string>());
+}
+}
+auto Chassis::currentPowerState() const ->
+        PowerState
+{
+    return _currentPowerState;
+}
+
+int Chassis::_callback_get_CurrentPowerState(
+        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<Chassis*>(context);
+        m.append(convertForMessage(o->currentPowerState()));
+    }
+    catch(sdbusplus::internal_exception_t& e)
+    {
+        sd_bus_error_set_const(error, e.name(), e.description());
+        return -EINVAL;
+    }
+
+    return true;
+}
+
+auto Chassis::currentPowerState(PowerState value) ->
+        PowerState
+{
+    if (_currentPowerState != value)
+    {
+        _currentPowerState = value;
+        _xyz_openbmc_project_State_Chassis_interface.property_changed("CurrentPowerState");
+    }
+
+    return _currentPowerState;
+}
+
+int Chassis::_callback_set_CurrentPowerState(
+        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<Chassis*>(context);
+
+        std::string v{};
+        m.read(v);
+        o->currentPowerState(convertPowerStateFromString(v));
+    }
+    catch(sdbusplus::internal_exception_t& e)
+    {
+        sd_bus_error_set_const(error, e.name(), e.description());
+        return -EINVAL;
+    }
+
+    return true;
+}
+
+namespace details
+{
+namespace Chassis
+{
+static const auto _property_CurrentPowerState =
+    utility::tuple_to_array(message::types::type_id<
+            std::string>());
+}
+}
+
+
+namespace
+{
+/** String to enum mapping for Chassis::Transition */
+static const std::tuple<const char*, Chassis::Transition> mappingChassisTransition[] =
+        {
+            std::make_tuple( "xyz.openbmc_project.State.Chassis.Transition.Off",                 Chassis::Transition::Off ),
+            std::make_tuple( "xyz.openbmc_project.State.Chassis.Transition.On",                 Chassis::Transition::On ),
+        };
+
+} // anonymous namespace
+
+auto Chassis::convertTransitionFromString(std::string& s) ->
+        Transition
+{
+    auto i = std::find_if(
+            std::begin(mappingChassisTransition),
+            std::end(mappingChassisTransition),
+            [&s](auto& e){ return 0 == strcmp(s.c_str(), std::get<0>(e)); } );
+    if (std::end(mappingChassisTransition) == i)
+    {
+        throw sdbusplus::exception::InvalidEnumString();
+    }
+    else
+    {
+        return std::get<1>(*i);
+    }
+}
+
+std::string convertForMessage(Chassis::Transition v)
+{
+    auto i = std::find_if(
+            std::begin(mappingChassisTransition),
+            std::end(mappingChassisTransition),
+            [v](auto& e){ return v == std::get<1>(e); });
+    return std::get<0>(*i);
+}
+
+namespace
+{
+/** String to enum mapping for Chassis::PowerState */
+static const std::tuple<const char*, Chassis::PowerState> mappingChassisPowerState[] =
+        {
+            std::make_tuple( "xyz.openbmc_project.State.Chassis.PowerState.Off",                 Chassis::PowerState::Off ),
+            std::make_tuple( "xyz.openbmc_project.State.Chassis.PowerState.On",                 Chassis::PowerState::On ),
+        };
+
+} // anonymous namespace
+
+auto Chassis::convertPowerStateFromString(std::string& s) ->
+        PowerState
+{
+    auto i = std::find_if(
+            std::begin(mappingChassisPowerState),
+            std::end(mappingChassisPowerState),
+            [&s](auto& e){ return 0 == strcmp(s.c_str(), std::get<0>(e)); } );
+    if (std::end(mappingChassisPowerState) == i)
+    {
+        throw sdbusplus::exception::InvalidEnumString();
+    }
+    else
+    {
+        return std::get<1>(*i);
+    }
+}
+
+std::string convertForMessage(Chassis::PowerState v)
+{
+    auto i = std::find_if(
+            std::begin(mappingChassisPowerState),
+            std::end(mappingChassisPowerState),
+            [v](auto& e){ return v == std::get<1>(e); });
+    return std::get<0>(*i);
+}
+
+const vtable::vtable_t Chassis::_vtable[] = {
+    vtable::start(),
+    vtable::property("RequestedPowerTransition",
+                     details::Chassis::_property_RequestedPowerTransition
+                        .data(),
+                     _callback_get_RequestedPowerTransition,
+                     _callback_set_RequestedPowerTransition,
+                     vtable::property_::emits_change),
+    vtable::property("CurrentPowerState",
+                     details::Chassis::_property_CurrentPowerState
+                        .data(),
+                     _callback_get_CurrentPowerState,
+                     _callback_set_CurrentPowerState,
+                     vtable::property_::emits_change),
+    vtable::end()
+};
+
+} // namespace server
+} // namespace State
+} // namespace openbmc_project
+} // namespace xyz
+} // namespace sdbusplus
+
diff --git a/xyz/openbmc_project/State/Chassis/server.hpp b/xyz/openbmc_project/State/Chassis/server.hpp
new file mode 100644
index 0000000..b823b7f
--- /dev/null
+++ b/xyz/openbmc_project/State/Chassis/server.hpp
@@ -0,0 +1,132 @@
+#pragma once
+#include <tuple>
+#include <systemd/sd-bus.h>
+#include <sdbusplus/server.hpp>
+
+namespace sdbusplus
+{
+namespace xyz
+{
+namespace openbmc_project
+{
+namespace State
+{
+namespace server
+{
+
+class Chassis
+{
+    public:
+        /* Define all of the basic class operations:
+         *     Not allowed:
+         *         - Default constructor to avoid nullptrs.
+         *         - Copy operations due to internal unique_ptr.
+         *         - Move operations due to 'this' being registered as the
+         *           'context' with sdbus.
+         *     Allowed:
+         *         - Destructor.
+         */
+        Chassis() = delete;
+        Chassis(const Chassis&) = delete;
+        Chassis& operator=(const Chassis&) = delete;
+        Chassis(Chassis&&) = delete;
+        Chassis& operator=(Chassis&&) = delete;
+        virtual ~Chassis() = default;
+
+        /** @brief Constructor to put object onto bus at a dbus path.
+         *  @param[in] bus - Bus to attach to.
+         *  @param[in] path - Path to attach at.
+         */
+        Chassis(bus::bus& bus, const char* path);
+
+        enum class Transition
+        {
+            Off,
+            On,
+        };
+        enum class PowerState
+        {
+            Off,
+            On,
+        };
+
+
+
+        /** Get value of RequestedPowerTransition */
+        virtual Transition requestedPowerTransition() const;
+        /** Set value of RequestedPowerTransition */
+        virtual Transition requestedPowerTransition(Transition value);
+        /** Get value of CurrentPowerState */
+        virtual PowerState currentPowerState() const;
+        /** Set value of CurrentPowerState */
+        virtual PowerState currentPowerState(PowerState value);
+
+    /** @brief Convert a string to an appropriate enum value.
+     *  @param[in] s - The string to convert in the form of
+     *                 "xyz.openbmc_project.State.Chassis.<value name>"
+     *  @return - The enum value.
+     */
+    static Transition convertTransitionFromString(std::string& s);
+    /** @brief Convert a string to an appropriate enum value.
+     *  @param[in] s - The string to convert in the form of
+     *                 "xyz.openbmc_project.State.Chassis.<value name>"
+     *  @return - The enum value.
+     */
+    static PowerState convertPowerStateFromString(std::string& s);
+
+    private:
+
+        /** @brief sd-bus callback for get-property 'RequestedPowerTransition' */
+        static int _callback_get_RequestedPowerTransition(
+            sd_bus*, const char*, const char*, const char*,
+            sd_bus_message*, void*, sd_bus_error*);
+        /** @brief sd-bus callback for set-property 'RequestedPowerTransition' */
+        static int _callback_set_RequestedPowerTransition(
+            sd_bus*, const char*, const char*, const char*,
+            sd_bus_message*, void*, sd_bus_error*);
+
+        /** @brief sd-bus callback for get-property 'CurrentPowerState' */
+        static int _callback_get_CurrentPowerState(
+            sd_bus*, const char*, const char*, const char*,
+            sd_bus_message*, void*, sd_bus_error*);
+        /** @brief sd-bus callback for set-property 'CurrentPowerState' */
+        static int _callback_set_CurrentPowerState(
+            sd_bus*, const char*, const char*, const char*,
+            sd_bus_message*, void*, sd_bus_error*);
+
+
+        static constexpr auto _interface = "xyz.openbmc_project.State.Chassis";
+        static const vtable::vtable_t _vtable[];
+        sdbusplus::server::interface::interface
+                _xyz_openbmc_project_State_Chassis_interface;
+
+        Transition _requestedPowerTransition = Transition::Off;
+        PowerState _currentPowerState{};
+
+};
+
+/* Specialization of sdbusplus::server::bindings::details::convertForMessage
+ * for enum-type Chassis::Transition.
+ *
+ * This converts from the enum to a constant c-string representing the enum.
+ *
+ * @param[in] e - Enum value to convert.
+ * @return C-string representing the name for the enum value.
+ */
+std::string convertForMessage(Chassis::Transition e);
+/* Specialization of sdbusplus::server::bindings::details::convertForMessage
+ * for enum-type Chassis::PowerState.
+ *
+ * This converts from the enum to a constant c-string representing the enum.
+ *
+ * @param[in] e - Enum value to convert.
+ * @return C-string representing the name for the enum value.
+ */
+std::string convertForMessage(Chassis::PowerState e);
+
+} // namespace server
+} // namespace State
+} // namespace openbmc_project
+} // namespace xyz
+} // namespace sdbusplus
+