xref: /openbmc/phosphor-fan-presence/presence/tach.cpp (revision 5593560b1e1a7785a491d4650c4f3f61ffdaba90)
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 <string>
17 #include <tuple>
18 #include <vector>
19 #include "tach.hpp"
20 #include "rpolicy.hpp"
21 
22 namespace phosphor
23 {
24 namespace fan
25 {
26 namespace presence
27 {
28 
29 using namespace std::literals::string_literals;
30 
31 static const auto tachNamespace = "/xyz/openbmc_project/sensors/fan_tach/"s;
32 static const auto tachIface = "xyz.openbmc_project.Sensor.Value"s;
33 static const auto tachProperty = "Value"s;
34 
35 Tach::Tach(
36         const std::vector<std::string>& sensors) : currentState(false)
37 {
38     // Initialize state.
39     for (const auto& s : sensors)
40     {
41         state.emplace_back(s, nullptr, 0);
42     }
43 }
44 
45 bool Tach::start()
46 {
47     for (size_t i = 0; i < state.size(); ++i)
48     {
49         auto& s = state[i];
50         auto tachPath = tachNamespace + std::get<std::string>(s);
51 
52         // Register for signal callbacks.
53         std::get<1>(s) = std::make_unique<sdbusplus::bus::match::match>(
54                 util::SDBusPlus::getBus(),
55                 sdbusplus::bus::match::rules::propertiesChanged(
56                     tachPath, tachIface),
57                 [this, i](auto& msg){ this->propertiesChanged(i, msg);});
58 
59         // Get an initial tach speed.
60         std::get<int64_t>(s) = util::SDBusPlus::getProperty<int64_t>(
61                 tachPath,
62                 tachIface,
63                 tachProperty);
64     }
65 
66     // Set the initial state of the sensor.
67     currentState = std::any_of(
68             state.begin(),
69             state.end(),
70             [](const auto & s)
71             {
72                 return std::get<int64_t>(s) != 0;
73             });
74 
75     return currentState;
76 }
77 
78 void Tach::stop()
79 {
80     for (auto& s : state)
81     {
82         // De-register signal callbacks.
83         std::get<1>(s) = nullptr;
84     }
85 }
86 
87 bool Tach::present()
88 {
89     // Live query the tach readings.
90     std::vector<int64_t> values;
91     for (const auto& s : state)
92     {
93         values.push_back(
94                 util::SDBusPlus::getProperty<int64_t>(
95                         tachNamespace + std::get<std::string>(s),
96                         tachIface,
97                         tachProperty));
98     }
99 
100     return std::any_of(
101             values.begin(),
102             values.end(),
103             [](const auto & v) {return v != 0;});
104 }
105 
106 void Tach::propertiesChanged(
107         size_t sensor,
108         sdbusplus::message::message& msg)
109 {
110     std::string iface;
111     util::Properties<int64_t> properties;
112     msg.read(iface, properties);
113 
114     propertiesChanged(sensor, properties);
115 }
116 
117 void Tach::propertiesChanged(
118         size_t sensor,
119         const util::Properties<int64_t>& props)
120 {
121     auto& s = state[sensor];
122 
123     // Find the Value property containing the speed.
124     auto it = props.find(tachProperty);
125     if (it != props.end())
126     {
127         std::get<int64_t>(s) =
128             sdbusplus::message::variant_ns::get<int64_t>(it->second);
129 
130         auto newState = std::any_of(
131                 state.begin(),
132                 state.end(),
133                 [](const auto & s)
134                 {
135                     return std::get<int64_t>(s) != 0;
136                 });
137 
138         if (currentState != newState)
139         {
140             getPolicy().stateChanged(newState);
141             currentState = newState;
142         }
143     }
144 }
145 
146 } // namespace presence
147 } // namespace fan
148 } // namespace phosphor
149