xref: /openbmc/dbus-sensors/src/smbpbi/SmbpbiSensor.cpp (revision ced35e14360cb13b92ca0ac394037acbdbbcacc0)
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