blob: 39e385dd07f36ee116a65f07564712216bced92c [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
Ed Tanous8a57ec02020-10-09 12:46:52 -070017#include <IpmbSensor.hpp>
18#include <Utils.hpp>
19#include <VariantVisitors.hpp>
Patrick Venture96e97db2019-10-31 13:44:38 -070020#include <boost/container/flat_map.hpp>
James Feist38fb5982020-05-28 10:09:54 -070021#include <sdbusplus/asio/connection.hpp>
22#include <sdbusplus/asio/object_server.hpp>
23#include <sdbusplus/bus/match.hpp>
24
James Feist6ef20402019-01-07 16:45:08 -080025#include <chrono>
Ed Tanous8a57ec02020-10-09 12:46:52 -070026#include <cmath>
Patrick Venture96e97db2019-10-31 13:44:38 -070027#include <functional>
James Feist6ef20402019-01-07 16:45:08 -080028#include <iostream>
29#include <limits>
Patrick Venture96e97db2019-10-31 13:44:38 -070030#include <memory>
James Feist6ef20402019-01-07 16:45:08 -080031#include <numeric>
Patrick Venture96e97db2019-10-31 13:44:38 -070032#include <string>
33#include <tuple>
34#include <variant>
James Feist6ef20402019-01-07 16:45:08 -080035#include <vector>
36
37constexpr const bool debug = false;
38
Zev Weiss054aad82022-08-18 01:37:34 -070039constexpr const char* sensorType = "IpmbSensor";
James Feist6ef20402019-01-07 16:45:08 -080040static constexpr double ipmbMaxReading = 0xFF;
41static constexpr double ipmbMinReading = 0;
42
43static constexpr uint8_t meAddress = 1;
44static constexpr uint8_t lun = 0;
Anoop S832a2c62020-11-20 19:21:22 +000045static constexpr uint8_t hostSMbusIndexDefault = 0x03;
Jayashree-D9f6d4fd2021-04-13 18:27:22 +053046static constexpr float pollRateDefault = 1; // in seconds
James Feist6ef20402019-01-07 16:45:08 -080047
Vijay Khemka682a5cb2019-07-18 17:34:03 -070048static constexpr const char* sensorPathPrefix = "/xyz/openbmc_project/sensors/";
49
James Feist6ef20402019-01-07 16:45:08 -080050using IpmbMethodType =
51 std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>;
52
James Feistf7e2c5d2019-02-13 17:27:51 -080053boost::container::flat_map<std::string, std::unique_ptr<IpmbSensor>> sensors;
54
Ed Tanous9b4a20e2022-09-06 08:47:11 -070055std::unique_ptr<boost::asio::steady_timer> initCmdTimer;
James Feist0d4f2bd2019-03-05 13:15:40 -080056
James Feist6ef20402019-01-07 16:45:08 -080057IpmbSensor::IpmbSensor(std::shared_ptr<sdbusplus::asio::connection>& conn,
58 boost::asio::io_service& io,
59 const std::string& sensorName,
60 const std::string& sensorConfiguration,
61 sdbusplus::asio::object_server& objectServer,
62 std::vector<thresholds::Threshold>&& thresholdData,
Anoop S832a2c62020-11-20 19:21:22 +000063 uint8_t deviceAddress, uint8_t hostSMbusIndex,
Jayashree-D9f6d4fd2021-04-13 18:27:22 +053064 const float pollRate, std::string& sensorTypeName) :
Zhikui Renda98f092021-11-01 09:41:08 -070065 Sensor(escapeName(sensorName), std::move(thresholdData),
Zev Weiss054aad82022-08-18 01:37:34 -070066 sensorConfiguration, "IpmbSensor", false, false, ipmbMaxReading,
67 ipmbMinReading, conn, PowerState::on),
Anoop S832a2c62020-11-20 19:21:22 +000068 deviceAddress(deviceAddress), hostSMbusIndex(hostSMbusIndex),
Jayashree-D9f6d4fd2021-04-13 18:27:22 +053069 sensorPollMs(static_cast<int>(pollRate * 1000)), objectServer(objectServer),
70 waitTimer(io)
James Feist6ef20402019-01-07 16:45:08 -080071{
Vijay Khemka682a5cb2019-07-18 17:34:03 -070072 std::string dbusPath = sensorPathPrefix + sensorTypeName + "/" + name;
73
James Feist6ef20402019-01-07 16:45:08 -080074 sensorInterface = objectServer.add_interface(
Vijay Khemka682a5cb2019-07-18 17:34:03 -070075 dbusPath, "xyz.openbmc_project.Sensor.Value");
James Feist6ef20402019-01-07 16:45:08 -080076
Jayashree Dhanapal56678082022-01-04 17:27:20 +053077 for (const auto& threshold : thresholds)
James Feist6ef20402019-01-07 16:45:08 -080078 {
Jayashree Dhanapal56678082022-01-04 17:27:20 +053079 std::string interface = thresholds::getInterface(threshold.level);
80 thresholdInterfaces[static_cast<size_t>(threshold.level)] =
81 objectServer.add_interface(dbusPath, interface);
James Feist6ef20402019-01-07 16:45:08 -080082 }
James Feist2adc95c2019-09-30 14:55:28 -070083 association = objectServer.add_interface(dbusPath, association::interface);
James Feist6ef20402019-01-07 16:45:08 -080084}
85
86IpmbSensor::~IpmbSensor()
87{
88 waitTimer.cancel();
Jayashree Dhanapal56678082022-01-04 17:27:20 +053089 for (const auto& iface : thresholdInterfaces)
90 {
91 objectServer.remove_interface(iface);
92 }
James Feist6ef20402019-01-07 16:45:08 -080093 objectServer.remove_interface(sensorInterface);
James Feist078f2322019-03-08 11:09:05 -080094 objectServer.remove_interface(association);
James Feist6ef20402019-01-07 16:45:08 -080095}
96
Ed Tanous2049bd22022-07-09 07:20:26 -070097std::string IpmbSensor::getSubTypeUnits(void) const
Zev Weiss6b6891c2021-04-22 02:46:21 -050098{
99 switch (subType)
100 {
101 case IpmbSubType::temp:
102 return sensor_paths::unitDegreesC;
103 case IpmbSubType::curr:
104 return sensor_paths::unitAmperes;
105 case IpmbSubType::power:
106 return sensor_paths::unitWatts;
107 case IpmbSubType::volt:
108 return sensor_paths::unitVolts;
109 case IpmbSubType::util:
110 return sensor_paths::unitPercent;
111 default:
112 throw std::runtime_error("Invalid sensor type");
113 }
114}
115
James Feist6ef20402019-01-07 16:45:08 -0800116void IpmbSensor::init(void)
117{
James Feist6ef20402019-01-07 16:45:08 -0800118 loadDefaults();
Andrei Kartashev39287412022-02-04 16:04:47 +0300119 setInitialProperties(getSubTypeUnits());
James Feist6ef20402019-01-07 16:45:08 -0800120 if (initCommand)
121 {
James Feistf7e2c5d2019-02-13 17:27:51 -0800122 runInitCmd();
123 }
124 read();
125}
126
127void IpmbSensor::runInitCmd()
128{
129 if (initCommand)
130 {
James Feist6ef20402019-01-07 16:45:08 -0800131 dbusConnection->async_method_call(
132 [this](boost::system::error_code ec,
133 const IpmbMethodType& response) {
Ed Tanousbb679322022-05-16 16:10:00 -0700134 const int& status = std::get<0>(response);
James Feist6ef20402019-01-07 16:45:08 -0800135
Ed Tanous2049bd22022-07-09 07:20:26 -0700136 if (ec || (status != 0))
Ed Tanousbb679322022-05-16 16:10:00 -0700137 {
138 std::cerr << "Error setting init command for device: " << name
139 << "\n";
140 }
James Feist6ef20402019-01-07 16:45:08 -0800141 },
142 "xyz.openbmc_project.Ipmi.Channel.Ipmb",
143 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb",
144 "sendRequest", commandAddress, netfn, lun, *initCommand, initData);
145 }
James Feist6ef20402019-01-07 16:45:08 -0800146}
147
148void IpmbSensor::loadDefaults()
149{
150 if (type == IpmbType::meSensor)
151 {
152 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200153 netfn = ipmi::sensor::netFn;
154 command = ipmi::sensor::getSensorReading;
James Feist6ef20402019-01-07 16:45:08 -0800155 commandData = {deviceAddress};
James Feistd7ae29a2020-06-25 15:42:46 -0700156 readingFormat = ReadingFormat::byte0;
James Feist6ef20402019-01-07 16:45:08 -0800157 }
158 else if (type == IpmbType::PXE1410CVR)
159 {
160 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200161 netfn = ipmi::me_bridge::netFn;
162 command = ipmi::me_bridge::sendRawPmbus;
163 initCommand = ipmi::me_bridge::sendRawPmbus;
James Feistd7ae29a2020-06-25 15:42:46 -0700164 // pmbus read temp
Anoop S832a2c62020-11-20 19:21:22 +0000165 commandData = {0x57, 0x01, 0x00, 0x16, hostSMbusIndex,
166 deviceAddress, 0x00, 0x00, 0x00, 0x00,
167 0x01, 0x02, 0x8d};
James Feistd7ae29a2020-06-25 15:42:46 -0700168 // goto page 0
Anoop S832a2c62020-11-20 19:21:22 +0000169 initData = {0x57, 0x01, 0x00, 0x14, hostSMbusIndex,
170 deviceAddress, 0x00, 0x00, 0x00, 0x00,
171 0x02, 0x00, 0x00, 0x00};
Jayashree-D37322572021-03-19 17:40:56 +0530172 readingFormat = ReadingFormat::linearElevenBit;
James Feist6ef20402019-01-07 16:45:08 -0800173 }
174 else if (type == IpmbType::IR38363VR)
175 {
176 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200177 netfn = ipmi::me_bridge::netFn;
178 command = ipmi::me_bridge::sendRawPmbus;
James Feistd7ae29a2020-06-25 15:42:46 -0700179 // pmbus read temp
Anoop S832a2c62020-11-20 19:21:22 +0000180 commandData = {0x57, 0x01, 0x00, 0x16, hostSMbusIndex,
181 deviceAddress, 00, 0x00, 0x00, 0x00,
182 0x01, 0x02, 0x8D};
James Feistd7ae29a2020-06-25 15:42:46 -0700183 readingFormat = ReadingFormat::elevenBitShift;
James Feist6ef20402019-01-07 16:45:08 -0800184 }
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700185 else if (type == IpmbType::ADM1278HSC)
186 {
187 commandAddress = meAddress;
Ed Tanousa771f6a2022-01-14 09:36:51 -0800188 uint8_t snsNum = 0;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700189 switch (subType)
190 {
191 case IpmbSubType::temp:
192 case IpmbSubType::curr:
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700193 if (subType == IpmbSubType::temp)
Ed Tanous8a57ec02020-10-09 12:46:52 -0700194 {
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700195 snsNum = 0x8d;
Ed Tanous8a57ec02020-10-09 12:46:52 -0700196 }
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700197 else
Ed Tanous8a57ec02020-10-09 12:46:52 -0700198 {
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700199 snsNum = 0x8c;
Ed Tanous8a57ec02020-10-09 12:46:52 -0700200 }
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200201 netfn = ipmi::me_bridge::netFn;
202 command = ipmi::me_bridge::sendRawPmbus;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700203 commandData = {0x57, 0x01, 0x00, 0x86, deviceAddress,
204 0x00, 0x00, 0x01, 0x02, snsNum};
James Feistd7ae29a2020-06-25 15:42:46 -0700205 readingFormat = ReadingFormat::elevenBit;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700206 break;
207 case IpmbSubType::power:
208 case IpmbSubType::volt:
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200209 netfn = ipmi::sensor::netFn;
210 command = ipmi::sensor::getSensorReading;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700211 commandData = {deviceAddress};
James Feistd7ae29a2020-06-25 15:42:46 -0700212 readingFormat = ReadingFormat::byte0;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700213 break;
214 default:
215 throw std::runtime_error("Invalid sensor type");
216 }
217 }
James Feist6ef20402019-01-07 16:45:08 -0800218 else if (type == IpmbType::mpsVR)
219 {
220 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200221 netfn = ipmi::me_bridge::netFn;
222 command = ipmi::me_bridge::sendRawPmbus;
223 initCommand = ipmi::me_bridge::sendRawPmbus;
James Feistd7ae29a2020-06-25 15:42:46 -0700224 // pmbus read temp
Anoop S832a2c62020-11-20 19:21:22 +0000225 commandData = {0x57, 0x01, 0x00, 0x16, hostSMbusIndex,
226 deviceAddress, 0x00, 0x00, 0x00, 0x00,
227 0x01, 0x02, 0x8d};
James Feistd7ae29a2020-06-25 15:42:46 -0700228 // goto page 0
Anoop S832a2c62020-11-20 19:21:22 +0000229 initData = {0x57, 0x01, 0x00, 0x14, hostSMbusIndex,
230 deviceAddress, 0x00, 0x00, 0x00, 0x00,
231 0x02, 0x00, 0x00, 0x00};
James Feistd7ae29a2020-06-25 15:42:46 -0700232 readingFormat = ReadingFormat::byte3;
James Feist6ef20402019-01-07 16:45:08 -0800233 }
234 else
235 {
236 throw std::runtime_error("Invalid sensor type");
237 }
Adrian Ambrożewicz45e92772020-06-04 13:59:55 +0200238
239 if (subType == IpmbSubType::util)
240 {
241 // Utilization need to be scaled to percent
242 maxValue = 100;
243 minValue = 0;
244 }
James Feist6ef20402019-01-07 16:45:08 -0800245}
246
247void IpmbSensor::checkThresholds(void)
248{
James Feist6ef20402019-01-07 16:45:08 -0800249 thresholds::checkThresholds(this);
250}
251
James Feist961bf092020-07-01 16:38:12 -0700252bool IpmbSensor::processReading(const std::vector<uint8_t>& data, double& resp)
James Feistd7ae29a2020-06-25 15:42:46 -0700253{
254
255 switch (readingFormat)
256 {
257 case (ReadingFormat::byte0):
James Feiste4a970d2020-08-19 11:21:58 -0700258 {
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200259 if (command == ipmi::sensor::getSensorReading &&
260 !ipmi::sensor::isValid(data))
James Feistcf4238e2020-07-28 16:40:03 -0700261 {
262 return false;
263 }
James Feist961bf092020-07-01 16:38:12 -0700264 resp = data[0];
265 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700266 }
James Feistd7ae29a2020-06-25 15:42:46 -0700267 case (ReadingFormat::byte3):
James Feiste4a970d2020-08-19 11:21:58 -0700268 {
James Feistd7ae29a2020-06-25 15:42:46 -0700269 if (data.size() < 4)
270 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700271 if (errCount == 0U)
James Feist961bf092020-07-01 16:38:12 -0700272 {
273 std::cerr << "Invalid data length returned for " << name
274 << "\n";
275 }
276 return false;
James Feistd7ae29a2020-06-25 15:42:46 -0700277 }
James Feist961bf092020-07-01 16:38:12 -0700278 resp = data[3];
279 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700280 }
James Feistd7ae29a2020-06-25 15:42:46 -0700281 case (ReadingFormat::elevenBit):
James Feiste4a970d2020-08-19 11:21:58 -0700282 {
James Feistd7ae29a2020-06-25 15:42:46 -0700283 if (data.size() < 5)
284 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700285 if (errCount == 0U)
James Feist961bf092020-07-01 16:38:12 -0700286 {
287 std::cerr << "Invalid data length returned for " << name
288 << "\n";
289 }
290 return false;
James Feistd7ae29a2020-06-25 15:42:46 -0700291 }
292
James Feiste4a970d2020-08-19 11:21:58 -0700293 int16_t value = ((data[4] << 8) | data[3]);
James Feiste4a970d2020-08-19 11:21:58 -0700294 resp = value;
James Feist961bf092020-07-01 16:38:12 -0700295 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700296 }
James Feistd7ae29a2020-06-25 15:42:46 -0700297 case (ReadingFormat::elevenBitShift):
James Feiste4a970d2020-08-19 11:21:58 -0700298 {
James Feistd7ae29a2020-06-25 15:42:46 -0700299 if (data.size() < 5)
300 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700301 if (errCount == 0U)
James Feist961bf092020-07-01 16:38:12 -0700302 {
303 std::cerr << "Invalid data length returned for " << name
304 << "\n";
305 }
306 return false;
James Feistd7ae29a2020-06-25 15:42:46 -0700307 }
308
James Feist961bf092020-07-01 16:38:12 -0700309 resp = ((data[4] << 8) | data[3]) >> 3;
310 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700311 }
Jayashree-D37322572021-03-19 17:40:56 +0530312 case (ReadingFormat::linearElevenBit):
313 {
314 if (data.size() < 5)
315 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700316 if (errCount == 0U)
Jayashree-D37322572021-03-19 17:40:56 +0530317 {
318 std::cerr << "Invalid data length returned for " << name
319 << "\n";
320 }
321 return false;
322 }
323
324 int16_t value = ((data[4] << 8) | data[3]);
325 constexpr const size_t shift = 16 - 11; // 11bit into 16bit
326 value <<= shift;
327 value >>= shift;
328 resp = value;
329 return true;
330 }
James Feistd7ae29a2020-06-25 15:42:46 -0700331 default:
332 throw std::runtime_error("Invalid reading type");
333 }
334}
335
James Feist6ef20402019-01-07 16:45:08 -0800336void IpmbSensor::read(void)
337{
Ed Tanous9b4a20e2022-09-06 08:47:11 -0700338 waitTimer.expires_from_now(std::chrono::milliseconds(sensorPollMs));
James Feist6ef20402019-01-07 16:45:08 -0800339 waitTimer.async_wait([this](const boost::system::error_code& ec) {
340 if (ec == boost::asio::error::operation_aborted)
341 {
342 return; // we're being canceled
343 }
Adrian Ambrożewicz623723b2020-07-29 12:53:54 +0200344 if (!readingStateGood())
James Feist6ef20402019-01-07 16:45:08 -0800345 {
Adrian Ambrożewicz623723b2020-07-29 12:53:54 +0200346 updateValue(std::numeric_limits<double>::quiet_NaN());
James Feist6ef20402019-01-07 16:45:08 -0800347 read();
348 return;
349 }
350 dbusConnection->async_method_call(
351 [this](boost::system::error_code ec,
352 const IpmbMethodType& response) {
Ed Tanousbb679322022-05-16 16:10:00 -0700353 const int& status = std::get<0>(response);
Ed Tanous2049bd22022-07-09 07:20:26 -0700354 if (ec || (status != 0))
Ed Tanousbb679322022-05-16 16:10:00 -0700355 {
356 incrementError();
James Feist6ef20402019-01-07 16:45:08 -0800357 read();
Ed Tanousbb679322022-05-16 16:10:00 -0700358 return;
359 }
360 const std::vector<uint8_t>& data = std::get<5>(response);
361 if constexpr (debug)
362 {
363 std::cout << name << ": ";
364 for (size_t d : data)
365 {
366 std::cout << d << " ";
367 }
368 std::cout << "\n";
369 }
370 if (data.empty())
371 {
372 incrementError();
373 read();
374 return;
375 }
376
377 double value = 0;
378
379 if (!processReading(data, value))
380 {
381 incrementError();
382 read();
383 return;
384 }
385
386 // rawValue only used in debug logging
387 // up to 5th byte in data are used to derive value
388 size_t end = std::min(sizeof(uint64_t), data.size());
389 uint64_t rawData = 0;
390 for (size_t i = 0; i < end; i++)
391 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700392 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
Ed Tanousbb679322022-05-16 16:10:00 -0700393 reinterpret_cast<uint8_t*>(&rawData)[i] = data[i];
394 }
395 rawValue = static_cast<double>(rawData);
396
397 /* Adjust value as per scale and offset */
398 value = (value * scaleVal) + offsetVal;
399 updateValue(value);
400 read();
James Feist6ef20402019-01-07 16:45:08 -0800401 },
402 "xyz.openbmc_project.Ipmi.Channel.Ipmb",
403 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb",
404 "sendRequest", commandAddress, netfn, lun, command, commandData);
405 });
406}
Jayashree Dhanapal84189752022-03-07 12:51:54 +0530407
408bool IpmbSensor::sensorClassType(const std::string& sensorClass)
409{
410 if (sensorClass == "PxeBridgeTemp")
411 {
412 type = IpmbType::PXE1410CVR;
413 }
414 else if (sensorClass == "IRBridgeTemp")
415 {
416 type = IpmbType::IR38363VR;
417 }
418 else if (sensorClass == "HSCBridge")
419 {
420 type = IpmbType::ADM1278HSC;
421 }
422 else if (sensorClass == "MpsBridgeTemp")
423 {
424 type = IpmbType::mpsVR;
425 }
426 else if (sensorClass == "METemp" || sensorClass == "MESensor")
427 {
428 type = IpmbType::meSensor;
429 }
430 else
431 {
432 std::cerr << "Invalid class " << sensorClass << "\n";
433 return false;
434 }
435 return true;
436}
437
438void IpmbSensor::sensorSubType(const std::string& sensorTypeName)
439{
440 if (sensorTypeName == "voltage")
441 {
442 subType = IpmbSubType::volt;
443 }
444 else if (sensorTypeName == "power")
445 {
446 subType = IpmbSubType::power;
447 }
448 else if (sensorTypeName == "current")
449 {
450 subType = IpmbSubType::curr;
451 }
452 else if (sensorTypeName == "utilization")
453 {
454 subType = IpmbSubType::util;
455 }
456 else
457 {
458 subType = IpmbSubType::temp;
459 }
460}
461
462void IpmbSensor::parseConfigValues(const SensorBaseConfigMap& entry)
463{
464 auto findScaleVal = entry.find("ScaleValue");
465 if (findScaleVal != entry.end())
466 {
467 scaleVal = std::visit(VariantToDoubleVisitor(), findScaleVal->second);
468 }
469
470 auto findOffsetVal = entry.find("OffsetValue");
471 if (findOffsetVal != entry.end())
472 {
473 offsetVal = std::visit(VariantToDoubleVisitor(), findOffsetVal->second);
474 }
475
Zev Weissa4d27682022-07-19 15:30:36 -0700476 readState = getPowerState(entry);
Jayashree Dhanapal84189752022-03-07 12:51:54 +0530477}
478
James Feist6ef20402019-01-07 16:45:08 -0800479void createSensors(
480 boost::asio::io_service& io, sdbusplus::asio::object_server& objectServer,
481 boost::container::flat_map<std::string, std::unique_ptr<IpmbSensor>>&
482 sensors,
483 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection)
484{
485 if (!dbusConnection)
486 {
487 std::cerr << "Connection not created\n";
488 return;
489 }
490 dbusConnection->async_method_call(
491 [&](boost::system::error_code ec, const ManagedObjectType& resp) {
Ed Tanousbb679322022-05-16 16:10:00 -0700492 if (ec)
493 {
494 std::cerr << "Error contacting entity manager\n";
495 return;
496 }
Zev Weiss8ba551b2022-08-12 18:21:02 -0700497 for (const auto& [path, interfaces] : resp)
Ed Tanousbb679322022-05-16 16:10:00 -0700498 {
Zev Weiss8ba551b2022-08-12 18:21:02 -0700499 for (const auto& [intf, cfg] : interfaces)
James Feist6ef20402019-01-07 16:45:08 -0800500 {
Zev Weiss054aad82022-08-18 01:37:34 -0700501 if (intf != configInterfaceName(sensorType))
James Feist6ef20402019-01-07 16:45:08 -0800502 {
Ed Tanousbb679322022-05-16 16:10:00 -0700503 continue;
James Feist6ef20402019-01-07 16:45:08 -0800504 }
Zev Weiss8ba551b2022-08-12 18:21:02 -0700505 std::string name = loadVariant<std::string>(cfg, "Name");
Ed Tanousbb679322022-05-16 16:10:00 -0700506
507 std::vector<thresholds::Threshold> sensorThresholds;
Zev Weiss8ba551b2022-08-12 18:21:02 -0700508 if (!parseThresholdsFromConfig(interfaces, sensorThresholds))
Ed Tanousbb679322022-05-16 16:10:00 -0700509 {
510 std::cerr << "error populating thresholds for " << name
511 << "\n";
512 }
Zev Weiss8ba551b2022-08-12 18:21:02 -0700513 uint8_t deviceAddress = loadVariant<uint8_t>(cfg, "Address");
Ed Tanousbb679322022-05-16 16:10:00 -0700514
515 std::string sensorClass =
Zev Weiss8ba551b2022-08-12 18:21:02 -0700516 loadVariant<std::string>(cfg, "Class");
Ed Tanousbb679322022-05-16 16:10:00 -0700517
518 uint8_t hostSMbusIndex = hostSMbusIndexDefault;
Zev Weiss8ba551b2022-08-12 18:21:02 -0700519 auto findSmType = cfg.find("HostSMbusIndex");
520 if (findSmType != cfg.end())
Ed Tanousbb679322022-05-16 16:10:00 -0700521 {
522 hostSMbusIndex = std::visit(VariantToUnsignedIntVisitor(),
523 findSmType->second);
524 }
525
Zev Weiss8569bf22022-10-11 15:37:44 -0700526 float pollRate = getPollRate(cfg, pollRateDefault);
Ed Tanousbb679322022-05-16 16:10:00 -0700527
528 /* Default sensor type is "temperature" */
529 std::string sensorTypeName = "temperature";
Zev Weiss8ba551b2022-08-12 18:21:02 -0700530 auto findType = cfg.find("SensorType");
531 if (findType != cfg.end())
Ed Tanousbb679322022-05-16 16:10:00 -0700532 {
533 sensorTypeName =
534 std::visit(VariantToStringVisitor(), findType->second);
535 }
536
537 auto& sensor = sensors[name];
538 sensor = std::make_unique<IpmbSensor>(
Zev Weiss8ba551b2022-08-12 18:21:02 -0700539 dbusConnection, io, name, path, objectServer,
Ed Tanousbb679322022-05-16 16:10:00 -0700540 std::move(sensorThresholds), deviceAddress, hostSMbusIndex,
541 pollRate, sensorTypeName);
542
Zev Weiss8ba551b2022-08-12 18:21:02 -0700543 sensor->parseConfigValues(cfg);
Ed Tanousbb679322022-05-16 16:10:00 -0700544 if (!(sensor->sensorClassType(sensorClass)))
545 {
546 continue;
547 }
548 sensor->sensorSubType(sensorTypeName);
549 sensor->init();
James Feist6ef20402019-01-07 16:45:08 -0800550 }
Ed Tanousbb679322022-05-16 16:10:00 -0700551 }
James Feist6ef20402019-01-07 16:45:08 -0800552 },
JeffLin2c5a1f22022-10-05 15:19:09 +0800553 entityManagerName, "/xyz/openbmc_project/inventory",
554 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
James Feist6ef20402019-01-07 16:45:08 -0800555}
556
Patrick Williams92f8f512022-07-22 19:26:55 -0500557void reinitSensors(sdbusplus::message_t& message)
James Feistf7e2c5d2019-02-13 17:27:51 -0800558{
James Feist0d4f2bd2019-03-05 13:15:40 -0800559 constexpr const size_t reinitWaitSeconds = 2;
James Feistf7e2c5d2019-02-13 17:27:51 -0800560 std::string objectName;
James Feist52497fd2019-06-07 13:01:33 -0700561 boost::container::flat_map<std::string, std::variant<std::string>> values;
James Feistf7e2c5d2019-02-13 17:27:51 -0800562 message.read(objectName, values);
James Feist0d4f2bd2019-03-05 13:15:40 -0800563
James Feist52497fd2019-06-07 13:01:33 -0700564 auto findStatus = values.find(power::property);
565 if (findStatus != values.end())
James Feistf7e2c5d2019-02-13 17:27:51 -0800566 {
Zev Weiss6c106d62022-08-17 20:50:00 -0700567 bool powerStatus =
568 std::get<std::string>(findStatus->second).ends_with(".Running");
James Feistf7e2c5d2019-02-13 17:27:51 -0800569 if (powerStatus)
570 {
James Feist0d4f2bd2019-03-05 13:15:40 -0800571 if (!initCmdTimer)
James Feistf7e2c5d2019-02-13 17:27:51 -0800572 {
James Feist0d4f2bd2019-03-05 13:15:40 -0800573 // this should be impossible
574 return;
James Feistf7e2c5d2019-02-13 17:27:51 -0800575 }
James Feist0d4f2bd2019-03-05 13:15:40 -0800576 // we seem to send this command too fast sometimes, wait before
577 // sending
578 initCmdTimer->expires_from_now(
Ed Tanous9b4a20e2022-09-06 08:47:11 -0700579 std::chrono::seconds(reinitWaitSeconds));
James Feist0d4f2bd2019-03-05 13:15:40 -0800580
581 initCmdTimer->async_wait([](const boost::system::error_code ec) {
582 if (ec == boost::asio::error::operation_aborted)
583 {
584 return; // we're being canceled
585 }
586
Zev Weiss8ba551b2022-08-12 18:21:02 -0700587 for (const auto& [name, sensor] : sensors)
James Feist0d4f2bd2019-03-05 13:15:40 -0800588 {
Zev Weiss8ba551b2022-08-12 18:21:02 -0700589 if (sensor)
James Feist0d4f2bd2019-03-05 13:15:40 -0800590 {
Zev Weiss8ba551b2022-08-12 18:21:02 -0700591 sensor->runInitCmd();
James Feist0d4f2bd2019-03-05 13:15:40 -0800592 }
593 }
594 });
James Feistf7e2c5d2019-02-13 17:27:51 -0800595 }
596 }
597}
598
James Feistb6c0b912019-07-09 12:21:44 -0700599int main()
James Feist6ef20402019-01-07 16:45:08 -0800600{
601
602 boost::asio::io_service io;
603 auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
Ed Tanous14ed5e92022-07-12 15:50:23 -0700604 sdbusplus::asio::object_server objectServer(systemBus, true);
605 objectServer.add_manager("/xyz/openbmc_project/sensors");
James Feist6ef20402019-01-07 16:45:08 -0800606 systemBus->request_name("xyz.openbmc_project.IpmbSensor");
James Feist6ef20402019-01-07 16:45:08 -0800607
Ed Tanous9b4a20e2022-09-06 08:47:11 -0700608 initCmdTimer = std::make_unique<boost::asio::steady_timer>(io);
James Feist0d4f2bd2019-03-05 13:15:40 -0800609
James Feist6ef20402019-01-07 16:45:08 -0800610 io.post([&]() { createSensors(io, objectServer, sensors, systemBus); });
611
Ed Tanous9b4a20e2022-09-06 08:47:11 -0700612 boost::asio::steady_timer configTimer(io);
James Feist6ef20402019-01-07 16:45:08 -0800613
Patrick Williams92f8f512022-07-22 19:26:55 -0500614 std::function<void(sdbusplus::message_t&)> eventHandler =
615 [&](sdbusplus::message_t&) {
Ed Tanous9b4a20e2022-09-06 08:47:11 -0700616 configTimer.expires_from_now(std::chrono::seconds(1));
Ed Tanousbb679322022-05-16 16:10:00 -0700617 // create a timer because normally multiple properties change
618 configTimer.async_wait([&](const boost::system::error_code& ec) {
619 if (ec == boost::asio::error::operation_aborted)
620 {
621 return; // we're being canceled
622 }
623 createSensors(io, objectServer, sensors, systemBus);
624 if (sensors.empty())
625 {
626 std::cout << "Configuration not detected\n";
627 }
628 });
629 };
James Feist6ef20402019-01-07 16:45:08 -0800630
Zev Weiss214d9712022-08-12 12:54:31 -0700631 std::vector<std::unique_ptr<sdbusplus::bus::match_t>> matches =
632 setupPropertiesChangedMatches(
Zev Weiss054aad82022-08-18 01:37:34 -0700633 *systemBus, std::to_array<const char*>({sensorType}), eventHandler);
James Feist6ef20402019-01-07 16:45:08 -0800634
Patrick Williams92f8f512022-07-22 19:26:55 -0500635 sdbusplus::bus::match_t powerChangeMatch(
636 static_cast<sdbusplus::bus_t&>(*systemBus),
James Feist52497fd2019-06-07 13:01:33 -0700637 "type='signal',interface='" + std::string(properties::interface) +
638 "',path='" + std::string(power::path) + "',arg0='" +
639 std::string(power::interface) + "'",
James Feistf7e2c5d2019-02-13 17:27:51 -0800640 reinitSensors);
641
Bruce Lee1263c3d2021-06-04 15:16:33 +0800642 setupManufacturingModeMatch(*systemBus);
James Feist6ef20402019-01-07 16:45:08 -0800643 io.run();
Zhikui Rene76a5a62021-07-09 15:16:32 -0700644 return 0;
James Feist6ef20402019-01-07 16:45:08 -0800645}