blob: dac5de7354ecd517ae75c5878d1d29044f48e677 [file] [log] [blame] [edit]
#!/usr/bin/env python3
import os
import sys
from argparse import ArgumentParser
import yaml
from mako.template import Template
"""
This script generates the data structures for the
phosphor-fan-monitor application.
A future improvement is to get the fan inventory names
from a separate file, so just that file could be generated
from the MRW.
"""
tmpl = """\
<%!
def indent(str, depth):
return ''.join(4*' '*depth+line for line in str.splitlines(True))
%>\
<%def name="getCondParams(cond)" buffered="True">
%if (cond['name'] == 'propertiesMatch'):
std::vector<PropertyState>{
%for i in cond['properties']:
PropertyState{
{
"${i['object']}",
"${i['interface']}",
"${i['property']['name']}"
},
static_cast<${i['property']['type']}>(${str(i['property']['value']).lower()})
},
%endfor
}
%endif
</%def>\
/* This is a generated file. */
#include "fan_defs.hpp"
#include "types.hpp"
#include "groups.hpp"
#include "conditions.hpp"
using namespace phosphor::fan::monitor;
using namespace phosphor::fan::trust;
const std::vector<FanDefinition> fanDefinitions
{
%for fan_data in data.get('fans', {}):
FanDefinition{"${fan_data['inventory']}",
${fan_data.get('method', {})},
${fan_data.get('functional_delay', 0)},
${fan_data.get('allowed_out_of_range_time', {})},
${fan_data['deviation']},
${fan_data.get('upper_deviation', fan_data['deviation'])},
${fan_data['num_sensors_nonfunc_for_fan_nonfunc']},
0, // Monitor start delay - not used in YAML configs
0, // Count interval - not used in YAML configs
std::nullopt, // nonfuncRotorErrorDelay - also not used here
std::nullopt, // fanMissingErrorDelay - also not used here
std::vector<SensorDefinition>{
%for sensor in fan_data['sensors']:
<%
#has_target is a bool, and we need a true instead of True
has_target = str(sensor['has_target']).lower()
target_interface = sensor.get(
'target_interface',
'xyz.openbmc_project.Control.FanSpeed')
target_path = sensor.get(
'target_path',
'')
factor = sensor.get('factor', 1)
offset = sensor.get('offset', 0)
threshold = sensor.get('threshold', 1)
ignore_above_max = str(sensor.get(
'ignore_above_max', False)).lower()
%> \
SensorDefinition{"${sensor['name']}",
${has_target},
"${target_interface}",
"${target_path}",
${factor},
${offset},
${threshold},
${ignore_above_max}},
%endfor
},
%if ('condition' in fan_data) and \
(fan_data['condition'] is not None):
make_condition(condition::${fan_data['condition']['name']}(\
${indent(getCondParams(cond=fan_data['condition']), 5)}\
)),
%else:
{},
%endif
false // set_func_on_present. Hardcoded to false.
},
%endfor
};
##Function to generate the group creation lambda.
##If a group were to ever need a different constructor,
##it could be handled here.
<%def name="get_lambda_contents(group)">
std::vector<GroupDefinition> group{
%for member in group['group']:
<%
in_trust = str(member.get('in_trust', "true")).lower()
%>
GroupDefinition{"${member['name']}", ${in_trust}},
%endfor
};
return std::make_unique<${group['class']}>(group);
</%def>
const std::vector<CreateGroupFunction> trustGroups
{
%for group in data.get('sensor_trust_groups', {}):
{
[]()
{\
${get_lambda_contents(group)}\
}
},
%endfor
};
"""
if __name__ == "__main__":
parser = ArgumentParser(
description="Phosphor fan monitor definition parser"
)
parser.add_argument(
"-m",
"--monitor_yaml",
dest="monitor_yaml",
default="example/monitor.yaml",
help="fan monitor definitional yaml",
)
parser.add_argument(
"-o",
"--output_dir",
dest="output_dir",
default=".",
help="output directory",
)
args = parser.parse_args()
if not args.monitor_yaml:
parser.print_usage()
sys.exit(1)
with open(args.monitor_yaml, "r") as monitor_input:
monitor_data = yaml.safe_load(monitor_input) or {}
# Do some minor input validation
for fan in monitor_data.get("fans", {}):
if (fan["deviation"] < 0) or (fan["deviation"] > 100):
sys.exit("Invalid deviation value " + str(fan["deviation"]))
output_file = os.path.join(args.output_dir, "fan_monitor_defs.cpp")
with open(output_file, "w") as output:
output.write(Template(tmpl).render(data=monitor_data))