sysfs: Integrate class into Physical and tests

Change-Id: I7d5ad19df5ef1258a4e669ea3243b7411f371d9c
Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
diff --git a/Makefile.am b/Makefile.am
index 5683086..68921d2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -3,10 +3,12 @@
 phosphor_ledcontroller_SOURCES = \
 				controller.cpp  \
 				argument.cpp 	\
-				physical.cpp
+				physical.cpp \
+				sysfs.cpp
 
 phosphor_ledcontroller_LDFLAGS = $(SDBUSPLUS_LIBS) \
-                                 $(PHOSPHOR_DBUS_INTERFACES_LIBS)
+                                 $(PHOSPHOR_DBUS_INTERFACES_LIBS) \
+				 -lstdc++fs
 phosphor_ledcontroller_CFLAGS =  $(SDBUSPLUS_CFLAGS) \
                                  $(PHOSPHOR_DBUS_INTERFACES_CFLAGS)
 
diff --git a/controller.cpp b/controller.cpp
index 02120e2..82430a7 100644
--- a/controller.cpp
+++ b/controller.cpp
@@ -18,6 +18,7 @@
 
 #include "argument.hpp"
 #include "physical.hpp"
+#include "sysfs.hpp"
 
 #include <algorithm>
 #include <iostream>
@@ -33,6 +34,8 @@
 
 int main(int argc, char** argv)
 {
+    namespace fs = std::experimental::filesystem;
+
     // Read arguments.
     auto options = phosphor::led::ArgumentParser(argc, argv);
 
@@ -81,7 +84,8 @@
 
     // Create the Physical LED objects for directing actions.
     // Need to save this else sdbusplus destructor will wipe this off.
-    phosphor::led::Physical led(bus, objPath, path);
+    phosphor::led::SysfsLed sled{fs::path(path)};
+    phosphor::led::Physical led(bus, objPath, sled);
 
     /** @brief Claim the bus */
     bus.request_name(busName.c_str());
diff --git a/physical.cpp b/physical.cpp
index e7ca582..3290661 100644
--- a/physical.cpp
+++ b/physical.cpp
@@ -26,26 +26,19 @@
 /** @brief Populates key parameters */
 void Physical::setInitialState()
 {
-    // Control files in /sys/class/leds/<led-name>
-    brightCtrl = path + BRIGHTNESS;
-    blinkCtrl = path + BLINKCTRL;
-
-    delayOnCtrl = path + DELAYON;
-    delayOffCtrl = path + DELAYOFF;
-
     // 1. read /sys/class/leds/name/trigger
     // 2. If its 'timer', then its blinking.
     //    2.1: On blink, use delay_on and delay_off into dutyOn
     // 3. If its 'none', then read brightness. 255 means, its ON, else OFF.
 
-    auto trigger = read<std::string>(blinkCtrl);
+    auto trigger = led.getTrigger();
     if (trigger == "timer")
     {
         // LED is blinking. Get the delay_on and delay_off and compute
         // DutyCycle. sfsfs values are in strings. Need to convert 'em over to
         // integer.
-        auto delayOn = std::stoi(read<std::string>(delayOnCtrl));
-        auto delayOff = std::stoi(read<std::string>(delayOffCtrl));
+        auto delayOn = led.getDelayOn();
+        auto delayOff = led.getDelayOff();
 
         // Calculate frequency and then percentage ON
         frequency = delayOn + delayOff;
@@ -63,8 +56,8 @@
         frequency = 1000;
 
         // LED is either ON or OFF
-        auto brightness = read<std::string>(brightCtrl);
-        if (brightness == std::string(ASSERT))
+        auto brightness = led.getBrightness();
+        if (brightness == ASSERT)
         {
             // LED is in Solid ON
             sdbusplus::xyz::openbmc_project::Led::server ::Physical::state(
@@ -126,10 +119,10 @@
     auto value = (action == Action::On) ? ASSERT : DEASSERT;
 
     // Write "none" to trigger to clear any previous action
-    write(blinkCtrl, "none");
+    led.setTrigger("none");
 
     // And write the current command
-    write(brightCtrl, value);
+    led.setBrightness(value);
     return;
 }
 
@@ -140,15 +133,15 @@
     auto dutyOn = this->dutyOn();
 
     // Write "timer" to "trigger" file
-    write(blinkCtrl, "timer");
+    led.setTrigger("timer");
 
     // Write DutyON. Value in percentage 1_millisecond.
     // so 50% input becomes 500. Driver wants string input
     auto percentage = frequency / 100;
-    write(delayOnCtrl, std::to_string(dutyOn * percentage));
+    led.setDelayOn(dutyOn * percentage);
 
     // Write DutyOFF. Value in milli seconds so 50% input becomes 500.
-    write(delayOffCtrl, std::to_string((100 - dutyOn) * percentage));
+    led.setDelayOff((100 - dutyOn) * percentage);
     return;
 }
 
diff --git a/physical.hpp b/physical.hpp
index 47ad7d5..c8ef4fd 100644
--- a/physical.hpp
+++ b/physical.hpp
@@ -1,50 +1,22 @@
 #pragma once
 
+#include "sysfs.hpp"
+
 #include <fstream>
 #include <sdbusplus/bus.hpp>
 #include <sdbusplus/server/object.hpp>
 #include <string>
 #include <xyz/openbmc_project/Led/Physical/server.hpp>
+
 namespace phosphor
 {
 namespace led
 {
-/** @brief Acts as input and output file for the current LED power state.
- *   Write "0" to trigger a LED OFF operation.
- *   Write "255" to trigger a LED ON operation.
- *   To know the current power state of the LED, a read on this
- *   would give either 0 or 255 indicating if the LED is currently
- *   Off / On AT THAT moment.
- *   Example: /sys/class/leds/myled/brightness
- */
-constexpr auto BRIGHTNESS = "/brightness";
-
 /** @brief Assert LED by writing 255 */
-constexpr auto ASSERT = "255";
+constexpr auto ASSERT = 255;
 
 /** @brief De-assert by writing "0" */
-constexpr auto DEASSERT = "0";
-
-/** @brief Write "timer" to this file telling the driver that
- *   the intended operation is BLINK. When the value "timer" is written to
- *   the file, 2 more files get auto generated and are named "delay_on" and
- *   "delay_off"
- *   To move away from blinking, write "none"
- *   Example:  /sys/class/leds/myled/trigger
- */
-constexpr auto BLINKCTRL = "/trigger";
-
-/** @brief write number of milliseconds that the LED needs to be ON
- *   while blinking. Default is 500 by the driver.
- *   Example:  /sys/class/leds/myled/delay_on
- */
-constexpr auto DELAYON = "/delay_on";
-
-/** @brief Write number of milliseconds that the LED needs to be OFF
- *   while blinking. Default is 500 by the driver.
- *   Example:  /sys/class/leds/myled/delay_off
- */
-constexpr auto DELAYOFF = "/delay_off";
+constexpr auto DEASSERT = 0;
 
 /** @class Physical
  *  @brief Responsible for applying actions on a particular physical LED
@@ -70,12 +42,12 @@
      * @param[in] ledPath   - sysfs path where this LED is exported
      */
     Physical(sdbusplus::bus::bus& bus, const std::string& objPath,
-             const std::string& ledPath) :
+             SysfsLed& led) :
 
         sdbusplus::server::object::object<
             sdbusplus::xyz::openbmc_project::Led::server::Physical>(
             bus, objPath.c_str(), true),
-        path(ledPath)
+        led(led)
     {
         // Suppose this is getting launched as part of BMC reboot, then we
         // need to save what the micro-controller currently has.
@@ -93,28 +65,15 @@
     Action state(Action value) override;
 
   private:
-    /** @brief File system location where this LED is exposed
-     *   Typically /sys/class/leds/<Led-Name>
+    /** @brief Associated LED implementation
      */
-    std::string path;
+    SysfsLed& led;
 
     /** @brief Frequency range that the LED can operate on.
      *  Will be removed when frequency is put into interface
      */
     uint32_t frequency;
 
-    /** @brief Brightness described above */
-    std::string brightCtrl;
-
-    /** @brief BlinkCtrl described above */
-    std::string blinkCtrl;
-
-    /** @brief delay_on described above */
-    std::string delayOnCtrl;
-
-    /** @brief delay_ff described above */
-    std::string delayOffCtrl;
-
     /** @brief reads sysfs and then setsup the parameteres accordingly
      *
      *  @return None
@@ -143,46 +102,6 @@
      *  @return None
      */
     void blinkOperation();
-
-    /** @brief Generic file writer.
-     *   There are files like "brightness", "trigger" , "delay_on" and
-     *   "delay_off" that will tell what the LED driver needs to do.
-     *
-     *  @param[in] filename - Name of file to be written
-     *  @param[in] data     - Data to be written to
-     *  @return             - None
-     */
-    template <typename T>
-    auto write(const std::string& fileName, T&& data)
-    {
-        if (std::ifstream(fileName))
-        {
-            std::ofstream file(fileName, std::ios::out);
-            file << data;
-            file.close();
-        }
-        return;
-    }
-
-    /** @brief Generic file reader.
-     *   There are files like "brightness", "trigger" , "delay_on" and
-     *   "delay_off" that will tell what the LED driver needs to do.
-     *
-     *  @param[in] filename - Name of file to be read
-     *  @return             - File content
-     */
-    template <typename T>
-    T read(const std::string& fileName)
-    {
-        T data = T();
-        if (std::ifstream(fileName))
-        {
-            std::ifstream file(fileName, std::ios::in);
-            file >> data;
-            file.close();
-        }
-        return data;
-    }
 };
 
 } // namespace led
diff --git a/test/Makefile.am.include b/test/Makefile.am.include
index 95fe19e..98cc6fb 100644
--- a/test/Makefile.am.include
+++ b/test/Makefile.am.include
@@ -21,7 +21,7 @@
 	-lgtest -lgtest_main -lgmock $(PTHREAD_CFLAGS) $(OESDK_TESTCASE_FLAGS)
 
 test_physical_SOURCES = %reldir%/physical.cpp
-test_physical_LDADD = physical.o
+test_physical_LDADD = physical.o sysfs.o
 
 test_sysfs_SOURCES = %reldir%/sysfs.cpp
 test_sysfs_LDADD = sysfs.cpp
diff --git a/test/physical.cpp b/test/physical.cpp
index 9ab4a30..4316b16 100644
--- a/test/physical.cpp
+++ b/test/physical.cpp
@@ -8,30 +8,35 @@
 constexpr auto LED_SYSFS = "/sys/class/leds/test";
 
 using Action = sdbusplus::xyz::openbmc_project::Led::server::Physical::Action;
+namespace fs = std::experimental::filesystem;
 
 TEST(Physical, ctor)
 {
     sdbusplus::bus::bus bus = sdbusplus::bus::new_default();
-    phosphor::led::Physical led(bus, LED_OBJ, LED_SYSFS);
+    phosphor::led::SysfsLed led{fs::path(LED_SYSFS)};
+    phosphor::led::Physical phy(bus, LED_OBJ, led);
 }
 
 TEST(Physical, off)
 {
     sdbusplus::bus::bus bus = sdbusplus::bus::new_default();
-    phosphor::led::Physical led(bus, LED_OBJ, LED_SYSFS);
-    led.state(Action::Off);
+    phosphor::led::SysfsLed led{fs::path(LED_SYSFS)};
+    phosphor::led::Physical phy(bus, LED_OBJ, led);
+    phy.state(Action::Off);
 }
 
 TEST(Physical, on)
 {
     sdbusplus::bus::bus bus = sdbusplus::bus::new_default();
-    phosphor::led::Physical led(bus, LED_OBJ, LED_SYSFS);
-    led.state(Action::On);
+    phosphor::led::SysfsLed led{fs::path(LED_SYSFS)};
+    phosphor::led::Physical phy(bus, LED_OBJ, led);
+    phy.state(Action::On);
 }
 
 TEST(Physical, blink)
 {
     sdbusplus::bus::bus bus = sdbusplus::bus::new_default();
-    phosphor::led::Physical led(bus, LED_OBJ, LED_SYSFS);
-    led.state(Action::Blink);
+    phosphor::led::SysfsLed led{fs::path(LED_SYSFS)};
+    phosphor::led::Physical phy(bus, LED_OBJ, led);
+    phy.state(Action::Blink);
 }