blob: 2af79e4c3fb9b589a0ac5b31efcf3a2c7d8b3069 [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 Dhanapal6ee62942021-12-14 15:22:23 +053046static constexpr uint8_t ipmbBusIndexDefault = 0;
Jayashree-D9f6d4fd2021-04-13 18:27:22 +053047static constexpr float pollRateDefault = 1; // in seconds
James Feist6ef20402019-01-07 16:45:08 -080048
Vijay Khemka682a5cb2019-07-18 17:34:03 -070049static constexpr const char* sensorPathPrefix = "/xyz/openbmc_project/sensors/";
50
James Feist6ef20402019-01-07 16:45:08 -080051using IpmbMethodType =
52 std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>;
53
James Feistf7e2c5d2019-02-13 17:27:51 -080054boost::container::flat_map<std::string, std::unique_ptr<IpmbSensor>> sensors;
55
Ed Tanous9b4a20e2022-09-06 08:47:11 -070056std::unique_ptr<boost::asio::steady_timer> initCmdTimer;
James Feist0d4f2bd2019-03-05 13:15:40 -080057
James Feist6ef20402019-01-07 16:45:08 -080058IpmbSensor::IpmbSensor(std::shared_ptr<sdbusplus::asio::connection>& conn,
59 boost::asio::io_service& io,
60 const std::string& sensorName,
61 const std::string& sensorConfiguration,
62 sdbusplus::asio::object_server& objectServer,
63 std::vector<thresholds::Threshold>&& thresholdData,
Anoop S832a2c62020-11-20 19:21:22 +000064 uint8_t deviceAddress, uint8_t hostSMbusIndex,
Jayashree-D9f6d4fd2021-04-13 18:27:22 +053065 const float pollRate, std::string& sensorTypeName) :
Zhikui Renda98f092021-11-01 09:41:08 -070066 Sensor(escapeName(sensorName), std::move(thresholdData),
Zev Weiss054aad82022-08-18 01:37:34 -070067 sensorConfiguration, "IpmbSensor", false, false, ipmbMaxReading,
68 ipmbMinReading, conn, PowerState::on),
Anoop S832a2c62020-11-20 19:21:22 +000069 deviceAddress(deviceAddress), hostSMbusIndex(hostSMbusIndex),
Jayashree-D9f6d4fd2021-04-13 18:27:22 +053070 sensorPollMs(static_cast<int>(pollRate * 1000)), objectServer(objectServer),
71 waitTimer(io)
James Feist6ef20402019-01-07 16:45:08 -080072{
Vijay Khemka682a5cb2019-07-18 17:34:03 -070073 std::string dbusPath = sensorPathPrefix + sensorTypeName + "/" + name;
74
James Feist6ef20402019-01-07 16:45:08 -080075 sensorInterface = objectServer.add_interface(
Vijay Khemka682a5cb2019-07-18 17:34:03 -070076 dbusPath, "xyz.openbmc_project.Sensor.Value");
James Feist6ef20402019-01-07 16:45:08 -080077
Jayashree Dhanapal56678082022-01-04 17:27:20 +053078 for (const auto& threshold : thresholds)
James Feist6ef20402019-01-07 16:45:08 -080079 {
Jayashree Dhanapal56678082022-01-04 17:27:20 +053080 std::string interface = thresholds::getInterface(threshold.level);
81 thresholdInterfaces[static_cast<size_t>(threshold.level)] =
82 objectServer.add_interface(dbusPath, interface);
James Feist6ef20402019-01-07 16:45:08 -080083 }
James Feist2adc95c2019-09-30 14:55:28 -070084 association = objectServer.add_interface(dbusPath, association::interface);
James Feist6ef20402019-01-07 16:45:08 -080085}
86
87IpmbSensor::~IpmbSensor()
88{
89 waitTimer.cancel();
Jayashree Dhanapal56678082022-01-04 17:27:20 +053090 for (const auto& iface : thresholdInterfaces)
91 {
92 objectServer.remove_interface(iface);
93 }
James Feist6ef20402019-01-07 16:45:08 -080094 objectServer.remove_interface(sensorInterface);
James Feist078f2322019-03-08 11:09:05 -080095 objectServer.remove_interface(association);
James Feist6ef20402019-01-07 16:45:08 -080096}
97
Ed Tanous2049bd22022-07-09 07:20:26 -070098std::string IpmbSensor::getSubTypeUnits(void) const
Zev Weiss6b6891c2021-04-22 02:46:21 -050099{
100 switch (subType)
101 {
102 case IpmbSubType::temp:
103 return sensor_paths::unitDegreesC;
104 case IpmbSubType::curr:
105 return sensor_paths::unitAmperes;
106 case IpmbSubType::power:
107 return sensor_paths::unitWatts;
108 case IpmbSubType::volt:
109 return sensor_paths::unitVolts;
110 case IpmbSubType::util:
111 return sensor_paths::unitPercent;
112 default:
113 throw std::runtime_error("Invalid sensor type");
114 }
115}
116
James Feist6ef20402019-01-07 16:45:08 -0800117void IpmbSensor::init(void)
118{
James Feist6ef20402019-01-07 16:45:08 -0800119 loadDefaults();
Andrei Kartashev39287412022-02-04 16:04:47 +0300120 setInitialProperties(getSubTypeUnits());
James Feist6ef20402019-01-07 16:45:08 -0800121 if (initCommand)
122 {
James Feistf7e2c5d2019-02-13 17:27:51 -0800123 runInitCmd();
124 }
125 read();
126}
127
128void IpmbSensor::runInitCmd()
129{
130 if (initCommand)
131 {
James Feist6ef20402019-01-07 16:45:08 -0800132 dbusConnection->async_method_call(
133 [this](boost::system::error_code ec,
134 const IpmbMethodType& response) {
Ed Tanousbb679322022-05-16 16:10:00 -0700135 const int& status = std::get<0>(response);
James Feist6ef20402019-01-07 16:45:08 -0800136
Ed Tanous2049bd22022-07-09 07:20:26 -0700137 if (ec || (status != 0))
Ed Tanousbb679322022-05-16 16:10:00 -0700138 {
139 std::cerr << "Error setting init command for device: " << name
140 << "\n";
141 }
James Feist6ef20402019-01-07 16:45:08 -0800142 },
143 "xyz.openbmc_project.Ipmi.Channel.Ipmb",
144 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb",
145 "sendRequest", commandAddress, netfn, lun, *initCommand, initData);
146 }
James Feist6ef20402019-01-07 16:45:08 -0800147}
148
149void IpmbSensor::loadDefaults()
150{
151 if (type == IpmbType::meSensor)
152 {
153 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200154 netfn = ipmi::sensor::netFn;
155 command = ipmi::sensor::getSensorReading;
James Feist6ef20402019-01-07 16:45:08 -0800156 commandData = {deviceAddress};
James Feistd7ae29a2020-06-25 15:42:46 -0700157 readingFormat = ReadingFormat::byte0;
James Feist6ef20402019-01-07 16:45:08 -0800158 }
159 else if (type == IpmbType::PXE1410CVR)
160 {
161 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200162 netfn = ipmi::me_bridge::netFn;
163 command = ipmi::me_bridge::sendRawPmbus;
164 initCommand = ipmi::me_bridge::sendRawPmbus;
James Feistd7ae29a2020-06-25 15:42:46 -0700165 // pmbus read temp
Anoop S832a2c62020-11-20 19:21:22 +0000166 commandData = {0x57, 0x01, 0x00, 0x16, hostSMbusIndex,
167 deviceAddress, 0x00, 0x00, 0x00, 0x00,
168 0x01, 0x02, 0x8d};
James Feistd7ae29a2020-06-25 15:42:46 -0700169 // goto page 0
Anoop S832a2c62020-11-20 19:21:22 +0000170 initData = {0x57, 0x01, 0x00, 0x14, hostSMbusIndex,
171 deviceAddress, 0x00, 0x00, 0x00, 0x00,
172 0x02, 0x00, 0x00, 0x00};
Jayashree-D37322572021-03-19 17:40:56 +0530173 readingFormat = ReadingFormat::linearElevenBit;
James Feist6ef20402019-01-07 16:45:08 -0800174 }
175 else if (type == IpmbType::IR38363VR)
176 {
177 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200178 netfn = ipmi::me_bridge::netFn;
179 command = ipmi::me_bridge::sendRawPmbus;
James Feistd7ae29a2020-06-25 15:42:46 -0700180 // pmbus read temp
Anoop S832a2c62020-11-20 19:21:22 +0000181 commandData = {0x57, 0x01, 0x00, 0x16, hostSMbusIndex,
182 deviceAddress, 00, 0x00, 0x00, 0x00,
183 0x01, 0x02, 0x8D};
James Feistd7ae29a2020-06-25 15:42:46 -0700184 readingFormat = ReadingFormat::elevenBitShift;
James Feist6ef20402019-01-07 16:45:08 -0800185 }
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700186 else if (type == IpmbType::ADM1278HSC)
187 {
188 commandAddress = meAddress;
Ed Tanousa771f6a2022-01-14 09:36:51 -0800189 uint8_t snsNum = 0;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700190 switch (subType)
191 {
192 case IpmbSubType::temp:
193 case IpmbSubType::curr:
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700194 if (subType == IpmbSubType::temp)
Ed Tanous8a57ec02020-10-09 12:46:52 -0700195 {
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700196 snsNum = 0x8d;
Ed Tanous8a57ec02020-10-09 12:46:52 -0700197 }
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700198 else
Ed Tanous8a57ec02020-10-09 12:46:52 -0700199 {
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700200 snsNum = 0x8c;
Ed Tanous8a57ec02020-10-09 12:46:52 -0700201 }
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200202 netfn = ipmi::me_bridge::netFn;
203 command = ipmi::me_bridge::sendRawPmbus;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700204 commandData = {0x57, 0x01, 0x00, 0x86, deviceAddress,
205 0x00, 0x00, 0x01, 0x02, snsNum};
James Feistd7ae29a2020-06-25 15:42:46 -0700206 readingFormat = ReadingFormat::elevenBit;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700207 break;
208 case IpmbSubType::power:
209 case IpmbSubType::volt:
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200210 netfn = ipmi::sensor::netFn;
211 command = ipmi::sensor::getSensorReading;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700212 commandData = {deviceAddress};
James Feistd7ae29a2020-06-25 15:42:46 -0700213 readingFormat = ReadingFormat::byte0;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700214 break;
215 default:
216 throw std::runtime_error("Invalid sensor type");
217 }
218 }
James Feist6ef20402019-01-07 16:45:08 -0800219 else if (type == IpmbType::mpsVR)
220 {
221 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200222 netfn = ipmi::me_bridge::netFn;
223 command = ipmi::me_bridge::sendRawPmbus;
224 initCommand = ipmi::me_bridge::sendRawPmbus;
James Feistd7ae29a2020-06-25 15:42:46 -0700225 // pmbus read temp
Anoop S832a2c62020-11-20 19:21:22 +0000226 commandData = {0x57, 0x01, 0x00, 0x16, hostSMbusIndex,
227 deviceAddress, 0x00, 0x00, 0x00, 0x00,
228 0x01, 0x02, 0x8d};
James Feistd7ae29a2020-06-25 15:42:46 -0700229 // goto page 0
Anoop S832a2c62020-11-20 19:21:22 +0000230 initData = {0x57, 0x01, 0x00, 0x14, hostSMbusIndex,
231 deviceAddress, 0x00, 0x00, 0x00, 0x00,
232 0x02, 0x00, 0x00, 0x00};
James Feistd7ae29a2020-06-25 15:42:46 -0700233 readingFormat = ReadingFormat::byte3;
James Feist6ef20402019-01-07 16:45:08 -0800234 }
235 else
236 {
237 throw std::runtime_error("Invalid sensor type");
238 }
Adrian Ambrożewicz45e92772020-06-04 13:59:55 +0200239
240 if (subType == IpmbSubType::util)
241 {
242 // Utilization need to be scaled to percent
243 maxValue = 100;
244 minValue = 0;
245 }
James Feist6ef20402019-01-07 16:45:08 -0800246}
247
248void IpmbSensor::checkThresholds(void)
249{
James Feist6ef20402019-01-07 16:45:08 -0800250 thresholds::checkThresholds(this);
251}
252
James Feist961bf092020-07-01 16:38:12 -0700253bool IpmbSensor::processReading(const std::vector<uint8_t>& data, double& resp)
James Feistd7ae29a2020-06-25 15:42:46 -0700254{
255
256 switch (readingFormat)
257 {
258 case (ReadingFormat::byte0):
James Feiste4a970d2020-08-19 11:21:58 -0700259 {
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200260 if (command == ipmi::sensor::getSensorReading &&
261 !ipmi::sensor::isValid(data))
James Feistcf4238e2020-07-28 16:40:03 -0700262 {
263 return false;
264 }
James Feist961bf092020-07-01 16:38:12 -0700265 resp = data[0];
266 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700267 }
James Feistd7ae29a2020-06-25 15:42:46 -0700268 case (ReadingFormat::byte3):
James Feiste4a970d2020-08-19 11:21:58 -0700269 {
James Feistd7ae29a2020-06-25 15:42:46 -0700270 if (data.size() < 4)
271 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700272 if (errCount == 0U)
James Feist961bf092020-07-01 16:38:12 -0700273 {
274 std::cerr << "Invalid data length returned for " << name
275 << "\n";
276 }
277 return false;
James Feistd7ae29a2020-06-25 15:42:46 -0700278 }
James Feist961bf092020-07-01 16:38:12 -0700279 resp = data[3];
280 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700281 }
James Feistd7ae29a2020-06-25 15:42:46 -0700282 case (ReadingFormat::elevenBit):
James Feiste4a970d2020-08-19 11:21:58 -0700283 {
James Feistd7ae29a2020-06-25 15:42:46 -0700284 if (data.size() < 5)
285 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700286 if (errCount == 0U)
James Feist961bf092020-07-01 16:38:12 -0700287 {
288 std::cerr << "Invalid data length returned for " << name
289 << "\n";
290 }
291 return false;
James Feistd7ae29a2020-06-25 15:42:46 -0700292 }
293
James Feiste4a970d2020-08-19 11:21:58 -0700294 int16_t value = ((data[4] << 8) | data[3]);
James Feiste4a970d2020-08-19 11:21:58 -0700295 resp = value;
James Feist961bf092020-07-01 16:38:12 -0700296 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700297 }
James Feistd7ae29a2020-06-25 15:42:46 -0700298 case (ReadingFormat::elevenBitShift):
James Feiste4a970d2020-08-19 11:21:58 -0700299 {
James Feistd7ae29a2020-06-25 15:42:46 -0700300 if (data.size() < 5)
301 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700302 if (errCount == 0U)
James Feist961bf092020-07-01 16:38:12 -0700303 {
304 std::cerr << "Invalid data length returned for " << name
305 << "\n";
306 }
307 return false;
James Feistd7ae29a2020-06-25 15:42:46 -0700308 }
309
James Feist961bf092020-07-01 16:38:12 -0700310 resp = ((data[4] << 8) | data[3]) >> 3;
311 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700312 }
Jayashree-D37322572021-03-19 17:40:56 +0530313 case (ReadingFormat::linearElevenBit):
314 {
315 if (data.size() < 5)
316 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700317 if (errCount == 0U)
Jayashree-D37322572021-03-19 17:40:56 +0530318 {
319 std::cerr << "Invalid data length returned for " << name
320 << "\n";
321 }
322 return false;
323 }
324
325 int16_t value = ((data[4] << 8) | data[3]);
326 constexpr const size_t shift = 16 - 11; // 11bit into 16bit
327 value <<= shift;
328 value >>= shift;
329 resp = value;
330 return true;
331 }
James Feistd7ae29a2020-06-25 15:42:46 -0700332 default:
333 throw std::runtime_error("Invalid reading type");
334 }
335}
336
James Feist6ef20402019-01-07 16:45:08 -0800337void IpmbSensor::read(void)
338{
Ed Tanous9b4a20e2022-09-06 08:47:11 -0700339 waitTimer.expires_from_now(std::chrono::milliseconds(sensorPollMs));
James Feist6ef20402019-01-07 16:45:08 -0800340 waitTimer.async_wait([this](const boost::system::error_code& ec) {
341 if (ec == boost::asio::error::operation_aborted)
342 {
343 return; // we're being canceled
344 }
Adrian Ambrożewicz623723b2020-07-29 12:53:54 +0200345 if (!readingStateGood())
James Feist6ef20402019-01-07 16:45:08 -0800346 {
Adrian Ambrożewicz623723b2020-07-29 12:53:54 +0200347 updateValue(std::numeric_limits<double>::quiet_NaN());
James Feist6ef20402019-01-07 16:45:08 -0800348 read();
349 return;
350 }
351 dbusConnection->async_method_call(
352 [this](boost::system::error_code ec,
353 const IpmbMethodType& response) {
Ed Tanousbb679322022-05-16 16:10:00 -0700354 const int& status = std::get<0>(response);
Ed Tanous2049bd22022-07-09 07:20:26 -0700355 if (ec || (status != 0))
Ed Tanousbb679322022-05-16 16:10:00 -0700356 {
357 incrementError();
James Feist6ef20402019-01-07 16:45:08 -0800358 read();
Ed Tanousbb679322022-05-16 16:10:00 -0700359 return;
360 }
361 const std::vector<uint8_t>& data = std::get<5>(response);
362 if constexpr (debug)
363 {
364 std::cout << name << ": ";
365 for (size_t d : data)
366 {
367 std::cout << d << " ";
368 }
369 std::cout << "\n";
370 }
371 if (data.empty())
372 {
373 incrementError();
374 read();
375 return;
376 }
377
378 double value = 0;
379
380 if (!processReading(data, value))
381 {
382 incrementError();
383 read();
384 return;
385 }
386
387 // rawValue only used in debug logging
388 // up to 5th byte in data are used to derive value
389 size_t end = std::min(sizeof(uint64_t), data.size());
390 uint64_t rawData = 0;
391 for (size_t i = 0; i < end; i++)
392 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700393 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
Ed Tanousbb679322022-05-16 16:10:00 -0700394 reinterpret_cast<uint8_t*>(&rawData)[i] = data[i];
395 }
396 rawValue = static_cast<double>(rawData);
397
398 /* Adjust value as per scale and offset */
399 value = (value * scaleVal) + offsetVal;
400 updateValue(value);
401 read();
James Feist6ef20402019-01-07 16:45:08 -0800402 },
403 "xyz.openbmc_project.Ipmi.Channel.Ipmb",
404 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb",
405 "sendRequest", commandAddress, netfn, lun, command, commandData);
406 });
407}
Jayashree Dhanapal84189752022-03-07 12:51:54 +0530408
409bool IpmbSensor::sensorClassType(const std::string& sensorClass)
410{
411 if (sensorClass == "PxeBridgeTemp")
412 {
413 type = IpmbType::PXE1410CVR;
414 }
415 else if (sensorClass == "IRBridgeTemp")
416 {
417 type = IpmbType::IR38363VR;
418 }
419 else if (sensorClass == "HSCBridge")
420 {
421 type = IpmbType::ADM1278HSC;
422 }
423 else if (sensorClass == "MpsBridgeTemp")
424 {
425 type = IpmbType::mpsVR;
426 }
427 else if (sensorClass == "METemp" || sensorClass == "MESensor")
428 {
429 type = IpmbType::meSensor;
430 }
431 else
432 {
433 std::cerr << "Invalid class " << sensorClass << "\n";
434 return false;
435 }
436 return true;
437}
438
439void IpmbSensor::sensorSubType(const std::string& sensorTypeName)
440{
441 if (sensorTypeName == "voltage")
442 {
443 subType = IpmbSubType::volt;
444 }
445 else if (sensorTypeName == "power")
446 {
447 subType = IpmbSubType::power;
448 }
449 else if (sensorTypeName == "current")
450 {
451 subType = IpmbSubType::curr;
452 }
453 else if (sensorTypeName == "utilization")
454 {
455 subType = IpmbSubType::util;
456 }
457 else
458 {
459 subType = IpmbSubType::temp;
460 }
461}
462
463void IpmbSensor::parseConfigValues(const SensorBaseConfigMap& entry)
464{
465 auto findScaleVal = entry.find("ScaleValue");
466 if (findScaleVal != entry.end())
467 {
468 scaleVal = std::visit(VariantToDoubleVisitor(), findScaleVal->second);
469 }
470
471 auto findOffsetVal = entry.find("OffsetValue");
472 if (findOffsetVal != entry.end())
473 {
474 offsetVal = std::visit(VariantToDoubleVisitor(), findOffsetVal->second);
475 }
476
Zev Weissa4d27682022-07-19 15:30:36 -0700477 readState = getPowerState(entry);
Jayashree Dhanapal84189752022-03-07 12:51:54 +0530478}
479
James Feist6ef20402019-01-07 16:45:08 -0800480void createSensors(
481 boost::asio::io_service& io, sdbusplus::asio::object_server& objectServer,
482 boost::container::flat_map<std::string, std::unique_ptr<IpmbSensor>>&
483 sensors,
484 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection)
485{
486 if (!dbusConnection)
487 {
488 std::cerr << "Connection not created\n";
489 return;
490 }
491 dbusConnection->async_method_call(
492 [&](boost::system::error_code ec, const ManagedObjectType& resp) {
Ed Tanousbb679322022-05-16 16:10:00 -0700493 if (ec)
494 {
495 std::cerr << "Error contacting entity manager\n";
496 return;
497 }
Zev Weiss8ba551b2022-08-12 18:21:02 -0700498 for (const auto& [path, interfaces] : resp)
Ed Tanousbb679322022-05-16 16:10:00 -0700499 {
Zev Weiss8ba551b2022-08-12 18:21:02 -0700500 for (const auto& [intf, cfg] : interfaces)
James Feist6ef20402019-01-07 16:45:08 -0800501 {
Zev Weiss054aad82022-08-18 01:37:34 -0700502 if (intf != configInterfaceName(sensorType))
James Feist6ef20402019-01-07 16:45:08 -0800503 {
Ed Tanousbb679322022-05-16 16:10:00 -0700504 continue;
James Feist6ef20402019-01-07 16:45:08 -0800505 }
Zev Weiss8ba551b2022-08-12 18:21:02 -0700506 std::string name = loadVariant<std::string>(cfg, "Name");
Ed Tanousbb679322022-05-16 16:10:00 -0700507
508 std::vector<thresholds::Threshold> sensorThresholds;
Zev Weiss8ba551b2022-08-12 18:21:02 -0700509 if (!parseThresholdsFromConfig(interfaces, sensorThresholds))
Ed Tanousbb679322022-05-16 16:10:00 -0700510 {
511 std::cerr << "error populating thresholds for " << name
512 << "\n";
513 }
Zev Weiss8ba551b2022-08-12 18:21:02 -0700514 uint8_t deviceAddress = loadVariant<uint8_t>(cfg, "Address");
Ed Tanousbb679322022-05-16 16:10:00 -0700515
516 std::string sensorClass =
Zev Weiss8ba551b2022-08-12 18:21:02 -0700517 loadVariant<std::string>(cfg, "Class");
Ed Tanousbb679322022-05-16 16:10:00 -0700518
519 uint8_t hostSMbusIndex = hostSMbusIndexDefault;
Zev Weiss8ba551b2022-08-12 18:21:02 -0700520 auto findSmType = cfg.find("HostSMbusIndex");
521 if (findSmType != cfg.end())
Ed Tanousbb679322022-05-16 16:10:00 -0700522 {
523 hostSMbusIndex = std::visit(VariantToUnsignedIntVisitor(),
524 findSmType->second);
525 }
526
Zev Weiss8569bf22022-10-11 15:37:44 -0700527 float pollRate = getPollRate(cfg, pollRateDefault);
Ed Tanousbb679322022-05-16 16:10:00 -0700528
Jayashree Dhanapal6ee62942021-12-14 15:22:23 +0530529 uint8_t ipmbBusIndex = ipmbBusIndexDefault;
530 auto findBusType = cfg.find("Bus");
531 if (findBusType != cfg.end())
532 {
533 ipmbBusIndex = std::visit(VariantToUnsignedIntVisitor(),
534 findBusType->second);
535 std::cerr << "Ipmb Bus Index for " << name << " is "
536 << static_cast<int>(ipmbBusIndex) << "\n";
537 }
538
Ed Tanousbb679322022-05-16 16:10:00 -0700539 /* Default sensor type is "temperature" */
540 std::string sensorTypeName = "temperature";
Zev Weiss8ba551b2022-08-12 18:21:02 -0700541 auto findType = cfg.find("SensorType");
542 if (findType != cfg.end())
Ed Tanousbb679322022-05-16 16:10:00 -0700543 {
544 sensorTypeName =
545 std::visit(VariantToStringVisitor(), findType->second);
546 }
547
548 auto& sensor = sensors[name];
549 sensor = std::make_unique<IpmbSensor>(
Zev Weiss8ba551b2022-08-12 18:21:02 -0700550 dbusConnection, io, name, path, objectServer,
Ed Tanousbb679322022-05-16 16:10:00 -0700551 std::move(sensorThresholds), deviceAddress, hostSMbusIndex,
552 pollRate, sensorTypeName);
553
Zev Weiss8ba551b2022-08-12 18:21:02 -0700554 sensor->parseConfigValues(cfg);
Ed Tanousbb679322022-05-16 16:10:00 -0700555 if (!(sensor->sensorClassType(sensorClass)))
556 {
557 continue;
558 }
559 sensor->sensorSubType(sensorTypeName);
560 sensor->init();
James Feist6ef20402019-01-07 16:45:08 -0800561 }
Ed Tanousbb679322022-05-16 16:10:00 -0700562 }
James Feist6ef20402019-01-07 16:45:08 -0800563 },
JeffLin2c5a1f22022-10-05 15:19:09 +0800564 entityManagerName, "/xyz/openbmc_project/inventory",
565 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
James Feist6ef20402019-01-07 16:45:08 -0800566}
567
Patrick Williams92f8f512022-07-22 19:26:55 -0500568void reinitSensors(sdbusplus::message_t& message)
James Feistf7e2c5d2019-02-13 17:27:51 -0800569{
James Feist0d4f2bd2019-03-05 13:15:40 -0800570 constexpr const size_t reinitWaitSeconds = 2;
James Feistf7e2c5d2019-02-13 17:27:51 -0800571 std::string objectName;
James Feist52497fd2019-06-07 13:01:33 -0700572 boost::container::flat_map<std::string, std::variant<std::string>> values;
James Feistf7e2c5d2019-02-13 17:27:51 -0800573 message.read(objectName, values);
James Feist0d4f2bd2019-03-05 13:15:40 -0800574
James Feist52497fd2019-06-07 13:01:33 -0700575 auto findStatus = values.find(power::property);
576 if (findStatus != values.end())
James Feistf7e2c5d2019-02-13 17:27:51 -0800577 {
Zev Weiss6c106d62022-08-17 20:50:00 -0700578 bool powerStatus =
579 std::get<std::string>(findStatus->second).ends_with(".Running");
James Feistf7e2c5d2019-02-13 17:27:51 -0800580 if (powerStatus)
581 {
James Feist0d4f2bd2019-03-05 13:15:40 -0800582 if (!initCmdTimer)
James Feistf7e2c5d2019-02-13 17:27:51 -0800583 {
James Feist0d4f2bd2019-03-05 13:15:40 -0800584 // this should be impossible
585 return;
James Feistf7e2c5d2019-02-13 17:27:51 -0800586 }
James Feist0d4f2bd2019-03-05 13:15:40 -0800587 // we seem to send this command too fast sometimes, wait before
588 // sending
589 initCmdTimer->expires_from_now(
Ed Tanous9b4a20e2022-09-06 08:47:11 -0700590 std::chrono::seconds(reinitWaitSeconds));
James Feist0d4f2bd2019-03-05 13:15:40 -0800591
592 initCmdTimer->async_wait([](const boost::system::error_code ec) {
593 if (ec == boost::asio::error::operation_aborted)
594 {
595 return; // we're being canceled
596 }
597
Zev Weiss8ba551b2022-08-12 18:21:02 -0700598 for (const auto& [name, sensor] : sensors)
James Feist0d4f2bd2019-03-05 13:15:40 -0800599 {
Zev Weiss8ba551b2022-08-12 18:21:02 -0700600 if (sensor)
James Feist0d4f2bd2019-03-05 13:15:40 -0800601 {
Zev Weiss8ba551b2022-08-12 18:21:02 -0700602 sensor->runInitCmd();
James Feist0d4f2bd2019-03-05 13:15:40 -0800603 }
604 }
605 });
James Feistf7e2c5d2019-02-13 17:27:51 -0800606 }
607 }
608}
609
James Feistb6c0b912019-07-09 12:21:44 -0700610int main()
James Feist6ef20402019-01-07 16:45:08 -0800611{
612
613 boost::asio::io_service io;
614 auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
Ed Tanous14ed5e92022-07-12 15:50:23 -0700615 sdbusplus::asio::object_server objectServer(systemBus, true);
616 objectServer.add_manager("/xyz/openbmc_project/sensors");
James Feist6ef20402019-01-07 16:45:08 -0800617 systemBus->request_name("xyz.openbmc_project.IpmbSensor");
James Feist6ef20402019-01-07 16:45:08 -0800618
Ed Tanous9b4a20e2022-09-06 08:47:11 -0700619 initCmdTimer = std::make_unique<boost::asio::steady_timer>(io);
James Feist0d4f2bd2019-03-05 13:15:40 -0800620
James Feist6ef20402019-01-07 16:45:08 -0800621 io.post([&]() { createSensors(io, objectServer, sensors, systemBus); });
622
Ed Tanous9b4a20e2022-09-06 08:47:11 -0700623 boost::asio::steady_timer configTimer(io);
James Feist6ef20402019-01-07 16:45:08 -0800624
Patrick Williams92f8f512022-07-22 19:26:55 -0500625 std::function<void(sdbusplus::message_t&)> eventHandler =
626 [&](sdbusplus::message_t&) {
Ed Tanous9b4a20e2022-09-06 08:47:11 -0700627 configTimer.expires_from_now(std::chrono::seconds(1));
Ed Tanousbb679322022-05-16 16:10:00 -0700628 // create a timer because normally multiple properties change
629 configTimer.async_wait([&](const boost::system::error_code& ec) {
630 if (ec == boost::asio::error::operation_aborted)
631 {
632 return; // we're being canceled
633 }
634 createSensors(io, objectServer, sensors, systemBus);
635 if (sensors.empty())
636 {
637 std::cout << "Configuration not detected\n";
638 }
639 });
640 };
James Feist6ef20402019-01-07 16:45:08 -0800641
Zev Weiss214d9712022-08-12 12:54:31 -0700642 std::vector<std::unique_ptr<sdbusplus::bus::match_t>> matches =
643 setupPropertiesChangedMatches(
Zev Weiss054aad82022-08-18 01:37:34 -0700644 *systemBus, std::to_array<const char*>({sensorType}), eventHandler);
James Feist6ef20402019-01-07 16:45:08 -0800645
Patrick Williams92f8f512022-07-22 19:26:55 -0500646 sdbusplus::bus::match_t powerChangeMatch(
647 static_cast<sdbusplus::bus_t&>(*systemBus),
James Feist52497fd2019-06-07 13:01:33 -0700648 "type='signal',interface='" + std::string(properties::interface) +
649 "',path='" + std::string(power::path) + "',arg0='" +
650 std::string(power::interface) + "'",
James Feistf7e2c5d2019-02-13 17:27:51 -0800651 reinitSensors);
652
Bruce Lee1263c3d2021-06-04 15:16:33 +0800653 setupManufacturingModeMatch(*systemBus);
James Feist6ef20402019-01-07 16:45:08 -0800654 io.run();
Zhikui Rene76a5a62021-07-09 15:16:32 -0700655 return 0;
James Feist6ef20402019-01-07 16:45:08 -0800656}