sensor: Implement sensor "ACCURACY"

Support the accuracy attribute of the sensor. Since the latest
Redfish spec needs to support the accuracy attribute of the sensor,
extend the configuration file syntax to support the accuracy value,
read the value and publish it to the new D-Bus Accuracy interface.

Also, This function will be synchronized to the dbus sensors repo in
the future.

Tested: Build phosphor-hwmon successfully
eg: The configuration accuracy in power supply is 1
~# busctl get-property xyz.openbmc_project.Hwmon-xxx.Hwmon1
/xyz/openbmc_project/sensors/power/ps0_input_power
xyz.openbmc_project.Sensor.Accuracy Accuracy
d 1

Signed-off-by: George Liu <liuxiwei@inspur.com>
Change-Id: Idd0159b75a7506001cf886f4ae8a22dbd38b1135
diff --git a/interface.hpp b/interface.hpp
index 00ac05e..6e2d71d 100644
--- a/interface.hpp
+++ b/interface.hpp
@@ -3,6 +3,7 @@
 #include <sdbusplus/server.hpp>
 #include <xyz/openbmc_project/Control/FanPwm/server.hpp>
 #include <xyz/openbmc_project/Control/FanSpeed/server.hpp>
+#include <xyz/openbmc_project/Sensor/Accuracy/server.hpp>
 #include <xyz/openbmc_project/Sensor/Threshold/Critical/server.hpp>
 #include <xyz/openbmc_project/Sensor/Threshold/Warning/server.hpp>
 #include <xyz/openbmc_project/Sensor/Value/server.hpp>
@@ -31,6 +32,10 @@
 
 using SensorValueType = double;
 
+using AccuracyInterface =
+    sdbusplus::xyz::openbmc_project::Sensor::server::Accuracy;
+using AccuracyObject = ServerObject<AccuracyInterface>;
+
 enum class InterfaceType
 {
     VALUE,
@@ -39,6 +44,7 @@
     FAN_SPEED,
     FAN_PWM,
     STATUS,
+    ACCURACY,
 };
 
 // vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
diff --git a/mainloop.cpp b/mainloop.cpp
index 85770a2..f205003 100644
--- a/mainloop.cpp
+++ b/mainloop.cpp
@@ -174,14 +174,17 @@
 {
     std::string id = getID(sensor);
     std::string label;
+    std::string accuracy;
 
     if (!id.empty())
     {
         // Ignore inputs without a label.
         label = env::getEnv("LABEL", sensor.first.first, id);
+        accuracy = env::getEnv("ACCURACY", sensor.first.first, id);
     }
 
-    return std::make_tuple(std::move(id), std::move(label));
+    return std::make_tuple(std::move(id), std::move(label),
+                           std::move(accuracy));
 }
 
 /**
@@ -237,6 +240,20 @@
     auto valueInterface = static_cast<std::shared_ptr<ValueObject>>(nullptr);
     try
     {
+        // Add accuracy interface
+        auto accuracyStr = std::get<sensorAccuracy>(properties);
+        try
+        {
+            if (!accuracyStr.empty())
+            {
+                auto accuracy = stod(accuracyStr);
+                sensorObj->addAccuracy(info, accuracy);
+            }
+        }
+        catch (const std::invalid_argument&)
+        {
+        }
+
         // Add status interface based on _fault file being present
         sensorObj->addStatus(info);
         valueInterface = sensorObj->addValue(retryIO, info, _timedoutMap);
diff --git a/mainloop.hpp b/mainloop.hpp
index a187b39..468223b 100644
--- a/mainloop.hpp
+++ b/mainloop.hpp
@@ -23,7 +23,8 @@
 
 static constexpr auto sensorID = 0;
 static constexpr auto sensorLabel = 1;
-using SensorIdentifiers = std::tuple<std::string, std::string>;
+static constexpr auto sensorAccuracy = 2;
+using SensorIdentifiers = std::tuple<std::string, std::string, std::string>;
 
 /** @class MainLoop
  *  @brief hwmon-readd main application loop.
diff --git a/sensor.cpp b/sensor.cpp
index 2f6ee34..1d031f4 100644
--- a/sensor.cpp
+++ b/sensor.cpp
@@ -263,6 +263,22 @@
     return iface;
 }
 
+std::shared_ptr<AccuracyObject> Sensor::addAccuracy(ObjectInfo& info,
+                                                    double accuracy)
+{
+    auto& objPath = std::get<std::string>(info);
+    auto& obj = std::get<InterfaceMap>(info);
+
+    auto& bus = *std::get<sdbusplus::bus_t*>(info);
+    auto iface = std::make_shared<AccuracyObject>(
+        bus, objPath.c_str(), AccuracyObject::action::emit_no_signals);
+
+    iface->accuracy(accuracy);
+    obj[InterfaceType::ACCURACY] = iface;
+
+    return iface;
+}
+
 void gpioLock(const gpioplus::HandleInterface*&& handle)
 {
     handle->setValues({0});
diff --git a/sensor.hpp b/sensor.hpp
index a1e0524..1fd6a70 100644
--- a/sensor.hpp
+++ b/sensor.hpp
@@ -125,6 +125,19 @@
     std::shared_ptr<StatusObject> addStatus(ObjectInfo& info);
 
     /**
+     * @brief Add Accuracy interface and accuracy property for sensor
+     * @details Accuracy interface is the accuracy range (+/-) of the sensor
+     * Value as a percentage, with a value between 0 and 100.
+     *
+     * @param[in] info     - Sensor object information
+     * @param[in] accuracy - The accuracy value for sensor readings
+     *
+     * @return - Shared pointer to the accuracy object
+     */
+    std::shared_ptr<AccuracyObject> addAccuracy(ObjectInfo& info,
+                                                double accuracy);
+
+    /**
      * @brief Get the scale from the sensor.
      *
      * @return - Scale value