diff options
| author | Patrick Venture <venture@google.com> | 2019-02-08 14:37:45 -0800 |
|---|---|---|
| committer | Patrick Venture <venture@google.com> | 2019-02-11 11:35:04 -0800 |
| commit | d1491724370970457a82db13f262ce84b017a82d (patch) | |
| tree | 91a30966dc3404b00de56f31641f7ed08f1c843d | |
| parent | 7280e27eff5bd0c4b16daa311f9d866fe488f790 (diff) | |
| download | phosphor-pid-control-d1491724370970457a82db13f262ce84b017a82d.tar.gz phosphor-pid-control-d1491724370970457a82db13f262ce84b017a82d.zip | |
add support to build zones and PIDs from json
Add support to build zones and PIDs from a json configuration file.
Change-Id: If8608dcd3e084cebabb71fc39851044df4d5d7c2
Signed-off-by: Patrick Venture <venture@google.com>
| -rw-r--r-- | Makefile.am | 1 | ||||
| -rw-r--r-- | pid/buildjson.cpp | 106 | ||||
| -rw-r--r-- | pid/buildjson.hpp | 18 | ||||
| -rw-r--r-- | test/Makefile.am | 5 | ||||
| -rw-r--r-- | test/pid_json_unittest.cpp | 68 |
5 files changed, 197 insertions, 1 deletions
diff --git a/Makefile.am b/Makefile.am index 09a52d5..cce4f4c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -73,6 +73,7 @@ libswampd_la_SOURCES = \ pid/stepwisecontroller.cpp \ pid/builder.cpp \ pid/builderconfig.cpp \ + pid/buildjson.cpp \ pid/zone.cpp \ pid/util.cpp \ pid/pidthread.cpp \ diff --git a/pid/buildjson.cpp b/pid/buildjson.cpp new file mode 100644 index 0000000..d89da92 --- /dev/null +++ b/pid/buildjson.cpp @@ -0,0 +1,106 @@ +/** + * Copyright 2019 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/buildjson.hpp" + +#include "conf.hpp" + +#include <map> +#include <nlohmann/json.hpp> +#include <tuple> + +using json = nlohmann::json; + +void from_json(const json& j, ControllerInfo& c) +{ + j.at("type").get_to(c.type); + j.at("inputs").get_to(c.inputs); + j.at("setpoint").get_to(c.setpoint); + + /* TODO: We need to handle parsing other PID controller configurations. + * We can do that by checking for different keys and making the decision + * accordingly. + */ + auto p = j.at("pid"); + p.at("samplePeriod").get_to(c.pidInfo.ts); + p.at("proportionalCoeff").get_to(c.pidInfo.proportionalCoeff); + p.at("integralCoeff").get_to(c.pidInfo.integralCoeff); + p.at("feedFwdOffOffsetCoeff").get_to(c.pidInfo.feedFwdOffset); + p.at("feedFwdGainCoeff").get_to(c.pidInfo.feedFwdGain); + p.at("integralLimit_min").get_to(c.pidInfo.integralLimit.min); + p.at("integralLimit_max").get_to(c.pidInfo.integralLimit.max); + p.at("outLim_min").get_to(c.pidInfo.outLim.min); + p.at("outLim_max").get_to(c.pidInfo.outLim.max); + p.at("slewNeg").get_to(c.pidInfo.slewNeg); + p.at("slewPos").get_to(c.pidInfo.slewPos); + + auto positiveHysteresis = p.find("positiveHysteresis"); + if (positiveHysteresis == p.end()) + { + c.pidInfo.positiveHysteresis = 0.0; + } + else + { + j.at("positiveHysteresis").get_to(c.pidInfo.positiveHysteresis); + } + + auto negativeHysteresis = p.find("negativeHysteresis"); + if (negativeHysteresis == p.end()) + { + c.pidInfo.negativeHysteresis = 0.0; + } + else + { + j.at("negativeHysteresis").get_to(c.pidInfo.negativeHysteresis); + } +} + +std::pair<std::map<int64_t, PIDConf>, std::map<int64_t, struct ZoneConfig>> + buildPIDsFromJson(const json& data) +{ + // zone -> pids + std::map<int64_t, PIDConf> pidConfig; + // zone -> configs + std::map<int64_t, struct ZoneConfig> zoneConfig; + + /* TODO: if zones is empty, that's invalid. */ + auto zones = data["zones"]; + for (const auto& zone : zones) + { + int64_t id; + PIDConf thisZone; + struct ZoneConfig thisZoneConfig; + + /* TODO: using at() throws a specific exception we can catch */ + id = zone["id"]; + thisZoneConfig.minThermalRpm = zone["minThermalRpm"]; + thisZoneConfig.failsafePercent = zone["failsafePercent"]; + + auto pids = zone["pids"]; + for (const auto& pid : pids) + { + auto name = pid["name"]; + auto item = pid.get<ControllerInfo>(); + + thisZone[name] = item; + } + + pidConfig[id] = thisZone; + zoneConfig[id] = thisZoneConfig; + } + + return std::make_pair(pidConfig, zoneConfig); +} diff --git a/pid/buildjson.hpp b/pid/buildjson.hpp new file mode 100644 index 0000000..626c982 --- /dev/null +++ b/pid/buildjson.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include "conf.hpp" + +#include <map> +#include <nlohmann/json.hpp> +#include <tuple> + +using json = nlohmann::json; + +/** + * Given the json "zones" data, create the map of PIDs and the map of zones. + * + * @param[in] data - the json data + * @return the pidConfig, and the zoneConfig + */ +std::pair<std::map<int64_t, PIDConf>, std::map<int64_t, struct ZoneConfig>> + buildPIDsFromJson(const json& data); diff --git a/test/Makefile.am b/test/Makefile.am index fb1d58d..5375eb4 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -18,7 +18,7 @@ check_PROGRAMS = sensor_manager_unittest sensor_pluggable_unittest \ pid_thermalcontroller_unittest pid_fancontroller_unittest \ pid_stepwisecontroller_unittest \ dbus_passive_unittest dbus_active_unittest \ - sensors_json_unittest + sensors_json_unittest pid_json_unittest TESTS = $(check_PROGRAMS) # Until libconfig is mocked out or replaced, include it. @@ -62,3 +62,6 @@ dbus_active_unittest_LDADD = $(top_builddir)/dbus/dbusactiveread.o sensors_json_unittest_SOURCES = sensors_json_unittest.cpp sensors_json_unittest_LDADD = $(top_builddir)/sensors/buildjson.o + +pid_json_unittest_SOURCES = pid_json_unittest.cpp +pid_json_unittest_LDADD = $(top_builddir)/pid/buildjson.o diff --git a/test/pid_json_unittest.cpp b/test/pid_json_unittest.cpp new file mode 100644 index 0000000..f0effbd --- /dev/null +++ b/test/pid_json_unittest.cpp @@ -0,0 +1,68 @@ +#include "pid/buildjson.hpp" + +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +TEST(ZoneFromJson, emptyZone) +{ + // There is a zone key, but it's empty. + // This is technically invalid. + + std::map<int64_t, PIDConf> pidConfig; + std::map<int64_t, struct ZoneConfig> zoneConfig; + + auto j2 = R"( + { + "zones": [] + } + )"_json; + + std::tie(pidConfig, zoneConfig) = buildPIDsFromJson(j2); + + EXPECT_TRUE(pidConfig.empty()); + EXPECT_TRUE(zoneConfig.empty()); +} + +TEST(ZoneFromJson, oneZoneOnePid) +{ + // Parse a valid configuration with one zone and one PID. + + std::map<int64_t, PIDConf> pidConfig; + std::map<int64_t, struct ZoneConfig> zoneConfig; + + auto j2 = R"( + { + "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 + } + }] + }] + } + )"_json; + + std::tie(pidConfig, zoneConfig) = buildPIDsFromJson(j2); + EXPECT_EQ(pidConfig.size(), 1); + EXPECT_EQ(zoneConfig.size(), 1); + + EXPECT_EQ(pidConfig[1]["fan1-5"].type, "fan"); + EXPECT_DOUBLE_EQ(zoneConfig[1].minThermalRpm, 3000.0); +} |

