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