swap libconfig++ for json in configuration parsing

Parse the configuration file as json and not libconfig++.

Change-Id: Ic3e71cc810195387617b545566cf757c61c71942
Signed-off-by: Patrick Venture <venture@google.com>
diff --git a/Makefile.am b/Makefile.am
index c227281..0484a89 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -39,7 +39,6 @@
 libswampd_la_LDFLAGS = -static
 libswampd_la_LIBADD = \
 	-lstdc++fs \
-	-lconfig++ \
 	$(SDBUSPLUS_LIBS) \
 	$(PHOSPHOR_DBUS_INTERFACES_LIBS) \
 	$(PHOSPHOR_LOGGING_LIBS)
@@ -62,7 +61,6 @@
 	sensors/pluggable.cpp \
 	sensors/host.cpp \
 	sensors/builder.cpp \
-	sensors/builderconfig.cpp \
 	sensors/buildjson.cpp \
 	sensors/manager.cpp \
 	pid/ec/pid.cpp \
@@ -72,7 +70,6 @@
 	pid/pidcontroller.cpp \
 	pid/stepwisecontroller.cpp \
 	pid/builder.cpp \
-	pid/builderconfig.cpp \
 	pid/buildjson.cpp \
 	pid/zone.cpp \
 	pid/util.cpp \
diff --git a/configure.ac b/configure.ac
index ca42e3e..8a2db08 100644
--- a/configure.ac
+++ b/configure.ac
@@ -45,12 +45,6 @@
     [],
     [AC_MSG_ERROR(["phosphor-dbus-interfaces required and not found."])]
 )
