Use generic interface to look for configs

IBM has specific interface IBMCompatibleSystem to look for the
compatible system location under which the configs are placed. The
Entity Manager schema for the property under this interface and the
interface name itself can't be generic for other meta systems.
To find a more common interface, this should be the one that is probed
together with chassis and has its property value corresponding to
system's name.

This commit proposes the use of the property Names under the interface
xyz.openbmc_project.Inventory.Decorator.Compatible [1]. The property
can be configured in chassis's Entity Manager json configuration with
a list of one or more compatible system strings. The usage of this
interface was mentioned in document [2].

[1] https://github.com/openbmc/phosphor-dbus-interfaces/blob/master/\
yaml/xyz/openbmc_project/Inventory/Decorator/Compatible.interface.yaml
[2] https://github.com/openbmc/phosphor-dbus-interfaces/blob/master/\
yaml/xyz/openbmc_project/Software/README.md#compatibility

Tested in Ampere's Mt.Mitchell platform.

1. Configure the interface in Motherboard's Entity Manager config:
"xyz.openbmc_project.Inventory.Decorator.Compatible": {
            "Names": ["com.ampere.Hardware.Chassis.Model.MtMitchell"]
        }
2. Configs are already placed under
/usr/share/phosphor-fan-presence/<daemon>/\
com.ampere.Hardware.Chassis.Model.MtMitchell/
3. When Entity Manager config is probed:
$ busctl call -j xyz.openbmc_project.ObjectMapper \
/xyz/openbmc_project/object_mapper xyz.openbmc_project.ObjectMapper \
GetSubTreePaths sias / 0 1
xyz.openbmc_project.Inventory.Decorator.Compatible
{
  "type": "a{sa{sas}}",
  "data": [
    [
       "/xyz/openbmc_project/inventory/system/board/\
Mt_Mitchell_Motherboard" : {
           "xyz.openbmc_project.EntityManager" : [
                ...
                "xyz.openbmc_project.Inventory.Decorator.Compatible
           ]
         }
    ]
  ]
}

$ busctl get-property xyz.openbmc_project.EntityManager \
/xyz/openbmc_project/inventory/system/board/Mt_Mitchell_Motherboard \
xyz.openbmc_project.Inventory.Decorator.Compatible Names
as 1 "com.ampere.Hardware.Chassis.Model.MtMitchell"
4. When phosphor-fan's daemon starts, it can successfully find
configs under the folder "com.ampere.Hardware.Chassis.Model.MtMitchell"

Signed-off-by: Chau Ly <chaul@amperecomputing.com>
Change-Id: I55107f1c2a78e78ba7cea650b8eaeaf4fd615d2b
diff --git a/docs/control/README.md b/docs/control/README.md
index 9a6490e..39fa080 100644
--- a/docs/control/README.md
+++ b/docs/control/README.md
@@ -63,24 +63,24 @@
 where more than one type of machine is supported in a single BMC firmware image
 and those system types can not share any one common config file.
 
-A system type sub-directory can be obtained from the `IBMCompatibleSystem` D-Bus
-interface's `Names` property. The `Names` property contains a list of one or
-more compatible system types, ordered from most specific to the most general.
+A system type sub-directory can be obtained from the
+`Inventory.Decorator.Compatible` D-Bus interface's `Names` property. The
+property holds a list of one or more compatible system types.
 
 Example:
 
-- `ibm,rainier-2u`
-- `ibm,rainier`
+- `com.ampere.Hardware.Chassis.Model.MtJade`
+- `com.ampere.Hardware.Chassis.Model.MtMitchell`
 
 The `phosphor-fan-control` application then traverses the supported directory,
-appending each compatible system type entry as a sub-directory from most
-specific to most general on each config file until it is found.
+appending each compatible system type entry as a sub-directory on each config
+file until it is found.
 
 Example:
 
-1. `/usr/share/phosphor-fan-presence/control/ibm,rainier-2u/`
+1. `/usr/share/phosphor-fan-presence/control/com.ampere.Hardware.Chassis.Model.MtJade/`
    - (directory/config file does not exist)
