ipmi: add zone controller interface

Implementations of this interface can make the library mode testable and
work in environments other than dbus.

The main entry point to the IPMI handler now expects to receive a
handler pointer.  The handler itself is implemented to process IPMI
requests and responses in the expected way.  The default object receives
a dbus implementation for the zone controls.

Signed-off-by: Patrick Venture <venture@google.com>
Change-Id: I6d7be871bdc5cce3c3cc53c16d80b501aaaafc7d
diff --git a/ipmi/dbus_mode.cpp b/ipmi/dbus_mode.cpp
index 76b4eba..7ea7fd4 100644
--- a/ipmi/dbus_mode.cpp
+++ b/ipmi/dbus_mode.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "dbus_mode.hpp"
+
 #include <ipmid/api.h>
 
 #include <sdbusplus/bus.hpp>
@@ -21,6 +23,7 @@
 
 #include <cstdint>
 #include <string>
+#include <variant>
 
 namespace pid_control
 {
@@ -44,8 +47,8 @@
     return std::string(objectPath) + std::to_string(zone);
 }
 
-uint8_t getFanCtrlProperty(uint8_t zoneId, bool* value,
-                           const std::string& property)
+uint8_t DbusZoneControl::getFanCtrlProperty(uint8_t zoneId, bool* value,
+                                            const std::string& property)
 {
     std::string path = getControlPath(zoneId);
 
@@ -73,5 +76,33 @@
     return IPMI_CC_OK;
 }
 
+uint8_t DbusZoneControl::setFanCtrlProperty(uint8_t zoneId, bool value,
+                                            const std::string& property)
+{
+    using Value = std::variant<bool>;
+    Value v{value};
+
+    std::string path = getControlPath(zoneId);
+
+    auto PropertyWriteBus = sdbusplus::bus::new_system();
+    auto pimMsg = PropertyWriteBus.new_method_call(busName, path.c_str(),
+                                                   propertiesintf, "Set");
+    pimMsg.append(intf);
+    pimMsg.append(property);
+    pimMsg.append(v);
+
+    try
+    {
+        PropertyWriteBus.call_noreply(pimMsg);
+    }
+    catch (const sdbusplus::exception::SdBusError& ex)
+    {
+        return IPMI_CC_INVALID;
+    }
+
+    /* TODO(venture): Should sanity check the result. */
+    return IPMI_CC_OK;
+}
+
 } // namespace ipmi
 } // namespace pid_control