dbus-sdr: Make VoltageRegulatorMode exposed to sensorTree.

getSensorSubtree() now search for
xyz.openbmc_project.Control.VoltageRegulatorMode
under the path /xyz/openbmc_project/vr.

Only the failure of searching sensor path is considered as an error.

Tested: ipmiStorageGetSDR()

This requires all the changes in
https://gerrit.openbmc-project.xyz/q/hashtag:%22dbus-sdr-vr-sensors%22+(status:open%20OR%20status:merged)

```
ipmitool sdr list event -v
Running Get PICMG Properties my_addr 0x20, transit 0, target 0
Error response 0xc1 from Get PICMG Properities
Running Get VSO Capabilities my_addr 0x20, transit 0, target 0
Invalid completion code received: Invalid command
Discovered IPMB address 0x0
Sensor ID              : vr_sensor_0_fprof (0xb4)
Entity ID              : 11.5 (Add-in Card)
Sensor Type            : Module / Board (0x15)

Sensor ID              : vr_sensor_1_fprof (0xb5)
Entity ID              : 11.6 (Add-in Card)
Sensor Type            : Module / Board (0x15)

...

```

Signed-off-by: Hao Jiang <jianghao@google.com>
Change-Id: I76d3fedb1cc0a2bc865c2a9c83c0418eb0ee99be
Signed-off-by: Willy Tu <wltu@google.com>
diff --git a/dbus-sdr/sdrutils.cpp b/dbus-sdr/sdrutils.cpp
index 1eadb6f..dbb1445 100644
--- a/dbus-sdr/sdrutils.cpp
+++ b/dbus-sdr/sdrutils.cpp
@@ -43,27 +43,60 @@
 
     sensorTreePtr = std::make_shared<SensorSubTree>();
 
-    auto mapperCall =
-        dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
-                              "/xyz/openbmc_project/object_mapper",
-                              "xyz.openbmc_project.ObjectMapper", "GetSubTree");
     static constexpr const int32_t depth = 2;
-    static constexpr std::array<const char*, 3> interfaces = {
+
+    auto lbdUpdateSensorTree = [&dbus](const char* path,
+                                       const auto& interfaces) {
+        auto mapperCall = dbus->new_method_call(
+            "xyz.openbmc_project.ObjectMapper",
+            "/xyz/openbmc_project/object_mapper",
+            "xyz.openbmc_project.ObjectMapper", "GetSubTree");
+        SensorSubTree sensorTreePartial;
+
+        mapperCall.append(path, depth, interfaces);
+
+        try
+        {
+            auto mapperReply = dbus->call(mapperCall);
+            mapperReply.read(sensorTreePartial);
+        }
+        catch (sdbusplus::exception_t& e)
+        {
+            phosphor::logging::log<phosphor::logging::level::ERR>(
+                "fail to update subtree",
+                phosphor::logging::entry("PATH=%s", path),
+                phosphor::logging::entry("WHAT=%s", e.what()));
+            return false;
+        }
+        if constexpr (debug)
+        {
+            std::fprintf(stderr, "IPMI updated: %zu sensors under %s\n",
+                         sensorTreePartial.size(), path);
+        }
+        sensorTreePtr->merge(std::move(sensorTreePartial));
+        return true;
+    };
+
+    // Add sensors to SensorTree
+    static constexpr const std::array sensorInterfaces = {
         "xyz.openbmc_project.Sensor.Value",
         "xyz.openbmc_project.Sensor.Threshold.Warning",
         "xyz.openbmc_project.Sensor.Threshold.Critical"};
-    mapperCall.append("/xyz/openbmc_project/sensors", depth, interfaces);
+    static constexpr const std::array vrInterfaces = {
+        "xyz.openbmc_project.Control.VoltageRegulatorMode"};
 
-    try
+    bool sensorRez =
+        lbdUpdateSensorTree("/xyz/openbmc_project/sensors", sensorInterfaces);
+
+    // Error if searching for sensors failed.
+    if (!sensorRez)
     {
-        auto mapperReply = dbus->call(mapperCall);
-        mapperReply.read(*sensorTreePtr);
-    }
-    catch (sdbusplus::exception_t& e)
-    {
-        phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
         return sensorUpdatedIndex;
     }
+
+    // Add VR control as optional search path.
+    (void)lbdUpdateSensorTree("/xyz/openbmc_project/vr", vrInterfaces);
+
     subtree = sensorTreePtr;
     sensorUpdatedIndex++;
     // The SDR is being regenerated, wipe the old stats
diff --git a/include/dbus-sdr/sdrutils.hpp b/include/dbus-sdr/sdrutils.hpp
index 8a3858c..753c0dd 100644
--- a/include/dbus-sdr/sdrutils.hpp
+++ b/include/dbus-sdr/sdrutils.hpp
@@ -213,6 +213,17 @@
 // sensors. These objects are global singletons, used from a variety of places.
 inline IPMIStatsTable sdrStatsTable;
 
+/**
+ * Search ObjectMapper for sensors and update them to subtree.
+ *
+ * The function will search for sensors under either
+ * /xyz/openbmc_project/sensors or /xyz/openbmc_project/extsensors. It will
+ * optionally search VR typed sensors under /xyz/openbmc_project/vr
+ *
+ * @return the updated amount of times any of "sensors" or "extsensors" sensor
+ * paths updated successfully, previous amount if all failed. The "vr"
+ * sensor path is optional, and does not participate in the return value.
+ */
 uint16_t getSensorSubtree(std::shared_ptr<SensorSubTree>& subtree);
 
 bool getSensorNumMap(std::shared_ptr<SensorNumMap>& sensorNumMap);