blob: 401da120d6ca6ab1160ac7e6e737cceef21a1b14 [file] [log] [blame]
James Feist6714a252018-09-10 15:26:18 -07001/*
2// Copyright (c) 2017 Intel 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
Ed Tanous8a57ec02020-10-09 12:46:52 -070017#include <ADCSensor.hpp>
18#include <Utils.hpp>
19#include <VariantVisitors.hpp>
James Feistb83bb2b2019-05-31 12:31:23 -070020#include <boost/algorithm/string/case_conv.hpp>
James Feist6714a252018-09-10 15:26:18 -070021#include <boost/algorithm/string/predicate.hpp>
22#include <boost/algorithm/string/replace.hpp>
23#include <boost/container/flat_set.hpp>
James Feist38fb5982020-05-28 10:09:54 -070024#include <sdbusplus/asio/connection.hpp>
25#include <sdbusplus/asio/object_server.hpp>
26#include <sdbusplus/bus/match.hpp>
27
James Feist24f02f22019-04-15 11:05:39 -070028#include <filesystem>
James Feist6714a252018-09-10 15:26:18 -070029#include <fstream>
Patrick Venture96e97db2019-10-31 13:44:38 -070030#include <functional>
31#include <memory>
Zhu, Yungea5b1bbc2019-04-09 19:49:36 -040032#include <optional>
James Feist6714a252018-09-10 15:26:18 -070033#include <regex>
Patrick Venture96e97db2019-10-31 13:44:38 -070034#include <string>
35#include <variant>
36#include <vector>
James Feist6714a252018-09-10 15:26:18 -070037
Jeff Lind9cd7042020-11-20 15:49:28 +080038static constexpr float pollRateDefault = 0.5;
Zev Weissf72eb832021-06-25 05:55:08 +000039static constexpr float gpioBridgeSetupTimeDefault = 0.02;
James Feist6714a252018-09-10 15:26:18 -070040
James Feistcf3bce62019-01-08 10:07:19 -080041namespace fs = std::filesystem;
James Feist3eb82622019-02-08 13:10:22 -080042
Brandon Kim66558232021-11-09 16:53:08 -080043static constexpr auto sensorTypes{
44 std::to_array<const char*>({"xyz.openbmc_project.Configuration.ADC"})};
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -070045static std::regex inputRegex(R"(in(\d+)_input)");
James Feist6714a252018-09-10 15:26:18 -070046
James Feistb83bb2b2019-05-31 12:31:23 -070047static boost::container::flat_map<size_t, bool> cpuPresence;
48
Matt Spinler6ad74d92022-03-01 10:56:46 -060049enum class UpdateType
50{
51 init,
52 cpuPresenceChange
53};
54
James Feist08aec6f2019-01-30 16:17:04 -080055// filter out adc from any other voltage sensor
56bool isAdc(const fs::path& parentPath)
57{
58 fs::path namePath = parentPath / "name";
59
60 std::ifstream nameFile(namePath);
61 if (!nameFile.good())
62 {
63 std::cerr << "Failure reading " << namePath.string() << "\n";
64 return false;
65 }
66
67 std::string name;
68 std::getline(nameFile, name);
69
70 return name == "iio_hwmon";
71}
72
James Feist6714a252018-09-10 15:26:18 -070073void createSensors(
74 boost::asio::io_service& io, sdbusplus::asio::object_server& objectServer,
Yong Li1afda6b2020-04-09 19:24:13 +080075 boost::container::flat_map<std::string, std::shared_ptr<ADCSensor>>&
James Feist6714a252018-09-10 15:26:18 -070076 sensors,
77 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection,
James Feist5591cf082020-07-15 16:44:54 -070078 const std::shared_ptr<boost::container::flat_set<std::string>>&
Matt Spinler6ad74d92022-03-01 10:56:46 -060079 sensorsChanged,
80 UpdateType updateType)
James Feist6714a252018-09-10 15:26:18 -070081{
James Feistc71c1192019-09-18 14:31:33 -070082 auto getter = std::make_shared<GetSensorConfiguration>(
83 dbusConnection,
Matt Spinler6ad74d92022-03-01 10:56:46 -060084 [&io, &objectServer, &sensors, &dbusConnection, sensorsChanged,
85 updateType](const ManagedObjectType& sensorConfigurations) {
James Feistc71c1192019-09-18 14:31:33 -070086 bool firstScan = sensorsChanged == nullptr;
87 std::vector<fs::path> paths;
88 if (!findFiles(fs::path("/sys/class/hwmon"), R"(in\d+_input)",
89 paths))
James Feist08aec6f2019-01-30 16:17:04 -080090 {
krishnar4a040ec42021-10-06 16:44:12 +053091 std::cerr << "No adc sensors in system\n";
James Feistc71c1192019-09-18 14:31:33 -070092 return;
93 }
94
95 // iterate through all found adc sensors, and try to match them with
96 // configuration
97 for (auto& path : paths)
98 {
99 if (!isAdc(path.parent_path()))
James Feist08aec6f2019-01-30 16:17:04 -0800100 {
James Feistc71c1192019-09-18 14:31:33 -0700101 continue;
James Feist08aec6f2019-01-30 16:17:04 -0800102 }
James Feistc71c1192019-09-18 14:31:33 -0700103 std::smatch match;
104 std::string pathStr = path.string();
James Feist08aec6f2019-01-30 16:17:04 -0800105
James Feistc71c1192019-09-18 14:31:33 -0700106 std::regex_search(pathStr, match, inputRegex);
107 std::string indexStr = *(match.begin() + 1);
James Feist08aec6f2019-01-30 16:17:04 -0800108
James Feistc71c1192019-09-18 14:31:33 -0700109 auto directory = path.parent_path();
110 // convert to 0 based
111 size_t index = std::stoul(indexStr) - 1;
James Feist08aec6f2019-01-30 16:17:04 -0800112
James Feistc71c1192019-09-18 14:31:33 -0700113 const SensorData* sensorData = nullptr;
114 const std::string* interfacePath = nullptr;
115 const std::pair<
116 std::string,
117 boost::container::flat_map<std::string, BasicVariantType>>*
Ed Tanousa771f6a2022-01-14 09:36:51 -0800118 baseConfiguration = nullptr;
James Feistc71c1192019-09-18 14:31:33 -0700119 for (const std::pair<sdbusplus::message::object_path,
120 SensorData>& sensor : sensorConfigurations)
James Feist6714a252018-09-10 15:26:18 -0700121 {
James Feistc71c1192019-09-18 14:31:33 -0700122 // clear it out each loop
123 baseConfiguration = nullptr;
James Feist6714a252018-09-10 15:26:18 -0700124
James Feistc71c1192019-09-18 14:31:33 -0700125 // find base configuration
126 for (const char* type : sensorTypes)
Jae Hyun Yoo12bbae02019-07-22 17:24:09 -0700127 {
James Feistc71c1192019-09-18 14:31:33 -0700128 auto sensorBase = sensor.second.find(type);
129 if (sensorBase != sensor.second.end())
Jae Hyun Yoo12bbae02019-07-22 17:24:09 -0700130 {
James Feistc71c1192019-09-18 14:31:33 -0700131 baseConfiguration = &(*sensorBase);
132 break;
Jae Hyun Yoo12bbae02019-07-22 17:24:09 -0700133 }
134 }
James Feistc71c1192019-09-18 14:31:33 -0700135 if (baseConfiguration == nullptr)
136 {
137 continue;
138 }
139 auto findIndex = baseConfiguration->second.find("Index");
140 if (findIndex == baseConfiguration->second.end())
141 {
142 std::cerr << "Base configuration missing Index"
143 << baseConfiguration->first << "\n";
144 continue;
145 }
146
147 unsigned int number = std::visit(
148 VariantToUnsignedIntVisitor(), findIndex->second);
149
150 if (number != index)
151 {
152 continue;
153 }
154
155 sensorData = &(sensor.second);
156 interfacePath = &(sensor.first.str);
157 break;
158 }
159 if (sensorData == nullptr)
160 {
161 std::cerr << "failed to find match for " << path.string()
162 << "\n";
163 continue;
Jae Hyun Yoo12bbae02019-07-22 17:24:09 -0700164 }
165
James Feistc71c1192019-09-18 14:31:33 -0700166 if (baseConfiguration == nullptr)
167 {
168 std::cerr << "error finding base configuration for"
169 << path.string() << "\n";
170 continue;
171 }
Jae Hyun Yoo12bbae02019-07-22 17:24:09 -0700172
James Feistc71c1192019-09-18 14:31:33 -0700173 auto findSensorName = baseConfiguration->second.find("Name");
174 if (findSensorName == baseConfiguration->second.end())
175 {
176 std::cerr << "could not determine configuration name for "
177 << path.string() << "\n";
178 continue;
179 }
180 std::string sensorName =
181 std::get<std::string>(findSensorName->second);
182
183 // on rescans, only update sensors we were signaled by
184 auto findSensor = sensors.find(sensorName);
185 if (!firstScan && findSensor != sensors.end())
186 {
187 bool found = false;
188 for (auto it = sensorsChanged->begin();
189 it != sensorsChanged->end(); it++)
190 {
Wludzik, Jozef9a445472020-06-24 12:11:09 +0200191 if (findSensor->second &&
192 boost::ends_with(*it, findSensor->second->name))
James Feistc71c1192019-09-18 14:31:33 -0700193 {
194 sensorsChanged->erase(it);
195 findSensor->second = nullptr;
196 found = true;
197 break;
198 }
199 }
200 if (!found)
201 {
202 continue;
203 }
204 }
Matt Spinler6ad74d92022-03-01 10:56:46 -0600205
206 auto findCPU = baseConfiguration->second.find("CPURequired");
207 if (findCPU != baseConfiguration->second.end())
208 {
209 size_t index =
210 std::visit(VariantToIntVisitor(), findCPU->second);
211 auto presenceFind = cpuPresence.find(index);
212 if (presenceFind == cpuPresence.end())
213 {
214 continue; // no such cpu
215 }
216 if (!presenceFind->second)
217 {
218 continue; // cpu not installed
219 }
220 }
221 else if (updateType == UpdateType::cpuPresenceChange)
222 {
223 continue;
224 }
225
James Feistc71c1192019-09-18 14:31:33 -0700226 std::vector<thresholds::Threshold> sensorThresholds;
227 if (!parseThresholdsFromConfig(*sensorData, sensorThresholds))
228 {
229 std::cerr << "error populating thresholds for "
230 << sensorName << "\n";
231 }
232
233 auto findScaleFactor =
234 baseConfiguration->second.find("ScaleFactor");
235 float scaleFactor = 1.0;
236 if (findScaleFactor != baseConfiguration->second.end())
237 {
238 scaleFactor = std::visit(VariantToFloatVisitor(),
239 findScaleFactor->second);
Zhikui Ren937eb542020-10-12 13:42:08 -0700240 // scaleFactor is used in division
241 if (scaleFactor == 0.0f)
242 {
243 scaleFactor = 1.0;
244 }
James Feistc71c1192019-09-18 14:31:33 -0700245 }
246
Jeff Lind9cd7042020-11-20 15:49:28 +0800247 auto findPollRate = baseConfiguration->second.find("PollRate");
248 float pollRate = pollRateDefault;
249 if (findPollRate != baseConfiguration->second.end())
250 {
251 pollRate = std::visit(VariantToFloatVisitor(),
252 findPollRate->second);
253 if (pollRate <= 0.0f)
254 {
255 pollRate = pollRateDefault; // polling time too short
256 }
257 }
258
James Feistc71c1192019-09-18 14:31:33 -0700259 auto findPowerOn = baseConfiguration->second.find("PowerState");
260 PowerState readState = PowerState::always;
261 if (findPowerOn != baseConfiguration->second.end())
262 {
263 std::string powerState = std::visit(
264 VariantToStringVisitor(), findPowerOn->second);
265 setReadState(powerState, readState);
266 }
267
James Feistc71c1192019-09-18 14:31:33 -0700268 auto& sensor = sensors[sensorName];
269 sensor = nullptr;
270
271 std::optional<BridgeGpio> bridgeGpio;
272 for (const SensorBaseConfiguration& suppConfig : *sensorData)
273 {
274 if (suppConfig.first.find("BridgeGpio") !=
275 std::string::npos)
276 {
277 auto findName = suppConfig.second.find("Name");
278 if (findName != suppConfig.second.end())
279 {
280 std::string gpioName = std::visit(
281 VariantToStringVisitor(), findName->second);
282
283 int polarity = gpiod::line::ACTIVE_HIGH;
284 auto findPolarity =
285 suppConfig.second.find("Polarity");
286 if (findPolarity != suppConfig.second.end())
287 {
288 if (std::string("Low") ==
289 std::visit(VariantToStringVisitor(),
290 findPolarity->second))
291 {
292 polarity = gpiod::line::ACTIVE_LOW;
293 }
294 }
Zev Weissf72eb832021-06-25 05:55:08 +0000295
296 float setupTime = gpioBridgeSetupTimeDefault;
297 auto findSetupTime =
298 suppConfig.second.find("SetupTime");
299 if (findSetupTime != suppConfig.second.end())
300 {
301 setupTime = std::visit(VariantToFloatVisitor(),
302 findSetupTime->second);
303 }
304
305 bridgeGpio =
306 BridgeGpio(gpioName, polarity, setupTime);
James Feistc71c1192019-09-18 14:31:33 -0700307 }
308
309 break;
310 }
311 }
312
Yong Li1afda6b2020-04-09 19:24:13 +0800313 sensor = std::make_shared<ADCSensor>(
James Feistc71c1192019-09-18 14:31:33 -0700314 path.string(), objectServer, dbusConnection, io, sensorName,
Jeff Lind9cd7042020-11-20 15:49:28 +0800315 std::move(sensorThresholds), scaleFactor, pollRate,
316 readState, *interfacePath, std::move(bridgeGpio));
Yong Li1afda6b2020-04-09 19:24:13 +0800317 sensor->setupRead();
James Feistc71c1192019-09-18 14:31:33 -0700318 }
Ed Tanous8a17c302021-09-02 15:07:11 -0700319 });
James Feistc71c1192019-09-18 14:31:33 -0700320
321 getter->getConfiguration(
322 std::vector<std::string>{sensorTypes.begin(), sensorTypes.end()});
James Feist6714a252018-09-10 15:26:18 -0700323}
324
James Feistb6c0b912019-07-09 12:21:44 -0700325int main()
James Feist6714a252018-09-10 15:26:18 -0700326{
327 boost::asio::io_service io;
328 auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
329 systemBus->request_name("xyz.openbmc_project.ADCSensor");
330 sdbusplus::asio::object_server objectServer(systemBus);
Yong Li1afda6b2020-04-09 19:24:13 +0800331 boost::container::flat_map<std::string, std::shared_ptr<ADCSensor>> sensors;
James Feist6714a252018-09-10 15:26:18 -0700332 std::vector<std::unique_ptr<sdbusplus::bus::match::match>> matches;
James Feist5591cf082020-07-15 16:44:54 -0700333 auto sensorsChanged =
334 std::make_shared<boost::container::flat_set<std::string>>();
James Feist6714a252018-09-10 15:26:18 -0700335
336 io.post([&]() {
Matt Spinler6ad74d92022-03-01 10:56:46 -0600337 createSensors(io, objectServer, sensors, systemBus, nullptr,
338 UpdateType::init);
James Feist6714a252018-09-10 15:26:18 -0700339 });
340
341 boost::asio::deadline_timer filterTimer(io);
342 std::function<void(sdbusplus::message::message&)> eventHandler =
343 [&](sdbusplus::message::message& message) {
344 if (message.is_method_error())
345 {
346 std::cerr << "callback method error\n";
347 return;
348 }
349 sensorsChanged->insert(message.get_path());
350 // this implicitly cancels the timer
351 filterTimer.expires_from_now(boost::posix_time::seconds(1));
352
353 filterTimer.async_wait([&](const boost::system::error_code& ec) {
354 if (ec == boost::asio::error::operation_aborted)
355 {
356 /* we were canceled*/
357 return;
358 }
Ed Tanous8a57ec02020-10-09 12:46:52 -0700359 if (ec)
James Feist6714a252018-09-10 15:26:18 -0700360 {
361 std::cerr << "timer error\n";
362 return;
363 }
364 createSensors(io, objectServer, sensors, systemBus,
Matt Spinler6ad74d92022-03-01 10:56:46 -0600365 sensorsChanged, UpdateType::init);
James Feist6714a252018-09-10 15:26:18 -0700366 });
367 };
368
James Feistb83bb2b2019-05-31 12:31:23 -0700369 std::function<void(sdbusplus::message::message&)> cpuPresenceHandler =
370 [&](sdbusplus::message::message& message) {
371 std::string path = message.get_path();
372 boost::to_lower(path);
373
374 if (path.rfind("cpu") == std::string::npos)
375 {
376 return; // not interested
377 }
378 size_t index = 0;
379 try
380 {
381 index = std::stoi(path.substr(path.size() - 1));
382 }
Patrick Williams26601e82021-10-06 12:43:25 -0500383 catch (const std::invalid_argument&)
James Feistb83bb2b2019-05-31 12:31:23 -0700384 {
385 std::cerr << "Found invalid path " << path << "\n";
386 return;
387 }
388
389 std::string objectName;
390 boost::container::flat_map<std::string, std::variant<bool>> values;
391 message.read(objectName, values);
392 auto findPresence = values.find("Present");
393 if (findPresence != values.end())
394 {
395 cpuPresence[index] = std::get<bool>(findPresence->second);
396 }
397
398 // this implicitly cancels the timer
399 filterTimer.expires_from_now(boost::posix_time::seconds(1));
400
401 filterTimer.async_wait([&](const boost::system::error_code& ec) {
402 if (ec == boost::asio::error::operation_aborted)
403 {
404 /* we were canceled*/
405 return;
406 }
Ed Tanous8a57ec02020-10-09 12:46:52 -0700407 if (ec)
James Feistb83bb2b2019-05-31 12:31:23 -0700408 {
409 std::cerr << "timer error\n";
410 return;
411 }
Matt Spinler6ad74d92022-03-01 10:56:46 -0600412 createSensors(io, objectServer, sensors, systemBus, nullptr,
413 UpdateType::cpuPresenceChange);
James Feistb83bb2b2019-05-31 12:31:23 -0700414 });
415 };
416
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700417 for (const char* type : sensorTypes)
James Feist6714a252018-09-10 15:26:18 -0700418 {
419 auto match = std::make_unique<sdbusplus::bus::match::match>(
420 static_cast<sdbusplus::bus::bus&>(*systemBus),
421 "type='signal',member='PropertiesChanged',path_namespace='" +
Jae Hyun Yoo9ced0a32018-10-25 10:42:39 -0700422 std::string(inventoryPath) + "',arg0namespace='" + type + "'",
James Feist6714a252018-09-10 15:26:18 -0700423 eventHandler);
424 matches.emplace_back(std::move(match));
425 }
James Feistb83bb2b2019-05-31 12:31:23 -0700426 matches.emplace_back(std::make_unique<sdbusplus::bus::match::match>(
427 static_cast<sdbusplus::bus::bus&>(*systemBus),
428 "type='signal',member='PropertiesChanged',path_namespace='" +
429 std::string(cpuInventoryPath) +
430 "',arg0namespace='xyz.openbmc_project.Inventory.Item'",
431 cpuPresenceHandler));
James Feist6714a252018-09-10 15:26:18 -0700432
Bruce Lee1263c3d2021-06-04 15:16:33 +0800433 setupManufacturingModeMatch(*systemBus);
James Feist6714a252018-09-10 15:26:18 -0700434 io.run();
435}