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