blob: 43d98bcea975d99b3a623d5c212866419f745bf3 [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
Matthew Barthe7d87052018-03-21 13:58:31 -0500417 if ('parameters' in eMatch['signal']) and \
418 (eMatch['signal']['parameters'] is not None):
419 eSignal = eMatch['signal']
420 else:
421 eSignal = next(s for s in events_data['signals']
422 if s['name'] == eMatch['signal'])
Matthew Barth6c050692017-12-05 15:30:09 -0600423 signal['signal'] = eSignal['name']
424 sparams = {}
425 if ('parameters' in eSignal) and \
426 (eSignal['parameters'] is not None):
427 splist = []
428 for p in eSignal['parameters']:
429 sp = str(p)
430 if (sp != 'type'):
431 splist.append(sp)
432 if (sp != 'group'):
433 sparams[sp] = "\"" + member[sp] + "\""
434 else:
435 sparams[sp] = "Group{\n"
436 for m in group['members']:
437 sparams[sp] += (
438 "{\n" +
439 "\"" + str(m['object']) + "\",\n" +
440 "{\"" + str(m['interface']) + "\"," +
441 "\"" + str(m['property']) + "\"}\n" +
442 "},\n")
443 sparams[sp] += "}"
Matthew Barth9f964bf2017-10-02 15:07:00 -0500444 else:
Matthew Barth6c050692017-12-05 15:30:09 -0600445 sparams[sp] = member[sp]
446 sparams['params'] = splist
447 signal['sparams'] = sparams
448 # Add signal handler
449 eHandler = next(h for h in events_data['handlers']
450 if h['name'] == eSignal['handler'])
451 signal['handler'] = eHandler['name']
452 hparams = {}
453 if ('parameters' in eHandler) and \
454 (eHandler['parameters'] is not None):
455 hplist = []
456 for p in eHandler['parameters']:
457 hp = str(p)
458 if (hp != 'type'):
459 hplist.append(hp)
460 if (hp != 'group'):
461 hparams[hp] = "\"" + member[hp] + "\""
462 else:
463 hparams[hp] = "Group{\n"
464 for m in group['members']:
465 hparams[hp] += (
466 "{\n" +
467 "\"" + str(m['object']) + "\",\n" +
468 "{\"" + str(m['interface']) + "\"," +
469 "\"" + str(m['property']) + "\"}\n" +
470 "},\n")
471 hparams[hp] += "}"
Matthew Barth9f964bf2017-10-02 15:07:00 -0500472 else:
Matthew Barth6c050692017-12-05 15:30:09 -0600473 hparams[hp] = member[hp]
474 hparams['params'] = hplist
475 signal['hparams'] = hparams
476 signals.append(signal)
Matthew Barth67967f92017-09-22 12:43:57 -0500477 event['signals'] = signals
Matthew Barth7f272fd2017-09-12 16:16:56 -0500478
479 # Add optional action call timer
480 timer = {}
481 interval = "static_cast<std::chrono::seconds>"
482 if ('timer' in e) and \
483 (e['timer'] is not None):
484 timer['interval'] = (interval +
485 "(" +
486 str(e['timer']['interval']) +
487 ")")
488 else:
489 timer['interval'] = (interval +
490 "(" + str(0) + ")")
Matthew Barth7b7ceb82017-10-04 12:59:50 -0500491 timer['type'] = "util::Timer::TimerType::repeating"
Matthew Barth7f272fd2017-09-12 16:16:56 -0500492 event['timer'] = timer
493
494 return event
495
496
497def addPrecondition(zNum, zCond, event, events_data):
Matthew Barth9af190c2017-08-08 14:20:43 -0500498 """
499 Parses the precondition section of an event and populates the necessary
500 structures to generate a precondition for a set speed event.
501 """
502 precond = {}
503 # Add set speed event precondition group
Matthew Barth6c050692017-12-05 15:30:09 -0600504 grps = getGroups(zNum, zCond, event['precondition'], events_data)
505 if not grps:
506 return
507 precond['pcgrps'] = grps
Matthew Barth9af190c2017-08-08 14:20:43 -0500508
Matthew Barth7f272fd2017-09-12 16:16:56 -0500509 # Add set speed event precondition actions
510 pc = []
511 pcs = {}
512 pcs['name'] = event['precondition']['name']
513 epc = next(p for p in events_data['preconditions']
Matthew Barth9af190c2017-08-08 14:20:43 -0500514 if p['name'] == event['precondition']['name'])
515 params = []
Matthew Barth7f272fd2017-09-12 16:16:56 -0500516 for p in epc['parameters']:
Matthew Barth9af190c2017-08-08 14:20:43 -0500517 param = {}
518 if p == 'groups':
519 param['type'] = "std::vector<PrecondGroup>"
520 param['open'] = "{"
521 param['close'] = "}"
522 values = []
Matthew Barth6c050692017-12-05 15:30:09 -0600523 for group in precond['pcgrps']:
524 for pcgrp in group['members']:
525 value = {}
526 value['value'] = (
527 "PrecondGroup{\"" +
528 str(pcgrp['object']) + "\",\"" +
529 str(pcgrp['interface']) + "\",\"" +
530 str(pcgrp['property']) + "\"," +
531 "static_cast<" +
532 str(pcgrp['type']).lower() + ">")
533 if isinstance(pcgrp['value'], str) or \
534 "string" in str(pcgrp['type']).lower():
535 value['value'] += ("(" + str(pcgrp['value']) + ")}")
536 else:
537 value['value'] += \
538 ("(" + str(pcgrp['value']).lower() + ")}")
539 values.append(value)
Matthew Barth9af190c2017-08-08 14:20:43 -0500540 param['values'] = values
541 params.append(param)
Matthew Barth7f272fd2017-09-12 16:16:56 -0500542 pcs['params'] = params
543 pc.append(pcs)
Matthew Barth9af190c2017-08-08 14:20:43 -0500544 precond['pcact'] = pc
545
Matthew Barth7f272fd2017-09-12 16:16:56 -0500546 pcevents = []
547 for pce in event['precondition']['events']:
548 pcevent = getEvent(zNum, zCond, pce, events_data)
549 if not pcevent:
550 continue
551 pcevents.append(pcevent)
552 precond['pcevts'] = pcevents
553
Matthew Barth67967f92017-09-22 12:43:57 -0500554 # Add precondition signal handlers
555 signals = []
Matthew Barth6c050692017-12-05 15:30:09 -0600556 for group in precond['pcgrps']:
557 for member in group['members']:
558 for eMatches in event['precondition']['matches']:
559 signal = {}
560 eMatch = next(m for m in events_data['matches']
561 if m['name'] == eMatches['name'])
562 signal['match'] = eMatch['name']
563 params = []
564 if ('parameters' in eMatch) and \
565 (eMatch['parameters'] is not None):
566 for p in eMatch['parameters']:
567 params.append(member[str(p)])
568 signal['mparams'] = params
Matthew Barthe7d87052018-03-21 13:58:31 -0500569 if ('parameters' in eMatch['signal']) and \
570 (eMatch['signal']['parameters'] is not None):
571 eSignal = eMatch['signal']
572 else:
573 eSignal = next(s for s in events_data['signals']
574 if s['name'] == eMatch['signal'])
Matthew Barth6c050692017-12-05 15:30:09 -0600575 signal['signal'] = eSignal['name']
576 sparams = {}
577 if ('parameters' in eSignal) and \
578 (eSignal['parameters'] is not None):
579 splist = []
580 for p in eSignal['parameters']:
581 sp = str(p)
582 if (sp != 'type'):
583 splist.append(sp)
584 if (sp != 'group'):
585 sparams[sp] = "\"" + member[sp] + "\""
586 else:
587 sparams[sp] = "Group{\n"
588 for m in group:
589 sparams[sp] += (
590 "{\n" +
591 "\"" + str(m['object']) + "\",\n" +
592 "{\"" + str(m['interface']) + "\"," +
593 "\"" + str(m['property']) + "\"}\n" +
594 "},\n")
595 sparams[sp] += "}"
Matthew Barth9f964bf2017-10-02 15:07:00 -0500596 else:
Matthew Barth6c050692017-12-05 15:30:09 -0600597 sparams[sp] = member[sp]
598 sparams['params'] = splist
599 signal['sparams'] = sparams
600 # Add signal handler
601 eHandler = next(h for h in events_data['handlers']
602 if h['name'] == eSignal['handler'])
603 signal['handler'] = eHandler['name']
604 hparams = {}
605 if ('parameters' in eHandler) and \
606 (eHandler['parameters'] is not None):
607 hplist = []
608 for p in eHandler['parameters']:
609 hp = str(p)
610 if (hp != 'type'):
611 hplist.append(hp)
612 if (hp != 'group'):
613 hparams[hp] = "\"" + member[hp] + "\""
614 else:
615 hparams[hp] = "Group{\n"
616 for m in group:
617 hparams[hp] += (
618 "{\n" +
619 "\"" + str(m['object']) + "\",\n" +
620 "{\"" + str(m['interface']) + "\"," +
621 "\"" + str(m['property']) + "\"}\n" +
622 "},\n")
623 hparams[hp] += "}"
Matthew Barth9f964bf2017-10-02 15:07:00 -0500624 else:
Matthew Barth6c050692017-12-05 15:30:09 -0600625 hparams[hp] = member[hp]
626 hparams['params'] = hplist
627 signal['hparams'] = hparams
628 signals.append(signal)
Matthew Barth67967f92017-09-22 12:43:57 -0500629 precond['pcsigs'] = signals
Matthew Barth9af190c2017-08-08 14:20:43 -0500630
Matthew Barth90149802017-08-15 10:51:37 -0500631 # Add optional action call timer
632 timer = {}
633 interval = "static_cast<std::chrono::seconds>"
634 if ('timer' in event['precondition']) and \
635 (event['precondition']['timer'] is not None):
636 timer['interval'] = (interval +
637 "(" +
638 str(event['precondition']['timer']['interval']) +
639 ")")
640 else:
641 timer['interval'] = (interval +
642 "(" + str(0) + ")")
Matthew Barth7b7ceb82017-10-04 12:59:50 -0500643 timer['type'] = "util::Timer::TimerType::repeating"
Matthew Barth90149802017-08-15 10:51:37 -0500644 precond['pctime'] = timer
645
Matthew Barth9af190c2017-08-08 14:20:43 -0500646 return precond
647
648
Gunnar Millsb751f322017-06-06 15:14:11 -0500649def getEventsInZone(zone_num, zone_conditions, events_data):
Matthew Barthd4d0f082017-05-16 13:51:10 -0500650 """
651 Constructs the event entries defined for each zone using the events yaml
652 provided.
653 """
654 events = []
Matthew Barthba102b32017-05-16 16:13:56 -0500655
Matthew Barthd4d0f082017-05-16 13:51:10 -0500656 if 'events' in events_data:
657 for e in events_data['events']:
Matthew Barthd4d0f082017-05-16 13:51:10 -0500658 event = {}
Matthew Barth9af190c2017-08-08 14:20:43 -0500659 # Add precondition if given
660 if ('precondition' in e) and \
661 (e['precondition'] is not None):
Matthew Barth7f272fd2017-09-12 16:16:56 -0500662 event['pc'] = addPrecondition(zone_num,
663 zone_conditions,
664 e,
665 events_data)
Matthew Barth90149802017-08-15 10:51:37 -0500666 else:
Matthew Barth7f272fd2017-09-12 16:16:56 -0500667 event = getEvent(zone_num, zone_conditions, e, events_data)
668 if not event:
669 continue
Matthew Barthd4d0f082017-05-16 13:51:10 -0500670 events.append(event)
671
672 return events
673
674
Matt Spinler78498c92017-04-11 13:59:46 -0500675def getFansInZone(zone_num, profiles, fan_data):
676 """
677 Parses the fan definition YAML files to find the fans
678 that match both the zone passed in and one of the
679 cooling profiles.
680 """
681
682 fans = []
683
684 for f in fan_data['fans']:
685
686 if zone_num != f['cooling_zone']:
687 continue
688
Gunnar Mills67e95512017-06-02 14:35:18 -0500689 # 'cooling_profile' is optional (use 'all' instead)
Matt Spinler78498c92017-04-11 13:59:46 -0500690 if f.get('cooling_profile') is None:
691 profile = "all"
692 else:
693 profile = f['cooling_profile']
694
695 if profile not in profiles:
696 continue
697
698 fan = {}
699 fan['name'] = f['inventory']
700 fan['sensors'] = f['sensors']
Lei YU069e4402018-01-31 16:47:37 +0800701 fan['target_interface'] = f.get(
702 'target_interface',
703 'xyz.openbmc_project.Control.FanSpeed')
Matt Spinler78498c92017-04-11 13:59:46 -0500704 fans.append(fan)
705
706 return fans
707
708
Gunnar Millsee8a2812017-06-02 14:26:47 -0500709def getConditionInZoneConditions(zone_condition, zone_conditions_data):
710 """
711 Parses the zone conditions definition YAML files to find the condition
712 that match both the zone condition passed in.
713 """
714
715 condition = {}
716
717 for c in zone_conditions_data['conditions']:
718
719 if zone_condition != c['name']:
720 continue
721 condition['type'] = c['type']
722 properties = []
723 for p in c['properties']:
724 property = {}
725 property['property'] = p['property']
726 property['interface'] = p['interface']
727 property['path'] = p['path']
728 property['type'] = p['type'].lower()
729 property['value'] = str(p['value']).lower()
730 properties.append(property)
731 condition['properties'] = properties
732
733 return condition
734
735
736def buildZoneData(zone_data, fan_data, events_data, zone_conditions_data):
Matt Spinler78498c92017-04-11 13:59:46 -0500737 """
738 Combines the zone definition YAML and fan
739 definition YAML to create a data structure defining
740 the fan cooling zones.
741 """
742
743 zone_groups = []
744
745 for group in zone_data:
746 conditions = []
Gunnar Millsee8a2812017-06-02 14:26:47 -0500747 # zone conditions are optional
748 if 'zone_conditions' in group and group['zone_conditions'] is not None:
749 for c in group['zone_conditions']:
750
751 if not zone_conditions_data:
Gunnar Millsb751f322017-06-06 15:14:11 -0500752 sys.exit("No zone_conditions YAML file but " +
Gunnar Millsee8a2812017-06-02 14:26:47 -0500753 "zone_conditions used in zone YAML")
754
755 condition = getConditionInZoneConditions(c['name'],
756 zone_conditions_data)
757
758 if not condition:
759 sys.exit("Missing zone condition " + c['name'])
760
761 conditions.append(condition)
Matt Spinler78498c92017-04-11 13:59:46 -0500762
763 zone_group = {}
764 zone_group['conditions'] = conditions
765
766 zones = []
767 for z in group['zones']:
768 zone = {}
769
Gunnar Mills67e95512017-06-02 14:35:18 -0500770 # 'zone' is required
771 if ('zone' not in z) or (z['zone'] is None):
Matt Spinler78498c92017-04-11 13:59:46 -0500772 sys.exit("Missing fan zone number in " + zone_yaml)
773
774 zone['num'] = z['zone']
775
776 zone['full_speed'] = z['full_speed']
777
Matthew Barth1de66622017-06-12 13:13:02 -0500778 zone['default_floor'] = z['default_floor']
779
Matthew Bartha9561842017-06-29 11:43:45 -0500780 # 'increase_delay' is optional (use 0 by default)
781 key = 'increase_delay'
782 zone[key] = z.setdefault(key, 0)
783
784 # 'decrease_interval' is optional (use 0 by default)
785 key = 'decrease_interval'
786 zone[key] = z.setdefault(key, 0)
787
Gunnar Mills67e95512017-06-02 14:35:18 -0500788 # 'cooling_profiles' is optional (use 'all' instead)
789 if ('cooling_profiles' not in z) or \
Matt Spinler78498c92017-04-11 13:59:46 -0500790 (z['cooling_profiles'] is None):
791 profiles = ["all"]
792 else:
793 profiles = z['cooling_profiles']
794
795 fans = getFansInZone(z['zone'], profiles, fan_data)
Gunnar Millsb751f322017-06-06 15:14:11 -0500796 events = getEventsInZone(z['zone'], group['zone_conditions'],
797 events_data)
Matt Spinler78498c92017-04-11 13:59:46 -0500798
799 if len(fans) == 0:
800 sys.exit("Didn't find any fans in zone " + str(zone['num']))
801
802 zone['fans'] = fans
Matthew Barthd4d0f082017-05-16 13:51:10 -0500803 zone['events'] = events
Matt Spinler78498c92017-04-11 13:59:46 -0500804 zones.append(zone)
805
806 zone_group['zones'] = zones
807 zone_groups.append(zone_group)
808
809 return zone_groups
810
811
Matt Spinlerd08dbe22017-04-11 13:52:54 -0500812if __name__ == '__main__':
813 parser = ArgumentParser(
814 description="Phosphor fan zone definition parser")
815
816 parser.add_argument('-z', '--zone_yaml', dest='zone_yaml',
817 default="example/zones.yaml",
818 help='fan zone definitional yaml')
819 parser.add_argument('-f', '--fan_yaml', dest='fan_yaml',
820 default="example/fans.yaml",
821 help='fan definitional yaml')
Matthew Barthd4d0f082017-05-16 13:51:10 -0500822 parser.add_argument('-e', '--events_yaml', dest='events_yaml',
823 help='events to set speeds yaml')
Gunnar Millsee8a2812017-06-02 14:26:47 -0500824 parser.add_argument('-c', '--zone_conditions_yaml',
825 dest='zone_conditions_yaml',
826 help='conditions to determine zone yaml')
Matt Spinlerd08dbe22017-04-11 13:52:54 -0500827 parser.add_argument('-o', '--output_dir', dest='output_dir',
828 default=".",
829 help='output directory')
830 args = parser.parse_args()
831
832 if not args.zone_yaml or not args.fan_yaml:
833 parser.print_usage()
834 sys.exit(-1)
835
836 with open(args.zone_yaml, 'r') as zone_input:
837 zone_data = yaml.safe_load(zone_input) or {}
838
839 with open(args.fan_yaml, 'r') as fan_input:
840 fan_data = yaml.safe_load(fan_input) or {}
841
Matthew Barthd4d0f082017-05-16 13:51:10 -0500842 events_data = {}
843 if args.events_yaml:
844 with open(args.events_yaml, 'r') as events_input:
845 events_data = yaml.safe_load(events_input) or {}
846
Gunnar Millsee8a2812017-06-02 14:26:47 -0500847 zone_conditions_data = {}
848 if args.zone_conditions_yaml:
849 with open(args.zone_conditions_yaml, 'r') as zone_conditions_input:
850 zone_conditions_data = yaml.safe_load(zone_conditions_input) or {}
851
Matt Spinleree7f6422017-05-09 11:03:14 -0500852 zone_config = buildZoneData(zone_data.get('zone_configuration', {}),
Gunnar Millsee8a2812017-06-02 14:26:47 -0500853 fan_data, events_data, zone_conditions_data)
Matt Spinleree7f6422017-05-09 11:03:14 -0500854
855 manager_config = zone_data.get('manager_configuration', {})
856
857 if manager_config.get('power_on_delay') is None:
858 manager_config['power_on_delay'] = 0
Matt Spinlerd08dbe22017-04-11 13:52:54 -0500859
860 output_file = os.path.join(args.output_dir, "fan_zone_defs.cpp")
861 with open(output_file, 'w') as output:
Matt Spinleree7f6422017-05-09 11:03:14 -0500862 output.write(Template(tmpl).render(zones=zone_config,
863 mgr_data=manager_config))