blob: 04f206fa3d7e658e78c99feb2cad962de7160bbb [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"
17
18using namespace phosphor::fan::control;
19
Matt Spinleree7f6422017-05-09 11:03:14 -050020const unsigned int Manager::_powerOnDelay{${mgr_data['power_on_delay']}};
21
Matt Spinlerd08dbe22017-04-11 13:52:54 -050022const std::vector<ZoneGroup> Manager::_zoneLayouts
23{
24%for zone_group in zones:
Matt Spinler78498c92017-04-11 13:59:46 -050025 ZoneGroup{std::vector<Condition>{},
26 std::vector<ZoneDefinition>{
27 %for zone in zone_group['zones']:
28 ZoneDefinition{${zone['num']},
29 ${zone['full_speed']},
30 std::vector<FanDefinition>{
31 %for fan in zone['fans']:
32 FanDefinition{"${fan['name']}",
33 std::vector<std::string>{
34 %for sensor in fan['sensors']:
35 "${sensor}",
36 %endfor
37 }
38 },
39 %endfor
40 }
41 },
42 %endfor
43 }
44 },
Matt Spinlerd08dbe22017-04-11 13:52:54 -050045%endfor
46};
47'''
48
Matt Spinler78498c92017-04-11 13:59:46 -050049
50def getFansInZone(zone_num, profiles, fan_data):
51 """
52 Parses the fan definition YAML files to find the fans
53 that match both the zone passed in and one of the
54 cooling profiles.
55 """
56
57 fans = []
58
59 for f in fan_data['fans']:
60
61 if zone_num != f['cooling_zone']:
62 continue
63
64 #'cooling_profile' is optional (use 'all' instead)
65 if f.get('cooling_profile') is None:
66 profile = "all"
67 else:
68 profile = f['cooling_profile']
69
70 if profile not in profiles:
71 continue
72
73 fan = {}
74 fan['name'] = f['inventory']
75 fan['sensors'] = f['sensors']
76 fans.append(fan)
77
78 return fans
79
80
81def buildZoneData(zone_data, fan_data):
82 """
83 Combines the zone definition YAML and fan
84 definition YAML to create a data structure defining
85 the fan cooling zones.
86 """
87
88 zone_groups = []
89
90 for group in zone_data:
91 conditions = []
92 for c in group['zone_conditions']:
93 conditions.append(c['name'])
94
95 zone_group = {}
96 zone_group['conditions'] = conditions
97
98 zones = []
99 for z in group['zones']:
100 zone = {}
101
102 #'zone' is required
103 if (not 'zone' in z) or (z['zone'] is None):
104 sys.exit("Missing fan zone number in " + zone_yaml)
105
106 zone['num'] = z['zone']
107
108 zone['full_speed'] = z['full_speed']
109
110 #'cooling_profiles' is optional (use 'all' instead)
111 if (not 'cooling_profiles' in z) or \
112 (z['cooling_profiles'] is None):
113 profiles = ["all"]
114 else:
115 profiles = z['cooling_profiles']
116
117 fans = getFansInZone(z['zone'], profiles, fan_data)
118
119 if len(fans) == 0:
120 sys.exit("Didn't find any fans in zone " + str(zone['num']))
121
122 zone['fans'] = fans
123 zones.append(zone)
124
125 zone_group['zones'] = zones
126 zone_groups.append(zone_group)
127
128 return zone_groups
129
130
Matt Spinlerd08dbe22017-04-11 13:52:54 -0500131if __name__ == '__main__':
132 parser = ArgumentParser(
133 description="Phosphor fan zone definition parser")
134
135 parser.add_argument('-z', '--zone_yaml', dest='zone_yaml',
136 default="example/zones.yaml",
137 help='fan zone definitional yaml')
138 parser.add_argument('-f', '--fan_yaml', dest='fan_yaml',
139 default="example/fans.yaml",
140 help='fan definitional yaml')
141 parser.add_argument('-o', '--output_dir', dest='output_dir',
142 default=".",
143 help='output directory')
144 args = parser.parse_args()
145
146 if not args.zone_yaml or not args.fan_yaml:
147 parser.print_usage()
148 sys.exit(-1)
149
150 with open(args.zone_yaml, 'r') as zone_input:
151 zone_data = yaml.safe_load(zone_input) or {}
152
153 with open(args.fan_yaml, 'r') as fan_input:
154 fan_data = yaml.safe_load(fan_input) or {}
155
Matt Spinleree7f6422017-05-09 11:03:14 -0500156 zone_config = buildZoneData(zone_data.get('zone_configuration', {}),
157 fan_data)
158
159 manager_config = zone_data.get('manager_configuration', {})
160
161 if manager_config.get('power_on_delay') is None:
162 manager_config['power_on_delay'] = 0
Matt Spinlerd08dbe22017-04-11 13:52:54 -0500163
164 output_file = os.path.join(args.output_dir, "fan_zone_defs.cpp")
165 with open(output_file, 'w') as output:
Matt Spinleree7f6422017-05-09 11:03:14 -0500166 output.write(Template(tmpl).render(zones=zone_config,
167 mgr_data=manager_config))