1d1491724SPatrick Venture /**
2d1491724SPatrick Venture * Copyright 2019 Google Inc.
3d1491724SPatrick Venture *
4d1491724SPatrick Venture * Licensed under the Apache License, Version 2.0 (the "License");
5d1491724SPatrick Venture * you may not use this file except in compliance with the License.
6d1491724SPatrick Venture * You may obtain a copy of the License at
7d1491724SPatrick Venture *
8d1491724SPatrick Venture * http://www.apache.org/licenses/LICENSE-2.0
9d1491724SPatrick Venture *
10d1491724SPatrick Venture * Unless required by applicable law or agreed to in writing, software
11d1491724SPatrick Venture * distributed under the License is distributed on an "AS IS" BASIS,
12d1491724SPatrick Venture * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d1491724SPatrick Venture * See the License for the specific language governing permissions and
14d1491724SPatrick Venture * limitations under the License.
15d1491724SPatrick Venture */
16d1491724SPatrick Venture
17d1491724SPatrick Venture #include "pid/buildjson.hpp"
18d1491724SPatrick Venture
19d1491724SPatrick Venture #include "conf.hpp"
2031058fd3SJosh Lehan #include "util.hpp"
21d1491724SPatrick Venture
22d1491724SPatrick Venture #include <nlohmann/json.hpp>
23a83a3eccSPatrick Venture
240e8fc398SBonnie Lo #include <iostream>
2531058fd3SJosh Lehan #include <limits>
26a83a3eccSPatrick Venture #include <map>
27d1491724SPatrick Venture #include <tuple>
28d1491724SPatrick Venture
29a076487aSPatrick Venture namespace pid_control
30a076487aSPatrick Venture {
31a076487aSPatrick Venture
32d1491724SPatrick Venture using json = nlohmann::json;
33d1491724SPatrick Venture
34f81f2886SJames Feist namespace conf
35f81f2886SJames Feist {
3631058fd3SJosh Lehan
from_json(const json & j,conf::ControllerInfo & c)37f81f2886SJames Feist void from_json(const json& j, conf::ControllerInfo& c)
38d1491724SPatrick Venture {
3931058fd3SJosh Lehan std::vector<std::string> inputNames;
403f0f7bc3SJosh Lehan std::vector<std::string> missingAcceptableNames;
4131058fd3SJosh Lehan
42d1491724SPatrick Venture j.at("type").get_to(c.type);
4331058fd3SJosh Lehan j.at("inputs").get_to(inputNames);
44d1491724SPatrick Venture j.at("setpoint").get_to(c.setpoint);
45d1491724SPatrick Venture
4631058fd3SJosh Lehan std::vector<double> inputTempToMargin;
4731058fd3SJosh Lehan
4831058fd3SJosh Lehan auto findTempToMargin = j.find("tempToMargin");
4931058fd3SJosh Lehan if (findTempToMargin != j.end())
5031058fd3SJosh Lehan {
5131058fd3SJosh Lehan findTempToMargin->get_to(inputTempToMargin);
5231058fd3SJosh Lehan }
5331058fd3SJosh Lehan
543f0f7bc3SJosh Lehan auto findMissingAcceptable = j.find("missingIsAcceptable");
553f0f7bc3SJosh Lehan if (findMissingAcceptable != j.end())
563f0f7bc3SJosh Lehan {
573f0f7bc3SJosh Lehan findMissingAcceptable->get_to(missingAcceptableNames);
583f0f7bc3SJosh Lehan }
593f0f7bc3SJosh Lehan
603f0f7bc3SJosh Lehan c.inputs = spliceInputs(inputNames, inputTempToMargin,
613f0f7bc3SJosh Lehan missingAcceptableNames);
6231058fd3SJosh Lehan
63d1491724SPatrick Venture /* TODO: We need to handle parsing other PID controller configurations.
64d1491724SPatrick Venture * We can do that by checking for different keys and making the decision
65d1491724SPatrick Venture * accordingly.
66d1491724SPatrick Venture */
67d1491724SPatrick Venture auto p = j.at("pid");
68375f7098SHank Liou
69*5d897e2aSDelphine CC Chiu auto checkHysterWithSetpt = p.find("checkHysteresisWithSetpoint");
70375f7098SHank Liou auto positiveHysteresis = p.find("positiveHysteresis");
71375f7098SHank Liou auto negativeHysteresis = p.find("negativeHysteresis");
72c612c051SJosh Lehan auto derivativeCoeff = p.find("derivativeCoeff");
739788963cSDelphine CC Chiu auto checkHysterWithSetptValue = false;
74375f7098SHank Liou auto positiveHysteresisValue = 0.0;
75375f7098SHank Liou auto negativeHysteresisValue = 0.0;
76c612c051SJosh Lehan auto derivativeCoeffValue = 0.0;
779788963cSDelphine CC Chiu if (checkHysterWithSetpt != p.end())
789788963cSDelphine CC Chiu {
799788963cSDelphine CC Chiu checkHysterWithSetpt->get_to(checkHysterWithSetptValue);
809788963cSDelphine CC Chiu }
81375f7098SHank Liou if (positiveHysteresis != p.end())
82375f7098SHank Liou {
83c612c051SJosh Lehan positiveHysteresis->get_to(positiveHysteresisValue);
84375f7098SHank Liou }
85375f7098SHank Liou if (negativeHysteresis != p.end())
86375f7098SHank Liou {
87c612c051SJosh Lehan negativeHysteresis->get_to(negativeHysteresisValue);
88c612c051SJosh Lehan }
89c612c051SJosh Lehan if (derivativeCoeff != p.end())
90c612c051SJosh Lehan {
91c612c051SJosh Lehan derivativeCoeff->get_to(derivativeCoeffValue);
92375f7098SHank Liou }
93375f7098SHank Liou
949fe3a3c7Sykchiu auto failSafePercent = j.find("FailSafePercent");
959fe3a3c7Sykchiu auto failSafePercentValue = 0;
969fe3a3c7Sykchiu if (failSafePercent != j.end())
979fe3a3c7Sykchiu {
989fe3a3c7Sykchiu failSafePercent->get_to(failSafePercentValue);
999fe3a3c7Sykchiu }
1009fe3a3c7Sykchiu c.failSafePercent = failSafePercentValue;
1019fe3a3c7Sykchiu
102375f7098SHank Liou if (c.type != "stepwise")
103375f7098SHank Liou {
104d1491724SPatrick Venture p.at("samplePeriod").get_to(c.pidInfo.ts);
105d1491724SPatrick Venture p.at("proportionalCoeff").get_to(c.pidInfo.proportionalCoeff);
106d1491724SPatrick Venture p.at("integralCoeff").get_to(c.pidInfo.integralCoeff);
107903b0427SPatrick Venture p.at("feedFwdOffsetCoeff").get_to(c.pidInfo.feedFwdOffset);
108d1491724SPatrick Venture p.at("feedFwdGainCoeff").get_to(c.pidInfo.feedFwdGain);
109d1491724SPatrick Venture p.at("integralLimit_min").get_to(c.pidInfo.integralLimit.min);
110d1491724SPatrick Venture p.at("integralLimit_max").get_to(c.pidInfo.integralLimit.max);
111d1491724SPatrick Venture p.at("outLim_min").get_to(c.pidInfo.outLim.min);
112d1491724SPatrick Venture p.at("outLim_max").get_to(c.pidInfo.outLim.max);
113d1491724SPatrick Venture p.at("slewNeg").get_to(c.pidInfo.slewNeg);
114d1491724SPatrick Venture p.at("slewPos").get_to(c.pidInfo.slewPos);
115d1491724SPatrick Venture
116c612c051SJosh Lehan // Unlike other coefficients, treat derivativeCoeff as an optional
117c612c051SJosh Lehan // parameter, as support for it is fairly new, to avoid breaking
118c612c051SJosh Lehan // existing configurations in the field that predate it.
119375f7098SHank Liou c.pidInfo.positiveHysteresis = positiveHysteresisValue;
120375f7098SHank Liou c.pidInfo.negativeHysteresis = negativeHysteresisValue;
121c612c051SJosh Lehan c.pidInfo.derivativeCoeff = derivativeCoeffValue;
1229788963cSDelphine CC Chiu c.pidInfo.checkHysterWithSetpt = checkHysterWithSetptValue;
123d1491724SPatrick Venture }
124d1491724SPatrick Venture else
125d1491724SPatrick Venture {
126375f7098SHank Liou p.at("samplePeriod").get_to(c.stepwiseInfo.ts);
127375f7098SHank Liou p.at("isCeiling").get_to(c.stepwiseInfo.isCeiling);
128375f7098SHank Liou
129375f7098SHank Liou for (size_t i = 0; i < ec::maxStepwisePoints; i++)
130375f7098SHank Liou {
131375f7098SHank Liou c.stepwiseInfo.reading[i] =
132375f7098SHank Liou std::numeric_limits<double>::quiet_NaN();
133375f7098SHank Liou c.stepwiseInfo.output[i] = std::numeric_limits<double>::quiet_NaN();
134d1491724SPatrick Venture }
135d1491724SPatrick Venture
136375f7098SHank Liou auto reading = p.find("reading");
137375f7098SHank Liou if (reading != p.end())
138d1491724SPatrick Venture {
139375f7098SHank Liou auto r = p.at("reading");
140375f7098SHank Liou for (size_t i = 0; i < ec::maxStepwisePoints; i++)
141375f7098SHank Liou {
142375f7098SHank Liou auto n = r.find(std::to_string(i));
143375f7098SHank Liou if (n != r.end())
144375f7098SHank Liou {
145375f7098SHank Liou r.at(std::to_string(i)).get_to(c.stepwiseInfo.reading[i]);
146d1491724SPatrick Venture }
147375f7098SHank Liou }
148375f7098SHank Liou }
149375f7098SHank Liou
150375f7098SHank Liou auto output = p.find("output");
151375f7098SHank Liou if (output != p.end())
152d1491724SPatrick Venture {
153375f7098SHank Liou auto o = p.at("output");
154375f7098SHank Liou for (size_t i = 0; i < ec::maxStepwisePoints; i++)
155375f7098SHank Liou {
156375f7098SHank Liou auto n = o.find(std::to_string(i));
157375f7098SHank Liou if (n != o.end())
158375f7098SHank Liou {
159375f7098SHank Liou o.at(std::to_string(i)).get_to(c.stepwiseInfo.output[i]);
160375f7098SHank Liou }
161375f7098SHank Liou }
162375f7098SHank Liou }
163375f7098SHank Liou
164375f7098SHank Liou c.stepwiseInfo.positiveHysteresis = positiveHysteresisValue;
165375f7098SHank Liou c.stepwiseInfo.negativeHysteresis = negativeHysteresisValue;
166d1491724SPatrick Venture }
167d1491724SPatrick Venture }
16831058fd3SJosh Lehan
169f81f2886SJames Feist } // namespace conf
170d1491724SPatrick Venture
getCycleTimeSetting(const auto & zone,const int id,const std::string & attributeName,uint64_t & value)171239aa7d7SHarvey Wu inline void getCycleTimeSetting(const auto& zone, const int id,
172239aa7d7SHarvey Wu const std::string& attributeName,
173239aa7d7SHarvey Wu uint64_t& value)
174239aa7d7SHarvey Wu {
175239aa7d7SHarvey Wu auto findAttributeName = zone.find(attributeName);
176239aa7d7SHarvey Wu if (findAttributeName != zone.end())
177239aa7d7SHarvey Wu {
178239aa7d7SHarvey Wu uint64_t tmpAttributeValue = 0;
179239aa7d7SHarvey Wu findAttributeName->get_to(tmpAttributeValue);
180239aa7d7SHarvey Wu if (tmpAttributeValue >= 1)
181239aa7d7SHarvey Wu {
182239aa7d7SHarvey Wu value = tmpAttributeValue;
183239aa7d7SHarvey Wu }
184239aa7d7SHarvey Wu else
185239aa7d7SHarvey Wu {
186239aa7d7SHarvey Wu std::cerr << "Zone " << id << ": " << attributeName
187239aa7d7SHarvey Wu << " is invalid. Use default " << value << " ms\n";
188239aa7d7SHarvey Wu }
189239aa7d7SHarvey Wu }
190239aa7d7SHarvey Wu else
191239aa7d7SHarvey Wu {
192239aa7d7SHarvey Wu std::cerr << "Zone " << id << ": " << attributeName
193239aa7d7SHarvey Wu << " cannot find setting. Use default " << value << " ms\n";
194239aa7d7SHarvey Wu }
195239aa7d7SHarvey Wu }
196239aa7d7SHarvey Wu
1971df9e879SPatrick Venture std::pair<std::map<int64_t, conf::PIDConf>, std::map<int64_t, conf::ZoneConfig>>
buildPIDsFromJson(const json & data)198d1491724SPatrick Venture buildPIDsFromJson(const json& data)
199d1491724SPatrick Venture {
200d1491724SPatrick Venture // zone -> pids
201f81f2886SJames Feist std::map<int64_t, conf::PIDConf> pidConfig;
202d1491724SPatrick Venture // zone -> configs
2031df9e879SPatrick Venture std::map<int64_t, conf::ZoneConfig> zoneConfig;
204d1491724SPatrick Venture
205d1491724SPatrick Venture /* TODO: if zones is empty, that's invalid. */
206d1491724SPatrick Venture auto zones = data["zones"];
207d1491724SPatrick Venture for (const auto& zone : zones)
208d1491724SPatrick Venture {
209d1491724SPatrick Venture int64_t id;
210f81f2886SJames Feist conf::PIDConf thisZone;
2111df9e879SPatrick Venture conf::ZoneConfig thisZoneConfig;
212d1491724SPatrick Venture
213d1491724SPatrick Venture /* TODO: using at() throws a specific exception we can catch */
214d1491724SPatrick Venture id = zone["id"];
2153484bedaSJames Feist thisZoneConfig.minThermalOutput = zone["minThermalOutput"];
216d1491724SPatrick Venture thisZoneConfig.failsafePercent = zone["failsafePercent"];
217d1491724SPatrick Venture
218239aa7d7SHarvey Wu getCycleTimeSetting(zone, id, "cycleIntervalTimeMS",
219239aa7d7SHarvey Wu thisZoneConfig.cycleTime.cycleIntervalTimeMS);
220239aa7d7SHarvey Wu getCycleTimeSetting(zone, id, "updateThermalsTimeMS",
221239aa7d7SHarvey Wu thisZoneConfig.cycleTime.updateThermalsTimeMS);
2220e8fc398SBonnie Lo
2239788963cSDelphine CC Chiu bool accumulateSetPoint = false;
2249788963cSDelphine CC Chiu auto findAccSetPoint = zone.find("accumulateSetPoint");
2259788963cSDelphine CC Chiu if (findAccSetPoint != zone.end())
2269788963cSDelphine CC Chiu {
2279788963cSDelphine CC Chiu findAccSetPoint->get_to(accumulateSetPoint);
2289788963cSDelphine CC Chiu }
2299788963cSDelphine CC Chiu thisZoneConfig.accumulateSetPoint = accumulateSetPoint;
2309788963cSDelphine CC Chiu
231d1491724SPatrick Venture auto pids = zone["pids"];
232d1491724SPatrick Venture for (const auto& pid : pids)
233d1491724SPatrick Venture {
234d1491724SPatrick Venture auto name = pid["name"];
235f81f2886SJames Feist auto item = pid.get<conf::ControllerInfo>();
236d1491724SPatrick Venture
2377c6d35d5Sykchiu if (thisZone.find(name) != thisZone.end())
2387c6d35d5Sykchiu {
2397c6d35d5Sykchiu std::cerr << "Warning: zone " << id
2407c6d35d5Sykchiu << " have the same pid name " << name << std::endl;
2417c6d35d5Sykchiu }
2427c6d35d5Sykchiu
243d1491724SPatrick Venture thisZone[name] = item;
244d1491724SPatrick Venture }
245d1491724SPatrick Venture
246d1491724SPatrick Venture pidConfig[id] = thisZone;
247d1491724SPatrick Venture zoneConfig[id] = thisZoneConfig;
248d1491724SPatrick Venture }
249d1491724SPatrick Venture
250d1491724SPatrick Venture return std::make_pair(pidConfig, zoneConfig);
251d1491724SPatrick Venture }
252a076487aSPatrick Venture
253a076487aSPatrick Venture } // namespace pid_control
254