Add CapLimits dbus interface to occ-control app

The power cap limits were previously hosted by Settings, but those are
system settings and the limits are not really settings (users can not
adjust these). This will allow occ-control to update these limits as
required but makes them readonly on dbus.
occ-control will now be persisting these limits.

Tested on Rainier:

'''
=> busctl -l introspect org.open_power.OCC.Control /xyz/openbmc_project/control/host0/power_cap_limits
...
xyz.openbmc_project.Control.Power.CapLimits interface -         -            -
.MaxPowerCapValue                           property  u         2777         emits-change
.MinPowerCapValue                           property  u         1286         emits-change
.MinSoftPowerCapValue                       property  u         556          emits-change

=> hexdump /var/lib//openpower-occ-control/powerCapData
0000000 0001 0000 0001 0000 022c 0000 0506 0000
0000010 0ad9 0000
0000014
'''

Change-Id: I75fd98be18c884961f417cc53213b9cb06a82947
Signed-off-by: Chris Cain <cjcain@us.ibm.com>
diff --git a/powercap.hpp b/powercap.hpp
index 45d1203..c46b6b9 100644
--- a/powercap.hpp
+++ b/powercap.hpp
@@ -6,6 +6,7 @@
 
 #include <sdbusplus/bus.hpp>
 #include <sdbusplus/bus/match.hpp>
+#include <xyz/openbmc_project/Control/Power/CapLimits/server.hpp>
 
 #include <filesystem>
 #include <regex>
@@ -22,6 +23,95 @@
 namespace sdbusRule = sdbusplus::bus::match::rules;
 namespace fs = std::filesystem;
 
+constexpr auto PCAPLIMITS_PATH =
+    "/xyz/openbmc_project/control/host0/power_cap_limits";
+
+namespace Base = sdbusplus::xyz::openbmc_project::Control::Power::server;
+using CapLimitsInterface = sdbusplus::server::object_t<Base::CapLimits>;
+
+constexpr auto PCAPDATA_FILE_VERSION = 1;
+struct PowerCapData
+{
+    uint32_t version = PCAPDATA_FILE_VERSION;
+    bool initialized = false;
+    uint32_t softMin = 0x0000;
+    uint32_t hardMin = 0x0000;
+    uint32_t max = UINT_MAX;
+};
+
+/** @class OccPersistCapData
+ *  @brief Provides persistent container to store data for OCC
+ *
+ * Data is stored in filesystem
+ */
+class OccPersistCapData
+{
+  public:
+    ~OccPersistCapData() = default;
+    OccPersistCapData(const OccPersistCapData&) = default;
+    OccPersistCapData& operator=(const OccPersistCapData&) = default;
+    OccPersistCapData(OccPersistCapData&&) = default;
+    OccPersistCapData& operator=(OccPersistCapData&&) = default;
+
+    /** @brief Loads any saved power cap data */
+    OccPersistCapData()
+    {
+        load();
+    }
+
+    /** @brief Save Power Mode data to persistent file
+     *
+     *  @param[in] softMin - soft minimum power cap in Watts
+     *  @param[in] hardMin - hard minimum power cap in Watts
+     *  @param[in] max     - maximum power cap in Watts
+     */
+    void updateCapLimits(const uint32_t softMin, const uint32_t hardMin,
+                         const uint32_t max)
+    {
+        capData.softMin = softMin;
+        capData.hardMin = hardMin;
+        capData.max = max;
+        capData.initialized = true;
+        save();
+    }
+
+    /** @brief Return the power cap limits
+     *
+     *  @param[out] softMin - soft minimum power cap in Watts
+     *  @param[out] hardMin - hard minimum power cap in Watts
+     *  @param[out] max     - maximum power cap in Watts
+     */
+    void getCapLimits(uint32_t& softMin, uint32_t& hardMin, uint32_t& max) const
+    {
+        // If not initialized yet, still return PowerCapData defaults
+        softMin = capData.softMin;
+        hardMin = capData.hardMin;
+        max = capData.max;
+    }
+
+    /** @brief Return true if the power cap limits are available */
+    bool limitsAvailable()
+    {
+        return (capData.initialized);
+    }
+
+    /** @brief Saves the Power Mode data in the filesystem. */
+    void save();
+
+    /** @brief Trace the Power Mode and IPS parameters. */
+    void print();
+
+  private:
+    /** @brief Power Mode data filename to store persistent data */
+    static constexpr auto powerCapFilename = "powerCapData";
+
+    /** @brief Power Mode data object to be persisted */
+    PowerCapData capData;
+
+    /** @brief Loads the persisted power cap data from the filesystem. */
+    void load();
+};
+
 /** @class PowerCap
  *  @brief Monitors for changes to the power cap and notifies occ
  *
@@ -30,7 +120,7 @@
  *  the power cap to the OCC if the cap is changed while the occ is active.
  */
 
-class PowerCap
+class PowerCap : public CapLimitsInterface
 {
   public:
     /** @brief PowerCap object to inform occ of changes to cap
@@ -42,6 +132,8 @@
      * @param[in] occStatus - The occ status object
      */
     explicit PowerCap(Status& occStatus) :
+        CapLimitsInterface(utils::getBus(), PCAPLIMITS_PATH,
+                           CapLimitsInterface::action::defer_emit),
         occStatus(occStatus),
         pcapMatch(
             utils::getBus(),
@@ -51,7 +143,16 @@
                 sdbusRule::argN(0, "xyz.openbmc_project.Control.Power.Cap") +
                 sdbusRule::interface("org.freedesktop.DBus.Properties"),
             std::bind(std::mem_fn(&PowerCap::pcapChanged), this,
-                      std::placeholders::_1)) {};
+                      std::placeholders::_1))
+    {
+        //  Read the current limits from persistent data
+        uint32_t capSoftMin, capHardMin, capMax;
+        persistedData.getCapLimits(capSoftMin, capHardMin, capMax);
+        // Update limits on dbus
+        updateDbusPcapLimits(capSoftMin, capHardMin, capMax);
+        // CapLimit interface is now ready
+        this->emit_object_added();
+    };
 
     /** @brief Return the appropriate value to write to the OCC (output/DC
      * power)
@@ -67,6 +168,9 @@
     void updatePcapBounds();
 
   private:
+    /** @brief Persisted power cap limits */
+    OccPersistCapData persistedData;
+
     /** @brief Callback for pcap setting changes
      *
      * Process change and inform OCC
@@ -126,24 +230,9 @@
      * @param[in]  softMin - soft minimum power cap in Watts
      * @param[in]  hardMin - hard minimum power cap in Watts
      * @param[in]  pcapMax - maximum power cap in Watts
-     *
-     * @return true if all parms were written successfully
      */
-    bool updateDbusPcapLimits(uint32_t softMin, uint32_t hardMin,
+    void updateDbusPcapLimits(uint32_t softMin, uint32_t hardMin,
                               uint32_t pcapMax);
-
-    /** @brief Read the power cap bounds from DBus
-     *
-     * @param[out]  softMin - soft minimum power cap in Watts
-     * @param[out]  hardMin - hard minimum power cap in Watts
-     * @param[out]  pcapMax - maximum power cap in Watts
-     *
-     * @return true if all parms were read successfully
-     *         If a parm is not successfully read, it will default to 0 for the
-     *           Min parameter and INT_MAX for the Max parameter
-     */
-    bool readDbusPcapLimits(uint32_t& softMin, uint32_t& hardMin,
-                            uint32_t& max);
 };
 
 } // namespace powercap