blob: 3fc0ee51f5cee96ef281a4a9ac0c00ca863f1674 [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
Vikash Chandola1f847972022-09-28 09:47:32 +000051boost::container::flat_map<std::string, std::shared_ptr<IpmbSensor>> sensors;
James Feistf7e2c5d2019-02-13 17:27:51 -080052
Ed Tanous9b4a20e2022-09-06 08:47:11 -070053std::unique_ptr<boost::asio::steady_timer> initCmdTimer;
James Feist0d4f2bd2019-03-05 13:15:40 -080054
James Feist6ef20402019-01-07 16:45:08 -080055IpmbSensor::IpmbSensor(std::shared_ptr<sdbusplus::asio::connection>& conn,
56 boost::asio::io_service& io,
57 const std::string& sensorName,
58 const std::string& sensorConfiguration,
59 sdbusplus::asio::object_server& objectServer,
60 std::vector<thresholds::Threshold>&& thresholdData,
Anoop S832a2c62020-11-20 19:21:22 +000061 uint8_t deviceAddress, uint8_t hostSMbusIndex,
Jayashree-D9f6d4fd2021-04-13 18:27:22 +053062 const float pollRate, std::string& sensorTypeName) :
Zhikui Renda98f092021-11-01 09:41:08 -070063 Sensor(escapeName(sensorName), std::move(thresholdData),
Zev Weiss054aad82022-08-18 01:37:34 -070064 sensorConfiguration, "IpmbSensor", false, false, ipmbMaxReading,
65 ipmbMinReading, conn, PowerState::on),
Anoop S832a2c62020-11-20 19:21:22 +000066 deviceAddress(deviceAddress), hostSMbusIndex(hostSMbusIndex),
Jayashree-D9f6d4fd2021-04-13 18:27:22 +053067 sensorPollMs(static_cast<int>(pollRate * 1000)), objectServer(objectServer),
68 waitTimer(io)
James Feist6ef20402019-01-07 16:45:08 -080069{
Vijay Khemka682a5cb2019-07-18 17:34:03 -070070 std::string dbusPath = sensorPathPrefix + sensorTypeName + "/" + name;
71
James Feist6ef20402019-01-07 16:45:08 -080072 sensorInterface = objectServer.add_interface(
Vijay Khemka682a5cb2019-07-18 17:34:03 -070073 dbusPath, "xyz.openbmc_project.Sensor.Value");
James Feist6ef20402019-01-07 16:45:08 -080074
Jayashree Dhanapal56678082022-01-04 17:27:20 +053075 for (const auto& threshold : thresholds)
James Feist6ef20402019-01-07 16:45:08 -080076 {
Jayashree Dhanapal56678082022-01-04 17:27:20 +053077 std::string interface = thresholds::getInterface(threshold.level);
78 thresholdInterfaces[static_cast<size_t>(threshold.level)] =
79 objectServer.add_interface(dbusPath, interface);
James Feist6ef20402019-01-07 16:45:08 -080080 }
James Feist2adc95c2019-09-30 14:55:28 -070081 association = objectServer.add_interface(dbusPath, association::interface);
James Feist6ef20402019-01-07 16:45:08 -080082}
83
84IpmbSensor::~IpmbSensor()
85{
86 waitTimer.cancel();
Jayashree Dhanapal56678082022-01-04 17:27:20 +053087 for (const auto& iface : thresholdInterfaces)
88 {
89 objectServer.remove_interface(iface);
90 }
James Feist6ef20402019-01-07 16:45:08 -080091 objectServer.remove_interface(sensorInterface);
James Feist078f2322019-03-08 11:09:05 -080092 objectServer.remove_interface(association);
James Feist6ef20402019-01-07 16:45:08 -080093}
94
Ed Tanous2049bd22022-07-09 07:20:26 -070095std::string IpmbSensor::getSubTypeUnits(void) const
Zev Weiss6b6891c2021-04-22 02:46:21 -050096{
97 switch (subType)
98 {
99 case IpmbSubType::temp:
100 return sensor_paths::unitDegreesC;
101 case IpmbSubType::curr:
102 return sensor_paths::unitAmperes;
103 case IpmbSubType::power:
104 return sensor_paths::unitWatts;
105 case IpmbSubType::volt:
106 return sensor_paths::unitVolts;
107 case IpmbSubType::util:
108 return sensor_paths::unitPercent;
109 default:
110 throw std::runtime_error("Invalid sensor type");
111 }
112}
113
James Feist6ef20402019-01-07 16:45:08 -0800114void IpmbSensor::init(void)
115{
James Feist6ef20402019-01-07 16:45:08 -0800116 loadDefaults();
Andrei Kartashev39287412022-02-04 16:04:47 +0300117 setInitialProperties(getSubTypeUnits());
James Feist6ef20402019-01-07 16:45:08 -0800118 if (initCommand)
119 {
James Feistf7e2c5d2019-02-13 17:27:51 -0800120 runInitCmd();
121 }
122 read();
123}
124
Vikash Chandola1f847972022-09-28 09:47:32 +0000125static void initCmdCb(const std::weak_ptr<IpmbSensor>& weakRef,
126 const boost::system::error_code& ec,
127 const IpmbMethodType& response)
128{
129 std::shared_ptr<IpmbSensor> self = weakRef.lock();
130 if (!self)
131 {
132 return;
133 }
134 const int& status = std::get<0>(response);
135 if (ec || (status != 0))
136 {
137 std::cerr << "Error setting init command for device: " << self->name
138 << "\n";
139 }
140}
141
James Feistf7e2c5d2019-02-13 17:27:51 -0800142void IpmbSensor::runInitCmd()
143{
Vikash Chandola1f847972022-09-28 09:47:32 +0000144 if (!initCommand)
James Feistf7e2c5d2019-02-13 17:27:51 -0800145 {
Vikash Chandola1f847972022-09-28 09:47:32 +0000146 return;
James Feist6ef20402019-01-07 16:45:08 -0800147 }
Vikash Chandola1f847972022-09-28 09:47:32 +0000148 dbusConnection->async_method_call(
149 [weakRef{weak_from_this()}](const boost::system::error_code& ec,
150 const IpmbMethodType& response) {
151 initCmdCb(weakRef, ec, response);
152 },
153 "xyz.openbmc_project.Ipmi.Channel.Ipmb",
154 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb",
155 "sendRequest", commandAddress, netfn, lun, *initCommand, initData);
James Feist6ef20402019-01-07 16:45:08 -0800156}
157
158void IpmbSensor::loadDefaults()
159{
160 if (type == IpmbType::meSensor)
161 {
162 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200163 netfn = ipmi::sensor::netFn;
164 command = ipmi::sensor::getSensorReading;
James Feist6ef20402019-01-07 16:45:08 -0800165 commandData = {deviceAddress};
James Feistd7ae29a2020-06-25 15:42:46 -0700166 readingFormat = ReadingFormat::byte0;
James Feist6ef20402019-01-07 16:45:08 -0800167 }
168 else if (type == IpmbType::PXE1410CVR)
169 {
170 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200171 netfn = ipmi::me_bridge::netFn;
172 command = ipmi::me_bridge::sendRawPmbus;
173 initCommand = ipmi::me_bridge::sendRawPmbus;
James Feistd7ae29a2020-06-25 15:42:46 -0700174 // pmbus read temp
Anoop S832a2c62020-11-20 19:21:22 +0000175 commandData = {0x57, 0x01, 0x00, 0x16, hostSMbusIndex,
176 deviceAddress, 0x00, 0x00, 0x00, 0x00,
177 0x01, 0x02, 0x8d};
James Feistd7ae29a2020-06-25 15:42:46 -0700178 // goto page 0
Anoop S832a2c62020-11-20 19:21:22 +0000179 initData = {0x57, 0x01, 0x00, 0x14, hostSMbusIndex,
180 deviceAddress, 0x00, 0x00, 0x00, 0x00,
181 0x02, 0x00, 0x00, 0x00};
Jayashree-D37322572021-03-19 17:40:56 +0530182 readingFormat = ReadingFormat::linearElevenBit;
James Feist6ef20402019-01-07 16:45:08 -0800183 }
184 else if (type == IpmbType::IR38363VR)
185 {
186 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200187 netfn = ipmi::me_bridge::netFn;
188 command = ipmi::me_bridge::sendRawPmbus;
James Feistd7ae29a2020-06-25 15:42:46 -0700189 // pmbus read temp
Anoop S832a2c62020-11-20 19:21:22 +0000190 commandData = {0x57, 0x01, 0x00, 0x16, hostSMbusIndex,
191 deviceAddress, 00, 0x00, 0x00, 0x00,
192 0x01, 0x02, 0x8D};
James Feistd7ae29a2020-06-25 15:42:46 -0700193 readingFormat = ReadingFormat::elevenBitShift;
James Feist6ef20402019-01-07 16:45:08 -0800194 }
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700195 else if (type == IpmbType::ADM1278HSC)
196 {
197 commandAddress = meAddress;
Ed Tanousa771f6a2022-01-14 09:36:51 -0800198 uint8_t snsNum = 0;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700199 switch (subType)
200 {
201 case IpmbSubType::temp:
202 case IpmbSubType::curr:
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700203 if (subType == IpmbSubType::temp)
Ed Tanous8a57ec02020-10-09 12:46:52 -0700204 {
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700205 snsNum = 0x8d;
Ed Tanous8a57ec02020-10-09 12:46:52 -0700206 }
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700207 else
Ed Tanous8a57ec02020-10-09 12:46:52 -0700208 {
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700209 snsNum = 0x8c;
Ed Tanous8a57ec02020-10-09 12:46:52 -0700210 }
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200211 netfn = ipmi::me_bridge::netFn;
212 command = ipmi::me_bridge::sendRawPmbus;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700213 commandData = {0x57, 0x01, 0x00, 0x86, deviceAddress,
214 0x00, 0x00, 0x01, 0x02, snsNum};
James Feistd7ae29a2020-06-25 15:42:46 -0700215 readingFormat = ReadingFormat::elevenBit;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700216 break;
217 case IpmbSubType::power:
218 case IpmbSubType::volt:
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200219 netfn = ipmi::sensor::netFn;
220 command = ipmi::sensor::getSensorReading;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700221 commandData = {deviceAddress};
James Feistd7ae29a2020-06-25 15:42:46 -0700222 readingFormat = ReadingFormat::byte0;
Vijay Khemka682a5cb2019-07-18 17:34:03 -0700223 break;
224 default:
225 throw std::runtime_error("Invalid sensor type");
226 }
227 }
James Feist6ef20402019-01-07 16:45:08 -0800228 else if (type == IpmbType::mpsVR)
229 {
230 commandAddress = meAddress;
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200231 netfn = ipmi::me_bridge::netFn;
232 command = ipmi::me_bridge::sendRawPmbus;
233 initCommand = ipmi::me_bridge::sendRawPmbus;
James Feistd7ae29a2020-06-25 15:42:46 -0700234 // pmbus read temp
Anoop S832a2c62020-11-20 19:21:22 +0000235 commandData = {0x57, 0x01, 0x00, 0x16, hostSMbusIndex,
236 deviceAddress, 0x00, 0x00, 0x00, 0x00,
237 0x01, 0x02, 0x8d};
James Feistd7ae29a2020-06-25 15:42:46 -0700238 // goto page 0
Anoop S832a2c62020-11-20 19:21:22 +0000239 initData = {0x57, 0x01, 0x00, 0x14, hostSMbusIndex,
240 deviceAddress, 0x00, 0x00, 0x00, 0x00,
241 0x02, 0x00, 0x00, 0x00};
James Feistd7ae29a2020-06-25 15:42:46 -0700242 readingFormat = ReadingFormat::byte3;
James Feist6ef20402019-01-07 16:45:08 -0800243 }
244 else
245 {
246 throw std::runtime_error("Invalid sensor type");
247 }
Adrian Ambrożewicz45e92772020-06-04 13:59:55 +0200248
249 if (subType == IpmbSubType::util)
250 {
251 // Utilization need to be scaled to percent
252 maxValue = 100;
253 minValue = 0;
254 }
James Feist6ef20402019-01-07 16:45:08 -0800255}
256
257void IpmbSensor::checkThresholds(void)
258{
James Feist6ef20402019-01-07 16:45:08 -0800259 thresholds::checkThresholds(this);
260}
261
James Feist961bf092020-07-01 16:38:12 -0700262bool IpmbSensor::processReading(const std::vector<uint8_t>& data, double& resp)
James Feistd7ae29a2020-06-25 15:42:46 -0700263{
264
265 switch (readingFormat)
266 {
267 case (ReadingFormat::byte0):
James Feiste4a970d2020-08-19 11:21:58 -0700268 {
Adrian Ambrożewicz58e02ef2020-08-06 14:42:38 +0200269 if (command == ipmi::sensor::getSensorReading &&
270 !ipmi::sensor::isValid(data))
James Feistcf4238e2020-07-28 16:40:03 -0700271 {
272 return false;
273 }
James Feist961bf092020-07-01 16:38:12 -0700274 resp = data[0];
275 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700276 }
James Feistd7ae29a2020-06-25 15:42:46 -0700277 case (ReadingFormat::byte3):
James Feiste4a970d2020-08-19 11:21:58 -0700278 {
James Feistd7ae29a2020-06-25 15:42:46 -0700279 if (data.size() < 4)
280 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700281 if (errCount == 0U)
James Feist961bf092020-07-01 16:38:12 -0700282 {
283 std::cerr << "Invalid data length returned for " << name
284 << "\n";
285 }
286 return false;
James Feistd7ae29a2020-06-25 15:42:46 -0700287 }
James Feist961bf092020-07-01 16:38:12 -0700288 resp = data[3];
289 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700290 }
James Feistd7ae29a2020-06-25 15:42:46 -0700291 case (ReadingFormat::elevenBit):
James Feiste4a970d2020-08-19 11:21:58 -0700292 {
James Feistd7ae29a2020-06-25 15:42:46 -0700293 if (data.size() < 5)
294 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700295 if (errCount == 0U)
James Feist961bf092020-07-01 16:38:12 -0700296 {
297 std::cerr << "Invalid data length returned for " << name
298 << "\n";
299 }
300 return false;
James Feistd7ae29a2020-06-25 15:42:46 -0700301 }
302
James Feiste4a970d2020-08-19 11:21:58 -0700303 int16_t value = ((data[4] << 8) | data[3]);
James Feiste4a970d2020-08-19 11:21:58 -0700304 resp = value;
James Feist961bf092020-07-01 16:38:12 -0700305 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700306 }
James Feistd7ae29a2020-06-25 15:42:46 -0700307 case (ReadingFormat::elevenBitShift):
James Feiste4a970d2020-08-19 11:21:58 -0700308 {
James Feistd7ae29a2020-06-25 15:42:46 -0700309 if (data.size() < 5)
310 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700311 if (errCount == 0U)
James Feist961bf092020-07-01 16:38:12 -0700312 {
313 std::cerr << "Invalid data length returned for " << name
314 << "\n";
315 }
316 return false;
James Feistd7ae29a2020-06-25 15:42:46 -0700317 }
318
James Feist961bf092020-07-01 16:38:12 -0700319 resp = ((data[4] << 8) | data[3]) >> 3;
320 return true;
James Feiste4a970d2020-08-19 11:21:58 -0700321 }
Jayashree-D37322572021-03-19 17:40:56 +0530322 case (ReadingFormat::linearElevenBit):
323 {
324 if (data.size() < 5)
325 {
Ed Tanous2049bd22022-07-09 07:20:26 -0700326 if (errCount == 0U)
Jayashree-D37322572021-03-19 17:40:56 +0530327 {
328 std::cerr << "Invalid data length returned for " << name
329 << "\n";
330 }
331 return false;
332 }
333
334 int16_t value = ((data[4] << 8) | data[3]);
335 constexpr const size_t shift = 16 - 11; // 11bit into 16bit
336 value <<= shift;
337 value >>= shift;
338 resp = value;
339 return true;
340 }
James Feistd7ae29a2020-06-25 15:42:46 -0700341 default:
342 throw std::runtime_error("Invalid reading type");
343 }
344}
345
Vikash Chandola1f847972022-09-28 09:47:32 +0000346void IpmbSensor::ipmbRequestCompletionCb(const boost::system::error_code& ec,
347 const IpmbMethodType& response)
348{
349 const int& status = std::get<0>(response);
350 if (ec || (status != 0))
351 {
352 incrementError();
353 read();
354 return;
355 }
356 const std::vector<uint8_t>& data = std::get<5>(response);
357 if constexpr (debug)
358 {
359 std::cout << name << ": ";
360 for (size_t d : data)
361 {
362 std::cout << d << " ";
363 }
364 std::cout << "\n";
365 }
366 if (data.empty())
367 {
368 incrementError();
369 read();
370 return;
371 }
372
373 double value = 0;
374
375 if (!processReading(data, value))
376 {
377 incrementError();
378 read();
379 return;
380 }
381
382 // rawValue only used in debug logging
383 // up to 5th byte in data are used to derive value
384 size_t end = std::min(sizeof(uint64_t), data.size());
385 uint64_t rawData = 0;
386 for (size_t i = 0; i < end; i++)
387 {
388 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
389 reinterpret_cast<uint8_t*>(&rawData)[i] = data[i];
390 }
391 rawValue = static_cast<double>(rawData);
392
393 /* Adjust value as per scale and offset */
394 value = (value * scaleVal) + offsetVal;
395 updateValue(value);
396 read();
397}
398
James Feist6ef20402019-01-07 16:45:08 -0800399void IpmbSensor::read(void)
400{
Ed Tanous9b4a20e2022-09-06 08:47:11 -0700401 waitTimer.expires_from_now(std::chrono::milliseconds(sensorPollMs));
Vikash Chandola1f847972022-09-28 09:47:32 +0000402 waitTimer.async_wait(
403 [weakRef{weak_from_this()}](const boost::system::error_code& ec) {
James Feist6ef20402019-01-07 16:45:08 -0800404 if (ec == boost::asio::error::operation_aborted)
405 {
406 return; // we're being canceled
407 }
Vikash Chandola1f847972022-09-28 09:47:32 +0000408 std::shared_ptr<IpmbSensor> self = weakRef.lock();
409 if (!self)
James Feist6ef20402019-01-07 16:45:08 -0800410 {
James Feist6ef20402019-01-07 16:45:08 -0800411 return;
412 }
Vikash Chandola1f847972022-09-28 09:47:32 +0000413 self->sendIpmbRequest();
James Feist6ef20402019-01-07 16:45:08 -0800414 });
415}
Jayashree Dhanapal84189752022-03-07 12:51:54 +0530416
Vikash Chandola1f847972022-09-28 09:47:32 +0000417void IpmbSensor::sendIpmbRequest()
418{
419 if (!readingStateGood())
420 {
421 updateValue(std::numeric_limits<double>::quiet_NaN());
422 read();
423 return;
424 }
425 dbusConnection->async_method_call(
426 [weakRef{weak_from_this()}](boost::system::error_code ec,
427 const IpmbMethodType& response) {
428 std::shared_ptr<IpmbSensor> self = weakRef.lock();
429 if (!self)
430 {
431 return;
432 }
433 self->ipmbRequestCompletionCb(ec, response);
434 },
435 "xyz.openbmc_project.Ipmi.Channel.Ipmb",
436 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb",
437 "sendRequest", commandAddress, netfn, lun, command, commandData);
438}
439
Jayashree Dhanapal84189752022-03-07 12:51:54 +0530440bool IpmbSensor::sensorClassType(const std::string& sensorClass)
441{
442 if (sensorClass == "PxeBridgeTemp")
443 {
444 type = IpmbType::PXE1410CVR;
445 }
446 else if (sensorClass == "IRBridgeTemp")
447 {
448 type = IpmbType::IR38363VR;
449 }
450 else if (sensorClass == "HSCBridge")
451 {
452 type = IpmbType::ADM1278HSC;
453 }
454 else if (sensorClass == "MpsBridgeTemp")
455 {
456 type = IpmbType::mpsVR;
457 }
458 else if (sensorClass == "METemp" || sensorClass == "MESensor")
459 {
460 type = IpmbType::meSensor;
461 }
462 else
463 {
464 std::cerr << "Invalid class " << sensorClass << "\n";
465 return false;
466 }
467 return true;
468}
469
470void IpmbSensor::sensorSubType(const std::string& sensorTypeName)
471{
472 if (sensorTypeName == "voltage")
473 {
474 subType = IpmbSubType::volt;
475 }
476 else if (sensorTypeName == "power")
477 {
478 subType = IpmbSubType::power;
479 }
480 else if (sensorTypeName == "current")
481 {
482 subType = IpmbSubType::curr;
483 }
484 else if (sensorTypeName == "utilization")
485 {
486 subType = IpmbSubType::util;
487 }
488 else
489 {
490 subType = IpmbSubType::temp;
491 }
492}
493
494void IpmbSensor::parseConfigValues(const SensorBaseConfigMap& entry)
495{
496 auto findScaleVal = entry.find("ScaleValue");
497 if (findScaleVal != entry.end())
498 {
499 scaleVal = std::visit(VariantToDoubleVisitor(), findScaleVal->second);
500 }
501
502 auto findOffsetVal = entry.find("OffsetValue");
503 if (findOffsetVal != entry.end())
504 {
505 offsetVal = std::visit(VariantToDoubleVisitor(), findOffsetVal->second);
506 }
507
Zev Weissa4d27682022-07-19 15:30:36 -0700508 readState = getPowerState(entry);
Jayashree Dhanapal84189752022-03-07 12:51:54 +0530509}
510
James Feist6ef20402019-01-07 16:45:08 -0800511void createSensors(
512 boost::asio::io_service& io, sdbusplus::asio::object_server& objectServer,
Vikash Chandola1f847972022-09-28 09:47:32 +0000513 boost::container::flat_map<std::string, std::shared_ptr<IpmbSensor>>&
James Feist6ef20402019-01-07 16:45:08 -0800514 sensors,
515 std::shared_ptr<sdbusplus::asio::connection>& dbusConnection)
516{
517 if (!dbusConnection)
518 {
519 std::cerr << "Connection not created\n";
520 return;
521 }
522 dbusConnection->async_method_call(
523 [&](boost::system::error_code ec, const ManagedObjectType& resp) {
Ed Tanousbb679322022-05-16 16:10:00 -0700524 if (ec)
525 {
526 std::cerr << "Error contacting entity manager\n";
527 return;
528 }
Zev Weiss8ba551b2022-08-12 18:21:02 -0700529 for (const auto& [path, interfaces] : resp)
Ed Tanousbb679322022-05-16 16:10:00 -0700530 {
Zev Weiss8ba551b2022-08-12 18:21:02 -0700531 for (const auto& [intf, cfg] : interfaces)
James Feist6ef20402019-01-07 16:45:08 -0800532 {
Zev Weiss054aad82022-08-18 01:37:34 -0700533 if (intf != configInterfaceName(sensorType))
James Feist6ef20402019-01-07 16:45:08 -0800534 {
Ed Tanousbb679322022-05-16 16:10:00 -0700535 continue;
James Feist6ef20402019-01-07 16:45:08 -0800536 }
Zev Weiss8ba551b2022-08-12 18:21:02 -0700537 std::string name = loadVariant<std::string>(cfg, "Name");
Ed Tanousbb679322022-05-16 16:10:00 -0700538
539 std::vector<thresholds::Threshold> sensorThresholds;
Zev Weiss8ba551b2022-08-12 18:21:02 -0700540 if (!parseThresholdsFromConfig(interfaces, sensorThresholds))
Ed Tanousbb679322022-05-16 16:10:00 -0700541 {
542 std::cerr << "error populating thresholds for " << name
543 << "\n";
544 }
Zev Weiss8ba551b2022-08-12 18:21:02 -0700545 uint8_t deviceAddress = loadVariant<uint8_t>(cfg, "Address");
Ed Tanousbb679322022-05-16 16:10:00 -0700546
547 std::string sensorClass =
Zev Weiss8ba551b2022-08-12 18:21:02 -0700548 loadVariant<std::string>(cfg, "Class");
Ed Tanousbb679322022-05-16 16:10:00 -0700549
550 uint8_t hostSMbusIndex = hostSMbusIndexDefault;
Zev Weiss8ba551b2022-08-12 18:21:02 -0700551 auto findSmType = cfg.find("HostSMbusIndex");
552 if (findSmType != cfg.end())
Ed Tanousbb679322022-05-16 16:10:00 -0700553 {
554 hostSMbusIndex = std::visit(VariantToUnsignedIntVisitor(),
555 findSmType->second);
556 }
557
Zev Weiss8569bf22022-10-11 15:37:44 -0700558 float pollRate = getPollRate(cfg, pollRateDefault);
Ed Tanousbb679322022-05-16 16:10:00 -0700559
Jayashree Dhanapal6ee62942021-12-14 15:22:23 +0530560 uint8_t ipmbBusIndex = ipmbBusIndexDefault;
561 auto findBusType = cfg.find("Bus");
562 if (findBusType != cfg.end())
563 {
564 ipmbBusIndex = std::visit(VariantToUnsignedIntVisitor(),
565 findBusType->second);
566 std::cerr << "Ipmb Bus Index for " << name << " is "
567 << static_cast<int>(ipmbBusIndex) << "\n";
568 }
569
Ed Tanousbb679322022-05-16 16:10:00 -0700570 /* Default sensor type is "temperature" */
571 std::string sensorTypeName = "temperature";
Zev Weiss8ba551b2022-08-12 18:21:02 -0700572 auto findType = cfg.find("SensorType");
573 if (findType != cfg.end())
Ed Tanousbb679322022-05-16 16:10:00 -0700574 {
575 sensorTypeName =
576 std::visit(VariantToStringVisitor(), findType->second);
577 }
578
579 auto& sensor = sensors[name];
Vikash Chandola1f847972022-09-28 09:47:32 +0000580 sensor = nullptr;
581 sensor = std::make_shared<IpmbSensor>(
Zev Weiss8ba551b2022-08-12 18:21:02 -0700582 dbusConnection, io, name, path, objectServer,
Ed Tanousbb679322022-05-16 16:10:00 -0700583 std::move(sensorThresholds), deviceAddress, hostSMbusIndex,
584 pollRate, sensorTypeName);
585
Zev Weiss8ba551b2022-08-12 18:21:02 -0700586 sensor->parseConfigValues(cfg);
Ed Tanousbb679322022-05-16 16:10:00 -0700587 if (!(sensor->sensorClassType(sensorClass)))
588 {
589 continue;
590 }
591 sensor->sensorSubType(sensorTypeName);
592 sensor->init();
James Feist6ef20402019-01-07 16:45:08 -0800593 }
Ed Tanousbb679322022-05-16 16:10:00 -0700594 }
James Feist6ef20402019-01-07 16:45:08 -0800595 },
JeffLin2c5a1f22022-10-05 15:19:09 +0800596 entityManagerName, "/xyz/openbmc_project/inventory",
597 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
James Feist6ef20402019-01-07 16:45:08 -0800598}
599
Patrick Williams92f8f512022-07-22 19:26:55 -0500600void reinitSensors(sdbusplus::message_t& message)
James Feistf7e2c5d2019-02-13 17:27:51 -0800601{
James Feist0d4f2bd2019-03-05 13:15:40 -0800602 constexpr const size_t reinitWaitSeconds = 2;
James Feistf7e2c5d2019-02-13 17:27:51 -0800603 std::string objectName;
James Feist52497fd2019-06-07 13:01:33 -0700604 boost::container::flat_map<std::string, std::variant<std::string>> values;
James Feistf7e2c5d2019-02-13 17:27:51 -0800605 message.read(objectName, values);
James Feist0d4f2bd2019-03-05 13:15:40 -0800606
James Feist52497fd2019-06-07 13:01:33 -0700607 auto findStatus = values.find(power::property);
608 if (findStatus != values.end())
James Feistf7e2c5d2019-02-13 17:27:51 -0800609 {
Zev Weiss6c106d62022-08-17 20:50:00 -0700610 bool powerStatus =
611 std::get<std::string>(findStatus->second).ends_with(".Running");
James Feistf7e2c5d2019-02-13 17:27:51 -0800612 if (powerStatus)
613 {
James Feist0d4f2bd2019-03-05 13:15:40 -0800614 if (!initCmdTimer)
James Feistf7e2c5d2019-02-13 17:27:51 -0800615 {
James Feist0d4f2bd2019-03-05 13:15:40 -0800616 // this should be impossible
617 return;
James Feistf7e2c5d2019-02-13 17:27:51 -0800618 }
James Feist0d4f2bd2019-03-05 13:15:40 -0800619 // we seem to send this command too fast sometimes, wait before
620 // sending
621 initCmdTimer->expires_from_now(
Ed Tanous9b4a20e2022-09-06 08:47:11 -0700622 std::chrono::seconds(reinitWaitSeconds));
James Feist0d4f2bd2019-03-05 13:15:40 -0800623
624 initCmdTimer->async_wait([](const boost::system::error_code ec) {
625 if (ec == boost::asio::error::operation_aborted)
626 {
627 return; // we're being canceled
628 }
629
Zev Weiss8ba551b2022-08-12 18:21:02 -0700630 for (const auto& [name, sensor] : sensors)
James Feist0d4f2bd2019-03-05 13:15:40 -0800631 {
Zev Weiss8ba551b2022-08-12 18:21:02 -0700632 if (sensor)
James Feist0d4f2bd2019-03-05 13:15:40 -0800633 {
Zev Weiss8ba551b2022-08-12 18:21:02 -0700634 sensor->runInitCmd();
James Feist0d4f2bd2019-03-05 13:15:40 -0800635 }
636 }
637 });
James Feistf7e2c5d2019-02-13 17:27:51 -0800638 }
639 }
640}
641
James Feistb6c0b912019-07-09 12:21:44 -0700642int main()
James Feist6ef20402019-01-07 16:45:08 -0800643{
644
645 boost::asio::io_service io;
646 auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
Ed Tanous14ed5e92022-07-12 15:50:23 -0700647 sdbusplus::asio::object_server objectServer(systemBus, true);
648 objectServer.add_manager("/xyz/openbmc_project/sensors");
James Feist6ef20402019-01-07 16:45:08 -0800649 systemBus->request_name("xyz.openbmc_project.IpmbSensor");
James Feist6ef20402019-01-07 16:45:08 -0800650
Ed Tanous9b4a20e2022-09-06 08:47:11 -0700651 initCmdTimer = std::make_unique<boost::asio::steady_timer>(io);
James Feist0d4f2bd2019-03-05 13:15:40 -0800652
James Feist6ef20402019-01-07 16:45:08 -0800653 io.post([&]() { createSensors(io, objectServer, sensors, systemBus); });
654
Ed Tanous9b4a20e2022-09-06 08:47:11 -0700655 boost::asio::steady_timer configTimer(io);
James Feist6ef20402019-01-07 16:45:08 -0800656
Patrick Williams92f8f512022-07-22 19:26:55 -0500657 std::function<void(sdbusplus::message_t&)> eventHandler =
658 [&](sdbusplus::message_t&) {
Ed Tanous9b4a20e2022-09-06 08:47:11 -0700659 configTimer.expires_from_now(std::chrono::seconds(1));
Ed Tanousbb679322022-05-16 16:10:00 -0700660 // create a timer because normally multiple properties change
661 configTimer.async_wait([&](const boost::system::error_code& ec) {
662 if (ec == boost::asio::error::operation_aborted)
663 {
664 return; // we're being canceled
665 }
666 createSensors(io, objectServer, sensors, systemBus);
667 if (sensors.empty())
668 {
669 std::cout << "Configuration not detected\n";
670 }
671 });
672 };
James Feist6ef20402019-01-07 16:45:08 -0800673
Zev Weiss214d9712022-08-12 12:54:31 -0700674 std::vector<std::unique_ptr<sdbusplus::bus::match_t>> matches =
675 setupPropertiesChangedMatches(
Zev Weiss054aad82022-08-18 01:37:34 -0700676 *systemBus, std::to_array<const char*>({sensorType}), eventHandler);
James Feist6ef20402019-01-07 16:45:08 -0800677
Patrick Williams92f8f512022-07-22 19:26:55 -0500678 sdbusplus::bus::match_t powerChangeMatch(
679 static_cast<sdbusplus::bus_t&>(*systemBus),
James Feist52497fd2019-06-07 13:01:33 -0700680 "type='signal',interface='" + std::string(properties::interface) +
681 "',path='" + std::string(power::path) + "',arg0='" +
682 std::string(power::interface) + "'",
James Feistf7e2c5d2019-02-13 17:27:51 -0800683 reinitSensors);
684
Bruce Lee1263c3d2021-06-04 15:16:33 +0800685 setupManufacturingModeMatch(*systemBus);
James Feist6ef20402019-01-07 16:45:08 -0800686 io.run();
Zhikui Rene76a5a62021-07-09 15:16:32 -0700687 return 0;
James Feist6ef20402019-01-07 16:45:08 -0800688}