xref: /openbmc/phosphor-fan-presence/presence/tach.cpp (revision 9e9f599cece7fe6cdf99b1927a515fc8a552b7e9)
1 /**
2  * Copyright © 2017 IBM Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "tach.hpp"
17 
18 #include "rpolicy.hpp"
19 
20 #include <phosphor-logging/log.hpp>
21 
22 #include <string>
23 #include <tuple>
24 #include <vector>
25 
26 namespace phosphor
27 {
28 namespace fan
29 {
30 namespace presence
31 {
32 
33 using namespace phosphor::logging;
34 using namespace std::literals::string_literals;
35 
36 static const auto tachNamespace = "/xyz/openbmc_project/sensors/fan_tach/"s;
37 static const auto tachIface = "xyz.openbmc_project.Sensor.Value"s;
38 static const auto tachProperty = "Value"s;
39 
40 Tach::Tach(const std::vector<std::string>& sensors) : currentState(false)
41 {
42     // Initialize state.
43     for (const auto& s : sensors)
44     {
45         state.emplace_back(s, nullptr, 0);
46     }
47 }
48 
49 bool Tach::start()
50 {
51     for (size_t i = 0; i < state.size(); ++i)
52     {
53         auto& s = state[i];
54         auto tachPath = tachNamespace + std::get<std::string>(s);
55 
56         // Register for signal callbacks.
57         std::get<1>(s) = std::make_unique<sdbusplus::bus::match::match>(
58             util::SDBusPlus::getBus(),
59             sdbusplus::bus::match::rules::propertiesChanged(tachPath,
60                                                             tachIface),
61             [this, i](auto& msg) { this->propertiesChanged(i, msg); });
62 
63         // Get an initial tach speed.
64         try
65         {
66             std::get<double>(s) = util::SDBusPlus::getProperty<double>(
67                 tachPath, tachIface, tachProperty);
68         }
69         catch (std::exception&)
70         {
71             // Assume not spinning.
72 
73             std::get<double>(s) = 0;
74             log<level::INFO>("Unable to read fan tach sensor.",
75                              entry("SENSOR=%s", tachPath.c_str()));
76         }
77     }
78 
79     // Set the initial state of the sensor.
80     currentState = std::any_of(state.begin(), state.end(), [](const auto& s) {
81         return std::get<double>(s) != 0;
82     });
83 
84     return currentState;
85 }
86 
87 void Tach::stop()
88 {
89     for (auto& s : state)
90     {
91         // De-register signal callbacks.
92         std::get<1>(s) = nullptr;
93     }
94 }
95 
96 bool Tach::present()
97 {
98     // Live query the tach readings.
99     std::vector<double> values;
100     for (const auto& s : state)
101     {
102         values.push_back(util::SDBusPlus::getProperty<double>(
103             tachNamespace + std::get<std::string>(s), tachIface, tachProperty));
104     }
105 
106     return std::any_of(values.begin(), values.end(),
107                        [](const auto& v) { return v != 0; });
108 }
109 
110 void Tach::propertiesChanged(size_t sensor, sdbusplus::message::message& msg)
111 {
112     std::string iface;
113     util::Properties<double> properties;
114     msg.read(iface, properties);
115 
116     propertiesChanged(sensor, properties);
117 }
118 
119 void Tach::propertiesChanged(size_t sensor,
120                              const util::Properties<double>& props)
121 {
122     // Find the Value property containing the speed.
123     auto it = props.find(tachProperty);
124     if (it != props.end())
125     {
126         auto& s = state[sensor];
127         std::get<double>(s) = std::get<double>(it->second);
128 
129         auto newState =
130             std::any_of(state.begin(), state.end(),
131                         [](const auto& s) { return std::get<double>(s) != 0; });
132 
133         if (currentState != newState)
134         {
135             getPolicy().stateChanged(newState, *this);
136             currentState = newState;
137         }
138     }
139 }
140 
141 } // namespace presence
142 } // namespace fan
143 } // namespace phosphor
144