PSUSensor: add IIO device sensor
Support IIO device on D-bus via dbus-sensors, expose path to support
multi-channel labels.
Reference:
https://gerrit.openbmc.org/c/openbmc/dbus-sensors/+/47822
This patch is able to support the IIO device ADS1015
Use with this patch.
https://gerrit.openbmc.org/c/openbmc/entity-manager/+/58505
Json config
{
"Address": "0x49",
"Bus": 11,
"Labels": [
"in_voltage1",
"in_voltage2"
],
"Name": "vr_prnt_cem",
"EntityId": "0x07",
"EntityInstance": "0x17",
"in_voltage1_Name": "vr_prnt_msas1",
"in_voltage1_Scale": 1000,
"in_voltage2_Name": "vr_prnt_msas2",
"in_voltage2_Scale": 1000,
"PowerState": "On",
"Thresholds": [
{
"Direction": "greater than",
"Label": "in_voltage1",
"Name": "upper critical",
"Severity": 1,
"Value": 2.0
},
{
"Direction": "less than",
"Label": "in_voltage1",
"Name": "lower critical",
"Severity": 1,
"Value": 0.0
},
{
"Direction": "greater than",
"Label": "in_voltage2",
"Name": "upper critical",
"Severity": 1,
"Value": 2.0
},
{
"Direction": "less than",
"Label": "in_voltage2",
"Name": "lower critical",
"Severity": 1,
"Value": 0.0
}
],
"in_voltage1_Max": 2.0,
"in_voltage1_Min": 0.0,
"in_voltage2_Max": 2.0,
"in_voltage2_Min": 0.0,
"PollRate": 1.0,
"Type": "ADS1015"
}
Tested:
root@qbmc:~# busctl tree xyz.openbmc_project.EntityManager |grep msas
|-/xyz/openbmc_project/inventory/system/board/Yertle/vr_prnt_msas1
`-/xyz/openbmc_project/inventory/system/board/Yertle/vr_prnt_msas2
root@qbmc:~# busctl tree xyz.openbmc_project.PSUSensor
`-/xyz
`-/xyz/openbmc_project
|-/xyz/openbmc_project/control
`-/xyz/openbmc_project/sensors
`-/xyz/openbmc_project/sensors/voltage
|-/xyz/openbmc_project/sensors/voltage/vr_prnt_msas1
`-/xyz/openbmc_project/sensors/voltage/vr_prnt_msas2
root@qbmc:~# busctl get-property xyz.openbmc_project.PSUSensor \
/xyz/openbmc_project/sensors/voltage/vr_prnt_msas1 \
xyz.openbmc_project.Sensor.Value Value
d 1.72
Signed-off-by: Joseph Fu <joseph.fu@quantatw.com>
Change-Id: I584f5d79850921e702b8572fb6b38e9dcfc44d25
diff --git a/src/PSUSensorMain.cpp b/src/PSUSensorMain.cpp
index 510dde4..663567d 100644
--- a/src/PSUSensorMain.cpp
+++ b/src/PSUSensorMain.cpp
@@ -48,6 +48,7 @@
{"ADM1275", I2CDeviceType{"adm1275", true}},
{"ADM1278", I2CDeviceType{"adm1278", true}},
{"ADM1293", I2CDeviceType{"adm1293", true}},
+ {"ADS1015", I2CDeviceType{"ads1015", true}},
{"ADS7830", I2CDeviceType{"ads7830", true}},
{"AHE50DC_FAN", I2CDeviceType{"ahe50dc_fan", true}},
{"BMR490", I2CDeviceType{"bmr490", true}},
@@ -97,6 +98,20 @@
{"XDPE152C4", I2CDeviceType{"xdpe152c4", true}},
};
+enum class DevTypes
+{
+ Unknown = 0,
+ HWMON,
+ IIO
+};
+
+struct DevParams
+{
+ unsigned int matchIndex = 0;
+ std::string matchRegEx;
+ std::string nameRegEx;
+};
+
namespace fs = std::filesystem;
static boost::container::flat_map<std::string, std::shared_ptr<PSUSensor>>
@@ -119,6 +134,7 @@
static std::vector<PSUProperty> psuProperties;
static boost::container::flat_map<size_t, bool> cpuPresence;
+static boost::container::flat_map<DevTypes, DevParams> devParamMap;
// Function CheckEvent will check each attribute from eventMatch table in the
// sysfs. If the attributes exists in sysfs, then store the complete path
@@ -293,7 +309,9 @@
auto devices = instantiateDevices(sensorConfigs, sensors, sensorTypes);
std::vector<fs::path> pmbusPaths;
- if (!findFiles(fs::path("/sys/class/hwmon"), "name", pmbusPaths))
+ findFiles(fs::path("/sys/bus/iio/devices"), "name", pmbusPaths);
+ findFiles(fs::path("/sys/class/hwmon"), "name", pmbusPaths);
+ if (pmbusPaths.empty())
{
std::cerr << "No PSU sensors in system\n";
return;
@@ -338,8 +356,18 @@
continue; // check if path has already been searched
}
- fs::path device = directory / "device";
- std::string deviceName = fs::canonical(device).stem();
+ DevTypes devType = DevTypes::HWMON;
+ std::string deviceName;
+ if (directory.parent_path() == "/sys/class/hwmon")
+ {
+ deviceName = fs::canonical(directory / "device").stem();
+ }
+ else
+ {
+ deviceName = fs::canonical(directory).parent_path().stem();
+ devType = DevTypes::IIO;
+ }
+
auto findHyphen = deviceName.find('-');
if (findHyphen == std::string::npos)
{
@@ -509,7 +537,8 @@
} while (findPSUName != baseConfig->end());
std::vector<fs::path> sensorPaths;
- if (!findFiles(directory, R"(\w\d+_input$)", sensorPaths, 0))
+ if (!findFiles(directory, devParamMap[devType].matchRegEx, sensorPaths,
+ 0))
{
std::cerr << "No PSU non-label sensor in PSU\n";
continue;
@@ -535,7 +564,7 @@
std::get<std::vector<std::string>>(findLabelObj->second);
}
- std::regex sensorNameRegEx("([A-Za-z]+)[0-9]*_");
+ std::regex sensorNameRegEx(devParamMap[devType].nameRegEx);
std::smatch matches;
for (const auto& sensorPath : sensorPaths)
@@ -549,7 +578,9 @@
{
// hwmon *_input filename without number:
// in, curr, power, temp, ...
- sensorNameSubStr = matches[1];
+ // iio in_*_raw filename without number:
+ // voltage, temp, pressure, ...
+ sensorNameSubStr = matches[devParamMap[devType].matchIndex];
}
else
{
@@ -560,61 +591,73 @@
std::string labelPath;
- /* find and differentiate _max and _input to replace "label" */
- size_t pos = sensorPathStr.find('_');
- if (pos != std::string::npos)
+ if (devType == DevTypes::HWMON)
{
- std::string sensorPathStrMax = sensorPathStr.substr(pos);
- if (sensorPathStrMax == "_max")
+ /* find and differentiate _max and _input to replace "label" */
+ size_t pos = sensorPathStr.find('_');
+ if (pos != std::string::npos)
{
- labelPath = boost::replace_all_copy(sensorPathStr, "max",
- "label");
- maxLabel = true;
+ std::string sensorPathStrMax = sensorPathStr.substr(pos);
+ if (sensorPathStrMax == "_max")
+ {
+ labelPath = boost::replace_all_copy(sensorPathStr,
+ "max", "label");
+ maxLabel = true;
+ }
+ else
+ {
+ labelPath = boost::replace_all_copy(sensorPathStr,
+ "input", "label");
+ maxLabel = false;
+ }
}
else
{
- labelPath = boost::replace_all_copy(sensorPathStr, "input",
- "label");
- maxLabel = false;
- }
- }
- else
- {
- continue;
- }
-
- std::ifstream labelFile(labelPath);
- if (!labelFile.good())
- {
- if constexpr (debug)
- {
- std::cerr << "Input file " << sensorPath
- << " has no corresponding label file\n";
- }
- // hwmon *_input filename with number:
- // temp1, temp2, temp3, ...
- labelHead = sensorNameStr.substr(0, sensorNameStr.find('_'));
- }
- else
- {
- std::string label;
- std::getline(labelFile, label);
- labelFile.close();
- auto findSensor = sensors.find(label);
- if (findSensor != sensors.end())
- {
continue;
}
- // hwmon corresponding *_label file contents:
- // vin1, vout1, ...
- labelHead = label.substr(0, label.find(' '));
- }
+ std::ifstream labelFile(labelPath);
+ if (!labelFile.good())
+ {
+ if constexpr (debug)
+ {
+ std::cerr << "Input file " << sensorPath
+ << " has no corresponding label file\n";
+ }
+ // hwmon *_input filename with number:
+ // temp1, temp2, temp3, ...
+ labelHead = sensorNameStr.substr(0,
+ sensorNameStr.find('_'));
+ }
+ else
+ {
+ std::string label;
+ std::getline(labelFile, label);
+ labelFile.close();
+ auto findSensor = sensors.find(label);
+ if (findSensor != sensors.end())
+ {
+ continue;
+ }
- /* append "max" for labelMatch */
- if (maxLabel)
+ // hwmon corresponding *_label file contents:
+ // vin1, vout1, ...
+ labelHead = label.substr(0, label.find(' '));
+ }
+
+ /* append "max" for labelMatch */
+ if (maxLabel)
+ {
+ labelHead.insert(0, "max");
+ }
+
+ checkPWMSensor(sensorPath, labelHead, *interfacePath,
+ dbusConnection, objectServer, psuNames[0]);
+ }
+ else if (devType == DevTypes::IIO)
{
- labelHead.insert(0, "max");
+ auto findIIOHyphen = sensorNameStr.find_last_of('_');
+ labelHead = sensorNameStr.substr(0, findIIOHyphen);
}
if constexpr (debug)
@@ -623,9 +666,6 @@
<< "\" label=\"" << labelHead << "\"\n";
}
- checkPWMSensor(sensorPath, labelHead, *interfacePath,
- dbusConnection, objectServer, psuNames[0]);
-
if (!findLabels.empty())
{
/* Check if this labelHead is enabled in config file */
@@ -817,7 +857,10 @@
}
}
- checkEventLimits(sensorPathStr, limitEventMatch, eventPathList);
+ if (devType == DevTypes::HWMON)
+ {
+ checkEventLimits(sensorPathStr, limitEventMatch, eventPathList);
+ }
// Similarly, if sensor scaling factor is being customized,
// then the below power-of-10 constraint becomes unnecessary,
@@ -932,13 +975,16 @@
}
}
- // OperationalStatus event
- combineEvents[*psuName + "OperationalStatus"] = nullptr;
- combineEvents[*psuName + "OperationalStatus"] =
- std::make_unique<PSUCombineEvent>(objectServer, dbusConnection, io,
- *psuName, readState,
- eventPathList, groupEventPathList,
- "OperationalStatus", pollRate);
+ if (devType == DevTypes::HWMON)
+ {
+ // OperationalStatus event
+ combineEvents[*psuName + "OperationalStatus"] = nullptr;
+ combineEvents[*psuName + "OperationalStatus"] =
+ std::make_unique<PSUCombineEvent>(
+ objectServer, dbusConnection, io, *psuName, readState,
+ eventPathList, groupEventPathList, "OperationalStatus",
+ pollRate);
+ }
}
if constexpr (debug)
@@ -974,6 +1020,7 @@
{"curr", sensor_paths::unitAmperes},
{"temp", sensor_paths::unitDegreesC},
{"in", sensor_paths::unitVolts},
+ {"voltage", sensor_paths::unitVolts},
{"fan", sensor_paths::unitRPMs}};
labelMatch = {
@@ -992,6 +1039,10 @@
{"vin1", PSUProperty("Input Voltage", 300, 0, 3, 0)},
{"vin2", PSUProperty("Input Voltage", 300, 0, 3, 0)},
{"maxvin", PSUProperty("Max Input Voltage", 300, 0, 3, 0)},
+ {"in_voltage0", PSUProperty("Output Voltage", 255, 0, 3, 0)},
+ {"in_voltage1", PSUProperty("Output Voltage", 255, 0, 3, 0)},
+ {"in_voltage2", PSUProperty("Output Voltage", 255, 0, 3, 0)},
+ {"in_voltage3", PSUProperty("Output Voltage", 255, 0, 3, 0)},
{"vout1", PSUProperty("Output Voltage", 255, 0, 3, 0)},
{"vout2", PSUProperty("Output Voltage", 255, 0, 3, 0)},
{"vout3", PSUProperty("Output Voltage", 255, 0, 3, 0)},
@@ -1085,6 +1136,11 @@
{"fan2", {"fan2_alarm", "fan2_fault"}},
{"fan3", {"fan3_alarm", "fan3_fault"}},
{"fan4", {"fan4_alarm", "fan4_fault"}}}}};
+
+ devParamMap = {
+ {DevTypes::HWMON, {1, R"(\w\d+_input$)", "([A-Za-z]+)[0-9]*_"}},
+ {DevTypes::IIO,
+ {2, R"(\w+_(raw|input)$)", "^(in|out)_([A-Za-z]+)[0-9]*_"}}};
}
static void powerStateChanged(