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