Update PowerSupply to be derived from Device

The PowerSupply will pass a name and instance number down to the Device
class it is derived from, but will also have an inventory path and a
path to monitor for PMBus interfaces.

Change-Id: I29f875fda1f07d031b58ec7ffd381d655495f248
Signed-off-by: Brandon Wyman <bjwyman@gmail.com>
diff --git a/power-supply/argument.cpp b/power-supply/argument.cpp
index 55a81ae..ebdf982 100644
--- a/power-supply/argument.cpp
+++ b/power-supply/argument.cpp
@@ -65,19 +65,26 @@
 {
     std::cerr << "Usage: " << argv[0] << " [options]\n";
     std::cerr << "Options:\n";
-    std::cerr << "    --help               print this menu\n";
-    std::cerr << "    --path=<objpath>     path to location to monitor\n";
+    std::cerr << "    --help                           print this menu\n";
+    std::cerr << "    --path=<objpath>                 path to location to "
+                 "monitor\n";
+    std::cerr << "    --instance=<instance number>     Instance number for this"
+                 " power supply\n";
+    std::cerr << "    --inventory=<inventory path>     Inventory path for this"
+                 " power supply\n";
     std::cerr << std::flush;
 }
 
 const option ArgumentParser::options[] =
 {
-    { "path",   required_argument,  NULL,   'p' },
-    { "help",   no_argument,        NULL,   'h' },
+    { "path",       required_argument,  NULL,   'p' },
+    { "instance",   required_argument,  NULL,   'n' },
+    { "inventory",  required_argument,  NULL,   'i' },
+    { "help",       no_argument,        NULL,   'h' },
     { 0, 0, 0, 0},
 };
 
-const char* ArgumentParser::optionStr = "p:h";
+const char* ArgumentParser::optionStr = "p:n:i:h";
 
 const std::string ArgumentParser::trueString = "true";
 const std::string ArgumentParser::emptyString = "";
diff --git a/power-supply/main.cpp b/power-supply/main.cpp
index d14d37c..eb3f9ed 100644
--- a/power-supply/main.cpp
+++ b/power-supply/main.cpp
@@ -18,17 +18,20 @@
 #include <systemd/sd-daemon.h>
 #include "argument.hpp"
 #include "event.hpp"
+#include "power_supply.hpp"
+#include "device_monitor.hpp"
 
 using namespace witherspoon::power;
 using namespace phosphor::logging;
 
 int main(int argc, char* argv[])
 {
-    auto rc = -1;
     auto options = ArgumentParser(argc, argv);
 
     auto objpath = (options)["path"];
-    if (argc < 2)
+    auto instnum = (options)["instance"];
+    auto invpath = (options)["inventory"];
+    if (argc < 4)
     {
         std::cerr << std::endl << "Too few arguments" << std::endl;
         options.usage(argv);
@@ -41,6 +44,24 @@
         return -2;
     }
 
+    if (instnum == ArgumentParser::emptyString)
+    {
+        log<level::ERR>("Device monitoring instance number argument required");
+        return -3;
+    }
+
+    if (invpath == ArgumentParser::emptyString)
+    {
+        log<level::ERR>("Device monitoring inventory path argument required");
+        return -4;
+    }
+
+    auto objname = "power_supply" + instnum;
+    auto instance = std::stoul(instnum);
+    auto psuDevice = std::make_unique<psu::PowerSupply>(objname,
+                                                        std::move(instance),
+                                                        std::move(objpath),
+                                                        std::move(invpath));
     auto bus = sdbusplus::bus::new_default();
     sd_event* events = nullptr;
 
@@ -49,7 +70,7 @@
     {
         log<level::ERR>("Failed call to sd_event_default()",
                         entry("ERROR=%s", strerror(-r)));
-        return -3;
+        return -5;
     }
 
     witherspoon::power::event::Event eventPtr{events};
@@ -58,14 +79,11 @@
     //handle both sd_events (for the timers) and dbus signals.
     bus.attach_event(eventPtr.get(), SD_EVENT_PRIORITY_NORMAL);
 
-    r = sd_event_loop(eventPtr.get());
-    if (r < 0)
-    {
-        log<level::ERR>("Failed call to sd_event_loop",
-                        entry("ERROR=%s", strerror(-r)));
-    }
+    // TODO: Use inventory path to subscribe to signal change for power supply presence.
 
-    rc = 0;
+    auto pollInterval = std::chrono::milliseconds(1000);
+    DeviceMonitor mainloop(std::move(psuDevice), eventPtr, pollInterval);
+    mainloop.run();
 
-    return rc;
+    return 0;
 }
diff --git a/power-supply/power_supply.cpp b/power-supply/power_supply.cpp
index f246ca4..e9f5d6b 100644
--- a/power-supply/power_supply.cpp
+++ b/power-supply/power_supply.cpp
@@ -15,13 +15,25 @@
  */
 #include "power_supply.hpp"
 
-namespace phosphor
+namespace witherspoon
 {
 namespace power
 {
 namespace psu
 {
 
+void PowerSupply::analyze()
+{
+    //TODO analyze() needs to be implemented in this class.
+    return;
+}
+
+void PowerSupply::clearFaults()
+{
+    //TODO
+    return;
+}
+
 }
 }
 }
diff --git a/power-supply/power_supply.hpp b/power-supply/power_supply.hpp
index 1eab5c4..4249024 100644
--- a/power-supply/power_supply.hpp
+++ b/power-supply/power_supply.hpp
@@ -1,6 +1,7 @@
 #pragma once
+#include "device.hpp"
 
-namespace phosphor
+namespace witherspoon
 {
 namespace power
 {
@@ -9,18 +10,61 @@
 
 /**
  * @class PowerSupply
- * Represents a PMBus power supply.
+ * Represents a PMBus power supply device.
  */
-class PowerSupply
+class PowerSupply : public Device
 {
     public:
         PowerSupply() = delete;
         PowerSupply(const PowerSupply&) = delete;
-        PowerSupply& operator=(const PowerSupply&) = delete;
         PowerSupply(PowerSupply&&) = default;
+        PowerSupply& operator=(const PowerSupply&) = default;
         PowerSupply& operator=(PowerSupply&&) = default;
         ~PowerSupply() = default;
 
+        /**
+         * Constructor
+         *
+         * @param[in] name - the device name
+         * @param[in] inst - the device instance
+         * @param[in] objpath - the path to monitor
+         * @param[in] invpath - the inventory path to use
+         */
+        PowerSupply(const std::string& name, size_t inst,
+                    const std::string& objpath, const std::string& invpath)
+            : Device(name, inst), monitorPath(objpath), inventoryPath(invpath)
+        {
+        }
+
+        /**
+         * Power supply specific function to analyze for faults/errors.
+         *
+         * Various PMBus status bits will be checked for fault conditions.
+         * If a certain fault bits are on, the appropriate error will be
+         * committed.
+         */
+        void analyze() override;
+
+        /**
+         * Write PMBus CLEAR_FAULTS
+         *
+         * This function will be called in various situations in order to clear
+         * any fault status bits that may have been set, in order to start over
+         * with a clean state. Presence changes and power state changes will
+         * want to clear any faults logged.
+         */
+        void clearFaults() override;
+
+    private:
+        /**
+         * The path to use for reading various PMBus bits/words.
+         */
+        std::string monitorPath;
+
+        /**
+         * The D-Bus path to use for this power supply's inventory status.
+         */
+        std::string inventoryPath;
 };
 
 }