1 /** 2 * Copyright 2019 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "pid/buildjson.hpp" 18 19 #include "conf.hpp" 20 21 #include <map> 22 #include <nlohmann/json.hpp> 23 #include <tuple> 24 25 using json = nlohmann::json; 26 27 namespace conf 28 { 29 void from_json(const json& j, conf::ControllerInfo& c) 30 { 31 j.at("type").get_to(c.type); 32 j.at("inputs").get_to(c.inputs); 33 j.at("setpoint").get_to(c.setpoint); 34 35 /* TODO: We need to handle parsing other PID controller configurations. 36 * We can do that by checking for different keys and making the decision 37 * accordingly. 38 */ 39 auto p = j.at("pid"); 40 41 auto positiveHysteresis = p.find("positiveHysteresis"); 42 auto negativeHysteresis = p.find("negativeHysteresis"); 43 auto positiveHysteresisValue = 0.0; 44 auto negativeHysteresisValue = 0.0; 45 if (positiveHysteresis != p.end()) 46 { 47 p.at("positiveHysteresis").get_to(positiveHysteresisValue); 48 } 49 if (negativeHysteresis != p.end()) 50 { 51 p.at("negativeHysteresis").get_to(negativeHysteresisValue); 52 } 53 54 if (c.type != "stepwise") 55 { 56 p.at("samplePeriod").get_to(c.pidInfo.ts); 57 p.at("proportionalCoeff").get_to(c.pidInfo.proportionalCoeff); 58 p.at("integralCoeff").get_to(c.pidInfo.integralCoeff); 59 p.at("feedFwdOffsetCoeff").get_to(c.pidInfo.feedFwdOffset); 60 p.at("feedFwdGainCoeff").get_to(c.pidInfo.feedFwdGain); 61 p.at("integralLimit_min").get_to(c.pidInfo.integralLimit.min); 62 p.at("integralLimit_max").get_to(c.pidInfo.integralLimit.max); 63 p.at("outLim_min").get_to(c.pidInfo.outLim.min); 64 p.at("outLim_max").get_to(c.pidInfo.outLim.max); 65 p.at("slewNeg").get_to(c.pidInfo.slewNeg); 66 p.at("slewPos").get_to(c.pidInfo.slewPos); 67 68 c.pidInfo.positiveHysteresis = positiveHysteresisValue; 69 c.pidInfo.negativeHysteresis = negativeHysteresisValue; 70 } 71 else 72 { 73 p.at("samplePeriod").get_to(c.stepwiseInfo.ts); 74 p.at("isCeiling").get_to(c.stepwiseInfo.isCeiling); 75 76 for (size_t i = 0; i < ec::maxStepwisePoints; i++) 77 { 78 c.stepwiseInfo.reading[i] = 79 std::numeric_limits<double>::quiet_NaN(); 80 c.stepwiseInfo.output[i] = std::numeric_limits<double>::quiet_NaN(); 81 } 82 83 auto reading = p.find("reading"); 84 if (reading != p.end()) 85 { 86 auto r = p.at("reading"); 87 for (size_t i = 0; i < ec::maxStepwisePoints; i++) 88 { 89 auto n = r.find(std::to_string(i)); 90 if (n != r.end()) 91 { 92 r.at(std::to_string(i)).get_to(c.stepwiseInfo.reading[i]); 93 } 94 } 95 } 96 97 auto output = p.find("output"); 98 if (output != p.end()) 99 { 100 auto o = p.at("output"); 101 for (size_t i = 0; i < ec::maxStepwisePoints; i++) 102 { 103 auto n = o.find(std::to_string(i)); 104 if (n != o.end()) 105 { 106 o.at(std::to_string(i)).get_to(c.stepwiseInfo.output[i]); 107 } 108 } 109 } 110 111 c.stepwiseInfo.positiveHysteresis = positiveHysteresisValue; 112 c.stepwiseInfo.negativeHysteresis = negativeHysteresisValue; 113 } 114 } 115 } // namespace conf 116 117 std::pair<std::map<int64_t, conf::PIDConf>, 118 std::map<int64_t, struct conf::ZoneConfig>> 119 buildPIDsFromJson(const json& data) 120 { 121 // zone -> pids 122 std::map<int64_t, conf::PIDConf> pidConfig; 123 // zone -> configs 124 std::map<int64_t, struct conf::ZoneConfig> zoneConfig; 125 126 /* TODO: if zones is empty, that's invalid. */ 127 auto zones = data["zones"]; 128 for (const auto& zone : zones) 129 { 130 int64_t id; 131 conf::PIDConf thisZone; 132 struct conf::ZoneConfig thisZoneConfig; 133 134 /* TODO: using at() throws a specific exception we can catch */ 135 id = zone["id"]; 136 thisZoneConfig.minThermalOutput = zone["minThermalOutput"]; 137 thisZoneConfig.failsafePercent = zone["failsafePercent"]; 138 139 auto pids = zone["pids"]; 140 for (const auto& pid : pids) 141 { 142 auto name = pid["name"]; 143 auto item = pid.get<conf::ControllerInfo>(); 144 145 thisZone[name] = item; 146 } 147 148 pidConfig[id] = thisZone; 149 zoneConfig[id] = thisZoneConfig; 150 } 151 152 return std::make_pair(pidConfig, zoneConfig); 153 } 154