blob: 3f106c20508990fda32d20a13c5077e471dd31e7 [file] [log] [blame]
Matthew Barthf24d7742020-03-17 16:12:15 -05001#!/usr/bin/env python3
Matt Spinlerd08dbe22017-04-11 13:52:54 -05002
3"""
4This script reads in fan definition and zone definition YAML
5files and generates a set of structures for use by the fan control code.
6"""
7
8import os
9import sys
10import yaml
11from argparse import ArgumentParser
Matthew Barth702c4a52018-02-28 16:23:11 -060012from mako.lookup import TemplateLookup
Matt Spinlerd08dbe22017-04-11 13:52:54 -050013
Matt Spinler78498c92017-04-11 13:59:46 -050014
Matthew Barth7883f582019-02-14 14:24:46 -060015def parse_cpp_type(typeName):
16 """
17 Take a list of dbus types from YAML and convert it to a recursive cpp
18 formed data structure. Each entry of the original list gets converted
19 into a tuple consisting of the type name and a list with the params
20 for this type,
21 e.g.
22 ['dict', ['string', 'dict', ['string', 'int64']]]
23 is converted to
24 [('dict', [('string', []), ('dict', [('string', []),
25 ('int64', [])]]]
26 """
27
28 if not typeName:
29 return None
30
31 # Type names are _almost_ valid YAML. Insert a , before each [
32 # and then wrap it in a [ ] and it becomes valid YAML (assuming
33 # the user gave us a valid typename).
34 typeArray = yaml.safe_load("[" + ",[".join(typeName.split("[")) + "]")
35 typeTuple = preprocess_yaml_type_array(typeArray).pop(0)
36 return get_cpp_type(typeTuple)
37
38
39def preprocess_yaml_type_array(typeArray):
40 """
41 Flattens an array type into a tuple list that can be used to get the
42 supported cpp type from each element.
43 """
44
45 result = []
46
47 for i in range(len(typeArray)):
48 # Ignore lists because we merge them with the previous element
49 if type(typeArray[i]) is list:
50 continue
51
52 # If there is a next element and it is a list, merge it with the
53 # current element.
Patrick Williams0f2588f2022-12-05 10:17:03 -060054 if i < len(typeArray) - 1 and type(typeArray[i + 1]) is list:
Matthew Barth7883f582019-02-14 14:24:46 -060055 result.append(
Patrick Williams0f2588f2022-12-05 10:17:03 -060056 (typeArray[i], preprocess_yaml_type_array(typeArray[i + 1]))
57 )
Matthew Barth7883f582019-02-14 14:24:46 -060058 else:
59 result.append((typeArray[i], []))
60
61 return result
62
63
64def get_cpp_type(typeTuple):
65 """
66 Take a list of dbus types and perform validity checking, such as:
67 [ variant [ dict [ int32, int32 ], double ] ]
68 This function then converts the type-list into a C++ type string.
69 """
70
71 propertyMap = {
Patrick Williams0f2588f2022-12-05 10:17:03 -060072 "byte": {"cppName": "uint8_t", "params": 0},
73 "boolean": {"cppName": "bool", "params": 0},
74 "int16": {"cppName": "int16_t", "params": 0},
75 "uint16": {"cppName": "uint16_t", "params": 0},
76 "int32": {"cppName": "int32_t", "params": 0},
77 "uint32": {"cppName": "uint32_t", "params": 0},
78 "int64": {"cppName": "int64_t", "params": 0},
79 "uint64": {"cppName": "uint64_t", "params": 0},
80 "double": {"cppName": "double", "params": 0},
81 "string": {"cppName": "std::string", "params": 0},
82 "array": {"cppName": "std::vector", "params": 1},
83 "dict": {"cppName": "std::map", "params": 2},
84 }
Matthew Barth7883f582019-02-14 14:24:46 -060085
86 if len(typeTuple) != 2:
87 raise RuntimeError("Invalid typeTuple %s" % typeTuple)
88
89 first = typeTuple[0]
90 entry = propertyMap[first]
91
Patrick Williams0f2588f2022-12-05 10:17:03 -060092 result = entry["cppName"]
Matthew Barth7883f582019-02-14 14:24:46 -060093
94 # Handle 0-entry parameter lists.
Patrick Williams0f2588f2022-12-05 10:17:03 -060095 if entry["params"] == 0:
96 if len(typeTuple[1]) != 0:
Matthew Barth7883f582019-02-14 14:24:46 -060097 raise RuntimeError("Invalid typeTuple %s" % typeTuple)
98 else:
99 return result
100
101 # Get the parameter list
102 rest = typeTuple[1]
103
104 # Confirm parameter count matches.
Patrick Williams0f2588f2022-12-05 10:17:03 -0600105 if (entry["params"] != -1) and (entry["params"] != len(rest)):
106 raise RuntimeError("Invalid entry count for %s : %s" % (first, rest))
Matthew Barth7883f582019-02-14 14:24:46 -0600107
108 # Parse each parameter entry, if appropriate, and create C++ template
109 # syntax.
Patrick Williams0f2588f2022-12-05 10:17:03 -0600110 result += "<"
111 if entry.get("noparse"):
Matthew Barth7883f582019-02-14 14:24:46 -0600112 # Do not parse the parameter list, just use the first element
113 # of each tuple and ignore possible parameters
114 result += ", ".join([e[0] for e in rest])
115 else:
Matthew Barth867a31c2020-02-13 13:13:44 -0600116 result += ", ".join([get_cpp_type(e) for e in rest])
Patrick Williams0f2588f2022-12-05 10:17:03 -0600117 result += ">"
Matthew Barth7883f582019-02-14 14:24:46 -0600118
119 return result
120
121
Matthew Barthbb12c922017-06-13 13:57:40 -0500122def convertToMap(listOfDict):
123 """
124 Converts a list of dictionary entries to a std::map initialization list.
125 """
Patrick Williams0f2588f2022-12-05 10:17:03 -0600126 listOfDict = listOfDict.replace("'", '"')
127 listOfDict = listOfDict.replace("[", "{")
128 listOfDict = listOfDict.replace("]", "}")
129 listOfDict = listOfDict.replace(":", ",")
Matthew Barthbb12c922017-06-13 13:57:40 -0500130 return listOfDict
131
132
Matthew Bartha1aef7a2019-01-16 11:02:57 -0600133def genEvent(event):
134 """
135 Generates the source code of an event and returns it as a string
136 """
137 e = "SetSpeedEvent{\n"
Patrick Williams0f2588f2022-12-05 10:17:03 -0600138 e += '"' + event["name"] + '",\n'
Matthew Bartha1aef7a2019-01-16 11:02:57 -0600139 e += "Group{\n"
Patrick Williams0f2588f2022-12-05 10:17:03 -0600140 for group in event["groups"]:
141 for member in group["members"]:
142 e += '{"' + member["object"] + '",\n'
143 e += '"' + member["interface"] + '",\n'
144 e += '"' + member["property"] + '"},\n'
Matthew Bartha1aef7a2019-01-16 11:02:57 -0600145 e += "},\n"
146
Matthew Barth06fa7812018-11-20 09:54:30 -0600147 e += "ActionData{\n"
Patrick Williams0f2588f2022-12-05 10:17:03 -0600148 for d in event["action"]:
Matthew Barth06fa7812018-11-20 09:54:30 -0600149 e += "{Group{\n"
Patrick Williams0f2588f2022-12-05 10:17:03 -0600150 for g in d["groups"]:
151 for m in g["members"]:
152 e += '{"' + m["object"] + '",\n'
153 e += '"' + m["interface"] + '",\n'
154 e += '"' + m["property"] + '"},\n'
Matthew Barth06fa7812018-11-20 09:54:30 -0600155 e += "},\n"
156 e += "std::vector<Action>{\n"
Patrick Williams0f2588f2022-12-05 10:17:03 -0600157 for a in d["actions"]:
158 if len(a["parameters"]) != 0:
159 e += "make_action(action::" + a["name"] + "(\n"
Matthew Barth8a697b62018-12-14 13:23:47 -0600160 else:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600161 e += "make_action(action::" + a["name"] + "\n"
162 for i, p in enumerate(a["parameters"]):
163 if (i + 1) != len(a["parameters"]):
Matthew Barth06fa7812018-11-20 09:54:30 -0600164 e += p + ",\n"
165 else:
166 e += p + "\n"
Patrick Williams0f2588f2022-12-05 10:17:03 -0600167 if len(a["parameters"]) != 0:
Matthew Barth8a697b62018-12-14 13:23:47 -0600168 e += ")),\n"
169 else:
170 e += "),\n"
Matthew Barth06fa7812018-11-20 09:54:30 -0600171 e += "}},\n"
172 e += "},\n"
Matthew Bartha1aef7a2019-01-16 11:02:57 -0600173
Matthew Barth1b4de262018-03-06 13:03:16 -0600174 e += "std::vector<Trigger>{\n"
Patrick Williams0f2588f2022-12-05 10:17:03 -0600175 if ("timer" in event["triggers"]) and (
176 event["triggers"]["timer"] is not None
177 ):
178 e += "\tmake_trigger(trigger::timer(TimerConf{\n"
179 e += "\t" + event["triggers"]["timer"]["interval"] + ",\n"
180 e += "\t" + event["triggers"]["timer"]["type"] + "\n"
181 e += "\t})),\n"
Matthew Bartha1aef7a2019-01-16 11:02:57 -0600182
Patrick Williams0f2588f2022-12-05 10:17:03 -0600183 if ("signals" in event["triggers"]) and (
184 event["triggers"]["signals"] is not None
185 ):
186 for s in event["triggers"]["signals"]:
Matthew Barth016bd242018-03-07 16:06:06 -0600187 e += "\tmake_trigger(trigger::signal(\n"
Patrick Williams0f2588f2022-12-05 10:17:03 -0600188 e += "match::" + s["match"] + "(\n"
189 for i, mp in enumerate(s["mparams"]["params"]):
190 if (i + 1) != len(s["mparams"]["params"]):
191 e += "\t\t\t" + s["mparams"][mp] + ",\n"
Matthew Barth016bd242018-03-07 16:06:06 -0600192 else:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600193 e += "\t\t\t" + s["mparams"][mp] + "\n"
Matthew Barth926df662018-10-09 09:51:12 -0500194 e += "\t\t),\n"
195 e += "\t\tmake_handler<SignalHandler>(\n"
Patrick Williams0f2588f2022-12-05 10:17:03 -0600196 if ("type" in s["sparams"]) and (s["sparams"]["type"] is not None):
197 e += s["signal"] + "<" + s["sparams"]["type"] + ">(\n"
Matthew Bartha1aef7a2019-01-16 11:02:57 -0600198 else:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600199 e += s["signal"] + "(\n"
200 for sp in s["sparams"]["params"]:
201 e += s["sparams"][sp] + ",\n"
202 if ("type" in s["hparams"]) and (s["hparams"]["type"] is not None):
203 e += (
204 "handler::"
205 + s["handler"]
206 + "<"
207 + s["hparams"]["type"]
208 + ">(\n"
209 )
Matthew Bartha1aef7a2019-01-16 11:02:57 -0600210 else:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600211 e += "handler::" + s["handler"] + "(\n)"
212 for i, hp in enumerate(s["hparams"]["params"]):
213 if (i + 1) != len(s["hparams"]["params"]):
214 e += s["hparams"][hp] + ",\n"
Matthew Barth016bd242018-03-07 16:06:06 -0600215 else:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600216 e += s["hparams"][hp] + "\n"
Matthew Barth016bd242018-03-07 16:06:06 -0600217 e += "))\n"
Matthew Barth926df662018-10-09 09:51:12 -0500218 e += "\t\t)\n"
Matthew Barth016bd242018-03-07 16:06:06 -0600219 e += "\t)),\n"
220
Patrick Williams0f2588f2022-12-05 10:17:03 -0600221 if "init" in event["triggers"]:
222 for i in event["triggers"]["init"]:
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600223 e += "\tmake_trigger(trigger::init(\n"
Patrick Williams0f2588f2022-12-05 10:17:03 -0600224 if "method" in i:
Matthew Barth926df662018-10-09 09:51:12 -0500225 e += "\t\tmake_handler<MethodHandler>(\n"
Patrick Williams0f2588f2022-12-05 10:17:03 -0600226 if ("type" in i["mparams"]) and (
227 i["mparams"]["type"] is not None
228 ):
229 e += i["method"] + "<" + i["mparams"]["type"] + ">(\n"
Matthew Barth926df662018-10-09 09:51:12 -0500230 else:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600231 e += i["method"] + "(\n"
232 for ip in i["mparams"]["params"]:
233 e += i["mparams"][ip] + ",\n"
234 if ("type" in i["hparams"]) and (
235 i["hparams"]["type"] is not None
236 ):
237 e += (
238 "handler::"
239 + i["handler"]
240 + "<"
241 + i["hparams"]["type"]
242 + ">(\n"
243 )
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600244 else:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600245 e += "handler::" + i["handler"] + "(\n)"
246 for i, hp in enumerate(i["hparams"]["params"]):
247 if (i + 1) != len(i["hparams"]["params"]):
248 e += i["hparams"][hp] + ",\n"
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600249 else:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600250 e += i["hparams"][hp] + "\n"
Matthew Barth926df662018-10-09 09:51:12 -0500251 e += "))\n"
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600252 e += "\t\t)\n"
253 e += "\t)),\n"
254
Matthew Bartha1aef7a2019-01-16 11:02:57 -0600255 e += "},\n"
Matthew Bartha1aef7a2019-01-16 11:02:57 -0600256
257 e += "}"
258
259 return e
260
261
Matthew Barth6c050692017-12-05 15:30:09 -0600262def getGroups(zNum, zCond, edata, events):
263 """
264 Extract and construct the groups for the given event.
265 """
266 groups = []
Patrick Williams0f2588f2022-12-05 10:17:03 -0600267 if ("groups" in edata) and (edata["groups"] is not None):
268 for eGroups in edata["groups"]:
269 if ("zone_conditions" in eGroups) and (
270 eGroups["zone_conditions"] is not None
271 ):
Matthew Barthf7e1cb32018-11-19 11:19:09 -0600272 # Zone conditions are optional in the events yaml but skip
273 # if this event's condition is not in this zone's conditions
Patrick Williams0f2588f2022-12-05 10:17:03 -0600274 if all(
275 "name" in z
276 and z["name"] is not None
277 and not any(c["name"] == z["name"] for c in zCond)
278 for z in eGroups["zone_conditions"]
279 ):
Matthew Barthf7e1cb32018-11-19 11:19:09 -0600280 continue
Matthew Barth6c050692017-12-05 15:30:09 -0600281
Matthew Barthf7e1cb32018-11-19 11:19:09 -0600282 # Zone numbers are optional in the events yaml but skip if this
283 # zone's zone number is not in the event's zone numbers
Patrick Williams0f2588f2022-12-05 10:17:03 -0600284 if all(
285 "zones" in z
286 and z["zones"] is not None
287 and zNum not in z["zones"]
288 for z in eGroups["zone_conditions"]
289 ):
Matthew Barthf7e1cb32018-11-19 11:19:09 -0600290 continue
Patrick Williams0f2588f2022-12-05 10:17:03 -0600291 eGroup = next(
292 g for g in events["groups"] if g["name"] == eGroups["name"]
293 )
Matthew Barth6c050692017-12-05 15:30:09 -0600294
Matthew Barthf7e1cb32018-11-19 11:19:09 -0600295 group = {}
296 members = []
Patrick Williams0f2588f2022-12-05 10:17:03 -0600297 group["name"] = eGroup["name"]
298 for m in eGroup["members"]:
Matthew Barthf7e1cb32018-11-19 11:19:09 -0600299 member = {}
Patrick Williams0f2588f2022-12-05 10:17:03 -0600300 member["path"] = eGroup["type"]
301 member["object"] = eGroup["type"] + m
302 member["interface"] = eGroups["interface"]
303 member["property"] = eGroups["property"]["name"]
304 member["type"] = eGroups["property"]["type"]
Matthew Barthf7e1cb32018-11-19 11:19:09 -0600305 # Use defined service to note member on zone object
Patrick Williams0f2588f2022-12-05 10:17:03 -0600306 if ("service" in eGroup) and (eGroup["service"] is not None):
307 member["service"] = eGroup["service"]
Matthew Barthf7e1cb32018-11-19 11:19:09 -0600308 # Add expected group member's property value if given
Patrick Williams0f2588f2022-12-05 10:17:03 -0600309 if ("value" in eGroups["property"]) and (
310 eGroups["property"]["value"] is not None
311 ):
312 if (
313 isinstance(eGroups["property"]["value"], str)
314 or "string" in str(member["type"]).lower()
315 ):
316 member["value"] = (
317 '"' + eGroups["property"]["value"] + '"'
318 )
319 else:
320 member["value"] = eGroups["property"]["value"]
Matthew Barthf7e1cb32018-11-19 11:19:09 -0600321 members.append(member)
Patrick Williams0f2588f2022-12-05 10:17:03 -0600322 group["members"] = members
Matthew Barthf7e1cb32018-11-19 11:19:09 -0600323 groups.append(group)
Matthew Barth6c050692017-12-05 15:30:09 -0600324 return groups
325
326
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600327def getParameters(member, groups, section, events):
Matthew Barth73379f92018-03-15 11:37:10 -0500328 """
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600329 Extracts and constructs a section's parameters
Matthew Barth73379f92018-03-15 11:37:10 -0500330 """
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600331 params = {}
Patrick Williams0f2588f2022-12-05 10:17:03 -0600332 if ("parameters" in section) and (section["parameters"] is not None):
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600333 plist = []
Patrick Williams0f2588f2022-12-05 10:17:03 -0600334 for sp in section["parameters"]:
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600335 p = str(sp)
Patrick Williams0f2588f2022-12-05 10:17:03 -0600336 if p != "type":
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600337 plist.append(p)
Patrick Williams0f2588f2022-12-05 10:17:03 -0600338 if p != "group":
339 params[p] = '"' + member[p] + '"'
Matthew Barth73379f92018-03-15 11:37:10 -0500340 else:
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600341 params[p] = "Group\n{\n"
342 for g in groups:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600343 for m in g["members"]:
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600344 params[p] += (
Patrick Williams0f2588f2022-12-05 10:17:03 -0600345 '{"'
346 + str(m["object"])
347 + '",\n'
348 + '"'
349 + str(m["interface"])
350 + '",\n'
351 + '"'
352 + str(m["property"])
353 + '"},\n'
354 )
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600355 params[p] += "}"
Matthew Barth73379f92018-03-15 11:37:10 -0500356 else:
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600357 params[p] = member[p]
Patrick Williams0f2588f2022-12-05 10:17:03 -0600358 params["params"] = plist
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600359 else:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600360 params["params"] = []
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600361 return params
362
363
364def getInit(eGrps, eTrig, events):
365 """
366 Extracts and constructs an init trigger for the event's groups
367 which are required to be of the same type.
368 """
369 method = {}
370 methods = []
Patrick Williams0f2588f2022-12-05 10:17:03 -0600371 if len(eGrps) > 0:
Matthew Barth03774012018-10-26 13:25:43 -0500372 # Use the first group member for retrieving the type
Patrick Williams0f2588f2022-12-05 10:17:03 -0600373 member = eGrps[0]["members"][0]
374 if ("method" in eTrig) and (eTrig["method"] is not None):
Matthew Barth03774012018-10-26 13:25:43 -0500375 # Add method parameters
Patrick Williams0f2588f2022-12-05 10:17:03 -0600376 eMethod = next(
377 m for m in events["methods"] if m["name"] == eTrig["method"]
378 )
379 method["method"] = eMethod["name"]
380 method["mparams"] = getParameters(member, eGrps, eMethod, events)
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600381
Matthew Barth03774012018-10-26 13:25:43 -0500382 # Add handler parameters
Patrick Williams0f2588f2022-12-05 10:17:03 -0600383 eHandler = next(
384 h for h in events["handlers"] if h["name"] == eTrig["handler"]
385 )
386 method["handler"] = eHandler["name"]
387 method["hparams"] = getParameters(member, eGrps, eHandler, events)
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600388
389 methods.append(method)
390
391 return methods
Matthew Barth73379f92018-03-15 11:37:10 -0500392
393
Matthew Bartha69465a2018-03-02 13:50:59 -0600394def getSignal(eGrps, eTrig, events):
395 """
396 Extracts and constructs for each group member a signal
397 subscription of each match listed in the trigger.
398 """
399 signals = []
400 for group in eGrps:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600401 for member in group["members"]:
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600402 signal = {}
403 # Add signal parameters
Patrick Williams0f2588f2022-12-05 10:17:03 -0600404 eSignal = next(
405 s for s in events["signals"] if s["name"] == eTrig["signal"]
406 )
407 signal["signal"] = eSignal["name"]
408 signal["sparams"] = getParameters(member, eGrps, eSignal, events)
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600409
410 # If service not given, subscribe to signal match
Patrick Williams0f2588f2022-12-05 10:17:03 -0600411 if "service" not in member:
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600412 # Add signal match parameters
Patrick Williams0f2588f2022-12-05 10:17:03 -0600413 eMatch = next(
414 m
415 for m in events["matches"]
416 if m["name"] == eSignal["match"]
417 )
418 signal["match"] = eMatch["name"]
419 signal["mparams"] = getParameters(
420 member, eGrps, eMatch, events
421 )
Matthew Bartha69465a2018-03-02 13:50:59 -0600422
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600423 # Add handler parameters
Patrick Williams0f2588f2022-12-05 10:17:03 -0600424 eHandler = next(
425 h for h in events["handlers"] if h["name"] == eTrig["handler"]
426 )
427 signal["handler"] = eHandler["name"]
428 signal["hparams"] = getParameters(member, eGrps, eHandler, events)
Matthew Barth73379f92018-03-15 11:37:10 -0500429
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600430 signals.append(signal)
Matthew Barth73379f92018-03-15 11:37:10 -0500431
Matthew Bartha69465a2018-03-02 13:50:59 -0600432 return signals
433
434
Matthew Barthd0b90fc2018-03-05 09:38:45 -0600435def getTimer(eTrig):
436 """
437 Extracts and constructs the required parameters for an
438 event timer.
439 """
440 timer = {}
Patrick Williams0f2588f2022-12-05 10:17:03 -0600441 timer["interval"] = (
442 "static_cast<std::chrono::microseconds>"
443 + "("
444 + str(eTrig["interval"])
445 + ")"
446 )
447 timer["type"] = "TimerType::" + str(eTrig["type"])
Matthew Barthd0b90fc2018-03-05 09:38:45 -0600448 return timer
449
450
Matthew Bartha1aef7a2019-01-16 11:02:57 -0600451def getActions(zNum, zCond, edata, actions, events):
Matthew Barth9df74752017-10-11 14:39:31 -0500452 """
453 Extracts and constructs the make_action function call for
454 all the actions within the given event.
455 """
456 action = []
Patrick Williams0f2588f2022-12-05 10:17:03 -0600457 for eActions in actions["actions"]:
Matthew Barth9df74752017-10-11 14:39:31 -0500458 actions = {}
Patrick Williams0f2588f2022-12-05 10:17:03 -0600459 eAction = next(
460 a for a in events["actions"] if a["name"] == eActions["name"]
461 )
462 actions["name"] = eAction["name"]
463 actions["groups"] = getGroups(zNum, zCond, eActions, events)
Matthew Barth9df74752017-10-11 14:39:31 -0500464 params = []
Patrick Williams0f2588f2022-12-05 10:17:03 -0600465 if ("parameters" in eAction) and (eAction["parameters"] is not None):
466 for p in eAction["parameters"]:
Matthew Barth9df74752017-10-11 14:39:31 -0500467 param = "static_cast<"
468 if type(eActions[p]) is not dict:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600469 if p == "actions":
Matthew Barth9df74752017-10-11 14:39:31 -0500470 param = "std::vector<Action>{"
Patrick Williams0f2588f2022-12-05 10:17:03 -0600471 pActs = getActions(
472 zNum, zCond, edata, eActions, events
473 )
Matthew Barth9df74752017-10-11 14:39:31 -0500474 for a in pActs:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600475 if len(a["parameters"]) != 0:
Matthew Barth9df74752017-10-11 14:39:31 -0500476 param += (
Patrick Williams0f2588f2022-12-05 10:17:03 -0600477 "make_action(action::" + a["name"] + "(\n"
478 )
479 for i, ap in enumerate(a["parameters"]):
480 if (i + 1) != len(a["parameters"]):
481 param += ap + ","
Matthew Barth9df74752017-10-11 14:39:31 -0500482 else:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600483 param += ap + ")"
Matthew Barth9df74752017-10-11 14:39:31 -0500484 else:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600485 param += "make_action(action::" + a["name"]
Matthew Barth9df74752017-10-11 14:39:31 -0500486 param += "),"
487 param += "}"
Patrick Williams0f2588f2022-12-05 10:17:03 -0600488 elif p == "defevents" or p == "altevents" or p == "events":
Matthew Bartha1aef7a2019-01-16 11:02:57 -0600489 param = "std::vector<SetSpeedEvent>{\n"
490 for i, e in enumerate(eActions[p]):
491 aEvent = getEvent(zNum, zCond, e, events)
492 if not aEvent:
493 continue
Patrick Williams0f2588f2022-12-05 10:17:03 -0600494 if (i + 1) != len(eActions[p]):
Matthew Bartha1aef7a2019-01-16 11:02:57 -0600495 param += genEvent(aEvent) + ",\n"
496 else:
497 param += genEvent(aEvent) + "\n"
498 param += "\t}"
Patrick Williams0f2588f2022-12-05 10:17:03 -0600499 elif p == "property":
500 if (
501 isinstance(eActions[p], str)
502 or "string" in str(eActions[p]["type"]).lower()
503 ):
Matthew Barth9a5b6992018-01-23 15:32:26 -0600504 param += (
Patrick Williams0f2588f2022-12-05 10:17:03 -0600505 str(eActions[p]["type"]).lower()
506 + '>("'
507 + str(eActions[p])
508 + '")'
509 )
Matthew Barth9a5b6992018-01-23 15:32:26 -0600510 else:
511 param += (
Patrick Williams0f2588f2022-12-05 10:17:03 -0600512 str(eActions[p]["type"]).lower()
513 + ">("
514 + str(eActions[p]["value"]).lower()
515 + ")"
516 )
Matthew Barth9df74752017-10-11 14:39:31 -0500517 else:
518 # Default type to 'size_t' when not given
Patrick Williams0f2588f2022-12-05 10:17:03 -0600519 param += "size_t>(" + str(eActions[p]).lower() + ")"
Matthew Barth9df74752017-10-11 14:39:31 -0500520 else:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600521 if p == "timer":
Matthew Barthd0b90fc2018-03-05 09:38:45 -0600522 t = getTimer(eActions[p])
Matthew Barth9df74752017-10-11 14:39:31 -0500523 param = (
Patrick Williams0f2588f2022-12-05 10:17:03 -0600524 "TimerConf{"
525 + t["interval"]
526 + ","
527 + t["type"]
528 + "}"
529 )
Matthew Barth9df74752017-10-11 14:39:31 -0500530 else:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600531 param += str(eActions[p]["type"]).lower() + ">("
532 if p != "map":
533 if (
534 isinstance(eActions[p]["value"], str)
535 or "string" in str(eActions[p]["type"]).lower()
536 ):
537 param += '"' + str(eActions[p]["value"]) + '")'
Matthew Barth9a5b6992018-01-23 15:32:26 -0600538 else:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600539 param += (
540 str(eActions[p]["value"]).lower() + ")"
541 )
Matthew Barth9df74752017-10-11 14:39:31 -0500542 else:
543 param += (
Patrick Williams0f2588f2022-12-05 10:17:03 -0600544 str(eActions[p]["type"]).lower()
545 + convertToMap(str(eActions[p]["value"]))
546 + ")"
547 )
Matthew Barth9df74752017-10-11 14:39:31 -0500548 params.append(param)
Patrick Williams0f2588f2022-12-05 10:17:03 -0600549 actions["parameters"] = params
Matthew Barth9df74752017-10-11 14:39:31 -0500550 action.append(actions)
551 return action
552
553
Matthew Barth7f272fd2017-09-12 16:16:56 -0500554def getEvent(zone_num, zone_conditions, e, events_data):
555 """
556 Parses the sections of an event and populates the properties
557 that construct an event within the generated source.
558 """
559 event = {}
Matthew Barth7f272fd2017-09-12 16:16:56 -0500560
Matthew Barth621a5772018-11-14 14:55:11 -0600561 # Add set speed event name
Patrick Williams0f2588f2022-12-05 10:17:03 -0600562 event["name"] = e["name"]
Matthew Barth621a5772018-11-14 14:55:11 -0600563
Matthew Barth6c050692017-12-05 15:30:09 -0600564 # Add set speed event groups
Patrick Williams0f2588f2022-12-05 10:17:03 -0600565 event["groups"] = getGroups(zone_num, zone_conditions, e, events_data)
Matthew Barth7f272fd2017-09-12 16:16:56 -0500566
Matthew Barthe3d1c4a2018-01-11 13:53:49 -0600567 # Add optional set speed actions and function parameters
Patrick Williams0f2588f2022-12-05 10:17:03 -0600568 event["action"] = []
569 if ("actions" in e) and (e["actions"] is not None):
Matthew Barth06fa7812018-11-20 09:54:30 -0600570 # List of dicts containing the list of groups and list of actions
571 sseActions = []
572 eActions = getActions(zone_num, zone_conditions, e, e, events_data)
573 for eAction in eActions:
574 # Skip events that have no groups defined for the event or actions
Patrick Williams0f2588f2022-12-05 10:17:03 -0600575 if not event["groups"] and not eAction["groups"]:
Matthew Barth06fa7812018-11-20 09:54:30 -0600576 continue
577 # Find group in sseActions
578 grpExists = False
579 for sseDict in sseActions:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600580 if eAction["groups"] == sseDict["groups"]:
Matthew Barth06fa7812018-11-20 09:54:30 -0600581 # Extend 'actions' list
Patrick Williams0f2588f2022-12-05 10:17:03 -0600582 del eAction["groups"]
583 sseDict["actions"].append(eAction)
Matthew Barth06fa7812018-11-20 09:54:30 -0600584 grpExists = True
585 break
586 if not grpExists:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600587 grps = eAction["groups"]
588 del eAction["groups"]
Matthew Barth06fa7812018-11-20 09:54:30 -0600589 actList = []
590 actList.append(eAction)
Patrick Williams0f2588f2022-12-05 10:17:03 -0600591 sseActions.append({"groups": grps, "actions": actList})
592 event["action"] = sseActions
Matthew Barth7f272fd2017-09-12 16:16:56 -0500593
Matthew Bartha69465a2018-03-02 13:50:59 -0600594 # Add event triggers
Patrick Williams0f2588f2022-12-05 10:17:03 -0600595 event["triggers"] = {}
596 for trig in e["triggers"]:
Matthew Bartha69465a2018-03-02 13:50:59 -0600597 triggers = []
Patrick Williams0f2588f2022-12-05 10:17:03 -0600598 if trig["name"] == "timer":
599 event["triggers"]["timer"] = getTimer(trig)
600 elif trig["name"] == "signal":
601 if "signals" not in event["triggers"]:
602 event["triggers"]["signals"] = []
603 triggers = getSignal(event["groups"], trig, events_data)
604 event["triggers"]["signals"].extend(triggers)
605 elif trig["name"] == "init":
606 triggers = getInit(event["groups"], trig, events_data)
607 event["triggers"]["init"] = triggers
Matthew Barth7f272fd2017-09-12 16:16:56 -0500608
Matthew Barth7f272fd2017-09-12 16:16:56 -0500609 return event
610
611
612def addPrecondition(zNum, zCond, event, events_data):
Matthew Barth9af190c2017-08-08 14:20:43 -0500613 """
614 Parses the precondition section of an event and populates the necessary
615 structures to generate a precondition for a set speed event.
616 """
617 precond = {}
Matthew Barth621a5772018-11-14 14:55:11 -0600618
619 # Add set speed event precondition name
Patrick Williams0f2588f2022-12-05 10:17:03 -0600620 precond["pcname"] = event["name"]
Matthew Barth621a5772018-11-14 14:55:11 -0600621
Matthew Barth9af190c2017-08-08 14:20:43 -0500622 # Add set speed event precondition group
Patrick Williams0f2588f2022-12-05 10:17:03 -0600623 precond["pcgrps"] = getGroups(
624 zNum, zCond, event["precondition"], events_data
625 )
Matthew Barth9af190c2017-08-08 14:20:43 -0500626
Matthew Barth7f272fd2017-09-12 16:16:56 -0500627 # Add set speed event precondition actions
628 pc = []
629 pcs = {}
Patrick Williams0f2588f2022-12-05 10:17:03 -0600630 pcs["name"] = event["precondition"]["name"]
631 epc = next(
632 p
633 for p in events_data["preconditions"]
634 if p["name"] == event["precondition"]["name"]
635 )
Matthew Barth9af190c2017-08-08 14:20:43 -0500636 params = []
Patrick Williams0f2588f2022-12-05 10:17:03 -0600637 for p in epc["parameters"] or []:
Matthew Barth9af190c2017-08-08 14:20:43 -0500638 param = {}
Patrick Williams0f2588f2022-12-05 10:17:03 -0600639 if p == "groups":
640 param["type"] = "std::vector<PrecondGroup>"
641 param["open"] = "{"
642 param["close"] = "}"
Matthew Barth9af190c2017-08-08 14:20:43 -0500643 values = []
Patrick Williams0f2588f2022-12-05 10:17:03 -0600644 for group in precond["pcgrps"]:
645 for pcgrp in group["members"]:
Matthew Barth6c050692017-12-05 15:30:09 -0600646 value = {}
Patrick Williams0f2588f2022-12-05 10:17:03 -0600647 value["value"] = (
648 'PrecondGroup{"'
649 + str(pcgrp["object"])
650 + '","'
651 + str(pcgrp["interface"])
652 + '","'
653 + str(pcgrp["property"])
654 + '",'
655 + "static_cast<"
656 + str(pcgrp["type"]).lower()
657 + ">"
658 )
659 if (
660 isinstance(pcgrp["value"], str)
661 or "string" in str(pcgrp["type"]).lower()
662 ):
663 value["value"] += "(" + str(pcgrp["value"]) + ")}"
Matthew Barth6c050692017-12-05 15:30:09 -0600664 else:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600665 value["value"] += (
666 "(" + str(pcgrp["value"]).lower() + ")}"
667 )
Matthew Barth6c050692017-12-05 15:30:09 -0600668 values.append(value)
Patrick Williams0f2588f2022-12-05 10:17:03 -0600669 param["values"] = values
Matthew Barth9af190c2017-08-08 14:20:43 -0500670 params.append(param)
Patrick Williams0f2588f2022-12-05 10:17:03 -0600671 pcs["params"] = params
Matthew Barth7f272fd2017-09-12 16:16:56 -0500672 pc.append(pcs)
Patrick Williams0f2588f2022-12-05 10:17:03 -0600673 precond["pcact"] = pc
Matthew Barth9af190c2017-08-08 14:20:43 -0500674
Matthew Barth7f272fd2017-09-12 16:16:56 -0500675 pcevents = []
Patrick Williams0f2588f2022-12-05 10:17:03 -0600676 for pce in event["precondition"]["events"]:
Matthew Barth7f272fd2017-09-12 16:16:56 -0500677 pcevent = getEvent(zNum, zCond, pce, events_data)
678 if not pcevent:
679 continue
680 pcevents.append(pcevent)
Patrick Williams0f2588f2022-12-05 10:17:03 -0600681 precond["pcevts"] = pcevents
Matthew Barth7f272fd2017-09-12 16:16:56 -0500682
Matthew Barthf20c3212018-03-02 14:42:55 -0600683 # Add precondition event triggers
Patrick Williams0f2588f2022-12-05 10:17:03 -0600684 precond["triggers"] = {}
685 for trig in event["precondition"]["triggers"]:
Matthew Barthf20c3212018-03-02 14:42:55 -0600686 triggers = []
Patrick Williams0f2588f2022-12-05 10:17:03 -0600687 if trig["name"] == "timer":
688 precond["triggers"]["pctime"] = getTimer(trig)
689 elif trig["name"] == "signal":
690 if "pcsigs" not in precond["triggers"]:
691 precond["triggers"]["pcsigs"] = []
692 triggers = getSignal(precond["pcgrps"], trig, events_data)
693 precond["triggers"]["pcsigs"].extend(triggers)
694 elif trig["name"] == "init":
695 triggers = getInit(precond["pcgrps"], trig, events_data)
696 precond["triggers"]["init"] = triggers
Matthew Barth9af190c2017-08-08 14:20:43 -0500697
698 return precond
699
700
Gunnar Millsb751f322017-06-06 15:14:11 -0500701def getEventsInZone(zone_num, zone_conditions, events_data):
Matthew Barthd4d0f082017-05-16 13:51:10 -0500702 """
703 Constructs the event entries defined for each zone using the events yaml
704 provided.
705 """
706 events = []
Matthew Barthba102b32017-05-16 16:13:56 -0500707
Patrick Williams0f2588f2022-12-05 10:17:03 -0600708 if "events" in events_data:
709 for e in events_data["events"]:
Matthew Barthd4d0f082017-05-16 13:51:10 -0500710 event = {}
Matthew Barth621a5772018-11-14 14:55:11 -0600711
Matthew Barth9af190c2017-08-08 14:20:43 -0500712 # Add precondition if given
Patrick Williams0f2588f2022-12-05 10:17:03 -0600713 if ("precondition" in e) and (e["precondition"] is not None):
714 event["pc"] = addPrecondition(
715 zone_num, zone_conditions, e, events_data
716 )
Matthew Barth90149802017-08-15 10:51:37 -0500717 else:
Matthew Barth7f272fd2017-09-12 16:16:56 -0500718 event = getEvent(zone_num, zone_conditions, e, events_data)
Matthew Bartha6f75162018-11-20 13:50:42 -0600719 # Remove empty events and events that have
720 # no groups defined for the event or any of the actions
Patrick Williams0f2588f2022-12-05 10:17:03 -0600721 if not event or (
722 not event["groups"]
723 and all(not a["groups"] for a in event["action"])
724 ):
Matthew Barth7f272fd2017-09-12 16:16:56 -0500725 continue
Matthew Barthd4d0f082017-05-16 13:51:10 -0500726 events.append(event)
727
728 return events
729
730
Matt Spinler78498c92017-04-11 13:59:46 -0500731def getFansInZone(zone_num, profiles, fan_data):
732 """
733 Parses the fan definition YAML files to find the fans
734 that match both the zone passed in and one of the
735 cooling profiles.
736 """
737
738 fans = []
739
Patrick Williams0f2588f2022-12-05 10:17:03 -0600740 for f in fan_data["fans"]:
741 if zone_num != f["cooling_zone"]:
Matt Spinler78498c92017-04-11 13:59:46 -0500742 continue
743
Gunnar Mills67e95512017-06-02 14:35:18 -0500744 # 'cooling_profile' is optional (use 'all' instead)
Patrick Williams0f2588f2022-12-05 10:17:03 -0600745 if f.get("cooling_profile") is None:
Matt Spinler78498c92017-04-11 13:59:46 -0500746 profile = "all"
747 else:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600748 profile = f["cooling_profile"]
Matt Spinler78498c92017-04-11 13:59:46 -0500749
750 if profile not in profiles:
751 continue
752
753 fan = {}
Patrick Williams0f2588f2022-12-05 10:17:03 -0600754 fan["name"] = f["inventory"]
755 fan["sensors"] = f["sensors"]
756 fan["target_interface"] = f.get(
757 "target_interface", "xyz.openbmc_project.Control.FanSpeed"
758 )
759 fan["target_path"] = f.get(
760 "target_path", "/xyz/openbmc_project/sensors/fan_tach/"
761 )
Matt Spinler78498c92017-04-11 13:59:46 -0500762 fans.append(fan)
763
764 return fans
765
766
Matthew Barth7883f582019-02-14 14:24:46 -0600767def getIfacesInZone(zone_ifaces):
768 """
769 Parse given interfaces for a zone for associating a zone with an interface
770 and set any properties listed to defined values upon fan control starting
771 on the zone.
772 """
773
774 ifaces = []
775 for i in zone_ifaces:
776 iface = {}
777 # Interface name not needed yet for fan zones but
778 # may be necessary as more interfaces are extended by the zones
Patrick Williams0f2588f2022-12-05 10:17:03 -0600779 iface["name"] = i["name"]
Matthew Barth7883f582019-02-14 14:24:46 -0600780
Patrick Williams0f2588f2022-12-05 10:17:03 -0600781 if ("properties" in i) and (i["properties"] is not None):
Matthew Barth7883f582019-02-14 14:24:46 -0600782 props = []
Patrick Williams0f2588f2022-12-05 10:17:03 -0600783 for p in i["properties"]:
Matthew Barth7883f582019-02-14 14:24:46 -0600784 prop = {}
Patrick Williams0f2588f2022-12-05 10:17:03 -0600785 prop["name"] = p["name"]
786 prop["func"] = str(p["name"]).lower()
787 prop["type"] = parse_cpp_type(p["type"])
788 if "persist" in p:
789 persist = p["persist"]
790 if persist is not None:
791 if isinstance(persist, bool):
792 prop["persist"] = "true" if persist else "false"
Matthew Barth59096e52019-02-18 12:23:38 -0600793 else:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600794 prop["persist"] = "false"
Matthew Barth7883f582019-02-14 14:24:46 -0600795 vals = []
Patrick Williams0f2588f2022-12-05 10:17:03 -0600796 for v in p["values"]:
797 val = v["value"]
798 if val is not None:
799 if isinstance(val, bool):
Matthew Barth7883f582019-02-14 14:24:46 -0600800 # Convert True/False to 'true'/'false'
Patrick Williams0f2588f2022-12-05 10:17:03 -0600801 val = "true" if val else "false"
802 elif isinstance(val, str):
Matthew Barth7883f582019-02-14 14:24:46 -0600803 # Wrap strings with double-quotes
Patrick Williams0f2588f2022-12-05 10:17:03 -0600804 val = '"' + val + '"'
Matthew Barth7883f582019-02-14 14:24:46 -0600805 vals.append(val)
Patrick Williams0f2588f2022-12-05 10:17:03 -0600806 prop["values"] = vals
Matthew Barth7883f582019-02-14 14:24:46 -0600807 props.append(prop)
Patrick Williams0f2588f2022-12-05 10:17:03 -0600808 iface["props"] = props
Matthew Barth7883f582019-02-14 14:24:46 -0600809 ifaces.append(iface)
810
811 return ifaces
812
813
Gunnar Millsee8a2812017-06-02 14:26:47 -0500814def getConditionInZoneConditions(zone_condition, zone_conditions_data):
815 """
816 Parses the zone conditions definition YAML files to find the condition
817 that match both the zone condition passed in.
818 """
819
820 condition = {}
821
Patrick Williams0f2588f2022-12-05 10:17:03 -0600822 for c in zone_conditions_data["conditions"]:
823 if zone_condition != c["name"]:
Gunnar Millsee8a2812017-06-02 14:26:47 -0500824 continue
Patrick Williams0f2588f2022-12-05 10:17:03 -0600825 condition["type"] = c["type"]
Gunnar Millsee8a2812017-06-02 14:26:47 -0500826 properties = []
Patrick Williams0f2588f2022-12-05 10:17:03 -0600827 for p in c["properties"]:
Gunnar Millsee8a2812017-06-02 14:26:47 -0500828 property = {}
Patrick Williams0f2588f2022-12-05 10:17:03 -0600829 property["property"] = p["property"]
830 property["interface"] = p["interface"]
831 property["path"] = p["path"]
832 property["type"] = p["type"].lower()
833 property["value"] = str(p["value"]).lower()
Gunnar Millsee8a2812017-06-02 14:26:47 -0500834 properties.append(property)
Patrick Williams0f2588f2022-12-05 10:17:03 -0600835 condition["properties"] = properties
Gunnar Millsee8a2812017-06-02 14:26:47 -0500836
837 return condition
838
839
840def buildZoneData(zone_data, fan_data, events_data, zone_conditions_data):
Matt Spinler78498c92017-04-11 13:59:46 -0500841 """
842 Combines the zone definition YAML and fan
843 definition YAML to create a data structure defining
844 the fan cooling zones.
845 """
846
847 zone_groups = []
848
Matthew Barth005ff2f2020-02-18 11:17:41 -0600849 # Allow zone_conditions to not be in yaml (since its optional)
850 if not isinstance(zone_data, list) and zone_data != {}:
851 zone_data = [zone_data]
Matt Spinler78498c92017-04-11 13:59:46 -0500852 for group in zone_data:
853 conditions = []
Gunnar Millsee8a2812017-06-02 14:26:47 -0500854 # zone conditions are optional
Patrick Williams0f2588f2022-12-05 10:17:03 -0600855 if "zone_conditions" in group and group["zone_conditions"] is not None:
856 for c in group["zone_conditions"]:
Gunnar Millsee8a2812017-06-02 14:26:47 -0500857 if not zone_conditions_data:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600858 sys.exit(
859 "No zone_conditions YAML file but "
860 + "zone_conditions used in zone YAML"
861 )
Gunnar Millsee8a2812017-06-02 14:26:47 -0500862
Patrick Williams0f2588f2022-12-05 10:17:03 -0600863 condition = getConditionInZoneConditions(
864 c["name"], zone_conditions_data
865 )
Gunnar Millsee8a2812017-06-02 14:26:47 -0500866
867 if not condition:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600868 sys.exit("Missing zone condition " + c["name"])
Gunnar Millsee8a2812017-06-02 14:26:47 -0500869
870 conditions.append(condition)
Matt Spinler78498c92017-04-11 13:59:46 -0500871
872 zone_group = {}
Patrick Williams0f2588f2022-12-05 10:17:03 -0600873 zone_group["conditions"] = conditions
Matt Spinler78498c92017-04-11 13:59:46 -0500874
875 zones = []
Patrick Williams0f2588f2022-12-05 10:17:03 -0600876 for z in group["zones"]:
Matt Spinler78498c92017-04-11 13:59:46 -0500877 zone = {}
878
Gunnar Mills67e95512017-06-02 14:35:18 -0500879 # 'zone' is required
Patrick Williams0f2588f2022-12-05 10:17:03 -0600880 if ("zone" not in z) or (z["zone"] is None):
881 sys.exit("Missing fan zone number in " + z)
Matt Spinler78498c92017-04-11 13:59:46 -0500882
Patrick Williams0f2588f2022-12-05 10:17:03 -0600883 zone["num"] = z["zone"]
Matt Spinler78498c92017-04-11 13:59:46 -0500884
Patrick Williams0f2588f2022-12-05 10:17:03 -0600885 zone["full_speed"] = z["full_speed"]
Matt Spinler78498c92017-04-11 13:59:46 -0500886
Patrick Williams0f2588f2022-12-05 10:17:03 -0600887 zone["default_floor"] = z["default_floor"]
Matthew Barth1de66622017-06-12 13:13:02 -0500888
Matthew Bartha9561842017-06-29 11:43:45 -0500889 # 'increase_delay' is optional (use 0 by default)
Patrick Williams0f2588f2022-12-05 10:17:03 -0600890 key = "increase_delay"
Matthew Bartha9561842017-06-29 11:43:45 -0500891 zone[key] = z.setdefault(key, 0)
892
893 # 'decrease_interval' is optional (use 0 by default)
Patrick Williams0f2588f2022-12-05 10:17:03 -0600894 key = "decrease_interval"
Matthew Bartha9561842017-06-29 11:43:45 -0500895 zone[key] = z.setdefault(key, 0)
896
Gunnar Mills67e95512017-06-02 14:35:18 -0500897 # 'cooling_profiles' is optional (use 'all' instead)
Patrick Williams0f2588f2022-12-05 10:17:03 -0600898 if ("cooling_profiles" not in z) or (
899 z["cooling_profiles"] is None
900 ):
Matt Spinler78498c92017-04-11 13:59:46 -0500901 profiles = ["all"]
902 else:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600903 profiles = z["cooling_profiles"]
Matt Spinler78498c92017-04-11 13:59:46 -0500904
Matthew Barth7883f582019-02-14 14:24:46 -0600905 # 'interfaces' is optional (no default)
Matthew Barth64099cd2019-02-18 09:43:12 -0600906 ifaces = []
Patrick Williams0f2588f2022-12-05 10:17:03 -0600907 if ("interfaces" in z) and (z["interfaces"] is not None):
908 ifaces = getIfacesInZone(z["interfaces"])
Matthew Barth7883f582019-02-14 14:24:46 -0600909
Patrick Williams0f2588f2022-12-05 10:17:03 -0600910 fans = getFansInZone(z["zone"], profiles, fan_data)
911 events = getEventsInZone(
912 z["zone"], group.get("zone_conditions", {}), events_data
913 )
Matt Spinler78498c92017-04-11 13:59:46 -0500914
915 if len(fans) == 0:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600916 sys.exit("Didn't find any fans in zone " + str(zone["num"]))
Matt Spinler78498c92017-04-11 13:59:46 -0500917
Patrick Williams0f2588f2022-12-05 10:17:03 -0600918 if ifaces:
919 zone["ifaces"] = ifaces
920 zone["fans"] = fans
921 zone["events"] = events
Matt Spinler78498c92017-04-11 13:59:46 -0500922 zones.append(zone)
923
Patrick Williams0f2588f2022-12-05 10:17:03 -0600924 zone_group["zones"] = zones
Matt Spinler78498c92017-04-11 13:59:46 -0500925 zone_groups.append(zone_group)
926
927 return zone_groups
928
929
Patrick Williams0f2588f2022-12-05 10:17:03 -0600930if __name__ == "__main__":
931 parser = ArgumentParser(description="Phosphor fan zone definition parser")
Matt Spinlerd08dbe22017-04-11 13:52:54 -0500932
Patrick Williams0f2588f2022-12-05 10:17:03 -0600933 parser.add_argument(
934 "-z",
935 "--zone_yaml",
936 dest="zone_yaml",
937 default="example/zones.yaml",
938 help="fan zone definitional yaml",
939 )
940 parser.add_argument(
941 "-f",
942 "--fan_yaml",
943 dest="fan_yaml",
944 default="example/fans.yaml",
945 help="fan definitional yaml",
946 )
947 parser.add_argument(
948 "-e",
949 "--events_yaml",
950 dest="events_yaml",
951 help="events to set speeds yaml",
952 )
953 parser.add_argument(
954 "-c",
955 "--zone_conditions_yaml",
956 dest="zone_conditions_yaml",
957 help="conditions to determine zone yaml",
958 )
959 parser.add_argument(
960 "-o",
961 "--output_dir",
962 dest="output_dir",
963 default=".",
964 help="output directory",
965 )
Matt Spinlerd08dbe22017-04-11 13:52:54 -0500966 args = parser.parse_args()
967
968 if not args.zone_yaml or not args.fan_yaml:
969 parser.print_usage()
William A. Kennington III3e781062018-10-19 17:18:34 -0700970 sys.exit(1)
Matt Spinlerd08dbe22017-04-11 13:52:54 -0500971
Patrick Williams0f2588f2022-12-05 10:17:03 -0600972 with open(args.zone_yaml, "r") as zone_input:
Matt Spinlerd08dbe22017-04-11 13:52:54 -0500973 zone_data = yaml.safe_load(zone_input) or {}
974
Patrick Williams0f2588f2022-12-05 10:17:03 -0600975 with open(args.fan_yaml, "r") as fan_input:
Matt Spinlerd08dbe22017-04-11 13:52:54 -0500976 fan_data = yaml.safe_load(fan_input) or {}
977
Matthew Barthd4d0f082017-05-16 13:51:10 -0500978 events_data = {}
979 if args.events_yaml:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600980 with open(args.events_yaml, "r") as events_input:
Matthew Barthd4d0f082017-05-16 13:51:10 -0500981 events_data = yaml.safe_load(events_input) or {}
982
Gunnar Millsee8a2812017-06-02 14:26:47 -0500983 zone_conditions_data = {}
984 if args.zone_conditions_yaml:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600985 with open(args.zone_conditions_yaml, "r") as zone_conditions_input:
Gunnar Millsee8a2812017-06-02 14:26:47 -0500986 zone_conditions_data = yaml.safe_load(zone_conditions_input) or {}
987
Patrick Williams0f2588f2022-12-05 10:17:03 -0600988 zone_config = buildZoneData(
989 zone_data.get("zone_configuration", {}),
990 fan_data,
991 events_data,
992 zone_conditions_data,
993 )
Matt Spinleree7f6422017-05-09 11:03:14 -0500994
Patrick Williams0f2588f2022-12-05 10:17:03 -0600995 manager_config = zone_data.get("manager_configuration", {})
Matt Spinleree7f6422017-05-09 11:03:14 -0500996
Patrick Williams0f2588f2022-12-05 10:17:03 -0600997 if manager_config.get("power_on_delay") is None:
998 manager_config["power_on_delay"] = 0
Matt Spinlerd08dbe22017-04-11 13:52:54 -0500999
Matthew Barth702c4a52018-02-28 16:23:11 -06001000 tmpls_dir = os.path.join(
Patrick Williams0f2588f2022-12-05 10:17:03 -06001001 os.path.dirname(os.path.realpath(__file__)), "templates"
1002 )
Matt Spinlerd08dbe22017-04-11 13:52:54 -05001003 output_file = os.path.join(args.output_dir, "fan_zone_defs.cpp")
Matthew Barth702c4a52018-02-28 16:23:11 -06001004 if sys.version_info < (3, 0):
1005 lkup = TemplateLookup(
Patrick Williams0f2588f2022-12-05 10:17:03 -06001006 directories=tmpls_dir.split(), disable_unicode=True
1007 )
Matthew Barth702c4a52018-02-28 16:23:11 -06001008 else:
Patrick Williams0f2588f2022-12-05 10:17:03 -06001009 lkup = TemplateLookup(directories=tmpls_dir.split())
1010 tmpl = lkup.get_template("fan_zone_defs.mako.cpp")
1011 with open(output_file, "w") as output:
1012 output.write(tmpl.render(zones=zone_config, mgr_data=manager_config))