blob: 97d62eae26782a6b33aee12188db5bb18ee0fb06 [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
Matt Spinleree7f6422017-05-09 11:03:14 -050014#Note: Condition is a TODO (openbmc/openbmc#1500)
Matt Spinlerd08dbe22017-04-11 13:52:54 -050015tmpl = '''/* This is a generated file. */
16#include "manager.hpp"
Matthew Barthba102b32017-05-16 16:13:56 -050017#include "functor.hpp"
18#include "actions.hpp"
Matt Spinlerd08dbe22017-04-11 13:52:54 -050019
20using namespace phosphor::fan::control;
21
Matt Spinleree7f6422017-05-09 11:03:14 -050022const unsigned int Manager::_powerOnDelay{${mgr_data['power_on_delay']}};
23
Matt Spinlerd08dbe22017-04-11 13:52:54 -050024const std::vector<ZoneGroup> Manager::_zoneLayouts
25{
26%for zone_group in zones:
Matt Spinler78498c92017-04-11 13:59:46 -050027 ZoneGroup{std::vector<Condition>{},
28 std::vector<ZoneDefinition>{
29 %for zone in zone_group['zones']:
30 ZoneDefinition{${zone['num']},
31 ${zone['full_speed']},
32 std::vector<FanDefinition>{
33 %for fan in zone['fans']:
34 FanDefinition{"${fan['name']}",
35 std::vector<std::string>{
36 %for sensor in fan['sensors']:
37 "${sensor}",
38 %endfor
39 }
40 },
41 %endfor
Matthew Barthd4d0f082017-05-16 13:51:10 -050042 },
43 std::vector<SetSpeedEvent>{
44 %for event in zone['events']:
45 SetSpeedEvent{
46 Group{
47 %for member in event['group']:
48 {
49 "${member['name']}",
50 {"${member['interface']}",
51 "${member['property']}"}
52 },
53 %endfor
Matthew Barthba102b32017-05-16 16:13:56 -050054 },
55 make_action(action::${event['action']['name']}(
56 %for index, param in enumerate(event['action']['parameters']):
57 %if (index+1) != len(event['action']['parameters']):
58 static_cast<${param['type']}>(${param['value']}),
59 %else:
60 static_cast<${param['type']}>(${param['value']})
61 %endif
62 %endfor
63 )),
Matthew Barthd4d0f082017-05-16 13:51:10 -050064 },
65 %endfor
Matt Spinler78498c92017-04-11 13:59:46 -050066 }
67 },
68 %endfor
69 }
70 },
Matt Spinlerd08dbe22017-04-11 13:52:54 -050071%endfor
72};
73'''
74
Matt Spinler78498c92017-04-11 13:59:46 -050075
Matthew Barthd4d0f082017-05-16 13:51:10 -050076def getEventsInZone(zone_num, events_data):
77 """
78 Constructs the event entries defined for each zone using the events yaml
79 provided.
80 """
81 events = []
Matthew Barthba102b32017-05-16 16:13:56 -050082
Matthew Barthd4d0f082017-05-16 13:51:10 -050083 if 'events' in events_data:
84 for e in events_data['events']:
85 for z in e['zone_conditions']:
86 if zone_num not in z['zones']:
87 continue
88
89 event = {}
90 # Add set speed event group
91 group = []
92 groups = next(g for g in events_data['groups']
93 if g['name'] == e['group'])
94 for member in groups['members']:
95 members = {}
96 members['name'] = ("/xyz/openbmc_project/" +
97 groups['type'] +
98 member)
99 members['interface'] = e['interface']
100 members['property'] = e['property']['name']
101 group.append(members)
102 event['group'] = group
Matthew Barthba102b32017-05-16 16:13:56 -0500103
104 # Add set speed action and function parameters
105 action = {}
106 actions = next(a for a in events_data['actions']
107 if a['name'] == e['action']['name'])
108 action['name'] = actions['name']
109 params = []
110 for p in actions['parameters']:
111 param = {}
112 if type(e['action'][p]) is not dict:
113 if p == 'property':
114 param['value'] = str(e['action'][p]).lower()
115 param['type'] = str(e['property']['type']).lower()
116 else:
117 # Default type to 'size_t' when not given
118 param['value'] = str(e['action'][p]).lower()
119 param['type'] = 'size_t'
120 params.append(param)
121 else:
122 param['value'] = str(e['action'][p]['value']).lower()
123 param['type'] = str(e['action'][p]['type']).lower()
124 params.append(param)
125 action['parameters'] = params
126 event['action'] = action
127
Matthew Barthd4d0f082017-05-16 13:51:10 -0500128 events.append(event)
129
130 return events
131
132
Matt Spinler78498c92017-04-11 13:59:46 -0500133def getFansInZone(zone_num, profiles, fan_data):
134 """
135 Parses the fan definition YAML files to find the fans
136 that match both the zone passed in and one of the
137 cooling profiles.
138 """
139
140 fans = []
141
142 for f in fan_data['fans']:
143
144 if zone_num != f['cooling_zone']:
145 continue
146
147 #'cooling_profile' is optional (use 'all' instead)
148 if f.get('cooling_profile') is None:
149 profile = "all"
150 else:
151 profile = f['cooling_profile']
152
153 if profile not in profiles:
154 continue
155
156 fan = {}
157 fan['name'] = f['inventory']
158 fan['sensors'] = f['sensors']
159 fans.append(fan)
160
161 return fans
162
163
Matthew Barthd4d0f082017-05-16 13:51:10 -0500164def buildZoneData(zone_data, fan_data, events_data):
Matt Spinler78498c92017-04-11 13:59:46 -0500165 """
166 Combines the zone definition YAML and fan
167 definition YAML to create a data structure defining
168 the fan cooling zones.
169 """
170
171 zone_groups = []
172
173 for group in zone_data:
174 conditions = []
175 for c in group['zone_conditions']:
176 conditions.append(c['name'])
177
178 zone_group = {}
179 zone_group['conditions'] = conditions
180
181 zones = []
182 for z in group['zones']:
183 zone = {}
184
185 #'zone' is required
186 if (not 'zone' in z) or (z['zone'] is None):
187 sys.exit("Missing fan zone number in " + zone_yaml)
188
189 zone['num'] = z['zone']
190
191 zone['full_speed'] = z['full_speed']
192
193 #'cooling_profiles' is optional (use 'all' instead)
194 if (not 'cooling_profiles' in z) or \
195 (z['cooling_profiles'] is None):
196 profiles = ["all"]
197 else:
198 profiles = z['cooling_profiles']
199
200 fans = getFansInZone(z['zone'], profiles, fan_data)
Matthew Barthd4d0f082017-05-16 13:51:10 -0500201 events = getEventsInZone(z['zone'], events_data)
Matt Spinler78498c92017-04-11 13:59:46 -0500202
203 if len(fans) == 0:
204 sys.exit("Didn't find any fans in zone " + str(zone['num']))
205
206 zone['fans'] = fans
Matthew Barthd4d0f082017-05-16 13:51:10 -0500207 zone['events'] = events
Matt Spinler78498c92017-04-11 13:59:46 -0500208 zones.append(zone)
209
210 zone_group['zones'] = zones
211 zone_groups.append(zone_group)
212
213 return zone_groups
214
215
Matt Spinlerd08dbe22017-04-11 13:52:54 -0500216if __name__ == '__main__':
217 parser = ArgumentParser(
218 description="Phosphor fan zone definition parser")
219
220 parser.add_argument('-z', '--zone_yaml', dest='zone_yaml',
221 default="example/zones.yaml",
222 help='fan zone definitional yaml')
223 parser.add_argument('-f', '--fan_yaml', dest='fan_yaml',
224 default="example/fans.yaml",
225 help='fan definitional yaml')
Matthew Barthd4d0f082017-05-16 13:51:10 -0500226 parser.add_argument('-e', '--events_yaml', dest='events_yaml',
227 help='events to set speeds yaml')
Matt Spinlerd08dbe22017-04-11 13:52:54 -0500228 parser.add_argument('-o', '--output_dir', dest='output_dir',
229 default=".",
230 help='output directory')
231 args = parser.parse_args()
232
233 if not args.zone_yaml or not args.fan_yaml:
234 parser.print_usage()
235 sys.exit(-1)
236
237 with open(args.zone_yaml, 'r') as zone_input:
238 zone_data = yaml.safe_load(zone_input) or {}
239
240 with open(args.fan_yaml, 'r') as fan_input:
241 fan_data = yaml.safe_load(fan_input) or {}
242
Matthew Barthd4d0f082017-05-16 13:51:10 -0500243 events_data = {}
244 if args.events_yaml:
245 with open(args.events_yaml, 'r') as events_input:
246 events_data = yaml.safe_load(events_input) or {}
247
Matt Spinleree7f6422017-05-09 11:03:14 -0500248 zone_config = buildZoneData(zone_data.get('zone_configuration', {}),
Matthew Barthd4d0f082017-05-16 13:51:10 -0500249 fan_data, events_data)
Matt Spinleree7f6422017-05-09 11:03:14 -0500250
251 manager_config = zone_data.get('manager_configuration', {})
252
253 if manager_config.get('power_on_delay') is None:
254 manager_config['power_on_delay'] = 0
Matt Spinlerd08dbe22017-04-11 13:52:54 -0500255
256 output_file = os.path.join(args.output_dir, "fan_zone_defs.cpp")
257 with open(output_file, 'w') as output:
Matt Spinleree7f6422017-05-09 11:03:14 -0500258 output.write(Template(tmpl).render(zones=zone_config,
259 mgr_data=manager_config))