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