From 44b058eaa23a58fd294ce91c4c4144f7fa5a1c2e Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Mon, 8 May 2023 23:37:33 +0300 Subject: [PATCH 01/16] topology2: doc: topology2-filter.py: Add topology2 Doxygen filter This is the second version of topology2 to C Doxygen filter. Its far from perfect, but it should get us started. The purpose of the translated C code is not to document actual topology2 code, but only to provide anchors for Doxygen to form a network of links through which to navigate the topology sources and find the pieces of related Doxygen documentation. The filter also creates separate pages of the original code and adds links next to the pages in the C struct definition, instance documentation and their possible Doxygen documentation. Signed-off-by: Jyri Sarha --- .../topology2/doc/topology2-filter.py | 745 ++++++++++++++++++ 1 file changed, 745 insertions(+) create mode 100755 tools/topology/topology2/doc/topology2-filter.py diff --git a/tools/topology/topology2/doc/topology2-filter.py b/tools/topology/topology2/doc/topology2-filter.py new file mode 100755 index 000000000000..7ff465c66be7 --- /dev/null +++ b/tools/topology/topology2/doc/topology2-filter.py @@ -0,0 +1,745 @@ +#!/usr/bin/python3 +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2023 Intel Corporation. All rights reserved. +# +# The usage of this command is simple. It takes one argument, a path +# to a SOF topology2 source file, and it produces to stdout something +# that can be parsed by Doxygen as C source. Produced output contains +# C struct definitions and instantiations analogous to the topology2 +# classes and object instances. +# +# The purpose of the translated C code is not to document actual +# topology2 code, but only to provide anchors for Doxygen to form a +# network of links through which to navigate the topology sources and +# find the pieces of related Doxygen documentation. The filter also +# creates separate pages of the original code and adds links next to the +# pages in the C struct definition, instance documentation and their +# possible Doxygen documentation. + +import sys +import os +import re +import io +import logging + +logging.basicConfig(filename='filter_debug.txt', filemode='a', encoding='utf-8', + level=logging.DEBUG) + +def fname(): + try: + name = sys._getframe(1).f_code.co_name + except (IndexError, TypeError, AttributeError): + name = "" + return name + +def cbracket_count(line): + val = line.count("{") - line.count("}") + return val + +def sbracket_count(line): + val = line.count("[") - line.count("]") + return val + +def doxy_check_add(doxy, line): + if line.find("##") >= 0: + doxy = doxy + line[line.find("##"):].replace("##", "//!", 1) + if line.find("#") >= 0: + line = line[0:line.find("#")] + return (doxy, line) + +def print_doxy(doxy, file = sys.stdout): + if len(doxy): + print(doxy, file=file) + return "" + return doxy + +def parse_include_str(line): + if re.search(r"^\s*\<[A-Za-z0-9\/_\-\.]+\>\s*", line): + tok = line.split() + return "#include " + tok[0] + "\n" + return None + +def parse_include(line): + str = parse_include_str(line) + if str: + print(str) + return True + return False + +def parse_define_block(fline, instream): + """Parses topology2 Define { } block and outputs C-preprocessor #define macros + + Parameters: + fline (string): First input line that was read by the caller + instream (stream): Input stream of topology2 file we are decoding + + Returns: + string: The original code that was translated + """ + if re.search(r"^\s*Define\s+\{", fline): + logging.debug("fline: %s", fline) + doxy = "" + for line in instream: + if cbracket_count(line) < 0: + break + (doxy, line) = doxy_check_add(doxy, line) + doxy = print_doxy(doxy) + tok = line.split(maxsplit = 2) + if len(tok) < 2: + continue + val = trim_value(line[line.find(tok[0]) + len(tok[0]):]) + print("#define %s\t%s" % (trim_c_id(tok[0]), val)) + return True + return False + +def parse_include_by_key(fline, instream, file): # For now just skip + """Handles IncludeByKey { } blocks, currently handles only actual + includes, not nested {} blocks but everything is included into + raw_code return value. + + Parameters: + fline (string): First input line that was read by the caller + instream (stream): Input stream of topology2 file we are decoding + file (stream): Output stream for the translated output + + Returns: + string: The original code that was translated + + """ + if re.search(r"^\s*IncludeByKey\.", fline): + logging.debug("fline: %s", fline) + bsum = cbracket_count(fline) + if bsum == 1: + # Assume IncludeByKey. { + tok = fline.split() + tok = tok[0].split(".") + name = tok[1] + raw_code = "" + ifstr = "if" + for line in instream: + raw_code = raw_code + line + bsum = bsum + cbracket_count(line) + tok = line.split("\"") + if len(tok) >= 4: + print("#%s %s == \"%s\"\n#include <%s>" % + (ifstr, name, tok[1], tok[3]), file = file) + if ifstr == "if": + ifstr = "elif" + if bsum < 1: + if ifstr != "if": + print("#endif", file = file) + return raw_code + return None + +def trim_value(val): + val = val.strip(" \t\n$") + end = len(val) - 1 + if val[0:1] == "\"" and val[end:] == "\"": + return val + if val.isidentifier() or val.isnumeric(): + return val + if val[0:1] == "\'" and val[end:] == "\'": + val = val.strip("\'") + return "\"" + val + "\"" + +def trim_c_id(name): + name = name.strip(" \t\n\"\'") + name = name.replace("-", "_") + name = name.replace(" ", "_") + return name + + +def parse_attribute_constraints(instream, name): + """Parses a Constraints { } block and produces a C enum definition if possible + + Parameters: + instream (stream): Input stream of topology2 file we are decoding + name (string): Attribute name of this constraints block belongs to + + Returns: + string: C enum definition or an empty string + + """ + logging.debug("name: %s", name) + valid_values = [] + tuple_values = [] + doxy = "" # This is thrown away since there is no C anchror to connect it- + raw_code = "" + enum = "" + for line in instream: + raw_code = raw_code + line + (doxy, line) = doxy_check_add(doxy, line) + if cbracket_count(line) < 0: + break + if re.search(r"^\s*\!valid_values\s+\[", line): + for line in instream: + raw_code = raw_code + line + (doxy, line) = doxy_check_add(doxy, line) + if sbracket_count(line) < 0: + break + valid_values.append(trim_c_id(line)) + if re.search(r"^\s*\!tuple_values\s+\[", line): + for line in instream: + raw_code = raw_code + line + (doxy, line) = doxy_check_add(doxy, line) + if sbracket_count(line) < 0: + break + tuple_values.append(trim_value(line)) + if len(valid_values) > 1 and len(valid_values) == len(tuple_values): + enum = "enum " + name + " {\n" + for i in range(len(valid_values)): + enum = enum + "\t\t" + valid_values[i] + " =\t" + tuple_values[i] + ",\n" + enum = enum + "\t}" + elif len(valid_values) > 1 and len(tuple_values) == 0: + enum = "enum " + name + " {\n" + for i in range(len(valid_values)): + enum = enum + "\t\t" + valid_values[i] + "," + if valid_values[i][0:1] == "$": # If its a variable add a reference to it + enum = enum + " //!< \\ref " + valid_values[i][1:] + enum = enum + "\n" + enum = enum + "\t}" + return (raw_code, enum) + +def parse_class_attribute(attributes, doxy, instream, fline): + """Parses a DefineAttribute { } block and collects the information into + attributes dict. Any already accumulated Doxygen documentation is + also stored there under the attribute name- + + Parameters: + attributes (dict): A dictionary where data about the attribute is stored + doxy (strung): Doxygen documentation collected just before the attribute + instream (stream): Input stream of topology2 file we are decoding + fline (string): First input line that was read by the caller + + Returns: + string: The original code that was translated + """ + logging.debug("fline: %s", fline) + tok = fline.split("\"") + if len(tok) > 1: + name = tok[1] + else: + tok = fline.split(".") + tok = tok[1].split(" ") + name = tok[0] + (doxy, fline) = doxy_check_add(doxy, fline) + bsum = cbracket_count(fline) + typestr = "" + token_ref = "" + ref_type = "" + enum = "" + raw_code = "" + if bsum < 1: + # Assume: DefineAttribute.name {} + typestr = "int" + else: + for line in instream: + raw_code = raw_code + line + (doxy, line) = doxy_check_add(doxy, line) + bsum = bsum + cbracket_count(line) + if bsum < 1: + break + if re.search(r"^\s*constraints\s+\{", line) and bsum == 2: + (code, enum) = parse_attribute_constraints(instream, name) + raw_code = raw_code + code + bsum = 1 + elif re.search(r"^\s*type\s", line): + tok = line.split() + typestr = tok[1].strip(" \t\n\"\'") + elif re.search(r"^\s*token_ref\s", line): + tok = line.split() + token_ref = tok[1].strip(" \t\n\"\'") + tok = token_ref.split(".") + ref_type = tok[1] + logging.debug("type %s token_ref %s ref_type %s enum %s", + typestr, token_ref, ref_type, enum) + if enum != "" and ref_type != "bool": + typestr = enum + if ref_type == "string": + doxy = doxy + "//! \\em string type\n" + elif typestr == "" or ref_type == "bool": + typestr = ref_type + attributes[name] = { "type": typestr, "doxy": doxy, "token_ref": token_ref } + return raw_code + +def print_attributes(attributes): + """Print out struct members and their doxygen documentation from attributes dict. + + Parameters: + attributes (dict): A dictionary where data about the attributes was stored + """ + for name in attributes: + doxy = "" + if attributes[name].get("doxy"): + doxy = attributes[name]["doxy"] + "\n" + if attributes[name].get("type"): + typestr = attributes[name]["type"] + print("%s\t%s %s;\n" % (doxy, typestr, name)) + +def set_attribute_flag(attributes, attribute, flag): + if not attributes.get(attribute): + attributes[attribute] = {} + attributes[attribute][flag] = True + +def parse_attributes_block(instream, attributes, attrib_doxy): + """Parse attributes block inside class definition and store the flags in attributes dict + + Parameters: + instream (stream): Input stream of topology2 file we are decoding + attributes (dict): Dict where data about the attributes is stored + attrib_doxy (dict): Dict to store doxygen docs associated with the attributes block + + Returns: + string: The original code that was translated + """ + logging.debug("called") + raw_code = "" + doxy = "" + for line in instream: + raw_code = raw_code + line + (doxy, line) = doxy_check_add(doxy, line) + if cbracket_count(line) < 0: + break + if re.search(r"^\s*\!constructor\s+\[", line): + for line in instream: + raw_code = raw_code + line + (doxy, line) = doxy_check_add(doxy, line) + if sbracket_count(line) < 0: + break + set_attribute_flag(attributes, trim_c_id(line), "constructor") + attrib_doxy["constructor"] = doxy + doxy = "" + elif re.search(r"^\s*\!mandatory\s+\[", line): + for line in instream: + raw_code = raw_code + line + (doxy, line) = doxy_check_add(doxy, line) + if sbracket_count(line) < 0: + break + set_attribute_flag(attributes, trim_c_id(line), "mandatory") + attrib_doxy["mandatory"] = doxy + doxy = "" + elif re.search(r"^\s*\!immutable\s+\[", line): + for line in instream: + raw_code = raw_code + line + (doxy, line) = doxy_check_add(doxy, line) + if sbracket_count(line) < 0: + break + set_attribute_flag(attributes, trim_c_id(line), "immutable") + attrib_doxy["immutable"] = doxy + doxy = "" + elif re.search(r"^\s*\!deprecated\s+\[", line): + attrib_doxy["deprecated"] = doxy + doxy = "" + for line in instream: + raw_code = raw_code + line + (doxy, line) = doxy_check_add(doxy, line) + if sbracket_count(line) < 0: + break + set_attribute_flag(attributes, trim_c_id(line), "deprecated") + elif re.search(r"^\s*unique\s+", line): + tok = line.split() + attrib_doxy["unique"] = doxy + doxy = "" + set_attribute_flag(attributes, trim_c_id(tok[1]), "unique") + return raw_code + +def attribute_block_print(class_name, attributes, attrib_doxy): + """Generates a Doxygen documentation section from attribute flags + and doxygen docs stored to attrib_doxy + + Parameters: + class_name (string): Name of the class we are processing + attributes (dict): Dict where data about the attributes was stored + attrib_doxy (dict): Dict where doxygen docs of the attributes block was stored + + """ + logging.debug("class_name \'%s\'", class_name) + for field in attrib_doxy: + # Only add attribute paragraph if there are doxygen comment for it + if attrib_doxy[field] != "": + print("//! \\par %s attributes:\n//!" % field.capitalize()) + for attr in attributes: + if attributes[attr].get(field): + print("//! \\link %s::%s \\endlink \\n" % (class_name, attr)) + print("//! \\n\n%s" % attrib_doxy[field]) + +def attribute_block_info_add(attributes, attrib_doxy): + """Add simple bullets in the attribute (= struct members) documentation if + the attribute has constructor, mandatory, immutable, deprecated, or unique + property. + + Parameters: + attributes (dict): Dict where data about the attributes was stored + attrib_doxy (dict): Dict where doxygen docs of the attributes block was stored + + """ + # TODO: Add short documentation about the attribute properties and link to it. + for field in attrib_doxy: + for attr in attributes: + if attributes[attr].get(field): + if not attributes[attr].get("doxy"): + attributes[attr]["doxy"] = "" + attributes[attr]["doxy"] = "//! - \\em " + field + " attribute.\\n\n" + attributes[attr]["doxy"] + +def parse_class_contents(class_name, attributes, attrib_doxy, objs, defaults, + instream, includef = ""): + """Translates the contents inside a class definition { } block + + Parameters: + class_name (string): Class name + attributes (dict): Dict where data about the attributes is stored + attrib_doxy (dict): Dict to store doxygen docs associated with the attributes block + objs (dict): Dict to store fist level contained objects with Docxyge docs + defaults (streaM): Stream where the instances of the objects are printed + instream (stream): Input stream of topology2 file we are decoding + includef (string): Include file from where the attributes and objects inline included from + + Returns: + string: The original code that was translated + """ + bsum = 1 + doxy_addition = "" + if includef != "": + doxy_addition = "//! - Included from <" + includef + ">\\n\n" + doxy = "" + raw_code = "" + for line in instream: + raw_code = raw_code + line + if parse_include_str(line): + # Inline files that are included from within a class definition + filename = line[line.find("<") + 1:line.find(">")] + logging.debug("try to inline include \'%s\' from \'%s\'", + filename, os.getcwd()) + # NOTE: The path is relative to when the script exists so + # two levels up and we are at topology2 root + with open("../../" + filename, "r+", encoding="ascii") as ifile: + parse_class_contents(class_name, attributes, attrib_doxy, objs, + defaults, ifile, filename) + continue + if (code := parse_include_by_key(line, instream, sys.stdout)): + raw_code = raw_code + code + continue + if re.search(r"^\s*DefineAttribute\.", line): + doxy = doxy_addition + doxy + raw_code = raw_code + parse_class_attribute(attributes, doxy, instream, line) + doxy = "" + elif re.search(r"^\s*DefineArgument\.", line): + for line in instream: # Just skip, this is only used in bytes.conf + if cbracket_count(line) < 0: + break + elif re.search(r"^\s*attributes\s+\{", line): + doxy = "" # Doxy comments before attributes block end in weird places + raw_code = raw_code + parse_attributes_block(instream, attributes, attrib_doxy) + elif re.search(r"^\s*Object\.", line): + # TODO: Pass collected doxy comments to parse_object and store in objs + doxy = "" + raw_code = raw_code + parse_object(instream, line, file = defaults, + objects = objs, tabs = "\t", ending = ",") + else: # If nothing else matched, assume a default value definition for an attribute + (doxy, line) = doxy_check_add(doxy, line) + tok = line.split() + if len(tok) == 2 and tok[0].isidentifier(): + if doxy != "": + print(doxy, file = defaults) + doxy = "" + val = trim_value(line[line.find(tok[0]) + len(tok[0]):]) + print("\t.%s =\t%s," % (trim_c_id(tok[0]), val), + file = defaults) + bsum = bsum + cbracket_count(line) + if bsum < 1: + break + return raw_code + +def parse_class(instream, fline): + """Parse class definition and print out C struct definition + + Parameters: + fline (string): First input line that was read by the caller + instream (stream): Input stream of topology2 file we are decoding + """ + logging.debug("fline: %s", fline) + tok = fline.split(maxsplit = 2) + cdef = tok[0].split(".") + # base = cdef[1] # Just in case we go back to C++ tralation + class_name = cdef[2] + class_name = trim_c_id(class_name) + attributes = {} + attrib_doxy = {} + defaults = io.StringIO() + objs = {} + raw_code = fline + parse_class_contents(class_name, attributes, attrib_doxy, + objs, defaults, instream) + attribute_block_print(class_name, attributes, attrib_doxy) + attribute_block_info_add(attributes, attrib_doxy) + print("//! \\ref %s_rawcode" % class_name) + print("struct %s {" % class_name) + print_attributes(attributes) + for obj in objs: + if objs[obj]["count"] > 1: + for i in range(objs[obj]["count"]): + print(objs[obj]["doxy"][i]) + print("\tstruct %s %s%d;" % (obj, obj, i)) + else: + print(objs[obj]["doxy"][0]) + print("\tstruct %s %s;" % (obj, obj)) + print("};\n") + print("/*! \\page %s_rawcode The %s class definition in topology2 code\n\t\\code{.unparsed}" % + (class_name, class_name)) + print(raw_code) + print("\t\\endcode\n*/") + print("//! \\var struct %s %s_defaults" % (class_name, class_name)) + print("//! \\brief %s class default values" % class_name) + print("struct %s %s_defaults = {\n" % (class_name, class_name)) + print(defaults.getvalue()) + print("};\n") + defaults.close() + +def parse_members(instream, cbsum, tabs, file): + """Parse attribute initializations from object instantiation + + Parameters: + instream (stream): Input stream of topology2 file we are decoding + cbsum (int): The amount of curly brackets "{" WE HAVE OPEN + tabs (string): Current level of indentation + + Returns: + string: The original code that was translated + """ + doxy = "" + raw_code = "" + for line in instream: + raw_code = raw_code + line + if (code := parse_include_by_key(line, instream, file)): + raw_code = raw_code + code + continue + cbsum = cbsum + cbracket_count(line) + (doxy, line) = doxy_check_add(doxy, line) + # Assume ending } to be alone on its own line + if cbsum < 1: + break + if re.search(r"^\s*Object\.", line): + logging.debug("object-line: %s", line) + obj = line.split(".") + if cbsum == 2: + # Assume Object.Base.name.1 { + doxy = print_doxy(doxy, file = file) + raw_code = raw_code + parse_object(instream, line, file = file, tabs = tabs, ending = ",") + cbsum = 1 + elif cbsum == 1: + # Assume Object.Base.name.1 {} + doxy = print_doxy(doxy, file = file) + print("%s.%s = {}," % (tabs, obj[2]), file = file) + else: + tok = line.split(maxsplit = 1) + if len(tok) >=2: + name = tok[0] + val = trim_value(tok[1]) + doxy = print_doxy(doxy, file = file) + print("%s.%s = %s," % (tabs, name, val), file = file) + return raw_code + +# +def object_instance_prefix(name, ending): + """Decide "struct name name =" or ".name =" based on instantiation ending in ',' or ';' + + Parameters: + name (string): Name of the object instance + ending (string): Either ',' or ';' indication if this is an instance or a definition + + """ + if ending == ";": + return "struct " + name + " " + return "." + +def parse_object(instream, fline, file = sys.stdout, objects = {}, tabs = "", ending = ";"): + """Translates all Object instatiation into initialized C structs + Note that dict arguments in python are passed as reference + + Parameters: + instream (stream): Input stream of topology2 file we are decoding + fline (string): First input line that was read by the caller + file (stream): Where the C struct instance or definition is printed + objects (dict): Dict to store fist level contained objects with Docxyge docs + ending (string): Either ',' or ';' indication if this is an instance or a definition + tabs (string): Current level of indentation + + Returns: + string: The original code that was translated + """ + logging.debug("fline: %s", fline) + tok = fline.split(maxsplit = 2) + obj = tok[0].split(".") + cbsum = cbracket_count(fline) + sbsum = sbracket_count(fline) + name = "" + doxy = "" + raw_code = "" + if len(obj) == 4 and sbsum == 0 and cbsum == 0: + # Assume Object.Base.name.1 { } + name = obj[2] + name = trim_c_id(name) + doxy = print_doxy(doxy, file = file) + prefix = object_instance_prefix(name, ending) + print("%s%s = {}%s" % (prefix, name, ending), file = file) + objects[name] = { "count": 1, "doxy": [doxy] } + elif len(obj) == 4 and sbsum == 0 and cbsum == 1: + # Assume Object.Base.name.1 { + name = obj[2] + name = trim_c_id(name) + doxy = print_doxy(doxy, file = file) + prefix = object_instance_prefix(name, ending) + print("%s%s%s = {" % (tabs, prefix, name), file = file) + raw_code = raw_code + parse_members(instream, cbsum, tabs + "\t", file) + print("%s}%s" % (tabs, ending), file = file) + objects[name] = { "count": 1, "doxy": [doxy] } + elif len(obj) == 3 and sbsum == 1 and cbsum == 0: + # Assume Object.Base.name [ + name = obj[2] + name = trim_c_id(name) + doxy = print_doxy(doxy, file = file) + prefix = object_instance_prefix(name, ending) + print("%s%s%s[] = {" % (tabs, prefix, name), file = file) + objects[name] = { "count": 0, "doxy": [] } + for line in instream: + raw_code = raw_code + line + if parse_include(line): + continue + if (code := parse_include_by_key(line, instream, sys.stdout)): + raw_code = raw_code + code + continue + sbsum = sbsum + sbracket_count(line) + cbsum = cbsum + cbracket_count(line) + (doxy, line) = doxy_check_add(doxy, line) + if sbsum < 1: + print("%s}%s" % (tabs, ending), file = file) + break + if cbsum == 1: # Assume starting { on its own line + objects[name]["count"] = objects[name]["count"] + 1 + objects[name]["doxy"].append(doxy) + doxy = print_doxy(doxy, file = file) + print("%s\t{" % tabs, file = file) + raw_code = raw_code + parse_members(instream, cbsum, tabs + "\t\t", file) + cbsum = 0 + print("%s\t}," % tabs, file = file) + elif len(obj) == 2 and sbsum == 0 and cbsum == 1: + # Assume Object.Base { + for line in instream: + raw_code = raw_code + line + if parse_include(line): + continue + if (code := parse_include_by_key(line, instream, file)): + raw_code = raw_code + code + continue + sbsum = sbsum + sbracket_count(line) + cbsum = cbsum + cbracket_count(line) + (doxy, line) = doxy_check_add(doxy, line) + if cbsum < 1: # Ending } found + break + if sbsum == 1 and cbsum == 1 and sbracket_count(line) > 0: + # Assume Class_name [ + tok = line.split() + name = trim_c_id(tok[0]) + objects[name] = { "count": 0, "doxy": [] } + doxy = print_doxy(doxy, file = file) + prefix = object_instance_prefix(name, ending) + print("%s%s%s[] = {" % (tabs, prefix, name), file = file) + elif sbsum == 1 and cbsum == 2: + # Assume class_name [ \n { \n + objects[name]["count"] = objects[name]["count"] + 1 + objects[name]["doxy"].append(doxy) + doxy = print_doxy(doxy, file = file) + print("%s\t{" % tabs, file = file) + raw_code = raw_code + parse_members(instream, 1, tabs + "\t\t", file) + print("%s\t}," % tabs, file = file) + cbsum = 1 + elif sbsum == 0 and cbsum == 1 and sbracket_count(line) < 0: + # Assume ending ] of class table alone one its own line + print("%s}%s" % (tabs, ending), file = file) + elif sbsum == 0 and cbsum == 1 and line.count("}") == 1: + # Assume name."1" {} + # No init values, so no instantiation code needed, but we still need + # to store the object into objexts dict. + tok = line.split() + tok = tok[0].split(".") + name = trim_c_id(tok[0]) + if not objects.get(name): + objects[name] = { "count": 0, "doxy": [] } + objects[name]["count"] = objects[name]["count"] + 1 + objects[name]["doxy"].append(doxy) + doxy = print_doxy(doxy, file = file) + elif sbsum == 0 and cbsum == 2 and cbracket_count(line) == 1: + # Assume name."1" { + tok = line.split() + tok = tok[0].split(".") + name = trim_c_id(tok[0]) + mname = name + if len(tok) > 1: + idx = tok[1].strip(" \"\'") + if idx.isidentifier() or idx.isnumeric(): + mname = mname + "_" + idx + if not objects.get(name): + objects[name] = { "count": 0, "doxy": [] } + objects[name]["count"] = objects[name]["count"] + 1 + objects[name]["doxy"].append(doxy) + doxy = print_doxy(doxy, file = file) + prefix = object_instance_prefix(name, ending) + print("%s%s%s = {" % (tabs, prefix, mname), file = file) + raw_code = raw_code + parse_members(instream, 1, tabs + "\t", file) + cbsum = 1 + print("%s}%s" % (tabs, ending), file = file) + return raw_code + +def parse_object_and_make_raw_code_page(filename, index, instream, fline): + """Parses an object instance outputs its C equivalent, and creates a raw code page of + of it and prints a reference to it. Handles an "Object.... {}" instance completely + and produces possibly multiple initialized C structs, but always just one raw code + block containing the "Object.... {}" block completely. + + Parameters: + filename (stream): Name of the file we are paring + index (int): The index of the decoded Object block in this file we are handling + instream (stream): Input stream of topology2 file we are decoding + fline (string): First input line that was read by the caller + + """ + tok = filename.split("/") + filename = fname = tok[len(tok)-1] + fname = fname.replace("-", "_") + fname = fname.replace(".", "_") + c_instances = io.StringIO() + raw_code = fline + parse_object(instream, fline, c_instances) + print("/*! \\page %s_%d_rawcode The %s instances #%d in topology2 code\n\t\\code{.unparsed}" % + (fname, index, filename, index)) + print(raw_code) + print("\t\\endcode\n*/") + print("//! \\brief \\ref %s_%d_rawcode" % (fname, index)) + print(c_instances.getvalue()) + c_instances.close() + +# Main starts here, apart from debug file opening +filename = sys.argv[1] +logging.info("file: %s", filename) +with open(filename, "r+", encoding="ascii") as instream: + block_idx = 0 + + shortfname = filename[filename.find("/topology2/"):] + print("//! \\file %s" % shortfname[11:]) + print("//! Source file can be found " + + "here." + % shortfname) + for line in instream: + if parse_include(line): + continue + if parse_define_block(line, instream): + continue + if parse_include_by_key(line, instream, sys.stdout): + continue + if re.search(r"^\s*Class\.", line): + parse_class(instream, line) + elif re.search(r"^\s*Object\.", line): + parse_object_and_make_raw_code_page(filename, block_idx, instream, line) + block_idx = block_idx + 1 + elif line.find("##") >= 0: + sys.stdout.write(line.replace("##", "//!", 1)) + else: + sys.stdout.write("\n") From f74f213d462360ce1b3d621f245cdba97fc005c2 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Thu, 11 May 2023 17:02:20 +0300 Subject: [PATCH 02/16] topology2: doc: Add initial sof.doxygen.in Includes all *.conf files under topology2 to the Doxygen documentation and points directly to mainpage Doxygen source. Signed-off-by: Jyri Sarha --- tools/topology/topology2/doc/sof.doxygen.in | 32 +++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 tools/topology/topology2/doc/sof.doxygen.in diff --git a/tools/topology/topology2/doc/sof.doxygen.in b/tools/topology/topology2/doc/sof.doxygen.in new file mode 100644 index 000000000000..17068b4a91c3 --- /dev/null +++ b/tools/topology/topology2/doc/sof.doxygen.in @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: BSD-3-Clause +PROJECT_NAME = "Sound Open Firmware Topology2" +OUTPUT_DIRECTORY = doxygen +GENERATE_LATEX = NO +GENERATE_RTF = NO +GENERATE_MAN = NO +GENERATE_XML = YES + +CASE_SENSE_NAMES = NO +INPUT = @top_srcdir@ + +RECURSIVE = YES +FILE_PATTERNS = *.conf +IMAGE_PATH = +QUIET = YES +WARN_LOGFILE = doxygen_warnings.txt + +EXTRACT_ALL = YES +EXTRACT_STATIC = YES +WARN_IF_UNDOCUMENTED = NO +SHOW_INCLUDE_FILES = YES +JAVADOC_AUTOBRIEF = YES +INHERIT_DOCS = YES + +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = YES +OPTIMIZE_OUTPUT_FOR_C = YES + +HTML_TIMESTAMP = NO + +EXTENSION_MAPPING = conf=C +FILTER_PATTERNS = *.conf=@top_srcdir@/doc/topology2-filter.py From 7e20a69d058c23718652ec8711ce4abc348e09ca Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Thu, 31 Aug 2023 20:28:01 +0300 Subject: [PATCH 03/16] topology2: doc: Initial cmake build rules for doxygen documentation Signed-off-by: Jyri Sarha --- tools/topology/topology2/doc/CMakeLists.txt | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 tools/topology/topology2/doc/CMakeLists.txt diff --git a/tools/topology/topology2/doc/CMakeLists.txt b/tools/topology/topology2/doc/CMakeLists.txt new file mode 100644 index 000000000000..e5b9e4a5211c --- /dev/null +++ b/tools/topology/topology2/doc/CMakeLists.txt @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: BSD-3-Clause + +cmake_minimum_required(VERSION 3.13) + +project(SOF_TOPOLOGY2_DOC NONE) + +set(SOF_ROOT_SOURCE_DIRECTORY "${PROJECT_SOURCE_DIR}/..") + +set(top_srcdir "${SOF_ROOT_SOURCE_DIRECTORY}") + +configure_file( + "${PROJECT_SOURCE_DIR}/sof.doxygen.in" + "${PROJECT_BINARY_DIR}/sof.doxygen" +) + +add_custom_target("doc" ALL + COMMAND doxygen sof.doxygen + VERBATIM + USES_TERMINAL +) From 39f1c1af83258d9864c0ea5701a0a0134db76474 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Thu, 28 Sep 2023 22:56:49 +0300 Subject: [PATCH 04/16] topology2: doc: Add README instructing how to build the documentation Signed-off-by: Jyri Sarha --- tools/topology/topology2/doc/README | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tools/topology/topology2/doc/README diff --git a/tools/topology/topology2/doc/README b/tools/topology/topology2/doc/README new file mode 100644 index 000000000000..a412e1d2d707 --- /dev/null +++ b/tools/topology/topology2/doc/README @@ -0,0 +1,7 @@ +To build the topology2 source documentation do following steps: + +cd tools/topology/topology2/doc +cmake -B build/ +cmake --build build/ -v + +After the last command you should find the html documentation under: sof/tools/topology/topology2/doc/build/doxygen/html From cf3f409fccc3551ed6fed41a4f2a2b62b3d286d1 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Wed, 27 Sep 2023 19:01:26 +0300 Subject: [PATCH 05/16] topology2: doc: topology2-generate-contents.sh: Script to generate contents This commit adds topology2-generate-contents.sh the script to generate the contents page that will be inline included to the mainpage added in the next commit. Signed-off-by: Jyri Sarha --- .../doc/topology2-generate-contents.sh | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100755 tools/topology/topology2/doc/topology2-generate-contents.sh diff --git a/tools/topology/topology2/doc/topology2-generate-contents.sh b/tools/topology/topology2/doc/topology2-generate-contents.sh new file mode 100755 index 000000000000..ea5b4ed059cb --- /dev/null +++ b/tools/topology/topology2/doc/topology2-generate-contents.sh @@ -0,0 +1,31 @@ +#!/bin/bash +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2023 Intel Corporation. All rights reserved. +# This script generates the contents page and stores it in extra-contents/contents.doxy + +set -e +cd "$(dirname "$0")" + +generate_contents () +{ + cat < Date: Tue, 5 Sep 2023 00:15:23 +0300 Subject: [PATCH 06/16] topology2: doc: mainpage.doxy: Add simple main-page with contents The initial main-page contains a short introduction into topology2 Doxygen documentation, and an inline reference to automatically generated contents page. The commit also adds more advanced cmake rules to track all document dependencies. Signed-off-by: Jyri Sarha --- tools/topology/topology2/doc/CMakeLists.txt | 29 ++++++++++++++++- .../doc/extra-contents/mainpage.doxy | 32 +++++++++++++++++++ tools/topology/topology2/doc/sof.doxygen.in | 6 ++-- 3 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 tools/topology/topology2/doc/extra-contents/mainpage.doxy diff --git a/tools/topology/topology2/doc/CMakeLists.txt b/tools/topology/topology2/doc/CMakeLists.txt index e5b9e4a5211c..303d06da3d15 100644 --- a/tools/topology/topology2/doc/CMakeLists.txt +++ b/tools/topology/topology2/doc/CMakeLists.txt @@ -7,14 +7,41 @@ project(SOF_TOPOLOGY2_DOC NONE) set(SOF_ROOT_SOURCE_DIRECTORY "${PROJECT_SOURCE_DIR}/..") set(top_srcdir "${SOF_ROOT_SOURCE_DIRECTORY}") +set(top_bindir "${PROJECT_BINARY_DIR}") configure_file( "${PROJECT_SOURCE_DIR}/sof.doxygen.in" "${PROJECT_BINARY_DIR}/sof.doxygen" ) -add_custom_target("doc" ALL +file(GLOB_RECURSE topology2_sources "${SOF_ROOT_SOURCE_DIRECTORY}/*.conf") +file(GLOB_RECURSE extra_sources "${PROJECT_SOURCE_DIR}/extra-contents/*.doxy") + +add_custom_command( + OUTPUT ${PROJECT_BINARY_DIR}/contents.doxy + COMMAND ${PROJECT_SOURCE_DIR}/topology2-generate-contents.sh > ${PROJECT_BINARY_DIR}/contents.doxy + DEPENDS ${PROJECT_SOURCE_DIR}/topology2-generate-contents.sh + DEPENDS ${topology2_sources} + VERBATIM +) + +add_custom_target(doc-contents + DEPENDS ${PROJECT_BINARY_DIR}/contents.doxy +) + +add_custom_command( + OUTPUT ${PROJECT_BINARY_DIR}/doxygen/html/index.html COMMAND doxygen sof.doxygen + DEPENDS ${PROJECT_BINARY_DIR}/sof.doxygen + DEPENDS ${PROJECT_SOURCE_DIR}/topology2-filter.py + DEPENDS doc-contents + DEPENDS ${extra_sources} + DEPENDS ${topology2_sources} VERBATIM USES_TERMINAL ) + +add_custom_target(doc ALL + DEPENDS ${PROJECT_BINARY_DIR}/doxygen/html/index.html + VERBATIM +) diff --git a/tools/topology/topology2/doc/extra-contents/mainpage.doxy b/tools/topology/topology2/doc/extra-contents/mainpage.doxy new file mode 100644 index 000000000000..4b2a2bfcabc8 --- /dev/null +++ b/tools/topology/topology2/doc/extra-contents/mainpage.doxy @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* Copyright(c) 2023 Intel Corporation. All rights reserved. */ +/*! \mainpage Sound Open Firmware Topology2 + * + * \section this_document This Document + * + * This document is generated from SOF topology2 sources and its + * purpose is provide examples of how SOF ALSA topologies are built + * through instantiating toppology2 classes. + * + * The documentation is provided using Doxygen package and a Doxygen + * filter that translates the topology2 classes into C-structures. The + * filter is implemented in python and can be found from + * tools/topology/topology2/doc/topology2-filter.py + * + * The topology2 language syntax is described in detail here. + * + * \subsection doc_reading Reading the document + * + * The purpose of the translated C code is not to document actual + * topology2 code, but only to provide anchors for Doxygen to form a + * network of links through which to navigate the topology sources and + * find the pieces of related Doxygen documentation. The filter also + * creates separate pages of the original code and add links next to + * the pages in the C struct definition and instance documentation. + * + * The most essential part of the documentation is the documentation of + * classes that shown as C structs in this Doxygen documentation. + * + * \copydoc doc_contents + */ diff --git a/tools/topology/topology2/doc/sof.doxygen.in b/tools/topology/topology2/doc/sof.doxygen.in index 17068b4a91c3..d964c58258da 100644 --- a/tools/topology/topology2/doc/sof.doxygen.in +++ b/tools/topology/topology2/doc/sof.doxygen.in @@ -7,7 +7,9 @@ GENERATE_MAN = NO GENERATE_XML = YES CASE_SENSE_NAMES = NO -INPUT = @top_srcdir@ +INPUT = @top_srcdir@ \ + @top_srcdir@/doc/extra-contents/ \ + @top_bindir@/contents.doxy RECURSIVE = YES FILE_PATTERNS = *.conf @@ -28,5 +30,5 @@ OPTIMIZE_OUTPUT_FOR_C = YES HTML_TIMESTAMP = NO -EXTENSION_MAPPING = conf=C +EXTENSION_MAPPING = conf=C,doxy=C FILTER_PATTERNS = *.conf=@top_srcdir@/doc/topology2-filter.py From 62647c0bd19cfdc063e55f16c1b8c92a6dddcd7d Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Thu, 31 Aug 2023 17:39:53 +0300 Subject: [PATCH 07/16] topology2: doc: gain.conf: Convert comments to Doxygen documentation Signed-off-by: Jyri Sarha --- .../topology2/include/components/gain.conf | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/tools/topology/topology2/include/components/gain.conf b/tools/topology/topology2/include/components/gain.conf index 395edb64ba94..52935f7a78eb 100644 --- a/tools/topology/topology2/include/components/gain.conf +++ b/tools/topology/topology2/include/components/gain.conf @@ -1,29 +1,29 @@ -# -# Common pipeline gain (volume) -# -# A generic gain (volume) widget. All attributes defined herein are namespaced -# by alsatplg to "Object.Widget.gain.N.attribute_name" -# -# Usage: this component can be used by declaring int a parent object. i.e. -# -# Object.Widget.gain."N" { -# index 1 -# format s24le -# no_pm "true" -# } -# -# Where N is the unique instance number for gain widget in the same alsaconf node. +## \struct gain +## \brief Common pipeline gain (volume) +## +## A generic gain (volume) widget. All attributes defined herein are namespaced +## by alsatplg to "Object.Widget.gain.N.attribute_name" +## +## Usage: this component can be used by declaring int a parent object. i.e. +## +## Object.Widget.gain."N" { +## index 1 +## format s24le +## no_pm "true" +## } +## +## Where N is the unique instance number for gain widget in the same alsaconf node. Class.Widget."gain" { # - # Pipeline ID for the gain widget object + ## Pipeline ID for the gain widget object # DefineAttribute."index" {} # - # gain object instance + ## gain object instance # DefineAttribute."instance" {} @@ -35,9 +35,9 @@ Class.Widget."gain" { # # - # Gain curve type. The values provided will be translated to integer values - # as specified in the tuple_values array. - # For example: "linear" is translated to 0, "log" to 1 etc. + ## Gain curve type. The values provided will be translated to integer values + ## as specified in the tuple_values array. + ## For example: "linear" is translated to 0, "log" to 1 etc. # DefineAttribute."curve_type" { type "string" @@ -56,7 +56,7 @@ Class.Widget."gain" { } # - # Gain curve in milliseconds + ## Gain curve in milliseconds # DefineAttribute."curve_duration" { # Token set reference name @@ -71,8 +71,8 @@ Class.Widget."gain" { # Attribute categories attributes { # - # The PGA widget name would be constructed using the index and instance attributes. - # For ex: "gain.1.1" or "gain.10.2" etc. + ## The PGA widget name would be constructed using the index and instance attributes. + ## For ex: "gain.1.1" or "gain.10.2" etc. # !constructor [ "index" @@ -114,9 +114,9 @@ Class.Widget."gain" { # gain widget mixer controls # Object.Control { - # gain mixer control + ## gain mixer control mixer."1" { - #Channel register and shift for Front Left/Right + ## Channel register and shift for Front Left/Right Object.Base.channel.1 { name "fl" shift 0 @@ -128,7 +128,7 @@ Class.Widget."gain" { Object.Base.ops.1 { name "ctl" info "volsw" - #256 binds the mixer control to volume get/put handlers + ## get = 256 binds the mixer control to volume get/put handlers get 256 put 256 } From 28759abdb7cf59931bfe24a86c74d818aec865b3 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Fri, 18 Aug 2023 12:52:58 +0300 Subject: [PATCH 08/16] topology2: doc: common.conf: Doxygenify the existing comments Signed-off-by: Jyri Sarha --- .../topology2/include/controls/common.conf | 92 ++++++++++++------- 1 file changed, 57 insertions(+), 35 deletions(-) diff --git a/tools/topology/topology2/include/controls/common.conf b/tools/topology/topology2/include/controls/common.conf index 77593fccc1fb..0cf249914070 100644 --- a/tools/topology/topology2/include/controls/common.conf +++ b/tools/topology/topology2/include/controls/common.conf @@ -1,15 +1,19 @@ -# Common class definitions for controls - -# -# Class for channel objects. These are instantiated as: -# Object.Base.channel."fl" { -# reg 1 -# shift 0 -# } -# +## \file common.conf +## \brief Common class definitions for controls. + +## \struct channel +## \brief Class for channel objects. +## These are instantiated as: +## +## Object.Base.channel."fl" { +## reg 1 +## shift 0 +## } +## + Class.Base."channel" { DefineAttribute."instance" {} - # name of the channel + ## name of the channel DefineAttribute."name" { type "string" } @@ -33,13 +37,18 @@ Class.Base."channel" { shift 1 } -# Class definition for control ops. These are instantiated as: -# Object.Base.ops."ctl" { -# info "volsw" -# get "259" -# put "259" -# } -# +## \struct ops +## \brief Class definition for control ops. +## +## These are instantiated as: +## +## Object.Base.ops."ctl" { +## info "volsw" +## get "259" +## put "259" +## } +## + Class.Base."ops" { DefineAttribute."instance" {} # ops name @@ -68,13 +77,17 @@ Class.Base."ops" { } } -# Class definition for control extops. These are instantiated as: -# Object.Base.extops."ctl" { -# info "volsw" -# get "258" -# put "258" -# } -# +## \struct extops +## \brief Class definition for control extops. +## These are instantiated as: +## +## Object.Base.extops."ctl" { +## info "volsw" +## get "258" +## put "258" +## } +## + Class.Base."extops" { DefineAttribute."instance" {} # extops name @@ -104,12 +117,15 @@ Class.Base."extops" { } } -# -# Class definition for scale objects. These are instantiated as follows: -# Object.Base.scale."name" { -# mute 1 -# } -# +## \struct scale +## \brief Class definition for scale objects. +## These are instantiated as follows: +## +## Object.Base.scale."name" { +## mute 1 +## } +## + Class.Base."scale" { DefineAttribute."instance" {} DefineAttribute."name" { @@ -139,11 +155,17 @@ Class.Base."scale" { mute 1 } -# -# Class definition for tlv objects. These are instantiated as follows: -# Object.Base.tlv."vtlv_m64s2" { -# Object.Base.scale."0" {} -# } +## \struct tlv +## \brief Class definition for tlv objects. +## These are instantiated as follows: +## +## Object.Base.tlv."vtlv_m64s2" { +## Object.Base.scale."0" {} +## } +## +## The linked object instance is \link scale \endlink . +## + Class.Base."tlv" { DefineAttribute."instance" {} DefineAttribute."name" { From c1e2230a813321a4e500d90435d0692c3dde0f82 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Thu, 11 May 2023 17:52:27 +0300 Subject: [PATCH 09/16] topology2: doc: mixer.conf: Doxygenify and improve the existing comments Improve and convert comments to doxygen documentation. Signed-off-by: Jyri Sarha --- .../topology2/include/controls/mixer.conf | 72 ++++++++++--------- 1 file changed, 38 insertions(+), 34 deletions(-) diff --git a/tools/topology/topology2/include/controls/mixer.conf b/tools/topology/topology2/include/controls/mixer.conf index 66b5085cf857..191230ec5bdc 100644 --- a/tools/topology/topology2/include/controls/mixer.conf +++ b/tools/topology/topology2/include/controls/mixer.conf @@ -1,41 +1,45 @@ -# -# Mixer kcontrol class. All attributes defined herein are namespaced -# by alsatplg to "Object.Control.mixer.N.attribute_name" -# -# Usage: this component can be used by instantiating it in the parent object. i.e. -# -# Object.Control.mixer."N" { -# index 1 -# name "1 Master Playback Volume" -# mas 32 -# Object.Base.channel.1 { -# name "fl" -# shift 0 -# reg 0 -# } -# Object.Base.channel.2 { -# name "fr" -# shift 1 -# reg 1 -# } -# Object.Base.ops."ctl" { -# info "volsw" -# get "258" -# put "258" -# } -# } -# -# Where N is the unique instance number for the buffer object within the same alsaconf node. -# The mixer control object should also include the ops, channels and tlv objects in the object -# instance +## \struct mixer +## \brief Topology Mixer class +## +## All attributes defined herein are namespaced +## by alsatplg to "Object.Control.mixer.N.attribute_name" +## +## Usage: this component can be used by instantiating it in the parent object. i.e. +## +## Object.Control.mixer."N" { +## index 1 +## name "1 Master Playback Volume" +## max 32 +## Object.Base.channel.1 { +## name "fl" +## shift 0 +## reg 0 +## } +## Object.Base.channel.2 { +## name "fr" +## shift 1 +## reg 1 +## } +## Object.Base.ops."ctl" { +## info "volsw" +## get "258" +## put "258" +## } +## } +## +## The linked object instaces are \link channel \endlink and \link ops \endlink . +## +## Where N is the unique instance number for the buffer object within the same alsaconf node. +## The mixer control object should also include the ops, channels and tlv objects in the object +## instance Class.Control."mixer" { - # - # Pipeline ID for the mixer object - # - DefineAttribute."index" {} + ## + ## @ Pipeline ID for the mixer object + ## + DefineAttribute."index" {} ##< Automatically given unique index # # Instance of mixer object in the same alsaconf node From 60632d6df67abf1731b6cbba60c100179907bda5 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Fri, 1 Sep 2023 13:06:10 +0300 Subject: [PATCH 10/16] topology2: doc: volume-playback.conf: Doxygenify existing comments Doxygenify all comments that are correctly placed near the attribute's or objects C-translation. This is not the case for comments before Object.Base { } definition or comment before including pipeline-common.conf, which is inlined by the topology2 filter, does not end up in any relevant place, so its better just leave those comments as they are. They can anyway be read from topology2 source snippets. Signed-off-by: Jyri Sarha --- .../include/pipelines/volume-playback.conf | 48 ++++++++++--------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/tools/topology/topology2/include/pipelines/volume-playback.conf b/tools/topology/topology2/include/pipelines/volume-playback.conf index d04830b2168a..fa007609ab4c 100644 --- a/tools/topology/topology2/include/pipelines/volume-playback.conf +++ b/tools/topology/topology2/include/pipelines/volume-playback.conf @@ -1,24 +1,26 @@ -# -# Volume playback pipeline -# -# A simple pipeline. All attributes defined herein are namespaced by alsatplg to -# "Object.Pipeline.volume-playback.N.attribute_name" -# -# Usage: this component can be used by declaring in the top-level topology conf file as follows: -# -# Object.Pipeline.volume-playback."N" { -# format "s16le" -# period 1000 -# time_domain "timer" -# channels 2 -# rate 48000 -# } -# -# where N is the unique pipeline_id for this pipeline object within the same alsaconf node. -# -# -# (source) host.N.playback -> buffer.N.1 -> volume.N.1 -> buffer.N.2 (sink endpoint) -# +## \struct volume_playback +## \brief Volume playback pipeline +## +## \par Instantiating volume-playback pipeline +## +## A simple pipeline. All attributes defined herein are namespaced by alsatplg +## to "Object.Pipeline.volume-playback.N.attribute_name" +## +## Usage: this component can be used by declaring in the top-level topology conf file as follows: +## +## Object.Pipeline.volume-playback."N" { +## format "s16le" +## period 1000 +## time_domain "timer" +## channels 2 +## rate 48000 +## } +## +## where N is the unique pipeline_id for this pipeline object within the same alsaconf node. +## +## +## (source) host.N.playback -> buffer.N.1 -> volume.N.1 -> buffer.N.2 (sink endpoint) +## @@ -31,7 +33,7 @@ Class.Pipeline."volume-playback" { attributes { - # pipeline name is constructed as "volume-playback.1" + ## pipeline name is constructed as "volume-playback.1" !constructor [ "index" ] @@ -49,9 +51,11 @@ Class.Pipeline."volume-playback" { } Object.Widget { + ## The pipeline object for captured playback pipeline."1" {} host."playback" { + ## "aif_in" is for playback type "aif_in" } From 0427fe0d13cc14fbf48d04990a50bea9b2dceeea Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Tue, 19 Sep 2023 12:32:18 +0300 Subject: [PATCH 11/16] topology2: doc: widget-common.conf: Attribute comments to Doxygen Change attribute comments to Doxygen comments. Signed-off-by: Jyri Sarha --- .../include/components/widget-common.conf | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/tools/topology/topology2/include/components/widget-common.conf b/tools/topology/topology2/include/components/widget-common.conf index af87e4e70f7d..3c398300ef89 100644 --- a/tools/topology/topology2/include/components/widget-common.conf +++ b/tools/topology/topology2/include/components/widget-common.conf @@ -2,12 +2,12 @@ # Common widget attribute definitions # -# instance of the widget object +## instance of the widget object DefineAttribute."instance" {} # -# no_pm - maps to the DAPM widget's reg field -# "false" value indicates that there is no direct DAPM for this widget +## no_pm - maps to the DAPM widget's reg field +## "false" value indicates that there is no direct DAPM for this widget # DefineAttribute."no_pm" { type "string" @@ -20,26 +20,26 @@ DefineAttribute."no_pm" { } # -# Widget Type - maps to the widget ID with values of type enum SND_SOC_TPLG_DAPM_* +## Widget Type - maps to the widget ID with values of type enum SND_SOC_TPLG_DAPM_* # DefineAttribute."type" { type "string" } # -# Stream name - maps to the DAPM widget's stream name +## Stream name - maps to the DAPM widget's stream name # DefineAttribute."stream_name" { type "string" } # -# Event type widget binds to +## Event type widget binds to # DefineAttribute.event_type {} # -# Widget event flags +## Widget event flags # DefineAttribute.event_flags {} @@ -47,7 +47,7 @@ DefineAttribute.event_flags {} # Attributes with a "token_ref" value will be added to widget's private data # -# widget format +## widget format DefineAttribute."format" { type "string" # Token set reference name and type @@ -62,49 +62,50 @@ DefineAttribute."format" { } } -# ID of the core this widget should be scheduled on +## ID of the core this widget should be scheduled on DefineAttribute."core_id" { # Token set reference name and type token_ref "comp.word" } -# number of periods to preload +## number of periods to preload DefineAttribute."preload_count" { # Token set reference name and type token_ref "comp.word" } -# Number of sink pins a widget can support +## Number of sink pins a widget can support DefineAttribute."num_input_pins" { # Token set reference name and type token_ref "comp.word" } -# Number of source pins a widget can support +## Number of source pins a widget can support DefineAttribute."num_output_pins" { # Token set reference name and type token_ref "comp.word" } -# Number of supported sink(input) audio formats +## Number of supported sink(input) audio formats DefineAttribute."num_input_audio_formats" { # Token set reference name and type token_ref "comp.word" } -# Number of supported source(output) audio formats +## Number of supported source(output) audio formats DefineAttribute."num_output_audio_formats" { # Token set reference name and type token_ref "comp.word" } -# Widget UUID +## Widget UUID DefineAttribute.uuid { type "string" # Token set reference name and type token_ref "comp.uuid" } +## Whether to add this widget's name to the beginning of all its associated mixer names DefineAttribute."no_wname_in_kcontrol_name" { type "string" # Token set reference name From 2ded578ebfa831d6b570d8d596e08ad7c86fa02d Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Tue, 26 Sep 2023 22:55:30 +0300 Subject: [PATCH 12/16] topology2: doc: audio_format.conf: Translate comments to Doxygen Signed-off-by: Jyri Sarha --- .../include/common/audio_format.conf | 73 ++++++++++--------- 1 file changed, 38 insertions(+), 35 deletions(-) diff --git a/tools/topology/topology2/include/common/audio_format.conf b/tools/topology/topology2/include/common/audio_format.conf index 8ee2e6bed86c..d572f3c00085 100644 --- a/tools/topology/topology2/include/common/audio_format.conf +++ b/tools/topology/topology2/include/common/audio_format.conf @@ -1,43 +1,44 @@ -# Class definition for audio format object -# audio_format objects can be instantiated as: -# -# Object.Base.audio_format."0" { -# in_rate 48000 -# in_sample_container_size 16 -# in_valid_bit_depth 16 -# in_interleaving_style "interleaved" -# out_rate 48000 -# out_sample_container_size 16 -# out_valid_bit_depth 16 -# out_interleaving_style "interleaved" - -# } -# +## \struct audio_format +## \brief Class definition for audio format object +## +## audio_format objects can be instantiated as: +## +## Object.Base.audio_format."0" { +## in_rate 48000 +## in_sample_container_size 16 +## in_valid_bit_depth 16 +## in_interleaving_style "interleaved" +## out_rate 48000 +## out_sample_container_size 16 +## out_valid_bit_depth 16 +## out_interleaving_style "interleaved" +## } +## Class.Base."audio_format" { DefineAttribute."instance" { } - # input sampling rate + ## input sampling rate DefineAttribute."in_rate" { # Token set reference name token_ref "cavs_audio_format.word" } - # input bit depth + # #input bit depth DefineAttribute."in_bit_depth" { # Token set reference name token_ref "cavs_audio_format.word" } - # input valid bit depth + ## input valid bit depth DefineAttribute."in_valid_bit_depth" { # Token set reference name token_ref "cavs_audio_format.word" } - # input channel count + ## input channel count DefineAttribute."in_channels" { # Token set reference name token_ref "cavs_audio_format.word" @@ -47,19 +48,19 @@ Class.Base."audio_format" { } } - # input channel map + ## input channel map DefineAttribute."in_ch_map" { # Token set reference name token_ref "cavs_audio_format.word" } - # input channel config + ## input channel config DefineAttribute."in_ch_cfg" { # Token set reference name token_ref "cavs_audio_format.word" } - # input interleaving style + ## input interleaving style DefineAttribute."in_interleaving_style" { type "string" # Token set reference name @@ -76,19 +77,20 @@ Class.Base."audio_format" { } } - # input format config + ## input format config DefineAttribute."in_fmt_cfg" { # Token set reference name token_ref "cavs_audio_format.word" } - # output sampling rate + ## output sampling rate DefineAttribute."out_rate" { # Token set reference name token_ref "cavs_audio_format.word" } - # input sample_type + ## Input sample_type. + ## Valid values for sample type are defined in common_definitions.conf. DefineAttribute."in_sample_type" { type string # Token set reference name @@ -104,19 +106,19 @@ Class.Base."audio_format" { } } - # output bit depth + ## output bit depth DefineAttribute."out_bit_depth" { # Token set reference name token_ref "cavs_audio_format.word" } - # output valid bit depth + ## output valid bit depth DefineAttribute."out_valid_bit_depth" { # Token set reference name token_ref "cavs_audio_format.word" } - # output channel count + ## output channel count DefineAttribute."out_channels" { # Token set reference name token_ref "cavs_audio_format.word" @@ -126,19 +128,19 @@ Class.Base."audio_format" { } } - # output channel map + ## output channel map DefineAttribute."out_ch_map" { # Token set reference name token_ref "cavs_audio_format.word" } - # output channel config + ## output channel config DefineAttribute."out_ch_cfg" { # Token set reference name token_ref "cavs_audio_format.word" } - # output interleaving style + ## output interleaving style DefineAttribute."out_interleaving_style" { type "string" # Token set reference name @@ -155,14 +157,14 @@ Class.Base."audio_format" { } } - # output format config + ## output format config DefineAttribute."out_fmt_cfg" { # Token set reference name token_ref "cavs_audio_format.word" } # - # input buffer size + ## input buffer size # DefineAttribute."ibs" { # Token set reference name and type @@ -170,14 +172,15 @@ Class.Base."audio_format" { } # - # output buffer size + ## output buffer size # DefineAttribute."obs" { # Token set reference name and type token_ref "cavs_audio_format.word" } - #output sample_type + ## Output sample_type. + ## Valid values for sample type are defined in common_definitions.conf. DefineAttribute."out_sample_type" { type string # Token set reference name From e6ec77ae3e34f64af43f2dd1058208c1e8b1167e Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Tue, 26 Sep 2023 23:01:06 +0300 Subject: [PATCH 13/16] topology2: doc: data.conf: Change comments to Doxygen Signed-off-by: Jyri Sarha --- .../topology/topology2/include/common/data.conf | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/tools/topology/topology2/include/common/data.conf b/tools/topology/topology2/include/common/data.conf index 84655302224e..02900ee192a4 100644 --- a/tools/topology/topology2/include/common/data.conf +++ b/tools/topology/topology2/include/common/data.conf @@ -1,10 +1,12 @@ -# Class definition for data object -# Data objects can be instantiated as: -# -# Object.Base.data."SOF ABI" { -# bytes "0x3, 0x12,0x1" -# } -# +## \struct data +## \brief Class definition for data object +## +## Data objects can be instantiated as: +## +## Object.Base.data."SOF ABI" { +## bytes "0x3, 0x12,0x1" +## } +## Class.Base."data" { DefineAttribute."instance" {} From 3d1d819d2f4b25a5435202d881570b0e4bec949c Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Tue, 26 Sep 2023 23:04:05 +0300 Subject: [PATCH 14/16] topology2: doc: fe_dai.conf: Change comments to Doxygen Signed-off-by: Jyri Sarha --- .../topology2/include/common/fe_dai.conf | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/tools/topology/topology2/include/common/fe_dai.conf b/tools/topology/topology2/include/common/fe_dai.conf index 8310c298c73b..e67d8aa4d22b 100644 --- a/tools/topology/topology2/include/common/fe_dai.conf +++ b/tools/topology/topology2/include/common/fe_dai.conf @@ -1,15 +1,17 @@ -# -# FE DAI Class definition. All attributes defined herein are namespaced -# by alsatplg to "Object.Base.fe_dai.instance.attribute_name". -# -# Usage: FE DAI objects can be instantiated as -# -# Object.Base.fe_dai.1 { -# id 0 -# } -# -# where NAME is the unique instance name for the FE DAI object within the -# same alsaconf node. +## \struct fe_dai +## \brief FE DAI Class definition +## +## All attributes defined herein are namespaced by alsatplg to +## "Object.Base.fe_dai.instance.attribute_name". +## +## Usage: FE DAI objects can be instantiated as +## +## Object.Base.fe_dai.1 { +## id 0 +## } +## +## where NAME is the unique instance name for the FE DAI object within the +## same alsaconf node. Class.Base."fe_dai" { From 037ab698d553554cf3d55b7ed667a2c16b4beee3 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Wed, 27 Sep 2023 18:56:55 +0300 Subject: [PATCH 15/16] topology2: doc: input_audio_format.conf: Translate comments to Doxygen Signed-off-by: Jyri Sarha --- .../include/common/input_audio_format.conf | 45 ++++++++++--------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/tools/topology/topology2/include/common/input_audio_format.conf b/tools/topology/topology2/include/common/input_audio_format.conf index f5b9956d841b..795f3cdb46b0 100644 --- a/tools/topology/topology2/include/common/input_audio_format.conf +++ b/tools/topology/topology2/include/common/input_audio_format.conf @@ -1,14 +1,16 @@ -# Class definition for input pin audio format object -# audio_format objects can be instantiated as: -# -# Object.Base.input_audio_format."0" { -# in_rate 48000 -# in_sample_container_size 16 -# in_valid_bit_depth 16 -# in_interleaving_style "interleaved" - -# } -# +## \struct input_audio_format +## \brief Volume playback pipeline +## +## Class definition for input pin audio format object +## audio_format objects can be instantiated as: +## +## Object.Base.input_audio_format."0" { +## in_rate 48000 +## in_sample_container_size 16 +## in_valid_bit_depth 16 +## in_interleaving_style "interleaved" +## } +## Class.Base."input_audio_format" { @@ -20,25 +22,25 @@ Class.Base."input_audio_format" { token_ref "cavs_audio_format.word" } - # input sampling rate + ## input sampling rate DefineAttribute."in_rate" { # Token set reference name token_ref "cavs_audio_format.word" } - # input bit depth + ## input bit depth DefineAttribute."in_bit_depth" { # Token set reference name token_ref "cavs_audio_format.word" } - # input valid bit depth + ## input valid bit depth DefineAttribute."in_valid_bit_depth" { # Token set reference name token_ref "cavs_audio_format.word" } - # input channel count + ## input channel count DefineAttribute."in_channels" { # Token set reference name token_ref "cavs_audio_format.word" @@ -48,19 +50,19 @@ Class.Base."input_audio_format" { } } - # input channel map + ## input channel map DefineAttribute."in_ch_map" { # Token set reference name token_ref "cavs_audio_format.word" } - # input channel config + ## input channel config DefineAttribute."in_ch_cfg" { # Token set reference name token_ref "cavs_audio_format.word" } - # input interleaving style + ## input interleaving style DefineAttribute."in_interleaving_style" { type "string" # Token set reference name @@ -77,13 +79,14 @@ Class.Base."input_audio_format" { } } - # input format config + ## input format config DefineAttribute."in_fmt_cfg" { # Token set reference name token_ref "cavs_audio_format.word" } - # input sample_type + ## Input sample_type. + ## Valid values for sample type are defined in common_definitions.conf. DefineAttribute."in_sample_type" { type string # Token set reference name @@ -100,7 +103,7 @@ Class.Base."input_audio_format" { } # - # input buffer size + ## input buffer size # DefineAttribute."ibs" { # Token set reference name and type From cf093731ba7e679f2e46f28a69c53586abc70932 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Fri, 29 Sep 2023 18:03:05 +0300 Subject: [PATCH 16/16] topology2: doc: Little fixes to make all classes show correctly There were couple of classes that did not have their topology2 snippets showing. Probably the essential problem was just the class definition starting from the first line of the file. There was nothing obviously wrong in the output of the filter, but the way the doxygen works is sometimes hard to anticipate. Adding \struct before the definition fixed the problem. Signed-off-by: Jyri Sarha --- tools/topology/topology2/include/dais/mic_extension.conf | 3 +++ tools/topology/topology2/include/dais/pdm_config.conf | 3 +++ tools/topology/topology2/platform/intel/ssp_aux_config.conf | 2 ++ 3 files changed, 8 insertions(+) diff --git a/tools/topology/topology2/include/dais/mic_extension.conf b/tools/topology/topology2/include/dais/mic_extension.conf index 6dc12a1f21b2..31628e9b2241 100644 --- a/tools/topology/topology2/include/dais/mic_extension.conf +++ b/tools/topology/topology2/include/dais/mic_extension.conf @@ -1,3 +1,6 @@ +## \brief Mic extension class +## \struct mic_extension + Class.Base."mic_extension" { DefineAttribute."id" {} diff --git a/tools/topology/topology2/include/dais/pdm_config.conf b/tools/topology/topology2/include/dais/pdm_config.conf index 2a8759a7742c..3745bea7998e 100644 --- a/tools/topology/topology2/include/dais/pdm_config.conf +++ b/tools/topology/topology2/include/dais/pdm_config.conf @@ -1,3 +1,6 @@ +## \brief Class for PDM config +## \struct pdm_config + Class.Base."pdm_config" { DefineAttribute."instance" {} # diff --git a/tools/topology/topology2/platform/intel/ssp_aux_config.conf b/tools/topology/topology2/platform/intel/ssp_aux_config.conf index 1a814edef07e..c084faa4195c 100644 --- a/tools/topology/topology2/platform/intel/ssp_aux_config.conf +++ b/tools/topology/topology2/platform/intel/ssp_aux_config.conf @@ -1,3 +1,5 @@ +## \struct mn_config + Class.Base."mn_config" { DefineAttribute."id" {}