blob: aa9ead0e6ad4f0ca1514cbecc8075b3088065e5d [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
Matt Spinlerd08dbe22017-04-11 13:52:54 -050010from argparse import ArgumentParser
Patrick Williamsc7f68be2022-12-08 06:18:00 -060011
12import yaml
Matthew Barth702c4a52018-02-28 16:23:11 -060013from mako.lookup import TemplateLookup
Matt Spinlerd08dbe22017-04-11 13:52:54 -050014
Matt Spinler78498c92017-04-11 13:59:46 -050015
Matthew Barth7883f582019-02-14 14:24:46 -060016def parse_cpp_type(typeName):
17 """
18 Take a list of dbus types from YAML and convert it to a recursive cpp
19 formed data structure. Each entry of the original list gets converted
20 into a tuple consisting of the type name and a list with the params
21 for this type,
22 e.g.
23 ['dict', ['string', 'dict', ['string', 'int64']]]
24 is converted to
25 [('dict', [('string', []), ('dict', [('string', []),
26 ('int64', [])]]]
27 """
28
29 if not typeName:
30 return None
31
32 # Type names are _almost_ valid YAML. Insert a , before each [
33 # and then wrap it in a [ ] and it becomes valid YAML (assuming
34 # the user gave us a valid typename).
35 typeArray = yaml.safe_load("[" + ",[".join(typeName.split("[")) + "]")
36 typeTuple = preprocess_yaml_type_array(typeArray).pop(0)
37 return get_cpp_type(typeTuple)
38
39
40def preprocess_yaml_type_array(typeArray):
41 """
42 Flattens an array type into a tuple list that can be used to get the
43 supported cpp type from each element.
44 """
45
46 result = []
47
48 for i in range(len(typeArray)):
49 # Ignore lists because we merge them with the previous element
50 if type(typeArray[i]) is list:
51 continue
52
53 # If there is a next element and it is a list, merge it with the
54 # current element.
Patrick Williams0f2588f2022-12-05 10:17:03 -060055 if i < len(typeArray) - 1 and type(typeArray[i + 1]) is list:
Matthew Barth7883f582019-02-14 14:24:46 -060056 result.append(
Patrick Williams0f2588f2022-12-05 10:17:03 -060057 (typeArray[i], preprocess_yaml_type_array(typeArray[i + 1]))
58 )
Matthew Barth7883f582019-02-14 14:24:46 -060059 else:
60 result.append((typeArray[i], []))
61
62 return result
63
64
65def get_cpp_type(typeTuple):
66 """
67 Take a list of dbus types and perform validity checking, such as:
68 [ variant [ dict [ int32, int32 ], double ] ]
69 This function then converts the type-list into a C++ type string.
70 """
71
72 propertyMap = {
Patrick Williams0f2588f2022-12-05 10:17:03 -060073 "byte": {"cppName": "uint8_t", "params": 0},
74 "boolean": {"cppName": "bool", "params": 0},
75 "int16": {"cppName": "int16_t", "params": 0},
76 "uint16": {"cppName": "uint16_t", "params": 0},
77 "int32": {"cppName": "int32_t", "params": 0},
78 "uint32": {"cppName": "uint32_t", "params": 0},
79 "int64": {"cppName": "int64_t", "params": 0},
80 "uint64": {"cppName": "uint64_t", "params": 0},
81 "double": {"cppName": "double", "params": 0},
82 "string": {"cppName": "std::string", "params": 0},
83 "array": {"cppName": "std::vector", "params": 1},
84 "dict": {"cppName": "std::map", "params": 2},
85 }
Matthew Barth7883f582019-02-14 14:24:46 -060086
87 if len(typeTuple) != 2:
88 raise RuntimeError("Invalid typeTuple %s" % typeTuple)
89
90 first = typeTuple[0]
91 entry = propertyMap[first]
92
Patrick Williams0f2588f2022-12-05 10:17:03 -060093 result = entry["cppName"]
Matthew Barth7883f582019-02-14 14:24:46 -060094
95 # Handle 0-entry parameter lists.
Patrick Williams0f2588f2022-12-05 10:17:03 -060096 if entry["params"] == 0:
97 if len(typeTuple[1]) != 0:
Matthew Barth7883f582019-02-14 14:24:46 -060098 raise RuntimeError("Invalid typeTuple %s" % typeTuple)
99 else:
100 return result
101
102 # Get the parameter list
103 rest = typeTuple[1]
104
105 # Confirm parameter count matches.
Patrick Williams0f2588f2022-12-05 10:17:03 -0600106 if (entry["params"] != -1) and (entry["params"] != len(rest)):
107 raise RuntimeError("Invalid entry count for %s : %s" % (first, rest))
Matthew Barth7883f582019-02-14 14:24:46 -0600108
109 # Parse each parameter entry, if appropriate, and create C++ template
110 # syntax.
Patrick Williams0f2588f2022-12-05 10:17:03 -0600111 result += "<"
112 if entry.get("noparse"):
Matthew Barth7883f582019-02-14 14:24:46 -0600113 # Do not parse the parameter list, just use the first element
114 # of each tuple and ignore possible parameters
115 result += ", ".join([e[0] for e in rest])
116 else:
Matthew Barth867a31c2020-02-13 13:13:44 -0600117 result += ", ".join([get_cpp_type(e) for e in rest])
Patrick Williams0f2588f2022-12-05 10:17:03 -0600118 result += ">"
Matthew Barth7883f582019-02-14 14:24:46 -0600119
120 return result
121
122
Matthew Barthbb12c922017-06-13 13:57:40 -0500123def convertToMap(listOfDict):
124 """
125 Converts a list of dictionary entries to a std::map initialization list.
126 """
Patrick Williams0f2588f2022-12-05 10:17:03 -0600127 listOfDict = listOfDict.replace("'", '"')
128 listOfDict = listOfDict.replace("[", "{")
129 listOfDict = listOfDict.replace("]", "}")
130 listOfDict = listOfDict.replace(":", ",")
Matthew Barthbb12c922017-06-13 13:57:40 -0500131 return listOfDict
132
133
Matthew Bartha1aef7a2019-01-16 11:02:57 -0600134def genEvent(event):
135 """
136 Generates the source code of an event and returns it as a string
137 """
138 e = "SetSpeedEvent{\n"
Patrick Williams0f2588f2022-12-05 10:17:03 -0600139 e += '"' + event["name"] + '",\n'
Matthew Bartha1aef7a2019-01-16 11:02:57 -0600140 e += "Group{\n"
Patrick Williams0f2588f2022-12-05 10:17:03 -0600141 for group in event["groups"]:
142 for member in group["members"]:
143 e += '{"' + member["object"] + '",\n'
144 e += '"' + member["interface"] + '",\n'
145 e += '"' + member["property"] + '"},\n'
Matthew Bartha1aef7a2019-01-16 11:02:57 -0600146 e += "},\n"
147
Matthew Barth06fa7812018-11-20 09:54:30 -0600148 e += "ActionData{\n"
Patrick Williams0f2588f2022-12-05 10:17:03 -0600149 for d in event["action"]:
Matthew Barth06fa7812018-11-20 09:54:30 -0600150 e += "{Group{\n"
Patrick Williams0f2588f2022-12-05 10:17:03 -0600151 for g in d["groups"]:
152 for m in g["members"]:
153 e += '{"' + m["object"] + '",\n'
154 e += '"' + m["interface"] + '",\n'
155 e += '"' + m["property"] + '"},\n'
Matthew Barth06fa7812018-11-20 09:54:30 -0600156 e += "},\n"
157 e += "std::vector<Action>{\n"
Patrick Williams0f2588f2022-12-05 10:17:03 -0600158 for a in d["actions"]:
159 if len(a["parameters"]) != 0:
160 e += "make_action(action::" + a["name"] + "(\n"
Matthew Barth8a697b62018-12-14 13:23:47 -0600161 else:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600162 e += "make_action(action::" + a["name"] + "\n"
163 for i, p in enumerate(a["parameters"]):
164 if (i + 1) != len(a["parameters"]):
Matthew Barth06fa7812018-11-20 09:54:30 -0600165 e += p + ",\n"
166 else:
167 e += p + "\n"
Patrick Williams0f2588f2022-12-05 10:17:03 -0600168 if len(a["parameters"]) != 0:
Matthew Barth8a697b62018-12-14 13:23:47 -0600169 e += ")),\n"
170 else:
171 e += "),\n"
Matthew Barth06fa7812018-11-20 09:54:30 -0600172 e += "}},\n"
173 e += "},\n"
Matthew Bartha1aef7a2019-01-16 11:02:57 -0600174
Matthew Barth1b4de262018-03-06 13:03:16 -0600175 e += "std::vector<Trigger>{\n"
Patrick Williams0f2588f2022-12-05 10:17:03 -0600176 if ("timer" in event["triggers"]) and (
177 event["triggers"]["timer"] is not None
178 ):
179 e += "\tmake_trigger(trigger::timer(TimerConf{\n"
180 e += "\t" + event["triggers"]["timer"]["interval"] + ",\n"
181 e += "\t" + event["triggers"]["timer"]["type"] + "\n"
182 e += "\t})),\n"
Matthew Bartha1aef7a2019-01-16 11:02:57 -0600183
Patrick Williams0f2588f2022-12-05 10:17:03 -0600184 if ("signals" in event["triggers"]) and (
185 event["triggers"]["signals"] is not None
186 ):
187 for s in event["triggers"]["signals"]:
Matthew Barth016bd242018-03-07 16:06:06 -0600188 e += "\tmake_trigger(trigger::signal(\n"
Patrick Williams0f2588f2022-12-05 10:17:03 -0600189 e += "match::" + s["match"] + "(\n"
190 for i, mp in enumerate(s["mparams"]["params"]):
191 if (i + 1) != len(s["mparams"]["params"]):
192 e += "\t\t\t" + s["mparams"][mp] + ",\n"
Matthew Barth016bd242018-03-07 16:06:06 -0600193 else:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600194 e += "\t\t\t" + s["mparams"][mp] + "\n"
Matthew Barth926df662018-10-09 09:51:12 -0500195 e += "\t\t),\n"
196 e += "\t\tmake_handler<SignalHandler>(\n"
Patrick Williams0f2588f2022-12-05 10:17:03 -0600197 if ("type" in s["sparams"]) and (s["sparams"]["type"] is not None):
198 e += s["signal"] + "<" + s["sparams"]["type"] + ">(\n"
Matthew Bartha1aef7a2019-01-16 11:02:57 -0600199 else:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600200 e += s["signal"] + "(\n"
201 for sp in s["sparams"]["params"]:
202 e += s["sparams"][sp] + ",\n"
203 if ("type" in s["hparams"]) and (s["hparams"]["type"] is not None):
204 e += (
205 "handler::"
206 + s["handler"]
207 + "<"
208 + s["hparams"]["type"]
209 + ">(\n"
210 )
Matthew Bartha1aef7a2019-01-16 11:02:57 -0600211 else:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600212 e += "handler::" + s["handler"] + "(\n)"
213 for i, hp in enumerate(s["hparams"]["params"]):
214 if (i + 1) != len(s["hparams"]["params"]):
215 e += s["hparams"][hp] + ",\n"
Matthew Barth016bd242018-03-07 16:06:06 -0600216 else:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600217 e += s["hparams"][hp] + "\n"
Matthew Barth016bd242018-03-07 16:06:06 -0600218 e += "))\n"
Matthew Barth926df662018-10-09 09:51:12 -0500219 e += "\t\t)\n"
Matthew Barth016bd242018-03-07 16:06:06 -0600220 e += "\t)),\n"
221
Patrick Williams0f2588f2022-12-05 10:17:03 -0600222 if "init" in event["triggers"]:
223 for i in event["triggers"]["init"]:
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600224 e += "\tmake_trigger(trigger::init(\n"
Patrick Williams0f2588f2022-12-05 10:17:03 -0600225 if "method" in i:
Matthew Barth926df662018-10-09 09:51:12 -0500226 e += "\t\tmake_handler<MethodHandler>(\n"
Patrick Williams0f2588f2022-12-05 10:17:03 -0600227 if ("type" in i["mparams"]) and (
228 i["mparams"]["type"] is not None
229 ):
230 e += i["method"] + "<" + i["mparams"]["type"] + ">(\n"
Matthew Barth926df662018-10-09 09:51:12 -0500231 else:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600232 e += i["method"] + "(\n"
233 for ip in i["mparams"]["params"]:
234 e += i["mparams"][ip] + ",\n"
235 if ("type" in i["hparams"]) and (
236 i["hparams"]["type"] is not None
237 ):
238 e += (
239 "handler::"
240 + i["handler"]
241 + "<"
242 + i["hparams"]["type"]
243 + ">(\n"
244 )
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600245 else:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600246 e += "handler::" + i["handler"] + "(\n)"
247 for i, hp in enumerate(i["hparams"]["params"]):
248 if (i + 1) != len(i["hparams"]["params"]):
249 e += i["hparams"][hp] + ",\n"
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600250 else:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600251 e += i["hparams"][hp] + "\n"
Matthew Barth926df662018-10-09 09:51:12 -0500252 e += "))\n"
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600253 e += "\t\t)\n"
254 e += "\t)),\n"
255
Matthew Bartha1aef7a2019-01-16 11:02:57 -0600256 e += "},\n"
Matthew Bartha1aef7a2019-01-16 11:02:57 -0600257
258 e += "}"
259
260 return e
261
262
Matthew Barth6c050692017-12-05 15:30:09 -0600263def getGroups(zNum, zCond, edata, events):
264 """
265 Extract and construct the groups for the given event.
266 """
267 groups = []
Patrick Williams0f2588f2022-12-05 10:17:03 -0600268 if ("groups" in edata) and (edata["groups"] is not None):
269 for eGroups in edata["groups"]:
270 if ("zone_conditions" in eGroups) and (
271 eGroups["zone_conditions"] is not None
272 ):
Matthew Barthf7e1cb32018-11-19 11:19:09 -0600273 # Zone conditions are optional in the events yaml but skip
274 # if this event's condition is not in this zone's conditions
Patrick Williams0f2588f2022-12-05 10:17:03 -0600275 if all(
276 "name" in z
277 and z["name"] is not None
278 and not any(c["name"] == z["name"] for c in zCond)
279 for z in eGroups["zone_conditions"]
280 ):
Matthew Barthf7e1cb32018-11-19 11:19:09 -0600281 continue
Matthew Barth6c050692017-12-05 15:30:09 -0600282
Matthew Barthf7e1cb32018-11-19 11:19:09 -0600283 # Zone numbers are optional in the events yaml but skip if this
284 # zone's zone number is not in the event's zone numbers
Patrick Williams0f2588f2022-12-05 10:17:03 -0600285 if all(
286 "zones" in z
287 and z["zones"] is not None
288 and zNum not in z["zones"]
289 for z in eGroups["zone_conditions"]
290 ):
Matthew Barthf7e1cb32018-11-19 11:19:09 -0600291 continue
Patrick Williams0f2588f2022-12-05 10:17:03 -0600292 eGroup = next(
293 g for g in events["groups"] if g["name"] == eGroups["name"]
294 )
Matthew Barth6c050692017-12-05 15:30:09 -0600295
Matthew Barthf7e1cb32018-11-19 11:19:09 -0600296 group = {}
297 members = []
Patrick Williams0f2588f2022-12-05 10:17:03 -0600298 group["name"] = eGroup["name"]
299 for m in eGroup["members"]:
Matthew Barthf7e1cb32018-11-19 11:19:09 -0600300 member = {}
Patrick Williams0f2588f2022-12-05 10:17:03 -0600301 member["path"] = eGroup["type"]
302 member["object"] = eGroup["type"] + m
303 member["interface"] = eGroups["interface"]
304 member["property"] = eGroups["property"]["name"]
305 member["type"] = eGroups["property"]["type"]
Matthew Barthf7e1cb32018-11-19 11:19:09 -0600306 # Use defined service to note member on zone object
Patrick Williams0f2588f2022-12-05 10:17:03 -0600307 if ("service" in eGroup) and (eGroup["service"] is not None):
308 member["service"] = eGroup["service"]
Matthew Barthf7e1cb32018-11-19 11:19:09 -0600309 # Add expected group member's property value if given
Patrick Williams0f2588f2022-12-05 10:17:03 -0600310 if ("value" in eGroups["property"]) and (
311 eGroups["property"]["value"] is not None
312 ):
313 if (
314 isinstance(eGroups["property"]["value"], str)
315 or "string" in str(member["type"]).lower()
316 ):
317 member["value"] = (
318 '"' + eGroups["property"]["value"] + '"'
319 )
320 else:
321 member["value"] = eGroups["property"]["value"]
Matthew Barthf7e1cb32018-11-19 11:19:09 -0600322 members.append(member)
Patrick Williams0f2588f2022-12-05 10:17:03 -0600323 group["members"] = members
Matthew Barthf7e1cb32018-11-19 11:19:09 -0600324 groups.append(group)
Matthew Barth6c050692017-12-05 15:30:09 -0600325 return groups
326
327
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600328def getParameters(member, groups, section, events):
Matthew Barth73379f92018-03-15 11:37:10 -0500329 """
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600330 Extracts and constructs a section's parameters
Matthew Barth73379f92018-03-15 11:37:10 -0500331 """
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600332 params = {}
Patrick Williams0f2588f2022-12-05 10:17:03 -0600333 if ("parameters" in section) and (section["parameters"] is not None):
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600334 plist = []
Patrick Williams0f2588f2022-12-05 10:17:03 -0600335 for sp in section["parameters"]:
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600336 p = str(sp)
Patrick Williams0f2588f2022-12-05 10:17:03 -0600337 if p != "type":
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600338 plist.append(p)
Patrick Williams0f2588f2022-12-05 10:17:03 -0600339 if p != "group":
340 params[p] = '"' + member[p] + '"'
Matthew Barth73379f92018-03-15 11:37:10 -0500341 else:
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600342 params[p] = "Group\n{\n"
343 for g in groups:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600344 for m in g["members"]:
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600345 params[p] += (
Patrick Williams0f2588f2022-12-05 10:17:03 -0600346 '{"'
347 + str(m["object"])
348 + '",\n'
349 + '"'
350 + str(m["interface"])
351 + '",\n'
352 + '"'
353 + str(m["property"])
354 + '"},\n'
355 )
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600356 params[p] += "}"
Matthew Barth73379f92018-03-15 11:37:10 -0500357 else:
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600358 params[p] = member[p]
Patrick Williams0f2588f2022-12-05 10:17:03 -0600359 params["params"] = plist
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600360 else:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600361 params["params"] = []
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600362 return params
363
364
365def getInit(eGrps, eTrig, events):
366 """
367 Extracts and constructs an init trigger for the event's groups
368 which are required to be of the same type.
369 """
370 method = {}
371 methods = []
Patrick Williams0f2588f2022-12-05 10:17:03 -0600372 if len(eGrps) > 0:
Matthew Barth03774012018-10-26 13:25:43 -0500373 # Use the first group member for retrieving the type
Patrick Williams0f2588f2022-12-05 10:17:03 -0600374 member = eGrps[0]["members"][0]
375 if ("method" in eTrig) and (eTrig["method"] is not None):
Matthew Barth03774012018-10-26 13:25:43 -0500376 # Add method parameters
Patrick Williams0f2588f2022-12-05 10:17:03 -0600377 eMethod = next(
378 m for m in events["methods"] if m["name"] == eTrig["method"]
379 )
380 method["method"] = eMethod["name"]
381 method["mparams"] = getParameters(member, eGrps, eMethod, events)
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600382
Matthew Barth03774012018-10-26 13:25:43 -0500383 # Add handler parameters
Patrick Williams0f2588f2022-12-05 10:17:03 -0600384 eHandler = next(
385 h for h in events["handlers"] if h["name"] == eTrig["handler"]
386 )
387 method["handler"] = eHandler["name"]
388 method["hparams"] = getParameters(member, eGrps, eHandler, events)
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600389
390 methods.append(method)
391
392 return methods
Matthew Barth73379f92018-03-15 11:37:10 -0500393
394
Matthew Bartha69465a2018-03-02 13:50:59 -0600395def getSignal(eGrps, eTrig, events):
396 """
397 Extracts and constructs for each group member a signal
398 subscription of each match listed in the trigger.
399 """
400 signals = []
401 for group in eGrps:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600402 for member in group["members"]:
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600403 signal = {}
404 # Add signal parameters
Patrick Williams0f2588f2022-12-05 10:17:03 -0600405 eSignal = next(
406 s for s in events["signals"] if s["name"] == eTrig["signal"]
407 )
408 signal["signal"] = eSignal["name"]
409 signal["sparams"] = getParameters(member, eGrps, eSignal, events)
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600410
411 # If service not given, subscribe to signal match
Patrick Williams0f2588f2022-12-05 10:17:03 -0600412 if "service" not in member:
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600413 # Add signal match parameters
Patrick Williams0f2588f2022-12-05 10:17:03 -0600414 eMatch = next(
415 m
416 for m in events["matches"]
417 if m["name"] == eSignal["match"]
418 )
419 signal["match"] = eMatch["name"]
420 signal["mparams"] = getParameters(
421 member, eGrps, eMatch, events
422 )
Matthew Bartha69465a2018-03-02 13:50:59 -0600423
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600424 # Add handler parameters
Patrick Williams0f2588f2022-12-05 10:17:03 -0600425 eHandler = next(
426 h for h in events["handlers"] if h["name"] == eTrig["handler"]
427 )
428 signal["handler"] = eHandler["name"]
429 signal["hparams"] = getParameters(member, eGrps, eHandler, events)
Matthew Barth73379f92018-03-15 11:37:10 -0500430
Matthew Barthcd3bfbc2018-03-07 16:26:03 -0600431 signals.append(signal)
Matthew Barth73379f92018-03-15 11:37:10 -0500432
Matthew Bartha69465a2018-03-02 13:50:59 -0600433 return signals
434
435
Matthew Barthd0b90fc2018-03-05 09:38:45 -0600436def getTimer(eTrig):
437 """
438 Extracts and constructs the required parameters for an
439 event timer.
440 """
441 timer = {}
Patrick Williams0f2588f2022-12-05 10:17:03 -0600442 timer["interval"] = (
443 "static_cast<std::chrono::microseconds>"
444 + "("
445 + str(eTrig["interval"])
446 + ")"
447 )
448 timer["type"] = "TimerType::" + str(eTrig["type"])
Matthew Barthd0b90fc2018-03-05 09:38:45 -0600449 return timer
450
451
Matthew Bartha1aef7a2019-01-16 11:02:57 -0600452def getActions(zNum, zCond, edata, actions, events):
Matthew Barth9df74752017-10-11 14:39:31 -0500453 """
454 Extracts and constructs the make_action function call for
455 all the actions within the given event.
456 """
457 action = []
Patrick Williams0f2588f2022-12-05 10:17:03 -0600458 for eActions in actions["actions"]:
Matthew Barth9df74752017-10-11 14:39:31 -0500459 actions = {}
Patrick Williams0f2588f2022-12-05 10:17:03 -0600460 eAction = next(
461 a for a in events["actions"] if a["name"] == eActions["name"]
462 )
463 actions["name"] = eAction["name"]
464 actions["groups"] = getGroups(zNum, zCond, eActions, events)
Matthew Barth9df74752017-10-11 14:39:31 -0500465 params = []
Patrick Williams0f2588f2022-12-05 10:17:03 -0600466 if ("parameters" in eAction) and (eAction["parameters"] is not None):
467 for p in eAction["parameters"]:
Matthew Barth9df74752017-10-11 14:39:31 -0500468 param = "static_cast<"
469 if type(eActions[p]) is not dict:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600470 if p == "actions":
Matthew Barth9df74752017-10-11 14:39:31 -0500471 param = "std::vector<Action>{"
Patrick Williams0f2588f2022-12-05 10:17:03 -0600472 pActs = getActions(
473 zNum, zCond, edata, eActions, events
474 )
Matthew Barth9df74752017-10-11 14:39:31 -0500475 for a in pActs:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600476 if len(a["parameters"]) != 0:
Matthew Barth9df74752017-10-11 14:39:31 -0500477 param += (
Patrick Williams0f2588f2022-12-05 10:17:03 -0600478 "make_action(action::" + a["name"] + "(\n"
479 )
480 for i, ap in enumerate(a["parameters"]):
481 if (i + 1) != len(a["parameters"]):
482 param += ap + ","
Matthew Barth9df74752017-10-11 14:39:31 -0500483 else:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600484 param += ap + ")"
Matthew Barth9df74752017-10-11 14:39:31 -0500485 else:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600486 param += "make_action(action::" + a["name"]
Matthew Barth9df74752017-10-11 14:39:31 -0500487 param += "),"
488 param += "}"
Patrick Williams0f2588f2022-12-05 10:17:03 -0600489 elif p == "defevents" or p == "altevents" or p == "events":
Matthew Bartha1aef7a2019-01-16 11:02:57 -0600490 param = "std::vector<SetSpeedEvent>{\n"
491 for i, e in enumerate(eActions[p]):
492 aEvent = getEvent(zNum, zCond, e, events)
493 if not aEvent:
494 continue
Patrick Williams0f2588f2022-12-05 10:17:03 -0600495 if (i + 1) != len(eActions[p]):
Matthew Bartha1aef7a2019-01-16 11:02:57 -0600496 param += genEvent(aEvent) + ",\n"
497 else:
498 param += genEvent(aEvent) + "\n"
499 param += "\t}"
Patrick Williams0f2588f2022-12-05 10:17:03 -0600500 elif p == "property":
501 if (
502 isinstance(eActions[p], str)
503 or "string" in str(eActions[p]["type"]).lower()
504 ):
Matthew Barth9a5b6992018-01-23 15:32:26 -0600505 param += (
Patrick Williams0f2588f2022-12-05 10:17:03 -0600506 str(eActions[p]["type"]).lower()
507 + '>("'
508 + str(eActions[p])
509 + '")'
510 )
Matthew Barth9a5b6992018-01-23 15:32:26 -0600511 else:
512 param += (
Patrick Williams0f2588f2022-12-05 10:17:03 -0600513 str(eActions[p]["type"]).lower()
514 + ">("
515 + str(eActions[p]["value"]).lower()
516 + ")"
517 )
Matthew Barth9df74752017-10-11 14:39:31 -0500518 else:
519 # Default type to 'size_t' when not given
Patrick Williams0f2588f2022-12-05 10:17:03 -0600520 param += "size_t>(" + str(eActions[p]).lower() + ")"
Matthew Barth9df74752017-10-11 14:39:31 -0500521 else:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600522 if p == "timer":
Matthew Barthd0b90fc2018-03-05 09:38:45 -0600523 t = getTimer(eActions[p])
Matthew Barth9df74752017-10-11 14:39:31 -0500524 param = (
Patrick Williams0f2588f2022-12-05 10:17:03 -0600525 "TimerConf{"
526 + t["interval"]
527 + ","
528 + t["type"]
529 + "}"
530 )
Matthew Barth9df74752017-10-11 14:39:31 -0500531 else:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600532 param += str(eActions[p]["type"]).lower() + ">("
533 if p != "map":
534 if (
535 isinstance(eActions[p]["value"], str)
536 or "string" in str(eActions[p]["type"]).lower()
537 ):
538 param += '"' + str(eActions[p]["value"]) + '")'
Matthew Barth9a5b6992018-01-23 15:32:26 -0600539 else:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600540 param += (
541 str(eActions[p]["value"]).lower() + ")"
542 )
Matthew Barth9df74752017-10-11 14:39:31 -0500543 else:
544 param += (
Patrick Williams0f2588f2022-12-05 10:17:03 -0600545 str(eActions[p]["type"]).lower()
546 + convertToMap(str(eActions[p]["value"]))
547 + ")"
548 )
Matthew Barth9df74752017-10-11 14:39:31 -0500549 params.append(param)
Patrick Williams0f2588f2022-12-05 10:17:03 -0600550 actions["parameters"] = params
Matthew Barth9df74752017-10-11 14:39:31 -0500551 action.append(actions)
552 return action
553
554
Matthew Barth7f272fd2017-09-12 16:16:56 -0500555def getEvent(zone_num, zone_conditions, e, events_data):
556 """
557 Parses the sections of an event and populates the properties
558 that construct an event within the generated source.
559 """
560 event = {}
Matthew Barth7f272fd2017-09-12 16:16:56 -0500561
Matthew Barth621a5772018-11-14 14:55:11 -0600562 # Add set speed event name
Patrick Williams0f2588f2022-12-05 10:17:03 -0600563 event["name"] = e["name"]
Matthew Barth621a5772018-11-14 14:55:11 -0600564
Matthew Barth6c050692017-12-05 15:30:09 -0600565 # Add set speed event groups
Patrick Williams0f2588f2022-12-05 10:17:03 -0600566 event["groups"] = getGroups(zone_num, zone_conditions, e, events_data)
Matthew Barth7f272fd2017-09-12 16:16:56 -0500567
Matthew Barthe3d1c4a2018-01-11 13:53:49 -0600568 # Add optional set speed actions and function parameters
Patrick Williams0f2588f2022-12-05 10:17:03 -0600569 event["action"] = []
570 if ("actions" in e) and (e["actions"] is not None):
Matthew Barth06fa7812018-11-20 09:54:30 -0600571 # List of dicts containing the list of groups and list of actions
572 sseActions = []
573 eActions = getActions(zone_num, zone_conditions, e, e, events_data)
574 for eAction in eActions:
575 # Skip events that have no groups defined for the event or actions
Patrick Williams0f2588f2022-12-05 10:17:03 -0600576 if not event["groups"] and not eAction["groups"]:
Matthew Barth06fa7812018-11-20 09:54:30 -0600577 continue
578 # Find group in sseActions
579 grpExists = False
580 for sseDict in sseActions:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600581 if eAction["groups"] == sseDict["groups"]:
Matthew Barth06fa7812018-11-20 09:54:30 -0600582 # Extend 'actions' list
Patrick Williams0f2588f2022-12-05 10:17:03 -0600583 del eAction["groups"]
584 sseDict["actions"].append(eAction)
Matthew Barth06fa7812018-11-20 09:54:30 -0600585 grpExists = True
586 break
587 if not grpExists:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600588 grps = eAction["groups"]
589 del eAction["groups"]
Matthew Barth06fa7812018-11-20 09:54:30 -0600590 actList = []
591 actList.append(eAction)
Patrick Williams0f2588f2022-12-05 10:17:03 -0600592 sseActions.append({"groups": grps, "actions": actList})
593 event["action"] = sseActions
Matthew Barth7f272fd2017-09-12 16:16:56 -0500594
Matthew Bartha69465a2018-03-02 13:50:59 -0600595 # Add event triggers
Patrick Williams0f2588f2022-12-05 10:17:03 -0600596 event["triggers"] = {}
597 for trig in e["triggers"]:
Matthew Bartha69465a2018-03-02 13:50:59 -0600598 triggers = []
Patrick Williams0f2588f2022-12-05 10:17:03 -0600599 if trig["name"] == "timer":
600 event["triggers"]["timer"] = getTimer(trig)
601 elif trig["name"] == "signal":
602 if "signals" not in event["triggers"]:
603 event["triggers"]["signals"] = []
604 triggers = getSignal(event["groups"], trig, events_data)
605 event["triggers"]["signals"].extend(triggers)
606 elif trig["name"] == "init":
607 triggers = getInit(event["groups"], trig, events_data)
608 event["triggers"]["init"] = triggers
Matthew Barth7f272fd2017-09-12 16:16:56 -0500609
Matthew Barth7f272fd2017-09-12 16:16:56 -0500610 return event
611
612
613def addPrecondition(zNum, zCond, event, events_data):
Matthew Barth9af190c2017-08-08 14:20:43 -0500614 """
615 Parses the precondition section of an event and populates the necessary
616 structures to generate a precondition for a set speed event.
617 """
618 precond = {}
Matthew Barth621a5772018-11-14 14:55:11 -0600619
620 # Add set speed event precondition name
Patrick Williams0f2588f2022-12-05 10:17:03 -0600621 precond["pcname"] = event["name"]
Matthew Barth621a5772018-11-14 14:55:11 -0600622
Matthew Barth9af190c2017-08-08 14:20:43 -0500623 # Add set speed event precondition group
Patrick Williams0f2588f2022-12-05 10:17:03 -0600624 precond["pcgrps"] = getGroups(
625 zNum, zCond, event["precondition"], events_data
626 )
Matthew Barth9af190c2017-08-08 14:20:43 -0500627
Matthew Barth7f272fd2017-09-12 16:16:56 -0500628 # Add set speed event precondition actions
629 pc = []
630 pcs = {}
Patrick Williams0f2588f2022-12-05 10:17:03 -0600631 pcs["name"] = event["precondition"]["name"]
632 epc = next(
633 p
634 for p in events_data["preconditions"]
635 if p["name"] == event["precondition"]["name"]
636 )
Matthew Barth9af190c2017-08-08 14:20:43 -0500637 params = []
Patrick Williams0f2588f2022-12-05 10:17:03 -0600638 for p in epc["parameters"] or []:
Matthew Barth9af190c2017-08-08 14:20:43 -0500639 param = {}
Patrick Williams0f2588f2022-12-05 10:17:03 -0600640 if p == "groups":
641 param["type"] = "std::vector<PrecondGroup>"
642 param["open"] = "{"
643 param["close"] = "}"
Matthew Barth9af190c2017-08-08 14:20:43 -0500644 values = []
Patrick Williams0f2588f2022-12-05 10:17:03 -0600645 for group in precond["pcgrps"]:
646 for pcgrp in group["members"]:
Matthew Barth6c050692017-12-05 15:30:09 -0600647 value = {}
Patrick Williams0f2588f2022-12-05 10:17:03 -0600648 value["value"] = (
649 'PrecondGroup{"'
650 + str(pcgrp["object"])
651 + '","'
652 + str(pcgrp["interface"])
653 + '","'
654 + str(pcgrp["property"])
655 + '",'
656 + "static_cast<"
657 + str(pcgrp["type"]).lower()
658 + ">"
659 )
660 if (
661 isinstance(pcgrp["value"], str)
662 or "string" in str(pcgrp["type"]).lower()
663 ):
664 value["value"] += "(" + str(pcgrp["value"]) + ")}"
Matthew Barth6c050692017-12-05 15:30:09 -0600665 else:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600666 value["value"] += (
667 "(" + str(pcgrp["value"]).lower() + ")}"
668 )
Matthew Barth6c050692017-12-05 15:30:09 -0600669 values.append(value)
Patrick Williams0f2588f2022-12-05 10:17:03 -0600670 param["values"] = values
Matthew Barth9af190c2017-08-08 14:20:43 -0500671 params.append(param)
Patrick Williams0f2588f2022-12-05 10:17:03 -0600672 pcs["params"] = params
Matthew Barth7f272fd2017-09-12 16:16:56 -0500673 pc.append(pcs)
Patrick Williams0f2588f2022-12-05 10:17:03 -0600674 precond["pcact"] = pc
Matthew Barth9af190c2017-08-08 14:20:43 -0500675
Matthew Barth7f272fd2017-09-12 16:16:56 -0500676 pcevents = []
Patrick Williams0f2588f2022-12-05 10:17:03 -0600677 for pce in event["precondition"]["events"]:
Matthew Barth7f272fd2017-09-12 16:16:56 -0500678 pcevent = getEvent(zNum, zCond, pce, events_data)
679 if not pcevent:
680 continue
681 pcevents.append(pcevent)
Patrick Williams0f2588f2022-12-05 10:17:03 -0600682 precond["pcevts"] = pcevents
Matthew Barth7f272fd2017-09-12 16:16:56 -0500683
Matthew Barthf20c3212018-03-02 14:42:55 -0600684 # Add precondition event triggers
Patrick Williams0f2588f2022-12-05 10:17:03 -0600685 precond["triggers"] = {}
686 for trig in event["precondition"]["triggers"]:
Matthew Barthf20c3212018-03-02 14:42:55 -0600687 triggers = []
Patrick Williams0f2588f2022-12-05 10:17:03 -0600688 if trig["name"] == "timer":
689 precond["triggers"]["pctime"] = getTimer(trig)
690 elif trig["name"] == "signal":
691 if "pcsigs" not in precond["triggers"]:
692 precond["triggers"]["pcsigs"] = []
693 triggers = getSignal(precond["pcgrps"], trig, events_data)
694 precond["triggers"]["pcsigs"].extend(triggers)
695 elif trig["name"] == "init":
696 triggers = getInit(precond["pcgrps"], trig, events_data)
697 precond["triggers"]["init"] = triggers
Matthew Barth9af190c2017-08-08 14:20:43 -0500698
699 return precond
700
701
Gunnar Millsb751f322017-06-06 15:14:11 -0500702def getEventsInZone(zone_num, zone_conditions, events_data):
Matthew Barthd4d0f082017-05-16 13:51:10 -0500703 """
704 Constructs the event entries defined for each zone using the events yaml
705 provided.
706 """
707 events = []
Matthew Barthba102b32017-05-16 16:13:56 -0500708
Patrick Williams0f2588f2022-12-05 10:17:03 -0600709 if "events" in events_data:
710 for e in events_data["events"]:
Matthew Barthd4d0f082017-05-16 13:51:10 -0500711 event = {}
Matthew Barth621a5772018-11-14 14:55:11 -0600712
Matthew Barth9af190c2017-08-08 14:20:43 -0500713 # Add precondition if given
Patrick Williams0f2588f2022-12-05 10:17:03 -0600714 if ("precondition" in e) and (e["precondition"] is not None):
715 event["pc"] = addPrecondition(
716 zone_num, zone_conditions, e, events_data
717 )
Matthew Barth90149802017-08-15 10:51:37 -0500718 else:
Matthew Barth7f272fd2017-09-12 16:16:56 -0500719 event = getEvent(zone_num, zone_conditions, e, events_data)
Matthew Bartha6f75162018-11-20 13:50:42 -0600720 # Remove empty events and events that have
721 # no groups defined for the event or any of the actions
Patrick Williams0f2588f2022-12-05 10:17:03 -0600722 if not event or (
723 not event["groups"]
724 and all(not a["groups"] for a in event["action"])
725 ):
Matthew Barth7f272fd2017-09-12 16:16:56 -0500726 continue
Matthew Barthd4d0f082017-05-16 13:51:10 -0500727 events.append(event)
728
729 return events
730
731
Matt Spinler78498c92017-04-11 13:59:46 -0500732def getFansInZone(zone_num, profiles, fan_data):
733 """
734 Parses the fan definition YAML files to find the fans
735 that match both the zone passed in and one of the
736 cooling profiles.
737 """
738
739 fans = []
740
Patrick Williams0f2588f2022-12-05 10:17:03 -0600741 for f in fan_data["fans"]:
742 if zone_num != f["cooling_zone"]:
Matt Spinler78498c92017-04-11 13:59:46 -0500743 continue
744
Gunnar Mills67e95512017-06-02 14:35:18 -0500745 # 'cooling_profile' is optional (use 'all' instead)
Patrick Williams0f2588f2022-12-05 10:17:03 -0600746 if f.get("cooling_profile") is None:
Matt Spinler78498c92017-04-11 13:59:46 -0500747 profile = "all"
748 else:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600749 profile = f["cooling_profile"]
Matt Spinler78498c92017-04-11 13:59:46 -0500750
751 if profile not in profiles:
752 continue
753
754 fan = {}
Patrick Williams0f2588f2022-12-05 10:17:03 -0600755 fan["name"] = f["inventory"]
756 fan["sensors"] = f["sensors"]
757 fan["target_interface"] = f.get(
758 "target_interface", "xyz.openbmc_project.Control.FanSpeed"
759 )
760 fan["target_path"] = f.get(
761 "target_path", "/xyz/openbmc_project/sensors/fan_tach/"
762 )
Matt Spinler78498c92017-04-11 13:59:46 -0500763 fans.append(fan)
764
765 return fans
766
767
Matthew Barth7883f582019-02-14 14:24:46 -0600768def getIfacesInZone(zone_ifaces):
769 """
770 Parse given interfaces for a zone for associating a zone with an interface
771 and set any properties listed to defined values upon fan control starting
772 on the zone.
773 """
774
775 ifaces = []
776 for i in zone_ifaces:
777 iface = {}
778 # Interface name not needed yet for fan zones but
779 # may be necessary as more interfaces are extended by the zones
Patrick Williams0f2588f2022-12-05 10:17:03 -0600780 iface["name"] = i["name"]
Matthew Barth7883f582019-02-14 14:24:46 -0600781
Patrick Williams0f2588f2022-12-05 10:17:03 -0600782 if ("properties" in i) and (i["properties"] is not None):
Matthew Barth7883f582019-02-14 14:24:46 -0600783 props = []
Patrick Williams0f2588f2022-12-05 10:17:03 -0600784 for p in i["properties"]:
Matthew Barth7883f582019-02-14 14:24:46 -0600785 prop = {}
Patrick Williams0f2588f2022-12-05 10:17:03 -0600786 prop["name"] = p["name"]
787 prop["func"] = str(p["name"]).lower()
788 prop["type"] = parse_cpp_type(p["type"])
789 if "persist" in p:
790 persist = p["persist"]
791 if persist is not None:
792 if isinstance(persist, bool):
793 prop["persist"] = "true" if persist else "false"
Matthew Barth59096e52019-02-18 12:23:38 -0600794 else:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600795 prop["persist"] = "false"
Matthew Barth7883f582019-02-14 14:24:46 -0600796 vals = []
Patrick Williams0f2588f2022-12-05 10:17:03 -0600797 for v in p["values"]:
798 val = v["value"]
799 if val is not None:
800 if isinstance(val, bool):
Matthew Barth7883f582019-02-14 14:24:46 -0600801 # Convert True/False to 'true'/'false'
Patrick Williams0f2588f2022-12-05 10:17:03 -0600802 val = "true" if val else "false"
803 elif isinstance(val, str):
Matthew Barth7883f582019-02-14 14:24:46 -0600804 # Wrap strings with double-quotes
Patrick Williams0f2588f2022-12-05 10:17:03 -0600805 val = '"' + val + '"'
Matthew Barth7883f582019-02-14 14:24:46 -0600806 vals.append(val)
Patrick Williams0f2588f2022-12-05 10:17:03 -0600807 prop["values"] = vals
Matthew Barth7883f582019-02-14 14:24:46 -0600808 props.append(prop)
Patrick Williams0f2588f2022-12-05 10:17:03 -0600809 iface["props"] = props
Matthew Barth7883f582019-02-14 14:24:46 -0600810 ifaces.append(iface)
811
812 return ifaces
813
814
Gunnar Millsee8a2812017-06-02 14:26:47 -0500815def getConditionInZoneConditions(zone_condition, zone_conditions_data):
816 """
817 Parses the zone conditions definition YAML files to find the condition
818 that match both the zone condition passed in.
819 """
820
821 condition = {}
822
Patrick Williams0f2588f2022-12-05 10:17:03 -0600823 for c in zone_conditions_data["conditions"]:
824 if zone_condition != c["name"]:
Gunnar Millsee8a2812017-06-02 14:26:47 -0500825 continue
Patrick Williams0f2588f2022-12-05 10:17:03 -0600826 condition["type"] = c["type"]
Gunnar Millsee8a2812017-06-02 14:26:47 -0500827 properties = []
Patrick Williams0f2588f2022-12-05 10:17:03 -0600828 for p in c["properties"]:
Gunnar Millsee8a2812017-06-02 14:26:47 -0500829 property = {}
Patrick Williams0f2588f2022-12-05 10:17:03 -0600830 property["property"] = p["property"]
831 property["interface"] = p["interface"]
832 property["path"] = p["path"]
833 property["type"] = p["type"].lower()
834 property["value"] = str(p["value"]).lower()
Gunnar Millsee8a2812017-06-02 14:26:47 -0500835 properties.append(property)
Patrick Williams0f2588f2022-12-05 10:17:03 -0600836 condition["properties"] = properties
Gunnar Millsee8a2812017-06-02 14:26:47 -0500837
838 return condition
839
840
841def buildZoneData(zone_data, fan_data, events_data, zone_conditions_data):
Matt Spinler78498c92017-04-11 13:59:46 -0500842 """
843 Combines the zone definition YAML and fan
844 definition YAML to create a data structure defining
845 the fan cooling zones.
846 """
847
848 zone_groups = []
849
Matthew Barth005ff2f2020-02-18 11:17:41 -0600850 # Allow zone_conditions to not be in yaml (since its optional)
851 if not isinstance(zone_data, list) and zone_data != {}:
852 zone_data = [zone_data]
Matt Spinler78498c92017-04-11 13:59:46 -0500853 for group in zone_data:
854 conditions = []
Gunnar Millsee8a2812017-06-02 14:26:47 -0500855 # zone conditions are optional
Patrick Williams0f2588f2022-12-05 10:17:03 -0600856 if "zone_conditions" in group and group["zone_conditions"] is not None:
857 for c in group["zone_conditions"]:
Gunnar Millsee8a2812017-06-02 14:26:47 -0500858 if not zone_conditions_data:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600859 sys.exit(
860 "No zone_conditions YAML file but "
861 + "zone_conditions used in zone YAML"
862 )
Gunnar Millsee8a2812017-06-02 14:26:47 -0500863
Patrick Williams0f2588f2022-12-05 10:17:03 -0600864 condition = getConditionInZoneConditions(
865 c["name"], zone_conditions_data
866 )
Gunnar Millsee8a2812017-06-02 14:26:47 -0500867
868 if not condition:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600869 sys.exit("Missing zone condition " + c["name"])
Gunnar Millsee8a2812017-06-02 14:26:47 -0500870
871 conditions.append(condition)
Matt Spinler78498c92017-04-11 13:59:46 -0500872
873 zone_group = {}
Patrick Williams0f2588f2022-12-05 10:17:03 -0600874 zone_group["conditions"] = conditions
Matt Spinler78498c92017-04-11 13:59:46 -0500875
876 zones = []
Patrick Williams0f2588f2022-12-05 10:17:03 -0600877 for z in group["zones"]:
Matt Spinler78498c92017-04-11 13:59:46 -0500878 zone = {}
879
Gunnar Mills67e95512017-06-02 14:35:18 -0500880 # 'zone' is required
Patrick Williams0f2588f2022-12-05 10:17:03 -0600881 if ("zone" not in z) or (z["zone"] is None):
882 sys.exit("Missing fan zone number in " + z)
Matt Spinler78498c92017-04-11 13:59:46 -0500883
Patrick Williams0f2588f2022-12-05 10:17:03 -0600884 zone["num"] = z["zone"]
Matt Spinler78498c92017-04-11 13:59:46 -0500885
Patrick Williams0f2588f2022-12-05 10:17:03 -0600886 zone["full_speed"] = z["full_speed"]
Matt Spinler78498c92017-04-11 13:59:46 -0500887
Patrick Williams0f2588f2022-12-05 10:17:03 -0600888 zone["default_floor"] = z["default_floor"]
Matthew Barth1de66622017-06-12 13:13:02 -0500889
Matthew Bartha9561842017-06-29 11:43:45 -0500890 # 'increase_delay' is optional (use 0 by default)
Patrick Williams0f2588f2022-12-05 10:17:03 -0600891 key = "increase_delay"
Matthew Bartha9561842017-06-29 11:43:45 -0500892 zone[key] = z.setdefault(key, 0)
893
894 # 'decrease_interval' is optional (use 0 by default)
Patrick Williams0f2588f2022-12-05 10:17:03 -0600895 key = "decrease_interval"
Matthew Bartha9561842017-06-29 11:43:45 -0500896 zone[key] = z.setdefault(key, 0)
897
Gunnar Mills67e95512017-06-02 14:35:18 -0500898 # 'cooling_profiles' is optional (use 'all' instead)
Patrick Williams0f2588f2022-12-05 10:17:03 -0600899 if ("cooling_profiles" not in z) or (
900 z["cooling_profiles"] is None
901 ):
Matt Spinler78498c92017-04-11 13:59:46 -0500902 profiles = ["all"]
903 else:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600904 profiles = z["cooling_profiles"]
Matt Spinler78498c92017-04-11 13:59:46 -0500905
Matthew Barth7883f582019-02-14 14:24:46 -0600906 # 'interfaces' is optional (no default)
Matthew Barth64099cd2019-02-18 09:43:12 -0600907 ifaces = []
Patrick Williams0f2588f2022-12-05 10:17:03 -0600908 if ("interfaces" in z) and (z["interfaces"] is not None):
909 ifaces = getIfacesInZone(z["interfaces"])
Matthew Barth7883f582019-02-14 14:24:46 -0600910
Patrick Williams0f2588f2022-12-05 10:17:03 -0600911 fans = getFansInZone(z["zone"], profiles, fan_data)
912 events = getEventsInZone(
913 z["zone"], group.get("zone_conditions", {}), events_data
914 )
Matt Spinler78498c92017-04-11 13:59:46 -0500915
916 if len(fans) == 0:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600917 sys.exit("Didn't find any fans in zone " + str(zone["num"]))
Matt Spinler78498c92017-04-11 13:59:46 -0500918
Patrick Williams0f2588f2022-12-05 10:17:03 -0600919 if ifaces:
920 zone["ifaces"] = ifaces
921 zone["fans"] = fans
922 zone["events"] = events
Matt Spinler78498c92017-04-11 13:59:46 -0500923 zones.append(zone)
924
Patrick Williams0f2588f2022-12-05 10:17:03 -0600925 zone_group["zones"] = zones
Matt Spinler78498c92017-04-11 13:59:46 -0500926 zone_groups.append(zone_group)
927
928 return zone_groups
929
930
Patrick Williams0f2588f2022-12-05 10:17:03 -0600931if __name__ == "__main__":
932 parser = ArgumentParser(description="Phosphor fan zone definition parser")
Matt Spinlerd08dbe22017-04-11 13:52:54 -0500933
Patrick Williams0f2588f2022-12-05 10:17:03 -0600934 parser.add_argument(
935 "-z",
936 "--zone_yaml",
937 dest="zone_yaml",
938 default="example/zones.yaml",
939 help="fan zone definitional yaml",
940 )
941 parser.add_argument(
942 "-f",
943 "--fan_yaml",
944 dest="fan_yaml",
945 default="example/fans.yaml",
946 help="fan definitional yaml",
947 )
948 parser.add_argument(
949 "-e",
950 "--events_yaml",
951 dest="events_yaml",
952 help="events to set speeds yaml",
953 )
954 parser.add_argument(
955 "-c",
956 "--zone_conditions_yaml",
957 dest="zone_conditions_yaml",
958 help="conditions to determine zone yaml",
959 )
960 parser.add_argument(
961 "-o",
962 "--output_dir",
963 dest="output_dir",
964 default=".",
965 help="output directory",
966 )
Matt Spinlerd08dbe22017-04-11 13:52:54 -0500967 args = parser.parse_args()
968
969 if not args.zone_yaml or not args.fan_yaml:
970 parser.print_usage()
William A. Kennington III3e781062018-10-19 17:18:34 -0700971 sys.exit(1)
Matt Spinlerd08dbe22017-04-11 13:52:54 -0500972
Patrick Williams0f2588f2022-12-05 10:17:03 -0600973 with open(args.zone_yaml, "r") as zone_input:
Matt Spinlerd08dbe22017-04-11 13:52:54 -0500974 zone_data = yaml.safe_load(zone_input) or {}
975
Patrick Williams0f2588f2022-12-05 10:17:03 -0600976 with open(args.fan_yaml, "r") as fan_input:
Matt Spinlerd08dbe22017-04-11 13:52:54 -0500977 fan_data = yaml.safe_load(fan_input) or {}
978
Matthew Barthd4d0f082017-05-16 13:51:10 -0500979 events_data = {}
980 if args.events_yaml:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600981 with open(args.events_yaml, "r") as events_input:
Matthew Barthd4d0f082017-05-16 13:51:10 -0500982 events_data = yaml.safe_load(events_input) or {}
983
Gunnar Millsee8a2812017-06-02 14:26:47 -0500984 zone_conditions_data = {}
985 if args.zone_conditions_yaml:
Patrick Williams0f2588f2022-12-05 10:17:03 -0600986 with open(args.zone_conditions_yaml, "r") as zone_conditions_input:
Gunnar Millsee8a2812017-06-02 14:26:47 -0500987 zone_conditions_data = yaml.safe_load(zone_conditions_input) or {}
988
Patrick Williams0f2588f2022-12-05 10:17:03 -0600989 zone_config = buildZoneData(
990 zone_data.get("zone_configuration", {}),
991 fan_data,
992 events_data,
993 zone_conditions_data,
994 )
Matt Spinleree7f6422017-05-09 11:03:14 -0500995
Patrick Williams0f2588f2022-12-05 10:17:03 -0600996 manager_config = zone_data.get("manager_configuration", {})
Matt Spinleree7f6422017-05-09 11:03:14 -0500997
Patrick Williams0f2588f2022-12-05 10:17:03 -0600998 if manager_config.get("power_on_delay") is None:
999 manager_config["power_on_delay"] = 0
Matt Spinlerd08dbe22017-04-11 13:52:54 -05001000
Matthew Barth702c4a52018-02-28 16:23:11 -06001001 tmpls_dir = os.path.join(
Patrick Williams0f2588f2022-12-05 10:17:03 -06001002 os.path.dirname(os.path.realpath(__file__)), "templates"
1003 )
Matt Spinlerd08dbe22017-04-11 13:52:54 -05001004 output_file = os.path.join(args.output_dir, "fan_zone_defs.cpp")
Matthew Barth702c4a52018-02-28 16:23:11 -06001005 if sys.version_info < (3, 0):
1006 lkup = TemplateLookup(
Patrick Williams0f2588f2022-12-05 10:17:03 -06001007 directories=tmpls_dir.split(), disable_unicode=True
1008 )
Matthew Barth702c4a52018-02-28 16:23:11 -06001009 else:
Patrick Williams0f2588f2022-12-05 10:17:03 -06001010 lkup = TemplateLookup(directories=tmpls_dir.split())
1011 tmpl = lkup.get_template("fan_zone_defs.mako.cpp")
1012 with open(output_file, "w") as output:
1013 output.write(tmpl.render(zones=zone_config, mgr_data=manager_config))