Fan control: Create Fan class

This class contains the inventory name of the fan,
and the sensor names representing the rotors.

Calling setSpeed on this object will set the speed
on all contained sensors.

Change-Id: I850e2d69067813005270105618fcf69b04382b03
Signed-off-by: Matt Spinler <spinler@us.ibm.com>
diff --git a/control/Makefile.am b/control/Makefile.am
index adfd227..56ba948 100644
--- a/control/Makefile.am
+++ b/control/Makefile.am
@@ -6,10 +6,12 @@
 
 phosphor_fan_control_SOURCES = \
 	generated.cpp \
+	fan.cpp \
 	main.cpp \
 	manager.cpp
 
 phosphor_fan_control_LDADD = \
+	$(top_builddir)/libfan.la \
 	$(SDBUSPLUS_LIBS) \
 	$(PHOSPHOR_LOGGING_LIBS)
 
diff --git a/control/fan.cpp b/control/fan.cpp
new file mode 100644
index 0000000..550d34a
--- /dev/null
+++ b/control/fan.cpp
@@ -0,0 +1,90 @@
+/**
+ * Copyright © 2017 IBM Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <phosphor-logging/log.hpp>
+#include <string>
+#include "fan.hpp"
+#include "utility.hpp"
+
+namespace phosphor
+{
+namespace fan
+{
+namespace control
+{
+
+constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties";
+constexpr auto FAN_SENSOR_PATH = "/xyz/openbmc_project/sensors/fan_tach/";
+constexpr auto FAN_SENSOR_CONTROL_INTF = "xyz.openbmc_project.Control.FanSpeed";
+constexpr auto FAN_TARGET_PROPERTY = "Target";
+
+
+Fan::Fan(sdbusplus::bus::bus& bus, const FanDefinition& def):
+    _bus(bus),
+    _name(std::get<fanNamePos>(def))
+{
+    auto sensors = std::get<sensorListPos>(def);
+    for (auto& s : sensors)
+    {
+        _sensors.emplace_back(FAN_SENSOR_PATH + s);
+    }
+}
+
+
+//TODO openbmc/openbmc#1524  Can cache this value when
+//openbmc/openbmc#1496 is resolved.
+std::string Fan::getService(const std::string& sensor)
+{
+    return phosphor::fan::util::getService(sensor,
+                                           FAN_SENSOR_CONTROL_INTF,
+                                           _bus);
+}
+
+
+void Fan::setSpeed(uint64_t speed)
+{
+    sdbusplus::message::variant<uint64_t> value = speed;
+    std::string property{FAN_TARGET_PROPERTY};
+
+    for (auto& sensor : _sensors)
+    {
+        try
+        {
+            auto service = getService(sensor);
+
+            auto method = _bus.new_method_call(service.c_str(),
+                                               sensor.c_str(),
+                                               PROPERTY_INTERFACE,
+                                               "Set");
+            method.append(FAN_SENSOR_CONTROL_INTF, property, value);
+
+            auto response = _bus.call(method);
+            if (response.is_method_error())
+            {
+                throw std::runtime_error(
+                    "Failed call to set fan speed on " + sensor);
+            }
+        }
+        catch (std::exception& e)
+        {
+            //Other applications will handle reporting errors for this
+            phosphor::logging::log<phosphor::logging::level::INFO>(e.what());
+        }
+    }
+}
+
+}
+}
+}
diff --git a/control/fan.hpp b/control/fan.hpp
new file mode 100644
index 0000000..e23d44e
--- /dev/null
+++ b/control/fan.hpp
@@ -0,0 +1,79 @@
+#pragma once
+#include <sdbusplus/bus.hpp>
+#include "types.hpp"
+
+namespace phosphor
+{
+namespace fan
+{
+namespace control
+{
+
+
+/**
+ * @class Fan
+ *
+ * Represents a fan.  It has sensors used for setting speeds
+ * on all of the contained rotors.  There may or may not be
+ * a 1 to 1 correspondence between rotors and sensors, depending
+ * on how the hardware and hwmon is configured.
+ *
+ */
+class Fan
+{
+    public:
+
+        Fan() = delete;
+        Fan(const Fan&) = delete;
+        Fan(Fan&&) = default;
+        Fan& operator=(const Fan&) = delete;
+        Fan& operator=(Fan&&) = default;
+        ~Fan() = default;
+
+        /**
+         * Creates a fan object with sensors specified by
+         * the fan definition data.
+         *
+         * @param[in] bus - the dbus object
+         * @param[in] def - the fan definition data
+         */
+        Fan(sdbusplus::bus::bus& bus, const FanDefinition& def);
+
+        /**
+         * Sets the speed value on all contained sensors
+         *
+         * @param[in] speed - the value to set
+         */
+        void setSpeed(uint64_t speed);
+
+    private:
+
+        /**
+         * Returns the service name to use for interacting
+         * with the fan sensor passed in.
+         *
+         * @param[in] sensor - the fan tach sensor name
+         * @return - the service name
+         */
+        std::string getService(const std::string& sensor);
+
+        /**
+         * The dbus object
+         */
+        sdbusplus::bus::bus& _bus;
+
+        /**
+         * The inventory name of the fan
+         */
+        std::string _name;
+
+        /**
+         * Vector of hwmon sensors for the rotors
+         */
+        std::vector<std::string> _sensors;
+};
+
+
+}
+}
+}