blob: a7c1e097436cec88e0101db0620e6a6fa7b6c2e0 [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 Feist961bf092020-07-01 16:38:12 -070072 ipmbMinReading, PowerState::on),
73 deviceAddress(deviceAddress), objectServer(objectServer),
74 dbusConnection(conn), waitTimer(io)
James Feist6ef20402019-01-07 16:45:08 -080075{
Vijay Khemka682a5cb2019-07-18 17:34:03 -070076 std::string dbusPath = sensorPathPrefix + sensorTypeName + "/" + name;
77
James Feist6ef20402019-01-07 16:45:08 -080078 sensorInterface = objectServer.add_interface(
Vijay Khemka682a5cb2019-07-18 17:34:03 -070079 dbusPath, "xyz.openbmc_project.Sensor.Value");
James Feist6ef20402019-01-07 16:45:08 -080080
81 if (thresholds::hasWarningInterface(thresholds))
82 {
83 thresholdInterfaceWarning = objectServer.add_interface(
Vijay Khemka682a5cb2019-07-18 17:34:03 -070084 dbusPath, "xyz.openbmc_project.Sensor.Threshold.Warning");
James Feist6ef20402019-01-07 16:45:08 -080085 }
86 if (thresholds::hasCriticalInterface(thresholds))
87 {
88 thresholdInterfaceCritical = objectServer.add_interface(
Vijay Khemka682a5cb2019-07-18 17:34:03 -070089 dbusPath, "xyz.openbmc_project.Sensor.Threshold.Critical");
James Feist6ef20402019-01-07 16:45:08 -080090 }
James Feist2adc95c2019-09-30 14:55:28 -070091 association = objectServer.add_interface(dbusPath, association::interface);
James Feist6ef20402019-01-07 16:45:08 -080092}
93
94IpmbSensor::~IpmbSensor()
95{
96 waitTimer.cancel();
97 objectServer.remove_interface(thresholdInterfaceWarning);
98 objectServer.remove_interface(thresholdInterfaceCritical);
99 objectServer.remove_interface(sensorInterface);
James Feist078f2322019-03-08 11:09:05 -0800100 objectServer.remove_interface(association);
James Feist6ef20402019-01-07 16:45:08 -0800101}
102
103void IpmbSensor::init(void)
104{
James Feist6ef20402019-01-07 16:45:08 -0800105 loadDefaults();
Adrian Ambrożewicz45e92772020-06-04 13:59:55 +0200106 setInitialProperties(dbusConnection);
James Feist6ef20402019-01-07 16:45:08 -0800107 if (initCommand)
108 {
James Feistf7e2c5d2019-02-13 17:27:51 -0800109 runInitCmd();
110 }
111 read();
112}
113
114void IpmbSensor::runInitCmd()
115{
116 if (initCommand)
117 {
James Feist6ef20402019-01-07 16:45:08 -0800118 dbusConnection->async_method_call(
119 [this](boost::system::error_code ec,
120 const IpmbMethodType& response) {
121 const int& status = std::get<0>(response);
122
123 if (ec || status)
124 {
125 std::cerr
126 << "Error setting init command for device: " << name
127 << "\n";
128 }
James Feist6ef20402019-01-07 16:45:08 -0800129 },
130 "xyz.openbmc_project.Ipmi.Channel.Ipmb",
131 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb",
132 "sendRequest", commandAddress, netfn, lun, *initCommand, initData);
133 }
James Feist6ef20402019-01-07 16:45:08 -0800134}
135
136void IpmbSensor::loadDefaults()
137{
138 if (type == IpmbType::meSensor)
139 {
140 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200141 netfn = ipmi::sensor::netFn;
142 command = ipmi::sensor::getSensorReading;
James Feist6ef20402019-01-07 16:45:08 -0800143 commandData = {deviceAddress};
James Feistd7ae29a2020-06-25 15:42:46 -0700144 readingFormat = ReadingFormat::byte0;
James Feist6ef20402019-01-07 16:45:08 -0800145 }
146 else if (type == IpmbType::PXE1410CVR)
147 {
148 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200149 netfn = ipmi::me_bridge::netFn;
150 command = ipmi::me_bridge::sendRawPmbus;
151 initCommand = ipmi::me_bridge::sendRawPmbus;
James Feistd7ae29a2020-06-25 15:42:46 -0700152 // pmbus read temp
153 commandData = {0x57, 0x01, 0x00, 0x16, 0x3, deviceAddress, 0x00,
154 0x00, 0x00, 0x00, 0x01, 0x02, 0x8d};
155 // goto page 0
James Feist6ef20402019-01-07 16:45:08 -0800156 initData = {0x57, 0x01, 0x00, 0x14, 0x03, deviceAddress, 0x00,
James Feistd7ae29a2020-06-25 15:42:46 -0700157 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00};
James Feiste4a970d2020-08-19 11:21:58 -0700158 readingFormat = ReadingFormat::elevenBit;
James Feist6ef20402019-01-07 16:45:08 -0800159 }
160 else if (type == IpmbType::IR38363VR)
161 {
162 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200163 netfn = ipmi::me_bridge::netFn;
164 command = ipmi::me_bridge::sendRawPmbus;
James Feistd7ae29a2020-06-25 15:42:46 -0700165 // pmbus read temp
James Feist6ef20402019-01-07 16:45:08 -0800166 commandData = {0x57, 0x01, 0x00, 0x16, 0x03, deviceAddress, 00,
167 0x00, 0x00, 0x00, 0x01, 0x02, 0x8D};
James Feistd7ae29a2020-06-25 15:42:46 -0700168 readingFormat = ReadingFormat::elevenBitShift;
James Feist6ef20402019-01-07 16:45:08 -0800169 }
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700170 else if (type == IpmbType::ADM1278HSC)
171 {
172 commandAddress = meAddress;
173 switch (subType)
174 {
175 case IpmbSubType::temp:
176 case IpmbSubType::curr:
177 uint8_t snsNum;
178 if (subType == IpmbSubType::temp)
179 snsNum = 0x8d;
180 else
181 snsNum = 0x8c;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200182 netfn = ipmi::me_bridge::netFn;
183 command = ipmi::me_bridge::sendRawPmbus;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700184 commandData = {0x57, 0x01, 0x00, 0x86, deviceAddress,
185 0x00, 0x00, 0x01, 0x02, snsNum};
James Feistd7ae29a2020-06-25 15:42:46 -0700186 readingFormat = ReadingFormat::elevenBit;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700187 break;
188 case IpmbSubType::power:
189 case IpmbSubType::volt:
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200190 netfn = ipmi::sensor::netFn;
191 command = ipmi::sensor::getSensorReading;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700192 commandData = {deviceAddress};
James Feistd7ae29a2020-06-25 15:42:46 -0700193 readingFormat = ReadingFormat::byte0;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700194 break;
195 default:
196 throw std::runtime_error("Invalid sensor type");
197 }
198 }
James Feist6ef20402019-01-07 16:45:08 -0800199 else if (type == IpmbType::mpsVR)
200 {
201 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200202 netfn = ipmi::me_bridge::netFn;
203 command = ipmi::me_bridge::sendRawPmbus;
204 initCommand = ipmi::me_bridge::sendRawPmbus;
James Feistd7ae29a2020-06-25 15:42:46 -0700205 // pmbus read temp
James Feist6ef20402019-01-07 16:45:08 -0800206 commandData = {0x57, 0x01, 0x00, 0x16, 0x3, deviceAddress, 0x00,
207 0x00, 0x00, 0x00, 0x01, 0x02, 0x8d};
James Feistd7ae29a2020-06-25 15:42:46 -0700208 // goto page 0
James Feist6ef20402019-01-07 16:45:08 -0800209 initData = {0x57, 0x01, 0x00, 0x14, 0x03, deviceAddress, 0x00,
210 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00};
James Feistd7ae29a2020-06-25 15:42:46 -0700211 readingFormat = ReadingFormat::byte3;
James Feist6ef20402019-01-07 16:45:08 -0800212 }
213 else
214 {
215 throw std::runtime_error("Invalid sensor type");
216 }
Adrian Ambrożewicz45e92772020-06-04 13:59:55 +0200217
218 if (subType == IpmbSubType::util)
219 {
220 // Utilization need to be scaled to percent
221 maxValue = 100;
222 minValue = 0;
223 }
James Feist6ef20402019-01-07 16:45:08 -0800224}
225
226void IpmbSensor::checkThresholds(void)
227{
James Feist6ef20402019-01-07 16:45:08 -0800228 thresholds::checkThresholds(this);
229}
230
James Feist961bf092020-07-01 16:38:12 -0700231bool IpmbSensor::processReading(const std::vector<uint8_t>& data, double& resp)
James Feistd7ae29a2020-06-25 15:42:46 -0700232{
233
234 switch (readingFormat)
235 {
236 case (ReadingFormat::byte0):
James Feiste4a970d2020-08-19 11:21:58 -0700237 {
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200238 if (command == ipmi::sensor::getSensorReading &&
239 !ipmi::sensor::isValid(data))
James Feistcf4238e2020-07-28 16:40:03 -0700240 {
241 return false;
242 }
James Feist961bf092020-07-01 16:38:12 -0700243 resp = data[0];
244 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700245 }
James Feistd7ae29a2020-06-25 15:42:46 -0700246 case (ReadingFormat::byte3):
James Feiste4a970d2020-08-19 11:21:58 -0700247 {
James Feistd7ae29a2020-06-25 15:42:46 -0700248 if (data.size() < 4)
249 {
James Feist961bf092020-07-01 16:38:12 -0700250 if (!errCount)
251 {
252 std::cerr << "Invalid data length returned for " << name
253 << "\n";
254 }
255 return false;
James Feistd7ae29a2020-06-25 15:42:46 -0700256 }
James Feist961bf092020-07-01 16:38:12 -0700257 resp = data[3];
258 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700259 }
James Feistd7ae29a2020-06-25 15:42:46 -0700260 case (ReadingFormat::elevenBit):
James Feiste4a970d2020-08-19 11:21:58 -0700261 {
James Feistd7ae29a2020-06-25 15:42:46 -0700262 if (data.size() < 5)
263 {
James Feist961bf092020-07-01 16:38:12 -0700264 if (!errCount)
265 {
266 std::cerr << "Invalid data length returned for " << name
267 << "\n";
268 }
269 return false;
James Feistd7ae29a2020-06-25 15:42:46 -0700270 }
271
James Feiste4a970d2020-08-19 11:21:58 -0700272 int16_t value = ((data[4] << 8) | data[3]);
273 constexpr const size_t shift = 16 - 11; // 11bit into 16bit
274 value <<= shift;
275 value >>= shift;
276 resp = value;
James Feist961bf092020-07-01 16:38:12 -0700277 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700278 }
James Feistd7ae29a2020-06-25 15:42:46 -0700279 case (ReadingFormat::elevenBitShift):
James Feiste4a970d2020-08-19 11:21:58 -0700280 {
James Feistd7ae29a2020-06-25 15:42:46 -0700281 if (data.size() < 5)
282 {
James Feist961bf092020-07-01 16:38:12 -0700283 if (!errCount)
284 {
285 std::cerr << "Invalid data length returned for " << name
286 << "\n";
287 }
288 return false;
James Feistd7ae29a2020-06-25 15:42:46 -0700289 }
290
James Feist961bf092020-07-01 16:38:12 -0700291 resp = ((data[4] << 8) | data[3]) >> 3;
292 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700293 }
James Feistd7ae29a2020-06-25 15:42:46 -0700294 default:
295 throw std::runtime_error("Invalid reading type");
296 }
297}
298
James Feist6ef20402019-01-07 16:45:08 -0800299void IpmbSensor::read(void)
300{
301 static constexpr size_t pollTime = 1; // in seconds
302
303 waitTimer.expires_from_now(boost::posix_time::seconds(pollTime));
304 waitTimer.async_wait([this](const boost::system::error_code& ec) {
305 if (ec == boost::asio::error::operation_aborted)
306 {
307 return; // we're being canceled
308 }
Adrian Ambrożewicz623723b2020-07-29 12:53:54 +0200309 if (!readingStateGood())
James Feist6ef20402019-01-07 16:45:08 -0800310 {
Adrian Ambrożewicz623723b2020-07-29 12:53:54 +0200311 updateValue(std::numeric_limits<double>::quiet_NaN());
James Feist6ef20402019-01-07 16:45:08 -0800312 read();
313 return;
314 }
315 dbusConnection->async_method_call(
316 [this](boost::system::error_code ec,
317 const IpmbMethodType& response) {
318 const int& status = std::get<0>(response);
319 if (ec || status)
320 {
James Feist961bf092020-07-01 16:38:12 -0700321 incrementError();
James Feist6ef20402019-01-07 16:45:08 -0800322 read();
323 return;
324 }
325 const std::vector<uint8_t>& data = std::get<5>(response);
326 if constexpr (debug)
327 {
328 std::cout << name << ": ";
329 for (size_t d : data)
330 {
331 std::cout << d << " ";
332 }
333 std::cout << "\n";
334 }
James Feistd7ae29a2020-06-25 15:42:46 -0700335 if (data.empty())
James Feist6ef20402019-01-07 16:45:08 -0800336 {
James Feist961bf092020-07-01 16:38:12 -0700337 incrementError();
James Feistd7ae29a2020-06-25 15:42:46 -0700338 read();
339 return;
James Feist6ef20402019-01-07 16:45:08 -0800340 }
James Feist961bf092020-07-01 16:38:12 -0700341
342 double value = 0;
343
344 if (!processReading(data, value))
345 {
346 incrementError();
347 read();
348 return;
349 }
Zhikui Rend3da1282020-09-11 17:02:01 -0700350 else
351 {
352 // rawValue only used in debug logging
353 // up to 5th byte in data are used to derive value
354 size_t end = std::min(sizeof(uint64_t), data.size());
355 uint64_t rawData = 0;
356 for (size_t i = 0; i < end; i++)
357 {
358 reinterpret_cast<uint8_t*>(&rawData)[i] = data[i];
359 }
360 rawValue = static_cast<double>(rawData);
361 }
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700362
363 /* Adjust value as per scale and offset */
364 value = (value * scaleVal) + offsetVal;
James Feist6ef20402019-01-07 16:45:08 -0800365 updateValue(value);
366 read();
367 },
368 "xyz.openbmc_project.Ipmi.Channel.Ipmb",
369 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb",
370 "sendRequest", commandAddress, netfn, lun, command, commandData);
371 });
372}
373void createSensors(
374 boost::asio::io_service& io, sdbusplus::asio::object_server& objectServer,
375 boost::container::flat_map<std::string, std::unique_ptr<IpmbSensor>>&
376 sensors,
377 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection)
378{
379 if (!dbusConnection)
380 {
381 std::cerr << "Connection not created\n";
382 return;
383 }
384 dbusConnection->async_method_call(
385 [&](boost::system::error_code ec, const ManagedObjectType& resp) {
386 if (ec)
387 {
388 std::cerr << "Error contacting entity manager\n";
389 return;
390 }
391 for (const auto& pathPair : resp)
392 {
393 for (const auto& entry : pathPair.second)
394 {
395 if (entry.first != configInterface)
396 {
397 continue;
398 }
399 std::string name =
400 loadVariant<std::string>(entry.second, "Name");
401
402 std::vector<thresholds::Threshold> sensorThresholds;
403 if (!parseThresholdsFromConfig(pathPair.second,
404 sensorThresholds))
405 {
406 std::cerr << "error populating thresholds for " << name
407 << "\n";
408 }
409 uint8_t deviceAddress =
410 loadVariant<uint8_t>(entry.second, "Address");
411
412 std::string sensorClass =
413 loadVariant<std::string>(entry.second, "Class");
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700414
415 /* Default sensor type is "temperature" */
416 std::string sensorTypeName = "temperature";
417 auto findType = entry.second.find("SensorType");
418 if (findType != entry.second.end())
419 {
420 sensorTypeName = std::visit(VariantToStringVisitor(),
421 findType->second);
422 }
423
James Feist6ef20402019-01-07 16:45:08 -0800424 auto& sensor = sensors[name];
425 sensor = std::make_unique<IpmbSensor>(
426 dbusConnection, io, name, pathPair.first, objectServer,
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700427 std::move(sensorThresholds), deviceAddress,
428 sensorTypeName);
429
430 /* Initialize scale and offset value */
431 sensor->scaleVal = 1;
432 sensor->offsetVal = 0;
433
434 auto findScaleVal = entry.second.find("ScaleValue");
435 if (findScaleVal != entry.second.end())
436 {
437 sensor->scaleVal = std::visit(VariantToDoubleVisitor(),
438 findScaleVal->second);
439 }
440
441 auto findOffsetVal = entry.second.find("OffsetValue");
442 if (findOffsetVal != entry.second.end())
443 {
444 sensor->offsetVal = std::visit(VariantToDoubleVisitor(),
445 findOffsetVal->second);
446 }
James Feist6ef20402019-01-07 16:45:08 -0800447
James Feistfc94b212019-02-06 16:14:51 -0800448 auto findPowerState = entry.second.find("PowerState");
449
450 if (findPowerState != entry.second.end())
451 {
452 std::string powerState = std::visit(
453 VariantToStringVisitor(), findPowerState->second);
454
455 setReadState(powerState, sensor->readState);
456 }
457
James Feist6ef20402019-01-07 16:45:08 -0800458 if (sensorClass == "PxeBridgeTemp")
459 {
460 sensor->type = IpmbType::PXE1410CVR;
461 }
462 else if (sensorClass == "IRBridgeTemp")
463 {
464 sensor->type = IpmbType::IR38363VR;
465 }
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700466 else if (sensorClass == "HSCBridge")
467 {
468 sensor->type = IpmbType::ADM1278HSC;
469 }
James Feist6ef20402019-01-07 16:45:08 -0800470 else if (sensorClass == "MpsBridgeTemp")
471 {
472 sensor->type = IpmbType::mpsVR;
473 }
Adrian Ambrożewicz45e92772020-06-04 13:59:55 +0200474 else if (sensorClass == "METemp" ||
475 sensorClass == "MESensor")
James Feist6ef20402019-01-07 16:45:08 -0800476 {
477 sensor->type = IpmbType::meSensor;
478 }
479 else
480 {
481 std::cerr << "Invalid class " << sensorClass << "\n";
482 continue;
483 }
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700484
485 if (sensorTypeName == "voltage")
486 {
487 sensor->subType = IpmbSubType::volt;
488 }
489 else if (sensorTypeName == "power")
490 {
491 sensor->subType = IpmbSubType::power;
492 }
493 else if (sensorTypeName == "current")
494 {
495 sensor->subType = IpmbSubType::curr;
496 }
Adrian Ambrożewicz45e92772020-06-04 13:59:55 +0200497 else if (sensorTypeName == "utilization")
498 {
499 sensor->subType = IpmbSubType::util;
500 }
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700501 else
502 {
503 sensor->subType = IpmbSubType::temp;
504 }
James Feist6ef20402019-01-07 16:45:08 -0800505 sensor->init();
506 }
507 }
508 },
509 entityManagerName, "/", "org.freedesktop.DBus.ObjectManager",
510 "GetManagedObjects");
511}
512
James Feistf7e2c5d2019-02-13 17:27:51 -0800513void reinitSensors(sdbusplus::message::message& message)
514{
James Feist0d4f2bd2019-03-05 13:15:40 -0800515 constexpr const size_t reinitWaitSeconds = 2;
James Feistf7e2c5d2019-02-13 17:27:51 -0800516 std::string objectName;
James Feist52497fd2019-06-07 13:01:33 -0700517 boost::container::flat_map<std::string, std::variant<std::string>> values;
James Feistf7e2c5d2019-02-13 17:27:51 -0800518 message.read(objectName, values);
James Feist0d4f2bd2019-03-05 13:15:40 -0800519
James Feist52497fd2019-06-07 13:01:33 -0700520 auto findStatus = values.find(power::property);
521 if (findStatus != values.end())
James Feistf7e2c5d2019-02-13 17:27:51 -0800522 {
James Feist52497fd2019-06-07 13:01:33 -0700523 bool powerStatus = boost::ends_with(
524 std::get<std::string>(findStatus->second), "Running");
James Feistf7e2c5d2019-02-13 17:27:51 -0800525 if (powerStatus)
526 {
James Feist0d4f2bd2019-03-05 13:15:40 -0800527 if (!initCmdTimer)
James Feistf7e2c5d2019-02-13 17:27:51 -0800528 {
James Feist0d4f2bd2019-03-05 13:15:40 -0800529 // this should be impossible
530 return;
James Feistf7e2c5d2019-02-13 17:27:51 -0800531 }
James Feist0d4f2bd2019-03-05 13:15:40 -0800532 // we seem to send this command too fast sometimes, wait before
533 // sending
534 initCmdTimer->expires_from_now(
535 boost::posix_time::seconds(reinitWaitSeconds));
536
537 initCmdTimer->async_wait([](const boost::system::error_code ec) {
538 if (ec == boost::asio::error::operation_aborted)
539 {
540 return; // we're being canceled
541 }
542
543 for (const auto& sensor : sensors)
544 {
545 if (sensor.second)
546 {
547 sensor.second->runInitCmd();
548 }
549 }
550 });
James Feistf7e2c5d2019-02-13 17:27:51 -0800551 }
552 }
553}
554
James Feistb6c0b912019-07-09 12:21:44 -0700555int main()
James Feist6ef20402019-01-07 16:45:08 -0800556{
557
558 boost::asio::io_service io;
559 auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
560 systemBus->request_name("xyz.openbmc_project.IpmbSensor");
561 sdbusplus::asio::object_server objectServer(systemBus);
James Feist6ef20402019-01-07 16:45:08 -0800562
James Feist0d4f2bd2019-03-05 13:15:40 -0800563 initCmdTimer = std::make_unique<boost::asio::deadline_timer>(io);
564
James Feist6ef20402019-01-07 16:45:08 -0800565 io.post([&]() { createSensors(io, objectServer, sensors, systemBus); });
566
567 boost::asio::deadline_timer configTimer(io);
568
569 std::function<void(sdbusplus::message::message&)> eventHandler =
James Feistb6c0b912019-07-09 12:21:44 -0700570 [&](sdbusplus::message::message&) {
James Feist6ef20402019-01-07 16:45:08 -0800571 configTimer.expires_from_now(boost::posix_time::seconds(1));
572 // create a timer because normally multiple properties change
573 configTimer.async_wait([&](const boost::system::error_code& ec) {
574 if (ec == boost::asio::error::operation_aborted)
575 {
576 return; // we're being canceled
577 }
578 createSensors(io, objectServer, sensors, systemBus);
579 if (sensors.empty())
580 {
581 std::cout << "Configuration not detected\n";
582 }
583 });
584 };
585
James Feistf7e2c5d2019-02-13 17:27:51 -0800586 sdbusplus::bus::match::match configMatch(
James Feist6ef20402019-01-07 16:45:08 -0800587 static_cast<sdbusplus::bus::bus&>(*systemBus),
588 "type='signal',member='PropertiesChanged',path_namespace='" +
589 std::string(inventoryPath) + "',arg0namespace='" + configInterface +
590 "'",
591 eventHandler);
592
James Feistf7e2c5d2019-02-13 17:27:51 -0800593 sdbusplus::bus::match::match powerChangeMatch(
594 static_cast<sdbusplus::bus::bus&>(*systemBus),
James Feist52497fd2019-06-07 13:01:33 -0700595 "type='signal',interface='" + std::string(properties::interface) +
596 "',path='" + std::string(power::path) + "',arg0='" +
597 std::string(power::interface) + "'",
James Feistf7e2c5d2019-02-13 17:27:51 -0800598 reinitSensors);
599
James Feist6ef20402019-01-07 16:45:08 -0800600 io.run();
601}