-PKG_CHECK_MODULES(
-    [LIBCONFIGXX],
-    [libconfig++ >= 1.5],
-    [],
-    [AC_MSG_ERROR([libconfig++ 1.5 or newer not found.])]
-)
 AC_CHECK_HEADER(
     [host-ipmid],
     [AC_MSG_ERROR(["phosphor-host-ipmid required and not found."])]
diff --git a/examples/fan-info.json b/examples/fan-info.json
new file mode 100644
index 0000000..45afe3f
--- /dev/null
+++ b/examples/fan-info.json
@@ -0,0 +1,166 @@
+{
+    "sensors" : [
+        {
+            "name": "fan1",
+            "type": "fan",
+            "readPath": "/xyz/openbmc_project/sensors/fan_tach/fan1",
+            "writePath": "/sys/devices/platform/ahb/ahb:apb/1e786000.pwm-tacho-controller/hwmon/**/pwm1",
+            "min": 0,
+            "max": 255
+        },
+        {
+            "name": "fan2",
+            "type": "fan",
+            "readPath": "/xyz/openbmc_project/sensors/fan_tach/fan2",
+            "writePath": "/sys/devices/platform/ahb/ahb:apb/1e786000.pwm-tacho-controller/hwmon/**/pwm2",
+            "min": 0,
+            "max": 255
+        },
+        {
+            "name": "fan3",
+            "type": "fan",
+            "readPath": "/xyz/openbmc_project/sensors/fan_tach/fan3",
+            "writePath": "/sys/devices/platform/ahb/ahb:apb/1e786000.pwm-tacho-controller/hwmon/**/pwm3",
+            "min": 0,
+            "max": 255
+        },
+        {
+            "name": "fan4",
+            "type": "fan",
+            "readPath": "/xyz/openbmc_project/sensors/fan_tach/fan4",
+            "writePath": "/sys/devices/platform/ahb/ahb:apb/1e786000.pwm-tacho-controller/hwmon/**/pwm4",
+            "min": 0,
+            "max": 255
+        },
+        {
+            "name": "fan5",
+            "type": "fan",
+            "readPath": "/xyz/openbmc_project/sensors/fan_tach/fan5"
+        },
+        {
+            "name": "fan6",
+            "type": "fan",
+            "readPath": "/xyz/openbmc_project/sensors/fan_tach/fan6"
+        },
+        {
+            "name": "fan7",
+            "type": "fan",
+            "readPath": "/xyz/openbmc_project/sensors/fan_tach/fan7"
+        },
+        {
+            "name": "fan8",
+            "type": "fan",
+            "readPath": "/xyz/openbmc_project/sensors/fan_tach/fan8"
+        },
+        {
+            "name": "fleeting0",
+            "type": "margin",
+            "readPath": "/xyz/openbmc_project/extsensors/margin/fleeting0",
+            "timeout": 4
+        }
+    ],
+    "zones" : [
+        {
+            "id": 1,
+            "minThermalRpm": 3000.0,
+            "failsafePercent": 75.0,
+            "pids": [
+                {
+                    "name": "fan1-5",
+                    "type": "fan",
+                    "inputs": ["fan1", "fan5"],
+                    "setpoint": 90.0,
+                    "pid": {
+                        "sampleperiod": 0.1,
+                        "proportionalCoeff": 0.0,
+                        "integralCoeff": 0.0,
+                        "feedFwdOffOffsetCoeff": 0.0,
+                        "feedFwdGainCoeff": 0.010,
+                        "integralLimit_min": 0.0,
+                        "integralLimit_max": 0.0,
+                        "outLim_min": 30.0,
+                        "outLim_max": 100.0,
+                        "slewNeg": 0.0,
+                        "slewPos": 0.0
+                    }
+                },
+                {
+                    "name": "fan2-6",
+                    "type": "fan",
+                    "inputs": ["fan2", "fan6"],
+                    "setpoint": 90.0,
+                    "pid": {
+                        "sampleperiod": 0.1,
+                        "proportionalCoeff": 0.0,
+                        "integralCoeff": 0.0,
+                        "feedFwdOffOffsetCoeff": 0.0,
+                        "feedFwdGainCoeff": 0.010,
+                        "integralLimit_min": 0.0,
+                        "integralLimit_max": 0.0,
+                        "outLim_min": 30.0,
+                        "outLim_max": 100.0,
+                        "slewNeg": 0.0,
+                        "slewPos": 0.0
+                    }
+                },
+                {
+                    "name": "fan3-7",
+                    "type": "fan",
+                    "inputs": ["fan3", "fan7"],
+                    "setpoint": 90.0,
+                    "pid": {
+                        "sampleperiod": 0.1,
+                        "proportionalCoeff": 0.0,
+                        "integralCoeff": 0.0,
+                        "feedFwdOffOffsetCoeff": 0.0,
+                        "feedFwdGainCoeff": 0.010,
+                        "integralLimit_min": 0.0,
+                        "integralLimit_max": 0.0,
+                        "outLim_min": 30.0,
+                        "outLim_max": 100.0,
+                        "slewNeg": 0.0,
+                        "slewPos": 0.0
+                    }
+                },
+                {
+                    "name": "fan4-8",
+                    "type": "fan",
+                    "inputs": ["fan4", "fan8"],
+                    "setpoint": 90.0,
+                    "pid": {
+                        "sampleperiod": 0.1,
+                        "proportionalCoeff": 0.0,
+                        "integralCoeff": 0.0,
+                        "feedFwdOffOffsetCoeff": 0.0,
+                        "feedFwdGainCoeff": 0.010,
+                        "integralLimit_min": 0.0,
+                        "integralLimit_max": 0.0,
+                        "outLim_min": 30.0,
+                        "outLim_max": 100.0,
+                        "slewNeg": 0.0,
+                        "slewPos": 0.0
+                    }
+                },
+                {
+                    "name": "fleetingpid0",
+                    "type": "margin",
+                    "inputs": ["fleeting0"],
+                    "setpoint": 10,
+                    "pid": {
+                        "sampleperiod": 1,
+                        "proportionalCoeff": 750.0,
+                        "integralCoeff": 16.0,
+                        "feedFwdOffOffsetCoeff": 0.0,
+                        "feedFwdGainCoeff": 0.0,
+                        "integralLimit_min": 3000,
+                        "integralLimit_max": 10000,
+                        "outLim_min": 3000,
+                        "outLim_max": 10000,
+                        "slewNeg": -100.0,
+                        "slewPos": 0.0
+                    }
+                }
+            ]
+        }
+    ]
+}
diff --git a/examples/swampd.conf b/examples/swampd.conf
deleted file mode 100644
index d1aeebb..0000000
--- a/examples/swampd.conf
+++ /dev/null
@@ -1,97 +0,0 @@
-
-sensors = (
-  { name = "fan1"
-    type = "fan"
-    readPath = "/xyz/openbmc_project/sensors/fan_tach/fan1"
-    writePath = "/sys/class/hwmon/hwmon0/pwm0"
-    min = 0
-  { name = "fan2"
-    type = "fan"
-    readPath = "/xyz/openbmc_project/sensors/fan_tach/fan2"
-    writePath = "/sys/class/hwmon/hwmon0/pwm1"
-    min = 0
-    max = 255
-    timeout = 0 },
-  { name = "fan3"
-    type = "fan"
-    readPath = "/xyz/openbmc_project/sensors/fan_tach/fan3"
-    writePath = "/sys/class/hwmon/hwmon0/pwm2"
-    min = 0
-    max = 255
-    timeout = 0 },
-  { name = "fan4"
-    type = "fan"
-    readPath = "/xyz/openbmc_project/sensors/fan_tach/fan4"
-    writePath = "/sys/class/hwmon/hwmon0/pwm3"
-    min = 0
-    max = 255
-    timeout = 0 },
-  { name = "fan5"
-    type = "fan"
-    readPath = "/xyz/openbmc_project/sensors/fan_tach/fan5"
-    writePath = ""
-    min = 0
-    max = 0
-    timeout = 0 },
-  { name = "fan6"
-    type = "fan"
-    readPath = "/xyz/openbmc_project/sensors/fan_tach/fan6"
-    writePath = ""
-    min = 0
-    max = 0
-    timeout = 0 },
-  { name = "fan7"
-    type = "fan"
-    readPath = "/xyz/openbmc_project/sensors/fan_tach/fan7"
-    writePath = ""
-    min = 0
-    max = 0
-    timeout = 0 },
-  { name = "fan8"
-    type = "fan"
-    readPath = "/xyz/openbmc_project/sensors/fan_tach/fan8"
-    writePath = ""
-    min = 0
-    max = 0
-    timeout = 0 }
-);
-
-zones = (
-  { id = 0x01
-    minThermalRpm = 3000.0
-    failsafepwm = 90.0
-    pids = (
-      { name = "allfans"
-        type = "fan"
-        inputs = (
-          "fan1",
-          "fan2",
-          "fan3",
-          "fan4",
-          "fan5",
-          "fan6",
-          "fan7",
-          "fan8"
-        )
-        setpoint = 90.0
-        pid = {
-          samplePeriod = 0.1
-          proportionalCoeff = 0.01
-          integralCoeff = 0.001
-          feedFwdOffOffsetCoeff = 0.0
-          feedFwdGainCoeff = 0.0
-          integralCoeff = {
-            min: 0.0
-            max: 100.0
-          }
-          outLimit = {
-            min: 0.0
-            max: 100.0
-          }
-          slewNeg = 0.0
-          slewPos = 0.0
-        }
-      }
-    )
-  }
-);
diff --git a/main.cpp b/main.cpp
index 5289101..4ff67c5 100644
--- a/main.cpp
+++ b/main.cpp
@@ -16,14 +16,15 @@
 
 #include "config.h"
 
+#include "build/buildjson.hpp"
 #include "conf.hpp"
 #include "interfaces.hpp"
 #include "pid/builder.hpp"
-#include "pid/builderconfig.hpp"
+#include "pid/buildjson.hpp"
 #include "pid/pidthread.hpp"
 #include "pid/zone.hpp"
 #include "sensors/builder.hpp"
-#include "sensors/builderconfig.hpp"
+#include "sensors/buildjson.hpp"
 #include "sensors/manager.hpp"
 #include "threads/busthread.hpp"
 #include "util.hpp"
@@ -37,6 +38,7 @@
 #include <sdbusplus/bus.hpp>
 #include <thread>
 #include <unordered_map>
+#include <utility>
 #include <vector>
 
 #if CONFIGURE_DBUS
@@ -104,8 +106,14 @@
     {
         try
         {
-            mgmr = buildSensorsFromConfig(configPath);
-            zones = buildZonesFromConfig(configPath, mgmr, modeControlBus);
+            auto jsonData = parseValidateJson(configPath);
+            mgmr = buildSensors(buildSensorsFromJson(jsonData));
+
+            std::map<int64_t, PIDConf> pidConfig;
+            std::map<int64_t, struct ZoneConfig> zoneConfig;
+            std::tie(pidConfig, zoneConfig) = buildPIDsFromJson(jsonData);
+
+            zones = buildZones(pidConfig, zoneConfig, mgmr, modeControlBus);
         }
         catch (const std::exception& e)
         {
diff --git a/pid/builderconfig.cpp b/pid/builderconfig.cpp
deleted file mode 100644
index ad62c85..0000000
--- a/pid/builderconfig.cpp
+++ /dev/null
@@ -1,155 +0,0 @@
-/**
- * Copyright 2017 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "pid/builderconfig.hpp"
-
-#include "conf.hpp"
-#include "pid/builder.hpp"
-
-#include <fstream>
-#include <iostream>
-#include <libconfig.h++>
-#include <memory>
-#include <sdbusplus/bus.hpp>
-#include <string>
-#include <unordered_map>
-
-std::unordered_map<int64_t, std::unique_ptr<PIDZone>>
-    buildZonesFromConfig(const std::string& path, SensorManager& mgr,
-                         sdbusplus::bus::bus& modeControlBus)
-{
-    using namespace libconfig;
-    // zone -> pids
-    std::map<int64_t, PIDConf> pidConfig;
-    // zone -> configs
-    std::map<int64_t, struct ZoneConfig> zoneConfig;
-
-    std::cerr << "entered BuildZonesFromConfig\n";
-
-    Config cfg;
-
-    /* The load was modeled after the example source provided. */
-    try
-    {
-        cfg.readFile(path.c_str());
-    }
-    catch (const FileIOException& fioex)
-    {
-        std::cerr << "I/O error while reading file: " << fioex.what()
-                  << std::endl;
-        throw;
-    }
-    catch (const ParseException& pex)
-    {
-        std::cerr << "Parse error at " << pex.getFile() << ":" << pex.getLine()
-                  << " - " << pex.getError() << std::endl;
-        throw;
-    }
-
-    try
-    {
-        const Setting& root = cfg.getRoot();
-        const Setting& zones = root["zones"];
-        int count = zones.getLength();
-
-        /* For each zone. */
-        for (int i = 0; i < count; ++i)
-        {
-            const Setting& zoneSettings = zones[i];
-
-            int id;
-            PIDConf thisZone;
-            struct ZoneConfig thisZoneConfig;
-
-            zoneSettings.lookupValue("id", id);
-
-            thisZoneConfig.minThermalRpm = zoneSettings.lookup("minThermalRpm");
-            thisZoneConfig.failsafePercent =
-                zoneSettings.lookup("failsafePercent");
-
-            const Setting& pids = zoneSettings["pids"];
-            int pidCount = pids.getLength();
-
-            for (int j = 0; j < pidCount; ++j)
-            {
-                const Setting& pid = pids[j];
-
-                std::string name;
-                struct ControllerInfo info;
-
-                /*
-                 * Mysteriously if you use lookupValue on these, and the type
-                 * is double.  It won't work right.
-                 *
-                 * If the configuration file value doesn't look explicitly like
-                 * a double it won't let you assign it to one.
-                 */
-                name = pid.lookup("name").c_str();
-                info.type = pid.lookup("type").c_str();
-                /* setpoint is only required to be set for thermal. */
-                /* TODO(venture): Verify this works optionally here. */
-                info.setpoint = pid.lookup("setpoint");
-                info.pidInfo.ts = pid.lookup("pid.samplePeriod");
-                info.pidInfo.proportionalCoeff =
-                    pid.lookup("pid.proportionalCoeff");
-                info.pidInfo.integralCoeff = pid.lookup("pid.integralCoeff");
-                info.pidInfo.feedFwdOffset =
-                    pid.lookup("pid.feedFwdOffOffsetCoeff");
-                info.pidInfo.feedFwdGain = pid.lookup("pid.feedFwdGainCoeff");
-                info.pidInfo.integralLimit.min =
-                    pid.lookup("pid.integralCoeff.min");
-                info.pidInfo.integralLimit.max =
-                    pid.lookup("pid.integralCoeff.max");
-                info.pidInfo.outLim.min = pid.lookup("pid.outLimit.min");
-                info.pidInfo.outLim.max = pid.lookup("pid.outLimit.max");
-                info.pidInfo.slewNeg = pid.lookup("pid.slewNeg");
-                info.pidInfo.slewPos = pid.lookup("pid.slewPos");
-
-                std::cerr << "outLim.min: " << info.pidInfo.outLim.min << "\n";
-                std::cerr << "outLim.max: " << info.pidInfo.outLim.max << "\n";
-
-                const Setting& inputs = pid["inputs"];
-                int icount = inputs.getLength();
-
-                for (int z = 0; z < icount; ++z)
-                {
-                    std::string v;
-                    v = pid["inputs"][z].c_str();
-                    info.inputs.push_back(v);
-                }
-
-                thisZone[name] = info;
-            }
-
-            pidConfig[static_cast<int64_t>(id)] = thisZone;
-            zoneConfig[static_cast<int64_t>(id)] = thisZoneConfig;
-        }
-    }
-    catch (const SettingTypeException& setex)
-    {
-        std::cerr << "Setting '" << setex.getPath() << "' type exception!"
-                  << std::endl;
-        throw;
-    }
-    catch (const SettingNotFoundException& snex)
-    {
-        std::cerr << "Setting '" << snex.getPath() << "' not found!"
-                  << std::endl;
-        throw;
-    }
-
-    return buildZones(pidConfig, zoneConfig, mgr, modeControlBus);
-}
diff --git a/pid/builderconfig.hpp b/pid/builderconfig.hpp
deleted file mode 100644
index 8390bee..0000000
--- a/pid/builderconfig.hpp
+++ /dev/null
@@ -1,13 +0,0 @@
-#pragma once
-
-#include "pid/zone.hpp"
-#include "sensors/manager.hpp"
-
-#include <memory>
-#include <sdbusplus/bus.hpp>
-#include <string>
-#include <unordered_map>
-
-std::unordered_map<int64_t, std::unique_ptr<PIDZone>>
-    buildZonesFromConfig(const std::string& path, SensorManager& mgr,
-                         sdbusplus::bus::bus& modeControlBus);
diff --git a/pid/zone.cpp b/pid/zone.cpp
index b6bdba0..4892409 100644
--- a/pid/zone.cpp
+++ b/pid/zone.cpp
@@ -29,7 +29,6 @@
 #include <cstring>
 #include <fstream>
 #include <iostream>
-#include <libconfig.h++>
 #include <memory>
 
 using tstamp = std::chrono::high_resolution_clock::time_point;
diff --git a/sensors/builderconfig.cpp b/sensors/builderconfig.cpp
deleted file mode 100644
index 5aa18bc..0000000
--- a/sensors/builderconfig.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-/**
- * Copyright 2017 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <iostream>
-#include <libconfig.h++>
-#include <string>
-#include <unordered_map>
-
-/* Configuration. */
-#include "conf.hpp"
-#include "sensors/builder.hpp"
-#include "sensors/manager.hpp"
-
-/*
- * If there's a configuration file, we build from that, and it requires special
- * parsing.  I should just ditch the compile-time version to reduce the
- * probability of sync bugs.
- */
-SensorManager buildSensorsFromConfig(const std::string& path)
-{
-    using namespace libconfig;
-
-    std::map<std::string, struct SensorConfig> config;
-    Config cfg;
-
-    std::cerr << "entered BuildSensorsFromConfig\n";
-
-    /* The load was modeled after the example source provided. */
-    try
-    {
-        cfg.readFile(path.c_str());
-    }
-    catch (const FileIOException& fioex)
-    {
-        std::cerr << "I/O error while reading file: " << fioex.what()
-                  << std::endl;
-        throw;
-    }
-    catch (const ParseException& pex)
-    {
-        std::cerr << "Parse error at " << pex.getFile() << ":" << pex.getLine()
-                  << " - " << pex.getError() << std::endl;
-        throw;
-    }
-
-    try
-    {
-        const Setting& root = cfg.getRoot();
-
-        /* Grab the list of sensors and create them all */
-        const Setting& sensors = root["sensors"];
-        int count = sensors.getLength();
-
-        for (int i = 0; i < count; ++i)
-        {
-            const Setting& sensor = sensors[i];
-
-            std::string name;
-            struct SensorConfig thisOne;
-
-            /* Not a super fan of using this library for run-time configuration.
-             */
-            name = sensor.lookup("name").c_str();
-            thisOne.type = sensor.lookup("type").c_str();
-            thisOne.readPath = sensor.lookup("readPath").c_str();
-            thisOne.writePath = sensor.lookup("writePath").c_str();
-
-            /* TODO: Document why this is wonky.  The library probably doesn't
-             * like int64_t
-             */
-            int min = sensor.lookup("min");
-            thisOne.min = static_cast<int64_t>(min);
-            int max = sensor.lookup("max");
-            thisOne.max = static_cast<int64_t>(max);
-            int timeout = sensor.lookup("timeout");
-            thisOne.timeout = static_cast<int64_t>(timeout);
-
-            // leaving for verification for now.  and yea the above is
-            // necessary.
-            std::cerr << "min: " << min << " max: " << max
-                      << " savedmin: " << thisOne.min
-                      << " savedmax: " << thisOne.max
-                      << " timeout: " << thisOne.timeout << std::endl;
-
-            config[name] = thisOne;
-        }
-    }
-    catch (const SettingTypeException& setex)
-    {
-        std::cerr << "Setting '" << setex.getPath() << "' type exception!"
-                  << std::endl;
-        throw;
-    }
-    catch (const SettingNotFoundException& snex)
-    {
-        std::cerr << "Setting not found!" << std::endl;
-        throw;
-    }
-
-    return buildSensors(config);
-}
diff --git a/sensors/builderconfig.hpp b/sensors/builderconfig.hpp
deleted file mode 100644
index da5306f..0000000
--- a/sensors/builderconfig.hpp
+++ /dev/null
@@ -1,11 +0,0 @@
-#pragma once
-
-#include "sensors/manager.hpp"
-
-#include <string>
-
-/**
- * Given a configuration file, parsable by libconfig++, parse it and then pass
- * the information onto BuildSensors.
- */
-SensorManager buildSensorsFromConfig(const std::string& path);