1f24d7749SMatthew Barth#!/usr/bin/env python3
285be2e70SMatt Spinler
385be2e70SMatt Spinlerimport os
485be2e70SMatt Spinlerimport sys
585be2e70SMatt Spinlerfrom argparse import ArgumentParser
60f2588f2SPatrick Williams
70f2588f2SPatrick Williamsimport yaml
885be2e70SMatt Spinlerfrom mako.template import Template
985be2e70SMatt Spinler
1085be2e70SMatt Spinler"""
1185be2e70SMatt SpinlerThis script generates the data structures for the
1285be2e70SMatt Spinlerphosphor-fan-monitor application.
1385be2e70SMatt Spinler
1485be2e70SMatt SpinlerA future improvement is to get the fan inventory names
1585be2e70SMatt Spinlerfrom a separate file, so just that file could be generated
1685be2e70SMatt Spinlerfrom the MRW.
1785be2e70SMatt Spinler"""
1885be2e70SMatt Spinler
1985be2e70SMatt Spinler
200f2588f2SPatrick Williamstmpl = """\
2133618bc1SMatthew Barth<%!
2233618bc1SMatthew Barthdef indent(str, depth):
2333618bc1SMatthew Barth    return ''.join(4*' '*depth+line for line in str.splitlines(True))
2433618bc1SMatthew Barth%>\
2533618bc1SMatthew Barth<%def name="getCondParams(cond)" buffered="True">
2633618bc1SMatthew Barth%if (cond['name'] == 'propertiesMatch'):
2733618bc1SMatthew Barthstd::vector<PropertyState>{
2833618bc1SMatthew Barth    %for i in cond['properties']:
2933618bc1SMatthew Barth    PropertyState{
3033618bc1SMatthew Barth        {
3133618bc1SMatthew Barth            "${i['object']}",
3233618bc1SMatthew Barth            "${i['interface']}",
3333618bc1SMatthew Barth            "${i['property']['name']}"
3433618bc1SMatthew Barth        },
3533618bc1SMatthew Barth        static_cast<${i['property']['type']}>(${str(i['property']['value']).lower()})
3633618bc1SMatthew Barth    },
3733618bc1SMatthew Barth    %endfor
3833618bc1SMatthew Barth}
3933618bc1SMatthew Barth%endif
4033618bc1SMatthew Barth</%def>\
4133618bc1SMatthew Barth/* This is a generated file. */
4285be2e70SMatt Spinler#include "fan_defs.hpp"
4385be2e70SMatt Spinler#include "types.hpp"
4435108a77SMatt Spinler#include "groups.hpp"
4533618bc1SMatthew Barth#include "conditions.hpp"
4685be2e70SMatt Spinler
4785be2e70SMatt Spinlerusing namespace phosphor::fan::monitor;
4835108a77SMatt Spinlerusing namespace phosphor::fan::trust;
4985be2e70SMatt Spinler
5085be2e70SMatt Spinlerconst std::vector<FanDefinition> fanDefinitions
5185be2e70SMatt Spinler{
5235108a77SMatt Spinler%for fan_data in data.get('fans', {}):
5385be2e70SMatt Spinler    FanDefinition{"${fan_data['inventory']}",
5469f2f48eSJolie Ku                  ${fan_data.get('method', {})},
559396bcc3SMatthew Barth                  ${fan_data.get('functional_delay', 0)},
5669f2f48eSJolie Ku                  ${fan_data.get('allowed_out_of_range_time', {})},
5785be2e70SMatt Spinler                  ${fan_data['deviation']},
58*f724c16bSMatt Spinler                  ${fan_data.get('upper_deviation', fan_data['deviation'])},
5985be2e70SMatt Spinler                  ${fan_data['num_sensors_nonfunc_for_fan_nonfunc']},
60b0412d07SMatt Spinler                  0, // Monitor start delay - not used in YAML configs
61623635c6SMatt Spinler                  0, // Count interval - not used in YAML configs
62f13b42e2SMatt Spinler                  std::nullopt, // nonfuncRotorErrorDelay - also not used here
6327f6b686SMatt Spinler                  std::nullopt, // fanMissingErrorDelay - also not used here
6485be2e70SMatt Spinler                  std::vector<SensorDefinition>{
6585be2e70SMatt Spinler                  %for sensor in fan_data['sensors']:
6685be2e70SMatt Spinler                  <%
6785be2e70SMatt Spinler                      #has_target is a bool, and we need a true instead of True
6885be2e70SMatt Spinler                      has_target = str(sensor['has_target']).lower()
6980f271b2SLei YU                      target_interface = sensor.get(
7080f271b2SLei YU                          'target_interface',
7180f271b2SLei YU                          'xyz.openbmc_project.Control.FanSpeed')
7227cc39f1SChau Ly                      target_path = sensor.get(
7327cc39f1SChau Ly                          'target_path',
7427cc39f1SChau Ly                          '')
758e5d197bSLei YU                      factor = sensor.get('factor', 1)
768e5d197bSLei YU                      offset = sensor.get('offset', 0)
7769f2f48eSJolie Ku                      threshold = sensor.get('threshold', 1)
788a8aa442SMatthew Barth                      ignore_above_max = str(sensor.get(
798a8aa442SMatthew Barth                          'ignore_above_max', False)).lower()
8085be2e70SMatt Spinler                  %> \
818e5d197bSLei YU                      SensorDefinition{"${sensor['name']}",
828e5d197bSLei YU                                       ${has_target},
8380f271b2SLei YU                                       "${target_interface}",
8427cc39f1SChau Ly                                       "${target_path}",
858e5d197bSLei YU                                       ${factor},
8669f2f48eSJolie Ku                                       ${offset},
878a8aa442SMatthew Barth                                       ${threshold},
888a8aa442SMatthew Barth                                       ${ignore_above_max}},
8985be2e70SMatt Spinler                  %endfor
9085be2e70SMatt Spinler                  },
9133618bc1SMatthew Barth                  %if ('condition' in fan_data) and \
9233618bc1SMatthew Barth                  (fan_data['condition'] is not None):
9333618bc1SMatthew Barth                  make_condition(condition::${fan_data['condition']['name']}(\
9433618bc1SMatthew Barth                      ${indent(getCondParams(cond=fan_data['condition']), 5)}\
95086e8168SMatt Spinler                  )),
9633618bc1SMatthew Barth                  %else:
97a3584bd2SMatt Spinler                  {},
9833618bc1SMatthew Barth                  %endif
99086e8168SMatt Spinler                  false // set_func_on_present. Hardcoded to false.
10085be2e70SMatt Spinler    },
10185be2e70SMatt Spinler%endfor
10285be2e70SMatt Spinler};
10335108a77SMatt Spinler
10435108a77SMatt Spinler##Function to generate the group creation lambda.
10535108a77SMatt Spinler##If a group were to ever need a different constructor,
10635108a77SMatt Spinler##it could be handled here.
10735108a77SMatt Spinler<%def name="get_lambda_contents(group)">
1086f31d19bSMatthew Barth            std::vector<GroupDefinition> group{
1096f31d19bSMatthew Barth            %for member in group['group']:
1106f31d19bSMatthew Barth            <%
1116f31d19bSMatthew Barth                in_trust = str(member.get('in_trust', "true")).lower()
1126f31d19bSMatthew Barth            %>
1136f31d19bSMatthew Barth                GroupDefinition{"${member['name']}", ${in_trust}},
11435108a77SMatt Spinler            %endfor
11535108a77SMatt Spinler            };
1166f31d19bSMatthew Barth            return std::make_unique<${group['class']}>(group);
11735108a77SMatt Spinler</%def>
11835108a77SMatt Spinlerconst std::vector<CreateGroupFunction> trustGroups
11935108a77SMatt Spinler{
12035108a77SMatt Spinler%for group in data.get('sensor_trust_groups', {}):
12135108a77SMatt Spinler    {
12235108a77SMatt Spinler        []()
12335108a77SMatt Spinler        {\
12435108a77SMatt Spinler${get_lambda_contents(group)}\
12535108a77SMatt Spinler        }
12635108a77SMatt Spinler    },
12735108a77SMatt Spinler%endfor
12835108a77SMatt Spinler};
1290f2588f2SPatrick Williams"""
13085be2e70SMatt Spinler
13185be2e70SMatt Spinler
1320f2588f2SPatrick Williamsif __name__ == "__main__":
13385be2e70SMatt Spinler    parser = ArgumentParser(
1340f2588f2SPatrick Williams        description="Phosphor fan monitor definition parser"
1350f2588f2SPatrick Williams    )
13685be2e70SMatt Spinler
1370f2588f2SPatrick Williams    parser.add_argument(
1380f2588f2SPatrick Williams        "-m",
1390f2588f2SPatrick Williams        "--monitor_yaml",
1400f2588f2SPatrick Williams        dest="monitor_yaml",
14185be2e70SMatt Spinler        default="example/monitor.yaml",
1420f2588f2SPatrick Williams        help="fan monitor definitional yaml",
1430f2588f2SPatrick Williams    )
1440f2588f2SPatrick Williams    parser.add_argument(
1450f2588f2SPatrick Williams        "-o",
1460f2588f2SPatrick Williams        "--output_dir",
1470f2588f2SPatrick Williams        dest="output_dir",
14885be2e70SMatt Spinler        default=".",
1490f2588f2SPatrick Williams        help="output directory",
1500f2588f2SPatrick Williams    )
15185be2e70SMatt Spinler    args = parser.parse_args()
15285be2e70SMatt Spinler
15385be2e70SMatt Spinler    if not args.monitor_yaml:
15485be2e70SMatt Spinler        parser.print_usage()
1553e781064SWilliam A. Kennington III        sys.exit(1)
15685be2e70SMatt Spinler
1570f2588f2SPatrick Williams    with open(args.monitor_yaml, "r") as monitor_input:
15885be2e70SMatt Spinler        monitor_data = yaml.safe_load(monitor_input) or {}
15985be2e70SMatt Spinler
16085be2e70SMatt Spinler    # Do some minor input validation
1610f2588f2SPatrick Williams    for fan in monitor_data.get("fans", {}):
1620f2588f2SPatrick Williams        if (fan["deviation"] < 0) or (fan["deviation"] > 100):
1630f2588f2SPatrick Williams            sys.exit("Invalid deviation value " + str(fan["deviation"]))
16485be2e70SMatt Spinler
16585be2e70SMatt Spinler    output_file = os.path.join(args.output_dir, "fan_monitor_defs.cpp")
1660f2588f2SPatrick Williams    with open(output_file, "w") as output:
16785be2e70SMatt Spinler        output.write(Template(tmpl).render(data=monitor_data))
168