blob: 80635756cdf16946a2edc48799a7318851523218 [file] [log] [blame]
#!/usr/bin/env python3
import argparse
import os
import re
import sys
import yaml
from inflection import underscore
def is_dbus_safe(name: str) -> bool:
"""
Check if a string is safe for use on D-Bus.
Args:
name (str): The input string.
Returns:
bool: True if the string is safe for D-Bus, False otherwise.
"""
if not name:
return False # Empty names are not allowed
# Check for invalid characters
if not re.match(r"^[a-zA-Z0-9_]+$", name):
return False
# Check for leading or trailing dots/underscores
if name[0] in "._" or name[-1] in "._":
return False
# Check for consecutive dots or underscores
if ".." in name or "__" in name:
return False
# Check length restriction
if len(name) > 255:
return False
return True
def convert_dbus_name_error(name: str) -> str:
if not is_dbus_safe(name):
print("WARNING: '" + name + "' is not dbus safe", file=sys.stderr)
raise ValueError("WARNING: '" + name + "' is not dbus safe")
return name
def convert_dbus_name_warn(name: str) -> str:
if not is_dbus_safe(name):
print("WARNING: '" + name + "' is not dbus safe", file=sys.stderr)
result = underscore(name)
if name != result:
print(
"WARNING: converted '" + name + "' to '" + result + "'",
file=sys.stderr,
)
return result
def config_error(ofile, led_name, group_name, message):
ofile.close()
os.remove(ofile.name)
raise ValueError(
"Invalid Configuration for LED ["
+ led_name
+ "] in Group ["
+ group_name
+ "]: "
+ message
)
def check_led_priority(led_name, group, value, priority_dict):
if led_name in priority_dict:
if value != priority_dict[led_name]:
# Priority for a particular LED needs to stay SAME
# across all groups
config_error(
ofile,
led_name,
group,
"Priority is NOT same across all groups",
)
else:
priority_dict[led_name] = value
return 0
def led_action_literal(action):
if action == "":
return "std::nullopt"
return "phosphor::led::Layout::Action::" + str(action)
def generate_file_single_led(
ifile, led_name, list_dict, priority_dict, ofile, has_group_priority, group
):
has_led_priority = "Priority" in list_dict
if has_group_priority and has_led_priority:
config_error(
ofile,
led_name,
group,
"cannot mix group priority with led priority",
)
if (not has_group_priority) and (not has_led_priority):
config_error(
ofile, led_name, group, "no group priority or led priority defined"
)
led_priority = list_dict.get("Priority", "")
if has_led_priority:
check_led_priority(led_name, group, led_priority, priority_dict)
action = led_action_literal(list_dict.get("Action", "Off"))
dutyOn = str(list_dict.get("DutyOn", 50))
period = str(list_dict.get("Period", 0))
priority = led_action_literal(led_priority)
ofile.write(' {"' + convert_dbus_name_warn(led_name) + '",')
ofile.write(action + ",")
ofile.write(dutyOn + ",")
ofile.write(period + ",")
ofile.write(priority + ",")
ofile.write("},\n")
return 0
def generate_file_single_group(ifile, group, priority_dict, ofile):
# This section generates an std::unordered_map of LedGroupNames to
# std::set of LEDs containing the name and properties
led_dict = ifile[group]
group_priority = 0
has_group_priority = led_dict and "Priority" in led_dict
if has_group_priority:
group_priority = led_dict["Priority"]
# we do not want to enumerate this as a led group
del led_dict["Priority"]
ofile.write(
' {"'
+ "/xyz/openbmc_project/led/groups/"
+ convert_dbus_name_error(group)
+ '"'
+ ",{ "
+ str(group_priority)
+ ",\n"
+ "{\n"
)
# Some LED groups could be empty
if not led_dict:
led_dict = {}
for led_name, list_dict in list(led_dict.items()):
generate_file_single_led(
ifile,
led_name,
list_dict,
priority_dict,
ofile,
has_group_priority,
group,
)
ofile.write(" }}},\n")
return 0
def generate_file(ifile, ofile):
# Dictionary having [Name:Priority]
priority_dict = {}
ofile.write("/* !!! WARNING: This is a GENERATED Code..")
ofile.write("Please do NOT Edit !!! */\n\n")
ofile.write("static const phosphor::led::GroupMap")
ofile.write(" systemLedMap = {\n\n")
for group in list(ifile.keys()):
generate_file_single_group(ifile, group, priority_dict, ofile)
ofile.write("};\n")
return 0
if __name__ == "__main__":
script_dir = os.path.dirname(os.path.realpath(__file__))
parser = argparse.ArgumentParser()
parser.add_argument(
"-f", "--filename", default="led.yaml", help="Input File Name"
)
parser.add_argument(
"-l",
"--output-filename",
dest="outputfilename",
default="led-gen.hpp",
help="Output File Name",
)
parser.add_argument(
"-i",
"--input-dir",
dest="inputdir",
default=script_dir,
help="Input directory",
)
parser.add_argument(
"-o",
"--output-dir",
dest="outputdir",
default=".",
help="Output directory.",
)
args = parser.parse_args()
# Default to the one that is in the current.
yaml_dir = script_dir
yaml_file = os.path.join(yaml_dir, "led.yaml")
if args.inputdir:
yaml_dir = args.inputdir
if args.filename:
yaml_file = os.path.join(yaml_dir, args.filename)
with open(yaml_file, "r") as f:
ifile = yaml.safe_load(f)
with open(os.path.join(args.outputdir, args.outputfilename), "w") as ofile:
generate_file(ifile, ofile)