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