diff --git a/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter b/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter index 0624c2d2eca7fd..99acb67bc867a9 100644 --- a/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter +++ b/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter @@ -4208,7 +4208,7 @@ server cluster UnitTesting = 4294048773 { attribute int16s rangeRestrictedInt16s = 41; attribute LONG_OCTET_STRING listLongOctetString[] = 42; attribute TestFabricScoped listFabricScoped[] = 43; - attribute boolean timedWriteBoolean = 48; + timedwrite attribute boolean timedWriteBoolean = 48; attribute boolean generalErrorBoolean = 49; attribute boolean clusterErrorBoolean = 50; attribute nullable boolean nullableBoolean = 16384; diff --git a/examples/all-clusters-minimal-app/all-clusters-common/all-clusters-minimal-app.matter b/examples/all-clusters-minimal-app/all-clusters-common/all-clusters-minimal-app.matter index 0b9400d1f4c62b..6a8b066ef5148a 100644 --- a/examples/all-clusters-minimal-app/all-clusters-common/all-clusters-minimal-app.matter +++ b/examples/all-clusters-minimal-app/all-clusters-common/all-clusters-minimal-app.matter @@ -3528,7 +3528,7 @@ server cluster UnitTesting = 4294048773 { attribute int16s rangeRestrictedInt16s = 41; attribute LONG_OCTET_STRING listLongOctetString[] = 42; attribute TestFabricScoped listFabricScoped[] = 43; - attribute boolean timedWriteBoolean = 48; + timedwrite attribute boolean timedWriteBoolean = 48; attribute boolean generalErrorBoolean = 49; attribute boolean clusterErrorBoolean = 50; attribute nullable boolean nullableBoolean = 16384; diff --git a/scripts/py_matter_idl/matter_idl/README.md b/scripts/py_matter_idl/matter_idl/README.md index e46fb4d00c853a..4446760bc5dc90 100644 --- a/scripts/py_matter_idl/matter_idl/README.md +++ b/scripts/py_matter_idl/matter_idl/README.md @@ -89,6 +89,9 @@ server cluster AccessControl = 31 { attribute AccessControlEntry acl[] = 0; // attributes are read-write by default attribute ExtensionEntry extension[] = 1; // and require a (spec defined) number + // attributes may require timed writes + timedwrite attribute int16u require_timed_writes = 3; + // Access control privileges on attributes default to: // // access(read: view, write: operate) diff --git a/scripts/py_matter_idl/matter_idl/matter_grammar.lark b/scripts/py_matter_idl/matter_idl/matter_grammar.lark index 14c0ffbb1baf55..e31e5a5cc2b700 100644 --- a/scripts/py_matter_idl/matter_idl/matter_grammar.lark +++ b/scripts/py_matter_idl/matter_idl/matter_grammar.lark @@ -35,6 +35,7 @@ attribute_with_access: attribute_access? struct_field attribute: attribute_qualities "attribute"i attribute_with_access ";" attribute_quality: "readonly"i -> attr_readonly | "nosubscribe"i -> attr_nosubscribe + | "timedwrite"i -> attr_timed attribute_qualities: attribute_quality* -> attribute_qualities request_struct: "request"i struct diff --git a/scripts/py_matter_idl/matter_idl/matter_idl_parser.py b/scripts/py_matter_idl/matter_idl/matter_idl_parser.py index 8683965743ffe8..0bbea23c1688bd 100755 --- a/scripts/py_matter_idl/matter_idl/matter_idl_parser.py +++ b/scripts/py_matter_idl/matter_idl/matter_idl_parser.py @@ -175,6 +175,9 @@ def attr_readonly(self, _): def attr_nosubscribe(self, _): return AttributeQuality.NOSUBSCRIBE + def attr_timed(self, _): + return AttributeQuality.TIMED_WRITE + def attribute_qualities(self, qualities): return UnionOfAllFlags(qualities) or AttributeQuality.NONE diff --git a/scripts/py_matter_idl/matter_idl/matter_idl_types.py b/scripts/py_matter_idl/matter_idl/matter_idl_types.py index 11df3b17771778..b4a47218a4d6d2 100644 --- a/scripts/py_matter_idl/matter_idl/matter_idl_types.py +++ b/scripts/py_matter_idl/matter_idl/matter_idl_types.py @@ -44,6 +44,7 @@ class AttributeQuality(enum.Flag): READABLE = enum.auto() WRITABLE = enum.auto() NOSUBSCRIBE = enum.auto() + TIMED_WRITE = enum.auto() class AttributeStorage(enum.Enum): @@ -135,6 +136,10 @@ def is_writable(self): def is_subscribable(self): return not (AttributeQuality.NOSUBSCRIBE & self.qualities) + @property + def requires_timed_write(self): + return AttributeQuality.TIMED_WRITE & self.qualities + @dataclass class Struct: diff --git a/scripts/py_matter_idl/matter_idl/test_matter_idl_parser.py b/scripts/py_matter_idl/matter_idl/test_matter_idl_parser.py index 4d429bd22e3a07..00b8bce8193510 100755 --- a/scripts/py_matter_idl/matter_idl/test_matter_idl_parser.py +++ b/scripts/py_matter_idl/matter_idl/test_matter_idl_parser.py @@ -165,6 +165,33 @@ def test_sized_attribute(self): )]) self.assertEqual(actual, expected) + def test_timed_attributes(self): + actual = parseText(""" + server cluster MyCluster = 1 { + attribute int32u attr1 = 1; + timedwrite attribute int32u attr2 = 2; + attribute int32u attr3 = 3; + timedwrite attribute octet_string<44> attr4[] = 4; + } + """) + + expected = Idl(clusters=[ + Cluster(side=ClusterSide.SERVER, + name="MyCluster", + code=1, + attributes=[ + Attribute(qualities=AttributeQuality.READABLE | AttributeQuality.WRITABLE, definition=Field( + data_type=DataType(name="int32u"), code=1, name="attr1")), + Attribute(qualities=AttributeQuality.READABLE | AttributeQuality.WRITABLE | AttributeQuality.TIMED_WRITE, definition=Field( + data_type=DataType(name="int32u"), code=2, name="attr2")), + Attribute(qualities=AttributeQuality.READABLE | AttributeQuality.WRITABLE, definition=Field( + data_type=DataType(name="int32u"), code=3, name="attr3")), + Attribute(qualities=AttributeQuality.READABLE | AttributeQuality.WRITABLE | AttributeQuality.TIMED_WRITE, definition=Field( + data_type=DataType(name="octet_string", max_length=44), code=4, name="attr4", is_list=True)), + ] + )]) + self.assertEqual(actual, expected) + def test_attribute_access(self): actual = parseText(""" server cluster MyCluster = 1 { diff --git a/src/app/zap-templates/templates/app/MatterIDL.zapt b/src/app/zap-templates/templates/app/MatterIDL.zapt index 9f67be02284118..cfe40d71f5dbd4 100644 --- a/src/app/zap-templates/templates/app/MatterIDL.zapt +++ b/src/app/zap-templates/templates/app/MatterIDL.zapt @@ -47,7 +47,10 @@ {{/zcl_events}} {{#chip_server_cluster_attributes}} {{#unless isGlobalAttribute}} - {{! ensure indent }}{{#unless isWritableAttribute~}} + {{! ensure indent }}{{#if mustUseTimedWrite~}} + timedwrite {{!marker to place a space even with whitespace removal~}} + {{~/if~}} + {{~#unless isWritableAttribute~}} readonly {{!marker to place a space even with whitespace removal~}} {{~/unless~}} {{~!TODO: write only attributes should also be supported~}} diff --git a/src/controller/data_model/controller-clusters.matter b/src/controller/data_model/controller-clusters.matter index cb4df8c85b8b09..5bdcbb9d25d207 100644 --- a/src/controller/data_model/controller-clusters.matter +++ b/src/controller/data_model/controller-clusters.matter @@ -4539,7 +4539,7 @@ client cluster UnitTesting = 4294048773 { attribute int16s rangeRestrictedInt16s = 41; attribute LONG_OCTET_STRING listLongOctetString[] = 42; attribute TestFabricScoped listFabricScoped[] = 43; - attribute boolean timedWriteBoolean = 48; + timedwrite attribute boolean timedWriteBoolean = 48; attribute boolean generalErrorBoolean = 49; attribute boolean clusterErrorBoolean = 50; attribute boolean unsupported = 255;