control: JSON parsing compile framework

Add the enabling framework of use of JSON config files for fan control.

Tested:
    Compile passes when `--enable-json` configure flag given
    Compile passes without enabling JSON
    No functional change when not using JSON

Change-Id: Ic70bfc63ad74cb79559ed839784cd214df403cb2
Signed-off-by: Matthew Barth <msbarth@us.ibm.com>
diff --git a/configure.ac b/configure.ac
index 89221ad..fd6284f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -110,61 +110,72 @@
 ])
 
 AS_IF([test "x$enable_control" != "xno"], [
-       # Add fan control Dbus attributes
-       AC_ARG_VAR(CONTROL_BUSNAME, [The fan control busname to own])
-       AS_IF([test "x$CONTROL_BUSNAME" == "x"],
-             [CONTROL_BUSNAME="xyz.openbmc_project.Control.Thermal"])
-       AC_DEFINE_UNQUOTED([CONTROL_BUSNAME], ["$CONTROL_BUSNAME"],
-                          [The fan control busname to own])
+    # Add fan control Dbus attributes
+    AC_ARG_VAR(CONTROL_BUSNAME, [The fan control busname to own])
+    AS_IF([test "x$CONTROL_BUSNAME" == "x"],
+          [CONTROL_BUSNAME="xyz.openbmc_project.Control.Thermal"])
+    AC_DEFINE_UNQUOTED([CONTROL_BUSNAME], ["$CONTROL_BUSNAME"],
+                       [The fan control busname to own])
 
-       AC_ARG_VAR(CONTROL_OBJPATH, [The fan control root object path])
-       AS_IF([test "x$CONTROL_OBJPATH" == "x"],
-             [CONTROL_OBJPATH="/xyz/openbmc_project/control/thermal"])
-       AC_DEFINE_UNQUOTED([CONTROL_OBJPATH], ["$CONTROL_OBJPATH"],
-                          [The fan control root object path])
+    AC_ARG_VAR(CONTROL_OBJPATH, [The fan control root object path])
+    AS_IF([test "x$CONTROL_OBJPATH" == "x"],
+          [CONTROL_OBJPATH="/xyz/openbmc_project/control/thermal"])
+    AC_DEFINE_UNQUOTED([CONTROL_OBJPATH], ["$CONTROL_OBJPATH"],
+                       [The fan control root object path])
 
-       AC_ARG_VAR(CONTROL_PERSIST_ROOT_PATH, [Root path for persisting zone property states])
-       AS_IF([test "x$CONTROL_PERSIST_ROOT_PATH" == "x"],
-             [CONTROL_PERSIST_ROOT_PATH="/var/lib/phosphor-fan-presence/control"])
-       AC_DEFINE_UNQUOTED([CONTROL_PERSIST_ROOT_PATH], ["$CONTROL_PERSIST_ROOT_PATH"],
-                          [Root path for persisting zone property states])
+    AC_ARG_VAR(CONTROL_PERSIST_ROOT_PATH, [Root path for persisting zone property states])
+    AS_IF([test "x$CONTROL_PERSIST_ROOT_PATH" == "x"],
+          [CONTROL_PERSIST_ROOT_PATH="/var/lib/phosphor-fan-presence/control"])
+    AC_DEFINE_UNQUOTED([CONTROL_PERSIST_ROOT_PATH], ["$CONTROL_PERSIST_ROOT_PATH"],
+                       [Root path for persisting zone property states])
 
-       # Add optional yaml file arguments
-       AC_ARG_VAR(FAN_DEF_YAML_FILE,
-                  [The fan definition file to use])
-       AS_IF([test "x$FAN_DEF_YAML_FILE" == "x"],
-             [FAN_DEF_YAML_FILE="\${top_srcdir}/control/example/fans.yaml"])
-       AC_DEFINE_UNQUOTED([FAN_DEF_YAML_FILE], ["$FAN_DEF_YAML_FILE"],
-                          [The fan definition file to use])
+    # Use runtime(json) config, otherwise default to compile time(yaml) config
+    AM_COND_IF([WANT_JSON],
+    [
+        AC_CHECK_HEADER(nlohmann/json.hpp, ,
+                [AC_MSG_ERROR([Could not find nlohmann/json.hpp... nlohmann/json package required])])
+        # Set config flag for runtime json usage
+        AC_DEFINE([CONTROL_USE_JSON], [1], [Fan control use runtime json configuration])
+        AC_MSG_NOTICE([Fan control json configuration usage enabled])
+    ],
+    [
+        # Add optional yaml file arguments
+        AC_ARG_VAR(FAN_DEF_YAML_FILE,
+                   [The fan definition file to use])
+        AS_IF([test "x$FAN_DEF_YAML_FILE" == "x"],
+              [FAN_DEF_YAML_FILE="\${top_srcdir}/control/example/fans.yaml"])
+        AC_DEFINE_UNQUOTED([FAN_DEF_YAML_FILE], ["$FAN_DEF_YAML_FILE"],
+                           [The fan definition file to use])
 
-       AC_ARG_VAR(FAN_ZONE_YAML_FILE,
-                  [The fan zone definition file to use])
-       AS_IF([test "x$FAN_ZONE_YAML_FILE" == "x"],
-             [FAN_ZONE_YAML_FILE="\${top_srcdir}/control/example/zones.yaml"])
-       AC_DEFINE_UNQUOTED([FAN_ZONE_YAML_FILE], ["$FAN_ZONE_YAML_FILE"],
-                          [The fan zone definition file to use])
+        AC_ARG_VAR(FAN_ZONE_YAML_FILE,
+                   [The fan zone definition file to use])
+        AS_IF([test "x$FAN_ZONE_YAML_FILE" == "x"],
+              [FAN_ZONE_YAML_FILE="\${top_srcdir}/control/example/zones.yaml"])
+        AC_DEFINE_UNQUOTED([FAN_ZONE_YAML_FILE], ["$FAN_ZONE_YAML_FILE"],
+                           [The fan zone definition file to use])
 
-      AC_ARG_VAR(ZONE_EVENTS_YAML_FILE,
-                 [The zone events definition file to use])
-      AS_IF([test "x$ZONE_EVENTS_YAML_FILE" == "x"],
-             [ZONE_EVENTS_YAML_FILE="\${top_srcdir}/control/example/events.yaml"])
-      AC_DEFINE_UNQUOTED([ZONE_EVENTS_YAML_FILE], ["$ZONE_EVENTS_YAML_FILE"],
-                         [The zone events definition file to use])
+        AC_ARG_VAR(ZONE_EVENTS_YAML_FILE,
+                   [The zone events definition file to use])
+        AS_IF([test "x$ZONE_EVENTS_YAML_FILE" == "x"],
+              [ZONE_EVENTS_YAML_FILE="\${top_srcdir}/control/example/events.yaml"])
+        AC_DEFINE_UNQUOTED([ZONE_EVENTS_YAML_FILE], ["$ZONE_EVENTS_YAML_FILE"],
+                           [The zone events definition file to use])
 
-      AC_ARG_VAR(ZONE_CONDITIONS_YAML_FILE,
-                 [The zone conditions definition file to use])
-      AS_IF([test "x$ZONE_CONDITIONS_YAML_FILE" == "x"],
-             [ZONE_CONDITIONS_YAML_FILE="\${top_srcdir}/control/example/zone_conditions.yaml"])
-      AC_DEFINE_UNQUOTED([ZONE_CONDITIONS_YAML_FILE], ["$ZONE_CONDITIONS_YAML_FILE"],
-                         [The zone conditions definition file to use])
+        AC_ARG_VAR(ZONE_CONDITIONS_YAML_FILE,
+                   [The zone conditions definition file to use])
+        AS_IF([test "x$ZONE_CONDITIONS_YAML_FILE" == "x"],
+              [ZONE_CONDITIONS_YAML_FILE="\${top_srcdir}/control/example/zone_conditions.yaml"])
+        AC_DEFINE_UNQUOTED([ZONE_CONDITIONS_YAML_FILE], ["$ZONE_CONDITIONS_YAML_FILE"],
+                           [The zone conditions definition file to use])
 
-      AC_SUBST([GEN_FAN_ZONE_DEFS],
-               ["$PYTHON \${top_srcdir}/control/gen-fan-zone-defs.py \
-                         -f $FAN_DEF_YAML_FILE \
-                         -z $FAN_ZONE_YAML_FILE \
-                         -e $ZONE_EVENTS_YAML_FILE \
-                         -c $ZONE_CONDITIONS_YAML_FILE"])
-      AC_CONFIG_FILES([control/Makefile])
+        AC_SUBST([GEN_FAN_ZONE_DEFS],
+                 ["$PYTHON \${top_srcdir}/control/gen-fan-zone-defs.py \
+                      -f $FAN_DEF_YAML_FILE \
+                      -z $FAN_ZONE_YAML_FILE \
+                      -e $ZONE_EVENTS_YAML_FILE \
+                      -c $ZONE_CONDITIONS_YAML_FILE"])
+    ])
+    AC_CONFIG_FILES([control/Makefile])
 ])
 
 AS_IF([test "x$enable_cooling_type" != "xno"], [
diff --git a/control/Makefile.am b/control/Makefile.am
index 8812b58..3ce3617 100644
--- a/control/Makefile.am
+++ b/control/Makefile.am
@@ -15,9 +15,6 @@
 	triggers.cpp \
 	zone.cpp
 
-nodist_phosphor_fan_control_SOURCES = \
-	fan_zone_defs.cpp
-
 phosphor_fan_control_LDADD = \
 	-lstdc++fs \
 	$(SDBUSPLUS_LIBS) \
@@ -33,7 +30,13 @@
 	${PHOSPHOR_DBUS_INTERFACES_CFLAGS} \
 	-flto
 
+if WANT_JSON
+phosphor_fan_control_SOURCES += json_parser.cpp
+else
 BUILT_SOURCES = fan_zone_defs.cpp
+nodist_phosphor_fan_control_SOURCES = \
+	fan_zone_defs.cpp
 
 fan_zone_defs.cpp: ${srcdir}/gen-fan-zone-defs.py
 	$(AM_V_GEN)$(GEN_FAN_ZONE_DEFS) > ${builddir}/$@
+endif
diff --git a/control/json_parser.cpp b/control/json_parser.cpp
new file mode 100644
index 0000000..2f5ddae
--- /dev/null
+++ b/control/json_parser.cpp
@@ -0,0 +1,19 @@
+/**
+ * Copyright © 2020 IBM Corporation
+ *
+ * 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 "json_parser.hpp"
+
+namespace phosphor::fan::control
+{} // namespace phosphor::fan::control
diff --git a/control/json_parser.hpp b/control/json_parser.hpp
new file mode 100644
index 0000000..eea2564
--- /dev/null
+++ b/control/json_parser.hpp
@@ -0,0 +1,19 @@
+/**
+ * Copyright © 2020 IBM Corporation
+ *
+ * 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.
+ */
+#pragma once
+
+namespace phosphor::fan::control
+{} // namespace phosphor::fan::control
diff --git a/control/manager.cpp b/control/manager.cpp
index 543d42f..d202fea 100644
--- a/control/manager.cpp
+++ b/control/manager.cpp
@@ -90,6 +90,7 @@
     // actual system configuration.
 
     // Find the 1 ZoneGroup that meets all of its conditions
+#ifndef CONTROL_USE_JSON
     for (auto& group : _zoneLayouts)
     {
         auto& conditions = std::get<conditionListPos>(group);
@@ -114,6 +115,7 @@
             break;
         }
     }
+#endif
 
     if (mode == Mode::control)
     {
@@ -127,13 +129,13 @@
     {
         z.second->setFullSpeed();
     }
-
+#ifndef CONTROL_USE_JSON
     auto delay = _powerOnDelay;
     while (delay > 0)
     {
         delay = sleep(delay);
     }
-
+#endif
     util::SDBusPlus::callMethod(_bus, SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
                                 SYSTEMD_INTERFACE, "StartUnit",
                                 FAN_CONTROL_READY_TARGET, "replace");
diff --git a/control/manager.hpp b/control/manager.hpp
index 34ae0b9..a2e44f5 100644
--- a/control/manager.hpp
+++ b/control/manager.hpp
@@ -1,5 +1,7 @@
 #pragma once
 
+#include "config.h"
+
 #include "types.hpp"
 #include "zone.hpp"
 
@@ -65,7 +67,7 @@
      * The fan zones in the system
      */
     ZoneMap _zones;
-
+#ifndef CONTROL_USE_JSON
     /**
      * The fan zone layout for the system.
      * This is generated data.
@@ -78,6 +80,7 @@
      * to give them a chance to get there.
      */
     static const unsigned int _powerOnDelay;
+#endif
 };
 
 } // namespace control