1#!/usr/bin/env python3
2import argparse
3import os
4
5import yaml
6from inflection import underscore
7
8
9def config_error(ofile, led_name, group_name, message):
10    ofile.close()
11    os.remove(ofile.name)
12    raise ValueError(
13        "Invalid Configuration for LED ["
14        + led_name
15        + "] in Group ["
16        + group_name
17        + "]: "
18        + message
19    )
20
21
22def check_led_priority(led_name, group, value, priority_dict):
23
24    if led_name in priority_dict:
25        if value != priority_dict[led_name]:
26            # Priority for a particular LED needs to stay SAME
27            # across all groups
28            config_error(
29                ofile,
30                led_name,
31                group,
32                "Priority is NOT same across all groups",
33            )
34    else:
35        priority_dict[led_name] = value
36
37    return 0
38
39
40def led_action_literal(action):
41    if action == "":
42        return "std::nullopt"
43
44    return "phosphor::led::Layout::Action::" + str(action)
45
46
47def generate_file_single_led(
48    ifile, led_name, list_dict, priority_dict, ofile, has_group_priority, group
49):
50
51    has_led_priority = "Priority" in list_dict
52
53    if has_group_priority and has_led_priority:
54        config_error(
55            ofile,
56            led_name,
57            group,
58            "cannot mix group priority with led priority",
59        )
60
61    if (not has_group_priority) and (not has_led_priority):
62        config_error(
63            ofile, led_name, group, "no group priority or led priority defined"
64        )
65
66    led_priority = list_dict.get("Priority", "")
67
68    if has_led_priority:
69        check_led_priority(led_name, group, led_priority, priority_dict)
70
71    action = led_action_literal(list_dict.get("Action", "Off"))
72    dutyOn = str(list_dict.get("DutyOn", 50))
73    period = str(list_dict.get("Period", 0))
74    priority = led_action_literal(led_priority)
75
76    ofile.write('        {"' + underscore(led_name) + '",')
77    ofile.write(action + ",")
78    ofile.write(dutyOn + ",")
79    ofile.write(period + ",")
80    ofile.write(priority + ",")
81
82    ofile.write("},\n")
83
84    return 0
85
86
87def generate_file_single_group(ifile, group, priority_dict, ofile):
88    # This section generates an std::unordered_map of LedGroupNames to
89    # std::set of LEDs containing the name and properties
90    led_dict = ifile[group]
91
92    group_priority = 0
93    has_group_priority = led_dict and "Priority" in led_dict
94
95    if has_group_priority:
96        group_priority = led_dict["Priority"]
97        # we do not want to enumerate this as a led group
98        del led_dict["Priority"]
99
100    ofile.write(
101        '   {"'
102        + "/xyz/openbmc_project/led/groups/"
103        + underscore(group)
104        + '"'
105        + ",{ "
106        + str(group_priority)
107        + ",\n"
108        + "{\n"
109    )
110
111    # Some LED groups could be empty
112    if not led_dict:
113        led_dict = {}
114
115    for led_name, list_dict in list(led_dict.items()):
116        generate_file_single_led(
117            ifile,
118            led_name,
119            list_dict,
120            priority_dict,
121            ofile,
122            has_group_priority,
123            group,
124        )
125
126    ofile.write("   }}},\n")
127
128    return 0
129
130
131def generate_file(ifile, ofile):
132    # Dictionary having [Name:Priority]
133    priority_dict = {}
134
135    ofile.write("/* !!! WARNING: This is a GENERATED Code..")
136    ofile.write("Please do NOT Edit !!! */\n\n")
137
138    ofile.write("static const phosphor::led::GroupMap")
139    ofile.write(" systemLedMap = {\n\n")
140
141    for group in list(ifile.keys()):
142        generate_file_single_group(ifile, group, priority_dict, ofile)
143    ofile.write("};\n")
144
145    return 0
146
147
148if __name__ == "__main__":
149    script_dir = os.path.dirname(os.path.realpath(__file__))
150    parser = argparse.ArgumentParser()
151    parser.add_argument(
152        "-f", "--filename", default="led.yaml", help="Input File Name"
153    )
154    parser.add_argument(
155        "-l",
156        "--output-filename",
157        dest="outputfilename",
158        default="led-gen.hpp",
159        help="Output File Name",
160    )
161    parser.add_argument(
162        "-i",
163        "--input-dir",
164        dest="inputdir",
165        default=script_dir,
166        help="Input directory",
167    )
168    parser.add_argument(
169        "-o",
170        "--output-dir",
171        dest="outputdir",
172        default=".",
173        help="Output directory.",
174    )
175
176    args = parser.parse_args()
177
178    # Default to the one that is in the current.
179    yaml_dir = script_dir
180    yaml_file = os.path.join(yaml_dir, "led.yaml")
181
182    if args.inputdir:
183        yaml_dir = args.inputdir
184
185    if args.filename:
186        yaml_file = os.path.join(yaml_dir, args.filename)
187
188    with open(yaml_file, "r") as f:
189        ifile = yaml.safe_load(f)
190
191    with open(os.path.join(args.outputdir, args.outputfilename), "w") as ofile:
192        generate_file(ifile, ofile)
193