blob: 40bec2cb8f9b69eee7713a4c989802b092c64f54 [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{
Matthew Barth6c050692017-12-05 15:30:09 -060046%for group in event['groups']:
47%for member in group['members']:
Matthew Barth7f272fd2017-09-12 16:16:56 -050048{
Matthew Barth67967f92017-09-22 12:43:57 -050049 "${member['object']}",
Matthew Barth7f272fd2017-09-12 16:16:56 -050050 {"${member['interface']}",
51 "${member['property']}"}
52},
53%endfor
Matthew Barth6c050692017-12-05 15:30:09 -060054%endfor
Matthew Barth7f272fd2017-09-12 16:16:56 -050055},
56std::vector<Action>{
57%for a in event['action']:
Matthew Barth4c04a012017-09-15 13:05:30 -050058%if len(a['parameters']) != 0:
Matthew Barth7f272fd2017-09-12 16:16:56 -050059make_action(action::${a['name']}(
Matthew Barth4c04a012017-09-15 13:05:30 -050060%else:
61make_action(action::${a['name']}
62%endif
Matthew Barth7f272fd2017-09-12 16:16:56 -050063%for i, p in enumerate(a['parameters']):
64%if (i+1) != len(a['parameters']):
Matthew Barth6c997d72017-10-10 15:32:09 -050065 ${p},
Matthew Barth7f272fd2017-09-12 16:16:56 -050066%else:
Matthew Barth6c997d72017-10-10 15:32:09 -050067 ${p})
Matthew Barth7f272fd2017-09-12 16:16:56 -050068%endif
69%endfor
Matthew Barth4c04a012017-09-15 13:05:30 -050070),
Matthew Barth7f272fd2017-09-12 16:16:56 -050071%endfor
72},
73Timer{
Matthew Barth7b7ceb82017-10-04 12:59:50 -050074 ${event['timer']['interval']},
75 ${event['timer']['type']}
Matthew Barth7f272fd2017-09-12 16:16:56 -050076},
Matthew Barth67967f92017-09-22 12:43:57 -050077std::vector<Signal>{
78%for s in event['signals']:
79 Signal{
Matthew Barth336f18a2017-09-26 09:15:56 -050080 match::${s['match']}(
Matthew Barth67967f92017-09-22 12:43:57 -050081 %for i, mp in enumerate(s['mparams']):
82 %if (i+1) != len(s['mparams']):
83 "${mp}",
84 %else:
85 "${mp}"
86 %endif
87 %endfor
88 ),
Matthew Barth9f964bf2017-10-02 15:07:00 -050089 make_handler(\
90 ${indent(genHandler(sig=s), 3)}\
91 )
Matthew Barth7f272fd2017-09-12 16:16:56 -050092 },
93%endfor
94}
Matthew Barth336f18a2017-09-26 09:15:56 -050095</%def>\
Matthew Barth7f272fd2017-09-12 16:16:56 -050096/* This is a generated file. */
Matt Spinlerd08dbe22017-04-11 13:52:54 -050097#include "manager.hpp"
Matthew Barthba102b32017-05-16 16:13:56 -050098#include "functor.hpp"
99#include "actions.hpp"
Matthew Barth7e527c12017-05-17 10:14:15 -0500100#include "handlers.hpp"
Matthew Barth9af190c2017-08-08 14:20:43 -0500101#include "preconditions.hpp"
Matthew Barth336f18a2017-09-26 09:15:56 -0500102#include "matches.hpp"
Matt Spinlerd08dbe22017-04-11 13:52:54 -0500103
104using namespace phosphor::fan::control;
105
Matt Spinleree7f6422017-05-09 11:03:14 -0500106const unsigned int Manager::_powerOnDelay{${mgr_data['power_on_delay']}};
107
Matt Spinlerd08dbe22017-04-11 13:52:54 -0500108const std::vector<ZoneGroup> Manager::_zoneLayouts
109{
110%for zone_group in zones:
Matthew Barth9c726672017-05-18 13:44:46 -0500111 ZoneGroup{
Gunnar Millsee8a2812017-06-02 14:26:47 -0500112 std::vector<Condition>{
113 %for condition in zone_group['conditions']:
114 Condition{
115 "${condition['type']}",
116 std::vector<ConditionProperty>{
117 %for property in condition['properties']:
118 ConditionProperty{
119 "${property['property']}",
120 "${property['interface']}",
121 "${property['path']}",
122 static_cast<${property['type']}>(${property['value']}),
123 },
124 %endfor
125 },
126 },
127 %endfor
128 },
Matthew Barth9c726672017-05-18 13:44:46 -0500129 std::vector<ZoneDefinition>{
130 %for zone in zone_group['zones']:
131 ZoneDefinition{
132 ${zone['num']},
133 ${zone['full_speed']},
Matthew Barth1de66622017-06-12 13:13:02 -0500134 ${zone['default_floor']},
Matthew Bartha9561842017-06-29 11:43:45 -0500135 ${zone['increase_delay']},
136 ${zone['decrease_interval']},
Matthew Barth9c726672017-05-18 13:44:46 -0500137 std::vector<FanDefinition>{
138 %for fan in zone['fans']:
139 FanDefinition{
140 "${fan['name']}",
141 std::vector<std::string>{
142 %for sensor in fan['sensors']:
143 "${sensor}",
144 %endfor
Lei YU069e4402018-01-31 16:47:37 +0800145 },
146 "${fan['target_interface']}"
Matthew Barth9c726672017-05-18 13:44:46 -0500147 },
148 %endfor
149 },
150 std::vector<SetSpeedEvent>{
151 %for event in zone['events']:
Matthew Barth9af190c2017-08-08 14:20:43 -0500152 %if ('pc' in event) and \
153 (event['pc'] is not None):
154 SetSpeedEvent{
155 Group{
Matthew Barth6c050692017-12-05 15:30:09 -0600156 %for group in event['pc']['pcgrps']:
157 %for member in group['members']:
Matthew Barth9af190c2017-08-08 14:20:43 -0500158 {
Matthew Barth67967f92017-09-22 12:43:57 -0500159 "${member['object']}",
Matthew Barth9af190c2017-08-08 14:20:43 -0500160 {"${member['interface']}",
161 "${member['property']}"}
162 },
163 %endfor
Matthew Barth6c050692017-12-05 15:30:09 -0600164 %endfor
Matthew Barth9af190c2017-08-08 14:20:43 -0500165 },
Matthew Barth7f272fd2017-09-12 16:16:56 -0500166 std::vector<Action>{
167 %for i, a in enumerate(event['pc']['pcact']):
Matthew Barth4c04a012017-09-15 13:05:30 -0500168 %if len(a['params']) != 0:
Matthew Barth9af190c2017-08-08 14:20:43 -0500169 make_action(
Matthew Barth7f272fd2017-09-12 16:16:56 -0500170 precondition::${a['name']}(
Matthew Barth4c04a012017-09-15 13:05:30 -0500171 %else:
172 make_action(
173 precondition::${a['name']}
174 %endif
Matthew Barth7f272fd2017-09-12 16:16:56 -0500175 %for p in a['params']:
Matthew Barth9af190c2017-08-08 14:20:43 -0500176 ${p['type']}${p['open']}
177 %for j, v in enumerate(p['values']):
178 %if (j+1) != len(p['values']):
179 ${v['value']},
180 %else:
181 ${v['value']}
182 %endif
183 %endfor
184 ${p['close']},
185 %endfor
Matthew Barth7f272fd2017-09-12 16:16:56 -0500186 %if (i+1) != len(event['pc']['pcact']):
Matthew Barth4c04a012017-09-15 13:05:30 -0500187 %if len(a['params']) != 0:
Matthew Barth7f272fd2017-09-12 16:16:56 -0500188 )),
Matthew Barth4c04a012017-09-15 13:05:30 -0500189 %else:
190 ),
191 %endif
Matthew Barth9c726672017-05-18 13:44:46 -0500192 %endif
193 %endfor
Matthew Barth7f272fd2017-09-12 16:16:56 -0500194 std::vector<SetSpeedEvent>{
195 %for pcevt in event['pc']['pcevts']:
196 SetSpeedEvent{\
197 ${indent(genSSE(event=pcevt), 6)}\
198 },
199 %endfor
200 %else:
201 SetSpeedEvent{\
202 ${indent(genSSE(event=event), 6)}
203 %endif
Matthew Barth9af190c2017-08-08 14:20:43 -0500204 %if ('pc' in event) and (event['pc'] is not None):
205 }
Matthew Barth4c04a012017-09-15 13:05:30 -0500206 %if len(event['pc']['pcact'][-1]['params']) != 0:
Matthew Barth9af190c2017-08-08 14:20:43 -0500207 )),
Matthew Barth4c04a012017-09-15 13:05:30 -0500208 %else:
209 ),
210 %endif
Matthew Barth7f272fd2017-09-12 16:16:56 -0500211 },
Matthew Barth90149802017-08-15 10:51:37 -0500212 Timer{
Matthew Barth7b7ceb82017-10-04 12:59:50 -0500213 ${event['pc']['pctime']['interval']},
214 ${event['pc']['pctime']['type']}
Matthew Barth90149802017-08-15 10:51:37 -0500215 },
Matthew Barth67967f92017-09-22 12:43:57 -0500216 std::vector<Signal>{
217 %for s in event['pc']['pcsigs']:
218 Signal{
Matthew Barth336f18a2017-09-26 09:15:56 -0500219 match::${s['match']}(
Matthew Barth67967f92017-09-22 12:43:57 -0500220 %for i, mp in enumerate(s['mparams']):
221 %if (i+1) != len(s['mparams']):
222 "${mp}",
223 %else:
224 "${mp}"
225 %endif
226 %endfor
227 ),
Matthew Barth9f964bf2017-10-02 15:07:00 -0500228 make_handler(\
229 ${indent(genHandler(sig=s), 9)}\
230 )
Matthew Barth9af190c2017-08-08 14:20:43 -0500231 },
232 %endfor
233 }
234 %endif
Matthew Barth9c726672017-05-18 13:44:46 -0500235 },
236 %endfor
237 }
238 },
239 %endfor
240 }
Matt Spinler78498c92017-04-11 13:59:46 -0500241 },
Matt Spinlerd08dbe22017-04-11 13:52:54 -0500242%endfor
243};
244'''
245
Matt Spinler78498c92017-04-11 13:59:46 -0500246
Matthew Barthbb12c922017-06-13 13:57:40 -0500247def convertToMap(listOfDict):
248 """
249 Converts a list of dictionary entries to a std::map initialization list.
250 """
Matthew Barth9a5b6992018-01-23 15:32:26 -0600251 listOfDict = listOfDict.replace('\'', '\"')
Matthew Barthbb12c922017-06-13 13:57:40 -0500252 listOfDict = listOfDict.replace('[', '{')
253 listOfDict = listOfDict.replace(']', '}')
254 listOfDict = listOfDict.replace(':', ',')
255 return listOfDict
256
257
Matthew Barth6c050692017-12-05 15:30:09 -0600258def getGroups(zNum, zCond, edata, events):
259 """
260 Extract and construct the groups for the given event.
261 """
262 groups = []
263 for eGroups in edata['groups']:
264 if ('zone_conditions' in eGroups) and \
265 (eGroups['zone_conditions'] is not None):
266 # Zone conditions are optional in the events yaml but skip
267 # if this event's condition is not in this zone's conditions
268 if all('name' in z and z['name'] is not None and
269 not any(c['name'] == z['name'] for c in zCond)
270 for z in eGroups['zone_conditions']):
271 continue
272
273 # Zone numbers are optional in the events yaml but skip if this
274 # zone's zone number is not in the event's zone numbers
275 if all('zones' in z and z['zones'] is not None and
276 zNum not in z['zones']
277 for z in eGroups['zone_conditions']):
278 continue
279
280 eGroup = next(g for g in events['groups']
281 if g['name'] == eGroups['name'])
282
283 group = {}
284 members = []
285 group['name'] = eGroup['name']
286 for m in eGroup['members']:
287 member = {}
288 member['path'] = eGroup['type']
289 member['object'] = (eGroup['type'] + m)
290 member['interface'] = eGroups['interface']
291 member['property'] = eGroups['property']['name']
292 member['type'] = eGroups['property']['type']
293 # Add expected group member's property value if given
294 if ('value' in eGroups['property']) and \
295 (eGroups['property']['value'] is not None):
296 if isinstance(eGroups['property']['value'], str) or \
297 "string" in str(member['type']).lower():
298 member['value'] = (
299 "\"" + eGroups['property']['value'] + "\"")
300 else:
301 member['value'] = eGroups['property']['value']
302 members.append(member)
303 group['members'] = members
304 groups.append(group)
305 return groups
306
307
Matthew Barth9df74752017-10-11 14:39:31 -0500308def getActions(edata, actions, events):
309 """
310 Extracts and constructs the make_action function call for
311 all the actions within the given event.
312 """
313 action = []
314 for eActions in actions['actions']:
315 actions = {}
316 eAction = next(a for a in events['actions']
317 if a['name'] == eActions['name'])
318 actions['name'] = eAction['name']
319 params = []
320 if ('parameters' in eAction) and \
321 (eAction['parameters'] is not None):
322 for p in eAction['parameters']:
323 param = "static_cast<"
324 if type(eActions[p]) is not dict:
325 if p == 'actions':
326 param = "std::vector<Action>{"
327 pActs = getActions(edata, eActions, events)
328 for a in pActs:
329 if (len(a['parameters']) != 0):
330 param += (
331 "make_action(action::" +
332 a['name'] +
333 "(\n")
334 for i, ap in enumerate(a['parameters']):
335 if (i+1) != len(a['parameters']):
336 param += (ap + ",")
337 else:
338 param += (ap + ")")
339 else:
340 param += ("make_action(action::" + a['name'])
341 param += "),"
342 param += "}"
343 elif p == 'property':
Matthew Barth9a5b6992018-01-23 15:32:26 -0600344 if isinstance(eActions[p], str) or \
Matthew Barth6c050692017-12-05 15:30:09 -0600345 "string" in str(eActions[p]['type']).lower():
Matthew Barth9a5b6992018-01-23 15:32:26 -0600346 param += (
Matthew Barth6c050692017-12-05 15:30:09 -0600347 str(eActions[p]['type']).lower() +
Matthew Barth9a5b6992018-01-23 15:32:26 -0600348 ">(\"" + str(eActions[p]) + "\")")
349 else:
350 param += (
Matthew Barth6c050692017-12-05 15:30:09 -0600351 str(eActions[p]['type']).lower() +
352 ">(" + str(eActions[p]['value']).lower() + ")")
Matthew Barth9df74752017-10-11 14:39:31 -0500353 else:
354 # Default type to 'size_t' when not given
355 param += ("size_t>(" + str(eActions[p]).lower() + ")")
356 else:
357 if p == 'timer':
358 param = (
359 "Timer{static_cast<std::chrono::seconds>(" +
360 str(eActions[p]['delay']) + "), " +
361 "util::Timer::TimerType::" +
362 str(eActions[p]['type']) + "}")
363 else:
364 param += (str(eActions[p]['type']).lower() + ">(")
365 if p != 'map':
Matthew Barth9a5b6992018-01-23 15:32:26 -0600366 if isinstance(eActions[p]['value'], str) or \
367 "string" in str(eActions[p]['type']).lower():
368 param += \
369 "\"" + str(eActions[p]['value']) + "\")"
370 else:
371 param += \
372 str(eActions[p]['value']).lower() + ")"
Matthew Barth9df74752017-10-11 14:39:31 -0500373 else:
374 param += (
375 str(eActions[p]['type']).lower() +
376 convertToMap(str(eActions[p]['value'])) + ")")
377 params.append(param)
378 actions['parameters'] = params
379 action.append(actions)
380 return action
381
382
Matthew Barth7f272fd2017-09-12 16:16:56 -0500383def getEvent(zone_num, zone_conditions, e, events_data):
384 """
385 Parses the sections of an event and populates the properties
386 that construct an event within the generated source.
387 """
388 event = {}
Matthew Barth7f272fd2017-09-12 16:16:56 -0500389
Matthew Barth6c050692017-12-05 15:30:09 -0600390 # Add set speed event groups
391 grps = getGroups(zone_num, zone_conditions, e, events_data)
392 if not grps:
Matthew Barth7f272fd2017-09-12 16:16:56 -0500393 return
Matthew Barth6c050692017-12-05 15:30:09 -0600394 event['groups'] = grps
Matthew Barth7f272fd2017-09-12 16:16:56 -0500395
396 # Add set speed actions and function parameters
Matthew Barth9df74752017-10-11 14:39:31 -0500397 event['action'] = getActions(e, e, events_data)
Matthew Barth7f272fd2017-09-12 16:16:56 -0500398
Matthew Barth67967f92017-09-22 12:43:57 -0500399 # Add signal handlers
400 signals = []
Matthew Barth6c050692017-12-05 15:30:09 -0600401 for group in event['groups']:
402 for member in group['members']:
403 for eMatches in e['matches']:
404 signal = {}
405 eMatch = next(m for m in events_data['matches']
406 if m['name'] == eMatches['name'])
407 signal['match'] = eMatch['name']
408 params = []
409 if ('parameters' in eMatch) and \
410 (eMatch['parameters'] is not None):
411 for p in eMatch['parameters']:
412 params.append(member[str(p)])
413 signal['mparams'] = params
414 eSignal = next(s for s in events_data['signals']
415 if s['name'] == eMatch['signal'])
416 signal['signal'] = eSignal['name']
417 sparams = {}
418 if ('parameters' in eSignal) and \
419 (eSignal['parameters'] is not None):
420 splist = []
421 for p in eSignal['parameters']:
422 sp = str(p)
423 if (sp != 'type'):
424 splist.append(sp)
425 if (sp != 'group'):
426 sparams[sp] = "\"" + member[sp] + "\""
427 else:
428 sparams[sp] = "Group{\n"
429 for m in group['members']:
430 sparams[sp] += (
431 "{\n" +
432 "\"" + str(m['object']) + "\",\n" +
433 "{\"" + str(m['interface']) + "\"," +
434 "\"" + str(m['property']) + "\"}\n" +
435 "},\n")
436 sparams[sp] += "}"
Matthew Barth9f964bf2017-10-02 15:07:00 -0500437 else:
Matthew Barth6c050692017-12-05 15:30:09 -0600438 sparams[sp] = member[sp]
439 sparams['params'] = splist
440 signal['sparams'] = sparams
441 # Add signal handler
442 eHandler = next(h for h in events_data['handlers']
443 if h['name'] == eSignal['handler'])
444 signal['handler'] = eHandler['name']
445 hparams = {}
446 if ('parameters' in eHandler) and \
447 (eHandler['parameters'] is not None):
448 hplist = []
449 for p in eHandler['parameters']:
450 hp = str(p)
451 if (hp != 'type'):
452 hplist.append(hp)
453 if (hp != 'group'):
454 hparams[hp] = "\"" + member[hp] + "\""
455 else:
456 hparams[hp] = "Group{\n"
457 for m in group['members']:
458 hparams[hp] += (
459 "{\n" +
460 "\"" + str(m['object']) + "\",\n" +
461 "{\"" + str(m['interface']) + "\"," +
462 "\"" + str(m['property']) + "\"}\n" +
463 "},\n")
464 hparams[hp] += "}"
Matthew Barth9f964bf2017-10-02 15:07:00 -0500465 else:
Matthew Barth6c050692017-12-05 15:30:09 -0600466 hparams[hp] = member[hp]
467 hparams['params'] = hplist
468 signal['hparams'] = hparams
469 signals.append(signal)
Matthew Barth67967f92017-09-22 12:43:57 -0500470 event['signals'] = signals
Matthew Barth7f272fd2017-09-12 16:16:56 -0500471
472 # Add optional action call timer
473 timer = {}
474 interval = "static_cast<std::chrono::seconds>"
475 if ('timer' in e) and \
476 (e['timer'] is not None):
477 timer['interval'] = (interval +
478 "(" +
479 str(e['timer']['interval']) +
480 ")")
481 else:
482 timer['interval'] = (interval +
483 "(" + str(0) + ")")
Matthew Barth7b7ceb82017-10-04 12:59:50 -0500484 timer['type'] = "util::Timer::TimerType::repeating"
Matthew Barth7f272fd2017-09-12 16:16:56 -0500485 event['timer'] = timer
486
487 return event
488
489
490def addPrecondition(zNum, zCond, event, events_data):
Matthew Barth9af190c2017-08-08 14:20:43 -0500491 """
492 Parses the precondition section of an event and populates the necessary
493 structures to generate a precondition for a set speed event.
494 """
495 precond = {}
496 # Add set speed event precondition group
Matthew Barth6c050692017-12-05 15:30:09 -0600497 grps = getGroups(zNum, zCond, event['precondition'], events_data)
498 if not grps:
499 return
500 precond['pcgrps'] = grps
Matthew Barth9af190c2017-08-08 14:20:43 -0500501
Matthew Barth7f272fd2017-09-12 16:16:56 -0500502 # Add set speed event precondition actions
503 pc = []
504 pcs = {}
505 pcs['name'] = event['precondition']['name']
506 epc = next(p for p in events_data['preconditions']
Matthew Barth9af190c2017-08-08 14:20:43 -0500507 if p['name'] == event['precondition']['name'])
508 params = []
Matthew Barth7f272fd2017-09-12 16:16:56 -0500509 for p in epc['parameters']:
Matthew Barth9af190c2017-08-08 14:20:43 -0500510 param = {}
511 if p == 'groups':
512 param['type'] = "std::vector<PrecondGroup>"
513 param['open'] = "{"
514 param['close'] = "}"
515 values = []
Matthew Barth6c050692017-12-05 15:30:09 -0600516 for group in precond['pcgrps']:
517 for pcgrp in group['members']:
518 value = {}
519 value['value'] = (
520 "PrecondGroup{\"" +
521 str(pcgrp['object']) + "\",\"" +
522 str(pcgrp['interface']) + "\",\"" +
523 str(pcgrp['property']) + "\"," +
524 "static_cast<" +
525 str(pcgrp['type']).lower() + ">")
526 if isinstance(pcgrp['value'], str) or \
527 "string" in str(pcgrp['type']).lower():
528 value['value'] += ("(" + str(pcgrp['value']) + ")}")
529 else:
530 value['value'] += \
531 ("(" + str(pcgrp['value']).lower() + ")}")
532 values.append(value)
Matthew Barth9af190c2017-08-08 14:20:43 -0500533 param['values'] = values
534 params.append(param)
Matthew Barth7f272fd2017-09-12 16:16:56 -0500535 pcs['params'] = params
536 pc.append(pcs)
Matthew Barth9af190c2017-08-08 14:20:43 -0500537 precond['pcact'] = pc
538
Matthew Barth7f272fd2017-09-12 16:16:56 -0500539 pcevents = []
540 for pce in event['precondition']['events']:
541 pcevent = getEvent(zNum, zCond, pce, events_data)
542 if not pcevent:
543 continue
544 pcevents.append(pcevent)
545 precond['pcevts'] = pcevents
546
Matthew Barth67967f92017-09-22 12:43:57 -0500547 # Add precondition signal handlers
548 signals = []
Matthew Barth6c050692017-12-05 15:30:09 -0600549 for group in precond['pcgrps']:
550 for member in group['members']:
551 for eMatches in event['precondition']['matches']:
552 signal = {}
553 eMatch = next(m for m in events_data['matches']
554 if m['name'] == eMatches['name'])
555 signal['match'] = eMatch['name']
556 params = []
557 if ('parameters' in eMatch) and \
558 (eMatch['parameters'] is not None):
559 for p in eMatch['parameters']:
560 params.append(member[str(p)])
561 signal['mparams'] = params
562 eSignal = next(s for s in events_data['signals']
563 if s['name'] == eMatch['signal'])
564 signal['signal'] = eSignal['name']
565 sparams = {}
566 if ('parameters' in eSignal) and \
567 (eSignal['parameters'] is not None):
568 splist = []
569 for p in eSignal['parameters']:
570 sp = str(p)
571 if (sp != 'type'):
572 splist.append(sp)
573 if (sp != 'group'):
574 sparams[sp] = "\"" + member[sp] + "\""
575 else:
576 sparams[sp] = "Group{\n"
577 for m in group:
578 sparams[sp] += (
579 "{\n" +
580 "\"" + str(m['object']) + "\",\n" +
581 "{\"" + str(m['interface']) + "\"," +
582 "\"" + str(m['property']) + "\"}\n" +
583 "},\n")
584 sparams[sp] += "}"
Matthew Barth9f964bf2017-10-02 15:07:00 -0500585 else:
Matthew Barth6c050692017-12-05 15:30:09 -0600586 sparams[sp] = member[sp]
587 sparams['params'] = splist
588 signal['sparams'] = sparams
589 # Add signal handler
590 eHandler = next(h for h in events_data['handlers']
591 if h['name'] == eSignal['handler'])
592 signal['handler'] = eHandler['name']
593 hparams = {}
594 if ('parameters' in eHandler) and \
595 (eHandler['parameters'] is not None):
596 hplist = []
597 for p in eHandler['parameters']:
598 hp = str(p)
599 if (hp != 'type'):
600 hplist.append(hp)
601 if (hp != 'group'):
602 hparams[hp] = "\"" + member[hp] + "\""
603 else:
604 hparams[hp] = "Group{\n"
605 for m in group:
606 hparams[hp] += (
607 "{\n" +
608 "\"" + str(m['object']) + "\",\n" +
609 "{\"" + str(m['interface']) + "\"," +
610 "\"" + str(m['property']) + "\"}\n" +
611 "},\n")
612 hparams[hp] += "}"
Matthew Barth9f964bf2017-10-02 15:07:00 -0500613 else:
Matthew Barth6c050692017-12-05 15:30:09 -0600614 hparams[hp] = member[hp]
615 hparams['params'] = hplist
616 signal['hparams'] = hparams
617 signals.append(signal)
Matthew Barth67967f92017-09-22 12:43:57 -0500618 precond['pcsigs'] = signals
Matthew Barth9af190c2017-08-08 14:20:43 -0500619
Matthew Barth90149802017-08-15 10:51:37 -0500620 # Add optional action call timer
621 timer = {}
622 interval = "static_cast<std::chrono::seconds>"
623 if ('timer' in event['precondition']) and \
624 (event['precondition']['timer'] is not None):
625 timer['interval'] = (interval +
626 "(" +
627 str(event['precondition']['timer']['interval']) +
628 ")")
629 else:
630 timer['interval'] = (interval +
631 "(" + str(0) + ")")
Matthew Barth7b7ceb82017-10-04 12:59:50 -0500632 timer['type'] = "util::Timer::TimerType::repeating"
Matthew Barth90149802017-08-15 10:51:37 -0500633 precond['pctime'] = timer
634
Matthew Barth9af190c2017-08-08 14:20:43 -0500635 return precond
636
637
Gunnar Millsb751f322017-06-06 15:14:11 -0500638def getEventsInZone(zone_num, zone_conditions, events_data):
Matthew Barthd4d0f082017-05-16 13:51:10 -0500639 """
640 Constructs the event entries defined for each zone using the events yaml
641 provided.
642 """
643 events = []
Matthew Barthba102b32017-05-16 16:13:56 -0500644
Matthew Barthd4d0f082017-05-16 13:51:10 -0500645 if 'events' in events_data:
646 for e in events_data['events']:
Matthew Barthd4d0f082017-05-16 13:51:10 -0500647 event = {}
Matthew Barth9af190c2017-08-08 14:20:43 -0500648 # Add precondition if given
649 if ('precondition' in e) and \
650 (e['precondition'] is not None):
Matthew Barth7f272fd2017-09-12 16:16:56 -0500651 event['pc'] = addPrecondition(zone_num,
652 zone_conditions,
653 e,
654 events_data)
Matthew Barth90149802017-08-15 10:51:37 -0500655 else:
Matthew Barth7f272fd2017-09-12 16:16:56 -0500656 event = getEvent(zone_num, zone_conditions, e, events_data)
657 if not event:
658 continue
Matthew Barthd4d0f082017-05-16 13:51:10 -0500659 events.append(event)
660
661 return events
662
663
Matt Spinler78498c92017-04-11 13:59:46 -0500664def getFansInZone(zone_num, profiles, fan_data):
665 """
666 Parses the fan definition YAML files to find the fans
667 that match both the zone passed in and one of the
668 cooling profiles.
669 """
670
671 fans = []
672
673 for f in fan_data['fans']:
674
675 if zone_num != f['cooling_zone']:
676 continue
677
Gunnar Mills67e95512017-06-02 14:35:18 -0500678 # 'cooling_profile' is optional (use 'all' instead)
Matt Spinler78498c92017-04-11 13:59:46 -0500679 if f.get('cooling_profile') is None:
680 profile = "all"
681 else:
682 profile = f['cooling_profile']
683
684 if profile not in profiles:
685 continue
686
687 fan = {}
688 fan['name'] = f['inventory']
689 fan['sensors'] = f['sensors']
Lei YU069e4402018-01-31 16:47:37 +0800690 fan['target_interface'] = f.get(
691 'target_interface',
692 'xyz.openbmc_project.Control.FanSpeed')
Matt Spinler78498c92017-04-11 13:59:46 -0500693 fans.append(fan)
694
695 return fans
696
697
Gunnar Millsee8a2812017-06-02 14:26:47 -0500698def getConditionInZoneConditions(zone_condition, zone_conditions_data):
699 """
700 Parses the zone conditions definition YAML files to find the condition
701 that match both the zone condition passed in.
702 """
703
704 condition = {}
705
706 for c in zone_conditions_data['conditions']:
707
708 if zone_condition != c['name']:
709 continue
710 condition['type'] = c['type']
711 properties = []
712 for p in c['properties']:
713 property = {}
714 property['property'] = p['property']
715 property['interface'] = p['interface']
716 property['path'] = p['path']
717 property['type'] = p['type'].lower()
718 property['value'] = str(p['value']).lower()
719 properties.append(property)
720 condition['properties'] = properties
721
722 return condition
723
724
725def buildZoneData(zone_data, fan_data, events_data, zone_conditions_data):
Matt Spinler78498c92017-04-11 13:59:46 -0500726 """
727 Combines the zone definition YAML and fan
728 definition YAML to create a data structure defining
729 the fan cooling zones.
730 """
731
732 zone_groups = []
733
734 for group in zone_data:
735 conditions = []
Gunnar Millsee8a2812017-06-02 14:26:47 -0500736 # zone conditions are optional
737 if 'zone_conditions' in group and group['zone_conditions'] is not None:
738 for c in group['zone_conditions']:
739
740 if not zone_conditions_data:
Gunnar Millsb751f322017-06-06 15:14:11 -0500741 sys.exit("No zone_conditions YAML file but " +
Gunnar Millsee8a2812017-06-02 14:26:47 -0500742 "zone_conditions used in zone YAML")
743
744 condition = getConditionInZoneConditions(c['name'],
745 zone_conditions_data)
746
747 if not condition:
748 sys.exit("Missing zone condition " + c['name'])
749
750 conditions.append(condition)
Matt Spinler78498c92017-04-11 13:59:46 -0500751
752 zone_group = {}
753 zone_group['conditions'] = conditions
754
755 zones = []
756 for z in group['zones']:
757 zone = {}
758
Gunnar Mills67e95512017-06-02 14:35:18 -0500759 # 'zone' is required
760 if ('zone' not in z) or (z['zone'] is None):
Matt Spinler78498c92017-04-11 13:59:46 -0500761 sys.exit("Missing fan zone number in " + zone_yaml)
762
763 zone['num'] = z['zone']
764
765 zone['full_speed'] = z['full_speed']
766
Matthew Barth1de66622017-06-12 13:13:02 -0500767 zone['default_floor'] = z['default_floor']
768
Matthew Bartha9561842017-06-29 11:43:45 -0500769 # 'increase_delay' is optional (use 0 by default)
770 key = 'increase_delay'
771 zone[key] = z.setdefault(key, 0)
772
773 # 'decrease_interval' is optional (use 0 by default)
774 key = 'decrease_interval'
775 zone[key] = z.setdefault(key, 0)
776
Gunnar Mills67e95512017-06-02 14:35:18 -0500777 # 'cooling_profiles' is optional (use 'all' instead)
778 if ('cooling_profiles' not in z) or \
Matt Spinler78498c92017-04-11 13:59:46 -0500779 (z['cooling_profiles'] is None):
780 profiles = ["all"]
781 else:
782 profiles = z['cooling_profiles']
783
784 fans = getFansInZone(z['zone'], profiles, fan_data)
Gunnar Millsb751f322017-06-06 15:14:11 -0500785 events = getEventsInZone(z['zone'], group['zone_conditions'],
786 events_data)
Matt Spinler78498c92017-04-11 13:59:46 -0500787
788 if len(fans) == 0:
789 sys.exit("Didn't find any fans in zone " + str(zone['num']))
790
791 zone['fans'] = fans
Matthew Barthd4d0f082017-05-16 13:51:10 -0500792 zone['events'] = events
Matt Spinler78498c92017-04-11 13:59:46 -0500793 zones.append(zone)
794
795 zone_group['zones'] = zones
796 zone_groups.append(zone_group)
797
798 return zone_groups
799
800
Matt Spinlerd08dbe22017-04-11 13:52:54 -0500801if __name__ == '__main__':
802 parser = ArgumentParser(
803 description="Phosphor fan zone definition parser")
804
805 parser.add_argument('-z', '--zone_yaml', dest='zone_yaml',
806 default="example/zones.yaml",
807 help='fan zone definitional yaml')
808 parser.add_argument('-f', '--fan_yaml', dest='fan_yaml',
809 default="example/fans.yaml",
810 help='fan definitional yaml')
Matthew Barthd4d0f082017-05-16 13:51:10 -0500811 parser.add_argument('-e', '--events_yaml', dest='events_yaml',
812 help='events to set speeds yaml')
Gunnar Millsee8a2812017-06-02 14:26:47 -0500813 parser.add_argument('-c', '--zone_conditions_yaml',
814 dest='zone_conditions_yaml',
815 help='conditions to determine zone yaml')
Matt Spinlerd08dbe22017-04-11 13:52:54 -0500816 parser.add_argument('-o', '--output_dir', dest='output_dir',
817 default=".",
818 help='output directory')
819 args = parser.parse_args()
820
821 if not args.zone_yaml or not args.fan_yaml:
822 parser.print_usage()
823 sys.exit(-1)
824
825 with open(args.zone_yaml, 'r') as zone_input:
826 zone_data = yaml.safe_load(zone_input) or {}
827
828 with open(args.fan_yaml, 'r') as fan_input:
829 fan_data = yaml.safe_load(fan_input) or {}
830
Matthew Barthd4d0f082017-05-16 13:51:10 -0500831 events_data = {}
832 if args.events_yaml:
833 with open(args.events_yaml, 'r') as events_input:
834 events_data = yaml.safe_load(events_input) or {}
835
Gunnar Millsee8a2812017-06-02 14:26:47 -0500836 zone_conditions_data = {}
837 if args.zone_conditions_yaml:
838 with open(args.zone_conditions_yaml, 'r') as zone_conditions_input:
839 zone_conditions_data = yaml.safe_load(zone_conditions_input) or {}
840
Matt Spinleree7f6422017-05-09 11:03:14 -0500841 zone_config = buildZoneData(zone_data.get('zone_configuration', {}),
Gunnar Millsee8a2812017-06-02 14:26:47 -0500842 fan_data, events_data, zone_conditions_data)
Matt Spinleree7f6422017-05-09 11:03:14 -0500843
844 manager_config = zone_data.get('manager_configuration', {})
845
846 if manager_config.get('power_on_delay') is None:
847 manager_config['power_on_delay'] = 0
Matt Spinlerd08dbe22017-04-11 13:52:54 -0500848
849 output_file = os.path.join(args.output_dir, "fan_zone_defs.cpp")
850 with open(output_file, 'w') as output:
Matt Spinleree7f6422017-05-09 11:03:14 -0500851 output.write(Template(tmpl).render(zones=zone_config,
852 mgr_data=manager_config))