blob: b89e5bc6d1b8a339f0b9239e32741e1fd3a88d2c [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
Matthew Barthe3d1c4a2018-01-11 13:53:49 -0600396 # Add optional set speed actions and function parameters
397 event['action'] = []
398 if ('actions' in e) and \
399 (e['actions'] is not None):
400 event['action'] = getActions(e, e, events_data)
Matthew Barth7f272fd2017-09-12 16:16:56 -0500401
Matthew Barth67967f92017-09-22 12:43:57 -0500402 # Add signal handlers
403 signals = []
Matthew Barth6c050692017-12-05 15:30:09 -0600404 for group in event['groups']:
405 for member in group['members']:
406 for eMatches in e['matches']:
407 signal = {}
408 eMatch = next(m for m in events_data['matches']
409 if m['name'] == eMatches['name'])
410 signal['match'] = eMatch['name']
411 params = []
412 if ('parameters' in eMatch) and \
413 (eMatch['parameters'] is not None):
414 for p in eMatch['parameters']:
415 params.append(member[str(p)])
416 signal['mparams'] = params
417 eSignal = next(s for s in events_data['signals']
418 if s['name'] == eMatch['signal'])
419 signal['signal'] = eSignal['name']
420 sparams = {}
421 if ('parameters' in eSignal) and \
422 (eSignal['parameters'] is not None):
423 splist = []
424 for p in eSignal['parameters']:
425 sp = str(p)
426 if (sp != 'type'):
427 splist.append(sp)
428 if (sp != 'group'):
429 sparams[sp] = "\"" + member[sp] + "\""
430 else:
431 sparams[sp] = "Group{\n"
432 for m in group['members']:
433 sparams[sp] += (
434 "{\n" +
435 "\"" + str(m['object']) + "\",\n" +
436 "{\"" + str(m['interface']) + "\"," +
437 "\"" + str(m['property']) + "\"}\n" +
438 "},\n")
439 sparams[sp] += "}"
Matthew Barth9f964bf2017-10-02 15:07:00 -0500440 else:
Matthew Barth6c050692017-12-05 15:30:09 -0600441 sparams[sp] = member[sp]
442 sparams['params'] = splist
443 signal['sparams'] = sparams
444 # Add signal handler
445 eHandler = next(h for h in events_data['handlers']
446 if h['name'] == eSignal['handler'])
447 signal['handler'] = eHandler['name']
448 hparams = {}
449 if ('parameters' in eHandler) and \
450 (eHandler['parameters'] is not None):
451 hplist = []
452 for p in eHandler['parameters']:
453 hp = str(p)
454 if (hp != 'type'):
455 hplist.append(hp)
456 if (hp != 'group'):
457 hparams[hp] = "\"" + member[hp] + "\""
458 else:
459 hparams[hp] = "Group{\n"
460 for m in group['members']:
461 hparams[hp] += (
462 "{\n" +
463 "\"" + str(m['object']) + "\",\n" +
464 "{\"" + str(m['interface']) + "\"," +
465 "\"" + str(m['property']) + "\"}\n" +
466 "},\n")
467 hparams[hp] += "}"
Matthew Barth9f964bf2017-10-02 15:07:00 -0500468 else:
Matthew Barth6c050692017-12-05 15:30:09 -0600469 hparams[hp] = member[hp]
470 hparams['params'] = hplist
471 signal['hparams'] = hparams
472 signals.append(signal)
Matthew Barth67967f92017-09-22 12:43:57 -0500473 event['signals'] = signals
Matthew Barth7f272fd2017-09-12 16:16:56 -0500474
475 # Add optional action call timer
476 timer = {}
477 interval = "static_cast<std::chrono::seconds>"
478 if ('timer' in e) and \
479 (e['timer'] is not None):
480 timer['interval'] = (interval +
481 "(" +
482 str(e['timer']['interval']) +
483 ")")
484 else:
485 timer['interval'] = (interval +
486 "(" + str(0) + ")")
Matthew Barth7b7ceb82017-10-04 12:59:50 -0500487 timer['type'] = "util::Timer::TimerType::repeating"
Matthew Barth7f272fd2017-09-12 16:16:56 -0500488 event['timer'] = timer
489
490 return event
491
492
493def addPrecondition(zNum, zCond, event, events_data):
Matthew Barth9af190c2017-08-08 14:20:43 -0500494 """
495 Parses the precondition section of an event and populates the necessary
496 structures to generate a precondition for a set speed event.
497 """
498 precond = {}
499 # Add set speed event precondition group
Matthew Barth6c050692017-12-05 15:30:09 -0600500 grps = getGroups(zNum, zCond, event['precondition'], events_data)
501 if not grps:
502 return
503 precond['pcgrps'] = grps
Matthew Barth9af190c2017-08-08 14:20:43 -0500504
Matthew Barth7f272fd2017-09-12 16:16:56 -0500505 # Add set speed event precondition actions
506 pc = []
507 pcs = {}
508 pcs['name'] = event['precondition']['name']
509 epc = next(p for p in events_data['preconditions']
Matthew Barth9af190c2017-08-08 14:20:43 -0500510 if p['name'] == event['precondition']['name'])
511 params = []
Matthew Barth7f272fd2017-09-12 16:16:56 -0500512 for p in epc['parameters']:
Matthew Barth9af190c2017-08-08 14:20:43 -0500513 param = {}
514 if p == 'groups':
515 param['type'] = "std::vector<PrecondGroup>"
516 param['open'] = "{"
517 param['close'] = "}"
518 values = []
Matthew Barth6c050692017-12-05 15:30:09 -0600519 for group in precond['pcgrps']:
520 for pcgrp in group['members']:
521 value = {}
522 value['value'] = (
523 "PrecondGroup{\"" +
524 str(pcgrp['object']) + "\",\"" +
525 str(pcgrp['interface']) + "\",\"" +
526 str(pcgrp['property']) + "\"," +
527 "static_cast<" +
528 str(pcgrp['type']).lower() + ">")
529 if isinstance(pcgrp['value'], str) or \
530 "string" in str(pcgrp['type']).lower():
531 value['value'] += ("(" + str(pcgrp['value']) + ")}")
532 else:
533 value['value'] += \
534 ("(" + str(pcgrp['value']).lower() + ")}")
535 values.append(value)
Matthew Barth9af190c2017-08-08 14:20:43 -0500536 param['values'] = values
537 params.append(param)
Matthew Barth7f272fd2017-09-12 16:16:56 -0500538 pcs['params'] = params
539 pc.append(pcs)
Matthew Barth9af190c2017-08-08 14:20:43 -0500540 precond['pcact'] = pc
541
Matthew Barth7f272fd2017-09-12 16:16:56 -0500542 pcevents = []
543 for pce in event['precondition']['events']:
544 pcevent = getEvent(zNum, zCond, pce, events_data)
545 if not pcevent:
546 continue
547 pcevents.append(pcevent)
548 precond['pcevts'] = pcevents
549
Matthew Barth67967f92017-09-22 12:43:57 -0500550 # Add precondition signal handlers
551 signals = []
Matthew Barth6c050692017-12-05 15:30:09 -0600552 for group in precond['pcgrps']:
553 for member in group['members']:
554 for eMatches in event['precondition']['matches']:
555 signal = {}
556 eMatch = next(m for m in events_data['matches']
557 if m['name'] == eMatches['name'])
558 signal['match'] = eMatch['name']
559 params = []
560 if ('parameters' in eMatch) and \
561 (eMatch['parameters'] is not None):
562 for p in eMatch['parameters']:
563 params.append(member[str(p)])
564 signal['mparams'] = params
565 eSignal = next(s for s in events_data['signals']
566 if s['name'] == eMatch['signal'])
567 signal['signal'] = eSignal['name']
568 sparams = {}
569 if ('parameters' in eSignal) and \
570 (eSignal['parameters'] is not None):
571 splist = []
572 for p in eSignal['parameters']:
573 sp = str(p)
574 if (sp != 'type'):
575 splist.append(sp)
576 if (sp != 'group'):
577 sparams[sp] = "\"" + member[sp] + "\""
578 else:
579 sparams[sp] = "Group{\n"
580 for m in group:
581 sparams[sp] += (
582 "{\n" +
583 "\"" + str(m['object']) + "\",\n" +
584 "{\"" + str(m['interface']) + "\"," +
585 "\"" + str(m['property']) + "\"}\n" +
586 "},\n")
587 sparams[sp] += "}"
Matthew Barth9f964bf2017-10-02 15:07:00 -0500588 else:
Matthew Barth6c050692017-12-05 15:30:09 -0600589 sparams[sp] = member[sp]
590 sparams['params'] = splist
591 signal['sparams'] = sparams
592 # Add signal handler
593 eHandler = next(h for h in events_data['handlers']
594 if h['name'] == eSignal['handler'])
595 signal['handler'] = eHandler['name']
596 hparams = {}
597 if ('parameters' in eHandler) and \
598 (eHandler['parameters'] is not None):
599 hplist = []
600 for p in eHandler['parameters']:
601 hp = str(p)
602 if (hp != 'type'):
603 hplist.append(hp)
604 if (hp != 'group'):
605 hparams[hp] = "\"" + member[hp] + "\""
606 else:
607 hparams[hp] = "Group{\n"
608 for m in group:
609 hparams[hp] += (
610 "{\n" +
611 "\"" + str(m['object']) + "\",\n" +
612 "{\"" + str(m['interface']) + "\"," +
613 "\"" + str(m['property']) + "\"}\n" +
614 "},\n")
615 hparams[hp] += "}"
Matthew Barth9f964bf2017-10-02 15:07:00 -0500616 else:
Matthew Barth6c050692017-12-05 15:30:09 -0600617 hparams[hp] = member[hp]
618 hparams['params'] = hplist
619 signal['hparams'] = hparams
620 signals.append(signal)
Matthew Barth67967f92017-09-22 12:43:57 -0500621 precond['pcsigs'] = signals
Matthew Barth9af190c2017-08-08 14:20:43 -0500622
Matthew Barth90149802017-08-15 10:51:37 -0500623 # Add optional action call timer
624 timer = {}
625 interval = "static_cast<std::chrono::seconds>"
626 if ('timer' in event['precondition']) and \
627 (event['precondition']['timer'] is not None):
628 timer['interval'] = (interval +
629 "(" +
630 str(event['precondition']['timer']['interval']) +
631 ")")
632 else:
633 timer['interval'] = (interval +
634 "(" + str(0) + ")")
Matthew Barth7b7ceb82017-10-04 12:59:50 -0500635 timer['type'] = "util::Timer::TimerType::repeating"
Matthew Barth90149802017-08-15 10:51:37 -0500636 precond['pctime'] = timer
637
Matthew Barth9af190c2017-08-08 14:20:43 -0500638 return precond
639
640
Gunnar Millsb751f322017-06-06 15:14:11 -0500641def getEventsInZone(zone_num, zone_conditions, events_data):
Matthew Barthd4d0f082017-05-16 13:51:10 -0500642 """
643 Constructs the event entries defined for each zone using the events yaml
644 provided.
645 """
646 events = []
Matthew Barthba102b32017-05-16 16:13:56 -0500647
Matthew Barthd4d0f082017-05-16 13:51:10 -0500648 if 'events' in events_data:
649 for e in events_data['events']:
Matthew Barthd4d0f082017-05-16 13:51:10 -0500650 event = {}
Matthew Barth9af190c2017-08-08 14:20:43 -0500651 # Add precondition if given
652 if ('precondition' in e) and \
653 (e['precondition'] is not None):
Matthew Barth7f272fd2017-09-12 16:16:56 -0500654 event['pc'] = addPrecondition(zone_num,
655 zone_conditions,
656 e,
657 events_data)
Matthew Barth90149802017-08-15 10:51:37 -0500658 else:
Matthew Barth7f272fd2017-09-12 16:16:56 -0500659 event = getEvent(zone_num, zone_conditions, e, events_data)
660 if not event:
661 continue
Matthew Barthd4d0f082017-05-16 13:51:10 -0500662 events.append(event)
663
664 return events
665
666
Matt Spinler78498c92017-04-11 13:59:46 -0500667def getFansInZone(zone_num, profiles, fan_data):
668 """
669 Parses the fan definition YAML files to find the fans
670 that match both the zone passed in and one of the
671 cooling profiles.
672 """
673
674 fans = []
675
676 for f in fan_data['fans']:
677
678 if zone_num != f['cooling_zone']:
679 continue
680
Gunnar Mills67e95512017-06-02 14:35:18 -0500681 # 'cooling_profile' is optional (use 'all' instead)
Matt Spinler78498c92017-04-11 13:59:46 -0500682 if f.get('cooling_profile') is None:
683 profile = "all"
684 else:
685 profile = f['cooling_profile']
686
687 if profile not in profiles:
688 continue
689
690 fan = {}
691 fan['name'] = f['inventory']
692 fan['sensors'] = f['sensors']
Lei YU069e4402018-01-31 16:47:37 +0800693 fan['target_interface'] = f.get(
694 'target_interface',
695 'xyz.openbmc_project.Control.FanSpeed')
Matt Spinler78498c92017-04-11 13:59:46 -0500696 fans.append(fan)
697
698 return fans
699
700
Gunnar Millsee8a2812017-06-02 14:26:47 -0500701def getConditionInZoneConditions(zone_condition, zone_conditions_data):
702 """
703 Parses the zone conditions definition YAML files to find the condition
704 that match both the zone condition passed in.
705 """
706
707 condition = {}
708
709 for c in zone_conditions_data['conditions']:
710
711 if zone_condition != c['name']:
712 continue
713 condition['type'] = c['type']
714 properties = []
715 for p in c['properties']:
716 property = {}
717 property['property'] = p['property']
718 property['interface'] = p['interface']
719 property['path'] = p['path']
720 property['type'] = p['type'].lower()
721 property['value'] = str(p['value']).lower()
722 properties.append(property)
723 condition['properties'] = properties
724
725 return condition
726
727
728def buildZoneData(zone_data, fan_data, events_data, zone_conditions_data):
Matt Spinler78498c92017-04-11 13:59:46 -0500729 """
730 Combines the zone definition YAML and fan
731 definition YAML to create a data structure defining
732 the fan cooling zones.
733 """
734
735 zone_groups = []
736
737 for group in zone_data:
738 conditions = []
Gunnar Millsee8a2812017-06-02 14:26:47 -0500739 # zone conditions are optional
740 if 'zone_conditions' in group and group['zone_conditions'] is not None:
741 for c in group['zone_conditions']:
742
743 if not zone_conditions_data:
Gunnar Millsb751f322017-06-06 15:14:11 -0500744 sys.exit("No zone_conditions YAML file but " +
Gunnar Millsee8a2812017-06-02 14:26:47 -0500745 "zone_conditions used in zone YAML")
746
747 condition = getConditionInZoneConditions(c['name'],
748 zone_conditions_data)
749
750 if not condition:
751 sys.exit("Missing zone condition " + c['name'])
752
753 conditions.append(condition)
Matt Spinler78498c92017-04-11 13:59:46 -0500754
755 zone_group = {}
756 zone_group['conditions'] = conditions
757
758 zones = []
759 for z in group['zones']:
760 zone = {}
761
Gunnar Mills67e95512017-06-02 14:35:18 -0500762 # 'zone' is required
763 if ('zone' not in z) or (z['zone'] is None):
Matt Spinler78498c92017-04-11 13:59:46 -0500764 sys.exit("Missing fan zone number in " + zone_yaml)
765
766 zone['num'] = z['zone']
767
768 zone['full_speed'] = z['full_speed']
769
Matthew Barth1de66622017-06-12 13:13:02 -0500770 zone['default_floor'] = z['default_floor']
771
Matthew Bartha9561842017-06-29 11:43:45 -0500772 # 'increase_delay' is optional (use 0 by default)
773 key = 'increase_delay'
774 zone[key] = z.setdefault(key, 0)
775
776 # 'decrease_interval' is optional (use 0 by default)
777 key = 'decrease_interval'
778 zone[key] = z.setdefault(key, 0)
779
Gunnar Mills67e95512017-06-02 14:35:18 -0500780 # 'cooling_profiles' is optional (use 'all' instead)
781 if ('cooling_profiles' not in z) or \
Matt Spinler78498c92017-04-11 13:59:46 -0500782 (z['cooling_profiles'] is None):
783 profiles = ["all"]
784 else:
785 profiles = z['cooling_profiles']
786
787 fans = getFansInZone(z['zone'], profiles, fan_data)
Gunnar Millsb751f322017-06-06 15:14:11 -0500788 events = getEventsInZone(z['zone'], group['zone_conditions'],
789 events_data)
Matt Spinler78498c92017-04-11 13:59:46 -0500790
791 if len(fans) == 0:
792 sys.exit("Didn't find any fans in zone " + str(zone['num']))
793
794 zone['fans'] = fans
Matthew Barthd4d0f082017-05-16 13:51:10 -0500795 zone['events'] = events
Matt Spinler78498c92017-04-11 13:59:46 -0500796 zones.append(zone)
797
798 zone_group['zones'] = zones
799 zone_groups.append(zone_group)
800
801 return zone_groups
802
803
Matt Spinlerd08dbe22017-04-11 13:52:54 -0500804if __name__ == '__main__':
805 parser = ArgumentParser(
806 description="Phosphor fan zone definition parser")
807
808 parser.add_argument('-z', '--zone_yaml', dest='zone_yaml',
809 default="example/zones.yaml",
810 help='fan zone definitional yaml')
811 parser.add_argument('-f', '--fan_yaml', dest='fan_yaml',
812 default="example/fans.yaml",
813 help='fan definitional yaml')
Matthew Barthd4d0f082017-05-16 13:51:10 -0500814 parser.add_argument('-e', '--events_yaml', dest='events_yaml',
815 help='events to set speeds yaml')
Gunnar Millsee8a2812017-06-02 14:26:47 -0500816 parser.add_argument('-c', '--zone_conditions_yaml',
817 dest='zone_conditions_yaml',
818 help='conditions to determine zone yaml')
Matt Spinlerd08dbe22017-04-11 13:52:54 -0500819 parser.add_argument('-o', '--output_dir', dest='output_dir',
820 default=".",
821 help='output directory')
822 args = parser.parse_args()
823
824 if not args.zone_yaml or not args.fan_yaml:
825 parser.print_usage()
826 sys.exit(-1)
827
828 with open(args.zone_yaml, 'r') as zone_input:
829 zone_data = yaml.safe_load(zone_input) or {}
830
831 with open(args.fan_yaml, 'r') as fan_input:
832 fan_data = yaml.safe_load(fan_input) or {}
833
Matthew Barthd4d0f082017-05-16 13:51:10 -0500834 events_data = {}
835 if args.events_yaml:
836 with open(args.events_yaml, 'r') as events_input:
837 events_data = yaml.safe_load(events_input) or {}
838
Gunnar Millsee8a2812017-06-02 14:26:47 -0500839 zone_conditions_data = {}
840 if args.zone_conditions_yaml:
841 with open(args.zone_conditions_yaml, 'r') as zone_conditions_input:
842 zone_conditions_data = yaml.safe_load(zone_conditions_input) or {}
843
Matt Spinleree7f6422017-05-09 11:03:14 -0500844 zone_config = buildZoneData(zone_data.get('zone_configuration', {}),
Gunnar Millsee8a2812017-06-02 14:26:47 -0500845 fan_data, events_data, zone_conditions_data)
Matt Spinleree7f6422017-05-09 11:03:14 -0500846
847 manager_config = zone_data.get('manager_configuration', {})
848
849 if manager_config.get('power_on_delay') is None:
850 manager_config['power_on_delay'] = 0
Matt Spinlerd08dbe22017-04-11 13:52:54 -0500851
852 output_file = os.path.join(args.output_dir, "fan_zone_defs.cpp")
853 with open(output_file, 'w') as output:
Matt Spinleree7f6422017-05-09 11:03:14 -0500854 output.write(Template(tmpl).render(zones=zone_config,
855 mgr_data=manager_config))