blob: dccdffb65943aa1f3f63cefee8044154613d8c8f [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;
52
Vijay Khemka682a5cb2019-07-18 17:34:03 -070053static constexpr const char* sensorPathPrefix = "/xyz/openbmc_project/sensors/";
54
James Feist6ef20402019-01-07 16:45:08 -080055using IpmbMethodType =
56 std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>;
57
James Feistf7e2c5d2019-02-13 17:27:51 -080058boost::container::flat_map<std::string, std::unique_ptr<IpmbSensor>> sensors;
59
James Feist0d4f2bd2019-03-05 13:15:40 -080060std::unique_ptr<boost::asio::deadline_timer> initCmdTimer;
61
James Feist6ef20402019-01-07 16:45:08 -080062IpmbSensor::IpmbSensor(std::shared_ptr<sdbusplus::asio::connection>& conn,
63 boost::asio::io_service& io,
64 const std::string& sensorName,
65 const std::string& sensorConfiguration,
66 sdbusplus::asio::object_server& objectServer,
67 std::vector<thresholds::Threshold>&& thresholdData,
Vijay Khemka682a5cb2019-07-18 17:34:03 -070068 uint8_t deviceAddress, std::string& sensorTypeName) :
James Feist6ef20402019-01-07 16:45:08 -080069 Sensor(boost::replace_all_copy(sensorName, " ", "_"),
James Feist930fcde2019-05-28 12:58:43 -070070 std::move(thresholdData), sensorConfiguration,
71 "xyz.openbmc_project.Configuration.ExitAirTemp", ipmbMaxReading,
James Feiste3338522020-09-15 15:40:30 -070072 ipmbMinReading, conn, PowerState::on),
73 deviceAddress(deviceAddress), objectServer(objectServer), waitTimer(io)
James Feist6ef20402019-01-07 16:45:08 -080074{
Vijay Khemka682a5cb2019-07-18 17:34:03 -070075 std::string dbusPath = sensorPathPrefix + sensorTypeName + "/" + name;
76
James Feist6ef20402019-01-07 16:45:08 -080077 sensorInterface = objectServer.add_interface(
Vijay Khemka682a5cb2019-07-18 17:34:03 -070078 dbusPath, "xyz.openbmc_project.Sensor.Value");
James Feist6ef20402019-01-07 16:45:08 -080079
80 if (thresholds::hasWarningInterface(thresholds))
81 {
82 thresholdInterfaceWarning = objectServer.add_interface(
Vijay Khemka682a5cb2019-07-18 17:34:03 -070083 dbusPath, "xyz.openbmc_project.Sensor.Threshold.Warning");
James Feist6ef20402019-01-07 16:45:08 -080084 }
85 if (thresholds::hasCriticalInterface(thresholds))
86 {
87 thresholdInterfaceCritical = objectServer.add_interface(
Vijay Khemka682a5cb2019-07-18 17:34:03 -070088 dbusPath, "xyz.openbmc_project.Sensor.Threshold.Critical");
James Feist6ef20402019-01-07 16:45:08 -080089 }
James Feist2adc95c2019-09-30 14:55:28 -070090 association = objectServer.add_interface(dbusPath, association::interface);
James Feist6ef20402019-01-07 16:45:08 -080091}
92
93IpmbSensor::~IpmbSensor()
94{
95 waitTimer.cancel();
96 objectServer.remove_interface(thresholdInterfaceWarning);
97 objectServer.remove_interface(thresholdInterfaceCritical);
98 objectServer.remove_interface(sensorInterface);
James Feist078f2322019-03-08 11:09:05 -080099 objectServer.remove_interface(association);
James Feist6ef20402019-01-07 16:45:08 -0800100}
101
102void IpmbSensor::init(void)
103{
James Feist6ef20402019-01-07 16:45:08 -0800104 loadDefaults();
Adrian Ambrożewicz45e92772020-06-04 13:59:55 +0200105 setInitialProperties(dbusConnection);
James Feist6ef20402019-01-07 16:45:08 -0800106 if (initCommand)
107 {
James Feistf7e2c5d2019-02-13 17:27:51 -0800108 runInitCmd();
109 }
110 read();
111}
112
113void IpmbSensor::runInitCmd()
114{
115 if (initCommand)
116 {
James Feist6ef20402019-01-07 16:45:08 -0800117 dbusConnection->async_method_call(
118 [this](boost::system::error_code ec,
119 const IpmbMethodType& response) {
120 const int& status = std::get<0>(response);
121
122 if (ec || status)
123 {
124 std::cerr
125 << "Error setting init command for device: " << name
126 << "\n";
127 }
James Feist6ef20402019-01-07 16:45:08 -0800128 },
129 "xyz.openbmc_project.Ipmi.Channel.Ipmb",
130 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb",
131 "sendRequest", commandAddress, netfn, lun, *initCommand, initData);
132 }
James Feist6ef20402019-01-07 16:45:08 -0800133}
134
135void IpmbSensor::loadDefaults()
136{
137 if (type == IpmbType::meSensor)
138 {
139 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200140 netfn = ipmi::sensor::netFn;
141 command = ipmi::sensor::getSensorReading;
James Feist6ef20402019-01-07 16:45:08 -0800142 commandData = {deviceAddress};
James Feistd7ae29a2020-06-25 15:42:46 -0700143 readingFormat = ReadingFormat::byte0;
James Feist6ef20402019-01-07 16:45:08 -0800144 }
145 else if (type == IpmbType::PXE1410CVR)
146 {
147 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200148 netfn = ipmi::me_bridge::netFn;
149 command = ipmi::me_bridge::sendRawPmbus;
150 initCommand = ipmi::me_bridge::sendRawPmbus;
James Feistd7ae29a2020-06-25 15:42:46 -0700151 // pmbus read temp
152 commandData = {0x57, 0x01, 0x00, 0x16, 0x3, deviceAddress, 0x00,
153 0x00, 0x00, 0x00, 0x01, 0x02, 0x8d};
154 // goto page 0
James Feist6ef20402019-01-07 16:45:08 -0800155 initData = {0x57, 0x01, 0x00, 0x14, 0x03, deviceAddress, 0x00,
James Feistd7ae29a2020-06-25 15:42:46 -0700156 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00};
James Feiste4a970d2020-08-19 11:21:58 -0700157 readingFormat = ReadingFormat::elevenBit;
James Feist6ef20402019-01-07 16:45:08 -0800158 }
159 else if (type == IpmbType::IR38363VR)
160 {
161 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200162 netfn = ipmi::me_bridge::netFn;
163 command = ipmi::me_bridge::sendRawPmbus;
James Feistd7ae29a2020-06-25 15:42:46 -0700164 // pmbus read temp
James Feist6ef20402019-01-07 16:45:08 -0800165 commandData = {0x57, 0x01, 0x00, 0x16, 0x03, deviceAddress, 00,
166 0x00, 0x00, 0x00, 0x01, 0x02, 0x8D};
James Feistd7ae29a2020-06-25 15:42:46 -0700167 readingFormat = ReadingFormat::elevenBitShift;
James Feist6ef20402019-01-07 16:45:08 -0800168 }
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700169 else if (type == IpmbType::ADM1278HSC)
170 {
171 commandAddress = meAddress;
172 switch (subType)
173 {
174 case IpmbSubType::temp:
175 case IpmbSubType::curr:
176 uint8_t snsNum;
177 if (subType == IpmbSubType::temp)
178 snsNum = 0x8d;
179 else
180 snsNum = 0x8c;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200181 netfn = ipmi::me_bridge::netFn;
182 command = ipmi::me_bridge::sendRawPmbus;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700183 commandData = {0x57, 0x01, 0x00, 0x86, deviceAddress,
184 0x00, 0x00, 0x01, 0x02, snsNum};
James Feistd7ae29a2020-06-25 15:42:46 -0700185 readingFormat = ReadingFormat::elevenBit;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700186 break;
187 case IpmbSubType::power:
188 case IpmbSubType::volt:
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200189 netfn = ipmi::sensor::netFn;
190 command = ipmi::sensor::getSensorReading;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700191 commandData = {deviceAddress};
James Feistd7ae29a2020-06-25 15:42:46 -0700192 readingFormat = ReadingFormat::byte0;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700193 break;
194 default:
195 throw std::runtime_error("Invalid sensor type");
196 }
197 }
James Feist6ef20402019-01-07 16:45:08 -0800198 else if (type == IpmbType::mpsVR)
199 {
200 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200201 netfn = ipmi::me_bridge::netFn;
202 command = ipmi::me_bridge::sendRawPmbus;
203 initCommand = ipmi::me_bridge::sendRawPmbus;
James Feistd7ae29a2020-06-25 15:42:46 -0700204 // pmbus read temp
James Feist6ef20402019-01-07 16:45:08 -0800205 commandData = {0x57, 0x01, 0x00, 0x16, 0x3, deviceAddress, 0x00,
206 0x00, 0x00, 0x00, 0x01, 0x02, 0x8d};
James Feistd7ae29a2020-06-25 15:42:46 -0700207 // goto page 0
James Feist6ef20402019-01-07 16:45:08 -0800208 initData = {0x57, 0x01, 0x00, 0x14, 0x03, deviceAddress, 0x00,
209 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00};
James Feistd7ae29a2020-06-25 15:42:46 -0700210 readingFormat = ReadingFormat::byte3;
James Feist6ef20402019-01-07 16:45:08 -0800211 }
212 else
213 {
214 throw std::runtime_error("Invalid sensor type");
215 }
Adrian Ambrożewicz45e92772020-06-04 13:59:55 +0200216
217 if (subType == IpmbSubType::util)
218 {
219 // Utilization need to be scaled to percent
220 maxValue = 100;
221 minValue = 0;
222 }
James Feist6ef20402019-01-07 16:45:08 -0800223}
224
225void IpmbSensor::checkThresholds(void)
226{
James Feist6ef20402019-01-07 16:45:08 -0800227 thresholds::checkThresholds(this);
228}
229
James Feist961bf092020-07-01 16:38:12 -0700230bool IpmbSensor::processReading(const std::vector<uint8_t>& data, double& resp)
James Feistd7ae29a2020-06-25 15:42:46 -0700231{
232
233 switch (readingFormat)
234 {
235 case (ReadingFormat::byte0):
James Feiste4a970d2020-08-19 11:21:58 -0700236 {
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200237 if (command == ipmi::sensor::getSensorReading &&
238 !ipmi::sensor::isValid(data))
James Feistcf4238e2020-07-28 16:40:03 -0700239 {
240 return false;
241 }
James Feist961bf092020-07-01 16:38:12 -0700242 resp = data[0];
243 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700244 }
James Feistd7ae29a2020-06-25 15:42:46 -0700245 case (ReadingFormat::byte3):
James Feiste4a970d2020-08-19 11:21:58 -0700246 {
James Feistd7ae29a2020-06-25 15:42:46 -0700247 if (data.size() < 4)
248 {
James Feist961bf092020-07-01 16:38:12 -0700249 if (!errCount)
250 {
251 std::cerr << "Invalid data length returned for " << name
252 << "\n";
253 }
254 return false;
James Feistd7ae29a2020-06-25 15:42:46 -0700255 }
James Feist961bf092020-07-01 16:38:12 -0700256 resp = data[3];
257 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700258 }
James Feistd7ae29a2020-06-25 15:42:46 -0700259 case (ReadingFormat::elevenBit):
James Feiste4a970d2020-08-19 11:21:58 -0700260 {
James Feistd7ae29a2020-06-25 15:42:46 -0700261 if (data.size() < 5)
262 {
James Feist961bf092020-07-01 16:38:12 -0700263 if (!errCount)
264 {
265 std::cerr << "Invalid data length returned for " << name
266 << "\n";
267 }
268 return false;
James Feistd7ae29a2020-06-25 15:42:46 -0700269 }
270
James Feiste4a970d2020-08-19 11:21:58 -0700271 int16_t value = ((data[4] << 8) | data[3]);
272 constexpr const size_t shift = 16 - 11; // 11bit into 16bit
273 value <<= shift;
274 value >>= shift;
275 resp = value;
James Feist961bf092020-07-01 16:38:12 -0700276 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700277 }
James Feistd7ae29a2020-06-25 15:42:46 -0700278 case (ReadingFormat::elevenBitShift):
James Feiste4a970d2020-08-19 11:21:58 -0700279 {
James Feistd7ae29a2020-06-25 15:42:46 -0700280 if (data.size() < 5)
281 {
James Feist961bf092020-07-01 16:38:12 -0700282 if (!errCount)
283 {
284 std::cerr << "Invalid data length returned for " << name
285 << "\n";
286 }
287 return false;
James Feistd7ae29a2020-06-25 15:42:46 -0700288 }
289
James Feist961bf092020-07-01 16:38:12 -0700290 resp = ((data[4] << 8) | data[3]) >> 3;
291 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700292 }
James Feistd7ae29a2020-06-25 15:42:46 -0700293 default:
294 throw std::runtime_error("Invalid reading type");
295 }
296}
297
James Feist6ef20402019-01-07 16:45:08 -0800298void IpmbSensor::read(void)
299{
300 static constexpr size_t pollTime = 1; // in seconds
301
302 waitTimer.expires_from_now(boost::posix_time::seconds(pollTime));
303 waitTimer.async_wait([this](const boost::system::error_code& ec) {
304 if (ec == boost::asio::error::operation_aborted)
305 {
306 return; // we're being canceled
307 }
Adrian Ambrożewicz623723b2020-07-29 12:53:54 +0200308 if (!readingStateGood())
James Feist6ef20402019-01-07 16:45:08 -0800309 {
Adrian Ambrożewicz623723b2020-07-29 12:53:54 +0200310 updateValue(std::numeric_limits<double>::quiet_NaN());
James Feist6ef20402019-01-07 16:45:08 -0800311 read();
312 return;
313 }
314 dbusConnection->async_method_call(
315 [this](boost::system::error_code ec,
316 const IpmbMethodType& response) {
317 const int& status = std::get<0>(response);
318 if (ec || status)
319 {
James Feist961bf092020-07-01 16:38:12 -0700320 incrementError();
James Feist6ef20402019-01-07 16:45:08 -0800321 read();
322 return;
323 }
324 const std::vector<uint8_t>& data = std::get<5>(response);
325 if constexpr (debug)
326 {
327 std::cout << name << ": ";
328 for (size_t d : data)
329 {
330 std::cout << d << " ";
331 }
332 std::cout << "\n";
333 }
James Feistd7ae29a2020-06-25 15:42:46 -0700334 if (data.empty())
James Feist6ef20402019-01-07 16:45:08 -0800335 {
James Feist961bf092020-07-01 16:38:12 -0700336 incrementError();
James Feistd7ae29a2020-06-25 15:42:46 -0700337 read();
338 return;
James Feist6ef20402019-01-07 16:45:08 -0800339 }
James Feist961bf092020-07-01 16:38:12 -0700340
341 double value = 0;
342
343 if (!processReading(data, value))
344 {
345 incrementError();
346 read();
347 return;
348 }
Zhikui Rend3da1282020-09-11 17:02:01 -0700349 else
350 {
351 // rawValue only used in debug logging
352 // up to 5th byte in data are used to derive value
353 size_t end = std::min(sizeof(uint64_t), data.size());
354 uint64_t rawData = 0;
355 for (size_t i = 0; i < end; i++)
356 {
357 reinterpret_cast<uint8_t*>(&rawData)[i] = data[i];
358 }
359 rawValue = static_cast<double>(rawData);
360 }
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700361
362 /* Adjust value as per scale and offset */
363 value = (value * scaleVal) + offsetVal;
James Feist6ef20402019-01-07 16:45:08 -0800364 updateValue(value);
365 read();
366 },
367 "xyz.openbmc_project.Ipmi.Channel.Ipmb",
368 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb",
369 "sendRequest", commandAddress, netfn, lun, command, commandData);
370 });
371}
372void createSensors(
373 boost::asio::io_service& io, sdbusplus::asio::object_server& objectServer,
374 boost::container::flat_map<std::string, std::unique_ptr<IpmbSensor>>&
375 sensors,
376 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection)
377{
378 if (!dbusConnection)
379 {
380 std::cerr << "Connection not created\n";
381 return;
382 }
383 dbusConnection->async_method_call(
384 [&](boost::system::error_code ec, const ManagedObjectType& resp) {
385 if (ec)
386 {
387 std::cerr << "Error contacting entity manager\n";
388 return;
389 }
390 for (const auto& pathPair : resp)
391 {
392 for (const auto& entry : pathPair.second)
393 {
394 if (entry.first != configInterface)
395 {
396 continue;
397 }
398 std::string name =
399 loadVariant<std::string>(entry.second, "Name");
400
401 std::vector<thresholds::Threshold> sensorThresholds;
402 if (!parseThresholdsFromConfig(pathPair.second,
403 sensorThresholds))
404 {
405 std::cerr << "error populating thresholds for " << name
406 << "\n";
407 }
408 uint8_t deviceAddress =
409 loadVariant<uint8_t>(entry.second, "Address");
410
411 std::string sensorClass =
412 loadVariant<std::string>(entry.second, "Class");
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700413
414 /* Default sensor type is "temperature" */
415 std::string sensorTypeName = "temperature";
416 auto findType = entry.second.find("SensorType");
417 if (findType != entry.second.end())
418 {
419 sensorTypeName = std::visit(VariantToStringVisitor(),
420 findType->second);
421 }
422
James Feist6ef20402019-01-07 16:45:08 -0800423 auto& sensor = sensors[name];
424 sensor = std::make_unique<IpmbSensor>(
425 dbusConnection, io, name, pathPair.first, objectServer,
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700426 std::move(sensorThresholds), deviceAddress,
427 sensorTypeName);
428
429 /* Initialize scale and offset value */
430 sensor->scaleVal = 1;
431 sensor->offsetVal = 0;
432
433 auto findScaleVal = entry.second.find("ScaleValue");
434 if (findScaleVal != entry.second.end())
435 {
436 sensor->scaleVal = std::visit(VariantToDoubleVisitor(),
437 findScaleVal->second);
438 }
439
440 auto findOffsetVal = entry.second.find("OffsetValue");
441 if (findOffsetVal != entry.second.end())
442 {
443 sensor->offsetVal = std::visit(VariantToDoubleVisitor(),
444 findOffsetVal->second);
445 }
James Feist6ef20402019-01-07 16:45:08 -0800446
James Feistfc94b212019-02-06 16:14:51 -0800447 auto findPowerState = entry.second.find("PowerState");
448
449 if (findPowerState != entry.second.end())
450 {
451 std::string powerState = std::visit(
452 VariantToStringVisitor(), findPowerState->second);
453
454 setReadState(powerState, sensor->readState);
455 }
456
James Feist6ef20402019-01-07 16:45:08 -0800457 if (sensorClass == "PxeBridgeTemp")
458 {
459 sensor->type = IpmbType::PXE1410CVR;
460 }
461 else if (sensorClass == "IRBridgeTemp")
462 {
463 sensor->type = IpmbType::IR38363VR;
464 }
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700465 else if (sensorClass == "HSCBridge")
466 {
467 sensor->type = IpmbType::ADM1278HSC;
468 }
James Feist6ef20402019-01-07 16:45:08 -0800469 else if (sensorClass == "MpsBridgeTemp")
470 {
471 sensor->type = IpmbType::mpsVR;
472 }
Adrian Ambrożewicz45e92772020-06-04 13:59:55 +0200473 else if (sensorClass == "METemp" ||
474 sensorClass == "MESensor")
James Feist6ef20402019-01-07 16:45:08 -0800475 {
476 sensor->type = IpmbType::meSensor;
477 }
478 else
479 {
480 std::cerr << "Invalid class " << sensorClass << "\n";
481 continue;
482 }
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700483
484 if (sensorTypeName == "voltage")
485 {
486 sensor->subType = IpmbSubType::volt;
487 }
488 else if (sensorTypeName == "power")
489 {
490 sensor->subType = IpmbSubType::power;
491 }
492 else if (sensorTypeName == "current")
493 {
494 sensor->subType = IpmbSubType::curr;
495 }
Adrian Ambrożewicz45e92772020-06-04 13:59:55 +0200496 else if (sensorTypeName == "utilization")
497 {
498 sensor->subType = IpmbSubType::util;
499 }
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700500 else
501 {
502 sensor->subType = IpmbSubType::temp;
503 }
James Feist6ef20402019-01-07 16:45:08 -0800504 sensor->init();
505 }
506 }
507 },
508 entityManagerName, "/", "org.freedesktop.DBus.ObjectManager",
509 "GetManagedObjects");
510}
511
James Feistf7e2c5d2019-02-13 17:27:51 -0800512void reinitSensors(sdbusplus::message::message& message)
513{
James Feist0d4f2bd2019-03-05 13:15:40 -0800514 constexpr const size_t reinitWaitSeconds = 2;
James Feistf7e2c5d2019-02-13 17:27:51 -0800515 std::string objectName;
James Feist52497fd2019-06-07 13:01:33 -0700516 boost::container::flat_map<std::string, std::variant<std::string>> values;
James Feistf7e2c5d2019-02-13 17:27:51 -0800517 message.read(objectName, values);
James Feist0d4f2bd2019-03-05 13:15:40 -0800518
James Feist52497fd2019-06-07 13:01:33 -0700519 auto findStatus = values.find(power::property);
520 if (findStatus != values.end())
James Feistf7e2c5d2019-02-13 17:27:51 -0800521 {
James Feist52497fd2019-06-07 13:01:33 -0700522 bool powerStatus = boost::ends_with(
523 std::get<std::string>(findStatus->second), "Running");
James Feistf7e2c5d2019-02-13 17:27:51 -0800524 if (powerStatus)
525 {
James Feist0d4f2bd2019-03-05 13:15:40 -0800526 if (!initCmdTimer)
James Feistf7e2c5d2019-02-13 17:27:51 -0800527 {
James Feist0d4f2bd2019-03-05 13:15:40 -0800528 // this should be impossible
529 return;
James Feistf7e2c5d2019-02-13 17:27:51 -0800530 }
James Feist0d4f2bd2019-03-05 13:15:40 -0800531 // we seem to send this command too fast sometimes, wait before
532 // sending
533 initCmdTimer->expires_from_now(
534 boost::posix_time::seconds(reinitWaitSeconds));
535
536 initCmdTimer->async_wait([](const boost::system::error_code ec) {
537 if (ec == boost::asio::error::operation_aborted)
538 {
539 return; // we're being canceled
540 }
541
542 for (const auto& sensor : sensors)
543 {
544 if (sensor.second)
545 {
546 sensor.second->runInitCmd();
547 }
548 }
549 });
James Feistf7e2c5d2019-02-13 17:27:51 -0800550 }
551 }
552}
553
James Feistb6c0b912019-07-09 12:21:44 -0700554int main()
James Feist6ef20402019-01-07 16:45:08 -0800555{
556
557 boost::asio::io_service io;
558 auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
559 systemBus->request_name("xyz.openbmc_project.IpmbSensor");
560 sdbusplus::asio::object_server objectServer(systemBus);
James Feist6ef20402019-01-07 16:45:08 -0800561
James Feist0d4f2bd2019-03-05 13:15:40 -0800562 initCmdTimer = std::make_unique<boost::asio::deadline_timer>(io);
563
James Feist6ef20402019-01-07 16:45:08 -0800564 io.post([&]() { createSensors(io, objectServer, sensors, systemBus); });
565
566 boost::asio::deadline_timer configTimer(io);
567
568 std::function<void(sdbusplus::message::message&)> eventHandler =
James Feistb6c0b912019-07-09 12:21:44 -0700569 [&](sdbusplus::message::message&) {
James Feist6ef20402019-01-07 16:45:08 -0800570 configTimer.expires_from_now(boost::posix_time::seconds(1));
571 // create a timer because normally multiple properties change
572 configTimer.async_wait([&](const boost::system::error_code& ec) {
573 if (ec == boost::asio::error::operation_aborted)
574 {
575 return; // we're being canceled
576 }
577 createSensors(io, objectServer, sensors, systemBus);
578 if (sensors.empty())
579 {
580 std::cout << "Configuration not detected\n";
581 }
582 });
583 };
584
James Feistf7e2c5d2019-02-13 17:27:51 -0800585 sdbusplus::bus::match::match configMatch(
James Feist6ef20402019-01-07 16:45:08 -0800586 static_cast<sdbusplus::bus::bus&>(*systemBus),
587 "type='signal',member='PropertiesChanged',path_namespace='" +
588 std::string(inventoryPath) + "',arg0namespace='" + configInterface +
589 "'",
590 eventHandler);
591
James Feistf7e2c5d2019-02-13 17:27:51 -0800592 sdbusplus::bus::match::match powerChangeMatch(
593 static_cast<sdbusplus::bus::bus&>(*systemBus),
James Feist52497fd2019-06-07 13:01:33 -0700594 "type='signal',interface='" + std::string(properties::interface) +
595 "',path='" + std::string(power::path) + "',arg0='" +
596 std::string(power::interface) + "'",
James Feistf7e2c5d2019-02-13 17:27:51 -0800597 reinitSensors);
598
James Feist6ef20402019-01-07 16:45:08 -0800599 io.run();
600}