xref: /openbmc/phosphor-hwmon/mainloop.cpp (revision ab795a1d)
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         Object o;
121         std::string objectPath{_root};
122 
123         objectPath.append("/");
124         objectPath.append(i.first.first);
125         objectPath.append("/");
126         objectPath.append(label);
127 
128         auto iface = std::make_shared<ValueObject>(_bus, objectPath.c_str());
129         iface->value(val);
130 
131         const auto& attrs = std::find_if(
132                                 typeAttrMap.begin(),
133                                 typeAttrMap.end(),
134                                 [&](const auto & e)
135         {
136             return i.first.first == getHwmonType(e);
137         });
138         if (attrs != typeAttrMap.end())
139         {
140             iface->unit(getUnit(*attrs));
141             iface->scale(getScale(*attrs));
142         }
143 
144         o.emplace(InterfaceType::VALUE, iface);
145 
146         auto value = std::make_tuple(
147                          std::move(i.second),
148                          std::move(label),
149                          std::move(o));
150 
151         state[std::move(i.first)] = std::move(value);
152     }
153 
154     {
155         auto copy = std::unique_ptr<char, phosphor::utility::Free<char>>(strdup(
156                         _path.c_str()));
157         auto busname = std::string(_prefix) + '.' + basename(copy.get());
158         _bus.request_name(busname.c_str());
159     }
160 
161     // TODO: Issue#3 - Need to make calls to the dbus sensor cache here to
162     //       ensure the objects all exist?
163 
164     // Polling loop.
165     while (!_shutdown)
166     {
167         // Iterate through all the sensors.
168         for (auto& i : state)
169         {
170             auto& attrs = std::get<0>(i.second);
171             if (attrs.find(hwmon::entry::input) != attrs.end())
172             {
173                 // Read value from sensor.
174                 int value = 0;
175                 read_sysfs(make_sysfs_path(_path,
176                                            i.first.first, i.first.second,
177                                            hwmon::entry::input),
178                            value);
179 
180                 auto& obj = std::get<Object>(i.second);
181                 auto iface = obj.find(InterfaceType::VALUE);
182 
183                 if (iface != obj.end())
184                 {
185                     auto realIface = std::experimental::any_cast<std::shared_ptr<ValueObject>>
186                                      (iface->second);
187                     realIface->value(value);
188                 }
189             }
190         }
191 
192         // Respond to DBus
193         _bus.process_discard();
194 
195         // Sleep until next interval.
196         // TODO: Issue#5 - Make this configurable.
197         // TODO: Issue#6 - Optionally look at polling interval sysfs entry.
198         _bus.wait((1000000us).count());
199 
200         // TODO: Issue#7 - Should probably periodically check the SensorSet
201         //       for new entries.
202     }
203 }
204 
205 // vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
206