diff --git a/.github/.wordlist.txt b/.github/.wordlist.txt index 6e8ed5fbe4a714..194d6c800f953f 100644 --- a/.github/.wordlist.txt +++ b/.github/.wordlist.txt @@ -1164,6 +1164,8 @@ saveAs sbin scalability scalable +schema +schemas scm sco scp diff --git a/scripts/codegen.py b/scripts/codegen.py index 291a5df4b97318..60c2ee8d9b6777 100755 --- a/scripts/codegen.py +++ b/scripts/codegen.py @@ -70,8 +70,10 @@ def write_new_data(self, relative_path: str, content: str): @click.option( '--generator', default='JAVA', - type=click.Choice(GENERATORS.keys(), case_sensitive=False), - help='What code generator to run') + help='What code generator to run. The choices are: '+'|'.join(GENERATORS.keys())+'. ' + + 'When using custom, provide the plugin path using `--generator custom::` syntax. ' + + 'For example, `--generator custom:./my_plugin:my_plugin_module` will load `./my_plugin/my_plugin_module/__init.py__` ' + + 'that defines a subclass of CodeGenerator named CustomGenerator.') @click.option( '--output-dir', type=click.Path(exists=False), @@ -110,16 +112,28 @@ def main(log_level, generator, output_dir, dry_run, name_only, expected_outputs, datefmt='%Y-%m-%d %H:%M:%S' ) - logging.info("Parsing idl from %s" % idl_path) - idl_tree = CreateParser().parse(open(idl_path, "rt").read()) - if name_only: storage = ListGeneratedFilesStorage() else: storage = FileSystemGeneratorStorage(output_dir) + logging.info("Parsing idl from %s" % idl_path) + idl_tree = CreateParser().parse(open(idl_path, "rt").read()) + + plugin_module = None + if generator.startswith('custom'): + # check that the plugin path is provided + if ':' not in generator: + logging.fatal("Custom generator plugin path not provided. Use --generator custom:") + sys.exit(1) + custom_params = generator.split(':') + (generator, plugin_path, plugin_module) = custom_params + logging.info("Using CustomGenerator at plugin path %s.%s" % (plugin_path, plugin_module)) + sys.path.append(plugin_path) + generator = 'CUSTOM' + logging.info("Running code generator %s" % generator) - generator = CodeGenerator.FromString(generator).Create(storage, idl=idl_tree) + generator = CodeGenerator.FromString(generator).Create(storage, idl=idl_tree, plugin_module=plugin_module) generator.render(dry_run) if expected_outputs: diff --git a/scripts/py_matter_idl/examples/README.md b/scripts/py_matter_idl/examples/README.md new file mode 100644 index 00000000000000..ba09f90c7918ca --- /dev/null +++ b/scripts/py_matter_idl/examples/README.md @@ -0,0 +1,21 @@ +## Creating a custom matter_idl generator + +The matter_idl tool can be used to generate arbitrary code based on the Matter +data model schemas. To create a custom generator that lives outside of the +Matter SDK tree, follow the design pattern of +scripts/py_matter_idl/examples/matter_idl_plugin: + +1. Create a directory for your python generator module, for example + "matter_idl_plugin". +2. Add an `__init__.py` under "matter_idl_plugin" implementing a subclass of + `CodeGenerator` named `CustomGenerator`. +3. Have `CustomGenerator` load jinja templates, also under the + "matter_idl_plugin" subdirectory. +4. Execute the `codegen.py` script passing the path to the parent directory of + "matter_idl_plugin" via + `--generator custom::` argument. + +``` +# From top-of-tree in this example +./scripts/codegen.py --generator custom:./scripts/py_matter_idl/examples:matter_idl_plugin ./src/controller/data_model/controller-clusters.matter +``` diff --git a/scripts/py_matter_idl/examples/matter_idl_plugin/__init__.py b/scripts/py_matter_idl/examples/matter_idl_plugin/__init__.py new file mode 100644 index 00000000000000..2389d423009b49 --- /dev/null +++ b/scripts/py_matter_idl/examples/matter_idl_plugin/__init__.py @@ -0,0 +1,240 @@ +# Copyright (c) 2023 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +from typing import List + +import jinja2 +from matter_idl.generators import CodeGenerator, GeneratorStorage +from matter_idl.matter_idl_types import Attribute, Cluster, ClusterSide, Command, Field, Idl + + +def toUpperSnakeCase(s): + """ Convert camelCaseString to UPPER_SNAKE_CASE with proper handling of acronyms and numerals. """ + lastLower = False + letters = [] + for c in s: + if c.isupper(): + if lastLower: + letters.append('_') + letters.append(c) + lastLower = False + else: + letters.append(c.upper()) + lastLower = True + + return ''.join(letters) + + +def toLowerSnakeCase(s): + """ Convert camelCaseString to lower_snake_case with proper handling of acronyms and numerals. """ + return toUpperSnakeCase(s).lower() + + +def toUpperAcronym(s): + """ Remove lower case letters and numbers from the given string""" + return ''.join([i for i in s if i.isupper() or i.isnumeric()]).upper() + + +def toEnumEntryName(enumEntry, enumName): + """ Create enum entry name by prepending that acronym of the enum name and converting to upper snake case """ + prefix = toUpperAcronym(enumName) + if (enumEntry[0] == 'k'): + enumEntry = enumEntry[1:] + return prefix + '_' + toUpperSnakeCase(enumEntry) + + +def toProtobufType(zapType: str) -> str: + """ Convert zap type to protobuf type """ + u32Types = ["uint32", "enum8", "enum16", "enum32", "bitmap8", "bitmap16", "bitmap32", "cluster_id", "attrib_id", "event_id", "command_id", + "endpoint_no", "group_id", "devtype_id", "fabric_idx", "vendor_id", "status_code", "faulttype", "levelcontroloptions", "percent100ths", "percent"] + u64Types = ["uint64", "enum64", "bitmap64", "node_id", "fabric_id", "int40u", "int48u", "int56u", "int64u"] + i32Types = ["int32", "int8s", "int16s", "int24s", "int32s"] + i64Types = ["int64", "int40s", "int48s", "int56s", "int64s"] + floatTypes = ["float", "double"] + stringTypes = ["char_string", "long_char_string"] + bytesTypes = ["octet_string", "long_octet_string"] + + zapTypeLower = zapType.lower() + if zapTypeLower in u32Types: + return "uint32" + if zapTypeLower in u64Types: + return "uint64" + if zapTypeLower in i32Types: + return "int32" + if zapTypeLower in i64Types: + return "int64" + if zapTypeLower in floatTypes: + return "float" + if zapTypeLower == "double": + return "double" + if zapTypeLower == "boolean": + return "bool" + if zapTypeLower in stringTypes: + return "string" + if zapTypeLower in bytesTypes: + return "bytes" + + # If no match, return the original type name for the Struct, Enum, or Bitmap. + return zapType + + +# Enum for encoding the type information into protobuf field tag for stateless translation. +# These values encoded to the upper range of the protobuf field tag. +class EncodingDataType: + UINT = 1 + INT = 2 + BOOL = 3 + CHAR_STRING = 4 + OCT_STRING = 5 + STRUCT = 6 + FLOAT = 7 + DOUBLE = 8 + + @staticmethod + def fromType(protobufType: str): + if protobufType == "uint32": + return EncodingDataType.UINT + if protobufType == "uint64": + return EncodingDataType.UINT + if protobufType == "int32": + return EncodingDataType.INT + if protobufType == "int64": + return EncodingDataType.INT + if protobufType == "bool": + return EncodingDataType.BOOL + if protobufType == "string": + return EncodingDataType.CHAR_STRING + if protobufType == "bytes": + return EncodingDataType.OCT_STRING + if protobufType == "float": + return EncodingDataType.FLOAT + if protobufType == "double": + return EncodingDataType.DOUBLE + + # If not a primitive type, it is a named type; assume it is a Struct. + # NOTE: the actual type may be an Enum or Bitmap. + return EncodingDataType.STRUCT + + +def commandArgs(command: Command, cluster: Cluster): + """Return the list of fields for the command request for the given command and cluster.""" + for struct in cluster.structs: + if struct.name == command.input_param: + return struct.fields + + # If the command has no input parameters, just return an empty list. + return [] + + +def commandResponseArgs(command: Command, cluster: Cluster): + """Return the list of fields for the command response for the given command and cluster.""" + for struct in cluster.structs: + if struct.name == command.output_param: + return struct.fields + + return [] + + +def toEncodedTag(tag, typeNum: EncodingDataType): + """ Return the final encoded tag from the given field number and field encoded data type. + The Matter field type information is encoded into the upper range of the protobuf field + tag for stateless translation to Matter TLV. """ + tag = (int(typeNum) << 19) | int(tag) + return tag + + +def toProtobufFullType(field: Field): + """Return the full protobuf type for the given field, including repeated and optional specifiers.""" + prefix = "" + protobufType = toProtobufType(field.data_type.name) + if field.is_list: + prefix = "repeated " + prefix + elif field.is_optional: + prefix = "optional " + prefix + return prefix + protobufType + + +def toFieldTag(field: Field): + protobufType = toProtobufType(field.data_type.name) + typeNum = EncodingDataType.fromType(protobufType) + tag = toEncodedTag(field.code, typeNum) + return tag + + +def toFieldComment(field: Field): + protobufType = toProtobufType(field.data_type.name) + typeNum = EncodingDataType.fromType(protobufType) + tagComment = "/** %s Type: %d IsList: %d FieldId: %d */" % ( + field.data_type.name, typeNum, field.is_list, field.code) + return tagComment + + +class CustomGenerator(CodeGenerator): + """ + Example of a custom generator. Outputs protobuf representation of Matter clusters. + """ + + def __init__(self, storage: GeneratorStorage, idl: Idl, **kargs): + """ + Inintialization is specific for java generation and will add + filters as required by the java .jinja templates to function. + """ + super().__init__(storage, idl) + + # Override the template path to use local templates within this plugin directory + self.jinja_env = jinja2.Environment( + loader=jinja2.FileSystemLoader( + searchpath=os.path.dirname(__file__)), + keep_trailing_newline=True) + + # String helpers + self.jinja_env.filters['toLowerSnakeCase'] = toLowerSnakeCase + self.jinja_env.filters['toUpperSnakeCase'] = toUpperSnakeCase + + # Type helpers + self.jinja_env.filters['toEnumEntryName'] = toEnumEntryName + self.jinja_env.filters['toProtobufType'] = toProtobufType + self.jinja_env.filters['toEncodedTag'] = toEncodedTag + + # Tag helpers + self.jinja_env.filters['toFieldTag'] = toFieldTag + self.jinja_env.filters['toProtobufFullType'] = toProtobufFullType + self.jinja_env.filters['toFieldComment'] = toFieldComment + + # Command helpers + self.jinja_env.filters['commandArgs'] = commandArgs + self.jinja_env.filters['commandResponseArgs'] = commandResponseArgs + + def internal_render_all(self): + """ + Renders the given custom template to the given output filename. + """ + + # Every cluster has its own impl, to avoid + # very large compilations (running out of RAM) + for cluster in self.idl.clusters: + if cluster.side != ClusterSide.CLIENT: + continue + + filename = "proto/%s_cluster.proto" % toLowerSnakeCase(cluster.name) + + # Header containing a macro to initialize all cluster plugins + self.internal_render_one_output( + template_path="./matter_cluster_proto.jinja", + output_file_name=filename, + vars={ + 'cluster': cluster, + } + ) diff --git a/scripts/py_matter_idl/examples/matter_idl_plugin/matter_cluster_proto.jinja b/scripts/py_matter_idl/examples/matter_idl_plugin/matter_cluster_proto.jinja new file mode 100644 index 00000000000000..6e6c83abce075e --- /dev/null +++ b/scripts/py_matter_idl/examples/matter_idl_plugin/matter_cluster_proto.jinja @@ -0,0 +1,94 @@ + +/// AUTO-GENERATED with matter_idl. + +syntax = "proto3"; + +package com.matter.example.proto; + +option java_multiple_files = true; + +message {{cluster.name}}Cluster { + // option (message_type) = MATTER_TRAIT; + + enum ClusterId { + CLUSTER_ID_UNSUPPORTED = 0; + CLUSTER_ID = {{cluster.code}}; + } +{%- if cluster.enums %} + + // Enums +{%- for entry in cluster.enums %} + enum {{entry.name}} { + {%- if (entry.entries[0].code != 0) %} + {{"unsupported" | toEnumEntryName(entry.name)}} = 0;{% endif -%} + {%- for field in entry.entries %} + {{field.name | toEnumEntryName(entry.name)}} = {{field.code}};{% endfor %} + } +{% endfor %}{% endif -%} +{%- if cluster.bitmaps %} + + // Bitmaps +{%- for entry in cluster.bitmaps %} + enum {{entry.name}} { + {{"unsupported" | toEnumEntryName(entry.name)}} = 0; + {%- for field in entry.entries %} + {{field.name | toEnumEntryName(entry.name)}} = {{field.code}};{% endfor %} + } +{% endfor %}{% endif -%} +{%- if cluster.structs %} + + // Structs +{%- for entry in cluster.structs %}{% if not entry.tag %} + message {{entry.name}} { + {%- for field in entry.fields %} + {{field | toFieldComment}} + {{field | toProtobufFullType}} {{field.name | toLowerSnakeCase}} = {{field | toFieldTag}};{% endfor %} + } +{% endif %}{% endfor %}{% endif -%} +{%- if cluster.attributes %} + + // Attributes +{%- for attr in cluster.attributes %} + {{attr.definition | toFieldComment}} + {{attr.definition.data_type.name | toProtobufType}} {{attr.definition.name | toLowerSnakeCase}} = {{attr.definition | toFieldTag()}}; + /* + [(attribute) = { +{%- if attr.is_writable %} + is_writable : true,{% endif %} +{%- if attr.is_subscribable %} + is_subscribable: true,{% endif %} + }]; + */ + +{% endfor %}{% endif -%} +{%- if cluster.commands %} + + // Commands +{%- for cmd in cluster.commands %} + message {{cmd.name}}Command { + // option (message_type) = MATTER_COMMAND; + {% if cmd.input_param %}{%- for field in cmd | commandArgs(cluster) %} + {{field | toFieldComment}} + {{field | toProtobufFullType}} {{field.name | toLowerSnakeCase}} = {{field | toFieldTag}};{% endfor %}{% endif %} + }{% if cmd.output_param != "DefaultSuccess" %} + + message {{cmd.name}}CommandResponse { + // option (message_type) = MATTER_COMMAND_RESPONSE; + {% if cmd.output_param %}{%- for field in cmd | commandResponseArgs(cluster) %} + {{field | toFieldComment}} + {{field | toProtobufFullType}} {{field.name | toLowerSnakeCase}} = {{field | toFieldTag}};{% endfor %}{% endif %} + }{% endif %} +{% endfor %}{% endif %} + +{%- if cluster.events %} + // Events +{%- for entry in cluster.events %} + message {{entry.name}} { + // option (message_type) = MATTER_EVENT; + {% for field in entry.fields %} + {{field | toFieldComment}} + {{field | toProtobufFullType}} {{field.name | toLowerSnakeCase}} = {{field | toFieldTag}};{% endfor %} + } + +{% endfor %}{% endif %} +} // {{cluster.name}}Cluster diff --git a/scripts/py_matter_idl/matter_idl/generators/bridge/__init__.py b/scripts/py_matter_idl/matter_idl/generators/bridge/__init__.py index 149e6cf33e1d04..2c38924f2c5b0a 100644 --- a/scripts/py_matter_idl/matter_idl/generators/bridge/__init__.py +++ b/scripts/py_matter_idl/matter_idl/generators/bridge/__init__.py @@ -16,13 +16,13 @@ import enum import logging import re +from typing import List, Set, Union -from matter_idl.generators import CodeGenerator, GeneratorStorage -from matter_idl.matter_idl_types import Idl, Field, Attribute, Cluster, ClusterSide from matter_idl import matter_idl_types -from matter_idl.generators.types import (ParseDataType, BasicString, BasicInteger, FundamentalType, - IdlType, IdlEnumType, IdlBitmapType, TypeLookupContext) -from typing import Union, List, Set +from matter_idl.generators import CodeGenerator, GeneratorStorage +from matter_idl.generators.types import (BasicInteger, BasicString, FundamentalType, IdlBitmapType, IdlEnumType, IdlType, + ParseDataType, TypeLookupContext) +from matter_idl.matter_idl_types import Attribute, Cluster, ClusterSide, Field, Idl def camel_to_const(s): @@ -135,7 +135,7 @@ class BridgeGenerator(CodeGenerator): Generation of bridge cpp code for matter. """ - def __init__(self, storage: GeneratorStorage, idl: Idl): + def __init__(self, storage: GeneratorStorage, idl: Idl, **kargs): """ Inintialization is specific for cpp generation and will add filters as required by the cpp .jinja templates to function. diff --git a/scripts/py_matter_idl/matter_idl/generators/cpp/application/__init__.py b/scripts/py_matter_idl/matter_idl/generators/cpp/application/__init__.py index ead462b2c33cb0..b1f061b56cce84 100644 --- a/scripts/py_matter_idl/matter_idl/generators/cpp/application/__init__.py +++ b/scripts/py_matter_idl/matter_idl/generators/cpp/application/__init__.py @@ -12,15 +12,16 @@ # See the License for the specific language governing permissions and # limitations under the License. -from matter_idl.generators import CodeGenerator, GeneratorStorage -from matter_idl.matter_idl_types import Idl, ClusterSide, Field, Attribute, Cluster, FieldQuality, Command, DataType -from matter_idl import matter_idl_types -from matter_idl.generators.types import ParseDataType, BasicString, BasicInteger, FundamentalType, IdlType, IdlEnumType, IdlBitmapType, TypeLookupContext -from typing import Union, List, Set -from stringcase import capitalcase - import enum import logging +from typing import List, Set, Union + +from matter_idl import matter_idl_types +from matter_idl.generators import CodeGenerator, GeneratorStorage +from matter_idl.generators.types import (BasicInteger, BasicString, FundamentalType, IdlBitmapType, IdlEnumType, IdlType, + ParseDataType, TypeLookupContext) +from matter_idl.matter_idl_types import Attribute, Cluster, ClusterSide, Command, DataType, Field, FieldQuality, Idl +from stringcase import capitalcase def serverClustersOnly(clusters: List[Cluster]) -> List[Cluster]: @@ -32,7 +33,7 @@ class CppApplicationGenerator(CodeGenerator): Generation of cpp code for application implementation for matter. """ - def __init__(self, storage: GeneratorStorage, idl: Idl): + def __init__(self, storage: GeneratorStorage, idl: Idl, **kargs): """ Inintialization is specific for java generation and will add filters as required by the java .jinja templates to function. diff --git a/scripts/py_matter_idl/matter_idl/generators/java/__init__.py b/scripts/py_matter_idl/matter_idl/generators/java/__init__.py index a0f465b4e2f416..3ea1a670492449 100644 --- a/scripts/py_matter_idl/matter_idl/generators/java/__init__.py +++ b/scripts/py_matter_idl/matter_idl/generators/java/__init__.py @@ -13,15 +13,16 @@ # See the License for the specific language governing permissions and # limitations under the License. -from matter_idl.generators import CodeGenerator, GeneratorStorage -from matter_idl.matter_idl_types import Idl, ClusterSide, Field, Attribute, Cluster, FieldQuality, Command, DataType -from matter_idl import matter_idl_types -from matter_idl.generators.types import ParseDataType, BasicString, BasicInteger, FundamentalType, IdlType, IdlEnumType, IdlBitmapType, TypeLookupContext -from typing import Union, List, Set -from stringcase import capitalcase - import enum import logging +from typing import List, Set, Union + +from matter_idl import matter_idl_types +from matter_idl.generators import CodeGenerator, GeneratorStorage +from matter_idl.generators.types import (BasicInteger, BasicString, FundamentalType, IdlBitmapType, IdlEnumType, IdlType, + ParseDataType, TypeLookupContext) +from matter_idl.matter_idl_types import Attribute, Cluster, ClusterSide, Command, DataType, Field, FieldQuality, Idl +from stringcase import capitalcase def FieldToGlobalName(field: Field, context: TypeLookupContext) -> Union[str, None]: @@ -348,7 +349,7 @@ class JavaGenerator(CodeGenerator): Generation of java code for matter. """ - def __init__(self, storage: GeneratorStorage, idl: Idl): + def __init__(self, storage: GeneratorStorage, idl: Idl, **kargs): """ Inintialization is specific for java generation and will add filters as required by the java .jinja templates to function. diff --git a/scripts/py_matter_idl/matter_idl/generators/registry.py b/scripts/py_matter_idl/matter_idl/generators/registry.py index bc6d0b972952c9..b3aab6df7b4cf0 100644 --- a/scripts/py_matter_idl/matter_idl/generators/registry.py +++ b/scripts/py_matter_idl/matter_idl/generators/registry.py @@ -13,6 +13,7 @@ # limitations under the License. import enum +import importlib from matter_idl.generators.bridge import BridgeGenerator from matter_idl.generators.cpp.application import CppApplicationGenerator @@ -28,6 +29,7 @@ class CodeGenerator(enum.Enum): JAVA = enum.auto() BRIDGE = enum.auto() CPP_APPLICATION = enum.auto() + CUSTOM = enum.auto() def Create(self, *args, **kargs): if self == CodeGenerator.JAVA: @@ -36,6 +38,14 @@ def Create(self, *args, **kargs): return BridgeGenerator(*args, **kargs) elif self == CodeGenerator.CPP_APPLICATION: return CppApplicationGenerator(*args, **kargs) + elif self == CodeGenerator.CUSTOM: + # Use a package naming convention to find the custom generator: + # ./matter_idl_plugin/__init__.py defines a subclass of CodeGenerator named CustomGenerator. + # The plugin is expected to be in the path provided via the `--plugin ` cli argument. + # Replaces `from plugin_module import CustomGenerator`` + plugin_module = importlib.import_module(kargs['plugin_module']) + CustomGenerator = plugin_module.CustomGenerator + return CustomGenerator(*args, **kargs) else: raise NameError("Unknown code generator type") @@ -56,4 +66,5 @@ def FromString(name): 'java': CodeGenerator.JAVA, 'bridge': CodeGenerator.BRIDGE, 'cpp-app': CodeGenerator.CPP_APPLICATION, + 'custom': CodeGenerator.CUSTOM, } diff --git a/scripts/py_matter_idl/matter_idl/test_generators.py b/scripts/py_matter_idl/matter_idl/test_generators.py index a5fbcb4a17f0b4..5d7034d20367ae 100755 --- a/scripts/py_matter_idl/matter_idl/test_generators.py +++ b/scripts/py_matter_idl/matter_idl/test_generators.py @@ -15,6 +15,7 @@ # limitations under the License. import os +import sys import unittest from dataclasses import dataclass, field from typing import List @@ -122,6 +123,11 @@ def _create_generator(self, storage: GeneratorStorage, idl: Idl): return BridgeGenerator(storage, idl) if self.generator_name.lower() == 'cpp-app': return CppApplicationGenerator(storage, idl) + if self.generator_name.lower() == 'custom-example-proto': + sys.path.append(os.path.abspath( + os.path.join(os.path.dirname(__file__), '../examples'))) + from matter_idl_plugin import CustomGenerator + return CustomGenerator(storage, idl) else: raise Exception("Unknown generator for testing: %s", self.generator_name.lower()) diff --git a/scripts/py_matter_idl/matter_idl/tests/available_tests.yaml b/scripts/py_matter_idl/matter_idl/tests/available_tests.yaml index a4e2c6778b5f95..1b5483588b9b52 100644 --- a/scripts/py_matter_idl/matter_idl/tests/available_tests.yaml +++ b/scripts/py_matter_idl/matter_idl/tests/available_tests.yaml @@ -76,3 +76,12 @@ cpp-app: inputs/large_lighting_app.matter: app/PluginApplicationCallbacks.h: outputs/large_lighting_app/cpp-app/PluginApplicationCallbacks.h app/callback-stub.cpp: outputs/large_lighting_app/cpp-app/callback-stub.cpp + +custom-example-proto: + inputs/several_clusters.matter: + proto/first_cluster.proto: outputs/proto/first_cluster.proto + proto/second_cluster.proto: outputs/proto/second_cluster.proto + proto/third_cluster.proto: outputs/proto/third_cluster.proto + + inputs/large_all_clusters_app.matter: + proto/ota_software_update_provider_cluster.proto: outputs/proto/ota_software_update_provider_cluster.proto diff --git a/scripts/py_matter_idl/matter_idl/tests/outputs/proto/first_cluster.proto b/scripts/py_matter_idl/matter_idl/tests/outputs/proto/first_cluster.proto new file mode 100644 index 00000000000000..479a1688fb50aa --- /dev/null +++ b/scripts/py_matter_idl/matter_idl/tests/outputs/proto/first_cluster.proto @@ -0,0 +1,29 @@ + +/// AUTO-GENERATED with matter_idl. + +syntax = "proto3"; + +package com.matter.example.proto; + +option java_multiple_files = true; + +message FirstCluster { + // option (message_type) = MATTER_TRAIT; + + enum ClusterId { + CLUSTER_ID_UNSUPPORTED = 0; + CLUSTER_ID = 1; + } + + // Attributes + /** int16u Type: 6 IsList: 0 FieldId: 1 */ + int16u some_integer = 3145729; + /* + [(attribute) = { + is_writable : true, + is_subscribable: true, + }]; + */ + + +} // FirstCluster diff --git a/scripts/py_matter_idl/matter_idl/tests/outputs/proto/ota_software_update_provider_cluster.proto b/scripts/py_matter_idl/matter_idl/tests/outputs/proto/ota_software_update_provider_cluster.proto new file mode 100644 index 00000000000000..15bfdb9abe5c4c --- /dev/null +++ b/scripts/py_matter_idl/matter_idl/tests/outputs/proto/ota_software_update_provider_cluster.proto @@ -0,0 +1,107 @@ + +/// AUTO-GENERATED with matter_idl. + +syntax = "proto3"; + +package com.matter.example.proto; + +option java_multiple_files = true; + +message OtaSoftwareUpdateProviderCluster { + // option (message_type) = MATTER_TRAIT; + + enum ClusterId { + CLUSTER_ID_UNSUPPORTED = 0; + CLUSTER_ID = 41; + } + + // Enums + enum OTAApplyUpdateAction { + OTAAUA_PROCEED = 0; + OTAAUA_AWAIT_NEXT_ACTION = 1; + OTAAUA_DISCONTINUE = 2; + } + + enum OTADownloadProtocol { + OTADP_BDXSYNCHRONOUS = 0; + OTADP_BDXASYNCHRONOUS = 1; + OTADP_HTTPS = 2; + OTADP_VENDOR_SPECIFIC = 3; + } + + enum OTAQueryStatus { + OTAQS_UPDATE_AVAILABLE = 0; + OTAQS_BUSY = 1; + OTAQS_NOT_AVAILABLE = 2; + OTAQS_DOWNLOAD_PROTOCOL_NOT_SUPPORTED = 3; + } + + + // Structs + + // Attributes + /** int16u Type: 6 IsList: 0 FieldId: 65533 */ + int16u cluster_revision = 3211261; + /* + [(attribute) = { + is_subscribable: true, + }]; + */ + + + + // Commands + message QueryImageCommand { + // option (message_type) = MATTER_COMMAND; + + /** vendor_id Type: 1 IsList: 0 FieldId: 0 */ + uint32 vendor_id = 524288; + /** INT16U Type: 6 IsList: 0 FieldId: 1 */ + INT16U product_id = 3145729; + /** INT32U Type: 6 IsList: 0 FieldId: 2 */ + INT32U software_version = 3145730; + /** OTADownloadProtocol Type: 6 IsList: 1 FieldId: 3 */ + repeated OTADownloadProtocol protocols_supported = 3145731; + /** INT16U Type: 6 IsList: 0 FieldId: 4 */ + optional INT16U hardware_version = 3145732; + /** CHAR_STRING Type: 4 IsList: 0 FieldId: 5 */ + optional string location = 2097157; + /** BOOLEAN Type: 3 IsList: 0 FieldId: 6 */ + optional bool requestor_can_consent = 1572870; + /** OCTET_STRING Type: 5 IsList: 0 FieldId: 7 */ + optional bytes metadata_for_provider = 2621447; + } + + message QueryImageCommandResponse { + // option (message_type) = MATTER_COMMAND_RESPONSE; + + } + + message ApplyUpdateRequestCommand { + // option (message_type) = MATTER_COMMAND; + + /** OCTET_STRING Type: 5 IsList: 0 FieldId: 0 */ + bytes update_token = 2621440; + /** INT32U Type: 6 IsList: 0 FieldId: 1 */ + INT32U new_version = 3145729; + } + + message ApplyUpdateRequestCommandResponse { + // option (message_type) = MATTER_COMMAND_RESPONSE; + + /** OTAApplyUpdateAction Type: 6 IsList: 0 FieldId: 0 */ + OTAApplyUpdateAction action = 3145728; + /** INT32U Type: 6 IsList: 0 FieldId: 1 */ + INT32U delayed_action_time = 3145729; + } + + message NotifyUpdateAppliedCommand { + // option (message_type) = MATTER_COMMAND; + + /** OCTET_STRING Type: 5 IsList: 0 FieldId: 0 */ + bytes update_token = 2621440; + /** INT32U Type: 6 IsList: 0 FieldId: 1 */ + INT32U software_version = 3145729; + } + +} // OtaSoftwareUpdateProviderCluster diff --git a/scripts/py_matter_idl/matter_idl/tests/outputs/proto/second_cluster.proto b/scripts/py_matter_idl/matter_idl/tests/outputs/proto/second_cluster.proto new file mode 100644 index 00000000000000..1ac9be7447c174 --- /dev/null +++ b/scripts/py_matter_idl/matter_idl/tests/outputs/proto/second_cluster.proto @@ -0,0 +1,28 @@ + +/// AUTO-GENERATED with matter_idl. + +syntax = "proto3"; + +package com.matter.example.proto; + +option java_multiple_files = true; + +message SecondCluster { + // option (message_type) = MATTER_TRAIT; + + enum ClusterId { + CLUSTER_ID_UNSUPPORTED = 0; + CLUSTER_ID = 2; + } + + // Attributes + /** octet_string Type: 5 IsList: 0 FieldId: 123 */ + bytes some_bytes = 2621563; + /* + [(attribute) = { + is_subscribable: true, + }]; + */ + + +} // SecondCluster diff --git a/scripts/py_matter_idl/matter_idl/tests/outputs/proto/third_cluster.proto b/scripts/py_matter_idl/matter_idl/tests/outputs/proto/third_cluster.proto new file mode 100644 index 00000000000000..16c8685257692e --- /dev/null +++ b/scripts/py_matter_idl/matter_idl/tests/outputs/proto/third_cluster.proto @@ -0,0 +1,54 @@ + +/// AUTO-GENERATED with matter_idl. + +syntax = "proto3"; + +package com.matter.example.proto; + +option java_multiple_files = true; + +message ThirdCluster { + // option (message_type) = MATTER_TRAIT; + + enum ClusterId { + CLUSTER_ID_UNSUPPORTED = 0; + CLUSTER_ID = 3; + } + + // Enums + enum MyEnum { + ME_UNKNOWN = 0; + ME_KNOWN = 100; + } + + + // Bitmaps + enum LevelControlOptions { + LCO_UNSUPPORTED = 0; + LCO_EXECUTE_IF_OFF = 1; + LCO_COUPLE_COLOR_TEMP_TO_LEVEL = 2; + } + + + // Attributes + /** MyEnum Type: 6 IsList: 0 FieldId: 10 */ + MyEnum some_enum = 3145738; + /* + [(attribute) = { + is_writable : true, + is_subscribable: true, + }]; + */ + + + /** LevelControlOptions Type: 1 IsList: 0 FieldId: 20 */ + uint32 options = 524308; + /* + [(attribute) = { + is_writable : true, + is_subscribable: true, + }]; + */ + + +} // ThirdCluster