185be2e70SMatt Spinler#!/usr/bin/env python
285be2e70SMatt Spinler
385be2e70SMatt Spinlerimport os
485be2e70SMatt Spinlerimport sys
585be2e70SMatt Spinlerimport yaml
685be2e70SMatt Spinlerfrom argparse import ArgumentParser
785be2e70SMatt Spinlerfrom mako.template import Template
885be2e70SMatt Spinler
985be2e70SMatt Spinler"""
1085be2e70SMatt SpinlerThis script generates the data structures for the
1185be2e70SMatt Spinlerphosphor-fan-monitor application.
1285be2e70SMatt Spinler
1385be2e70SMatt SpinlerA future improvement is to get the fan inventory names
1485be2e70SMatt Spinlerfrom a separate file, so just that file could be generated
1585be2e70SMatt Spinlerfrom the MRW.
1685be2e70SMatt Spinler"""
1785be2e70SMatt Spinler
1885be2e70SMatt Spinler
1985be2e70SMatt Spinlertmpl = '''/* This is a generated file. */
2085be2e70SMatt Spinler#include "fan_defs.hpp"
2185be2e70SMatt Spinler#include "types.hpp"
2235108a77SMatt Spinler#include "groups.hpp"
2385be2e70SMatt Spinler
2485be2e70SMatt Spinlerusing namespace phosphor::fan::monitor;
2535108a77SMatt Spinlerusing namespace phosphor::fan::trust;
2685be2e70SMatt Spinler
2785be2e70SMatt Spinlerconst std::vector<FanDefinition> fanDefinitions
2885be2e70SMatt Spinler{
2935108a77SMatt Spinler%for fan_data in data.get('fans', {}):
3085be2e70SMatt Spinler    FanDefinition{"${fan_data['inventory']}",
3185be2e70SMatt Spinler                  ${fan_data['allowed_out_of_range_time']},
3285be2e70SMatt Spinler                  ${fan_data['deviation']},
3385be2e70SMatt Spinler                  ${fan_data['num_sensors_nonfunc_for_fan_nonfunc']},
3485be2e70SMatt Spinler                  std::vector<SensorDefinition>{
3585be2e70SMatt Spinler                  %for sensor in fan_data['sensors']:
3685be2e70SMatt Spinler                  <%
3785be2e70SMatt Spinler                      #has_target is a bool, and we need a true instead of True
3885be2e70SMatt Spinler                      has_target = str(sensor['has_target']).lower()
39*80f271b2SLei YU                      target_interface = sensor.get(
40*80f271b2SLei YU                          'target_interface',
41*80f271b2SLei YU                          'xyz.openbmc_project.Control.FanSpeed')
428e5d197bSLei YU                      factor = sensor.get('factor', 1)
438e5d197bSLei YU                      offset = sensor.get('offset', 0)
4485be2e70SMatt Spinler                  %> \
458e5d197bSLei YU                      SensorDefinition{"${sensor['name']}",
468e5d197bSLei YU                                       ${has_target},
47*80f271b2SLei YU                                       "${target_interface}",
488e5d197bSLei YU                                       ${factor},
498e5d197bSLei YU                                       ${offset}},
5085be2e70SMatt Spinler                  %endfor
5185be2e70SMatt Spinler                  },
5285be2e70SMatt Spinler    },
5385be2e70SMatt Spinler%endfor
5485be2e70SMatt Spinler};
5535108a77SMatt Spinler
5635108a77SMatt Spinler##Function to generate the group creation lambda.
5735108a77SMatt Spinler##If a group were to ever need a different constructor,
5835108a77SMatt Spinler##it could be handled here.
5935108a77SMatt Spinler<%def name="get_lambda_contents(group)">
6035108a77SMatt Spinler            std::vector<std::string> names{
6135108a77SMatt Spinler            %for sensor in group['sensors']:
6235108a77SMatt Spinler                "${sensor['name']}",
6335108a77SMatt Spinler            %endfor
6435108a77SMatt Spinler            };
6535108a77SMatt Spinler            return std::make_unique<${group['class']}>(names);
6635108a77SMatt Spinler</%def>
6735108a77SMatt Spinlerconst std::vector<CreateGroupFunction> trustGroups
6835108a77SMatt Spinler{
6935108a77SMatt Spinler%for group in data.get('sensor_trust_groups', {}):
7035108a77SMatt Spinler    {
7135108a77SMatt Spinler        []()
7235108a77SMatt Spinler        {\
7335108a77SMatt Spinler${get_lambda_contents(group)}\
7435108a77SMatt Spinler        }
7535108a77SMatt Spinler    },
7635108a77SMatt Spinler%endfor
7735108a77SMatt Spinler};
7885be2e70SMatt Spinler'''
7985be2e70SMatt Spinler
8085be2e70SMatt Spinler
8185be2e70SMatt Spinlerif __name__ == '__main__':
8285be2e70SMatt Spinler    parser = ArgumentParser(
8385be2e70SMatt Spinler        description="Phosphor fan monitor definition parser")
8485be2e70SMatt Spinler
8585be2e70SMatt Spinler    parser.add_argument('-m', '--monitor_yaml', dest='monitor_yaml',
8685be2e70SMatt Spinler                        default="example/monitor.yaml",
8785be2e70SMatt Spinler                        help='fan monitor definitional yaml')
8885be2e70SMatt Spinler    parser.add_argument('-o', '--output_dir', dest='output_dir',
8985be2e70SMatt Spinler                        default=".",
9085be2e70SMatt Spinler                        help='output directory')
9185be2e70SMatt Spinler    args = parser.parse_args()
9285be2e70SMatt Spinler
9385be2e70SMatt Spinler    if not args.monitor_yaml:
9485be2e70SMatt Spinler        parser.print_usage()
9585be2e70SMatt Spinler        sys.exit(-1)
9685be2e70SMatt Spinler
9785be2e70SMatt Spinler    with open(args.monitor_yaml, 'r') as monitor_input:
9885be2e70SMatt Spinler        monitor_data = yaml.safe_load(monitor_input) or {}
9985be2e70SMatt Spinler
10085be2e70SMatt Spinler    #Do some minor input validation
10135108a77SMatt Spinler    for fan in monitor_data.get('fans', {}):
10285be2e70SMatt Spinler        if ((fan['deviation'] < 0) or (fan['deviation'] > 100)):
10385be2e70SMatt Spinler            sys.exit("Invalid deviation value " + str(fan['deviation']))
10485be2e70SMatt Spinler
10585be2e70SMatt Spinler    output_file = os.path.join(args.output_dir, "fan_monitor_defs.cpp")
10685be2e70SMatt Spinler    with open(output_file, 'w') as output:
10785be2e70SMatt Spinler        output.write(Template(tmpl).render(data=monitor_data))
108