1021261ceSAushim Nagarkatti /*
2021261ceSAushim Nagarkatti * SPDX-FileCopyrightText: Copyright (c) 2022-2025 NVIDIA CORPORATION &
3021261ceSAushim Nagarkatti * AFFILIATES. All rights reserved.
4021261ceSAushim Nagarkatti * SPDX-License-Identifier: Apache-2.0
5021261ceSAushim Nagarkatti */
6021261ceSAushim Nagarkatti
7021261ceSAushim Nagarkatti #include "SmbpbiSensor.hpp"
8021261ceSAushim Nagarkatti
9021261ceSAushim Nagarkatti #include "SensorPaths.hpp"
10021261ceSAushim Nagarkatti #include "Thresholds.hpp"
11021261ceSAushim Nagarkatti #include "Utils.hpp"
12021261ceSAushim Nagarkatti #include "sensor.hpp"
13021261ceSAushim Nagarkatti
14021261ceSAushim Nagarkatti #include <linux/i2c.h>
15021261ceSAushim Nagarkatti
16021261ceSAushim Nagarkatti #include <boost/asio/error.hpp>
17021261ceSAushim Nagarkatti #include <boost/asio/io_context.hpp>
18021261ceSAushim Nagarkatti #include <boost/asio/post.hpp>
19021261ceSAushim Nagarkatti #include <boost/container/flat_map.hpp>
20021261ceSAushim Nagarkatti #include <phosphor-logging/lg2.hpp>
21021261ceSAushim Nagarkatti #include <sdbusplus/asio/connection.hpp>
22021261ceSAushim Nagarkatti #include <sdbusplus/asio/object_server.hpp>
23*ced35e14SPatrick Williams #include <sdbusplus/bus.hpp>
24021261ceSAushim Nagarkatti #include <sdbusplus/bus/match.hpp>
25021261ceSAushim Nagarkatti #include <sdbusplus/message.hpp>
26021261ceSAushim Nagarkatti
27021261ceSAushim Nagarkatti #include <array>
28021261ceSAushim Nagarkatti #include <chrono>
29021261ceSAushim Nagarkatti #include <cmath>
30021261ceSAushim Nagarkatti #include <cstdint>
31021261ceSAushim Nagarkatti #include <cstring>
32021261ceSAushim Nagarkatti #include <functional>
33021261ceSAushim Nagarkatti #include <limits>
34021261ceSAushim Nagarkatti #include <memory>
35021261ceSAushim Nagarkatti #include <string>
36021261ceSAushim Nagarkatti #include <utility>
37021261ceSAushim Nagarkatti #include <vector>
38021261ceSAushim Nagarkatti
39021261ceSAushim Nagarkatti extern "C"
40021261ceSAushim Nagarkatti {
41021261ceSAushim Nagarkatti #include <linux/i2c-dev.h>
42021261ceSAushim Nagarkatti #include <sys/ioctl.h>
43021261ceSAushim Nagarkatti }
44021261ceSAushim Nagarkatti
45021261ceSAushim Nagarkatti constexpr const bool debug = false;
46021261ceSAushim Nagarkatti
47021261ceSAushim Nagarkatti constexpr const char* configInterface =
48021261ceSAushim Nagarkatti "xyz.openbmc_project.Configuration.SmbpbiVirtualEeprom";
49021261ceSAushim Nagarkatti constexpr const char* sensorRootPath = "/xyz/openbmc_project/sensors/";
50021261ceSAushim Nagarkatti constexpr const char* objectType = "SmbpbiVirtualEeprom";
51021261ceSAushim Nagarkatti
52021261ceSAushim Nagarkatti boost::container::flat_map<std::string, std::unique_ptr<SmbpbiSensor>> sensors;
53021261ceSAushim Nagarkatti
SmbpbiSensor(std::shared_ptr<sdbusplus::asio::connection> & conn,boost::asio::io_context & io,const std::string & sensorName,const std::string & sensorConfiguration,const std::string & objType,sdbusplus::asio::object_server & objectServer,std::vector<thresholds::Threshold> && thresholdData,uint8_t busId,uint8_t addr,uint16_t offset,std::string & sensorUnits,std::string & valueType,size_t pollTime,double minVal,double maxVal,std::string & path)54021261ceSAushim Nagarkatti SmbpbiSensor::SmbpbiSensor(
55021261ceSAushim Nagarkatti std::shared_ptr<sdbusplus::asio::connection>& conn,
56021261ceSAushim Nagarkatti boost::asio::io_context& io, const std::string& sensorName,
57021261ceSAushim Nagarkatti const std::string& sensorConfiguration, const std::string& objType,
58021261ceSAushim Nagarkatti sdbusplus::asio::object_server& objectServer,
59021261ceSAushim Nagarkatti std::vector<thresholds::Threshold>&& thresholdData, uint8_t busId,
60021261ceSAushim Nagarkatti uint8_t addr, uint16_t offset, std::string& sensorUnits,
61021261ceSAushim Nagarkatti std::string& valueType, size_t pollTime, double minVal, double maxVal,
62021261ceSAushim Nagarkatti std::string& path) :
63021261ceSAushim Nagarkatti Sensor(escapeName(sensorName), std::move(thresholdData),
64021261ceSAushim Nagarkatti sensorConfiguration, objType, false, false, maxVal, minVal, conn),
65021261ceSAushim Nagarkatti busId(busId), addr(addr), offset(offset), sensorUnits(sensorUnits),
66021261ceSAushim Nagarkatti valueType(valueType), objectServer(objectServer),
67021261ceSAushim Nagarkatti inputDev(io, path, boost::asio::random_access_file::read_only),
68021261ceSAushim Nagarkatti waitTimer(io), pollRateSecond(pollTime)
69021261ceSAushim Nagarkatti {
70021261ceSAushim Nagarkatti sensorType = sensor_paths::getPathForUnits(sensorUnits);
71021261ceSAushim Nagarkatti std::string sensorPath = sensorRootPath + sensorType + "/";
72021261ceSAushim Nagarkatti
73021261ceSAushim Nagarkatti sensorInterface =
74021261ceSAushim Nagarkatti objectServer.add_interface(sensorPath + name, sensorValueInterface);
75021261ceSAushim Nagarkatti
76021261ceSAushim Nagarkatti for (const auto& threshold : thresholds)
77021261ceSAushim Nagarkatti {
78021261ceSAushim Nagarkatti std::string interface = thresholds::getInterface(threshold.level);
79021261ceSAushim Nagarkatti thresholdInterfaces[static_cast<size_t>(threshold.level)] =
80021261ceSAushim Nagarkatti objectServer.add_interface(sensorPath + name, interface);
81021261ceSAushim Nagarkatti }
82021261ceSAushim Nagarkatti association =
83021261ceSAushim Nagarkatti objectServer.add_interface(sensorPath + name, association::interface);
84021261ceSAushim Nagarkatti
85021261ceSAushim Nagarkatti if (sensorType == "temperature")
86021261ceSAushim Nagarkatti {
87021261ceSAushim Nagarkatti setInitialProperties(sensor_paths::unitDegreesC);
88021261ceSAushim Nagarkatti }
89021261ceSAushim Nagarkatti else if (sensorType == "power")
90021261ceSAushim Nagarkatti {
91021261ceSAushim Nagarkatti setInitialProperties(sensor_paths::unitWatts);
92021261ceSAushim Nagarkatti }
93021261ceSAushim Nagarkatti else if (sensorType == "energy")
94021261ceSAushim Nagarkatti {
95021261ceSAushim Nagarkatti setInitialProperties(sensor_paths::unitJoules);
96021261ceSAushim Nagarkatti }
97021261ceSAushim Nagarkatti else if (sensorType == "voltage")
98021261ceSAushim Nagarkatti {
99021261ceSAushim Nagarkatti setInitialProperties(sensor_paths::unitVolts);
100021261ceSAushim Nagarkatti }
101021261ceSAushim Nagarkatti else
102021261ceSAushim Nagarkatti {
103021261ceSAushim Nagarkatti lg2::error("no sensor type found");
104021261ceSAushim Nagarkatti }
105021261ceSAushim Nagarkatti }
106021261ceSAushim Nagarkatti
~SmbpbiSensor()107021261ceSAushim Nagarkatti SmbpbiSensor::~SmbpbiSensor()
108021261ceSAushim Nagarkatti {
109021261ceSAushim Nagarkatti inputDev.close();
110021261ceSAushim Nagarkatti waitTimer.cancel();
111021261ceSAushim Nagarkatti for (const auto& iface : thresholdInterfaces)
112021261ceSAushim Nagarkatti {
113021261ceSAushim Nagarkatti objectServer.remove_interface(iface);
114021261ceSAushim Nagarkatti }
115021261ceSAushim Nagarkatti objectServer.remove_interface(sensorInterface);
116021261ceSAushim Nagarkatti objectServer.remove_interface(association);
117021261ceSAushim Nagarkatti }
118021261ceSAushim Nagarkatti
init()119021261ceSAushim Nagarkatti void SmbpbiSensor::init()
120021261ceSAushim Nagarkatti {
121021261ceSAushim Nagarkatti read();
122021261ceSAushim Nagarkatti }
123021261ceSAushim Nagarkatti
checkThresholds()124021261ceSAushim Nagarkatti void SmbpbiSensor::checkThresholds()
125021261ceSAushim Nagarkatti {
126021261ceSAushim Nagarkatti thresholds::checkThresholds(this);
127021261ceSAushim Nagarkatti }
128021261ceSAushim Nagarkatti
convert2Temp(const uint8_t * raw)129021261ceSAushim Nagarkatti double SmbpbiSensor::convert2Temp(const uint8_t* raw)
130021261ceSAushim Nagarkatti {
131021261ceSAushim Nagarkatti // Temp data is encoded in SMBPBI format. The 3 MSBs denote
132021261ceSAushim Nagarkatti // the integer portion, LSB is an encoded fraction.
133021261ceSAushim Nagarkatti // this automatic convert to int (two's complement integer)
134021261ceSAushim Nagarkatti int32_t intg = (raw[3] << 24 | raw[2] << 16 | raw[1] << 8 | raw[0]);
135021261ceSAushim Nagarkatti uint8_t frac = uint8_t(raw[0]);
136021261ceSAushim Nagarkatti // shift operation on a int keeps the sign in two's complement
137021261ceSAushim Nagarkatti intg >>= 8;
138021261ceSAushim Nagarkatti
139021261ceSAushim Nagarkatti double temp = 0;
140021261ceSAushim Nagarkatti if (intg > 0)
141021261ceSAushim Nagarkatti {
142021261ceSAushim Nagarkatti temp = double(intg) + double(frac / 256.0);
143021261ceSAushim Nagarkatti }
144021261ceSAushim Nagarkatti else
145021261ceSAushim Nagarkatti {
146021261ceSAushim Nagarkatti temp = double(intg) - double(frac / 256.0);
147021261ceSAushim Nagarkatti }
148021261ceSAushim Nagarkatti
149021261ceSAushim Nagarkatti return temp;
150021261ceSAushim Nagarkatti }
151021261ceSAushim Nagarkatti
convert2Power(const uint8_t * raw)152021261ceSAushim Nagarkatti double SmbpbiSensor::convert2Power(const uint8_t* raw)
153021261ceSAushim Nagarkatti {
154021261ceSAushim Nagarkatti // Power data is encoded as a 4-byte unsigned integer
155021261ceSAushim Nagarkatti uint32_t val = (raw[3] << 24) + (raw[2] << 16) + (raw[1] << 8) + raw[0];
156021261ceSAushim Nagarkatti
157021261ceSAushim Nagarkatti // mWatts to Watts
158021261ceSAushim Nagarkatti double power = static_cast<double>(val) / 1000;
159021261ceSAushim Nagarkatti
160021261ceSAushim Nagarkatti return power;
161021261ceSAushim Nagarkatti }
162021261ceSAushim Nagarkatti
i2cReadDataBytesDouble(double & reading)163021261ceSAushim Nagarkatti int SmbpbiSensor::i2cReadDataBytesDouble(double& reading)
164021261ceSAushim Nagarkatti {
165021261ceSAushim Nagarkatti constexpr int length =
166021261ceSAushim Nagarkatti i2CReadLenValues[static_cast<size_t>(I2C_READ_LEN_INDEX::FLOAT64)];
167021261ceSAushim Nagarkatti
168021261ceSAushim Nagarkatti static_assert(length == sizeof(reading), "Unsupported arch");
169021261ceSAushim Nagarkatti
170021261ceSAushim Nagarkatti std::array<uint8_t, length> buf{};
171021261ceSAushim Nagarkatti int ret = i2cReadDataBytes(buf.data(), length);
172021261ceSAushim Nagarkatti if (ret < 0)
173021261ceSAushim Nagarkatti {
174021261ceSAushim Nagarkatti return ret;
175021261ceSAushim Nagarkatti }
176021261ceSAushim Nagarkatti // there is no value updated from HMC if reading data is all 0xff
177021261ceSAushim Nagarkatti // Return NaN since reading is already a double
178021261ceSAushim Nagarkatti if (checkInvalidReading(buf.data(), length))
179021261ceSAushim Nagarkatti {
180021261ceSAushim Nagarkatti reading = std::numeric_limits<double>::quiet_NaN();
181021261ceSAushim Nagarkatti return 0;
182021261ceSAushim Nagarkatti }
183021261ceSAushim Nagarkatti uint64_t tempd = 0;
184021261ceSAushim Nagarkatti for (int byteI = 0; byteI < length; byteI++)
185021261ceSAushim Nagarkatti {
186021261ceSAushim Nagarkatti tempd |= static_cast<uint64_t>(buf[byteI]) << (8 * byteI);
187021261ceSAushim Nagarkatti }
188021261ceSAushim Nagarkatti std::memcpy(&reading, &tempd, sizeof(reading));
189021261ceSAushim Nagarkatti
190021261ceSAushim Nagarkatti return 0;
191021261ceSAushim Nagarkatti }
192021261ceSAushim Nagarkatti
i2cReadDataBytesUI64(uint64_t & reading)193021261ceSAushim Nagarkatti int SmbpbiSensor::i2cReadDataBytesUI64(uint64_t& reading)
194021261ceSAushim Nagarkatti {
195021261ceSAushim Nagarkatti constexpr int length =
196021261ceSAushim Nagarkatti i2CReadLenValues[static_cast<size_t>(I2C_READ_LEN_INDEX::UINT64)];
197021261ceSAushim Nagarkatti
198021261ceSAushim Nagarkatti static_assert(length == sizeof(reading), "Unsupported arch");
199021261ceSAushim Nagarkatti
200021261ceSAushim Nagarkatti std::array<uint8_t, length> buf{};
201021261ceSAushim Nagarkatti int ret = i2cReadDataBytes(buf.data(), length);
202021261ceSAushim Nagarkatti if (ret < 0)
203021261ceSAushim Nagarkatti {
204021261ceSAushim Nagarkatti return ret;
205021261ceSAushim Nagarkatti }
206021261ceSAushim Nagarkatti reading = 0;
207021261ceSAushim Nagarkatti for (int byteI = 0; byteI < length; byteI++)
208021261ceSAushim Nagarkatti {
209021261ceSAushim Nagarkatti reading |= static_cast<uint64_t>(buf[byteI]) << (8 * byteI);
210021261ceSAushim Nagarkatti }
211021261ceSAushim Nagarkatti return 0;
212021261ceSAushim Nagarkatti }
213021261ceSAushim Nagarkatti
214021261ceSAushim Nagarkatti // Generic i2c Command to read bytes
i2cReadDataBytes(uint8_t * reading,int length)215021261ceSAushim Nagarkatti int SmbpbiSensor::i2cReadDataBytes(uint8_t* reading, int length)
216021261ceSAushim Nagarkatti {
217021261ceSAushim Nagarkatti // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
218021261ceSAushim Nagarkatti const int fd = inputDev.native_handle();
219021261ceSAushim Nagarkatti if (fd < 0)
220021261ceSAushim Nagarkatti {
221021261ceSAushim Nagarkatti lg2::error(" unable to open i2c device on bus {BUS} err={FD}", "BUS",
222021261ceSAushim Nagarkatti busId, "FD", fd);
223021261ceSAushim Nagarkatti return -1;
224021261ceSAushim Nagarkatti }
225021261ceSAushim Nagarkatti
226021261ceSAushim Nagarkatti unsigned long funcs = 0;
227021261ceSAushim Nagarkatti // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
228021261ceSAushim Nagarkatti if (ioctl(fd, I2C_FUNCS, &funcs) < 0)
229021261ceSAushim Nagarkatti {
230021261ceSAushim Nagarkatti lg2::error(" I2C_FUNCS not supported");
231021261ceSAushim Nagarkatti return -1;
232021261ceSAushim Nagarkatti }
233021261ceSAushim Nagarkatti
234021261ceSAushim Nagarkatti int ret = 0;
235021261ceSAushim Nagarkatti struct i2c_rdwr_ioctl_data args = {nullptr, 0};
236021261ceSAushim Nagarkatti struct i2c_msg msg = {0, 0, 0, nullptr};
237021261ceSAushim Nagarkatti std::array<uint8_t, 8> cmd{};
238021261ceSAushim Nagarkatti
239021261ceSAushim Nagarkatti msg.addr = addr;
240021261ceSAushim Nagarkatti args.msgs = &msg;
241021261ceSAushim Nagarkatti args.nmsgs = 1;
242021261ceSAushim Nagarkatti
243021261ceSAushim Nagarkatti msg.flags = 0;
244021261ceSAushim Nagarkatti msg.buf = cmd.data();
245021261ceSAushim Nagarkatti // handle two bytes offset
246021261ceSAushim Nagarkatti if (offset > 255)
247021261ceSAushim Nagarkatti {
248021261ceSAushim Nagarkatti msg.len = 2;
249021261ceSAushim Nagarkatti msg.buf[0] = offset >> 8;
250021261ceSAushim Nagarkatti msg.buf[1] = offset & 0xFF;
251021261ceSAushim Nagarkatti }
252021261ceSAushim Nagarkatti else
253021261ceSAushim Nagarkatti {
254021261ceSAushim Nagarkatti msg.len = 1;
255021261ceSAushim Nagarkatti msg.buf[0] = offset & 0xFF;
256021261ceSAushim Nagarkatti }
257021261ceSAushim Nagarkatti
258021261ceSAushim Nagarkatti // write offset
259021261ceSAushim Nagarkatti // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
260021261ceSAushim Nagarkatti ret = ioctl(fd, I2C_RDWR, &args);
261021261ceSAushim Nagarkatti if (ret < 0)
262021261ceSAushim Nagarkatti {
263021261ceSAushim Nagarkatti return ret;
264021261ceSAushim Nagarkatti }
265021261ceSAushim Nagarkatti
266021261ceSAushim Nagarkatti msg.flags = I2C_M_RD;
267021261ceSAushim Nagarkatti msg.len = length;
268021261ceSAushim Nagarkatti msg.buf = reading;
269021261ceSAushim Nagarkatti
270021261ceSAushim Nagarkatti // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
271021261ceSAushim Nagarkatti ret = ioctl(fd, I2C_RDWR, &args);
272021261ceSAushim Nagarkatti if (ret < 0)
273021261ceSAushim Nagarkatti {
274021261ceSAushim Nagarkatti return ret;
275021261ceSAushim Nagarkatti }
276021261ceSAushim Nagarkatti return 0;
277021261ceSAushim Nagarkatti }
278021261ceSAushim Nagarkatti
readRawEEPROMData(double & data)279021261ceSAushim Nagarkatti int SmbpbiSensor::readRawEEPROMData(double& data)
280021261ceSAushim Nagarkatti {
281021261ceSAushim Nagarkatti uint64_t reading = 0;
282021261ceSAushim Nagarkatti int ret = i2cReadDataBytesUI64(reading);
283021261ceSAushim Nagarkatti if (ret < 0)
284021261ceSAushim Nagarkatti {
285021261ceSAushim Nagarkatti return ret;
286021261ceSAushim Nagarkatti }
287021261ceSAushim Nagarkatti // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
288021261ceSAushim Nagarkatti if (checkInvalidReading(reinterpret_cast<uint8_t*>(&reading),
289021261ceSAushim Nagarkatti sizeof(reading)))
290021261ceSAushim Nagarkatti {
291021261ceSAushim Nagarkatti data = std::numeric_limits<double>::quiet_NaN();
292021261ceSAushim Nagarkatti return 0;
293021261ceSAushim Nagarkatti }
294021261ceSAushim Nagarkatti if (debug)
295021261ceSAushim Nagarkatti {
296021261ceSAushim Nagarkatti lg2::error("offset: {OFFSET} reading: {READING}", "OFFSET", offset,
297021261ceSAushim Nagarkatti "READING", reading);
298021261ceSAushim Nagarkatti }
299021261ceSAushim Nagarkatti if (sensorType == "temperature")
300021261ceSAushim Nagarkatti {
301021261ceSAushim Nagarkatti // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
302021261ceSAushim Nagarkatti data = convert2Temp(reinterpret_cast<uint8_t*>(&reading));
303021261ceSAushim Nagarkatti }
304021261ceSAushim Nagarkatti else if (sensorType == "power")
305021261ceSAushim Nagarkatti {
306021261ceSAushim Nagarkatti // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
307021261ceSAushim Nagarkatti data = convert2Power(reinterpret_cast<uint8_t*>(&reading));
308021261ceSAushim Nagarkatti }
309021261ceSAushim Nagarkatti else if (sensorType == "energy")
310021261ceSAushim Nagarkatti {
311021261ceSAushim Nagarkatti data = reading / 1000.0; // mJ to J (double)
312021261ceSAushim Nagarkatti }
313021261ceSAushim Nagarkatti else
314021261ceSAushim Nagarkatti {
315021261ceSAushim Nagarkatti data = reading; // Voltage
316021261ceSAushim Nagarkatti }
317021261ceSAushim Nagarkatti return 0;
318021261ceSAushim Nagarkatti }
319021261ceSAushim Nagarkatti
readFloat64EEPROMData(double & data)320021261ceSAushim Nagarkatti int SmbpbiSensor::readFloat64EEPROMData(double& data)
321021261ceSAushim Nagarkatti {
322021261ceSAushim Nagarkatti double reading = 0;
323021261ceSAushim Nagarkatti int ret = i2cReadDataBytesDouble(reading);
324021261ceSAushim Nagarkatti if (ret < 0)
325021261ceSAushim Nagarkatti {
326021261ceSAushim Nagarkatti return ret;
327021261ceSAushim Nagarkatti }
328021261ceSAushim Nagarkatti data = reading;
329021261ceSAushim Nagarkatti return 0;
330021261ceSAushim Nagarkatti }
331021261ceSAushim Nagarkatti
waitReadCallback(const boost::system::error_code & ec)332021261ceSAushim Nagarkatti void SmbpbiSensor::waitReadCallback(const boost::system::error_code& ec)
333021261ceSAushim Nagarkatti {
334021261ceSAushim Nagarkatti if (ec == boost::asio::error::operation_aborted)
335021261ceSAushim Nagarkatti {
336021261ceSAushim Nagarkatti // we're being cancelled
337021261ceSAushim Nagarkatti return;
338021261ceSAushim Nagarkatti }
339021261ceSAushim Nagarkatti // read timer error
340021261ceSAushim Nagarkatti if (ec)
341021261ceSAushim Nagarkatti {
342021261ceSAushim Nagarkatti lg2::error("timer error");
343021261ceSAushim Nagarkatti return;
344021261ceSAushim Nagarkatti }
345021261ceSAushim Nagarkatti double temp = 0;
346021261ceSAushim Nagarkatti
347021261ceSAushim Nagarkatti int ret = 0;
348021261ceSAushim Nagarkatti // Sensor reading value types are sensor-specific. So, read
349021261ceSAushim Nagarkatti // and interpret sensor data based on it's value type.
350021261ceSAushim Nagarkatti if (valueType == "UINT64")
351021261ceSAushim Nagarkatti {
352021261ceSAushim Nagarkatti ret = readRawEEPROMData(temp);
353021261ceSAushim Nagarkatti }
354021261ceSAushim Nagarkatti else if (valueType == "FLOAT64")
355021261ceSAushim Nagarkatti {
356021261ceSAushim Nagarkatti ret = readFloat64EEPROMData(temp);
357021261ceSAushim Nagarkatti }
358021261ceSAushim Nagarkatti else
359021261ceSAushim Nagarkatti {
360021261ceSAushim Nagarkatti return;
361021261ceSAushim Nagarkatti }
362021261ceSAushim Nagarkatti
363021261ceSAushim Nagarkatti if (ret >= 0)
364021261ceSAushim Nagarkatti {
365021261ceSAushim Nagarkatti if constexpr (debug)
366021261ceSAushim Nagarkatti {
367021261ceSAushim Nagarkatti lg2::error("Value update to {TEMP}", "TEMP", temp);
368021261ceSAushim Nagarkatti }
369021261ceSAushim Nagarkatti updateValue(temp);
370021261ceSAushim Nagarkatti }
371021261ceSAushim Nagarkatti else
372021261ceSAushim Nagarkatti {
373021261ceSAushim Nagarkatti lg2::error("Invalid read getRegsInfo");
374021261ceSAushim Nagarkatti incrementError();
375021261ceSAushim Nagarkatti }
376021261ceSAushim Nagarkatti read();
377021261ceSAushim Nagarkatti }
378021261ceSAushim Nagarkatti
read()379021261ceSAushim Nagarkatti void SmbpbiSensor::read()
380021261ceSAushim Nagarkatti {
381021261ceSAushim Nagarkatti size_t pollTime = getPollRate(); // in seconds
382021261ceSAushim Nagarkatti
383021261ceSAushim Nagarkatti waitTimer.expires_after(std::chrono::seconds(pollTime));
384021261ceSAushim Nagarkatti waitTimer.async_wait([this](const boost::system::error_code& ec) {
385021261ceSAushim Nagarkatti this->waitReadCallback(ec);
386021261ceSAushim Nagarkatti });
387021261ceSAushim Nagarkatti }
388021261ceSAushim Nagarkatti
createSensorCallback(boost::system::error_code ec,const ManagedObjectType & resp,boost::asio::io_context & io,sdbusplus::asio::object_server & objectServer,std::shared_ptr<sdbusplus::asio::connection> & dbusConnection,boost::container::flat_map<std::string,std::unique_ptr<SmbpbiSensor>> & sensors)389021261ceSAushim Nagarkatti static void createSensorCallback(
390021261ceSAushim Nagarkatti boost::system::error_code ec, const ManagedObjectType& resp,
391021261ceSAushim Nagarkatti boost::asio::io_context& io, sdbusplus::asio::object_server& objectServer,
392021261ceSAushim Nagarkatti std::shared_ptr<sdbusplus::asio::connection>& dbusConnection,
393021261ceSAushim Nagarkatti boost::container::flat_map<std::string, std::unique_ptr<SmbpbiSensor>>&
394021261ceSAushim Nagarkatti sensors)
395021261ceSAushim Nagarkatti {
396021261ceSAushim Nagarkatti if (ec)
397021261ceSAushim Nagarkatti {
398021261ceSAushim Nagarkatti lg2::error("Error contacting entity manager");
399021261ceSAushim Nagarkatti return;
400021261ceSAushim Nagarkatti }
401021261ceSAushim Nagarkatti for (const auto& pathPair : resp)
402021261ceSAushim Nagarkatti {
403021261ceSAushim Nagarkatti for (const auto& entry : pathPair.second)
404021261ceSAushim Nagarkatti {
405021261ceSAushim Nagarkatti if (entry.first != configInterface)
406021261ceSAushim Nagarkatti {
407021261ceSAushim Nagarkatti continue;
408021261ceSAushim Nagarkatti }
409021261ceSAushim Nagarkatti std::string name = loadVariant<std::string>(entry.second, "Name");
410021261ceSAushim Nagarkatti
411021261ceSAushim Nagarkatti std::vector<thresholds::Threshold> sensorThresholds;
412021261ceSAushim Nagarkatti if (!parseThresholdsFromConfig(pathPair.second, sensorThresholds))
413021261ceSAushim Nagarkatti {
414021261ceSAushim Nagarkatti lg2::error("error populating thresholds for {NAME}", "NAME",
415021261ceSAushim Nagarkatti name);
416021261ceSAushim Nagarkatti }
417021261ceSAushim Nagarkatti
418021261ceSAushim Nagarkatti uint8_t busId = loadVariant<uint8_t>(entry.second, "Bus");
419021261ceSAushim Nagarkatti
420021261ceSAushim Nagarkatti uint8_t addr = loadVariant<uint8_t>(entry.second, "Address");
421021261ceSAushim Nagarkatti
422021261ceSAushim Nagarkatti uint16_t off = loadVariant<uint16_t>(entry.second, "ReadOffset");
423021261ceSAushim Nagarkatti
424021261ceSAushim Nagarkatti std::string sensorUnits =
425021261ceSAushim Nagarkatti loadVariant<std::string>(entry.second, "Units");
426021261ceSAushim Nagarkatti
427021261ceSAushim Nagarkatti std::string valueType =
428021261ceSAushim Nagarkatti loadVariant<std::string>(entry.second, "ValueType");
429021261ceSAushim Nagarkatti if (valueType != "UINT64" && valueType != "FLOAT64")
430021261ceSAushim Nagarkatti {
431021261ceSAushim Nagarkatti lg2::error("Invalid ValueType for sensor: {NAME}", "NAME",
432021261ceSAushim Nagarkatti name);
433021261ceSAushim Nagarkatti break;
434021261ceSAushim Nagarkatti }
435021261ceSAushim Nagarkatti
436021261ceSAushim Nagarkatti size_t rate = loadVariant<uint8_t>(entry.second, "PollRate");
437021261ceSAushim Nagarkatti
438021261ceSAushim Nagarkatti double minVal = loadVariant<double>(entry.second, "MinValue");
439021261ceSAushim Nagarkatti
440021261ceSAushim Nagarkatti double maxVal = loadVariant<double>(entry.second, "MaxValue");
441021261ceSAushim Nagarkatti if constexpr (debug)
442021261ceSAushim Nagarkatti {
443021261ceSAushim Nagarkatti lg2::info("Configuration parsed for \n\t {CONF}\nwith\n"
444021261ceSAushim Nagarkatti "\tName: {NAME}\n"
445021261ceSAushim Nagarkatti "\tBus: {BUS}\n"
446021261ceSAushim Nagarkatti "\tAddress:{ADDR}\n"
447021261ceSAushim Nagarkatti "\tOffset: {OFF}\n"
448021261ceSAushim Nagarkatti "\tType : {TYPE}\n"
449021261ceSAushim Nagarkatti "\tValue Type : {VALUETYPE}\n"
450021261ceSAushim Nagarkatti "\tPollrate: {RATE}\n"
451021261ceSAushim Nagarkatti "\tMinValue: {MIN}\n"
452021261ceSAushim Nagarkatti "\tMaxValue: {MAX}\n",
453021261ceSAushim Nagarkatti "CONF", entry.first, "NAME", name, "BUS",
454021261ceSAushim Nagarkatti static_cast<int>(busId), "ADDR",
455021261ceSAushim Nagarkatti static_cast<int>(addr), "OFF", static_cast<int>(off),
456021261ceSAushim Nagarkatti "UNITS", sensorUnits, "VALUETYPE", valueType, "RATE",
457021261ceSAushim Nagarkatti rate, "MIN", minVal, "MAX", maxVal);
458021261ceSAushim Nagarkatti }
459021261ceSAushim Nagarkatti
460021261ceSAushim Nagarkatti auto& sensor = sensors[name];
461021261ceSAushim Nagarkatti sensor = nullptr;
462021261ceSAushim Nagarkatti
463021261ceSAushim Nagarkatti std::string path = "/dev/i2c-" + std::to_string(busId);
464021261ceSAushim Nagarkatti
465021261ceSAushim Nagarkatti sensor = std::make_unique<SmbpbiSensor>(
466021261ceSAushim Nagarkatti dbusConnection, io, name, pathPair.first, objectType,
467021261ceSAushim Nagarkatti objectServer, std::move(sensorThresholds), busId, addr, off,
468021261ceSAushim Nagarkatti sensorUnits, valueType, rate, minVal, maxVal, path);
469021261ceSAushim Nagarkatti
470021261ceSAushim Nagarkatti sensor->init();
471021261ceSAushim Nagarkatti }
472021261ceSAushim Nagarkatti }
473021261ceSAushim Nagarkatti }
474021261ceSAushim Nagarkatti
createSensors(boost::asio::io_context & io,sdbusplus::asio::object_server & objectServer,boost::container::flat_map<std::string,std::unique_ptr<SmbpbiSensor>> & sensors,std::shared_ptr<sdbusplus::asio::connection> & dbusConnection)475021261ceSAushim Nagarkatti void createSensors(
476021261ceSAushim Nagarkatti boost::asio::io_context& io, sdbusplus::asio::object_server& objectServer,
477021261ceSAushim Nagarkatti boost::container::flat_map<std::string, std::unique_ptr<SmbpbiSensor>>&
478021261ceSAushim Nagarkatti sensors,
479021261ceSAushim Nagarkatti std::shared_ptr<sdbusplus::asio::connection>& dbusConnection)
480021261ceSAushim Nagarkatti {
481021261ceSAushim Nagarkatti if (!dbusConnection)
482021261ceSAushim Nagarkatti {
483021261ceSAushim Nagarkatti lg2::error("Connection not created");
484021261ceSAushim Nagarkatti return;
485021261ceSAushim Nagarkatti }
486021261ceSAushim Nagarkatti
487021261ceSAushim Nagarkatti dbusConnection->async_method_call(
488021261ceSAushim Nagarkatti [&io, &objectServer, &dbusConnection, &sensors](
489021261ceSAushim Nagarkatti boost::system::error_code ec, const ManagedObjectType& resp) {
490021261ceSAushim Nagarkatti createSensorCallback(ec, resp, io, objectServer, dbusConnection,
491021261ceSAushim Nagarkatti sensors);
492021261ceSAushim Nagarkatti },
493021261ceSAushim Nagarkatti entityManagerName, "/xyz/openbmc_project/inventory",
494021261ceSAushim Nagarkatti "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
495021261ceSAushim Nagarkatti }
496021261ceSAushim Nagarkatti
main()497021261ceSAushim Nagarkatti int main()
498021261ceSAushim Nagarkatti {
499021261ceSAushim Nagarkatti boost::asio::io_context io;
500021261ceSAushim Nagarkatti auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
501021261ceSAushim Nagarkatti sdbusplus::asio::object_server objectServer(systemBus, true);
502021261ceSAushim Nagarkatti objectServer.add_manager("/xyz/openbmc_project/sensors");
503021261ceSAushim Nagarkatti systemBus->request_name("xyz.openbmc_project.SMBPBI");
504021261ceSAushim Nagarkatti
505021261ceSAushim Nagarkatti boost::asio::post(io, [&]() {
506021261ceSAushim Nagarkatti createSensors(io, objectServer, sensors, systemBus);
507021261ceSAushim Nagarkatti });
508021261ceSAushim Nagarkatti
509021261ceSAushim Nagarkatti boost::asio::steady_timer configTimer(io);
510021261ceSAushim Nagarkatti
511*ced35e14SPatrick Williams std::function<void(sdbusplus::message_t&)> eventHandler =
512*ced35e14SPatrick Williams [&](sdbusplus::message_t&) {
513021261ceSAushim Nagarkatti configTimer.expires_after(std::chrono::seconds(1));
514021261ceSAushim Nagarkatti // create a timer because normally multiple properties change
515021261ceSAushim Nagarkatti configTimer.async_wait([&](const boost::system::error_code& ec) {
516021261ceSAushim Nagarkatti if (ec == boost::asio::error::operation_aborted)
517021261ceSAushim Nagarkatti {
518021261ceSAushim Nagarkatti return; // we're being canceled
519021261ceSAushim Nagarkatti }
520021261ceSAushim Nagarkatti // config timer error
521021261ceSAushim Nagarkatti if (ec)
522021261ceSAushim Nagarkatti {
523021261ceSAushim Nagarkatti lg2::error("timer error");
524021261ceSAushim Nagarkatti return;
525021261ceSAushim Nagarkatti }
526021261ceSAushim Nagarkatti createSensors(io, objectServer, sensors, systemBus);
527021261ceSAushim Nagarkatti if (sensors.empty())
528021261ceSAushim Nagarkatti {
529021261ceSAushim Nagarkatti lg2::info("Configuration not detected");
530021261ceSAushim Nagarkatti }
531021261ceSAushim Nagarkatti });
532021261ceSAushim Nagarkatti };
533021261ceSAushim Nagarkatti
534*ced35e14SPatrick Williams sdbusplus::bus::match_t configMatch(
535*ced35e14SPatrick Williams static_cast<sdbusplus::bus_t&>(*systemBus),
536021261ceSAushim Nagarkatti "type='signal',member='PropertiesChanged',"
537021261ceSAushim Nagarkatti "path_namespace='" +
538021261ceSAushim Nagarkatti std::string(inventoryPath) +
539021261ceSAushim Nagarkatti "',"
540021261ceSAushim Nagarkatti "arg0namespace='" +
541021261ceSAushim Nagarkatti configInterface + "'",
542021261ceSAushim Nagarkatti eventHandler);
543021261ceSAushim Nagarkatti
544021261ceSAushim Nagarkatti setupManufacturingModeMatch(*systemBus);
545021261ceSAushim Nagarkatti io.run();
546021261ceSAushim Nagarkatti return 0;
547021261ceSAushim Nagarkatti }
548