-2. `/usr/share/phosphor-fan-presence/control/ibm,rainier/events.json`
+2. `/usr/share/phosphor-fan-presence/control/com.ampere.Hardware.Chassis.Model.MtMitchell/events.json`
    - (config file found)
 
 If any required config file is not found and the machine is powered on, an error
diff --git a/docs/monitor/README.md b/docs/monitor/README.md
index db0c31f..34a746b 100644
--- a/docs/monitor/README.md
+++ b/docs/monitor/README.md
@@ -56,24 +56,24 @@
 where more than one type of machine is supported in a single BMC firmware image
 and those system types can not share a common config file.
 
-A system type sub-directory can be obtained from the `IBMCompatibleSystem` D-Bus
-interface's `Names` property. The `Names` property contains a list of one or
-more compatible system types, ordered from most specific to the most general.
+A system type sub-directory can be obtained from the
+`Inventory.Decorator.Compatible` D-Bus interface's `Names` property. The
+property holds a list of one or more compatible system types.
 
 Example:
 
-- `ibm,rainier-2u`
-- `ibm,rainier`
+- `com.ampere.Hardware.Chassis.Model.MtJade`
+- `com.ampere.Hardware.Chassis.Model.MtMitchell`
 
 The `phosphor-fan-monitor` application then traverses the supported directory,
-appending each compatible system type entry as a sub-directory from most
-specific to most general until the config file is found.
+appending each compatible system type entry as a sub-directory on each config
+file until it is found.
 
 Example:
 
-1. `/usr/share/phosphor-fan-presence/monitor/ibm,rainier-2u/`
+1. `/usr/share/phosphor-fan-presence/monitor/com.ampere.Hardware.Chassis.Model.MtJade/`
    - (directory/config file does not exist)
-2. `/usr/share/phosphor-fan-presence/monitor/ibm,rainier/config.json`
+2. `/usr/share/phosphor-fan-presence/monitor/com.ampere.Hardware.Chassis.Model.MtMitchell/config.json`
    - (config file found)
 
 If a config file is not found and the machine is powered on, an error is logged
diff --git a/docs/presence/README.md b/docs/presence/README.md
index 6f94a6e..b54fd8d 100644
--- a/docs/presence/README.md
+++ b/docs/presence/README.md
@@ -54,24 +54,24 @@
 where more than one type of machine is supported in a single BMC firmware image
 and those system types can not share a common config file.
 
-A system type sub-directory can be obtained from the `IBMCompatibleSystem` D-Bus
-interface's `Names` property. The `Names` property contains a list of one or
-more compatible system types, ordered from most specific to the most general.
+A system type sub-directory can be obtained from the
+`Inventory.Decorator.Compatible` D-Bus interface's `Names` property. The
+property holds a list of one or more compatible system types.
 
 Example:
 
-- `ibm,rainier-2u`
-- `ibm,rainier`
+- `com.ampere.Hardware.Chassis.Model.MtJade`
+- `com.ampere.Hardware.Chassis.Model.MtMitchell`
 
 The `phosphor-fan-presence-tach` application then traverses the supported
-directory, appending each compatible system type entry as a sub-directory from
-most specific to most general until the config file is found.
+directory, appending each compatible system type entry as a sub-directory on
+each config file until it is found.
 
 Example:
 
-1. `/usr/share/phosphor-fan-presence/presence/ibm,rainier-2u/`
+1. `/usr/share/phosphor-fan-presence/presence/com.ampere.Hardware.Chassis.Model.MtJade/`
    - (directory/config file does not exist)
-2. `/usr/share/phosphor-fan-presence/presence/ibm,rainier/config.json`
+2. `/usr/share/phosphor-fan-presence/presence/com.ampere.Hardware.Chassis.Model.MtMitchell/config.json`
    - (config file found)
 
 If a config file is not found and the machine is powered on, an error is logged
