control: Construct base zone group from JSON
Pulls together the profiles, zones, and fans JSON configurations to
construct a single zone group to be used as fan control's configuration.
This base zone group includes all that is necessary to get a basic fan
control configuration that will hold fans at the zone's given full
speed. A single zone group is created since the active state of any
configured profiles is checked while creating the zone group.
*Note that "profiles" in JSON configs replace what was called
"Conditions" in YAML based configs.
Tested:
Loaded profile based configurations
Loaded non-profile based configurations
Loaded combination of profile and non-profile based configurations
Change-Id: Id010c899a7633824b80c5cef21c848eadfb66243
Signed-off-by: Matthew Barth <msbarth@us.ibm.com>
diff --git a/control/json_parser.cpp b/control/json_parser.cpp
index 66c59e3..c074736 100644
--- a/control/json_parser.cpp
+++ b/control/json_parser.cpp
@@ -25,9 +25,39 @@
#include <sdbusplus/bus.hpp>
+#include <algorithm>
+#include <cstdlib>
+#include <tuple>
+#include <vector>
+
namespace phosphor::fan::control
{
+bool checkEntry(const std::vector<std::string>& activeProfiles,
+ const std::vector<std::string>& entryProfiles)
+{
+ // Include entry if its list of profiles to be included in is empty
+ if (entryProfiles.empty())
+ {
+ // Entry always to be included
+ return true;
+ }
+ else
+ {
+ for (const auto& profile : activeProfiles)
+ {
+ auto iter =
+ std::find(entryProfiles.begin(), entryProfiles.end(), profile);
+ if (iter != entryProfiles.end())
+ {
+ // Entry configured to be included in active profile
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
const std::vector<ZoneGroup> getZoneGroups(sdbusplus::bus::bus& bus)
{
std::vector<ZoneGroup> zoneGrps;
@@ -46,7 +76,68 @@
auto groups = getConfig<json::Group>(bus);
}
- // TODO Create zone groups after loading all JSON config files
+ // Ensure all configurations use the same set of active profiles
+ // (In case a profile's active state changes during configuration)
+ std::vector<std::string> activeProfiles;
+ for (const auto& profile : profiles)
+ {
+ if (profile.second->isActive())
+ {
+ activeProfiles.emplace_back(profile.first.first);
+ }
+ }
+
+ // Conditions list empty for JSON based configurations
+ // TODO Remove conditions after YAML based configuration removed
+ std::vector<Condition> conditions;
+ std::vector<ZoneDefinition> zoneDefs;
+ for (const auto& zone : zones)
+ {
+ // Check zone profiles against active profiles
+ if (checkEntry(activeProfiles, zone.second->getProfiles()))
+ {
+ auto zoneName = zone.second->getName();
+ // Create FanDefinition list for zone
+ std::vector<FanDefinition> fanDefs;
+ for (const auto& fan : fans)
+ {
+ // Check fan profiles against active profiles and
+ // if the fan is included in the zone
+ if (checkEntry(activeProfiles, fan.second->getProfiles()) &&
+ fan.second->getZone() == zoneName)
+ {
+ fanDefs.emplace_back(std::make_tuple(
+ fan.second->getName(), fan.second->getSensors(),
+ fan.second->getInterface()));
+ }
+ }
+
+ // Create SetSpeedEvents list for zone
+ std::vector<SetSpeedEvent> speedEvents;
+ // TODO Populate SetSpeedEvents list with configured events
+
+ // YAML zone name was an integer, JSON is a string
+ // Design direction is for it to be a string and this can be
+ // removed after YAML based configurations are removed.
+ char* zoneName_end;
+ auto zoneNum = std::strtol(zoneName.c_str(), &zoneName_end, 10);
+ if (*zoneName_end)
+ {
+ throw std::runtime_error(
+ "Zone names must be a string representation of a number");
+ }
+
+ zoneDefs.emplace_back(std::make_tuple(
+ zoneNum, zone.second->getFullSpeed(),
+ zone.second->getDefaultFloor(), zone.second->getIncDelay(),
+ zone.second->getDecInterval(), zone.second->getZoneHandlers(),
+ std::move(fanDefs), std::move(speedEvents)));
+ }
+ }
+ // TODO Should only result in a single entry but YAML based configurations
+ // produce a list of zone groups. Change to single zone group after YAML
+ // based configuartions are removed.
+ zoneGrps.emplace_back(std::make_tuple(conditions, zoneDefs));
return zoneGrps;
}
diff --git a/control/json_parser.hpp b/control/json_parser.hpp
index df9c680..7c08875 100644
--- a/control/json_parser.hpp
+++ b/control/json_parser.hpp
@@ -72,6 +72,28 @@
}
/**
+ * @brief Helper function to determine when a configuration entry is included
+ * based on the list of active profiles and its list of profiles
+ *
+ * A configuration entry may include a list of profiles that when any one of
+ * the profiles are active, the entry should be included. When the list of
+ * profiles for a configuration entry is empty, that results in always
+ * including the entry. An empty list of active profiles results in including
+ * only those entries configured without a list of profiles.
+ *
+ * i.e.) No profiles configured results in always being included, whereas
+ * providing a list of profiles on an entry results only in that entry being
+ * included when a profile in the list is active.
+ *
+ * @param[in] activeProfiles - List of active system profiles
+ * @param[in] entryProfiles - List of the configuration entry's profiles
+ *
+ * @return Whether the configuration entry should be included or not
+ */
+bool checkEntry(const std::vector<std::string>& activeProfiles,
+ const std::vector<std::string>& entryProfiles);
+
+/**
* @brief Get the configuration definitions for zone groups
*
* @param[in] bus - The dbus bus object
diff --git a/control/manager.cpp b/control/manager.cpp
index ff8afef..bdea542 100644
--- a/control/manager.cpp
+++ b/control/manager.cpp
@@ -92,13 +92,21 @@
// Create the appropriate Zone objects based on the
// actual system configuration.
#ifdef CONTROL_USE_JSON
- auto zoneLayouts = getZoneGroups(bus);
+ for (auto& group : getZoneGroups(bus))
+ {
+ // Create a Zone object for each zone in the group
+ for (auto& z : std::get<zoneListPos>(group))
+ {
+ fs::path path{CONTROL_OBJPATH};
+ path /= std::to_string(std::get<zoneNumPos>(z));
+ _zones.emplace(
+ std::get<zoneNumPos>(z),
+ std::make_unique<Zone>(mode, _bus, path.string(), event, z));
+ }
+ }
#else
- auto zoneLayouts = _zoneLayouts;
-#endif
-
// Find the 1 ZoneGroup that meets all of its conditions
- for (auto& group : zoneLayouts)
+ for (auto& group : _zoneLayouts)
{
auto& conditions = std::get<conditionListPos>(group);
@@ -122,6 +130,7 @@
break;
}
}
+#endif
if (mode == Mode::control)
{