blob: 3ccab3618a2f6ed34705d638c5b3fd74eba324a3 [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
13
Matthew Barth336f18a2017-09-26 09:15:56 -050014tmpl = '''\
Matthew Barth7f272fd2017-09-12 16:16:56 -050015<%!
16def indent(str, depth):
17 return ''.join(4*' '*depth+line for line in str.splitlines(True))
Matthew Barth336f18a2017-09-26 09:15:56 -050018%>\
Matthew Barth9f964bf2017-10-02 15:07:00 -050019<%def name="genHandler(sig)" buffered="True">
20%if ('type' in sig['sparams']) and \
21 (sig['sparams']['type'] is not None):
22${sig['signal']}<${sig['sparams']['type']}>(
23%else:
24${sig['signal']}(
25%endif
26%for spk in sig['sparams']['params']:
27${sig['sparams'][spk]},
28%endfor
29%if ('type' in sig['hparams']) and \
30 (sig['hparams']['type'] is not None):
31handler::${sig['handler']}<${sig['hparams']['type']}>(
32%else:
33handler::${sig['handler']}(
34%endif
35%for i, hpk in enumerate(sig['hparams']['params']):
36 %if (i+1) != len(sig['hparams']['params']):
37 ${sig['hparams'][hpk]},
38 %else:
39 ${sig['hparams'][hpk]}
40 %endif
41%endfor
42))
43</%def>\
Matthew Barth7f272fd2017-09-12 16:16:56 -050044<%def name="genSSE(event)" buffered="True">
45Group{
46%for member in event['group']:
47{
Matthew Barth67967f92017-09-22 12:43:57 -050048 "${member['object']}",
Matthew Barth7f272fd2017-09-12 16:16:56 -050049 {"${member['interface']}",
50 "${member['property']}"}
51},
52%endfor
53},
54std::vector<Action>{
55%for a in event['action']:
Matthew Barth4c04a012017-09-15 13:05:30 -050056%if len(a['parameters']) != 0:
Matthew Barth7f272fd2017-09-12 16:16:56 -050057make_action(action::${a['name']}(
Matthew Barth4c04a012017-09-15 13:05:30 -050058%else:
59make_action(action::${a['name']}
60%endif
Matthew Barth7f272fd2017-09-12 16:16:56 -050061%for i, p in enumerate(a['parameters']):
62%if (i+1) != len(a['parameters']):
Matthew Barth6c997d72017-10-10 15:32:09 -050063 ${p},
Matthew Barth7f272fd2017-09-12 16:16:56 -050064%else:
Matthew Barth6c997d72017-10-10 15:32:09 -050065 ${p})
Matthew Barth7f272fd2017-09-12 16:16:56 -050066%endif
67%endfor
Matthew Barth4c04a012017-09-15 13:05:30 -050068),
Matthew Barth7f272fd2017-09-12 16:16:56 -050069%endfor
70},
71Timer{
Matthew Barth7b7ceb82017-10-04 12:59:50 -050072 ${event['timer']['interval']},
73 ${event['timer']['type']}
Matthew Barth7f272fd2017-09-12 16:16:56 -050074},
Matthew Barth67967f92017-09-22 12:43:57 -050075std::vector<Signal>{
76%for s in event['signals']:
77 Signal{
Matthew Barth336f18a2017-09-26 09:15:56 -050078 match::${s['match']}(
Matthew Barth67967f92017-09-22 12:43:57 -050079 %for i, mp in enumerate(s['mparams']):
80 %if (i+1) != len(s['mparams']):
81 "${mp}",
82 %else:
83 "${mp}"
84 %endif
85 %endfor
86 ),
Matthew Barth9f964bf2017-10-02 15:07:00 -050087 make_handler(\
88 ${indent(genHandler(sig=s), 3)}\
89 )
Matthew Barth7f272fd2017-09-12 16:16:56 -050090 },
91%endfor
92}
Matthew Barth336f18a2017-09-26 09:15:56 -050093</%def>\
Matthew Barth7f272fd2017-09-12 16:16:56 -050094/* This is a generated file. */
Matt Spinlerd08dbe22017-04-11 13:52:54 -050095#include "manager.hpp"
Matthew Barthba102b32017-05-16 16:13:56 -050096#include "functor.hpp"
97#include "actions.hpp"
Matthew Barth7e527c12017-05-17 10:14:15 -050098#include "handlers.hpp"
Matthew Barth9af190c2017-08-08 14:20:43 -050099#include "preconditions.hpp"
Matthew Barth336f18a2017-09-26 09:15:56 -0500100#include "matches.hpp"
Matt Spinlerd08dbe22017-04-11 13:52:54 -0500101
102using namespace phosphor::fan::control;
103
Matt Spinleree7f6422017-05-09 11:03:14 -0500104const unsigned int Manager::_powerOnDelay{${mgr_data['power_on_delay']}};
105
Matt Spinlerd08dbe22017-04-11 13:52:54 -0500106const std::vector<ZoneGroup> Manager::_zoneLayouts
107{
108%for zone_group in zones:
Matthew Barth9c726672017-05-18 13:44:46 -0500109 ZoneGroup{
Gunnar Millsee8a2812017-06-02 14:26:47 -0500110 std::vector<Condition>{
111 %for condition in zone_group['conditions']:
112 Condition{
113 "${condition['type']}",
114 std::vector<ConditionProperty>{
115 %for property in condition['properties']:
116 ConditionProperty{
117 "${property['property']}",
118 "${property['interface']}",
119 "${property['path']}",
120 static_cast<${property['type']}>(${property['value']}),
121 },
122 %endfor
123 },
124 },
125 %endfor
126 },
Matthew Barth9c726672017-05-18 13:44:46 -0500127 std::vector<ZoneDefinition>{
128 %for zone in zone_group['zones']:
129 ZoneDefinition{
130 ${zone['num']},
131 ${zone['full_speed']},
Matthew Barth1de66622017-06-12 13:13:02 -0500132 ${zone['default_floor']},
Matthew Bartha9561842017-06-29 11:43:45 -0500133 ${zone['increase_delay']},
134 ${zone['decrease_interval']},
Matthew Barth9c726672017-05-18 13:44:46 -0500135 std::vector<FanDefinition>{
136 %for fan in zone['fans']:
137 FanDefinition{
138 "${fan['name']}",
139 std::vector<std::string>{
140 %for sensor in fan['sensors']:
141 "${sensor}",
142 %endfor
Lei YU069e4402018-01-31 16:47:37 +0800143 },
144 "${fan['target_interface']}"
Matthew Barth9c726672017-05-18 13:44:46 -0500145 },
146 %endfor
147 },
148 std::vector<SetSpeedEvent>{
149 %for event in zone['events']:
Matthew Barth9af190c2017-08-08 14:20:43 -0500150 %if ('pc' in event) and \
151 (event['pc'] is not None):
152 SetSpeedEvent{
153 Group{
154 %for member in event['pc']['pcgrp']:
155 {
Matthew Barth67967f92017-09-22 12:43:57 -0500156 "${member['object']}",
Matthew Barth9af190c2017-08-08 14:20:43 -0500157 {"${member['interface']}",
158 "${member['property']}"}
159 },
160 %endfor
161 },
Matthew Barth7f272fd2017-09-12 16:16:56 -0500162 std::vector<Action>{
163 %for i, a in enumerate(event['pc']['pcact']):
Matthew Barth4c04a012017-09-15 13:05:30 -0500164 %if len(a['params']) != 0:
Matthew Barth9af190c2017-08-08 14:20:43 -0500165 make_action(
Matthew Barth7f272fd2017-09-12 16:16:56 -0500166 precondition::${a['name']}(
Matthew Barth4c04a012017-09-15 13:05:30 -0500167 %else:
168 make_action(
169 precondition::${a['name']}
170 %endif
Matthew Barth7f272fd2017-09-12 16:16:56 -0500171 %for p in a['params']:
Matthew Barth9af190c2017-08-08 14:20:43 -0500172 ${p['type']}${p['open']}
173 %for j, v in enumerate(p['values']):
174 %if (j+1) != len(p['values']):
175 ${v['value']},
176 %else:
177 ${v['value']}
178 %endif
179 %endfor
180 ${p['close']},
181 %endfor
Matthew Barth7f272fd2017-09-12 16:16:56 -0500182 %if (i+1) != len(event['pc']['pcact']):
Matthew Barth4c04a012017-09-15 13:05:30 -0500183 %if len(a['params']) != 0:
Matthew Barth7f272fd2017-09-12 16:16:56 -0500184 )),
Matthew Barth4c04a012017-09-15 13:05:30 -0500185 %else:
186 ),
187 %endif
Matthew Barth9c726672017-05-18 13:44:46 -0500188 %endif
189 %endfor
Matthew Barth7f272fd2017-09-12 16:16:56 -0500190 std::vector<SetSpeedEvent>{
191 %for pcevt in event['pc']['pcevts']:
192 SetSpeedEvent{\
193 ${indent(genSSE(event=pcevt), 6)}\
194 },
195 %endfor
196 %else:
197 SetSpeedEvent{\
198 ${indent(genSSE(event=event), 6)}
199 %endif
Matthew Barth9af190c2017-08-08 14:20:43 -0500200 %if ('pc' in event) and (event['pc'] is not None):
201 }
Matthew Barth4c04a012017-09-15 13:05:30 -0500202 %if len(event['pc']['pcact'][-1]['params']) != 0:
Matthew Barth9af190c2017-08-08 14:20:43 -0500203 )),
Matthew Barth4c04a012017-09-15 13:05:30 -0500204 %else:
205 ),
206 %endif
Matthew Barth7f272fd2017-09-12 16:16:56 -0500207 },
Matthew Barth90149802017-08-15 10:51:37 -0500208 Timer{
Matthew Barth7b7ceb82017-10-04 12:59:50 -0500209 ${event['pc']['pctime']['interval']},
210 ${event['pc']['pctime']['type']}
Matthew Barth90149802017-08-15 10:51:37 -0500211 },
Matthew Barth67967f92017-09-22 12:43:57 -0500212 std::vector<Signal>{
213 %for s in event['pc']['pcsigs']:
214 Signal{
Matthew Barth336f18a2017-09-26 09:15:56 -0500215 match::${s['match']}(
Matthew Barth67967f92017-09-22 12:43:57 -0500216 %for i, mp in enumerate(s['mparams']):
217 %if (i+1) != len(s['mparams']):
218 "${mp}",
219 %else:
220 "${mp}"
221 %endif
222 %endfor
223 ),
Matthew Barth9f964bf2017-10-02 15:07:00 -0500224 make_handler(\
225 ${indent(genHandler(sig=s), 9)}\
226 )
Matthew Barth9af190c2017-08-08 14:20:43 -0500227 },
228 %endfor
229 }
230 %endif
Matthew Barth9c726672017-05-18 13:44:46 -0500231 },
232 %endfor
233 }
234 },
235 %endfor
236 }
Matt Spinler78498c92017-04-11 13:59:46 -0500237 },
Matt Spinlerd08dbe22017-04-11 13:52:54 -0500238%endfor
239};
240'''
241
Matt Spinler78498c92017-04-11 13:59:46 -0500242
Matthew Barthbb12c922017-06-13 13:57:40 -0500243def convertToMap(listOfDict):
244 """
245 Converts a list of dictionary entries to a std::map initialization list.
246 """
Matthew Barth9a5b6992018-01-23 15:32:26 -0600247 listOfDict = listOfDict.replace('\'', '\"')
Matthew Barthbb12c922017-06-13 13:57:40 -0500248 listOfDict = listOfDict.replace('[', '{')
249 listOfDict = listOfDict.replace(']', '}')
250 listOfDict = listOfDict.replace(':', ',')
251 return listOfDict
252
253
Matthew Barth9df74752017-10-11 14:39:31 -0500254def getActions(edata, actions, events):
255 """
256 Extracts and constructs the make_action function call for
257 all the actions within the given event.
258 """
259 action = []
260 for eActions in actions['actions']:
261 actions = {}
262 eAction = next(a for a in events['actions']
263 if a['name'] == eActions['name'])
264 actions['name'] = eAction['name']
265 params = []
266 if ('parameters' in eAction) and \
267 (eAction['parameters'] is not None):
268 for p in eAction['parameters']:
269 param = "static_cast<"
270 if type(eActions[p]) is not dict:
271 if p == 'actions':
272 param = "std::vector<Action>{"
273 pActs = getActions(edata, eActions, events)
274 for a in pActs:
275 if (len(a['parameters']) != 0):
276 param += (
277 "make_action(action::" +
278 a['name'] +
279 "(\n")
280 for i, ap in enumerate(a['parameters']):
281 if (i+1) != len(a['parameters']):
282 param += (ap + ",")
283 else:
284 param += (ap + ")")
285 else:
286 param += ("make_action(action::" + a['name'])
287 param += "),"
288 param += "}"
289 elif p == 'property':
Matthew Barth9a5b6992018-01-23 15:32:26 -0600290 if isinstance(eActions[p], str) or \
291 "string" in str(edata['property']['type']).lower():
292 param += (
293 str(edata['property']['type']).lower() +
294 ">(\"" + str(eActions[p]) + "\")")
295 else:
296 param += (
297 str(edata['property']['type']).lower() +
298 ">(" + str(eActions[p]).lower() + ")")
Matthew Barth9df74752017-10-11 14:39:31 -0500299 else:
300 # Default type to 'size_t' when not given
301 param += ("size_t>(" + str(eActions[p]).lower() + ")")
302 else:
303 if p == 'timer':
304 param = (
305 "Timer{static_cast<std::chrono::seconds>(" +
306 str(eActions[p]['delay']) + "), " +
307 "util::Timer::TimerType::" +
308 str(eActions[p]['type']) + "}")
309 else:
310 param += (str(eActions[p]['type']).lower() + ">(")
311 if p != 'map':
Matthew Barth9a5b6992018-01-23 15:32:26 -0600312 if isinstance(eActions[p]['value'], str) or \
313 "string" in str(eActions[p]['type']).lower():
314 param += \
315 "\"" + str(eActions[p]['value']) + "\")"
316 else:
317 param += \
318 str(eActions[p]['value']).lower() + ")"
Matthew Barth9df74752017-10-11 14:39:31 -0500319 else:
320 param += (
321 str(eActions[p]['type']).lower() +
322 convertToMap(str(eActions[p]['value'])) + ")")
323 params.append(param)
324 actions['parameters'] = params
325 action.append(actions)
326 return action
327
328
Matthew Barth7f272fd2017-09-12 16:16:56 -0500329def getEvent(zone_num, zone_conditions, e, events_data):
330 """
331 Parses the sections of an event and populates the properties
332 that construct an event within the generated source.
333 """
334 event = {}
335 # Zone numbers are optional in the events yaml but skip if this
336 # zone's zone number is not in the event's zone numbers
337 if all('zones' in z and
338 z['zones'] is not None and
339 zone_num not in z['zones']
340 for z in e['zone_conditions']):
341 return
342
343 # Zone conditions are optional in the events yaml but skip
344 # if this event's condition is not in this zone's conditions
345 if all('name' in z and z['name'] is not None and
346 not any(c['name'] == z['name'] for c in zone_conditions)
347 for z in e['zone_conditions']):
348 return
349
350 # Add set speed event group
351 group = []
352 groups = next(g for g in events_data['groups']
353 if g['name'] == e['group'])
354 for member in groups['members']:
355 members = {}
Matthew Barth67967f92017-09-22 12:43:57 -0500356 members['object'] = (groups['type'] +
357 member)
Matthew Barth7f272fd2017-09-12 16:16:56 -0500358 members['interface'] = e['interface']
359 members['property'] = e['property']['name']
Matthew Barth67967f92017-09-22 12:43:57 -0500360 members['type'] = e['property']['type']
Matthew Barth7f272fd2017-09-12 16:16:56 -0500361 group.append(members)
362 event['group'] = group
363
364 # Add set speed actions and function parameters
Matthew Barth9df74752017-10-11 14:39:31 -0500365 event['action'] = getActions(e, e, events_data)
Matthew Barth7f272fd2017-09-12 16:16:56 -0500366
Matthew Barth67967f92017-09-22 12:43:57 -0500367 # Add signal handlers
368 signals = []
369 for member in group:
370 for eMatches in e['matches']:
371 signal = {}
372 eMatch = next(m for m in events_data['matches']
373 if m['name'] == eMatches['name'])
374 signal['match'] = eMatch['name']
375 params = []
376 if ('parameters' in eMatch) and \
377 (eMatch['parameters'] is not None):
378 for p in eMatch['parameters']:
379 params.append(member[str(p)])
380 signal['mparams'] = params
381 eSignal = next(s for s in events_data['signals']
382 if s['name'] == eMatch['signal'])
383 signal['signal'] = eSignal['name']
384 sparams = {}
385 if ('parameters' in eSignal) and \
386 (eSignal['parameters'] is not None):
Matthew Barth9f964bf2017-10-02 15:07:00 -0500387 splist = []
Matthew Barth67967f92017-09-22 12:43:57 -0500388 for p in eSignal['parameters']:
Matthew Barth9f964bf2017-10-02 15:07:00 -0500389 sp = str(p)
390 if (sp != 'type'):
391 splist.append(sp)
392 if (sp != 'group'):
393 sparams[sp] = "\"" + member[sp] + "\""
394 else:
395 sparams[sp] = "Group{\n"
396 for m in group:
397 sparams[sp] += (
398 "{\n" +
399 "\"" + str(m['object']) + "\",\n" +
400 "{\"" + str(m['interface']) + "\"," +
401 "\"" + str(m['property']) + "\"}\n" +
402 "},\n")
403 sparams[sp] += "}"
404 else:
405 sparams[sp] = member[sp]
406 sparams['params'] = splist
Matthew Barth67967f92017-09-22 12:43:57 -0500407 signal['sparams'] = sparams
Matthew Barth9f964bf2017-10-02 15:07:00 -0500408 # Add signal handler
409 eHandler = next(h for h in events_data['handlers']
410 if h['name'] == eSignal['handler'])
411 signal['handler'] = eHandler['name']
412 hparams = {}
413 if ('parameters' in eHandler) and \
414 (eHandler['parameters'] is not None):
415 hplist = []
416 for p in eHandler['parameters']:
417 hp = str(p)
418 if (hp != 'type'):
419 hplist.append(hp)
420 if (hp != 'group'):
421 hparams[hp] = "\"" + member[hp] + "\""
422 else:
423 hparams[hp] = "Group{\n"
424 for m in group:
425 hparams[hp] += (
426 "{\n" +
427 "\"" + str(m['object']) + "\",\n" +
428 "{\"" + str(m['interface']) + "\"," +
429 "\"" + str(m['property']) + "\"}\n" +
430 "},\n")
431 hparams[hp] += "}"
432 else:
433 hparams[hp] = member[hp]
434 hparams['params'] = hplist
435 signal['hparams'] = hparams
Matthew Barth67967f92017-09-22 12:43:57 -0500436 signals.append(signal)
437 event['signals'] = signals
Matthew Barth7f272fd2017-09-12 16:16:56 -0500438
439 # Add optional action call timer
440 timer = {}
441 interval = "static_cast<std::chrono::seconds>"
442 if ('timer' in e) and \
443 (e['timer'] is not None):
444 timer['interval'] = (interval +
445 "(" +
446 str(e['timer']['interval']) +
447 ")")
448 else:
449 timer['interval'] = (interval +
450 "(" + str(0) + ")")
Matthew Barth7b7ceb82017-10-04 12:59:50 -0500451 timer['type'] = "util::Timer::TimerType::repeating"
Matthew Barth7f272fd2017-09-12 16:16:56 -0500452 event['timer'] = timer
453
454 return event
455
456
457def addPrecondition(zNum, zCond, event, events_data):
Matthew Barth9af190c2017-08-08 14:20:43 -0500458 """
459 Parses the precondition section of an event and populates the necessary
460 structures to generate a precondition for a set speed event.
461 """
462 precond = {}
463 # Add set speed event precondition group
464 group = []
465 for grp in event['precondition']['groups']:
466 groups = next(g for g in events_data['groups']
467 if g['name'] == grp['name'])
468 for member in groups['members']:
469 members = {}
Matthew Barth67967f92017-09-22 12:43:57 -0500470 members['object'] = (groups['type'] +
471 member)
Matthew Barth9af190c2017-08-08 14:20:43 -0500472 members['interface'] = grp['interface']
473 members['property'] = grp['property']['name']
474 members['type'] = grp['property']['type']
Matthew Barth9a5b6992018-01-23 15:32:26 -0600475 if isinstance(grp['property']['value'], str) or \
476 "string" in str(members['type']).lower():
477 members['value'] = "\"" + grp['property']['value'] + "\""
478 else:
479 members['value'] = grp['property']['value']
Matthew Barth9af190c2017-08-08 14:20:43 -0500480 group.append(members)
481 precond['pcgrp'] = group
482
Matthew Barth7f272fd2017-09-12 16:16:56 -0500483 # Add set speed event precondition actions
484 pc = []
485 pcs = {}
486 pcs['name'] = event['precondition']['name']
487 epc = next(p for p in events_data['preconditions']
Matthew Barth9af190c2017-08-08 14:20:43 -0500488 if p['name'] == event['precondition']['name'])
489 params = []
Matthew Barth7f272fd2017-09-12 16:16:56 -0500490 for p in epc['parameters']:
Matthew Barth9af190c2017-08-08 14:20:43 -0500491 param = {}
492 if p == 'groups':
493 param['type'] = "std::vector<PrecondGroup>"
494 param['open'] = "{"
495 param['close'] = "}"
496 values = []
497 for pcgrp in group:
498 value = {}
499 value['value'] = (
500 "PrecondGroup{\"" +
Matthew Barth67967f92017-09-22 12:43:57 -0500501 str(pcgrp['object']) + "\",\"" +
Matthew Barth9af190c2017-08-08 14:20:43 -0500502 str(pcgrp['interface']) + "\",\"" +
503 str(pcgrp['property']) + "\"," +
504 "static_cast<" +
Matthew Barth9a5b6992018-01-23 15:32:26 -0600505 str(pcgrp['type']).lower() + ">")
506 if isinstance(pcgrp['value'], str) or \
507 "string" in str(pcgrp['type']).lower():
508 value['value'] += ("(" + str(pcgrp['value']) + ")}")
509 else:
510 value['value'] += \
511 ("(" + str(pcgrp['value']).lower() + ")}")
Matthew Barth9af190c2017-08-08 14:20:43 -0500512 values.append(value)
513 param['values'] = values
514 params.append(param)
Matthew Barth7f272fd2017-09-12 16:16:56 -0500515 pcs['params'] = params
516 pc.append(pcs)
Matthew Barth9af190c2017-08-08 14:20:43 -0500517 precond['pcact'] = pc
518
Matthew Barth7f272fd2017-09-12 16:16:56 -0500519 pcevents = []
520 for pce in event['precondition']['events']:
521 pcevent = getEvent(zNum, zCond, pce, events_data)
522 if not pcevent:
523 continue
524 pcevents.append(pcevent)
525 precond['pcevts'] = pcevents
526
Matthew Barth67967f92017-09-22 12:43:57 -0500527 # Add precondition signal handlers
528 signals = []
Matthew Barth9af190c2017-08-08 14:20:43 -0500529 for member in group:
Matthew Barth67967f92017-09-22 12:43:57 -0500530 for eMatches in event['precondition']['matches']:
531 signal = {}
532 eMatch = next(m for m in events_data['matches']
533 if m['name'] == eMatches['name'])
534 signal['match'] = eMatch['name']
535 params = []
536 if ('parameters' in eMatch) and \
537 (eMatch['parameters'] is not None):
538 for p in eMatch['parameters']:
539 params.append(member[str(p)])
540 signal['mparams'] = params
541 eSignal = next(s for s in events_data['signals']
542 if s['name'] == eMatch['signal'])
543 signal['signal'] = eSignal['name']
544 sparams = {}
545 if ('parameters' in eSignal) and \
546 (eSignal['parameters'] is not None):
Matthew Barth9f964bf2017-10-02 15:07:00 -0500547 splist = []
Matthew Barth67967f92017-09-22 12:43:57 -0500548 for p in eSignal['parameters']:
Matthew Barth9f964bf2017-10-02 15:07:00 -0500549 sp = str(p)
550 if (sp != 'type'):
551 splist.append(sp)
552 if (sp != 'group'):
553 sparams[sp] = "\"" + member[sp] + "\""
554 else:
555 sparams[sp] = "Group{\n"
556 for m in group:
557 sparams[sp] += (
558 "{\n" +
559 "\"" + str(m['object']) + "\",\n" +
560 "{\"" + str(m['interface']) + "\"," +
561 "\"" + str(m['property']) + "\"}\n" +
562 "},\n")
563 sparams[sp] += "}"
564 else:
565 sparams[sp] = member[sp]
566 sparams['params'] = splist
Matthew Barth67967f92017-09-22 12:43:57 -0500567 signal['sparams'] = sparams
Matthew Barth9f964bf2017-10-02 15:07:00 -0500568 # Add signal handler
569 eHandler = next(h for h in events_data['handlers']
570 if h['name'] == eSignal['handler'])
571 signal['handler'] = eHandler['name']
572 hparams = {}
573 if ('parameters' in eHandler) and \
574 (eHandler['parameters'] is not None):
575 hplist = []
576 for p in eHandler['parameters']:
577 hp = str(p)
578 if (hp != 'type'):
579 hplist.append(hp)
580 if (hp != 'group'):
581 hparams[hp] = "\"" + member[hp] + "\""
582 else:
583 hparams[hp] = "Group{\n"
584 for m in group:
585 hparams[hp] += (
586 "{\n" +
587 "\"" + str(m['object']) + "\",\n" +
588 "{\"" + str(m['interface']) + "\"," +
589 "\"" + str(m['property']) + "\"}\n" +
590 "},\n")
591 hparams[hp] += "}"
592 else:
593 hparams[hp] = member[hp]
594 hparams['params'] = hplist
595 signal['hparams'] = hparams
Matthew Barth67967f92017-09-22 12:43:57 -0500596 signals.append(signal)
597 precond['pcsigs'] = signals
Matthew Barth9af190c2017-08-08 14:20:43 -0500598
Matthew Barth90149802017-08-15 10:51:37 -0500599 # Add optional action call timer
600 timer = {}
601 interval = "static_cast<std::chrono::seconds>"
602 if ('timer' in event['precondition']) and \
603 (event['precondition']['timer'] is not None):
604 timer['interval'] = (interval +
605 "(" +
606 str(event['precondition']['timer']['interval']) +
607 ")")
608 else:
609 timer['interval'] = (interval +
610 "(" + str(0) + ")")
Matthew Barth7b7ceb82017-10-04 12:59:50 -0500611 timer['type'] = "util::Timer::TimerType::repeating"
Matthew Barth90149802017-08-15 10:51:37 -0500612 precond['pctime'] = timer
613
Matthew Barth9af190c2017-08-08 14:20:43 -0500614 return precond
615
616
Gunnar Millsb751f322017-06-06 15:14:11 -0500617def getEventsInZone(zone_num, zone_conditions, events_data):
Matthew Barthd4d0f082017-05-16 13:51:10 -0500618 """
619 Constructs the event entries defined for each zone using the events yaml
620 provided.
621 """
622 events = []
Matthew Barthba102b32017-05-16 16:13:56 -0500623
Matthew Barthd4d0f082017-05-16 13:51:10 -0500624 if 'events' in events_data:
625 for e in events_data['events']:
Matthew Barthd4d0f082017-05-16 13:51:10 -0500626 event = {}
Matthew Barth9af190c2017-08-08 14:20:43 -0500627 # Add precondition if given
628 if ('precondition' in e) and \
629 (e['precondition'] is not None):
Matthew Barth7f272fd2017-09-12 16:16:56 -0500630 event['pc'] = addPrecondition(zone_num,
631 zone_conditions,
632 e,
633 events_data)
Matthew Barth90149802017-08-15 10:51:37 -0500634 else:
Matthew Barth7f272fd2017-09-12 16:16:56 -0500635 event = getEvent(zone_num, zone_conditions, e, events_data)
636 if not event:
637 continue
Matthew Barthd4d0f082017-05-16 13:51:10 -0500638 events.append(event)
639
640 return events
641
642
Matt Spinler78498c92017-04-11 13:59:46 -0500643def getFansInZone(zone_num, profiles, fan_data):
644 """
645 Parses the fan definition YAML files to find the fans
646 that match both the zone passed in and one of the
647 cooling profiles.
648 """
649
650 fans = []
651
652 for f in fan_data['fans']:
653
654 if zone_num != f['cooling_zone']:
655 continue
656
Gunnar Mills67e95512017-06-02 14:35:18 -0500657 # 'cooling_profile' is optional (use 'all' instead)
Matt Spinler78498c92017-04-11 13:59:46 -0500658 if f.get('cooling_profile') is None:
659 profile = "all"
660 else:
661 profile = f['cooling_profile']
662
663 if profile not in profiles:
664 continue
665
666 fan = {}
667 fan['name'] = f['inventory']
668 fan['sensors'] = f['sensors']
Lei YU069e4402018-01-31 16:47:37 +0800669 fan['target_interface'] = f.get(
670 'target_interface',
671 'xyz.openbmc_project.Control.FanSpeed')
Matt Spinler78498c92017-04-11 13:59:46 -0500672 fans.append(fan)
673
674 return fans
675
676
Gunnar Millsee8a2812017-06-02 14:26:47 -0500677def getConditionInZoneConditions(zone_condition, zone_conditions_data):
678 """
679 Parses the zone conditions definition YAML files to find the condition
680 that match both the zone condition passed in.
681 """
682
683 condition = {}
684
685 for c in zone_conditions_data['conditions']:
686
687 if zone_condition != c['name']:
688 continue
689 condition['type'] = c['type']
690 properties = []
691 for p in c['properties']:
692 property = {}
693 property['property'] = p['property']
694 property['interface'] = p['interface']
695 property['path'] = p['path']
696 property['type'] = p['type'].lower()
697 property['value'] = str(p['value']).lower()
698 properties.append(property)
699 condition['properties'] = properties
700
701 return condition
702
703
704def buildZoneData(zone_data, fan_data, events_data, zone_conditions_data):
Matt Spinler78498c92017-04-11 13:59:46 -0500705 """
706 Combines the zone definition YAML and fan
707 definition YAML to create a data structure defining
708 the fan cooling zones.
709 """
710
711 zone_groups = []
712
713 for group in zone_data:
714 conditions = []
Gunnar Millsee8a2812017-06-02 14:26:47 -0500715 # zone conditions are optional
716 if 'zone_conditions' in group and group['zone_conditions'] is not None:
717 for c in group['zone_conditions']:
718
719 if not zone_conditions_data:
Gunnar Millsb751f322017-06-06 15:14:11 -0500720 sys.exit("No zone_conditions YAML file but " +
Gunnar Millsee8a2812017-06-02 14:26:47 -0500721 "zone_conditions used in zone YAML")
722
723 condition = getConditionInZoneConditions(c['name'],
724 zone_conditions_data)
725
726 if not condition:
727 sys.exit("Missing zone condition " + c['name'])
728
729 conditions.append(condition)
Matt Spinler78498c92017-04-11 13:59:46 -0500730
731 zone_group = {}
732 zone_group['conditions'] = conditions
733
734 zones = []
735 for z in group['zones']:
736 zone = {}
737
Gunnar Mills67e95512017-06-02 14:35:18 -0500738 # 'zone' is required
739 if ('zone' not in z) or (z['zone'] is None):
Matt Spinler78498c92017-04-11 13:59:46 -0500740 sys.exit("Missing fan zone number in " + zone_yaml)
741
742 zone['num'] = z['zone']
743
744 zone['full_speed'] = z['full_speed']
745
Matthew Barth1de66622017-06-12 13:13:02 -0500746 zone['default_floor'] = z['default_floor']
747
Matthew Bartha9561842017-06-29 11:43:45 -0500748 # 'increase_delay' is optional (use 0 by default)
749 key = 'increase_delay'
750 zone[key] = z.setdefault(key, 0)
751
752 # 'decrease_interval' is optional (use 0 by default)
753 key = 'decrease_interval'
754 zone[key] = z.setdefault(key, 0)
755
Gunnar Mills67e95512017-06-02 14:35:18 -0500756 # 'cooling_profiles' is optional (use 'all' instead)
757 if ('cooling_profiles' not in z) or \
Matt Spinler78498c92017-04-11 13:59:46 -0500758 (z['cooling_profiles'] is None):
759 profiles = ["all"]
760 else:
761 profiles = z['cooling_profiles']
762
763 fans = getFansInZone(z['zone'], profiles, fan_data)
Gunnar Millsb751f322017-06-06 15:14:11 -0500764 events = getEventsInZone(z['zone'], group['zone_conditions'],
765 events_data)
Matt Spinler78498c92017-04-11 13:59:46 -0500766
767 if len(fans) == 0:
768 sys.exit("Didn't find any fans in zone " + str(zone['num']))
769
770 zone['fans'] = fans
Matthew Barthd4d0f082017-05-16 13:51:10 -0500771 zone['events'] = events
Matt Spinler78498c92017-04-11 13:59:46 -0500772 zones.append(zone)
773
774 zone_group['zones'] = zones
775 zone_groups.append(zone_group)
776
777 return zone_groups
778
779
Matt Spinlerd08dbe22017-04-11 13:52:54 -0500780if __name__ == '__main__':
781 parser = ArgumentParser(
782 description="Phosphor fan zone definition parser")
783
784 parser.add_argument('-z', '--zone_yaml', dest='zone_yaml',
785 default="example/zones.yaml",
786 help='fan zone definitional yaml')
787 parser.add_argument('-f', '--fan_yaml', dest='fan_yaml',
788 default="example/fans.yaml",
789 help='fan definitional yaml')
Matthew Barthd4d0f082017-05-16 13:51:10 -0500790 parser.add_argument('-e', '--events_yaml', dest='events_yaml',
791 help='events to set speeds yaml')
Gunnar Millsee8a2812017-06-02 14:26:47 -0500792 parser.add_argument('-c', '--zone_conditions_yaml',
793 dest='zone_conditions_yaml',
794 help='conditions to determine zone yaml')
Matt Spinlerd08dbe22017-04-11 13:52:54 -0500795 parser.add_argument('-o', '--output_dir', dest='output_dir',
796 default=".",
797 help='output directory')
798 args = parser.parse_args()
799
800 if not args.zone_yaml or not args.fan_yaml:
801 parser.print_usage()
802 sys.exit(-1)
803
804 with open(args.zone_yaml, 'r') as zone_input:
805 zone_data = yaml.safe_load(zone_input) or {}
806
807 with open(args.fan_yaml, 'r') as fan_input:
808 fan_data = yaml.safe_load(fan_input) or {}
809
Matthew Barthd4d0f082017-05-16 13:51:10 -0500810 events_data = {}
811 if args.events_yaml:
812 with open(args.events_yaml, 'r') as events_input:
813 events_data = yaml.safe_load(events_input) or {}
814
Gunnar Millsee8a2812017-06-02 14:26:47 -0500815 zone_conditions_data = {}
816 if args.zone_conditions_yaml:
817 with open(args.zone_conditions_yaml, 'r') as zone_conditions_input:
818 zone_conditions_data = yaml.safe_load(zone_conditions_input) or {}
819
Matt Spinleree7f6422017-05-09 11:03:14 -0500820 zone_config = buildZoneData(zone_data.get('zone_configuration', {}),
Gunnar Millsee8a2812017-06-02 14:26:47 -0500821 fan_data, events_data, zone_conditions_data)
Matt Spinleree7f6422017-05-09 11:03:14 -0500822
823 manager_config = zone_data.get('manager_configuration', {})
824
825 if manager_config.get('power_on_delay') is None:
826 manager_config['power_on_delay'] = 0
Matt Spinlerd08dbe22017-04-11 13:52:54 -0500827
828 output_file = os.path.join(args.output_dir, "fan_zone_defs.cpp")
829 with open(output_file, 'w') as output:
Matt Spinleree7f6422017-05-09 11:03:14 -0500830 output.write(Template(tmpl).render(zones=zone_config,
831 mgr_data=manager_config))