blob: 29fd7f47e87b62f3cfe5785e36629e1d12ef8aaa [file] [log] [blame]
James Feist6ef20402019-01-07 16:45:08 -08001/*
2// Copyright (c) 2019 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
17#include "IpmbSensor.hpp"
18
19#include "Utils.hpp"
20#include "VariantVisitors.hpp"
21
22#include <math.h>
23
24#include <boost/algorithm/string.hpp>
25#include <boost/algorithm/string/predicate.hpp>
26#include <boost/algorithm/string/replace.hpp>
Patrick Venture96e97db2019-10-31 13:44:38 -070027#include <boost/container/flat_map.hpp>
James Feist38fb5982020-05-28 10:09:54 -070028#include <sdbusplus/asio/connection.hpp>
29#include <sdbusplus/asio/object_server.hpp>
30#include <sdbusplus/bus/match.hpp>
31
James Feist6ef20402019-01-07 16:45:08 -080032#include <chrono>
Patrick Venture96e97db2019-10-31 13:44:38 -070033#include <functional>
James Feist6ef20402019-01-07 16:45:08 -080034#include <iostream>
35#include <limits>
Patrick Venture96e97db2019-10-31 13:44:38 -070036#include <memory>
James Feist6ef20402019-01-07 16:45:08 -080037#include <numeric>
Patrick Venture96e97db2019-10-31 13:44:38 -070038#include <string>
39#include <tuple>
40#include <variant>
James Feist6ef20402019-01-07 16:45:08 -080041#include <vector>
42
43constexpr const bool debug = false;
44
45constexpr const char* configInterface =
46 "xyz.openbmc_project.Configuration.IpmbSensor";
47static constexpr double ipmbMaxReading = 0xFF;
48static constexpr double ipmbMinReading = 0;
49
50static constexpr uint8_t meAddress = 1;
51static constexpr uint8_t lun = 0;
Anoop S832a2c62020-11-20 19:21:22 +000052static constexpr uint8_t hostSMbusIndexDefault = 0x03;
James Feist6ef20402019-01-07 16:45:08 -080053
Vijay Khemka682a5cb2019-07-18 17:34:03 -070054static constexpr const char* sensorPathPrefix = "/xyz/openbmc_project/sensors/";
55
James Feist6ef20402019-01-07 16:45:08 -080056using IpmbMethodType =
57 std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>;
58
James Feistf7e2c5d2019-02-13 17:27:51 -080059boost::container::flat_map<std::string, std::unique_ptr<IpmbSensor>> sensors;
60
James Feist0d4f2bd2019-03-05 13:15:40 -080061std::unique_ptr<boost::asio::deadline_timer> initCmdTimer;
62
James Feist6ef20402019-01-07 16:45:08 -080063IpmbSensor::IpmbSensor(std::shared_ptr<sdbusplus::asio::connection>& conn,
64 boost::asio::io_service& io,
65 const std::string& sensorName,
66 const std::string& sensorConfiguration,
67 sdbusplus::asio::object_server& objectServer,
68 std::vector<thresholds::Threshold>&& thresholdData,
Anoop S832a2c62020-11-20 19:21:22 +000069 uint8_t deviceAddress, uint8_t hostSMbusIndex,
70 std::string& sensorTypeName) :
James Feist6ef20402019-01-07 16:45:08 -080071 Sensor(boost::replace_all_copy(sensorName, " ", "_"),
James Feist930fcde2019-05-28 12:58:43 -070072 std::move(thresholdData), sensorConfiguration,
73 "xyz.openbmc_project.Configuration.ExitAirTemp", ipmbMaxReading,
James Feiste3338522020-09-15 15:40:30 -070074 ipmbMinReading, conn, PowerState::on),
Anoop S832a2c62020-11-20 19:21:22 +000075 deviceAddress(deviceAddress), hostSMbusIndex(hostSMbusIndex),
76 objectServer(objectServer), waitTimer(io)
James Feist6ef20402019-01-07 16:45:08 -080077{
Vijay Khemka682a5cb2019-07-18 17:34:03 -070078 std::string dbusPath = sensorPathPrefix + sensorTypeName + "/" + name;
79
James Feist6ef20402019-01-07 16:45:08 -080080 sensorInterface = objectServer.add_interface(
Vijay Khemka682a5cb2019-07-18 17:34:03 -070081 dbusPath, "xyz.openbmc_project.Sensor.Value");
James Feist6ef20402019-01-07 16:45:08 -080082
83 if (thresholds::hasWarningInterface(thresholds))
84 {
85 thresholdInterfaceWarning = objectServer.add_interface(
Vijay Khemka682a5cb2019-07-18 17:34:03 -070086 dbusPath, "xyz.openbmc_project.Sensor.Threshold.Warning");
James Feist6ef20402019-01-07 16:45:08 -080087 }
88 if (thresholds::hasCriticalInterface(thresholds))
89 {
90 thresholdInterfaceCritical = objectServer.add_interface(
Vijay Khemka682a5cb2019-07-18 17:34:03 -070091 dbusPath, "xyz.openbmc_project.Sensor.Threshold.Critical");
James Feist6ef20402019-01-07 16:45:08 -080092 }
James Feist2adc95c2019-09-30 14:55:28 -070093 association = objectServer.add_interface(dbusPath, association::interface);
James Feist6ef20402019-01-07 16:45:08 -080094}
95
96IpmbSensor::~IpmbSensor()
97{
98 waitTimer.cancel();
99 objectServer.remove_interface(thresholdInterfaceWarning);
100 objectServer.remove_interface(thresholdInterfaceCritical);
101 objectServer.remove_interface(sensorInterface);
James Feist078f2322019-03-08 11:09:05 -0800102 objectServer.remove_interface(association);
James Feist6ef20402019-01-07 16:45:08 -0800103}
104
105void IpmbSensor::init(void)
106{
James Feist6ef20402019-01-07 16:45:08 -0800107 loadDefaults();
Adrian Ambrożewicz45e92772020-06-04 13:59:55 +0200108 setInitialProperties(dbusConnection);
James Feist6ef20402019-01-07 16:45:08 -0800109 if (initCommand)
110 {
James Feistf7e2c5d2019-02-13 17:27:51 -0800111 runInitCmd();
112 }
113 read();
114}
115
116void IpmbSensor::runInitCmd()
117{
118 if (initCommand)
119 {
James Feist6ef20402019-01-07 16:45:08 -0800120 dbusConnection->async_method_call(
121 [this](boost::system::error_code ec,
122 const IpmbMethodType& response) {
123 const int& status = std::get<0>(response);
124
125 if (ec || status)
126 {
127 std::cerr
128 << "Error setting init command for device: " << name
129 << "\n";
130 }
James Feist6ef20402019-01-07 16:45:08 -0800131 },
132 "xyz.openbmc_project.Ipmi.Channel.Ipmb",
133 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb",
134 "sendRequest", commandAddress, netfn, lun, *initCommand, initData);
135 }
James Feist6ef20402019-01-07 16:45:08 -0800136}
137
138void IpmbSensor::loadDefaults()
139{
140 if (type == IpmbType::meSensor)
141 {
142 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200143 netfn = ipmi::sensor::netFn;
144 command = ipmi::sensor::getSensorReading;
James Feist6ef20402019-01-07 16:45:08 -0800145 commandData = {deviceAddress};
James Feistd7ae29a2020-06-25 15:42:46 -0700146 readingFormat = ReadingFormat::byte0;
James Feist6ef20402019-01-07 16:45:08 -0800147 }
148 else if (type == IpmbType::PXE1410CVR)
149 {
150 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200151 netfn = ipmi::me_bridge::netFn;
152 command = ipmi::me_bridge::sendRawPmbus;
153 initCommand = ipmi::me_bridge::sendRawPmbus;
James Feistd7ae29a2020-06-25 15:42:46 -0700154 // pmbus read temp
Anoop S832a2c62020-11-20 19:21:22 +0000155 commandData = {0x57, 0x01, 0x00, 0x16, hostSMbusIndex,
156 deviceAddress, 0x00, 0x00, 0x00, 0x00,
157 0x01, 0x02, 0x8d};
James Feistd7ae29a2020-06-25 15:42:46 -0700158 // goto page 0
Anoop S832a2c62020-11-20 19:21:22 +0000159 initData = {0x57, 0x01, 0x00, 0x14, hostSMbusIndex,
160 deviceAddress, 0x00, 0x00, 0x00, 0x00,
161 0x02, 0x00, 0x00, 0x00};
James Feiste4a970d2020-08-19 11:21:58 -0700162 readingFormat = ReadingFormat::elevenBit;
James Feist6ef20402019-01-07 16:45:08 -0800163 }
164 else if (type == IpmbType::IR38363VR)
165 {
166 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200167 netfn = ipmi::me_bridge::netFn;
168 command = ipmi::me_bridge::sendRawPmbus;
James Feistd7ae29a2020-06-25 15:42:46 -0700169 // pmbus read temp
Anoop S832a2c62020-11-20 19:21:22 +0000170 commandData = {0x57, 0x01, 0x00, 0x16, hostSMbusIndex,
171 deviceAddress, 00, 0x00, 0x00, 0x00,
172 0x01, 0x02, 0x8D};
James Feistd7ae29a2020-06-25 15:42:46 -0700173 readingFormat = ReadingFormat::elevenBitShift;
James Feist6ef20402019-01-07 16:45:08 -0800174 }
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700175 else if (type == IpmbType::ADM1278HSC)
176 {
177 commandAddress = meAddress;
178 switch (subType)
179 {
180 case IpmbSubType::temp:
181 case IpmbSubType::curr:
182 uint8_t snsNum;
183 if (subType == IpmbSubType::temp)
184 snsNum = 0x8d;
185 else
186 snsNum = 0x8c;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200187 netfn = ipmi::me_bridge::netFn;
188 command = ipmi::me_bridge::sendRawPmbus;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700189 commandData = {0x57, 0x01, 0x00, 0x86, deviceAddress,
190 0x00, 0x00, 0x01, 0x02, snsNum};
James Feistd7ae29a2020-06-25 15:42:46 -0700191 readingFormat = ReadingFormat::elevenBit;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700192 break;
193 case IpmbSubType::power:
194 case IpmbSubType::volt:
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200195 netfn = ipmi::sensor::netFn;
196 command = ipmi::sensor::getSensorReading;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700197 commandData = {deviceAddress};
James Feistd7ae29a2020-06-25 15:42:46 -0700198 readingFormat = ReadingFormat::byte0;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700199 break;
200 default:
201 throw std::runtime_error("Invalid sensor type");
202 }
203 }
James Feist6ef20402019-01-07 16:45:08 -0800204 else if (type == IpmbType::mpsVR)
205 {
206 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200207 netfn = ipmi::me_bridge::netFn;
208 command = ipmi::me_bridge::sendRawPmbus;
209 initCommand = ipmi::me_bridge::sendRawPmbus;
James Feistd7ae29a2020-06-25 15:42:46 -0700210 // pmbus read temp
Anoop S832a2c62020-11-20 19:21:22 +0000211 commandData = {0x57, 0x01, 0x00, 0x16, hostSMbusIndex,
212 deviceAddress, 0x00, 0x00, 0x00, 0x00,
213 0x01, 0x02, 0x8d};
James Feistd7ae29a2020-06-25 15:42:46 -0700214 // goto page 0
Anoop S832a2c62020-11-20 19:21:22 +0000215 initData = {0x57, 0x01, 0x00, 0x14, hostSMbusIndex,
216 deviceAddress, 0x00, 0x00, 0x00, 0x00,
217 0x02, 0x00, 0x00, 0x00};
James Feistd7ae29a2020-06-25 15:42:46 -0700218 readingFormat = ReadingFormat::byte3;
James Feist6ef20402019-01-07 16:45:08 -0800219 }
220 else
221 {
222 throw std::runtime_error("Invalid sensor type");
223 }
Adrian Ambrożewicz45e92772020-06-04 13:59:55 +0200224
225 if (subType == IpmbSubType::util)
226 {
227 // Utilization need to be scaled to percent
228 maxValue = 100;
229 minValue = 0;
230 }
James Feist6ef20402019-01-07 16:45:08 -0800231}
232
233void IpmbSensor::checkThresholds(void)
234{
James Feist6ef20402019-01-07 16:45:08 -0800235 thresholds::checkThresholds(this);
236}
237
James Feist961bf092020-07-01 16:38:12 -0700238bool IpmbSensor::processReading(const std::vector<uint8_t>& data, double& resp)
James Feistd7ae29a2020-06-25 15:42:46 -0700239{
240
241 switch (readingFormat)
242 {
243 case (ReadingFormat::byte0):
James Feiste4a970d2020-08-19 11:21:58 -0700244 {
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200245 if (command == ipmi::sensor::getSensorReading &&
246 !ipmi::sensor::isValid(data))
James Feistcf4238e2020-07-28 16:40:03 -0700247 {
248 return false;
249 }
James Feist961bf092020-07-01 16:38:12 -0700250 resp = data[0];
251 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700252 }
James Feistd7ae29a2020-06-25 15:42:46 -0700253 case (ReadingFormat::byte3):
James Feiste4a970d2020-08-19 11:21:58 -0700254 {
James Feistd7ae29a2020-06-25 15:42:46 -0700255 if (data.size() < 4)
256 {
James Feist961bf092020-07-01 16:38:12 -0700257 if (!errCount)
258 {
259 std::cerr << "Invalid data length returned for " << name
260 << "\n";
261 }
262 return false;
James Feistd7ae29a2020-06-25 15:42:46 -0700263 }
James Feist961bf092020-07-01 16:38:12 -0700264 resp = data[3];
265 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700266 }
James Feistd7ae29a2020-06-25 15:42:46 -0700267 case (ReadingFormat::elevenBit):
James Feiste4a970d2020-08-19 11:21:58 -0700268 {
James Feistd7ae29a2020-06-25 15:42:46 -0700269 if (data.size() < 5)
270 {
James Feist961bf092020-07-01 16:38:12 -0700271 if (!errCount)
272 {
273 std::cerr << "Invalid data length returned for " << name
274 << "\n";
275 }
276 return false;
James Feistd7ae29a2020-06-25 15:42:46 -0700277 }
278
James Feiste4a970d2020-08-19 11:21:58 -0700279 int16_t value = ((data[4] << 8) | data[3]);
280 constexpr const size_t shift = 16 - 11; // 11bit into 16bit
281 value <<= shift;
282 value >>= shift;
283 resp = value;
James Feist961bf092020-07-01 16:38:12 -0700284 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700285 }
James Feistd7ae29a2020-06-25 15:42:46 -0700286 case (ReadingFormat::elevenBitShift):
James Feiste4a970d2020-08-19 11:21:58 -0700287 {
James Feistd7ae29a2020-06-25 15:42:46 -0700288 if (data.size() < 5)
289 {
James Feist961bf092020-07-01 16:38:12 -0700290 if (!errCount)
291 {
292 std::cerr << "Invalid data length returned for " << name
293 << "\n";
294 }
295 return false;
James Feistd7ae29a2020-06-25 15:42:46 -0700296 }
297
James Feist961bf092020-07-01 16:38:12 -0700298 resp = ((data[4] << 8) | data[3]) >> 3;
299 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700300 }
James Feistd7ae29a2020-06-25 15:42:46 -0700301 default:
302 throw std::runtime_error("Invalid reading type");
303 }
304}
305
James Feist6ef20402019-01-07 16:45:08 -0800306void IpmbSensor::read(void)
307{
308 static constexpr size_t pollTime = 1; // in seconds
309
310 waitTimer.expires_from_now(boost::posix_time::seconds(pollTime));
311 waitTimer.async_wait([this](const boost::system::error_code& ec) {
312 if (ec == boost::asio::error::operation_aborted)
313 {
314 return; // we're being canceled
315 }
Adrian Ambrożewicz623723b2020-07-29 12:53:54 +0200316 if (!readingStateGood())
James Feist6ef20402019-01-07 16:45:08 -0800317 {
Adrian Ambrożewicz623723b2020-07-29 12:53:54 +0200318 updateValue(std::numeric_limits<double>::quiet_NaN());
James Feist6ef20402019-01-07 16:45:08 -0800319 read();
320 return;
321 }
322 dbusConnection->async_method_call(
323 [this](boost::system::error_code ec,
324 const IpmbMethodType& response) {
325 const int& status = std::get<0>(response);
326 if (ec || status)
327 {
James Feist961bf092020-07-01 16:38:12 -0700328 incrementError();
James Feist6ef20402019-01-07 16:45:08 -0800329 read();
330 return;
331 }
332 const std::vector<uint8_t>& data = std::get<5>(response);
333 if constexpr (debug)
334 {
335 std::cout << name << ": ";
336 for (size_t d : data)
337 {
338 std::cout << d << " ";
339 }
340 std::cout << "\n";
341 }
James Feistd7ae29a2020-06-25 15:42:46 -0700342 if (data.empty())
James Feist6ef20402019-01-07 16:45:08 -0800343 {
James Feist961bf092020-07-01 16:38:12 -0700344 incrementError();
James Feistd7ae29a2020-06-25 15:42:46 -0700345 read();
346 return;
James Feist6ef20402019-01-07 16:45:08 -0800347 }
James Feist961bf092020-07-01 16:38:12 -0700348
349 double value = 0;
350
351 if (!processReading(data, value))
352 {
353 incrementError();
354 read();
355 return;
356 }
Zhikui Rend3da1282020-09-11 17:02:01 -0700357 else
358 {
359 // rawValue only used in debug logging
360 // up to 5th byte in data are used to derive value
361 size_t end = std::min(sizeof(uint64_t), data.size());
362 uint64_t rawData = 0;
363 for (size_t i = 0; i < end; i++)
364 {
365 reinterpret_cast<uint8_t*>(&rawData)[i] = data[i];
366 }
367 rawValue = static_cast<double>(rawData);
368 }
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700369
370 /* Adjust value as per scale and offset */
371 value = (value * scaleVal) + offsetVal;
James Feist6ef20402019-01-07 16:45:08 -0800372 updateValue(value);
373 read();
374 },
375 "xyz.openbmc_project.Ipmi.Channel.Ipmb",
376 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb",
377 "sendRequest", commandAddress, netfn, lun, command, commandData);
378 });
379}
380void createSensors(
381 boost::asio::io_service& io, sdbusplus::asio::object_server& objectServer,
382 boost::container::flat_map<std::string, std::unique_ptr<IpmbSensor>>&
383 sensors,
384 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection)
385{
386 if (!dbusConnection)
387 {
388 std::cerr << "Connection not created\n";
389 return;
390 }
391 dbusConnection->async_method_call(
392 [&](boost::system::error_code ec, const ManagedObjectType& resp) {
393 if (ec)
394 {
395 std::cerr << "Error contacting entity manager\n";
396 return;
397 }
398 for (const auto& pathPair : resp)
399 {
400 for (const auto& entry : pathPair.second)
401 {
402 if (entry.first != configInterface)
403 {
404 continue;
405 }
406 std::string name =
407 loadVariant<std::string>(entry.second, "Name");
408
409 std::vector<thresholds::Threshold> sensorThresholds;
410 if (!parseThresholdsFromConfig(pathPair.second,
411 sensorThresholds))
412 {
413 std::cerr << "error populating thresholds for " << name
414 << "\n";
415 }
416 uint8_t deviceAddress =
417 loadVariant<uint8_t>(entry.second, "Address");
418
419 std::string sensorClass =
420 loadVariant<std::string>(entry.second, "Class");
Anoop S832a2c62020-11-20 19:21:22 +0000421 uint8_t hostSMbusIndex = hostSMbusIndexDefault;
422 auto findSmType = entry.second.find("HostSMbusIndex");
423 if (findSmType != entry.second.end())
424 {
425 hostSMbusIndex = std::visit(
426 VariantToUnsignedIntVisitor(), findSmType->second);
427 }
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700428
429 /* Default sensor type is "temperature" */
430 std::string sensorTypeName = "temperature";
431 auto findType = entry.second.find("SensorType");
432 if (findType != entry.second.end())
433 {
434 sensorTypeName = std::visit(VariantToStringVisitor(),
435 findType->second);
436 }
437
James Feist6ef20402019-01-07 16:45:08 -0800438 auto& sensor = sensors[name];
439 sensor = std::make_unique<IpmbSensor>(
440 dbusConnection, io, name, pathPair.first, objectServer,
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700441 std::move(sensorThresholds), deviceAddress,
Anoop S832a2c62020-11-20 19:21:22 +0000442 hostSMbusIndex, sensorTypeName);
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700443
444 /* Initialize scale and offset value */
445 sensor->scaleVal = 1;
446 sensor->offsetVal = 0;
447
448 auto findScaleVal = entry.second.find("ScaleValue");
449 if (findScaleVal != entry.second.end())
450 {
451 sensor->scaleVal = std::visit(VariantToDoubleVisitor(),
452 findScaleVal->second);
453 }
454
455 auto findOffsetVal = entry.second.find("OffsetValue");
456 if (findOffsetVal != entry.second.end())
457 {
458 sensor->offsetVal = std::visit(VariantToDoubleVisitor(),
459 findOffsetVal->second);
460 }
James Feist6ef20402019-01-07 16:45:08 -0800461
James Feistfc94b212019-02-06 16:14:51 -0800462 auto findPowerState = entry.second.find("PowerState");
463
464 if (findPowerState != entry.second.end())
465 {
466 std::string powerState = std::visit(
467 VariantToStringVisitor(), findPowerState->second);
468
469 setReadState(powerState, sensor->readState);
470 }
471
James Feist6ef20402019-01-07 16:45:08 -0800472 if (sensorClass == "PxeBridgeTemp")
473 {
474 sensor->type = IpmbType::PXE1410CVR;
475 }
476 else if (sensorClass == "IRBridgeTemp")
477 {
478 sensor->type = IpmbType::IR38363VR;
479 }
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700480 else if (sensorClass == "HSCBridge")
481 {
482 sensor->type = IpmbType::ADM1278HSC;
483 }
James Feist6ef20402019-01-07 16:45:08 -0800484 else if (sensorClass == "MpsBridgeTemp")
485 {
486 sensor->type = IpmbType::mpsVR;
487 }
Adrian Ambrożewicz45e92772020-06-04 13:59:55 +0200488 else if (sensorClass == "METemp" ||
489 sensorClass == "MESensor")
James Feist6ef20402019-01-07 16:45:08 -0800490 {
491 sensor->type = IpmbType::meSensor;
492 }
493 else
494 {
495 std::cerr << "Invalid class " << sensorClass << "\n";
496 continue;
497 }
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700498
499 if (sensorTypeName == "voltage")
500 {
501 sensor->subType = IpmbSubType::volt;
502 }
503 else if (sensorTypeName == "power")
504 {
505 sensor->subType = IpmbSubType::power;
506 }
507 else if (sensorTypeName == "current")
508 {
509 sensor->subType = IpmbSubType::curr;
510 }
Adrian Ambrożewicz45e92772020-06-04 13:59:55 +0200511 else if (sensorTypeName == "utilization")
512 {
513 sensor->subType = IpmbSubType::util;
514 }
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700515 else
516 {
517 sensor->subType = IpmbSubType::temp;
518 }
James Feist6ef20402019-01-07 16:45:08 -0800519 sensor->init();
520 }
521 }
522 },
523 entityManagerName, "/", "org.freedesktop.DBus.ObjectManager",
524 "GetManagedObjects");
525}
526
James Feistf7e2c5d2019-02-13 17:27:51 -0800527void reinitSensors(sdbusplus::message::message& message)
528{
James Feist0d4f2bd2019-03-05 13:15:40 -0800529 constexpr const size_t reinitWaitSeconds = 2;
James Feistf7e2c5d2019-02-13 17:27:51 -0800530 std::string objectName;
James Feist52497fd2019-06-07 13:01:33 -0700531 boost::container::flat_map<std::string, std::variant<std::string>> values;
James Feistf7e2c5d2019-02-13 17:27:51 -0800532 message.read(objectName, values);
James Feist0d4f2bd2019-03-05 13:15:40 -0800533
James Feist52497fd2019-06-07 13:01:33 -0700534 auto findStatus = values.find(power::property);
535 if (findStatus != values.end())
James Feistf7e2c5d2019-02-13 17:27:51 -0800536 {
James Feist52497fd2019-06-07 13:01:33 -0700537 bool powerStatus = boost::ends_with(
538 std::get<std::string>(findStatus->second), "Running");
James Feistf7e2c5d2019-02-13 17:27:51 -0800539 if (powerStatus)
540 {
James Feist0d4f2bd2019-03-05 13:15:40 -0800541 if (!initCmdTimer)
James Feistf7e2c5d2019-02-13 17:27:51 -0800542 {
James Feist0d4f2bd2019-03-05 13:15:40 -0800543 // this should be impossible
544 return;
James Feistf7e2c5d2019-02-13 17:27:51 -0800545 }
James Feist0d4f2bd2019-03-05 13:15:40 -0800546 // we seem to send this command too fast sometimes, wait before
547 // sending
548 initCmdTimer->expires_from_now(
549 boost::posix_time::seconds(reinitWaitSeconds));
550
551 initCmdTimer->async_wait([](const boost::system::error_code ec) {
552 if (ec == boost::asio::error::operation_aborted)
553 {
554 return; // we're being canceled
555 }
556
557 for (const auto& sensor : sensors)
558 {
559 if (sensor.second)
560 {
561 sensor.second->runInitCmd();
562 }
563 }
564 });
James Feistf7e2c5d2019-02-13 17:27:51 -0800565 }
566 }
567}
568
James Feistb6c0b912019-07-09 12:21:44 -0700569int main()
James Feist6ef20402019-01-07 16:45:08 -0800570{
571
572 boost::asio::io_service io;
573 auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
574 systemBus->request_name("xyz.openbmc_project.IpmbSensor");
575 sdbusplus::asio::object_server objectServer(systemBus);
James Feist6ef20402019-01-07 16:45:08 -0800576
James Feist0d4f2bd2019-03-05 13:15:40 -0800577 initCmdTimer = std::make_unique<boost::asio::deadline_timer>(io);
578
James Feist6ef20402019-01-07 16:45:08 -0800579 io.post([&]() { createSensors(io, objectServer, sensors, systemBus); });
580
581 boost::asio::deadline_timer configTimer(io);
582
583 std::function<void(sdbusplus::message::message&)> eventHandler =
James Feistb6c0b912019-07-09 12:21:44 -0700584 [&](sdbusplus::message::message&) {
James Feist6ef20402019-01-07 16:45:08 -0800585 configTimer.expires_from_now(boost::posix_time::seconds(1));
586 // create a timer because normally multiple properties change
587 configTimer.async_wait([&](const boost::system::error_code& ec) {
588 if (ec == boost::asio::error::operation_aborted)
589 {
590 return; // we're being canceled
591 }
592 createSensors(io, objectServer, sensors, systemBus);
593 if (sensors.empty())
594 {
595 std::cout << "Configuration not detected\n";
596 }
597 });
598 };
599
James Feistf7e2c5d2019-02-13 17:27:51 -0800600 sdbusplus::bus::match::match configMatch(
James Feist6ef20402019-01-07 16:45:08 -0800601 static_cast<sdbusplus::bus::bus&>(*systemBus),
602 "type='signal',member='PropertiesChanged',path_namespace='" +
603 std::string(inventoryPath) + "',arg0namespace='" + configInterface +
604 "'",
605 eventHandler);
606
James Feistf7e2c5d2019-02-13 17:27:51 -0800607 sdbusplus::bus::match::match powerChangeMatch(
608 static_cast<sdbusplus::bus::bus&>(*systemBus),
James Feist52497fd2019-06-07 13:01:33 -0700609 "type='signal',interface='" + std::string(properties::interface) +
610 "',path='" + std::string(power::path) + "',arg0='" +
611 std::string(power::interface) + "'",
James Feistf7e2c5d2019-02-13 17:27:51 -0800612 reinitSensors);
613
James Feist6ef20402019-01-07 16:45:08 -0800614 io.run();
615}