16714a25aSJames Feist /* 26714a25aSJames Feist // Copyright (c) 2017 Intel Corporation 36714a25aSJames Feist // 46714a25aSJames Feist // Licensed under the Apache License, Version 2.0 (the "License"); 56714a25aSJames Feist // you may not use this file except in compliance with the License. 66714a25aSJames Feist // You may obtain a copy of the License at 76714a25aSJames Feist // 86714a25aSJames Feist // http://www.apache.org/licenses/LICENSE-2.0 96714a25aSJames Feist // 106714a25aSJames Feist // Unless required by applicable law or agreed to in writing, software 116714a25aSJames Feist // distributed under the License is distributed on an "AS IS" BASIS, 126714a25aSJames Feist // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136714a25aSJames Feist // See the License for the specific language governing permissions and 146714a25aSJames Feist // limitations under the License. 156714a25aSJames Feist */ 166714a25aSJames Feist 176714a25aSJames Feist #include <HwmonTempSensor.hpp> 186714a25aSJames Feist #include <Utils.hpp> 196714a25aSJames Feist #include <boost/algorithm/string/predicate.hpp> 206714a25aSJames Feist #include <boost/algorithm/string/replace.hpp> 216714a25aSJames Feist #include <boost/container/flat_set.hpp> 2224f02f24SJames Feist #include <filesystem> 236714a25aSJames Feist #include <fstream> 246714a25aSJames Feist #include <regex> 256714a25aSJames Feist #include <sdbusplus/asio/connection.hpp> 266714a25aSJames Feist #include <sdbusplus/asio/object_server.hpp> 276714a25aSJames Feist 286714a25aSJames Feist static constexpr bool DEBUG = false; 296714a25aSJames Feist 30cf3bce6eSJames Feist namespace fs = std::filesystem; 313546adb9SPatrick Venture static constexpr std::array<const char*, 7> sensorTypes = { 326714a25aSJames Feist "xyz.openbmc_project.Configuration.TMP75", 3355ab2afbSJohn Wang "xyz.openbmc_project.Configuration.TMP421", 347fa475d3SPatrick Venture "xyz.openbmc_project.Configuration.TMP441", 3555ab2afbSJohn Wang "xyz.openbmc_project.Configuration.TMP112", 363546adb9SPatrick Venture "xyz.openbmc_project.Configuration.TMP175", 37bd1a9d5dSPatrick Venture "xyz.openbmc_project.Configuration.EMC1413", 38bd1a9d5dSPatrick Venture "xyz.openbmc_project.Configuration.MAX31725"}; 396714a25aSJames Feist 406714a25aSJames Feist void createSensors( 416714a25aSJames Feist boost::asio::io_service& io, sdbusplus::asio::object_server& objectServer, 426714a25aSJames Feist boost::container::flat_map<std::string, std::unique_ptr<HwmonTempSensor>>& 436714a25aSJames Feist sensors, 446714a25aSJames Feist std::shared_ptr<sdbusplus::asio::connection>& dbusConnection, 456714a25aSJames Feist const std::unique_ptr<boost::container::flat_set<std::string>>& 466714a25aSJames Feist sensorsChanged) 476714a25aSJames Feist { 48*df515159SJames Feist auto getter = std::make_shared<GetSensorConfiguration>( 49*df515159SJames Feist dbusConnection, 50*df515159SJames Feist std::move([&io, &objectServer, &sensors, &dbusConnection, 51*df515159SJames Feist &sensorsChanged]( 52*df515159SJames Feist const ManagedObjectType& sensorConfigurations) { 536714a25aSJames Feist bool firstScan = sensorsChanged == nullptr; 54*df515159SJames Feist 556714a25aSJames Feist std::vector<fs::path> paths; 56*df515159SJames Feist if (!findFiles(fs::path("/sys/class/hwmon"), R"(temp\d+_input)", 57*df515159SJames Feist paths)) 586714a25aSJames Feist { 596714a25aSJames Feist std::cerr << "No temperature sensors in system\n"; 606714a25aSJames Feist return; 616714a25aSJames Feist } 626714a25aSJames Feist 6337266ca9SJames Feist boost::container::flat_set<std::string> directories; 6437266ca9SJames Feist 65*df515159SJames Feist // iterate through all found temp sensors, and try to match them 66*df515159SJames Feist // with configuration 676714a25aSJames Feist for (auto& path : paths) 686714a25aSJames Feist { 696714a25aSJames Feist std::smatch match; 7037266ca9SJames Feist const std::string& pathStr = path.string(); 716714a25aSJames Feist auto directory = path.parent_path(); 726714a25aSJames Feist 7337266ca9SJames Feist auto ret = directories.insert(directory.string()); 7437266ca9SJames Feist if (!ret.second) 756714a25aSJames Feist { 7637266ca9SJames Feist continue; // already searched this path 7737266ca9SJames Feist } 7837266ca9SJames Feist 79b6c0b914SJames Feist fs::path device = directory / "device"; 8037266ca9SJames Feist std::string deviceName = fs::canonical(device).stem(); 8137266ca9SJames Feist auto findHyphen = deviceName.find("-"); 8237266ca9SJames Feist if (findHyphen == std::string::npos) 8337266ca9SJames Feist { 8437266ca9SJames Feist std::cerr << "found bad device " << deviceName << "\n"; 856714a25aSJames Feist continue; 866714a25aSJames Feist } 8737266ca9SJames Feist std::string busStr = deviceName.substr(0, findHyphen); 8837266ca9SJames Feist std::string addrStr = deviceName.substr(findHyphen + 1); 8937266ca9SJames Feist 9037266ca9SJames Feist size_t bus = 0; 9137266ca9SJames Feist size_t addr = 0; 9237266ca9SJames Feist try 936714a25aSJames Feist { 9437266ca9SJames Feist bus = std::stoi(busStr); 9537266ca9SJames Feist addr = std::stoi(addrStr, 0, 16); 9637266ca9SJames Feist } 97b6c0b914SJames Feist catch (std::invalid_argument&) 9837266ca9SJames Feist { 996714a25aSJames Feist continue; 1006714a25aSJames Feist } 1016714a25aSJames Feist const SensorData* sensorData = nullptr; 1026714a25aSJames Feist const std::string* interfacePath = nullptr; 10337266ca9SJames Feist const char* sensorType = nullptr; 104*df515159SJames Feist const std::pair< 105*df515159SJames Feist std::string, 106*df515159SJames Feist boost::container::flat_map<std::string, BasicVariantType>>* 1076714a25aSJames Feist baseConfiguration = nullptr; 10837266ca9SJames Feist 109*df515159SJames Feist for (const std::pair<sdbusplus::message::object_path, 110*df515159SJames Feist SensorData>& sensor : sensorConfigurations) 11137266ca9SJames Feist { 11237266ca9SJames Feist sensorData = &(sensor.second); 1139ced0a38SJae Hyun Yoo for (const char* type : sensorTypes) 1146714a25aSJames Feist { 1156714a25aSJames Feist auto sensorBase = sensorData->find(type); 1166714a25aSJames Feist if (sensorBase != sensorData->end()) 1176714a25aSJames Feist { 1186714a25aSJames Feist baseConfiguration = &(*sensorBase); 1196714a25aSJames Feist sensorType = type; 1206714a25aSJames Feist break; 1216714a25aSJames Feist } 1226714a25aSJames Feist } 1236714a25aSJames Feist if (baseConfiguration == nullptr) 1246714a25aSJames Feist { 12537266ca9SJames Feist std::cerr << "error finding base configuration for " 12637266ca9SJames Feist << deviceName << "\n"; 12737266ca9SJames Feist continue; 12837266ca9SJames Feist } 129*df515159SJames Feist auto configurationBus = 130*df515159SJames Feist baseConfiguration->second.find("Bus"); 13137266ca9SJames Feist auto configurationAddress = 13237266ca9SJames Feist baseConfiguration->second.find("Address"); 13337266ca9SJames Feist 13437266ca9SJames Feist if (configurationBus == baseConfiguration->second.end() || 13537266ca9SJames Feist configurationAddress == baseConfiguration->second.end()) 13637266ca9SJames Feist { 137*df515159SJames Feist std::cerr 138*df515159SJames Feist << "error finding bus or address in configuration"; 13937266ca9SJames Feist continue; 14037266ca9SJames Feist } 14137266ca9SJames Feist 1423eb82629SJames Feist if (std::get<uint64_t>(configurationBus->second) != bus || 143*df515159SJames Feist std::get<uint64_t>(configurationAddress->second) != 144*df515159SJames Feist addr) 14537266ca9SJames Feist { 14637266ca9SJames Feist continue; 14737266ca9SJames Feist } 14837266ca9SJames Feist 14937266ca9SJames Feist interfacePath = &(sensor.first.str); 15037266ca9SJames Feist break; 15137266ca9SJames Feist } 15237266ca9SJames Feist if (interfacePath == nullptr) 15337266ca9SJames Feist { 154*df515159SJames Feist std::cerr << "failed to find match for " << deviceName 155*df515159SJames Feist << "\n"; 1566714a25aSJames Feist continue; 1576714a25aSJames Feist } 1586714a25aSJames Feist 1596714a25aSJames Feist auto findSensorName = baseConfiguration->second.find("Name"); 1606714a25aSJames Feist if (findSensorName == baseConfiguration->second.end()) 1616714a25aSJames Feist { 1626714a25aSJames Feist std::cerr << "could not determine configuration name for " 16337266ca9SJames Feist << deviceName << "\n"; 1646714a25aSJames Feist continue; 1656714a25aSJames Feist } 166*df515159SJames Feist std::string sensorName = 167*df515159SJames Feist std::get<std::string>(findSensorName->second); 1686714a25aSJames Feist // on rescans, only update sensors we were signaled by 1696714a25aSJames Feist auto findSensor = sensors.find(sensorName); 1706714a25aSJames Feist if (!firstScan && findSensor != sensors.end()) 1716714a25aSJames Feist { 1726714a25aSJames Feist bool found = false; 173*df515159SJames Feist for (auto it = sensorsChanged->begin(); 174*df515159SJames Feist it != sensorsChanged->end(); it++) 1756714a25aSJames Feist { 1766714a25aSJames Feist if (boost::ends_with(*it, findSensor->second->name)) 1776714a25aSJames Feist { 1786714a25aSJames Feist sensorsChanged->erase(it); 1796714a25aSJames Feist findSensor->second = nullptr; 1806714a25aSJames Feist found = true; 1816714a25aSJames Feist break; 1826714a25aSJames Feist } 1836714a25aSJames Feist } 1846714a25aSJames Feist if (!found) 1856714a25aSJames Feist { 1866714a25aSJames Feist continue; 1876714a25aSJames Feist } 1886714a25aSJames Feist } 1896714a25aSJames Feist std::vector<thresholds::Threshold> sensorThresholds; 1909ced0a38SJae Hyun Yoo if (!parseThresholdsFromConfig(*sensorData, sensorThresholds)) 1916714a25aSJames Feist { 192*df515159SJames Feist std::cerr << "error populating thresholds for " 193*df515159SJames Feist << sensorName << "\n"; 1946714a25aSJames Feist } 195*df515159SJames Feist auto& sensor1 = sensors[sensorName]; 196*df515159SJames Feist sensor1 = nullptr; 197*df515159SJames Feist sensor1 = std::make_unique<HwmonTempSensor>( 198*df515159SJames Feist directory.string() + "/temp1_input", sensorType, 199*df515159SJames Feist objectServer, dbusConnection, io, sensorName, 200*df515159SJames Feist std::move(sensorThresholds), *interfacePath); 20137266ca9SJames Feist auto findSecondName = baseConfiguration->second.find("Name1"); 20237266ca9SJames Feist if (findSecondName == baseConfiguration->second.end()) 20337266ca9SJames Feist { 20437266ca9SJames Feist continue; 20537266ca9SJames Feist } 2063eb82629SJames Feist sensorName = std::get<std::string>(findSecondName->second); 207*df515159SJames Feist auto& sensor2 = sensors[sensorName]; 208*df515159SJames Feist sensor2 = nullptr; 209*df515159SJames Feist sensor2 = std::make_unique<HwmonTempSensor>( 210*df515159SJames Feist directory.string() + "/temp2_input", sensorType, 211*df515159SJames Feist objectServer, dbusConnection, io, sensorName, 21237266ca9SJames Feist std::vector<thresholds::Threshold>(), *interfacePath); 2136714a25aSJames Feist } 214*df515159SJames Feist })); 215*df515159SJames Feist getter->getConfiguration( 216*df515159SJames Feist std::vector<std::string>(sensorTypes.begin(), sensorTypes.end())); 2176714a25aSJames Feist } 2186714a25aSJames Feist 219b6c0b914SJames Feist int main() 2206714a25aSJames Feist { 2216714a25aSJames Feist boost::asio::io_service io; 2226714a25aSJames Feist auto systemBus = std::make_shared<sdbusplus::asio::connection>(io); 2236714a25aSJames Feist systemBus->request_name("xyz.openbmc_project.HwmonTempSensor"); 2246714a25aSJames Feist sdbusplus::asio::object_server objectServer(systemBus); 2256714a25aSJames Feist boost::container::flat_map<std::string, std::unique_ptr<HwmonTempSensor>> 2266714a25aSJames Feist sensors; 2276714a25aSJames Feist std::vector<std::unique_ptr<sdbusplus::bus::match::match>> matches; 2286714a25aSJames Feist std::unique_ptr<boost::container::flat_set<std::string>> sensorsChanged = 2296714a25aSJames Feist std::make_unique<boost::container::flat_set<std::string>>(); 2306714a25aSJames Feist 2316714a25aSJames Feist io.post([&]() { 2326714a25aSJames Feist createSensors(io, objectServer, sensors, systemBus, nullptr); 2336714a25aSJames Feist }); 2346714a25aSJames Feist 2356714a25aSJames Feist boost::asio::deadline_timer filterTimer(io); 2366714a25aSJames Feist std::function<void(sdbusplus::message::message&)> eventHandler = 2376714a25aSJames Feist [&](sdbusplus::message::message& message) { 2386714a25aSJames Feist if (message.is_method_error()) 2396714a25aSJames Feist { 2406714a25aSJames Feist std::cerr << "callback method error\n"; 2416714a25aSJames Feist return; 2426714a25aSJames Feist } 2436714a25aSJames Feist sensorsChanged->insert(message.get_path()); 2446714a25aSJames Feist // this implicitly cancels the timer 2456714a25aSJames Feist filterTimer.expires_from_now(boost::posix_time::seconds(1)); 2466714a25aSJames Feist 2476714a25aSJames Feist filterTimer.async_wait([&](const boost::system::error_code& ec) { 2486714a25aSJames Feist if (ec == boost::asio::error::operation_aborted) 2496714a25aSJames Feist { 2506714a25aSJames Feist /* we were canceled*/ 2516714a25aSJames Feist return; 2526714a25aSJames Feist } 2536714a25aSJames Feist else if (ec) 2546714a25aSJames Feist { 2556714a25aSJames Feist std::cerr << "timer error\n"; 2566714a25aSJames Feist return; 2576714a25aSJames Feist } 2586714a25aSJames Feist createSensors(io, objectServer, sensors, systemBus, 2596714a25aSJames Feist sensorsChanged); 2606714a25aSJames Feist }); 2616714a25aSJames Feist }; 2626714a25aSJames Feist 2639ced0a38SJae Hyun Yoo for (const char* type : sensorTypes) 2646714a25aSJames Feist { 2656714a25aSJames Feist auto match = std::make_unique<sdbusplus::bus::match::match>( 2666714a25aSJames Feist static_cast<sdbusplus::bus::bus&>(*systemBus), 2676714a25aSJames Feist "type='signal',member='PropertiesChanged',path_namespace='" + 2689ced0a38SJae Hyun Yoo std::string(inventoryPath) + "',arg0namespace='" + type + "'", 2696714a25aSJames Feist eventHandler); 2706714a25aSJames Feist matches.emplace_back(std::move(match)); 2716714a25aSJames Feist } 2726714a25aSJames Feist 2736714a25aSJames Feist io.run(); 2746714a25aSJames Feist } 275