summaryrefslogtreecommitdiffstats
path: root/presence
diff options
context:
space:
mode:
authorBrad Bishop <bradleyb@fuzziesquirrel.com>2017-04-22 14:19:45 -0400
committerBrad Bishop <bradleyb@fuzziesquirrel.com>2017-04-24 22:53:58 -0400
commit9df0e16e00338ea267c71a2bf3c314d39e8961be (patch)
tree56bd9da5f66fe259267001c2dc4b27773c6eeecb /presence
parente73446e30576ad6dc734398ad2ca709f2263ad51 (diff)
downloadphosphor-fan-presence-9df0e16e00338ea267c71a2bf3c314d39e8961be.tar.gz
phosphor-fan-presence-9df0e16e00338ea267c71a2bf3c314d39e8961be.zip
build: Move presence to a subdirectory
Change-Id: I33b28922107b9b041de3699e4a6eebd3d05ebdef Signed-off-by: Brad Bishop <bradleyb@fuzziesquirrel.com>
Diffstat (limited to 'presence')
-rw-r--r--presence/Makefile.am25
-rw-r--r--presence/example/fan-detect.yaml24
-rw-r--r--presence/fan_detect_defs.hpp9
-rw-r--r--presence/fan_enclosure.cpp105
-rw-r--r--presence/fan_enclosure.hpp114
-rw-r--r--presence/fan_properties.hpp22
-rwxr-xr-xpresence/gen-fan-detect-defs.py72
-rw-r--r--presence/sensor_base.hpp59
-rw-r--r--presence/tach_detect.cpp58
-rw-r--r--presence/tach_sensor.cpp69
-rw-r--r--presence/tach_sensor.hpp107
11 files changed, 664 insertions, 0 deletions
diff --git a/presence/Makefile.am b/presence/Makefile.am
new file mode 100644
index 0000000..10a7363
--- /dev/null
+++ b/presence/Makefile.am
@@ -0,0 +1,25 @@
+AM_DEFAULT_SOURCE_EXT = .cpp
+AM_CPPFLAGS = -iquote ${top_srcdir}
+
+sbin_PROGRAMS = \
+ phosphor-fan-presence-tach
+
+phosphor_fan_presence_tach_SOURCES = \
+ fan_enclosure.cpp \
+ tach_sensor.cpp \
+ tach_detect.cpp
+nodist_phosphor_fan_presence_tach_SOURCES = \
+ fan_detect_defs.cpp
+
+phosphor_fan_presence_tach_LDADD = \
+ $(top_builddir)/libfan.la \
+ $(SDBUSPLUS_LIBS) \
+ $(PHOSPHOR_LOGGING_LIBS)
+phosphor_fan_presence_tach_CXXFLAGS = \
+ $(SDBUSPLUS_CFLAGS) \
+ $(PHOSPHOR_LOGGING_CFLAGS)
+
+BUILT_SOURCES = fan_detect_defs.cpp
+
+fan_detect_defs.cpp: ${srcdir}/gen-fan-detect-defs.py
+ $(AM_V_GEN)$(GEN_FAN_DETECT_DEFS) > $@
diff --git a/presence/example/fan-detect.yaml b/presence/example/fan-detect.yaml
new file mode 100644
index 0000000..5a9e1bd
--- /dev/null
+++ b/presence/example/fan-detect.yaml
@@ -0,0 +1,24 @@
+# Example fan presence detection definitions
+
+# List each fan requiring presence detection and creation of an inventory object
+# within a system with the following parameters. The 'Detection' method must
+# have an associated fan presence detection application to properly handle
+# detecting fans using that type.
+
+#- [Detection method]:
+# - PrettyName: [pretty name of the fan]
+# Sensors: [List of sensors associated with this fan enclosure]
+# - i.e) For tach feedback detection:
+# The hwmon name for a detected fan rotor's tach feedback
+# For gpio detection:
+# The gpio pin name for the fan's presence line
+# Inventory: [The system inventory location for the fan]
+# Description: (Optional)
+
+# Example entry for a single fan's presence detected by 'Tach' feedback
+#- Tach:
+# - PrettyName: fan0
+# Sensors:
+# - fan0
+# Inventory: /system/chassis/fan0
+# Description: Chassis location A1
diff --git a/presence/fan_detect_defs.hpp b/presence/fan_detect_defs.hpp
new file mode 100644
index 0000000..6c49366
--- /dev/null
+++ b/presence/fan_detect_defs.hpp
@@ -0,0 +1,9 @@
+#pragma once
+
+#include <map>
+#include <set>
+#include <tuple>
+#include "fan_properties.hpp"
+
+extern const std::map<std::string,
+ std::set<phosphor::fan::Properties>> fanDetectMap;
diff --git a/presence/fan_enclosure.cpp b/presence/fan_enclosure.cpp
new file mode 100644
index 0000000..262876e
--- /dev/null
+++ b/presence/fan_enclosure.cpp
@@ -0,0 +1,105 @@
+/**
+ * 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 <algorithm>
+#include <phosphor-logging/log.hpp>
+#include "fan_enclosure.hpp"
+#include "utility.hpp"
+
+namespace phosphor
+{
+namespace fan
+{
+namespace presence
+{
+
+using namespace phosphor::logging;
+
+//TODO Should get these from phosphor-inventory-manager config.h
+constexpr auto INVENTORY_PATH = "/xyz/openbmc_project/inventory";
+constexpr auto INVENTORY_INTF = "xyz.openbmc_project.Inventory.Manager";
+
+presenceState FanEnclosure::getCurPresState()
+{
+ auto presPred = [](auto const& s) {return s->isPresent();};
+ // Determine if all sensors show fan is not present
+ auto isPresent = std::any_of(sensors.begin(),
+ sensors.end(),
+ presPred);
+
+ return (isPresent) ? PRESENT : NOT_PRESENT;
+}
+
+FanEnclosure::ObjectMap FanEnclosure::getObjectMap(const bool curPresState)
+{
+ ObjectMap invObj;
+ InterfaceMap invIntf;
+ PropertyMap invProp;
+
+ invProp.emplace("Present", curPresState);
+ invProp.emplace("PrettyName", fanDesc);
+ invIntf.emplace("xyz.openbmc_project.Inventory.Item", std::move(invProp));
+ Object fanInvPath = invPath;
+ invObj.emplace(std::move(fanInvPath), std::move(invIntf));
+
+ return invObj;
+}
+
+void FanEnclosure::updInventory()
+{
+ auto curPresState = getCurPresState();
+ // Only update inventory when presence state changed
+ if (presState != curPresState)
+ {
+ // Get inventory object for this fan
+ ObjectMap invObj = getObjectMap(curPresState);
+ // Get inventory manager service name from mapper
+ std::string invService;
+ try
+ {
+ invService = getInvService(bus);
+ }
+ catch (const std::runtime_error& err)
+ {
+ log<level::ERR>(err.what());
+ return;
+ }
+ // Update inventory for this fan
+ auto invMsg = bus.new_method_call(invService.c_str(),
+ INVENTORY_PATH,
+ INVENTORY_INTF,
+ "Notify");
+ invMsg.append(std::move(invObj));
+ auto invMgrResponseMsg = bus.call(invMsg);
+ if (invMgrResponseMsg.is_method_error())
+ {
+ log<level::ERR>(
+ "Error in inventory manager call to update inventory");
+ return;
+ }
+ // Inventory updated, set presence state to current
+ presState = curPresState;
+ }
+}
+
+void FanEnclosure::addSensor(
+ std::unique_ptr<Sensor>&& sensor)
+{
+ FanEnclosure::sensors.push_back(std::move(sensor));
+}
+
+} // namespace presence
+} // namespace fan
+} // namespace phosphor
diff --git a/presence/fan_enclosure.hpp b/presence/fan_enclosure.hpp
new file mode 100644
index 0000000..8f5cfdf
--- /dev/null
+++ b/presence/fan_enclosure.hpp
@@ -0,0 +1,114 @@
+#pragma once
+
+#include <sdbusplus/bus.hpp>
+#include "fan_properties.hpp"
+#include "sensor_base.hpp"
+
+
+namespace phosphor
+{
+namespace fan
+{
+namespace presence
+{
+
+/**
+ * @brief Specifies the defined presence states of a fan enclosure
+ */
+typedef enum presenceState
+{
+ NOT_PRESENT,
+ PRESENT,
+ UNKNOWN
+} presenceState;
+
+/**
+ * @class FanEnclosure
+ * @brief OpenBMC fan enclosure inventory presence implementation
+ * @details Inventory is based on the fan enclosure being present or not. This
+ * class represents that fan enclosure and updates its presences status within
+ * its inventory object based on the status of all its sensors.
+ */
+class FanEnclosure
+{
+ using Property = std::string;
+ using Value = sdbusplus::message::variant<bool, int64_t, std::string>;
+ // Association between property and its value
+ using PropertyMap = std::map<Property, Value>;
+ using Interface = std::string;
+ // Association between interface and the dbus property
+ using InterfaceMap = std::map<Interface, PropertyMap>;
+ using Object = sdbusplus::message::object_path;
+ // Association between object and the interface
+ using ObjectMap = std::map<Object, InterfaceMap>;
+
+ public:
+ FanEnclosure() = delete;
+ FanEnclosure(const FanEnclosure&) = delete;
+ FanEnclosure(FanEnclosure&&) = default;
+ FanEnclosure& operator=(const FanEnclosure&) = delete;
+ FanEnclosure& operator=(FanEnclosure&&) = delete;
+ ~FanEnclosure() = default;
+
+ /**
+ * @brief Constructs Fan Enclosure Object
+ *
+ * @param[in] bus - Dbus bus object
+ * @param[in] fanProp - Fan enclosure properties
+ */
+ FanEnclosure(sdbusplus::bus::bus& bus,
+ const phosphor::fan::Properties& fanProp) :
+ bus(bus),
+ invPath(std::get<0>(fanProp)),
+ fanDesc(std::get<1>(fanProp))
+ {
+ //Add this fan to inventory
+ updInventory();
+ }
+
+ /**
+ * @brief Update inventory when the determined presence of this fan
+ * enclosure has changed
+ */
+ void updInventory();
+ /**
+ * @brief Add a sensor association to this fan enclosure
+ *
+ * @param[in] sensor - Sensor associated to this fan enclosure
+ */
+ void addSensor(
+ std::unique_ptr<Sensor>&& sensor);
+
+ private:
+ /** @brief Connection for sdbusplus bus */
+ sdbusplus::bus::bus& bus;
+ /** @brief Inventory path for this fan enclosure */
+ const std::string invPath;
+ /** @brief Description used as 'PrettyName' on inventory object */
+ const std::string fanDesc;
+ /** @brief List of sensors associated with this fan enclosure */
+ std::vector<std::unique_ptr<Sensor>> sensors;
+ /** @brief Last known presence state of this fan enclosure */
+ presenceState presState = UNKNOWN;
+
+ /**
+ * @brief Get the current presence state based on all sensors
+ *
+ * @return Current presence state determined from all sensors
+ */
+ presenceState getCurPresState();
+
+ /**
+ * @brief Construct the inventory object map
+ *
+ * @param[in] Current presence state
+ *
+ * @return The inventory object map to update inventory
+ */
+ ObjectMap getObjectMap(bool curPresState);
+
+};
+
+} // namespace presence
+} // namespace fan
+} // namespace phosphor
diff --git a/presence/fan_properties.hpp b/presence/fan_properties.hpp
new file mode 100644
index 0000000..296318d
--- /dev/null
+++ b/presence/fan_properties.hpp
@@ -0,0 +1,22 @@
+#pragma once
+
+#include <string>
+#include <vector>
+#include <tuple>
+
+
+namespace phosphor
+{
+namespace fan
+{
+
+/**
+ * @brief Fan enclosure properties
+ * @details Contains the inventory path, description and list of sensors
+ */
+using Properties = std::tuple<std::string,
+ std::string,
+ std::vector<std::string>>;
+
+} // namespace fan
+} // namespace phosphor
diff --git a/presence/gen-fan-detect-defs.py b/presence/gen-fan-detect-defs.py
new file mode 100755
index 0000000..1bc980a
--- /dev/null
+++ b/presence/gen-fan-detect-defs.py
@@ -0,0 +1,72 @@
+#!/usr/bin/env python
+
+"""
+This script parses the given fan presence definition yaml file and generates
+a header file based on the defined methods for determining when a fan is
+present.
+"""
+
+import os
+import sys
+import yaml
+from argparse import ArgumentParser
+from mako.template import Template
+
+tmpl = '''/* This is a generated file. */
+#include "fan_detect_defs.hpp"
+
+const std::map<std::string, std::set<phosphor::fan::Properties>>
+fanDetectMap = {
+%for methods in presence:
+ %for method in methods:
+ <% m = method.lower() %> \
+ {"${m}", {
+ %for fan in methods[method]:
+ std::make_tuple("${fan['Inventory']}",
+ "${fan['PrettyName']}",
+ std::vector<std::string>{
+ %for s in fan['Sensors']:
+ "${s}",
+ %endfor
+ }),
+ %endfor
+ %endfor
+ }},
+%endfor
+};
+'''
+
+
+def get_filename():
+ """
+ Constructs and returns the fully qualified header filename.
+ """
+ script_dir = os.path.dirname(os.path.abspath(__file__))
+ header_file = os.path.join(script_dir, "fan_detect_defs.cpp")
+
+ return header_file
+
+
+if __name__ == '__main__':
+ parser = ArgumentParser()
+ # Input yaml containing how each fan's presence detection should be done
+ parser.add_argument("-y", "--yaml", dest="pres_yaml",
+ default=
+ "example/fan-detect.yaml",
+ help=
+ "Input fan presences definition yaml file to parse")
+ args = parser.parse_args(sys.argv[1:])
+
+ # Verify given yaml file exists
+ yaml_file = os.path.abspath(args.pres_yaml)
+ if not os.path.isfile(yaml_file):
+ print "Unable to find input yaml file " + yaml_file
+ exit(1)
+
+ with open(yaml_file, 'r') as yaml_input:
+ presence_data = yaml.safe_load(yaml_input) or {}
+
+ output_file = get_filename()
+
+ with open(output_file, 'w') as out:
+ out.write(Template(tmpl).render(presence=presence_data))
diff --git a/presence/sensor_base.hpp b/presence/sensor_base.hpp
new file mode 100644
index 0000000..c206e70
--- /dev/null
+++ b/presence/sensor_base.hpp
@@ -0,0 +1,59 @@
+#pragma once
+
+
+namespace phosphor
+{
+namespace fan
+{
+namespace presence
+{
+
+// Forward declare FanEnclosure
+class FanEnclosure;
+/**
+ * @class Sensor
+ * @brief Base sensor implementation to be extended
+ * @details A type of presence detection sensor would extend this to override
+ * how presences is determined by the fan enclosure containing that type
+ */
+class Sensor
+{
+ public:
+ Sensor() = delete;
+ Sensor(const Sensor&) = delete;
+ Sensor(Sensor&&) = delete;
+ Sensor& operator=(const Sensor&) = delete;
+ Sensor& operator=(Sensor&&) = delete;
+ virtual ~Sensor() = default;
+
+ /**
+ * @brief Constructs Sensor Object
+ *
+ * @param[in] id - ID name of this sensor
+ * @param[in] fanEnc - Reference to the fan enclosure with this sensor
+ */
+ Sensor(const std::string& id,
+ FanEnclosure& fanEnc) :
+ id(id),
+ fanEnc(fanEnc)
+ {
+ //Nothing to do here
+ }
+
+ /**
+ * @brief Presence function that must be implemented within the derived
+ * type of sensor's implementation on how presence is determined
+ */
+ virtual bool isPresent() = 0;
+
+ protected:
+ /** @brief ID name of this sensor */
+ const std::string id;
+ /** @brief Reference to the fan enclosure containing this sensor */
+ FanEnclosure& fanEnc;
+
+};
+
+} // namespace presence
+} // namespace fan
+} // namespace phosphor
diff --git a/presence/tach_detect.cpp b/presence/tach_detect.cpp
new file mode 100644
index 0000000..2449f82
--- /dev/null
+++ b/presence/tach_detect.cpp
@@ -0,0 +1,58 @@
+/**
+ * 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 <vector>
+#include <sdbusplus/bus.hpp>
+#include "fan_enclosure.hpp"
+#include "fan_detect_defs.hpp"
+#include "tach_sensor.hpp"
+
+
+int main(void)
+{
+ auto bus = sdbusplus::bus::new_default();
+
+ std::vector<std::unique_ptr<phosphor::fan::presence::FanEnclosure>> fans;
+
+ for (auto const& detectMap: fanDetectMap)
+ {
+ if (detectMap.first == "tach")
+ {
+ for (auto const& fanProp: detectMap.second)
+ {
+ auto fan = std::make_unique<
+ phosphor::fan::presence::FanEnclosure>(bus,
+ fanProp);
+ for (auto const &fanSensor: std::get<2>(fanProp))
+ {
+ auto sensor = std::make_unique<
+ phosphor::fan::presence::TachSensor>(bus,
+ fanSensor,
+ *fan);
+ fan->addSensor(std::move(sensor));
+ }
+ fans.push_back(std::move(fan));
+ }
+ }
+ }
+
+ while (true)
+ {
+ // Respond to dbus signals
+ bus.process_discard();
+ bus.wait();
+ }
+ return 0;
+}
diff --git a/presence/tach_sensor.cpp b/presence/tach_sensor.cpp
new file mode 100644
index 0000000..c21478b
--- /dev/null
+++ b/presence/tach_sensor.cpp
@@ -0,0 +1,69 @@
+/**
+ * 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 <sdbusplus/exception.hpp>
+#include "tach_sensor.hpp"
+#include "fan_enclosure.hpp"
+
+
+namespace phosphor
+{
+namespace fan
+{
+namespace presence
+{
+
+bool TachSensor::isPresent()
+{
+ return (tach != 0);
+}
+
+// Tach signal callback handler
+int TachSensor::handleTachChangeSignal(sd_bus_message* msg,
+ void* usrData,
+ sd_bus_error* err)
+{
+ auto sdbpMsg = sdbusplus::message::message(msg);
+ static_cast<TachSensor*>(usrData)->handleTachChange(sdbpMsg, err);
+ return 0;
+}
+
+void TachSensor::handleTachChange(sdbusplus::message::message& sdbpMsg,
+ sd_bus_error* err)
+{
+ std::string msgSensor;
+ std::map<std::string, sdbusplus::message::variant<int64_t>> msgData;
+ sdbpMsg.read(msgSensor, msgData);
+
+ // TODO openbmc/phosphor-fan-presence#5
+ // Update to use 'arg0namespace' match option to reduce dbus traffic
+ // Find interface with value property
+ if (msgSensor.compare("xyz.openbmc_project.Sensor.Value") == 0)
+ {
+ // Find the 'Value' property containing tach
+ auto valPropMap = msgData.find("Value");
+ if (valPropMap != msgData.end())
+ {
+ tach = sdbusplus::message::variant_ns::get<int64_t>(
+ valPropMap->second);
+ }
+ }
+ // Update inventory according to latest tach reported
+ fanEnc.updInventory();
+}
+
+} // namespace presence
+} // namespace fan
+} // namespace phosphor
diff --git a/presence/tach_sensor.hpp b/presence/tach_sensor.hpp
new file mode 100644
index 0000000..90d955b
--- /dev/null
+++ b/presence/tach_sensor.hpp
@@ -0,0 +1,107 @@
+#pragma once
+
+#include <sdbusplus/bus.hpp>
+#include <sdbusplus/server.hpp>
+#include "sensor_base.hpp"
+
+
+namespace phosphor
+{
+namespace fan
+{
+namespace presence
+{
+
+/**
+ * @class TachSensor
+ * @brief OpenBMC Tach feedback sensor presence implementation
+ * @details Derived sensor type that uses the tach feedback value to determine
+ * the presence of the fan enclosure that contains this sensor
+ */
+class TachSensor : public Sensor
+{
+ public:
+ TachSensor() = delete;
+ TachSensor(const TachSensor&) = delete;
+ TachSensor(TachSensor&&) = delete;
+ TachSensor& operator=(const TachSensor&) = delete;
+ TachSensor& operator=(TachSensor&&) = delete;
+ ~TachSensor() = default;
+
+ /**
+ * @brief Constructs Tach Sensor Object
+ *
+ * @param[in] bus - Dbus bus object
+ * @param[in] id - ID name of this sensor
+ * @param[in] fanEnc - Reference to the fan enclosure with this sensor
+ */
+ TachSensor(
+ sdbusplus::bus::bus& bus,
+ const std::string& id,
+ FanEnclosure& fanEnc) :
+ Sensor(id, fanEnc),
+ bus(bus),
+ tachSignal(bus,
+ match(id).c_str(),
+ handleTachChangeSignal,
+ this)
+ {
+ // Nothing to do here
+ }
+
+ /**
+ * @brief Determine the presence of this sensor using the tach feedback
+ *
+ * @return Presence state based on tach feedback
+ */
+ bool isPresent();
+
+ private:
+ /** @brief Connection for sdbusplus bus */
+ sdbusplus::bus::bus& bus;
+ /** @brief Used to subscribe to dbus signals */
+ sdbusplus::server::match::match tachSignal;
+ /** @brief Tach speed value given from the signal */
+ int64_t tach = 0;
+
+ /**
+ * @brief Appends the fan sensor id to construct a match string
+ *
+ * @param[in] id - Fan sensor id
+ *
+ * @return Match string to register signal for the fan sensor id
+ */
+ static std::string match(const std::string& id)
+ {
+ return std::string("type='signal',"
+ "interface='org.freedesktop.DBus.Properties',"
+ "member='PropertiesChanged',"
+ "path='/xyz/openbmc_project/sensors/fan_tach/" +
+ id + "'");
+ }
+ /**
+ * @brief Callback function on tach change signals
+ *
+ * @param[out] msg - Data associated with the subscribed signal
+ * @param[out] data - Pointer to this tach sensor object instance
+ * @param[out] err - Contains any sdbus error reference if occurred
+ *
+ * @return 0
+ */
+ static int handleTachChangeSignal(sd_bus_message* msg,
+ void* data,
+ sd_bus_error* err);
+ /**
+ * @brief Determine & handle when the signal was a tach change
+ *
+ * @param[in] msg - Expanded sdbusplus message data
+ * @param[in] err - Contains any sdbus error reference if occurred
+ */
+ void handleTachChange(sdbusplus::message::message& msg,
+ sd_bus_error* err);
+
+};
+
+} // namespace presence
+} // namespace fan
+} // namespace phosphor
OpenPOWER on IntegriCloud