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 auto addValue(const SensorSet::key_type& sensor, 66 const std::string& sysfsRoot, ObjectInfo& info) 67 { 68 // Get the initial value for the value interface. 69 auto& bus = *std::get<sdbusplus::bus::bus*>(info); 70 auto& obj = std::get<Object>(info); 71 auto& objPath = std::get<std::string>(info); 72 73 auto sysfsPath = make_sysfs_path( 74 sysfsRoot, 75 sensor.first, 76 sensor.second, 77 hwmon::entry::input); 78 int val = 0; 79 read_sysfs(sysfsPath, val); 80 81 auto iface = std::make_shared<ValueObject>(bus, objPath.c_str()); 82 iface->value(val); 83 84 // *INDENT-OFF* 85 const auto& attrs = std::find_if( 86 typeAttrMap.begin(), 87 typeAttrMap.end(), 88 [&](const auto & e) 89 { 90 return sensor.first == getHwmonType(e); 91 }); 92 // *INDENT-ON* 93 94 if (attrs != typeAttrMap.end()) 95 { 96 iface->unit(getUnit(*attrs)); 97 iface->scale(getScale(*attrs)); 98 } 99 100 obj[InterfaceType::VALUE] = iface; 101 return iface; 102 } 103 104 MainLoop::MainLoop( 105 sdbusplus::bus::bus&& bus, 106 const std::string& path, 107 const char* prefix, 108 const char* root) 109 : _bus(std::move(bus)), 110 _manager(sdbusplus::server::manager::manager(_bus, root)), 111 _shutdown(false), 112 _path(path), 113 _prefix(prefix), 114 _root(root), 115 state() 116 { 117 if (_path.back() == '/') 118 { 119 _path.pop_back(); 120 } 121 } 122 123 void MainLoop::shutdown() noexcept 124 { 125 _shutdown = true; 126 } 127 128 void MainLoop::run() 129 { 130 // Check sysfs for available sensors. 131 auto sensors = std::make_unique<SensorSet>(_path); 132 133 for (auto& i : *sensors) 134 { 135 // Get sensor configuration from the environment. 136 137 // Ignore inputs without a label. 138 auto label = getEnv("LABEL", i.first); 139 if (label.empty()) 140 { 141 continue; 142 } 143 144 std::string objectPath{_root}; 145 objectPath.append("/"); 146 objectPath.append(i.first.first); 147 objectPath.append("/"); 148 objectPath.append(label); 149 150 ObjectInfo info(&_bus, std::move(objectPath), Object()); 151 auto valueInterface = addValue(i.first, _path, info); 152 153 auto value = std::make_tuple( 154 std::move(i.second), 155 std::move(label), 156 std::move(info)); 157 158 state[std::move(i.first)] = std::move(value); 159 } 160 161 { 162 auto copy = std::unique_ptr<char, phosphor::utility::Free<char>>(strdup( 163 _path.c_str())); 164 auto busname = std::string(_prefix) + '.' + basename(copy.get()); 165 _bus.request_name(busname.c_str()); 166 } 167 168 // TODO: Issue#3 - Need to make calls to the dbus sensor cache here to 169 // ensure the objects all exist? 170 171 // Polling loop. 172 while (!_shutdown) 173 { 174 // Iterate through all the sensors. 175 for (auto& i : state) 176 { 177 auto& attrs = std::get<0>(i.second); 178 if (attrs.find(hwmon::entry::input) != attrs.end()) 179 { 180 // Read value from sensor. 181 int value = 0; 182 read_sysfs(make_sysfs_path(_path, 183 i.first.first, i.first.second, 184 hwmon::entry::input), 185 value); 186 187 auto& objInfo = std::get<ObjectInfo>(i.second); 188 auto& obj = std::get<Object>(objInfo); 189 auto iface = obj.find(InterfaceType::VALUE); 190 191 if (iface != obj.end()) 192 { 193 auto realIface = std::experimental::any_cast<std::shared_ptr<ValueObject>> 194 (iface->second); 195 realIface->value(value); 196 } 197 } 198 } 199 200 // Respond to DBus 201 _bus.process_discard(); 202 203 // Sleep until next interval. 204 // TODO: Issue#5 - Make this configurable. 205 // TODO: Issue#6 - Optionally look at polling interval sysfs entry. 206 _bus.wait((1000000us).count()); 207 208 // TODO: Issue#7 - Should probably periodically check the SensorSet 209 // for new entries. 210 } 211 } 212 213 // vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 214