diff options
author | Brad Bishop <bradleyb@fuzziesquirrel.com> | 2017-04-22 14:19:45 -0400 |
---|---|---|
committer | Brad Bishop <bradleyb@fuzziesquirrel.com> | 2017-04-24 22:53:58 -0400 |
commit | 9df0e16e00338ea267c71a2bf3c314d39e8961be (patch) | |
tree | 56bd9da5f66fe259267001c2dc4b27773c6eeecb /presence | |
parent | e73446e30576ad6dc734398ad2ca709f2263ad51 (diff) | |
download | phosphor-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.am | 25 | ||||
-rw-r--r-- | presence/example/fan-detect.yaml | 24 | ||||
-rw-r--r-- | presence/fan_detect_defs.hpp | 9 | ||||
-rw-r--r-- | presence/fan_enclosure.cpp | 105 | ||||
-rw-r--r-- | presence/fan_enclosure.hpp | 114 | ||||
-rw-r--r-- | presence/fan_properties.hpp | 22 | ||||
-rwxr-xr-x | presence/gen-fan-detect-defs.py | 72 | ||||
-rw-r--r-- | presence/sensor_base.hpp | 59 | ||||
-rw-r--r-- | presence/tach_detect.cpp | 58 | ||||
-rw-r--r-- | presence/tach_sensor.cpp | 69 | ||||
-rw-r--r-- | presence/tach_sensor.hpp | 107 |
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 |