1 #include "conf.hpp"
2 #include "pid/buildjson.hpp"
3
4 #include <sys/types.h>
5
6 #include <cstdint>
7 #include <map>
8 #include <tuple>
9
10 #include <gtest/gtest.h>
11
12 namespace pid_control
13 {
14 namespace
15 {
16
TEST(ZoneFromJson,emptyZone)17 TEST(ZoneFromJson, emptyZone)
18 {
19 // There is a zone key, but it's empty.
20 // This is technically invalid.
21
22 std::map<int64_t, conf::PIDConf> pidConfig;
23 std::map<int64_t, conf::ZoneConfig> zoneConfig;
24
25 auto j2 = R"(
26 {
27 "zones": []
28 }
29 )"_json;
30
31 std::tie(pidConfig, zoneConfig) = buildPIDsFromJson(j2);
32
33 EXPECT_TRUE(pidConfig.empty());
34 EXPECT_TRUE(zoneConfig.empty());
35 }
36
TEST(ZoneFromJson,oneZoneOnePid)37 TEST(ZoneFromJson, oneZoneOnePid)
38 {
39 // Parse a valid configuration with one zone and one PID.
40 // Intentionally omits "derivativeCoeff" to test that it is optional.
41
42 std::map<int64_t, conf::PIDConf> pidConfig;
43 std::map<int64_t, conf::ZoneConfig> zoneConfig;
44
45 auto j2 = R"(
46 {
47 "zones" : [{
48 "id": 1,
49 "minThermalOutput": 3000.0,
50 "failsafePercent": 75.0,
51 "pids": [{
52 "name": "fan1-5",
53 "type": "fan",
54 "inputs": ["fan1", "fan5"],
55 "setpoint": 90.0,
56 "pid": {
57 "samplePeriod": 0.1,
58 "proportionalCoeff": 0.0,
59 "integralCoeff": 0.0,
60 "feedFwdOffsetCoeff": 0.0,
61 "feedFwdGainCoeff": 0.010,
62 "integralLimit_min": 0.0,
63 "integralLimit_max": 0.0,
64 "outLim_min": 30.0,
65 "outLim_max": 100.0,
66 "slewNeg": 0.0,
67 "slewPos": 0.0
68 }
69 }]
70 }]
71 }
72 )"_json;
73
74 std::tie(pidConfig, zoneConfig) = buildPIDsFromJson(j2);
75 EXPECT_EQ(pidConfig.size(), static_cast<u_int64_t>(1));
76 EXPECT_EQ(zoneConfig.size(), static_cast<u_int64_t>(1));
77
78 EXPECT_EQ(pidConfig[1]["fan1-5"].type, "fan");
79 EXPECT_DOUBLE_EQ(zoneConfig[1].minThermalOutput, 3000.0);
80 }
81
TEST(ZoneFromJson,marginZone)82 TEST(ZoneFromJson, marginZone)
83 {
84 // Parse a valid configuration with one zone and one PID.
85 // This is a margin zone, and has both kinds of temperature
86 // sensors in it, absolute temperature and margin temperature.
87 // Tests that TempToMargin is parsed correctly.
88
89 std::map<int64_t, conf::PIDConf> pidConfig;
90 std::map<int64_t, conf::ZoneConfig> zoneConfig;
91
92 auto j2 = R"(
93 {
94 "zones" : [{
95 "id": 1,
96 "minThermalOutput": 3000.0,
97 "failsafePercent": 75.0,
98 "pids": [{
99 "name": "myPid",
100 "type": "margin",
101 "inputs": ["absolute0", "absolute1", "margin0", "margin1"],
102 "tempToMargin": [
103 85.0,
104 100.0
105 ],
106 "setpoint": 10.0,
107 "pid": {
108 "samplePeriod": 0.1,
109 "proportionalCoeff": 0.0,
110 "integralCoeff": 0.0,
111 "feedFwdOffsetCoeff": 0.0,
112 "feedFwdGainCoeff": 0.010,
113 "integralLimit_min": 0.0,
114 "integralLimit_max": 0.0,
115 "outLim_min": 30.0,
116 "outLim_max": 100.0,
117 "slewNeg": 0.0,
118 "slewPos": 0.0
119 }
120 }]
121 }]
122 }
123 )"_json;
124
125 std::tie(pidConfig, zoneConfig) = buildPIDsFromJson(j2);
126 EXPECT_EQ(pidConfig.size(), static_cast<u_int64_t>(1));
127 EXPECT_EQ(zoneConfig.size(), static_cast<u_int64_t>(1));
128
129 EXPECT_EQ(pidConfig[1]["myPid"].type, "margin");
130 EXPECT_DOUBLE_EQ(zoneConfig[1].minThermalOutput, 3000.0);
131
132 EXPECT_EQ(pidConfig[1]["myPid"].inputs[0].name, "absolute0");
133 EXPECT_DOUBLE_EQ(pidConfig[1]["myPid"].inputs[0].convertMarginZero, 85.0);
134 EXPECT_EQ(pidConfig[1]["myPid"].inputs[0].convertTempToMargin, true);
135
136 EXPECT_EQ(pidConfig[1]["myPid"].inputs[1].name, "absolute1");
137 EXPECT_DOUBLE_EQ(pidConfig[1]["myPid"].inputs[1].convertMarginZero, 100.0);
138 EXPECT_EQ(pidConfig[1]["myPid"].inputs[1].convertTempToMargin, true);
139
140 EXPECT_EQ(pidConfig[1]["myPid"].inputs[2].name, "margin0");
141 EXPECT_EQ(pidConfig[1]["myPid"].inputs[2].convertTempToMargin, false);
142
143 EXPECT_EQ(pidConfig[1]["myPid"].inputs[3].name, "margin1");
144 EXPECT_EQ(pidConfig[1]["myPid"].inputs[3].convertTempToMargin, false);
145 }
146
TEST(ZoneFromJson,oneZoneOnePidWithHysteresis)147 TEST(ZoneFromJson, oneZoneOnePidWithHysteresis)
148 {
149 // Parse a valid configuration with one zone and one PID and the PID uses
150 // Hysteresis parameters.
151
152 std::map<int64_t, conf::PIDConf> pidConfig;
153 std::map<int64_t, conf::ZoneConfig> zoneConfig;
154
155 auto j2 = R"(
156 {
157 "zones" : [{
158 "id": 1,
159 "minThermalOutput": 3000.0,
160 "failsafePercent": 75.0,
161 "pids": [{
162 "name": "fan1-5",
163 "type": "fan",
164 "inputs": ["fan1", "fan5"],
165 "setpoint": 90.0,
166 "pid": {
167 "samplePeriod": 0.1,
168 "proportionalCoeff": 0.0,
169 "integralCoeff": 0.0,
170 "derivativeCoeff": 0.0,
171 "feedFwdOffsetCoeff": 0.0,
172 "feedFwdGainCoeff": 0.010,
173 "integralLimit_min": 0.0,
174 "integralLimit_max": 0.0,
175 "outLim_min": 30.0,
176 "outLim_max": 100.0,
177 "slewNeg": 0.0,
178 "slewPos": 0.0,
179 "positiveHysteresis": 1000.0,
180 "negativeHysteresis": 9000.0
181 }
182 }]
183 }]
184 }
185 )"_json;
186
187 std::tie(pidConfig, zoneConfig) = buildPIDsFromJson(j2);
188 EXPECT_EQ(pidConfig.size(), static_cast<u_int64_t>(1));
189 EXPECT_EQ(zoneConfig.size(), static_cast<u_int64_t>(1));
190
191 EXPECT_EQ(pidConfig[1]["fan1-5"].type, "fan");
192 EXPECT_DOUBLE_EQ(pidConfig[1]["fan1-5"].pidInfo.positiveHysteresis, 1000.0);
193
194 EXPECT_DOUBLE_EQ(zoneConfig[1].minThermalOutput, 3000.0);
195 }
196
TEST(ZoneFromJson,oneZoneOneStepwiseWithHysteresis)197 TEST(ZoneFromJson, oneZoneOneStepwiseWithHysteresis)
198 {
199 // Parse a valid configuration with one zone and one PID and the PID uses
200 // Hysteresis parameters.
201
202 std::map<int64_t, conf::PIDConf> pidConfig;
203 std::map<int64_t, conf::ZoneConfig> zoneConfig;
204
205 auto j2 = R"(
206 {
207 "zones" : [{
208 "id": 1,
209 "minThermalOutput": 3000.0,
210 "failsafePercent": 75.0,
211 "pids": [{
212 "name": "temp1",
213 "type": "stepwise",
214 "inputs": ["temp1"],
215 "setpoint": 30.0,
216 "pid": {
217 "samplePeriod": 0.1,
218 "positiveHysteresis": 1.0,
219 "negativeHysteresis": 1.0,
220 "isCeiling": false,
221 "reading": {
222 "0": 45,
223 "1": 46,
224 "2": 47,
225 "3": 48,
226 "4": 49,
227 "5": 50,
228 "6": 51,
229 "7": 52,
230 "8": 53,
231 "9": 54,
232 "10": 55,
233 "11": 56,
234 "12": 57,
235 "13": 58,
236 "14": 59,
237 "15": 60,
238 "16": 61,
239 "17": 62,
240 "18": 63,
241 "19": 64
242 },
243 "output": {
244 "0": 5000,
245 "1": 2400,
246 "2": 2600,
247 "3": 2800,
248 "4": 3000,
249 "5": 3200,
250 "6": 3400,
251 "7": 3600,
252 "8": 3800,
253 "9": 4000,
254 "10": 4200,
255 "11": 4400,
256 "12": 4600,
257 "13": 4800,
258 "14": 5000,
259 "15": 5200,
260 "16": 5400,
261 "17": 5600,
262 "18": 5800,
263 "19": 6000
264 }
265 }
266 }]
267 }]
268 }
269 )"_json;
270
271 std::tie(pidConfig, zoneConfig) = buildPIDsFromJson(j2);
272 EXPECT_EQ(pidConfig.size(), static_cast<u_int64_t>(1));
273 EXPECT_EQ(zoneConfig.size(), static_cast<u_int64_t>(1));
274
275 EXPECT_EQ(pidConfig[1]["temp1"].type, "stepwise");
276 EXPECT_DOUBLE_EQ(pidConfig[1]["temp1"].stepwiseInfo.positiveHysteresis,
277 1.0);
278
279 EXPECT_DOUBLE_EQ(zoneConfig[1].minThermalOutput, 3000.0);
280 }
281
TEST(ZoneFromJson,getCycleInterval)282 TEST(ZoneFromJson, getCycleInterval)
283 {
284 // Parse a valid configuration with one zone and one PID and the zone have
285 // cycleIntervalTime and updateThermalsTime parameters.
286
287 std::map<int64_t, conf::PIDConf> pidConfig;
288 std::map<int64_t, conf::ZoneConfig> zoneConfig;
289
290 auto j2 = R"(
291 {
292 "zones" : [{
293 "id": 1,
294 "minThermalOutput": 3000.0,
295 "failsafePercent": 75.0,
296 "cycleIntervalTimeMS": 1000.0,
297 "updateThermalsTimeMS": 1000.0,
298 "pids": [{
299 "name": "fan1-5",
300 "type": "fan",
301 "inputs": ["fan1", "fan5"],
302 "setpoint": 90.0,
303 "pid": {
304 "samplePeriod": 0.1,
305 "proportionalCoeff": 0.0,
306 "integralCoeff": 0.0,
307 "derivativeCoeff": 0.0,
308 "feedFwdOffsetCoeff": 0.0,
309 "feedFwdGainCoeff": 0.010,
310 "integralLimit_min": 0.0,
311 "integralLimit_max": 0.0,
312 "outLim_min": 30.0,
313 "outLim_max": 100.0,
314 "slewNeg": 0.0,
315 "slewPos": 0.0
316 }
317 }]
318 }]
319 }
320 )"_json;
321
322 std::tie(pidConfig, zoneConfig) = buildPIDsFromJson(j2);
323 EXPECT_EQ(pidConfig.size(), static_cast<u_int64_t>(1));
324 EXPECT_EQ(zoneConfig.size(), static_cast<u_int64_t>(1));
325
326 EXPECT_EQ(pidConfig[1]["fan1-5"].type, "fan");
327 EXPECT_EQ(zoneConfig[1].cycleTime.cycleIntervalTimeMS,
328 static_cast<u_int64_t>(1000));
329 EXPECT_EQ(zoneConfig[1].cycleTime.updateThermalsTimeMS,
330 static_cast<u_int64_t>(1000));
331 EXPECT_DOUBLE_EQ(zoneConfig[1].minThermalOutput, 3000.0);
332 }
333
334 } // namespace
335 } // namespace pid_control
336