blob: 9f6e10546c386d276620c48f3aedd09f59f32074 [file] [log] [blame]
/**
* 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 "tach.hpp"
#include "logging.hpp"
#include "rpolicy.hpp"
#include <phosphor-logging/log.hpp>
#include <format>
#include <string>
#include <tuple>
#include <vector>
namespace phosphor
{
namespace fan
{
namespace presence
{
using namespace phosphor::logging;
using namespace std::literals::string_literals;
static const auto tachNamespace = "/xyz/openbmc_project/sensors/fan_tach/"s;
static const auto tachIface = "xyz.openbmc_project.Sensor.Value"s;
static const auto tachProperty = "Value"s;
Tach::Tach(const std::vector<std::string>& sensors) : currentState(false)
{
// Initialize state.
for (const auto& s : sensors)
{
state.emplace_back(s, nullptr, 0);
}
}
bool Tach::start()
{
for (size_t i = 0; i < state.size(); ++i)
{
auto& s = state[i];
auto tachPath = tachNamespace + std::get<std::string>(s);
// Register for signal callbacks.
std::get<1>(s) = std::make_unique<sdbusplus::bus::match_t>(
util::SDBusPlus::getBus(),
sdbusplus::bus::match::rules::propertiesChanged(tachPath,
tachIface),
[this, i](auto& msg) { this->propertiesChanged(i, msg); });
// Get an initial tach speed.
try
{
std::get<double>(s) = util::SDBusPlus::getProperty<double>(
tachPath, tachIface, tachProperty);
}
catch (const std::exception&)
{
// Assume not spinning.
std::get<double>(s) = 0;
log<level::INFO>(
std::format("Unable to read fan tach sensor {}", tachPath)
.c_str());
}
}
// Set the initial state of the sensor.
currentState = std::any_of(state.begin(), state.end(), [](const auto& s) {
return std::get<double>(s) != 0;
});
return currentState;
}
void Tach::stop()
{
for (auto& s : state)
{
// De-register signal callbacks.
std::get<1>(s) = nullptr;
}
}
bool Tach::present()
{
// Live query the tach readings.
std::vector<double> values;
for (const auto& s : state)
{
values.push_back(util::SDBusPlus::getProperty<double>(
tachNamespace + std::get<std::string>(s), tachIface, tachProperty));
}
return std::any_of(values.begin(), values.end(),
[](const auto& v) { return v != 0; });
}
void Tach::propertiesChanged(size_t sensor, sdbusplus::message_t& msg)
{
std::string iface;
util::Properties<double> properties;
msg.read(iface, properties);
propertiesChanged(sensor, properties);
}
void Tach::propertiesChanged(size_t sensor,
const util::Properties<double>& props)
{
// Find the Value property containing the speed.
auto it = props.find(tachProperty);
if (it != props.end())
{
auto& s = state[sensor];
std::get<double>(s) = std::get<double>(it->second);
auto newState =
std::any_of(state.begin(), state.end(),
[](const auto& s) { return std::get<double>(s) != 0; });
if (currentState != newState)
{
getPolicy().stateChanged(newState, *this);
currentState = newState;
}
}
}
void Tach::logConflict(const std::string& fanInventoryPath) const
{
getLogger().log(std::format(
"Tach sensor presence detect for fan {} said not present but "
"other methods indicated present",
fanInventoryPath));
// Let the code that monitors fan faults create the event
// logs for stopped rotors.
}
} // namespace presence
} // namespace fan
} // namespace phosphor