xref: /openbmc/phosphor-hwmon/mainloop.cpp (revision f7426cff)
1 /**
2  * Copyright © 2016 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 <iostream>
17 #include <memory>
18 #include <cstring>
19 #include <cstdlib>
20 #include <chrono>
21 #include <algorithm>
22 #include "sensorset.hpp"
23 #include "hwmon.hpp"
24 #include "sysfs.hpp"
25 #include "mainloop.hpp"
26 #include "util.hpp"
27 
28 using namespace std::literals::chrono_literals;
29 
30 static constexpr auto typeAttrMap =
31 {
32     // 1 - hwmon class
33     // 2 - unit
34     // 3 - sysfs scaling factor
35     std::make_tuple(
36         hwmon::type::ctemp,
37         ValueInterface::Unit::DegreesC,
38         -3),
39     std::make_tuple(
40         hwmon::type::cfan,
41         ValueInterface::Unit::RPMS,
42         0),
43     std::make_tuple(
44         hwmon::type::cvolt,
45         ValueInterface::Unit::Volts,
46         -3),
47 };
48 
49 auto getHwmonType(decltype(typeAttrMap)::const_reference attrs)
50 {
51     return std::get<0>(attrs);
52 }
53 
54 auto getUnit(decltype(typeAttrMap)::const_reference attrs)
55 {
56     return std::get<1>(attrs);
57 }
58 
59 auto getScale(decltype(typeAttrMap)::const_reference attrs)
60 {
61     return std::get<2>(attrs);
62 }
63 
64 MainLoop::MainLoop(
65     sdbusplus::bus::bus&& bus,
66     const std::string& path,
67     const char* prefix,
68     const char* root)
69     : _bus(std::move(bus)),
70       _manager(sdbusplus::server::manager::manager(_bus, root)),
71       _shutdown(false),
72       _path(path),
73       _prefix(prefix),
74       _root(root),
75       state()
76 {
77     if (_path.back() == '/')
78     {
79         _path.pop_back();
80     }
81 }
82 
83 void MainLoop::shutdown() noexcept
84 {
85     _shutdown = true;
86 }
87 
88 void MainLoop::run()
89 {
90     // Check sysfs for available sensors.
91     auto sensors = std::make_unique<SensorSet>(_path);
92 
93     for (auto& i : *sensors)
94     {
95         // Ignore inputs without a label.
96         std::string envKey = "LABEL_" + i.first.first + i.first.second;
97         std::string label;
98 
99         auto env = getenv(envKey.c_str());
100 
101         if (env)
102         {
103             label.assign(env);
104         }
105 
106         if (label.empty())
107         {
108             continue;
109         }
110 
111         // Get the initial value for the value interface.
112         auto sysfsPath = make_sysfs_path(
113                              _path,
114                              i.first.first,
115                              i.first.second,
116                              hwmon::entry::input);
117         int val = 0;
118         read_sysfs(sysfsPath, val);
119 
120         std::string objectPath{_root};
121         objectPath.append("/");
122         objectPath.append(i.first.first);
123         objectPath.append("/");
124         objectPath.append(label);
125 
126         ObjectInfo info(&_bus, std::move(objectPath), Object());
127         auto& o = std::get<Object>(info);
128 
129         auto iface = std::make_shared<ValueObject>(_bus, objectPath.c_str());
130         iface->value(val);
131 
132         const auto& attrs = std::find_if(
133                                 typeAttrMap.begin(),
134                                 typeAttrMap.end(),
135                                 [&](const auto & e)
136         {
137             return i.first.first == getHwmonType(e);
138         });
139         if (attrs != typeAttrMap.end())
140         {
141             iface->unit(getUnit(*attrs));
142             iface->scale(getScale(*attrs));
143         }
144 
145         o.emplace(InterfaceType::VALUE, iface);
146 
147         auto value = std::make_tuple(
148                          std::move(i.second),
149                          std::move(label),
150                          std::move(info));
151 
152         state[std::move(i.first)] = std::move(value);
153     }
154 
155     {
156         auto copy = std::unique_ptr<char, phosphor::utility::Free<char>>(strdup(
157                         _path.c_str()));
158         auto busname = std::string(_prefix) + '.' + basename(copy.get());
159         _bus.request_name(busname.c_str());
160     }
161 
162     // TODO: Issue#3 - Need to make calls to the dbus sensor cache here to
163     //       ensure the objects all exist?
164 
165     // Polling loop.
166     while (!_shutdown)
167     {
168         // Iterate through all the sensors.
169         for (auto& i : state)
170         {
171             auto& attrs = std::get<0>(i.second);
172             if (attrs.find(hwmon::entry::input) != attrs.end())
173             {
174                 // Read value from sensor.
175                 int value = 0;
176                 read_sysfs(make_sysfs_path(_path,
177                                            i.first.first, i.first.second,
178                                            hwmon::entry::input),
179                            value);
180 
181                 auto& objInfo = std::get<ObjectInfo>(i.second);
182                 auto& obj = std::get<Object>(objInfo);
183                 auto iface = obj.find(InterfaceType::VALUE);
184 
185                 if (iface != obj.end())
186                 {
187                     auto realIface = std::experimental::any_cast<std::shared_ptr<ValueObject>>
188                                      (iface->second);
189                     realIface->value(value);
190                 }
191             }
192         }
193 
194         // Respond to DBus
195         _bus.process_discard();
196 
197         // Sleep until next interval.
198         // TODO: Issue#5 - Make this configurable.
199         // TODO: Issue#6 - Optionally look at polling interval sysfs entry.
200         _bus.wait((1000000us).count());
201 
202         // TODO: Issue#7 - Should probably periodically check the SensorSet
203         //       for new entries.
204     }
205 }
206 
207 // vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
208