diff --git a/json_config.hpp b/json_config.hpp
index 3ec0c8a..04deb6b 100644
--- a/json_config.hpp
+++ b/json_config.hpp
@@ -37,7 +37,7 @@
 constexpr auto confBasePath = "/usr/share/phosphor-fan-presence";
 constexpr auto confCompatServ = "xyz.openbmc_project.EntityManager";
 constexpr auto confCompatIntf =
-    "xyz.openbmc_project.Configuration.IBMCompatibleSystem";
+    "xyz.openbmc_project.Inventory.Decorator.Compatible";
 constexpr auto confCompatProp = "Names";
 
 /**
@@ -84,10 +84,23 @@
      * Retrieve all the object paths implementing the compatible interface for
      * configuration file loading.
      */
-    static auto& getCompatObjPaths() __attribute__((pure))
+    std::vector<std::string>& getCompatObjPaths()
     {
-        static auto paths = util::SDBusPlus::getSubTreePathsRaw(
+        using SubTreeMap =
+            std::map<std::string,
+                     std::map<std::string, std::vector<std::string>>>;
+        SubTreeMap subTreeObjs = util::SDBusPlus::getSubTreeRaw(
             util::SDBusPlus::getBus(), "/", confCompatIntf, 0);
+
+        static std::vector<std::string> paths;
+        for (auto& [path, serviceMap] : subTreeObjs)
+        {
+            // Only save objects under confCompatServ
+            if (serviceMap.find(confCompatServ) != serviceMap.end())
+            {
+                paths.emplace_back(path);
+            }
+        }
         return paths;
     }
 
@@ -130,7 +143,7 @@
                 {
                     // Retrieve json config compatible relative path
                     // locations (last one found will be what's used if more
-                    // than one dbus object implementing the comptaible
+                    // than one dbus object implementing the compatible
                     // interface exists).
                     _confCompatValues =
                         util::SDBusPlus::getProperty<std::vector<std::string>>(
@@ -143,7 +156,16 @@
                     // path's compatible interface, ignore
                 }
             }
-            _loadFunc();
+            try
+            {
+                _loadFunc();
+            }
+            catch (const NoConfigFound&)
+            {
+                // The Decorator.Compatible interface is not unique to one
+                // single object on DBus so this should not be treated as a
+                // failure, wait for interfacesAdded signal.
+            }
         }
         else
         {
@@ -175,6 +197,12 @@
      */
     void compatIntfAdded(sdbusplus::message_t& msg)
     {
+        if (!_compatibleName.empty())
+        {
+            // Do not process the interfaceAdded signal if one compatible name
+            // has been successfully used to get config files
+            return;
+        }
         sdbusplus::message::object_path op;
         std::map<std::string,
                  std::map<std::string, std::variant<std::vector<std::string>>>>
@@ -239,11 +267,13 @@
             std::find_if(_confCompatValues.begin(), _confCompatValues.end(),
                          [&confFile, &appName, &fileName](const auto& value) {
             confFile = fs::path{confBasePath} / appName / value / fileName;
+            _compatibleName = value;
             return fs::exists(confFile);
         });
         if (it == _confCompatValues.end())
         {
             confFile.clear();
+            _compatibleName.clear();
         }
 
         if (confFile.empty() && !isOptional)
@@ -322,7 +352,7 @@
 
     /**
      * @brief The interfacesAdded match that is used to wait
-     *        for the IBMCompatibleSystem interface to show up.
+     *        for the Inventory.Decorator.Compatible interface to show up.
      */
     std::unique_ptr<sdbusplus::bus::match_t> _match;
 
@@ -334,6 +364,16 @@
      * interface, the last one found will be the list of compatible values used.
      */
     inline static std::vector<std::string> _confCompatValues;
+
+    /**
+     * @brief The compatible value that is currently used to load configuration
+     *
+     * The value extracted from the achieved property value list that is used
+     * as a sub-folder to append to the configuration location and really
+     * contains the configruation files
+     */
+
+    inline static std::string _compatibleName;
 };
 
 } // namespace phosphor::fan