blob: fdbdab870d28e5c075bde103e9bba1415e86ce41 [file] [log] [blame]
Matt Spinlerd08dbe22017-04-11 13:52:54 -05001#!/usr/bin/env python
2
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
12from mako.template import Template
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 Barthbb12c922017-06-13 13:57:40 -050016def convertToMap(listOfDict):
17 """
18 Converts a list of dictionary entries to a std::map initialization list.
19 """
Matthew Barth9a5b6992018-01-23 15:32:26 -060020 listOfDict = listOfDict.replace('\'', '\"')
Matthew Barthbb12c922017-06-13 13:57:40 -050021 listOfDict = listOfDict.replace('[', '{')
22 listOfDict = listOfDict.replace(']', '}')
23 listOfDict = listOfDict.replace(':', ',')
24 return listOfDict
25
26
Matthew Bartha1aef7a2019-01-16 11:02:57 -060027def genEvent(event):
28 """
29 Generates the source code of an event and returns it as a string
30 """
31 e = "SetSpeedEvent{\n"
32
33 e += "Group{\n"
34 for group in event['groups']:
35 for member in group['members']:
36 e += "{\n"
37 e += "\"" + member['object'] + "\",\n"
38 e += "{\"" + member['interface'] + "\",\n"
39 e += " \"" + member['property'] + "\"}\n"
40 e += "},\n"
41 e += "},\n"
42
43 e += "std::vector<Action>{\n"
44 for a in event['action']:
45 if len(a['parameters']) != 0:
46 e += "make_action(action::" + a['name'] + "(\n"
47 else:
48 e += "make_action(action::" + a['name'] + "\n"
49 for i, p in enumerate(a['parameters']):
50 if (i+1) != len(a['parameters']):
51 e += p + ",\n"
52 else:
53 e += p + ")\n"
54 e += "),\n"
55 e += "},\n"
56
57 e += "TimerConf{\n"
58 e += "\t" + event['timer']['interval'] + ",\n"
59 e += "\t" + event['timer']['type'] + "\n"
60 e += "},\n"
61
62 e += "std::vector<Signal>{\n"
63 for s in event['signals']:
64 e += "Signal{\n"
65 e += "match::" + s['match'] + "(\n"
66 for i, mp in enumerate(s['mparams']):
67 if (i+1) != len(s['mparams']):
68 e += "\"" + mp + "\",\n"
69 else:
70 e += "\"" + mp + "\"\n"
71 e += "),\n"
72 e += "make_handler(\n"
73 if ('type' in s['sparams']) and (s['sparams']['type'] is not None):
74 e += s['signal'] + "<" + s['sparams']['type'] + ">(\n"
75 else:
76 e += s['signal'] + "(\n"
77 for sp in s['sparams']['params']:
78 e += s['sparams'][sp] + ",\n"
79 if ('type' in s['hparams']) and (s['hparams']['type'] is not None):
80 e += ("handler::" + s['handler'] +
81 "<" + s['hparams']['type'] + ">(\n")
82 else:
83 e += "handler::" + s['handler'] + "(\n)"
84 for i, hp in enumerate(s['hparams']['params']):
85 if (i+1) != len(s['hparams']['params']):
86 e += s['hparams'][hp] + ",\n"
87 else:
88 e += s['hparams'][hp] + "\n"
89 e += "))\n"
90 e += ")\n"
91 e += "},\n"
92 e += "}\n"
93
94 e += "}"
95
96 return e
97
98
Matthew Barth6c050692017-12-05 15:30:09 -060099def getGroups(zNum, zCond, edata, events):
100 """
101 Extract and construct the groups for the given event.
102 """
103 groups = []
104 for eGroups in edata['groups']:
105 if ('zone_conditions' in eGroups) and \
106 (eGroups['zone_conditions'] is not None):
107 # Zone conditions are optional in the events yaml but skip
108 # if this event's condition is not in this zone's conditions
109 if all('name' in z and z['name'] is not None and
110 not any(c['name'] == z['name'] for c in zCond)
111 for z in eGroups['zone_conditions']):
112 continue
113
114 # Zone numbers are optional in the events yaml but skip if this
115 # zone's zone number is not in the event's zone numbers
116 if all('zones' in z and z['zones'] is not None and
117 zNum not in z['zones']
118 for z in eGroups['zone_conditions']):
119 continue
Matthew Barth6c050692017-12-05 15:30:09 -0600120 eGroup = next(g for g in events['groups']
121 if g['name'] == eGroups['name'])
122
123 group = {}
124 members = []
125 group['name'] = eGroup['name']
126 for m in eGroup['members']:
127 member = {}
128 member['path'] = eGroup['type']
129 member['object'] = (eGroup['type'] + m)
130 member['interface'] = eGroups['interface']
131 member['property'] = eGroups['property']['name']
132 member['type'] = eGroups['property']['type']
Matthew Barth18c91032019-01-29 15:36:00 -0600133 # Use defined service to note member on zone object
134 if ('service' in eGroup) and \
135 (eGroup['service'] is not None):
136 member['service'] = eGroup['service']
Matthew Barth6c050692017-12-05 15:30:09 -0600137 # Add expected group member's property value if given
138 if ('value' in eGroups['property']) and \
139 (eGroups['property']['value'] is not None):
140 if isinstance(eGroups['property']['value'], str) or \
141 "string" in str(member['type']).lower():
142 member['value'] = (
143 "\"" + eGroups['property']['value'] + "\"")
144 else:
145 member['value'] = eGroups['property']['value']
146 members.append(member)
147 group['members'] = members
148 groups.append(group)
149 return groups
150
151
Matthew Bartha1aef7a2019-01-16 11:02:57 -0600152def getActions(zNum, zCond, edata, actions, events):
Matthew Barth9df74752017-10-11 14:39:31 -0500153 """
154 Extracts and constructs the make_action function call for
155 all the actions within the given event.
156 """
157 action = []
158 for eActions in actions['actions']:
159 actions = {}
160 eAction = next(a for a in events['actions']
161 if a['name'] == eActions['name'])
162 actions['name'] = eAction['name']
163 params = []
164 if ('parameters' in eAction) and \
165 (eAction['parameters'] is not None):
166 for p in eAction['parameters']:
167 param = "static_cast<"
168 if type(eActions[p]) is not dict:
169 if p == 'actions':
170 param = "std::vector<Action>{"
Matthew Bartha1aef7a2019-01-16 11:02:57 -0600171 pActs = getActions(zNum,
172 zCond,
173 edata,
174 eActions,
175 events)
Matthew Barth9df74752017-10-11 14:39:31 -0500176 for a in pActs:
177 if (len(a['parameters']) != 0):
178 param += (
179 "make_action(action::" +
180 a['name'] +
181 "(\n")
182 for i, ap in enumerate(a['parameters']):
183 if (i+1) != len(a['parameters']):
184 param += (ap + ",")
185 else:
186 param += (ap + ")")
187 else:
188 param += ("make_action(action::" + a['name'])
189 param += "),"
190 param += "}"
Matthew Bartha1aef7a2019-01-16 11:02:57 -0600191 elif p == 'defevents' or p == 'altevents':
192 param = "std::vector<SetSpeedEvent>{\n"
193 for i, e in enumerate(eActions[p]):
194 aEvent = getEvent(zNum, zCond, e, events)
195 if not aEvent:
196 continue
197 if (i+1) != len(eActions[p]):
198 param += genEvent(aEvent) + ",\n"
199 else:
200 param += genEvent(aEvent) + "\n"
201 param += "\t}"
Matthew Barth9df74752017-10-11 14:39:31 -0500202 elif p == 'property':
Matthew Barth9a5b6992018-01-23 15:32:26 -0600203 if isinstance(eActions[p], str) or \
Matthew Barth6c050692017-12-05 15:30:09 -0600204 "string" in str(eActions[p]['type']).lower():
Matthew Barth9a5b6992018-01-23 15:32:26 -0600205 param += (
Matthew Barth6c050692017-12-05 15:30:09 -0600206 str(eActions[p]['type']).lower() +
Matthew Barth9a5b6992018-01-23 15:32:26 -0600207 ">(\"" + str(eActions[p]) + "\")")
208 else:
209 param += (
Matthew Barth6c050692017-12-05 15:30:09 -0600210 str(eActions[p]['type']).lower() +
211 ">(" + str(eActions[p]['value']).lower() + ")")
Matthew Barth9df74752017-10-11 14:39:31 -0500212 else:
213 # Default type to 'size_t' when not given
214 param += ("size_t>(" + str(eActions[p]).lower() + ")")
215 else:
216 if p == 'timer':
217 param = (
William A. Kennington III122b8432018-10-30 18:39:21 -0700218 "TimerConf{static_cast<std::chrono::seconds>(" +
Matthew Barth9df74752017-10-11 14:39:31 -0500219 str(eActions[p]['delay']) + "), " +
William A. Kennington III0ce353e2018-10-30 18:30:36 -0700220 "TimerType::" +
Matthew Barth9df74752017-10-11 14:39:31 -0500221 str(eActions[p]['type']) + "}")
222 else:
223 param += (str(eActions[p]['type']).lower() + ">(")
224 if p != 'map':
Matthew Barth9a5b6992018-01-23 15:32:26 -0600225 if isinstance(eActions[p]['value'], str) or \
226 "string" in str(eActions[p]['type']).lower():
227 param += \
228 "\"" + str(eActions[p]['value']) + "\")"
229 else:
230 param += \
231 str(eActions[p]['value']).lower() + ")"
Matthew Barth9df74752017-10-11 14:39:31 -0500232 else:
233 param += (
234 str(eActions[p]['type']).lower() +
235 convertToMap(str(eActions[p]['value'])) + ")")
236 params.append(param)
237 actions['parameters'] = params
238 action.append(actions)
239 return action
240
241
Matthew Barth7f272fd2017-09-12 16:16:56 -0500242def getEvent(zone_num, zone_conditions, e, events_data):
243 """
244 Parses the sections of an event and populates the properties
245 that construct an event within the generated source.
246 """
247 event = {}
Matthew Barth7f272fd2017-09-12 16:16:56 -0500248
Matthew Barth6c050692017-12-05 15:30:09 -0600249 # Add set speed event groups
250 grps = getGroups(zone_num, zone_conditions, e, events_data)
251 if not grps:
Matthew Barth7f272fd2017-09-12 16:16:56 -0500252 return
Matthew Barth6c050692017-12-05 15:30:09 -0600253 event['groups'] = grps
Matthew Barth7f272fd2017-09-12 16:16:56 -0500254
Matthew Barthe3d1c4a2018-01-11 13:53:49 -0600255 # Add optional set speed actions and function parameters
256 event['action'] = []
257 if ('actions' in e) and \
258 (e['actions'] is not None):
Matthew Bartha1aef7a2019-01-16 11:02:57 -0600259 event['action'] = getActions(zone_num,
260 zone_conditions,
261 e,
262 e,
263 events_data)
Matthew Barth7f272fd2017-09-12 16:16:56 -0500264
Matthew Barth67967f92017-09-22 12:43:57 -0500265 # Add signal handlers
266 signals = []
Matthew Barth6c050692017-12-05 15:30:09 -0600267 for group in event['groups']:
268 for member in group['members']:
269 for eMatches in e['matches']:
270 signal = {}
271 eMatch = next(m for m in events_data['matches']
272 if m['name'] == eMatches['name'])
Matthew Barth18c91032019-01-29 15:36:00 -0600273 # If service not given, subscribe to signal match
274 if ('service' not in member):
275 signal['match'] = eMatch['name']
276 params = []
277 if ('parameters' in eMatch) and \
278 (eMatch['parameters'] is not None):
279 for p in eMatch['parameters']:
280 params.append(member[str(p)])
281 signal['mparams'] = params
282
Matthew Barthe7d87052018-03-21 13:58:31 -0500283 if ('parameters' in eMatch['signal']) and \
284 (eMatch['signal']['parameters'] is not None):
285 eSignal = eMatch['signal']
286 else:
287 eSignal = next(s for s in events_data['signals']
288 if s['name'] == eMatch['signal'])
Matthew Barth6c050692017-12-05 15:30:09 -0600289 signal['signal'] = eSignal['name']
290 sparams = {}
291 if ('parameters' in eSignal) and \
292 (eSignal['parameters'] is not None):
293 splist = []
294 for p in eSignal['parameters']:
295 sp = str(p)
296 if (sp != 'type'):
297 splist.append(sp)
298 if (sp != 'group'):
299 sparams[sp] = "\"" + member[sp] + "\""
300 else:
301 sparams[sp] = "Group{\n"
302 for m in group['members']:
303 sparams[sp] += (
304 "{\n" +
305 "\"" + str(m['object']) + "\",\n" +
306 "{\"" + str(m['interface']) + "\"," +
307 "\"" + str(m['property']) + "\"}\n" +
308 "},\n")
309 sparams[sp] += "}"
Matthew Barth9f964bf2017-10-02 15:07:00 -0500310 else:
Matthew Barth6c050692017-12-05 15:30:09 -0600311 sparams[sp] = member[sp]
312 sparams['params'] = splist
313 signal['sparams'] = sparams
314 # Add signal handler
315 eHandler = next(h for h in events_data['handlers']
316 if h['name'] == eSignal['handler'])
317 signal['handler'] = eHandler['name']
318 hparams = {}
319 if ('parameters' in eHandler) and \
320 (eHandler['parameters'] is not None):
321 hplist = []
322 for p in eHandler['parameters']:
323 hp = str(p)
324 if (hp != 'type'):
325 hplist.append(hp)
326 if (hp != 'group'):
327 hparams[hp] = "\"" + member[hp] + "\""
328 else:
329 hparams[hp] = "Group{\n"
330 for m in group['members']:
331 hparams[hp] += (
332 "{\n" +
333 "\"" + str(m['object']) + "\",\n" +
334 "{\"" + str(m['interface']) + "\"," +
335 "\"" + str(m['property']) + "\"}\n" +
336 "},\n")
337 hparams[hp] += "}"
Matthew Barth9f964bf2017-10-02 15:07:00 -0500338 else:
Matthew Barth6c050692017-12-05 15:30:09 -0600339 hparams[hp] = member[hp]
340 hparams['params'] = hplist
341 signal['hparams'] = hparams
342 signals.append(signal)
Matthew Barth67967f92017-09-22 12:43:57 -0500343 event['signals'] = signals
Matthew Barth7f272fd2017-09-12 16:16:56 -0500344
345 # Add optional action call timer
346 timer = {}
347 interval = "static_cast<std::chrono::seconds>"
348 if ('timer' in e) and \
349 (e['timer'] is not None):
350 timer['interval'] = (interval +
351 "(" +
352 str(e['timer']['interval']) +
353 ")")
354 else:
355 timer['interval'] = (interval +
356 "(" + str(0) + ")")
William A. Kennington III0ce353e2018-10-30 18:30:36 -0700357 timer['type'] = "TimerType::repeating"
Matthew Barth7f272fd2017-09-12 16:16:56 -0500358 event['timer'] = timer
359
360 return event
361
362
363def addPrecondition(zNum, zCond, event, events_data):
Matthew Barth9af190c2017-08-08 14:20:43 -0500364 """
365 Parses the precondition section of an event and populates the necessary
366 structures to generate a precondition for a set speed event.
367 """
368 precond = {}
369 # Add set speed event precondition group
Matthew Barth6c050692017-12-05 15:30:09 -0600370 grps = getGroups(zNum, zCond, event['precondition'], events_data)
371 if not grps:
372 return
373 precond['pcgrps'] = grps
Matthew Barth9af190c2017-08-08 14:20:43 -0500374
Matthew Barth7f272fd2017-09-12 16:16:56 -0500375 # Add set speed event precondition actions
376 pc = []
377 pcs = {}
378 pcs['name'] = event['precondition']['name']
379 epc = next(p for p in events_data['preconditions']
Matthew Barth9af190c2017-08-08 14:20:43 -0500380 if p['name'] == event['precondition']['name'])
381 params = []
Matthew Barth7f272fd2017-09-12 16:16:56 -0500382 for p in epc['parameters']:
Matthew Barth9af190c2017-08-08 14:20:43 -0500383 param = {}
384 if p == 'groups':
385 param['type'] = "std::vector<PrecondGroup>"
386 param['open'] = "{"
387 param['close'] = "}"
388 values = []
Matthew Barth6c050692017-12-05 15:30:09 -0600389 for group in precond['pcgrps']:
390 for pcgrp in group['members']:
391 value = {}
392 value['value'] = (
393 "PrecondGroup{\"" +
394 str(pcgrp['object']) + "\",\"" +
395 str(pcgrp['interface']) + "\",\"" +
396 str(pcgrp['property']) + "\"," +
397 "static_cast<" +
398 str(pcgrp['type']).lower() + ">")
399 if isinstance(pcgrp['value'], str) or \
400 "string" in str(pcgrp['type']).lower():
401 value['value'] += ("(" + str(pcgrp['value']) + ")}")
402 else:
403 value['value'] += \
404 ("(" + str(pcgrp['value']).lower() + ")}")
405 values.append(value)
Matthew Barth9af190c2017-08-08 14:20:43 -0500406 param['values'] = values
407 params.append(param)
Matthew Barth7f272fd2017-09-12 16:16:56 -0500408 pcs['params'] = params
409 pc.append(pcs)
Matthew Barth9af190c2017-08-08 14:20:43 -0500410 precond['pcact'] = pc
411
Matthew Barth7f272fd2017-09-12 16:16:56 -0500412 pcevents = []
413 for pce in event['precondition']['events']:
414 pcevent = getEvent(zNum, zCond, pce, events_data)
415 if not pcevent:
416 continue
417 pcevents.append(pcevent)
418 precond['pcevts'] = pcevents
419
Matthew Barth67967f92017-09-22 12:43:57 -0500420 # Add precondition signal handlers
421 signals = []
Matthew Barth6c050692017-12-05 15:30:09 -0600422 for group in precond['pcgrps']:
423 for member in group['members']:
424 for eMatches in event['precondition']['matches']:
425 signal = {}
426 eMatch = next(m for m in events_data['matches']
427 if m['name'] == eMatches['name'])
Matthew Barth18c91032019-01-29 15:36:00 -0600428 # If service not given, subscribe to signal match
429 if ('service' not in member):
430 signal['match'] = eMatch['name']
431 params = []
432 if ('parameters' in eMatch) and \
433 (eMatch['parameters'] is not None):
434 for p in eMatch['parameters']:
435 params.append(member[str(p)])
436 signal['mparams'] = params
437
Matthew Barthe7d87052018-03-21 13:58:31 -0500438 if ('parameters' in eMatch['signal']) and \
439 (eMatch['signal']['parameters'] is not None):
440 eSignal = eMatch['signal']
441 else:
442 eSignal = next(s for s in events_data['signals']
443 if s['name'] == eMatch['signal'])
Matthew Barth6c050692017-12-05 15:30:09 -0600444 signal['signal'] = eSignal['name']
445 sparams = {}
446 if ('parameters' in eSignal) and \
447 (eSignal['parameters'] is not None):
448 splist = []
449 for p in eSignal['parameters']:
450 sp = str(p)
451 if (sp != 'type'):
452 splist.append(sp)
453 if (sp != 'group'):
454 sparams[sp] = "\"" + member[sp] + "\""
455 else:
456 sparams[sp] = "Group{\n"
457 for m in group:
458 sparams[sp] += (
459 "{\n" +
460 "\"" + str(m['object']) + "\",\n" +
461 "{\"" + str(m['interface']) + "\"," +
462 "\"" + str(m['property']) + "\"}\n" +
463 "},\n")
464 sparams[sp] += "}"
Matthew Barth9f964bf2017-10-02 15:07:00 -0500465 else:
Matthew Barth6c050692017-12-05 15:30:09 -0600466 sparams[sp] = member[sp]
467 sparams['params'] = splist
468 signal['sparams'] = sparams
469 # Add signal handler
470 eHandler = next(h for h in events_data['handlers']
471 if h['name'] == eSignal['handler'])
472 signal['handler'] = eHandler['name']
473 hparams = {}
474 if ('parameters' in eHandler) and \
475 (eHandler['parameters'] is not None):
476 hplist = []
477 for p in eHandler['parameters']:
478 hp = str(p)
479 if (hp != 'type'):
480 hplist.append(hp)
481 if (hp != 'group'):
482 hparams[hp] = "\"" + member[hp] + "\""
483 else:
484 hparams[hp] = "Group{\n"
485 for m in group:
486 hparams[hp] += (
487 "{\n" +
488 "\"" + str(m['object']) + "\",\n" +
489 "{\"" + str(m['interface']) + "\"," +
490 "\"" + str(m['property']) + "\"}\n" +
491 "},\n")
492 hparams[hp] += "}"
Matthew Barth9f964bf2017-10-02 15:07:00 -0500493 else:
Matthew Barth6c050692017-12-05 15:30:09 -0600494 hparams[hp] = member[hp]
495 hparams['params'] = hplist
496 signal['hparams'] = hparams
497 signals.append(signal)
Matthew Barth67967f92017-09-22 12:43:57 -0500498 precond['pcsigs'] = signals
Matthew Barth9af190c2017-08-08 14:20:43 -0500499
Matthew Barth90149802017-08-15 10:51:37 -0500500 # Add optional action call timer
501 timer = {}
502 interval = "static_cast<std::chrono::seconds>"
503 if ('timer' in event['precondition']) and \
504 (event['precondition']['timer'] is not None):
505 timer['interval'] = (interval +
506 "(" +
507 str(event['precondition']['timer']['interval']) +
508 ")")
509 else:
510 timer['interval'] = (interval +
511 "(" + str(0) + ")")
William A. Kennington III0ce353e2018-10-30 18:30:36 -0700512 timer['type'] = "TimerType::repeating"
Matthew Barth90149802017-08-15 10:51:37 -0500513 precond['pctime'] = timer
514
Matthew Barth9af190c2017-08-08 14:20:43 -0500515 return precond
516
517
Gunnar Millsb751f322017-06-06 15:14:11 -0500518def getEventsInZone(zone_num, zone_conditions, events_data):
Matthew Barthd4d0f082017-05-16 13:51:10 -0500519 """
520 Constructs the event entries defined for each zone using the events yaml
521 provided.
522 """
523 events = []
Matthew Barthba102b32017-05-16 16:13:56 -0500524
Matthew Barthd4d0f082017-05-16 13:51:10 -0500525 if 'events' in events_data:
526 for e in events_data['events']:
Matthew Barthd4d0f082017-05-16 13:51:10 -0500527 event = {}
Matthew Barth9af190c2017-08-08 14:20:43 -0500528 # Add precondition if given
529 if ('precondition' in e) and \
530 (e['precondition'] is not None):
Matthew Barth7f272fd2017-09-12 16:16:56 -0500531 event['pc'] = addPrecondition(zone_num,
532 zone_conditions,
533 e,
534 events_data)
Matthew Barth90149802017-08-15 10:51:37 -0500535 else:
Matthew Barth7f272fd2017-09-12 16:16:56 -0500536 event = getEvent(zone_num, zone_conditions, e, events_data)
537 if not event:
538 continue
Matthew Barthd4d0f082017-05-16 13:51:10 -0500539 events.append(event)
540
541 return events
542
543
Matt Spinler78498c92017-04-11 13:59:46 -0500544def getFansInZone(zone_num, profiles, fan_data):
545 """
546 Parses the fan definition YAML files to find the fans
547 that match both the zone passed in and one of the
548 cooling profiles.
549 """
550
551 fans = []
552
553 for f in fan_data['fans']:
554
555 if zone_num != f['cooling_zone']:
556 continue
557
Gunnar Mills67e95512017-06-02 14:35:18 -0500558 # 'cooling_profile' is optional (use 'all' instead)
Matt Spinler78498c92017-04-11 13:59:46 -0500559 if f.get('cooling_profile') is None:
560 profile = "all"
561 else:
562 profile = f['cooling_profile']
563
564 if profile not in profiles:
565 continue
566
567 fan = {}
568 fan['name'] = f['inventory']
569 fan['sensors'] = f['sensors']
Lei YU069e4402018-01-31 16:47:37 +0800570 fan['target_interface'] = f.get(
571 'target_interface',
572 'xyz.openbmc_project.Control.FanSpeed')
Matt Spinler78498c92017-04-11 13:59:46 -0500573 fans.append(fan)
574
575 return fans
576
577
Gunnar Millsee8a2812017-06-02 14:26:47 -0500578def getConditionInZoneConditions(zone_condition, zone_conditions_data):
579 """
580 Parses the zone conditions definition YAML files to find the condition
581 that match both the zone condition passed in.
582 """
583
584 condition = {}
585
586 for c in zone_conditions_data['conditions']:
587
588 if zone_condition != c['name']:
589 continue
590 condition['type'] = c['type']
591 properties = []
592 for p in c['properties']:
593 property = {}
594 property['property'] = p['property']
595 property['interface'] = p['interface']
596 property['path'] = p['path']
597 property['type'] = p['type'].lower()
598 property['value'] = str(p['value']).lower()
599 properties.append(property)
600 condition['properties'] = properties
601
602 return condition
603
604
605def buildZoneData(zone_data, fan_data, events_data, zone_conditions_data):
Matt Spinler78498c92017-04-11 13:59:46 -0500606 """
607 Combines the zone definition YAML and fan
608 definition YAML to create a data structure defining
609 the fan cooling zones.
610 """
611
612 zone_groups = []
613
614 for group in zone_data:
615 conditions = []
Gunnar Millsee8a2812017-06-02 14:26:47 -0500616 # zone conditions are optional
617 if 'zone_conditions' in group and group['zone_conditions'] is not None:
618 for c in group['zone_conditions']:
619
620 if not zone_conditions_data:
Gunnar Millsb751f322017-06-06 15:14:11 -0500621 sys.exit("No zone_conditions YAML file but " +
Gunnar Millsee8a2812017-06-02 14:26:47 -0500622 "zone_conditions used in zone YAML")
623
624 condition = getConditionInZoneConditions(c['name'],
625 zone_conditions_data)
626
627 if not condition:
628 sys.exit("Missing zone condition " + c['name'])
629
630 conditions.append(condition)
Matt Spinler78498c92017-04-11 13:59:46 -0500631
632 zone_group = {}
633 zone_group['conditions'] = conditions
634
635 zones = []
636 for z in group['zones']:
637 zone = {}
638
Gunnar Mills67e95512017-06-02 14:35:18 -0500639 # 'zone' is required
640 if ('zone' not in z) or (z['zone'] is None):
Matt Spinler78498c92017-04-11 13:59:46 -0500641 sys.exit("Missing fan zone number in " + zone_yaml)
642
643 zone['num'] = z['zone']
644
645 zone['full_speed'] = z['full_speed']
646
Matthew Barth1de66622017-06-12 13:13:02 -0500647 zone['default_floor'] = z['default_floor']
648
Matthew Bartha9561842017-06-29 11:43:45 -0500649 # 'increase_delay' is optional (use 0 by default)
650 key = 'increase_delay'
651 zone[key] = z.setdefault(key, 0)
652
653 # 'decrease_interval' is optional (use 0 by default)
654 key = 'decrease_interval'
655 zone[key] = z.setdefault(key, 0)
656
Gunnar Mills67e95512017-06-02 14:35:18 -0500657 # 'cooling_profiles' is optional (use 'all' instead)
658 if ('cooling_profiles' not in z) or \
Matt Spinler78498c92017-04-11 13:59:46 -0500659 (z['cooling_profiles'] is None):
660 profiles = ["all"]
661 else:
662 profiles = z['cooling_profiles']
663
664 fans = getFansInZone(z['zone'], profiles, fan_data)
Gunnar Millsb751f322017-06-06 15:14:11 -0500665 events = getEventsInZone(z['zone'], group['zone_conditions'],
666 events_data)
Matt Spinler78498c92017-04-11 13:59:46 -0500667
668 if len(fans) == 0:
669 sys.exit("Didn't find any fans in zone " + str(zone['num']))
670
671 zone['fans'] = fans
Matthew Barthd4d0f082017-05-16 13:51:10 -0500672 zone['events'] = events
Matt Spinler78498c92017-04-11 13:59:46 -0500673 zones.append(zone)
674
675 zone_group['zones'] = zones
676 zone_groups.append(zone_group)
677
678 return zone_groups
679
680
Matt Spinlerd08dbe22017-04-11 13:52:54 -0500681if __name__ == '__main__':
682 parser = ArgumentParser(
683 description="Phosphor fan zone definition parser")
684
685 parser.add_argument('-z', '--zone_yaml', dest='zone_yaml',
686 default="example/zones.yaml",
687 help='fan zone definitional yaml')
688 parser.add_argument('-f', '--fan_yaml', dest='fan_yaml',
689 default="example/fans.yaml",
690 help='fan definitional yaml')
Matthew Barthd4d0f082017-05-16 13:51:10 -0500691 parser.add_argument('-e', '--events_yaml', dest='events_yaml',
692 help='events to set speeds yaml')
Gunnar Millsee8a2812017-06-02 14:26:47 -0500693 parser.add_argument('-c', '--zone_conditions_yaml',
694 dest='zone_conditions_yaml',
695 help='conditions to determine zone yaml')
Matt Spinlerd08dbe22017-04-11 13:52:54 -0500696 parser.add_argument('-o', '--output_dir', dest='output_dir',
697 default=".",
698 help='output directory')
699 args = parser.parse_args()
700
701 if not args.zone_yaml or not args.fan_yaml:
702 parser.print_usage()
William A. Kennington III3e781062018-10-19 17:18:34 -0700703 sys.exit(1)
Matt Spinlerd08dbe22017-04-11 13:52:54 -0500704
705 with open(args.zone_yaml, 'r') as zone_input:
706 zone_data = yaml.safe_load(zone_input) or {}
707
708 with open(args.fan_yaml, 'r') as fan_input:
709 fan_data = yaml.safe_load(fan_input) or {}
710
Matthew Barthd4d0f082017-05-16 13:51:10 -0500711 events_data = {}
712 if args.events_yaml:
713 with open(args.events_yaml, 'r') as events_input:
714 events_data = yaml.safe_load(events_input) or {}
715
Gunnar Millsee8a2812017-06-02 14:26:47 -0500716 zone_conditions_data = {}
717 if args.zone_conditions_yaml:
718 with open(args.zone_conditions_yaml, 'r') as zone_conditions_input:
719 zone_conditions_data = yaml.safe_load(zone_conditions_input) or {}
720
Matt Spinleree7f6422017-05-09 11:03:14 -0500721 zone_config = buildZoneData(zone_data.get('zone_configuration', {}),
Gunnar Millsee8a2812017-06-02 14:26:47 -0500722 fan_data, events_data, zone_conditions_data)
Matt Spinleree7f6422017-05-09 11:03:14 -0500723
724 manager_config = zone_data.get('manager_configuration', {})
725
726 if manager_config.get('power_on_delay') is None:
727 manager_config['power_on_delay'] = 0
Matt Spinlerd08dbe22017-04-11 13:52:54 -0500728
Matthew Barth702c4a52018-02-28 16:23:11 -0600729 tmpls_dir = os.path.join(
730 os.path.dirname(os.path.realpath(__file__)),
731 "templates")
Matt Spinlerd08dbe22017-04-11 13:52:54 -0500732 output_file = os.path.join(args.output_dir, "fan_zone_defs.cpp")
Matthew Barth702c4a52018-02-28 16:23:11 -0600733 if sys.version_info < (3, 0):
734 lkup = TemplateLookup(
735 directories=tmpls_dir.split(),
736 disable_unicode=True)
737 else:
738 lkup = TemplateLookup(
739 directories=tmpls_dir.split())
740 tmpl = lkup.get_template('fan_zone_defs.mako.cpp')
Matt Spinlerd08dbe22017-04-11 13:52:54 -0500741 with open(output_file, 'w') as output:
Matthew Barth702c4a52018-02-28 16:23:11 -0600742 output.write(tmpl.render(zones=zone_config,
743 mgr_data=manager_config))